mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-16 13:23:46 +03:00
Upload
This commit is contained in:
52
lua/weapons/arccw_base/cl_blur.lua
Normal file
52
lua/weapons/arccw_base/cl_blur.lua
Normal file
@@ -0,0 +1,52 @@
|
||||
--[[
|
||||
| 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 dofmat = Material("pp/dof")
|
||||
|
||||
function SWEP:BlurWeapon()
|
||||
if !ArcCW.ConVars["blur"]:GetBool() then return end
|
||||
local delta = self:GetSightDelta()
|
||||
if delta >= 1 then return end
|
||||
local vm = self:GetOwner():GetViewModel()
|
||||
render.UpdateScreenEffectTexture()
|
||||
render.ClearStencil()
|
||||
render.SetStencilEnable(true)
|
||||
render.SetStencilCompareFunction(STENCIL_ALWAYS)
|
||||
render.SetStencilPassOperation(STENCIL_REPLACE)
|
||||
render.SetStencilFailOperation(STENCIL_KEEP)
|
||||
render.SetStencilZFailOperation(STENCIL_REPLACE)
|
||||
render.SetStencilWriteMask(0xFF)
|
||||
render.SetStencilTestMask(0xFF)
|
||||
render.SetBlend(1)
|
||||
render.SetStencilReferenceValue(55)
|
||||
ArcCW.Overdraw = true
|
||||
vm:DrawModel()
|
||||
ArcCW.Overdraw = false
|
||||
render.SetBlend(0)
|
||||
render.SetStencilPassOperation(STENCIL_REPLACE)
|
||||
render.SetStencilCompareFunction(STENCIL_EQUAL)
|
||||
-- render.SetColorMaterial()
|
||||
dofmat:SetFloat("bluramount", 0.1 * (1 - delta))
|
||||
render.SetMaterial(dofmat)
|
||||
render.DrawScreenQuad()
|
||||
render.SetStencilEnable(false)
|
||||
end
|
||||
|
||||
function SWEP:BlurNotWeapon()
|
||||
if !ArcCW.ConVars["blur"]:GetBool() then return end
|
||||
render.UpdateRefractTexture()
|
||||
DrawToyTown(3, ScrH())
|
||||
end
|
||||
|
||||
function SWEP:DoToyTown()
|
||||
if !ArcCW.ConVars["blur_toytown"]:GetBool() then return end
|
||||
render.UpdateRefractTexture()
|
||||
DrawToyTown(3, ScrH() * 0.4 * (1 - self:GetSightDelta()))
|
||||
end
|
||||
303
lua/weapons/arccw_base/cl_crosshair.lua
Normal file
303
lua/weapons/arccw_base/cl_crosshair.lua
Normal file
@@ -0,0 +1,303 @@
|
||||
--[[
|
||||
| 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 size = 0
|
||||
local clump_inner = Material("arccw/hud/clump_inner.png", "mips smooth")
|
||||
local clump_outer = Material("arccw/hud/clump_outer.png", "mips smooth")
|
||||
local aimtr_result = {}
|
||||
local aimtr = {}
|
||||
local square_mat = Material("color")
|
||||
|
||||
function SWEP:ShouldDrawCrosshair()
|
||||
if ArcCW.ConVars["override_crosshair_off"]:GetBool() then return false end
|
||||
if !ArcCW.ConVars["crosshair"]:GetBool() then return false end
|
||||
if self:GetReloading() then return false end
|
||||
if self:BarrelHitWall() > 0 then return false end
|
||||
local asight = self:GetActiveSights()
|
||||
|
||||
if !self:GetOwner():ShouldDrawLocalPlayer()
|
||||
and self:GetState() == ArcCW.STATE_SIGHTS and !asight.CrosshairInSights then
|
||||
return false
|
||||
end
|
||||
|
||||
if self:GetNWState() == ArcCW.STATE_SPRINT and !self:CanShootWhileSprint() then return false end
|
||||
if self:GetCurrentFiremode().Mode == 0 then return false end
|
||||
if self:GetBuff_Hook("Hook_ShouldNotFire") then return false end
|
||||
if self:GetNWState() == ArcCW.STATE_CUSTOMIZE then return false end
|
||||
if self:GetNWState() == ArcCW.STATE_DISABLE then return false end
|
||||
return true
|
||||
end
|
||||
|
||||
local cr_main = Color( 0, 255, 0 )
|
||||
local cr_shad = Color( 0, 0, 0, 127 )
|
||||
|
||||
local gaA = 0
|
||||
local gaD = 0
|
||||
|
||||
function SWEP:GetFOVAcc( acc, disp )
|
||||
cam.Start3D()
|
||||
local lool = ( EyePos() + ( EyeAngles():Forward() ) + ( ( ArcCW.MOAToAcc * (acc or self:GetBuff("AccuracyMOA")) ) * EyeAngles():Up() ) ):ToScreen()
|
||||
local lool2 = ( EyePos() + ( EyeAngles():Forward() ) + ( ( (disp or self:GetDispersion()) * ArcCW.MOAToAcc / 10 ) * EyeAngles():Up() ) ):ToScreen()
|
||||
cam.End3D()
|
||||
|
||||
local gau = 0
|
||||
gau = ( (ScrH() / 2) - lool.y )
|
||||
gaA = math.Approach(gaA, gau, (ScrH() / 2) * FrameTime())
|
||||
gau = 0
|
||||
gau = ( (ScrH() / 2) - lool2.y )
|
||||
gaD = math.Approach(gaD, gau, (ScrH() / 2) * FrameTime())
|
||||
|
||||
return gaA, gaD
|
||||
end
|
||||
|
||||
function SWEP:DrawDevCrosshair(x, y)
|
||||
surface.SetDrawColor(255, 50, 50, 255)
|
||||
|
||||
surface.DrawLine(x, y - 256, x, y + 256)
|
||||
surface.DrawLine(x - 256, y, x + 256, y)
|
||||
|
||||
|
||||
local gA, gD = self:GetFOVAcc( self:GetBuff("AccuracyMOA"), self:GetDispersion() )
|
||||
surface.DrawCircle(x, y, gA + gD, 255, 255, 255, 155)
|
||||
surface.DrawCircle(x, y, gA, 255, 255, 0, 55)
|
||||
|
||||
draw.SimpleTextOutlined(math.Round(self:GetDispersion(), 1) .. " MOA", "ArcCW_24_Unscaled", x - gA - gD - 16, y, color_white, TEXT_ALIGN_RIGHT, TEXT_ALIGN_BOTTOM, 1, Color(0, 0, 0))
|
||||
draw.SimpleTextOutlined(math.Round(self:GetBuff("AccuracyMOA"), 1) .. " MOA", "ArcCW_24_Unscaled", x - gA - gD - 16, y, Color(255, 255, 0), TEXT_ALIGN_RIGHT, TEXT_ALIGN_TOP, 1, Color(0, 0, 0))
|
||||
|
||||
|
||||
local dist = self:GetOwner():GetEyeTrace().HitPos:Distance(self:GetOwner():GetShootPos()) * ArcCW.HUToM
|
||||
local rf = self:GetRangeFraction(dist)
|
||||
|
||||
local dmg = math.floor(self:GetDamage(dist))
|
||||
draw.SimpleTextOutlined(dmg .. " damage", "ArcCW_24_Unscaled", x + 256, y, color_white, TEXT_ALIGN_RIGHT, TEXT_ALIGN_BOTTOM, 1, Color(0, 0, 0))
|
||||
draw.SimpleTextOutlined(math.Round(dist, 1) .. "m", "ArcCW_24_Unscaled", x + 256 - 64, y, color_white, TEXT_ALIGN_RIGHT, TEXT_ALIGN_TOP, 1, Color(0, 0, 0))
|
||||
draw.SimpleTextOutlined(math.Round(rf * 100) .. "%", "ArcCW_24_Unscaled", x + 256, y, color_white, TEXT_ALIGN_RIGHT, TEXT_ALIGN_TOP, 1, Color(0, 0, 0))
|
||||
|
||||
end
|
||||
|
||||
function SWEP:DoDrawCrosshair(x, y)
|
||||
local ply = LocalPlayer()
|
||||
local pos = ply:EyePos()
|
||||
local ang = ply:EyeAngles() - self:GetOurViewPunchAngles() + self:GetFreeAimOffset()
|
||||
|
||||
if self:GetBuff_Hook("Hook_PreDrawCrosshair") then return end
|
||||
|
||||
local static = ArcCW.ConVars["crosshair_static"]:GetBool()
|
||||
|
||||
local prong_dot = ArcCW.ConVars["crosshair_dot"]:GetBool()
|
||||
local prong_top = ArcCW.ConVars["crosshair_prong_top"]:GetBool()
|
||||
local prong_left = ArcCW.ConVars["crosshair_prong_left"]:GetBool()
|
||||
local prong_right = ArcCW.ConVars["crosshair_prong_right"]:GetBool()
|
||||
local prong_down = ArcCW.ConVars["crosshair_prong_bottom"]:GetBool()
|
||||
|
||||
local prong_len = ArcCW.ConVars["crosshair_length"]:GetFloat()
|
||||
local prong_wid = ArcCW.ConVars["crosshair_thickness"]:GetFloat()
|
||||
local prong_out = ArcCW.ConVars["crosshair_outline"]:GetInt()
|
||||
local prong_tilt = ArcCW.ConVars["crosshair_tilt"]:GetBool()
|
||||
|
||||
local clr = Color(ArcCW.ConVars["crosshair_clr_r"]:GetInt(),
|
||||
ArcCW.ConVars["crosshair_clr_g"]:GetInt(),
|
||||
ArcCW.ConVars["crosshair_clr_b"]:GetInt())
|
||||
if ArcCW.ConVars["ttt_rolecrosshair"] and ArcCW.ConVars["ttt_rolecrosshair"]:GetBool() then
|
||||
if GetRoundState() == ROUND_PREP or GetRoundState() == ROUND_POST then
|
||||
clr = Color(255, 255, 255)
|
||||
elseif ply.GetRoleColor and ply:GetRoleColor() then
|
||||
clr = ply:GetRoleColor() -- TTT2 feature
|
||||
elseif ply:IsActiveTraitor() then
|
||||
clr = Color(255, 50, 50)
|
||||
elseif ply:IsActiveDetective() then
|
||||
clr = Color(50, 50, 255)
|
||||
else
|
||||
clr = Color(50, 255, 50)
|
||||
end
|
||||
end
|
||||
if ArcCW.ConVars["crosshair_aa"]:GetBool() and ply.ArcCW_AATarget != nil and ArcCW.ConVars["aimassist"]:GetBool() and ArcCW.ConVars["aimassist_cl"]:GetBool() then
|
||||
-- whooie
|
||||
clr = Color(255, 0, 0)
|
||||
end
|
||||
clr.a = ArcCW.ConVars["crosshair_clr_a"]:GetInt()
|
||||
|
||||
local outlineClr = Color(ArcCW.ConVars["crosshair_outline_r"]:GetInt(),
|
||||
ArcCW.ConVars["crosshair_outline_g"]:GetInt(),
|
||||
ArcCW.ConVars["crosshair_outline_b"]:GetInt(),
|
||||
ArcCW.ConVars["crosshair_outline_a"]:GetInt())
|
||||
|
||||
local gA, gD = self:GetFOVAcc( self:GetBuff("AccuracyMOA"), self:GetDispersion() )
|
||||
local gap = (static and 8 or gA + gD) * ArcCW.ConVars["crosshair_gap"]:GetFloat()
|
||||
|
||||
gap = gap + ( ScreenScale(8) * math.Clamp(self.RecoilAmount, 0, 1) )
|
||||
|
||||
local prong = ScreenScale(prong_len)
|
||||
local p_w = ScreenScale(prong_wid)
|
||||
local p_w2 = p_w + prong_out
|
||||
|
||||
local sp
|
||||
if self:GetOwner():ShouldDrawLocalPlayer() then
|
||||
local tr = util.GetPlayerTrace(self:GetOwner())
|
||||
local trace = util.TraceLine( tr )
|
||||
|
||||
cam.Start3D()
|
||||
local coords = trace.HitPos:ToScreen()
|
||||
coords.x = math.Round(coords.x)
|
||||
coords.y = math.Round(coords.y)
|
||||
cam.End3D()
|
||||
sp = { visible = true, x = coords.x, y = coords.y }
|
||||
end
|
||||
|
||||
cam.Start3D()
|
||||
sp = (pos + (ang:Forward() * 3200)):ToScreen()
|
||||
cam.End3D()
|
||||
|
||||
if ArcCW.ConVars["crosshair_trueaim"]:GetBool() then
|
||||
aimtr.start = self:GetShootSrc()
|
||||
else
|
||||
aimtr.start = pos
|
||||
end
|
||||
|
||||
aimtr.endpos = aimtr.start + ((ply:EyeAngles() + self:GetFreeAimOffset()):Forward() * 100000)
|
||||
aimtr.filter = {ply}
|
||||
aimtr.output = aimtr_result
|
||||
|
||||
table.Add(aimtr.filter, ArcCW:GetVehicleFilter(ply) or {})
|
||||
|
||||
util.TraceLine(aimtr)
|
||||
|
||||
cam.Start3D()
|
||||
local w2s = aimtr_result.HitPos:ToScreen()
|
||||
w2s.x = math.Round(w2s.x)
|
||||
w2s.y = math.Round(w2s.y)
|
||||
cam.End3D()
|
||||
|
||||
sp.x = w2s.x sp.y = w2s.y
|
||||
x, y = sp.x, sp.y
|
||||
|
||||
if ArcCW.ConVars["dev_crosshair"]:GetBool() and LocalPlayer():IsAdmin() then
|
||||
self:DrawDevCrosshair(x, y)
|
||||
end
|
||||
|
||||
local st = self:GetSightTime() / 2
|
||||
|
||||
if self:ShouldDrawCrosshair() then
|
||||
self.CrosshairDelta = math.Approach(self.CrosshairDelta or 0, 1, FrameTime() * 1 / st)
|
||||
else
|
||||
self.CrosshairDelta = math.Approach(self.CrosshairDelta or 0, 0, FrameTime() * 1 / st)
|
||||
end
|
||||
|
||||
if ArcCW.ConVars["crosshair_equip"]:GetBool() and (self:GetBuff("ShootEntity", true) or self.PrimaryBash) then
|
||||
prong = ScreenScale(prong_wid)
|
||||
p_w = ScreenScale(prong_wid)
|
||||
p_w2 = p_w + prong_out
|
||||
end
|
||||
|
||||
if prong_dot then
|
||||
surface.SetDrawColor(outlineClr.r, outlineClr.g, outlineClr.b, outlineClr.a * self.CrosshairDelta)
|
||||
surface.DrawRect(x - p_w2 / 2, y - p_w2 / 2, p_w2, p_w2)
|
||||
|
||||
surface.SetDrawColor(clr.r, clr.g, clr.b, clr.a * self.CrosshairDelta)
|
||||
surface.DrawRect(x - p_w / 2, y - p_w / 2, p_w, p_w)
|
||||
end
|
||||
|
||||
|
||||
size = math.Approach(size, gap, FrameTime() * 32 * gap)
|
||||
gap = size
|
||||
if !static then gap = gap * self.CrosshairDelta end
|
||||
gap = math.max(4, gap)
|
||||
|
||||
local num = self:GetBuff("Num")
|
||||
if ArcCW.ConVars["crosshair_shotgun"]:GetBool() and num > 1 then
|
||||
prong = ScreenScale(prong_wid)
|
||||
p_w = ScreenScale(prong_len)
|
||||
p_w2 = p_w + prong_out
|
||||
end
|
||||
|
||||
local prong2 = prong + prong_out
|
||||
if prong_tilt then
|
||||
local angle = (prong_left and prong_top and prong_right and prong_down) and 45 or 30
|
||||
local rad = math.rad(angle)
|
||||
local dx = gap * math.cos(rad) + prong * math.cos(rad) / 2
|
||||
local dy = gap * math.sin(rad) + prong * math.sin(rad) / 2
|
||||
surface.SetMaterial(square_mat)
|
||||
-- Shade
|
||||
surface.SetDrawColor(outlineClr.r, outlineClr.g, outlineClr.b, outlineClr.a * self.CrosshairDelta)
|
||||
if prong_left and prong_top then
|
||||
surface.DrawTexturedRectRotated(x - dx, y - dy, prong2, p_w2, -angle)
|
||||
surface.DrawTexturedRectRotated(x + dx, y - dy, prong2, p_w2, angle)
|
||||
elseif prong_left or prong_top then
|
||||
surface.DrawRect(x - p_w2 / 2, y - gap - prong2 + prong_out / 2, p_w2, prong2)
|
||||
end
|
||||
if prong_right and prong_down then
|
||||
surface.DrawTexturedRectRotated(x + dx, y + dy, prong2, p_w2, -angle)
|
||||
surface.DrawTexturedRectRotated(x - dx, y + dy, prong2, p_w2, angle)
|
||||
elseif prong_right or prong_down then
|
||||
surface.DrawRect(x - p_w2 / 2, y + gap - prong_out / 2, p_w2, prong2)
|
||||
end
|
||||
-- Fill
|
||||
surface.SetDrawColor(clr.r, clr.g, clr.b, clr.a * self.CrosshairDelta)
|
||||
if prong_left and prong_top then
|
||||
surface.DrawTexturedRectRotated(x - dx, y - dy, prong, p_w, -angle)
|
||||
surface.DrawTexturedRectRotated(x + dx, y - dy, prong, p_w, angle)
|
||||
elseif prong_left or prong_top then
|
||||
surface.DrawRect(x - p_w / 2, y - gap - prong, p_w, prong)
|
||||
end
|
||||
if prong_right and prong_down then
|
||||
surface.DrawTexturedRectRotated(x + dx, y + dy, prong, p_w, -angle)
|
||||
surface.DrawTexturedRectRotated(x - dx, y + dy, prong, p_w, angle)
|
||||
elseif prong_right or prong_down then
|
||||
surface.DrawRect(x - p_w / 2, y + gap, p_w, prong)
|
||||
end
|
||||
else
|
||||
-- Shade
|
||||
surface.SetDrawColor(outlineClr.r, outlineClr.g, outlineClr.b, outlineClr.a * self.CrosshairDelta)
|
||||
if prong_left then
|
||||
surface.DrawRect(x - gap - prong2 + prong_out / 2, y - p_w2 / 2, prong2, p_w2)
|
||||
end
|
||||
if prong_right then
|
||||
surface.DrawRect(x + gap - prong_out / 2, y - p_w2 / 2, prong2, p_w2)
|
||||
end
|
||||
if prong_top then
|
||||
surface.DrawRect(x - p_w2 / 2, y - gap - prong2 + prong_out / 2, p_w2, prong2)
|
||||
end
|
||||
if prong_down then
|
||||
surface.DrawRect(x - p_w2 / 2, y + gap - prong_out / 2, p_w2, prong2)
|
||||
end
|
||||
-- Fill
|
||||
surface.SetDrawColor(clr.r, clr.g, clr.b, clr.a * self.CrosshairDelta)
|
||||
if prong_left then
|
||||
surface.DrawRect(x - gap - prong, y - p_w / 2, prong, p_w)
|
||||
end
|
||||
if prong_right then
|
||||
surface.DrawRect(x + gap, y - p_w / 2, prong, p_w)
|
||||
end
|
||||
if prong_top then
|
||||
surface.DrawRect(x - p_w / 2, y - gap - prong, p_w, prong)
|
||||
end
|
||||
if prong_down then
|
||||
surface.DrawRect(x - p_w / 2, y + gap, p_w, prong)
|
||||
end
|
||||
end
|
||||
|
||||
if ArcCW.ConVars["crosshair_clump"]:GetBool() and (ArcCW.ConVars["crosshair_clump_always"]:GetBool() or num > 1) then
|
||||
local acc = math.max(1, gA)
|
||||
if ArcCW.ConVars["crosshair_clump_outline"]:GetBool() then
|
||||
surface.SetMaterial(clump_outer)
|
||||
|
||||
for i=1, prong_out do
|
||||
surface.DrawCircle(x-1, y-0, acc + math.ceil(i*0.5) * (i % 2 == 1 and 1 or -1), outlineClr.r, outlineClr.g, outlineClr.b, outlineClr.a * self.CrosshairDelta)
|
||||
end
|
||||
surface.DrawCircle(x-1, y-0, acc, outlineClr.r, outlineClr.g, outlineClr.b, outlineClr.a * self.CrosshairDelta)
|
||||
end
|
||||
|
||||
surface.DrawCircle(x-1, y-0, acc, clr.r, clr.g, clr.b, clr.a * self.CrosshairDelta)
|
||||
end
|
||||
|
||||
self:GetBuff_Hook("Hook_PostDrawCrosshair", w2s)
|
||||
|
||||
return true
|
||||
end
|
||||
3102
lua/weapons/arccw_base/cl_customize2.lua
Normal file
3102
lua/weapons/arccw_base/cl_customize2.lua
Normal file
File diff suppressed because it is too large
Load Diff
968
lua/weapons/arccw_base/cl_holosight.lua
Normal file
968
lua/weapons/arccw_base/cl_holosight.lua
Normal file
@@ -0,0 +1,968 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
function SWEP:DoHolosight()
|
||||
|
||||
-- In VRMod, we draw all holosights all the time
|
||||
if vrmod and vrmod.IsPlayerInVR(self:GetOwner()) then
|
||||
for i, asight in pairs(self.SightTable) do
|
||||
local aslot = self.Attachments[asight.Slot] or {}
|
||||
local atttbl = asight.HolosightData
|
||||
|
||||
if !atttbl and aslot.Installed then
|
||||
atttbl = ArcCW.AttachmentTable[aslot.Installed]
|
||||
|
||||
if !atttbl.Holosight then return end
|
||||
end
|
||||
|
||||
if atttbl then
|
||||
local hsp = asight.HolosightPiece or self.HSPElement
|
||||
local hsm = asight.HolosightModel
|
||||
|
||||
if !hsp and !hsm then
|
||||
self:SetupActiveSights()
|
||||
return
|
||||
end
|
||||
|
||||
self:DrawHolosight(atttbl, hsm, hsp, asight)
|
||||
end
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local asight = self:GetActiveSights()
|
||||
if !asight then return end
|
||||
local aslot = self.Attachments[asight.Slot] or {}
|
||||
|
||||
local atttbl = asight.HolosightData
|
||||
|
||||
if !atttbl and aslot.Installed then
|
||||
atttbl = ArcCW.AttachmentTable[aslot.Installed]
|
||||
|
||||
if !atttbl.Holosight then return end
|
||||
end
|
||||
|
||||
if atttbl then
|
||||
local hsp = asight.HolosightPiece or self.HSPElement
|
||||
local hsm = asight.HolosightModel
|
||||
|
||||
if !hsp and !hsm then
|
||||
self:SetupActiveSights()
|
||||
return
|
||||
end
|
||||
|
||||
self:DrawHolosight(atttbl, hsm, hsp)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:ShouldFlatScope()
|
||||
return false -- this system was removed, but we need to keep this function
|
||||
end
|
||||
|
||||
local rtsize = ScrH()
|
||||
|
||||
local rtmat = GetRenderTarget("arccw_rtmat", rtsize, rtsize, false)
|
||||
local rtmat_cheap = GetRenderTarget("arccw_rtmat_cheap", ScrW(), ScrH(), false)
|
||||
local rtmat_spare = GetRenderTarget("arccw_rtmat_spare", ScrW(), ScrH(), false)
|
||||
|
||||
|
||||
local thermal = Material("models/debug/debugwhite")
|
||||
local colormod = Material("pp/colour")
|
||||
local coldtime = 30
|
||||
|
||||
local additionalFOVconvar = ArcCW.ConVars["vm_add_ads"]
|
||||
|
||||
local matRefract = Material("pp/arccw/refract_rt")
|
||||
local matRefract_cheap = Material("pp/arccw/refract_cs") -- cheap scopes stretches square overlays so i need to make it 16x9
|
||||
|
||||
matRefract:SetTexture("$fbtexture", render.GetScreenEffectTexture())
|
||||
matRefract_cheap:SetTexture("$fbtexture", render.GetScreenEffectTexture())
|
||||
|
||||
timer.Create("ihategmod", 5, 0, function() -- i really dont know what the fucking problem with cheap scopes they dont want to set texture as not cheap ones
|
||||
matRefract_cheap:SetTexture("$fbtexture", render.GetScreenEffectTexture())
|
||||
matRefract:SetTexture("$fbtexture", render.GetScreenEffectTexture()) -- not cheap scope here why not
|
||||
end)
|
||||
|
||||
local pp_ca_base, pp_ca_r, pp_ca_g, pp_ca_b = Material("pp/arccw/ca_base"), Material("pp/arccw/ca_r"), Material("pp/arccw/ca_g"), Material("pp/arccw/ca_b")
|
||||
local pp_ca_r_thermal, pp_ca_g_thermal, pp_ca_b_thermal = Material("pp/arccw/ca_r_thermal"), Material("pp/arccw/ca_g_thermal"), Material("pp/arccw/ca_b_thermal")
|
||||
|
||||
pp_ca_r:SetTexture("$basetexture", render.GetScreenEffectTexture())
|
||||
pp_ca_g:SetTexture("$basetexture", render.GetScreenEffectTexture())
|
||||
pp_ca_b:SetTexture("$basetexture", render.GetScreenEffectTexture())
|
||||
|
||||
pp_ca_r_thermal:SetTexture("$basetexture", render.GetScreenEffectTexture())
|
||||
pp_ca_g_thermal:SetTexture("$basetexture", render.GetScreenEffectTexture())
|
||||
pp_ca_b_thermal:SetTexture("$basetexture", render.GetScreenEffectTexture())
|
||||
|
||||
local greenColor = Color(0, 255, 0) -- optimized +10000fps
|
||||
local whiteColor = Color(255, 255, 255)
|
||||
local blackColor = Color(0, 0, 0)
|
||||
|
||||
local function DrawTexturedRectRotatedPoint( x, y, w, h, rot, x0, y0 ) -- stolen from gmod wiki
|
||||
local c = math.cos( math.rad( rot ) )
|
||||
local s = math.sin( math.rad( rot ) )
|
||||
|
||||
local newx = y0 * s - x0 * c
|
||||
local newy = y0 * c + x0 * s
|
||||
|
||||
surface.DrawTexturedRectRotated( x + newx, y + newy, w, h, rot )
|
||||
end
|
||||
|
||||
|
||||
local function IsWHOT(ent)
|
||||
if !ent:IsValid() or ent:IsWorld() then return false end
|
||||
|
||||
if ent:IsPlayer() then -- balling
|
||||
if ent.ArcticMedShots_ActiveEffects and ent.ArcticMedShots_ActiveEffects["coldblooded"] or ent:Health() <= 0 then return false end -- arc stims
|
||||
return true
|
||||
end
|
||||
|
||||
if ent:IsNPC() or ent:IsNextBot() then -- npcs
|
||||
if ent.ArcCWCLHealth and ent.ArcCWCLHealth <= 0 or ent:Health() <= 0 then return false end
|
||||
return true
|
||||
end
|
||||
|
||||
if ent:IsRagdoll() then -- ragdolling
|
||||
if !ent.ArcCW_ColdTime then ent.ArcCW_ColdTime = CurTime() + coldtime end
|
||||
return ent.ArcCW_ColdTime > CurTime()
|
||||
end
|
||||
|
||||
if ent:IsVehicle() or ent:IsOnFire() or ent.ArcCW_Hot or ent:IsScripted() and !ent:GetOwner():IsValid() then -- vroom vroom + :fire: + ents but not guns (guns on ground will be fine)
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:FormThermalImaging(tex)
|
||||
if !tex then
|
||||
tex = render.GetRenderTarget()
|
||||
end
|
||||
|
||||
render.PushRenderTarget(tex)
|
||||
|
||||
cam.Start3D()
|
||||
|
||||
if tex then
|
||||
colormod:SetTexture("$fbtexture", tex)
|
||||
else
|
||||
colormod:SetTexture("$fbtexture", render.GetScreenEffectTexture())
|
||||
end
|
||||
|
||||
local asight = self:GetActiveSights()
|
||||
|
||||
local nvsc = asight.ThermalScopeColor or whiteColor
|
||||
local tvsc = asight.ThermalHighlightColor or whiteColor
|
||||
|
||||
local tab = ents.GetAll()
|
||||
|
||||
-- table.Add(tab, player.GetAll())
|
||||
-- table.Add(tab, ents.FindByClass("npc_*"))
|
||||
|
||||
render.SetStencilEnable(true)
|
||||
render.SetStencilWriteMask(255)
|
||||
render.SetStencilTestMask(255)
|
||||
render.ClearStencil()
|
||||
|
||||
local sw = ScrH()
|
||||
local sh = sw
|
||||
|
||||
local sx = (ScrW() - sw) / 2
|
||||
local sy = (ScrH() - sh) / 2
|
||||
|
||||
render.SetScissorRect( sx, sy, sx + sw, sy + sh, true )
|
||||
|
||||
render.SetStencilReferenceValue(64)
|
||||
|
||||
render.SetStencilPassOperation(STENCIL_REPLACE)
|
||||
render.SetStencilFailOperation(STENCIL_KEEP)
|
||||
render.SetStencilZFailOperation(STENCIL_KEEP)
|
||||
render.SetStencilCompareFunction(STENCIL_ALWAYS)
|
||||
|
||||
for _, v in pairs(tab) do
|
||||
|
||||
if !IsWHOT(v) then continue end
|
||||
|
||||
if !asight.ThermalScopeSimple then
|
||||
render.SetBlend(0.5)
|
||||
render.SuppressEngineLighting(true)
|
||||
|
||||
render.SetColorModulation(250, 250, 250)
|
||||
|
||||
v:DrawModel()
|
||||
end
|
||||
end
|
||||
|
||||
render.SetColorModulation(1, 1, 1)
|
||||
|
||||
render.SuppressEngineLighting(false)
|
||||
|
||||
render.MaterialOverride()
|
||||
|
||||
render.SetBlend(1)
|
||||
|
||||
render.SetStencilCompareFunction(STENCIL_EQUAL)
|
||||
|
||||
if asight.ThermalScopeSimple then
|
||||
surface.SetDrawColor(255, 255, 255, 255)
|
||||
surface.DrawRect(0, 0, ScrW(), ScrH())
|
||||
end
|
||||
|
||||
DrawColorModify({
|
||||
["$pp_colour_addr"] = 0,
|
||||
["$pp_colour_addg"] = 0,
|
||||
["$pp_colour_addb"] = 0,
|
||||
["$pp_colour_brightness"] = 0,
|
||||
["$pp_colour_contrast"] = 1,
|
||||
["$pp_colour_colour"] = 0,
|
||||
["$pp_colour_mulr"] = 0,
|
||||
["$pp_colour_mulg"] = 0,
|
||||
["$pp_colour_mulb"] = 0
|
||||
})
|
||||
|
||||
DrawColorModify({
|
||||
["$pp_colour_addr"] = tvsc.r - 255,
|
||||
["$pp_colour_addg"] = tvsc.g - 255,
|
||||
["$pp_colour_addb"] = tvsc.b - 255,
|
||||
["$pp_colour_addr"] = 0,
|
||||
["$pp_colour_addg"] = 0,
|
||||
["$pp_colour_addb"] = 0,
|
||||
["$pp_colour_brightness"] = 0,
|
||||
["$pp_colour_contrast"] = 1,
|
||||
["$pp_colour_colour"] = 1,
|
||||
["$pp_colour_mulr"] = 0,
|
||||
["$pp_colour_mulg"] = 0,
|
||||
["$pp_colour_mulb"] = 0
|
||||
})
|
||||
|
||||
if !asight.ThermalNoCC then
|
||||
render.SetStencilCompareFunction(STENCIL_NOTEQUAL)
|
||||
render.SetStencilPassOperation(STENCIL_KEEP)
|
||||
|
||||
if !asight.ThermalFullColor then
|
||||
DrawColorModify({
|
||||
["$pp_colour_addr"] = 0,
|
||||
["$pp_colour_addg"] = 0,
|
||||
["$pp_colour_addb"] = 0,
|
||||
["$pp_colour_brightness"] = 0,
|
||||
["$pp_colour_contrast"] = 1,
|
||||
["$pp_colour_colour"] = 0,
|
||||
["$pp_colour_mulr"] = 0,
|
||||
["$pp_colour_mulg"] = 0,
|
||||
["$pp_colour_mulb"] = 0
|
||||
})
|
||||
end
|
||||
|
||||
if ArcCW.ConVars["thermalpp"]:GetBool() and ArcCW.ConVars["scopepp"]:GetBool() then
|
||||
-- chromatic abberation
|
||||
|
||||
render.CopyRenderTargetToTexture(render.GetScreenEffectTexture())
|
||||
|
||||
render.SetMaterial( pp_ca_base )
|
||||
render.DrawScreenQuad()
|
||||
render.SetMaterial( pp_ca_r_thermal )
|
||||
render.DrawScreenQuad()
|
||||
render.SetMaterial( pp_ca_g_thermal )
|
||||
render.DrawScreenQuad()
|
||||
render.SetMaterial( pp_ca_b_thermal )
|
||||
render.DrawScreenQuad()
|
||||
-- pasted here cause otherwise either target colors will get fucked either pp either motion blur
|
||||
end
|
||||
|
||||
DrawColorModify({
|
||||
["$pp_colour_addr"] = nvsc.r - 255,
|
||||
["$pp_colour_addg"] = nvsc.g - 255,
|
||||
["$pp_colour_addb"] = nvsc.b - 255,
|
||||
-- ["$pp_colour_addr"] = 0,
|
||||
-- ["$pp_colour_addg"] = 0,
|
||||
-- ["$pp_colour_addb"] = 0,
|
||||
["$pp_colour_brightness"] = asight.Brightness or 0.1,
|
||||
["$pp_colour_contrast"] = asight.Contrast or 0.5,
|
||||
["$pp_colour_colour"] = asight.Colormult or 1,
|
||||
["$pp_colour_mulr"] = 0,
|
||||
["$pp_colour_mulg"] = 0,
|
||||
["$pp_colour_mulb"] = 0
|
||||
})
|
||||
end
|
||||
|
||||
render.SetScissorRect( sx, sy, sx + sw, sy + sh, false )
|
||||
|
||||
render.SetStencilEnable(false)
|
||||
|
||||
colormod:SetTexture("$fbtexture", render.GetScreenEffectTexture())
|
||||
|
||||
cam.End3D()
|
||||
|
||||
if ArcCW.ConVars["thermalpp"]:GetBool() then
|
||||
if !render.SupportsPixelShaders_2_0() then return end
|
||||
|
||||
DrawSharpen(0.3,0.9)
|
||||
DrawBloom(0,0.3,5,5,3,0.5,1,1,1)
|
||||
-- DrawMotionBlur(0.7,1,1/(asight.FPSLock or 45)) -- upd i changed order and it fucking worked lmao //////i cant fucking understand why motionblur fucks render target
|
||||
end
|
||||
|
||||
render.PopRenderTarget()
|
||||
end
|
||||
|
||||
function SWEP:FormNightVision(tex)
|
||||
local asight = self:GetActiveSights()
|
||||
|
||||
local orig = colormod:GetTexture("$fbtexture")
|
||||
|
||||
colormod:SetTexture("$fbtexture", tex)
|
||||
|
||||
render.PushRenderTarget(tex)
|
||||
|
||||
local nvsc = asight.NVScopeColor or greenColor
|
||||
|
||||
if !asight.NVFullColor then
|
||||
DrawColorModify({
|
||||
["$pp_colour_addr"] = 0,
|
||||
["$pp_colour_addg"] = 0,
|
||||
["$pp_colour_addb"] = 0,
|
||||
["$pp_colour_brightness"] = 0,
|
||||
["$pp_colour_contrast"] = 1,
|
||||
["$pp_colour_colour"] = 0,
|
||||
["$pp_colour_mulr"] = 0,
|
||||
["$pp_colour_mulg"] = 0,
|
||||
["$pp_colour_mulb"] = 0
|
||||
})
|
||||
end
|
||||
|
||||
DrawColorModify({
|
||||
["$pp_colour_addr"] = nvsc.r - 255,
|
||||
["$pp_colour_addg"] = nvsc.g - 255,
|
||||
["$pp_colour_addb"] = nvsc.b - 255,
|
||||
["$pp_colour_brightness"] = asight.Brightness or -0.05,
|
||||
["$pp_colour_contrast"] = asight.Contrast or 4,
|
||||
["$pp_colour_colour"] = 1,
|
||||
["$pp_colour_mulr"] = 0,
|
||||
["$pp_colour_mulg"] = 0,
|
||||
["$pp_colour_mulb"] = 0
|
||||
})
|
||||
|
||||
render.PopRenderTarget()
|
||||
|
||||
colormod:SetTexture("$fbtexture", orig)
|
||||
end
|
||||
|
||||
local pp_cc_tab = {
|
||||
["$pp_colour_addr"] = 0,
|
||||
["$pp_colour_addg"] = 0,
|
||||
["$pp_colour_addb"] = 0,
|
||||
["$pp_colour_brightness"] = 0, -- why nothing works hh
|
||||
["$pp_colour_contrast"] = 0.9, -- but same time chroma dont work without calling it
|
||||
["$pp_colour_colour"] = 1,
|
||||
["$pp_colour_mulr"] = 0,
|
||||
["$pp_colour_mulg"] = 0,
|
||||
["$pp_colour_mulb"] = 0
|
||||
}
|
||||
|
||||
function SWEP:FormPP(tex)
|
||||
if !render.SupportsPixelShaders_2_0() then return end
|
||||
|
||||
local asight = self:GetActiveSights()
|
||||
|
||||
if asight.Thermal then return end -- eyah
|
||||
|
||||
local cs = ArcCW.ConVars["cheapscopes"]:GetBool()
|
||||
local refract = ArcCW.ConVars["scopepp_refract"]:GetBool()
|
||||
local pp = ArcCW.ConVars["scopepp"]:GetBool()
|
||||
|
||||
|
||||
if refract or pp then
|
||||
if !cs then render.PushRenderTarget(tex) end
|
||||
render.CopyRenderTargetToTexture(render.GetScreenEffectTexture())
|
||||
|
||||
if pp then
|
||||
render.SetMaterial( pp_ca_base )
|
||||
render.DrawScreenQuad()
|
||||
render.SetMaterial( pp_ca_r )
|
||||
render.DrawScreenQuad()
|
||||
render.SetMaterial( pp_ca_g )
|
||||
render.DrawScreenQuad()
|
||||
render.SetMaterial( pp_ca_b )
|
||||
render.DrawScreenQuad()
|
||||
-- Color modify
|
||||
|
||||
DrawColorModify( pp_cc_tab )
|
||||
-- Sharpen
|
||||
DrawSharpen(-0.1, 5) -- dont work for some reason
|
||||
end
|
||||
|
||||
if refract then
|
||||
local addads = math.Clamp(additionalFOVconvar:GetFloat(), -2, 14)
|
||||
local refractratio = ArcCW.ConVars["scopepp_refract_ratio"]:GetFloat() or 0
|
||||
local refractamount = (-0.6 + addads / 30) * refractratio
|
||||
local refractmat = cs and matRefract_cheap or matRefract
|
||||
|
||||
refractmat:SetFloat( "$refractamount", refractamount )
|
||||
|
||||
render.SetMaterial(refractmat)
|
||||
render.DrawScreenQuad()
|
||||
end
|
||||
|
||||
if !cs then render.PopRenderTarget() end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:FormCheapScope()
|
||||
local screen = render.GetRenderTarget()
|
||||
|
||||
render.CopyTexture( screen, rtmat_spare )
|
||||
|
||||
render.PushRenderTarget(screen)
|
||||
cam.Start3D(EyePos(), EyeAngles(), nil, nil, nil, nil, nil, 0, nil)
|
||||
ArcCW.LaserBehavior = true
|
||||
self:DoLaser(false)
|
||||
ArcCW.LaserBehavior = false
|
||||
cam.End3D()
|
||||
|
||||
self:FormPP(screen)
|
||||
|
||||
render.PopRenderTarget()
|
||||
|
||||
-- so, in order to avoid the fact that copying RTs doesn't transfer depth buffer data, we just take the screen texture and...
|
||||
-- redraw it to cover up the thermal scope stuff. Don't think too hard about this. You have plenty of VRAM.
|
||||
|
||||
local asight = self:GetActiveSights()
|
||||
|
||||
if asight.Thermal then
|
||||
self:FormThermalImaging(screen)
|
||||
end
|
||||
|
||||
if asight.SpecialScopeFunction then
|
||||
asight.SpecialScopeFunction(screen)
|
||||
end
|
||||
|
||||
-- integrated render delay for better optimization
|
||||
if asight.FPSLock then
|
||||
asight.fpsdelay = CurTime() + 1 / (asight.FPSLock or 45)
|
||||
end
|
||||
|
||||
render.CopyTexture( screen, rtmat_cheap )
|
||||
|
||||
render.DrawTextureToScreen(rtmat_spare)
|
||||
|
||||
render.UpdateFullScreenDepthTexture()
|
||||
end
|
||||
|
||||
function SWEP:FormRTScope()
|
||||
local asight = self:GetActiveSights()
|
||||
|
||||
if !asight then return end
|
||||
|
||||
if !asight.MagnifiedOptic then return end
|
||||
|
||||
local mag = asight.ScopeMagnification
|
||||
|
||||
cam.Start3D()
|
||||
|
||||
ArcCW.Overdraw = true
|
||||
ArcCW.LaserBehavior = true
|
||||
ArcCW.VMInRT = true
|
||||
|
||||
local rtangles, rtpos, rtdrawvm
|
||||
|
||||
if self:GetState() == ArcCW.STATE_SIGHTS then
|
||||
if ArcCW.ConVars["drawbarrel"]:GetBool() and ArcCW.ConVars["vm_coolsway"]:GetBool() and asight.Slot and asight.Slot == 1 then -- slot check to ignore integrated
|
||||
rtangles = self.VMAng - self.VMAngOffset - (self:GetOurViewPunchAngles() * mag * 0.1)
|
||||
rtangles.x = rtangles.x - self.VMPosOffset_Lerp.z * 10
|
||||
rtangles.y = rtangles.y + self.VMPosOffset_Lerp.y * 10
|
||||
|
||||
rtpos = self.VMPos + self.VMAng:Forward() * (asight.EVPos.y + 7 + (asight.ScopeMagnificationMax and asight.ScopeMagnificationMax / 3 or asight.HolosightData.HolosightMagnification / 3)) -- eh
|
||||
rtdrawvm = true
|
||||
else
|
||||
rtangles = EyeAngles()
|
||||
rtpos = EyePos()
|
||||
rtdrawvm = false
|
||||
|
||||
-- HACK HACK HACK HACK HACK
|
||||
-- If we do not draw the viewmodel in RT scope, calling GetAttachment on the vm seems to break LHIK.
|
||||
-- So... just draw it! The results gets drawn over again so it doesn't affect the outcome
|
||||
render.RenderView({drawviewmodel = true}) -- ?????
|
||||
end
|
||||
end
|
||||
|
||||
local addads = math.Clamp(additionalFOVconvar:GetFloat(), -2, 14)
|
||||
|
||||
local rt = {
|
||||
w = rtsize,
|
||||
h = rtsize,
|
||||
angles = rtangles,
|
||||
origin = rtpos,
|
||||
drawviewmodel = rtdrawvm,
|
||||
fov = self:GetOwner():GetFOV() / mag / 1.2 - (addads or 0) / 4,
|
||||
}
|
||||
|
||||
rtsize = ScrH()
|
||||
|
||||
if ScrH() > ScrW() then rtsize = ScrW() end
|
||||
|
||||
local rtres = asight.ForceLowRes and ScrH() * 0.6 or ScrH() -- we can emit low res lcd displays for scopes
|
||||
|
||||
rtmat = GetRenderTarget("arccw_rtmat" .. rtres, rtres, rtres, false)
|
||||
|
||||
render.PushRenderTarget(rtmat, 0, 0, rtsize, rtsize)
|
||||
|
||||
render.ClearRenderTarget(rt, blackColor)
|
||||
|
||||
if self:GetState() == ArcCW.STATE_SIGHTS then
|
||||
render.RenderView(rt)
|
||||
cam.Start3D(EyePos(), EyeAngles(), rt.fov, 0, 0, nil, nil, 0, nil)
|
||||
self:DoLaser(false)
|
||||
cam.End3D()
|
||||
end
|
||||
|
||||
ArcCW.Overdraw = false
|
||||
ArcCW.LaserBehavior = false
|
||||
ArcCW.VMInRT = false
|
||||
|
||||
self:FormPP(rtmat)
|
||||
|
||||
render.PopRenderTarget()
|
||||
|
||||
cam.End3D()
|
||||
|
||||
if asight.Thermal then
|
||||
self:FormThermalImaging(rtmat)
|
||||
end
|
||||
|
||||
if asight.SpecialScopeFunction then
|
||||
asight.SpecialScopeFunction(rtmat)
|
||||
end
|
||||
|
||||
-- integrated render delay for better optimization
|
||||
if asight.FPSLock then
|
||||
asight.fpsdelay = CurTime() + 1 / (asight.FPSLock or 45)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- local fpsdelay = CurTime()
|
||||
|
||||
hook.Add("RenderScene", "ArcCW", function()
|
||||
if ArcCW.ConVars["cheapscopes"]:GetBool() then return end
|
||||
|
||||
local wpn = LocalPlayer():GetActiveWeapon()
|
||||
|
||||
if !wpn.ArcCW then return end
|
||||
if wpn:GetActiveSights() and wpn:GetActiveSights().FPSLock
|
||||
and (wpn:GetActiveSights().fpsdelay or 0) > CurTime() then
|
||||
return
|
||||
end
|
||||
wpn:FormRTScope()
|
||||
end)
|
||||
|
||||
local black = Material("arccw/hud/black.png")
|
||||
local defaultdot = Material("arccw/hud/hit_dot.png")
|
||||
|
||||
function SWEP:DrawHolosight(hs, hsm, hsp, asight)
|
||||
-- holosight structure
|
||||
-- holosight model
|
||||
|
||||
local ref = 32
|
||||
|
||||
asight = asight or self:GetActiveSights()
|
||||
local delta = self:GetSightDelta()
|
||||
|
||||
if asight.HolosightData then
|
||||
hs = asight.HolosightData
|
||||
end
|
||||
|
||||
if self:GetState() != ArcCW.STATE_SIGHTS and delta > 0.5 or self:GetBarrelNearWall() > 0 then return end
|
||||
|
||||
if !hs then return end
|
||||
|
||||
if delta != 0 and ArcCW.ConVars["scopepp"]:GetBool() then
|
||||
pp_ca_r:SetVector("$color2", Vector(1-delta, 0, 0))
|
||||
pp_ca_g:SetVector("$color2", Vector(0, 1-delta, 0))
|
||||
pp_ca_b:SetVector("$color2", Vector(0, 0, 1-delta))
|
||||
pp_ca_base:SetFloat("$alpha", 1-delta)
|
||||
end
|
||||
|
||||
local hsc = Color(255, 255, 255) -- putting here global or white local SOMEHOW FUCKS IT EVEN GLOBAL BEING FUCKED WTF I HATE
|
||||
|
||||
if hs.Colorable then
|
||||
hsc.r = ArcCW.ConVars["scope_r"]:GetInt()
|
||||
hsc.g = ArcCW.ConVars["scope_g"]:GetInt()
|
||||
hsc.b = ArcCW.ConVars["scope_b"]:GetInt()
|
||||
else
|
||||
hsc = hs.HolosightColor or hsc
|
||||
end
|
||||
|
||||
local attid = 0
|
||||
|
||||
if hsm then
|
||||
|
||||
attid = hsm:LookupAttachment(asight.HolosightBone or hs.HolosightBone or "holosight")
|
||||
|
||||
if attid == 0 then
|
||||
attid = hsm:LookupAttachment("holosight")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local ret, pos, ang
|
||||
|
||||
if attid != 0 then
|
||||
|
||||
ret = hsm:GetAttachment(attid)
|
||||
pos = ret.Pos
|
||||
ang = ret.Ang
|
||||
|
||||
else
|
||||
|
||||
pos = EyePos()
|
||||
ang = EyeAngles()
|
||||
|
||||
end
|
||||
|
||||
local hsmag = asight.ScopeMagnification or 1
|
||||
|
||||
local size = hs.HolosightSize or 1
|
||||
|
||||
local addads = math.Clamp(additionalFOVconvar:GetFloat(), -2, 14)
|
||||
|
||||
local addconvar = asight.MagnifiedOptic and (addads or 0) or 0
|
||||
|
||||
size = size + addconvar + (addconvar > 5.5 and (addconvar-5.5) * 2 or 0)
|
||||
|
||||
|
||||
-- if asight.NightVision then
|
||||
|
||||
if hsmag and hsmag > 1 and delta < 1 and asight.NVScope then
|
||||
local screen = rtmat
|
||||
|
||||
if ArcCW.ConVars["cheapscopes"]:GetBool() then
|
||||
screen = rtmat_cheap
|
||||
end
|
||||
|
||||
if asight.NVScope then
|
||||
self:FormNightVision(screen)
|
||||
end
|
||||
end
|
||||
|
||||
render.UpdateScreenEffectTexture()
|
||||
render.ClearStencil()
|
||||
render.SetStencilEnable(true)
|
||||
render.SetStencilCompareFunction(STENCIL_ALWAYS)
|
||||
render.SetStencilPassOperation(STENCIL_REPLACE)
|
||||
render.SetStencilFailOperation(STENCIL_KEEP)
|
||||
render.SetStencilZFailOperation(STENCIL_REPLACE)
|
||||
render.SetStencilWriteMask(255)
|
||||
render.SetStencilTestMask(255)
|
||||
|
||||
render.SetBlend(0)
|
||||
|
||||
render.SetStencilReferenceValue(ref)
|
||||
|
||||
ArcCW.Overdraw = true
|
||||
|
||||
render.OverrideDepthEnable( true, true )
|
||||
|
||||
if !hsm then
|
||||
hsp:DrawModel()
|
||||
else
|
||||
|
||||
hsm:SetBodygroup(1, 0)
|
||||
|
||||
if !hsp or hs.HolosightNoHSP then
|
||||
hsm:DrawModel()
|
||||
end
|
||||
|
||||
-- render.MaterialOverride()
|
||||
|
||||
render.SetStencilReferenceValue(0)
|
||||
|
||||
hsm:SetBodygroup(1, 1)
|
||||
-- hsm:SetSubMaterial(0, "dev/no_pixel_write")
|
||||
hsm:DrawModel()
|
||||
-- hsm:SetSubMaterial()
|
||||
hsm:SetBodygroup(1, 0)
|
||||
|
||||
-- local vm = self:GetOwner():GetViewModel()
|
||||
|
||||
-- ArcCW.Overdraw = true
|
||||
-- vm:DrawModel()
|
||||
|
||||
-- ArcCW.Overdraw = false
|
||||
|
||||
render.SetStencilReferenceValue(ref)
|
||||
|
||||
if hsp then
|
||||
hsp:DrawModel()
|
||||
end
|
||||
end
|
||||
|
||||
-- render.MaterialOverride()
|
||||
|
||||
render.OverrideDepthEnable( false, true )
|
||||
|
||||
ArcCW.Overdraw = false
|
||||
|
||||
render.SetBlend(1)
|
||||
|
||||
render.SetStencilPassOperation(STENCIL_REPLACE)
|
||||
render.SetStencilCompareFunction(STENCIL_EQUAL)
|
||||
|
||||
-- local pos = EyePos()
|
||||
-- local ang = EyeAngles()
|
||||
|
||||
ang:RotateAroundAxis(ang:Forward(), -90)
|
||||
|
||||
local dir = ang:Up()
|
||||
|
||||
local pdiff = (pos - EyePos()):Length()
|
||||
|
||||
pos = LerpVector(delta, EyePos(), pos)
|
||||
|
||||
local eyeangs = self:GetOwner():EyeAngles() - self:GetOurViewPunchAngles() * hsmag * 0.1
|
||||
|
||||
-- local vm = hsm or hsp
|
||||
|
||||
-- eyeangs = eyeangs + (eyeangs - vm:GetAngles())
|
||||
|
||||
dir = LerpVector(delta, eyeangs:Forward(), dir:GetNormalized())
|
||||
|
||||
pdiff = Lerp(delta, pdiff, 0)
|
||||
|
||||
local d = (8 + pdiff)
|
||||
|
||||
d = hs.HolosightConstDist or d
|
||||
|
||||
local vmscale = (self.Attachments[asight.Slot] or {}).VMScale or Vector(1, 1, 1)
|
||||
|
||||
if hs.HolosightConstDist then
|
||||
vmscale = Vector(1, 1, 1)
|
||||
end
|
||||
|
||||
local hsx = vmscale[2] or 1
|
||||
local hsy = vmscale[3] or 1
|
||||
|
||||
pos = pos + (dir * d)
|
||||
|
||||
local pos2 = pos + (dir * -8)
|
||||
|
||||
local a = self:GetOwner():InVehicle() and {x = ScrW() / 2, y = ScrH() / 2} or pos:ToScreen()
|
||||
local x = a.x - (self.VMAngOffset.y - self.VMPosOffset_Lerp.y * 10) * (hsmag * 1.5) ^ 2
|
||||
local y = a.y + (self.VMAngOffset.x * 5 + self.VMPosOffset_Lerp.z * 10) * (hsmag * 1.5) ^ 2
|
||||
|
||||
local a2 = self:GetOwner():InVehicle() and {x = ScrW() / 2, y = ScrH() / 2} or pos2:ToScreen()
|
||||
|
||||
local off_x = a2.x - (ScrW() / 2)
|
||||
local off_y = a2.y - (ScrH() / 2)
|
||||
|
||||
--pos = pos + Vector(ArcCW.StrafeTilt(self), 0, 0)
|
||||
|
||||
-- local corner1, corner2, corner3, corner4
|
||||
|
||||
-- corner2 = pos + (ang:Right() * (-0.5 * size)) + (ang:Forward() * (0.5 * size))
|
||||
-- corner1 = pos + (ang:Right() * (-0.5 * size)) + (ang:Forward() * (-0.5 * size))
|
||||
-- corner4 = pos + (ang:Right() * (0.5 * size)) + (ang:Forward() * (-0.5 * size))
|
||||
-- corner3 = pos + (ang:Right() * (0.5 * size)) + (ang:Forward() * (0.5 * size))
|
||||
|
||||
-- render.SetColorMaterialIgnoreZ()
|
||||
-- render.DrawScreenQuad()
|
||||
|
||||
-- render.SetStencilEnable( false )
|
||||
-- local fovmag = asight.Magnification or 1
|
||||
|
||||
if hsmag and hsmag > 1 and delta < 1 then
|
||||
local screen = rtmat
|
||||
|
||||
-- local sw2 = ScrH()
|
||||
-- local sh2 = sw2
|
||||
|
||||
-- local sx2 = (ScrW() - sw2) / 2
|
||||
-- local sy2 = (ScrH() - sh2) / 2
|
||||
|
||||
-- render.SetScissorRect( sx2, sy2, sx2 + sw2, sy2 + sh2, true )
|
||||
|
||||
if render.GetHDREnabled() and delta < 0.07 then
|
||||
render.SetToneMappingScaleLinear(Vector(1,1,1)) -- hdr fix
|
||||
end
|
||||
|
||||
if ArcCW.ConVars["cheapscopes"]:GetBool() then
|
||||
|
||||
screen = rtmat_cheap
|
||||
|
||||
local addads = math.Clamp(additionalFOVconvar:GetFloat(), -2, 14)
|
||||
local csratio = math.Clamp(GetConVar("arccw_cheapscopesv2_ratio"):GetFloat(), 0, 1)
|
||||
|
||||
local ssmag = 1 + csratio * hsmag + (addads or 0) / 20 -- idk why 20
|
||||
local sw = ScrW() * ssmag
|
||||
local sh = ScrH() * ssmag
|
||||
|
||||
-- local sx = -(sw - ScrW()) / 2
|
||||
-- local sy = -(sh - ScrH()) / 2
|
||||
|
||||
local cpos = self:GetOwner():EyePos() + ((EyeAngles() + (self:GetOurViewPunchAngles() * 0.5)):Forward() * 2048)
|
||||
|
||||
--cpos:Rotate(Angle(0, -ArcCW.StrafeTilt(self), 0))
|
||||
|
||||
local ts = self:GetOwner():InVehicle() and {x = ScrW() / 2, y = ScrH() / 2} or cpos:ToScreen()
|
||||
|
||||
local sx = ts.x - (sw / 2) - off_x - (self.VMAngOffset.y - self.VMPosOffset_Lerp.y * 15) * (hsmag * 1) ^ 2
|
||||
local sy = ts.y - (sh / 2) - off_y + (self.VMAngOffset.x * 5 + self.VMPosOffset_Lerp.z * 15) * (hsmag * 1) ^ 2
|
||||
|
||||
render.SetMaterial(black)
|
||||
render.DrawScreenQuad()
|
||||
|
||||
render.DrawTextureToScreenRect(screen, sx, sy, sw, sh)
|
||||
|
||||
else
|
||||
|
||||
local sw = ScrH()
|
||||
local sh = sw
|
||||
|
||||
local sx = ((ScrW() - sw) / 2) - off_x
|
||||
local sy = ((ScrH() - sh) / 2) - off_x
|
||||
|
||||
render.SetMaterial(black)
|
||||
render.DrawScreenQuad()
|
||||
|
||||
render.DrawTextureToScreenRect(screen, sx, sy, sw, sh)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
-- cam.Start3D()
|
||||
|
||||
-- render.SetColorMaterialIgnoreZ()
|
||||
-- render.DrawScreenQuad()
|
||||
|
||||
-- render.DrawQuad( corner1, corner2, corner3, corner4, hsc or hs.HolosightColor )
|
||||
cam.IgnoreZ( true )
|
||||
|
||||
render.SetStencilReferenceValue(ref)
|
||||
|
||||
-- render.SetMaterial(hs.HolosightReticle or defaultdot)
|
||||
-- render.DrawSprite( pos, size * hsx, size * hsy, hsc or Color(255, 255, 255) )
|
||||
-- if !hs.HolosightNoFlare then
|
||||
-- render.SetMaterial(hs.HolosightFlare or hs.HolosightReticle or defaultdot)
|
||||
-- local hss = 0.75
|
||||
-- if hs.HolosightFlare then
|
||||
-- hss = 1
|
||||
-- end
|
||||
-- render.DrawSprite( pos, size * hss * hsx, size * hss * hsy, Color(255, 255, 255, 255) )
|
||||
-- end
|
||||
|
||||
cam.Start2D()
|
||||
|
||||
if hs.HolosightBlackbox then
|
||||
render.SetStencilPassOperation(STENCIL_KEEP)
|
||||
|
||||
surface.SetDrawColor(0, 0, 0, 255 * delta)
|
||||
surface.DrawRect(0, 0, ScrW(), ScrH())
|
||||
end
|
||||
|
||||
render.SetStencilPassOperation(STENCIL_DECR)
|
||||
render.SetStencilCompareFunction(STENCIL_EQUAL)
|
||||
|
||||
local hss = size * 32 * math.min(ScrW(), ScrH()) / 800
|
||||
|
||||
--local thej = self.TheJ.anga + LocalPlayer():GetViewPunchAngles() + self:GetOurViewPunchAngles()
|
||||
-- AYE, UR ACTIVE ANG BEIN TWISTED DUNT GIVE AUH SHET
|
||||
|
||||
surface.SetMaterial(hs.HolosightReticle or defaultdot)
|
||||
surface.SetDrawColor(hsc or 255, 255, 255)
|
||||
-- surface.DrawTexturedRect(x - (hss / 2), y - (hss / 2), hss, hss)
|
||||
|
||||
DrawTexturedRectRotatedPoint(x, y, hss, hss, -(self.VMAngOffset.r+self.VMAngOffset_Lerp.r+self:GetOurViewPunchAngles().r)*5 , 0, 0)
|
||||
|
||||
if !hs.HolosightNoFlare then
|
||||
render.SetStencilPassOperation(STENCIL_KEEP)
|
||||
render.SetStencilReferenceValue(ref - 1)
|
||||
surface.SetMaterial(hs.HolosightFlare or hs.HolosightReticle or defaultdot)
|
||||
surface.SetDrawColor(255, 255, 255, 150)
|
||||
|
||||
local hss2 = hss
|
||||
|
||||
if !hs.HolosightFlare then
|
||||
hss2 = hss - 2
|
||||
end
|
||||
|
||||
surface.DrawTexturedRect(x - (hss2 / 2), y - (hss2 / 2), hss2, hss2)
|
||||
--surface.DrawTexturedRectRotated(x, y, hss2, hss2, -thej.r or 0)
|
||||
|
||||
render.SetStencilReferenceValue(ref)
|
||||
end
|
||||
|
||||
if hs.HolosightBlackbox then
|
||||
-- render.SetColorMaterialIgnoreZ()
|
||||
-- render.DrawScreenQuad()
|
||||
|
||||
surface.SetDrawColor(0, 0, 0)
|
||||
surface.DrawRect(0, 0, ScrW(), ScrH())
|
||||
-- surface.DrawRect(0, (ScrH() - hss) / 2, ScrW(), (ScrH() - hss) / 2)
|
||||
end
|
||||
|
||||
cam.End2D()
|
||||
|
||||
render.SetStencilEnable( false )
|
||||
|
||||
cam.IgnoreZ( false )
|
||||
|
||||
-- cam.End3D()
|
||||
|
||||
if hsp then
|
||||
|
||||
cam.IgnoreZ(true)
|
||||
|
||||
if ArcCW.ConVars["glare"]:GetBool() then
|
||||
render.SetBlend(delta + 0.1)
|
||||
else
|
||||
render.SetBlend(delta)
|
||||
end
|
||||
hsp:DrawModel()
|
||||
render.SetBlend(1)
|
||||
|
||||
cam.IgnoreZ( false )
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- I wanted to make here procedural normal map for refract using rt but steamsnooze
|
||||
|
||||
|
||||
-- local TEX_SIZE = 512
|
||||
|
||||
-- local tex = GetRenderTarget( "ExampleRT", TEX_SIZE, TEX_SIZE )
|
||||
|
||||
-- local txBackground = surface.GetTextureID( "pp/arccw/lense_nrm2" )
|
||||
-- local myMat = CreateMaterial( "ExampleRTMat3", "UnlitGeneric", {
|
||||
-- ["$basetexture"] = tex:GetName() -- Make the material use our render target texture
|
||||
-- } )
|
||||
|
||||
-- hook.Add( "HUDPaint", "DrawExampleMat", function()
|
||||
-- render.PushRenderTarget( tex )
|
||||
-- cam.Start2D()
|
||||
|
||||
-- surface.SetDrawColor( 128,128,255 )
|
||||
-- surface.DrawRect(0,0,TEX_SIZE, TEX_SIZE)
|
||||
-- surface.SetDrawColor( color_white )
|
||||
-- surface.SetTexture( txBackground )
|
||||
-- local joke = math.sin(CurTime()*5)/4
|
||||
|
||||
-- surface.DrawTexturedRect( TEX_SIZE/4-joke/2, TEX_SIZE/4-joke/2, TEX_SIZE/2+joke, TEX_SIZE/2+joke )
|
||||
|
||||
-- cam.End2D()
|
||||
-- render.PopRenderTarget()
|
||||
-- surface.SetDrawColor( color_white )
|
||||
-- surface.SetMaterial( myMat )
|
||||
-- surface.DrawTexturedRect( 25, 25, TEX_SIZE, TEX_SIZE )
|
||||
-- print()
|
||||
-- DrawTexturedRectRotatedPoint(250+250/2,250+250/2,250,250,(CurTime()%360)*50,0,0)
|
||||
-- surface.DrawRect(250,250,250,250)
|
||||
|
||||
-- end )
|
||||
1205
lua/weapons/arccw_base/cl_hud.lua
Normal file
1205
lua/weapons/arccw_base/cl_hud.lua
Normal file
File diff suppressed because it is too large
Load Diff
199
lua/weapons/arccw_base/cl_laser.lua
Normal file
199
lua/weapons/arccw_base/cl_laser.lua
Normal file
@@ -0,0 +1,199 @@
|
||||
--[[
|
||||
| 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 mth = math
|
||||
local m_log10 = mth.log10
|
||||
local m_rand = mth.Rand
|
||||
local rnd = render
|
||||
local SetMat = rnd.SetMaterial
|
||||
local DrawBeam = rnd.DrawBeam
|
||||
local DrawSprite = rnd.DrawSprite
|
||||
local cam = cam
|
||||
|
||||
local lasermat = Material("arccw/laser")
|
||||
local flaremat = Material("effects/whiteflare")
|
||||
local delta = 1
|
||||
|
||||
function SWEP:DoLaser(world, nocontext)
|
||||
world = world or false
|
||||
|
||||
if !nocontext then
|
||||
if world then
|
||||
cam.Start3D()
|
||||
else
|
||||
cam.Start3D(EyePos(), EyeAngles(), self:QuickFOVix(self.CurrentViewModelFOV))
|
||||
end
|
||||
end
|
||||
|
||||
for slot, k in pairs(self.Attachments) do
|
||||
if !k.Installed then continue end
|
||||
|
||||
local attach = ArcCW.AttachmentTable[k.Installed]
|
||||
|
||||
if self:GetBuff_Stat("Laser", slot) then
|
||||
local color = self:GetBuff_Stat("LaserColor", slot) or attach.ColorOptionsTable[k.ColorOptionIndex or 1]
|
||||
|
||||
if world then
|
||||
if !k.WElement then continue end
|
||||
self:DrawLaser(attach, k.WElement.Model, color, true)
|
||||
else
|
||||
if !k.VElement then continue end
|
||||
self:DrawLaser(attach, k.VElement.Model, color)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.Lasers then
|
||||
if world then
|
||||
for _, k in pairs(self.Lasers) do
|
||||
self:DrawLaser(k, self.WMModel or self, k.LaserColor, true)
|
||||
end
|
||||
else
|
||||
-- cam.Start3D(nil, nil, self.ViewmodelFOV)
|
||||
for _, k in pairs(self.Lasers) do
|
||||
self:DrawLaser(k, self:GetOwner():GetViewModel(), k.LaserColor)
|
||||
end
|
||||
-- cam.End3D()
|
||||
end
|
||||
end
|
||||
|
||||
if !nocontext then
|
||||
cam.End3D()
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:DrawLaser(laser, model, color, world)
|
||||
local owner = self:GetOwner()
|
||||
local behav = ArcCW.LaserBehavior
|
||||
|
||||
if !owner then return end
|
||||
|
||||
if !IsValid(owner) then return end
|
||||
|
||||
if !model then return end
|
||||
|
||||
if !IsValid(model) then return end
|
||||
|
||||
local att = model:LookupAttachment(laser.LaserBone or "laser")
|
||||
|
||||
att = att == 0 and model:LookupAttachment("muzzle") or att
|
||||
|
||||
local pos, ang, dir
|
||||
|
||||
if att == 0 then
|
||||
pos = model:GetPos()
|
||||
ang = owner:EyeAngles() + self:GetFreeAimOffset()
|
||||
dir = ang:Forward()
|
||||
else
|
||||
local attdata = model:GetAttachment(att)
|
||||
pos, ang = attdata.Pos, attdata.Ang
|
||||
dir = -ang:Right()
|
||||
end
|
||||
|
||||
if world then
|
||||
dir = owner:IsNPC() and (-ang:Right()) or dir
|
||||
else
|
||||
ang:RotateAroundAxis(ang:Up(), 90)
|
||||
|
||||
if self.LaserOffsetAngle then
|
||||
ang:RotateAroundAxis(ang:Right(), self.LaserOffsetAngle[1])
|
||||
ang:RotateAroundAxis(ang:Up(), self.LaserOffsetAngle[2])
|
||||
ang:RotateAroundAxis(ang:Forward(), self.LaserOffsetAngle[3])
|
||||
end
|
||||
if self.LaserIronsAngle and self:GetActiveSights().IronSight then
|
||||
local d = 1 - self:GetSightDelta()
|
||||
ang:RotateAroundAxis(ang:Right(), d * self.LaserIronsAngle[1])
|
||||
ang:RotateAroundAxis(ang:Up(), d * self.LaserIronsAngle[2])
|
||||
ang:RotateAroundAxis(ang:Forward(), d * self.LaserIronsAngle[3])
|
||||
end
|
||||
|
||||
dir = ang:Forward()
|
||||
|
||||
local eyeang = EyeAngles() - self:GetOurViewPunchAngles() + self:GetFreeAimOffset()
|
||||
local canlaser = self:GetCurrentFiremode().Mode != 0 and !self:GetReloading() and self:BarrelHitWall() <= 0
|
||||
|
||||
delta = Lerp(0, delta, canlaser and self:GetSightDelta() or 1)
|
||||
|
||||
if self.GuaranteeLaser then
|
||||
delta = 1
|
||||
else
|
||||
delta = self:GetSightDelta()
|
||||
end
|
||||
|
||||
dir = Lerp(delta, eyeang:Forward(), dir)
|
||||
end
|
||||
|
||||
local beamdir, tracepos = dir, pos
|
||||
|
||||
beamdir = world and (-ang:Right()) or beamdir
|
||||
|
||||
if behav and !world then
|
||||
-- local cheap = ArcCW.ConVars["cheapscopes"]:GetBool()
|
||||
local punch = self:GetOurViewPunchAngles()
|
||||
|
||||
ang = EyeAngles() - punch + self:GetFreeAimOffset()
|
||||
|
||||
tracepos = EyePos() - Vector(0, 0, 1)
|
||||
pos, dir = tracepos, ang:Forward()
|
||||
beamdir = dir
|
||||
end
|
||||
|
||||
local dist = 128
|
||||
|
||||
local tl = {}
|
||||
tl.start = tracepos
|
||||
tl.endpos = tracepos + (dir * 33000)
|
||||
tl.filter = owner
|
||||
|
||||
local tr = util.TraceLine(tl)
|
||||
|
||||
tl.endpos = tracepos + (beamdir * dist)
|
||||
|
||||
local btr = util.TraceLine(tl)
|
||||
|
||||
local hit = tr.Hit
|
||||
local hitpos = tr.HitPos
|
||||
local solid = tr.StartSolid
|
||||
|
||||
local strength = laser.LaserStrength or 1
|
||||
local laserpos = solid and tr.StartPos or hitpos
|
||||
|
||||
laserpos = laserpos - ((EyeAngles() + self:GetFreeAimOffset()):Forward())
|
||||
|
||||
if solid then return end
|
||||
|
||||
local width = m_rand(0.05, 0.1) * strength * 1
|
||||
|
||||
if (!behav or world) and hit then
|
||||
SetMat(lasermat)
|
||||
local a = 200
|
||||
DrawBeam(pos, btr.HitPos, width * 0.3, 1, 0, Color(a, a, a, a))
|
||||
DrawBeam(pos, btr.HitPos, width, 1, 0, color)
|
||||
end
|
||||
|
||||
if hit and !tr.HitSky then
|
||||
local mul = 1 * strength
|
||||
mul = m_log10((hitpos - EyePos()):Length()) * strength
|
||||
local rad = m_rand(4, 6) * mul
|
||||
local glr = rad * m_rand(0.2, 0.3)
|
||||
|
||||
SetMat(flaremat)
|
||||
|
||||
-- if !world then
|
||||
-- cam.IgnoreZ(true)
|
||||
-- end
|
||||
DrawSprite(laserpos, rad, rad, color)
|
||||
DrawSprite(laserpos, glr, glr, color_white)
|
||||
|
||||
-- if !world then
|
||||
-- cam.IgnoreZ(false)
|
||||
-- end
|
||||
end
|
||||
end
|
||||
402
lua/weapons/arccw_base/cl_lhik.lua
Normal file
402
lua/weapons/arccw_base/cl_lhik.lua
Normal file
@@ -0,0 +1,402 @@
|
||||
--[[
|
||||
| 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 function qerp(delta, a, b)
|
||||
local qdelta = -(delta ^ 2) + (delta * 2)
|
||||
|
||||
qdelta = math.Clamp(qdelta, 0, 1)
|
||||
|
||||
return Lerp(qdelta, a, b)
|
||||
end
|
||||
|
||||
SWEP.LHIKAnimation_IsIdle = false
|
||||
SWEP.LHIKAnimation = nil
|
||||
SWEP.LHIKAnimationStart = 0
|
||||
SWEP.LHIKAnimationTime = 0
|
||||
|
||||
SWEP.LHIKCamAng = Angle(0, 0, 0)
|
||||
SWEP.LHIKGunAng = Angle(0, 0, 0)
|
||||
|
||||
function SWEP:DoLHIKAnimation(key, time, spbitch)
|
||||
if !IsValid(self:GetOwner()) then return end
|
||||
|
||||
if game.SinglePlayer() and !spbitch then
|
||||
timer.Simple(0, function() if IsValid(self) then self:DoLHIKAnimation(key, time, true) end end)
|
||||
return
|
||||
end
|
||||
|
||||
local vm = self:GetOwner():GetViewModel()
|
||||
if !IsValid(vm) then return end
|
||||
|
||||
local lhik_model
|
||||
local lhik_anim_model
|
||||
local LHIK_GunDriver
|
||||
local LHIK_CamDriver
|
||||
local offsetang
|
||||
|
||||
local tranim = self:GetBuff_Hook("Hook_LHIK_TranslateAnimation", key)
|
||||
|
||||
key = tranim or key
|
||||
|
||||
for i, k in pairs(self.Attachments) do
|
||||
if !k.Installed then continue end
|
||||
if !k.VElement then continue end
|
||||
|
||||
if self:GetBuff_Stat("LHIK", i) then
|
||||
lhik_model = k.VElement.Model
|
||||
lhik_anim_model = k.GodDriver and k.GodDriver.Model or false
|
||||
offsetang = k.VElement.OffsetAng
|
||||
|
||||
if self:GetBuff_Stat("LHIK_GunDriver", i) then
|
||||
LHIK_GunDriver = self:GetBuff_Stat("LHIK_GunDriver", i)
|
||||
end
|
||||
|
||||
if self:GetBuff_Stat("LHIK_CamDriver", i) then
|
||||
LHIK_CamDriver = self:GetBuff_Stat("LHIK_CamDriver", i)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if !IsValid(lhik_model) then return false end
|
||||
|
||||
local seq = lhik_model:LookupSequence(key)
|
||||
|
||||
if !seq then return false end
|
||||
if seq == -1 then return false end
|
||||
|
||||
lhik_model:ResetSequence(seq)
|
||||
if IsValid(lhik_anim_model) then
|
||||
lhik_anim_model:ResetSequence(seq)
|
||||
end
|
||||
|
||||
if !time or time < 0 then time = lhik_model:SequenceDuration(seq) end
|
||||
|
||||
self.LHIKAnimation = seq
|
||||
self.LHIKAnimationStart = UnPredictedCurTime()
|
||||
self.LHIKAnimationTime = time
|
||||
|
||||
self.LHIKAnimation_IsIdle = false
|
||||
|
||||
if IsValid(lhik_anim_model) and LHIK_GunDriver then
|
||||
local att = lhik_anim_model:LookupAttachment(LHIK_GunDriver)
|
||||
local ang = lhik_anim_model:GetAttachment(att).Ang
|
||||
local pos = lhik_anim_model:GetAttachment(att).Pos
|
||||
|
||||
self.LHIKGunAng = lhik_anim_model:WorldToLocalAngles(ang) - Angle(0, 90, 90)
|
||||
self.LHIKGunPos = lhik_anim_model:WorldToLocal(pos)
|
||||
|
||||
self.LHIKGunAngVM = vm:WorldToLocalAngles(ang) - Angle(0, 90, 90)
|
||||
self.LHIKGunPosVM = vm:WorldToLocal(pos)
|
||||
end
|
||||
|
||||
if IsValid(lhik_anim_model) and LHIK_CamDriver then
|
||||
local att = lhik_anim_model:LookupAttachment(LHIK_CamDriver)
|
||||
local ang = lhik_anim_model:GetAttachment(att).Ang
|
||||
|
||||
self.LHIKCamOffsetAng = offsetang
|
||||
self.LHIKCamAng = lhik_anim_model:WorldToLocalAngles(ang)
|
||||
end
|
||||
|
||||
-- lhik_model:SetCycle(0)
|
||||
-- lhik_model:SetPlaybackRate(dur / time)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
SWEP.LHIKDelta = {}
|
||||
SWEP.LHIKDeltaAng = {}
|
||||
SWEP.ViewModel_Hit = Vector(0, 0, 0)
|
||||
SWEP.Customize_Hide = 0
|
||||
|
||||
function SWEP:GetLHIKAnim()
|
||||
local cyc = (UnPredictedCurTime() - self.LHIKAnimationStart) / self.LHIKAnimationTime
|
||||
|
||||
if cyc > 1 then return nil end
|
||||
if self.LHIKAnimation_IsIdle then return nil end
|
||||
|
||||
return self.LHIKAnimation
|
||||
end
|
||||
|
||||
function SWEP:DoLHIK()
|
||||
if !IsValid(self:GetOwner()) then return end
|
||||
|
||||
local justhide = false
|
||||
local lhik_model = nil
|
||||
local lhik_anim_model = nil
|
||||
local hide_component = false
|
||||
local delta = 1
|
||||
|
||||
local vm = self:GetOwner():GetViewModel()
|
||||
|
||||
if !ArcCW.ConVars["reloadincust"]:GetBool() and !self.NoHideLeftHandInCustomization and !self:GetBuff_Override("Override_NoHideLeftHandInCustomization") then
|
||||
if self:GetState() == ArcCW.STATE_CUSTOMIZE then
|
||||
self.Customize_Hide = math.Approach(self.Customize_Hide, 1, FrameTime() / 0.25)
|
||||
else
|
||||
self.Customize_Hide = math.Approach(self.Customize_Hide, 0, FrameTime() / 0.25)
|
||||
end
|
||||
end
|
||||
|
||||
for i, k in pairs(self.Attachments) do
|
||||
if !k.Installed then continue end
|
||||
-- local atttbl = ArcCW.AttachmentTable[k.Installed]
|
||||
|
||||
-- if atttbl.LHIKHide then
|
||||
if self:GetBuff_Stat("LHIKHide", i) then
|
||||
justhide = true
|
||||
end
|
||||
|
||||
if !k.VElement then continue end
|
||||
|
||||
-- if atttbl.LHIK then
|
||||
if self:GetBuff_Stat("LHIK", i) then
|
||||
lhik_model = k.VElement.Model
|
||||
if k.GodDriver then
|
||||
lhik_anim_model = k.GodDriver.Model
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.LHIKTimeline then
|
||||
local tl = self.LHIKTimeline
|
||||
|
||||
local stage, next_stage, next_stage_index
|
||||
|
||||
for i, k in pairs(tl) do
|
||||
if !k or !k.t then continue end
|
||||
if k.t + self.LHIKStartTime > UnPredictedCurTime() then
|
||||
next_stage_index = i
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if next_stage_index then
|
||||
if next_stage_index == 1 then
|
||||
-- we are on the first stage.
|
||||
stage = {t = 0, lhik = 0}
|
||||
next_stage = self.LHIKTimeline[next_stage_index]
|
||||
else
|
||||
stage = self.LHIKTimeline[next_stage_index - 1]
|
||||
next_stage = self.LHIKTimeline[next_stage_index]
|
||||
end
|
||||
else
|
||||
stage = self.LHIKTimeline[#self.LHIKTimeline]
|
||||
next_stage = {t = self.LHIKEndTime, lhik = self.LHIKTimeline[#self.LHIKTimeline].lhik}
|
||||
end
|
||||
|
||||
local local_time = UnPredictedCurTime() - self.LHIKStartTime
|
||||
|
||||
local delta_time = next_stage.t - stage.t
|
||||
delta_time = (local_time - stage.t) / delta_time
|
||||
|
||||
delta = qerp(delta_time, stage.lhik, next_stage.lhik)
|
||||
|
||||
if lhik_model and IsValid(lhik_model) then
|
||||
local key
|
||||
|
||||
if stage.lhik > next_stage.lhik then
|
||||
key = "in"
|
||||
elseif next_stage.lhik > stage.lhik then
|
||||
key = "out"
|
||||
end
|
||||
|
||||
if key then
|
||||
local tranim = self:GetBuff_Hook("Hook_LHIK_TranslateAnimation", key)
|
||||
|
||||
key = tranim or key
|
||||
|
||||
local seq = lhik_model:LookupSequence(key)
|
||||
|
||||
if seq and seq > 0 then
|
||||
lhik_model:SetSequence(seq)
|
||||
lhik_model:SetCycle(delta)
|
||||
if lhik_anim_model then
|
||||
lhik_anim_model:SetSequence(seq)
|
||||
lhik_anim_model:SetCycle(delta)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- if tl[4] <= UnPredictedCurTime() then
|
||||
-- -- it's over
|
||||
-- delta = 1
|
||||
-- elseif tl[3] <= UnPredictedCurTime() then
|
||||
-- -- transition back to 1
|
||||
-- delta = (UnPredictedCurTime() - tl[3]) / (tl[4] - tl[3])
|
||||
-- delta = qerp(delta, 0, 1)
|
||||
|
||||
-- if lhik_model and IsValid(lhik_model) then
|
||||
-- local key = "out"
|
||||
|
||||
-- local tranim = self:GetBuff_Hook("Hook_LHIK_TranslateAnimation", key)
|
||||
|
||||
-- key = tranim or key
|
||||
|
||||
-- local seq = lhik_model:LookupSequence(key)
|
||||
|
||||
-- if seq and seq > 0 then
|
||||
-- lhik_model:SetSequence(seq)
|
||||
-- lhik_model:SetCycle(delta)
|
||||
-- end
|
||||
-- end
|
||||
-- elseif tl[2] <= UnPredictedCurTime() then
|
||||
-- -- hold 0
|
||||
-- delta = 0
|
||||
-- elseif tl[1] <= UnPredictedCurTime() then
|
||||
-- -- transition to 0
|
||||
-- delta = (UnPredictedCurTime() - tl[1]) / (tl[2] - tl[1])
|
||||
-- delta = qerp(delta, 1, 0)
|
||||
|
||||
-- if lhik_model and IsValid(lhik_model) then
|
||||
-- local key = "in"
|
||||
|
||||
-- local tranim = self:GetBuff_Hook("Hook_LHIK_TranslateAnimation", key)
|
||||
|
||||
-- key = tranim or key
|
||||
|
||||
-- local seq = lhik_model:LookupSequence(key)
|
||||
|
||||
-- if seq and seq > 0 then
|
||||
-- lhik_model:SetSequence(seq)
|
||||
-- lhik_model:SetCycle(delta)
|
||||
-- end
|
||||
-- end
|
||||
else
|
||||
-- hasn't started yet
|
||||
delta = 1
|
||||
end
|
||||
|
||||
if delta == 1 and self.Customize_Hide > 0 then
|
||||
if !lhik_model or !IsValid(lhik_model) then
|
||||
justhide = true
|
||||
delta = math.min(self.Customize_Hide, delta)
|
||||
else
|
||||
hide_component = true
|
||||
end
|
||||
end
|
||||
|
||||
if justhide then
|
||||
for _, bone in pairs(ArcCW.LHIKBones) do
|
||||
local vmbone = vm:LookupBone(bone)
|
||||
|
||||
if !vmbone then continue end -- Happens when spectating someone prolly
|
||||
|
||||
local vmtransform = vm:GetBoneMatrix(vmbone)
|
||||
|
||||
if !vmtransform then continue end -- something very bad has happened
|
||||
|
||||
local vm_pos = vmtransform:GetTranslation()
|
||||
local vm_ang = vmtransform:GetAngles()
|
||||
|
||||
local newtransform = Matrix()
|
||||
|
||||
newtransform:SetTranslation(LerpVector(delta, vm_pos, vm_pos - (EyeAngles():Up() * 12) - (EyeAngles():Forward() * 12) - (EyeAngles():Right() * 4)))
|
||||
newtransform:SetAngles(vm_ang)
|
||||
|
||||
vm:SetBoneMatrix(vmbone, newtransform)
|
||||
end
|
||||
end
|
||||
|
||||
if !lhik_model or !IsValid(lhik_model) then return end
|
||||
|
||||
lhik_model:SetupBones()
|
||||
|
||||
if justhide then return end
|
||||
|
||||
local cyc = (UnPredictedCurTime() - self.LHIKAnimationStart) / self.LHIKAnimationTime
|
||||
|
||||
if self.LHIKAnimation and cyc < 1 then
|
||||
lhik_model:SetSequence(self.LHIKAnimation)
|
||||
lhik_model:SetCycle(cyc)
|
||||
if IsValid(lhik_anim_model) then
|
||||
lhik_anim_model:SetSequence(self.LHIKAnimation)
|
||||
lhik_anim_model:SetCycle(cyc)
|
||||
end
|
||||
else
|
||||
local key = "idle"
|
||||
|
||||
local tranim = self:GetBuff_Hook("Hook_LHIK_TranslateAnimation", key)
|
||||
|
||||
key = tranim or key
|
||||
|
||||
if key and key != "DoNotPlayIdle" then
|
||||
self:DoLHIKAnimation(key, -1)
|
||||
end
|
||||
|
||||
self.LHIKAnimation_IsIdle = true
|
||||
end
|
||||
|
||||
local cf_deltapos = Vector(0, 0, 0)
|
||||
local cf = 0
|
||||
|
||||
|
||||
for _, bone in pairs(ArcCW.LHIKBones) do
|
||||
local vmbone = vm:LookupBone(bone)
|
||||
local lhikbone = lhik_model:LookupBone(bone)
|
||||
|
||||
if !vmbone then continue end
|
||||
if !lhikbone then continue end
|
||||
|
||||
local vmtransform = vm:GetBoneMatrix(vmbone)
|
||||
local lhiktransform = lhik_model:GetBoneMatrix(lhikbone)
|
||||
|
||||
if !vmtransform then continue end
|
||||
if !lhiktransform then continue end
|
||||
|
||||
local vm_pos = vmtransform:GetTranslation()
|
||||
local vm_ang = vmtransform:GetAngles()
|
||||
local lhik_pos = lhiktransform:GetTranslation()
|
||||
local lhik_ang = lhiktransform:GetAngles()
|
||||
|
||||
local newtransform = Matrix()
|
||||
|
||||
newtransform:SetTranslation(LerpVector(delta, vm_pos, lhik_pos))
|
||||
newtransform:SetAngles(LerpAngle(delta, vm_ang, lhik_ang))
|
||||
|
||||
if !self:GetBuff_Override("LHIK_GunDriver") and self.LHIKDelta[lhikbone] and self.LHIKAnimation and cyc < 1 then
|
||||
local deltapos = lhik_model:WorldToLocal(lhik_pos) - self.LHIKDelta[lhikbone]
|
||||
|
||||
if !deltapos:IsZero() then
|
||||
cf_deltapos = cf_deltapos + deltapos
|
||||
cf = cf + 1
|
||||
end
|
||||
end
|
||||
|
||||
self.LHIKDelta[lhikbone] = lhik_model:WorldToLocal(lhik_pos)
|
||||
|
||||
if hide_component then
|
||||
local new_pos = newtransform:GetTranslation()
|
||||
newtransform:SetTranslation(LerpVector(self.Customize_Hide, new_pos, new_pos - (EyeAngles():Up() * 12) - (EyeAngles():Forward() * 12) - (EyeAngles():Right() * 4)))
|
||||
end
|
||||
|
||||
local matrix = Matrix(newtransform)
|
||||
|
||||
vm:SetBoneMatrix(vmbone, matrix)
|
||||
|
||||
-- local vm_pos, vm_ang = vm:GetBonePosition(vmbone)
|
||||
-- local lhik_pos, lhik_ang = lhik_model:GetBonePosition(lhikbone)
|
||||
|
||||
-- local pos = LerpVector(delta, vm_pos, lhik_pos)
|
||||
-- local ang = LerpAngle(delta, vm_ang, lhik_ang)
|
||||
|
||||
-- vm:SetBonePosition(vmbone, pos, ang)
|
||||
end
|
||||
|
||||
if !cf_deltapos:IsZero() and cf > 0 and self:GetBuff_Override("LHIK_Animation") then
|
||||
local new = Vector(0, 0, 0)
|
||||
local viewmult = self:GetBuff_Override("LHIK_MovementMult") or 1
|
||||
|
||||
new[1] = cf_deltapos[2] * viewmult
|
||||
new[2] = cf_deltapos[1] * viewmult
|
||||
new[3] = cf_deltapos[3] * viewmult
|
||||
|
||||
self.ViewModel_Hit = LerpVector(0.25, self.ViewModel_Hit, new / cf):GetNormalized()
|
||||
end
|
||||
end
|
||||
373
lua/weapons/arccw_base/cl_light.lua
Normal file
373
lua/weapons/arccw_base/cl_light.lua
Normal file
@@ -0,0 +1,373 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
SWEP.Flashlights = {} -- tracks projectedlights
|
||||
-- {{att = int, light = ProjectedTexture}}
|
||||
SWEP.CheapFlashlights = {} -- tracks cheap flashlight models + lights
|
||||
-- {{att = int, dlight = DynamicLight, vlight = ClientsideModel}}
|
||||
|
||||
function SWEP:GetHasFlashlights()
|
||||
for i, k in pairs(self.Attachments) do
|
||||
if !k.Installed then continue end
|
||||
if self:GetBuff_Stat("Flashlight", i) != nil then return true end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:CreateFlashlightsVM()
|
||||
self:KillFlashlights()
|
||||
self.Flashlights = {}
|
||||
|
||||
local total_lights = 0
|
||||
|
||||
for i, k in pairs(self.Attachments) do
|
||||
if !k.Installed then continue end
|
||||
if self:GetBuff_Stat("Flashlight", i) then
|
||||
local newlight = {
|
||||
att = i,
|
||||
light = ProjectedTexture(),
|
||||
bone = self:GetBuff_Stat("FlashlightBone", i) or "laser",
|
||||
col = self:GetBuff_Stat("FlashlightColor", i) or Color(255, 255, 255),
|
||||
br = self:GetBuff_Stat("FlashlightBrightness", i) or 2
|
||||
}
|
||||
total_lights = total_lights + 1
|
||||
|
||||
local l = newlight.light
|
||||
if !IsValid(l) then continue end
|
||||
|
||||
table.insert(self.Flashlights, newlight)
|
||||
|
||||
l:SetFOV(self:GetBuff_Stat("FlashlightFOV", i) or 50)
|
||||
|
||||
if self:GetBuff_Stat("FlashlightHFOV", i) then
|
||||
l:SetHorizontalFOV(self:GetBuff_Stat("FlashlightHFOV", i))
|
||||
end
|
||||
|
||||
if self:GetBuff_Stat("FlashlightVFOV", i) then
|
||||
l:SetVerticalFOV(self:GetBuff_Stat("FlashlightVFOV", i))
|
||||
end
|
||||
|
||||
l:SetFarZ(self:GetBuff_Stat("FlashlightFarZ", i) or 512)
|
||||
l:SetNearZ(self:GetBuff_Stat("FlashlightNearZ", i) or 4)
|
||||
|
||||
local atten = self:GetBuff_Stat("FlashlightAttenuationType", i) or ArcCW.FLASH_ATT_LINEAR
|
||||
|
||||
l:SetLinearAttenuation(0)
|
||||
l:SetConstantAttenuation(0)
|
||||
l:SetQuadraticAttenuation(0)
|
||||
|
||||
if atten == ArcCW.FLASH_ATT_CONSTANT then
|
||||
l:SetConstantAttenuation(100)
|
||||
elseif atten == ArcCW.FLASH_ATT_QUADRATIC then
|
||||
l:SetQuadraticAttenuation(100)
|
||||
else
|
||||
l:SetLinearAttenuation(100)
|
||||
end
|
||||
|
||||
l:SetColor(self:GetBuff_Stat("FlashlightColor", i) or Color(255, 255, 255))
|
||||
l:SetTexture(self:GetBuff_Stat("FlashlightTexture", i))
|
||||
l:SetBrightness(self:GetBuff_Stat("FlashlightBrightness", i))
|
||||
l:SetEnableShadows(true)
|
||||
l:Update()
|
||||
|
||||
local g_light = {
|
||||
Weapon = self,
|
||||
ProjectedTexture = l
|
||||
}
|
||||
|
||||
table.insert(ArcCW.FlashlightPile, g_light)
|
||||
end
|
||||
end
|
||||
|
||||
if total_lights > 2 then -- you are a madman
|
||||
for i, k in pairs(self.Flashlights) do
|
||||
if k.light:IsValid() then k.light:SetEnableShadows(false) end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- for world model flashlights we will use a cheap solution similar to what HL2 uses
|
||||
-- throw up a volumetric light model
|
||||
-- function SWEP:CreateFlashlightsWM()
|
||||
-- self:KillFlashlights()
|
||||
-- self.CheapFlashlights = {}
|
||||
-- for i, k in pairs(self.Attachments) do
|
||||
-- if !k.Installed then continue end
|
||||
-- local atttbl = ArcCW.AttachmentTable[k.Installed]
|
||||
|
||||
-- if atttbl.Flashlight then
|
||||
-- local newlight = {
|
||||
-- att = i,
|
||||
-- vlight = ClientsideModel(ArcCW.VolumetricLightModel),
|
||||
-- scale_x = 1,
|
||||
-- scale_y = 1,
|
||||
-- maxz = atttbl.FlashlightFarZ or 512,
|
||||
-- bone = atttbl.FlashlightBone or "laser",
|
||||
-- col = Color(255, 255, 255)
|
||||
-- }
|
||||
|
||||
-- local vl = newlight.vlight
|
||||
|
||||
-- if !IsValid(vl) then continue end
|
||||
|
||||
-- table.insert(self.CheapFlashlights, newlight)
|
||||
|
||||
-- local xfov = atttbl.FlashlightHFOV or atttbl.FlashlightFOV or 50
|
||||
-- local yfov = atttbl.FlashlightVFOV or atttbl.FlashlightFOV or 50
|
||||
|
||||
-- local target_x = 128 * (xfov / 90)
|
||||
-- local target_y = 128 * (yfov / 90)
|
||||
|
||||
-- local scale_x = target_x / ArcCW.VolumetricLightX
|
||||
-- local scale_y = target_y / ArcCW.VolumetricLightY
|
||||
|
||||
-- newlight.scale_x = scale_x
|
||||
-- newlight.scale_y = scale_y
|
||||
|
||||
-- vl:SetNoDraw(ArcCW.NoDraw)
|
||||
-- vl:DrawShadow(false)
|
||||
-- local col = atttbl.FlashlightColor or Color(255, 255, 255)
|
||||
-- col = Color(255, 0, 0)
|
||||
-- newlight.col = col
|
||||
-- -- vl:SetColor(col)
|
||||
|
||||
-- local g_light = {
|
||||
-- Model = vl,
|
||||
-- Weapon = self
|
||||
-- }
|
||||
|
||||
-- table.insert(ArcCW.CSModelPile, g_light)
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
|
||||
function SWEP:KillFlashlights()
|
||||
self:KillFlashlightsVM()
|
||||
-- self:KillFlashlightsWM()
|
||||
end
|
||||
|
||||
function SWEP:KillFlashlightsVM()
|
||||
if !self.Flashlights then return end
|
||||
|
||||
for i, k in pairs(self.Flashlights) do
|
||||
if k.light and k.light:IsValid() then
|
||||
k.light:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
self.Flashlights = nil
|
||||
end
|
||||
|
||||
function SWEP:KillFlashlightsWM()
|
||||
-- if !self.CheapFlashlights then return end
|
||||
|
||||
-- for i, k in pairs(self.CheapFlashlights) do
|
||||
-- if k.vlight and k.vlight:IsValid() then
|
||||
-- k.vlight:Remove()
|
||||
-- end
|
||||
-- end
|
||||
|
||||
-- self.CheapFlashlights = nil
|
||||
end
|
||||
|
||||
-- given fov and distance solve apparent size
|
||||
local function solvetriangle(angle, dist)
|
||||
local a = angle / 2
|
||||
local b = dist
|
||||
return b * math.tan(a) * 2
|
||||
end
|
||||
|
||||
local flashlight_mat = Material("models/effects/vol_light002")
|
||||
-- local flashlight_mat = Material("effects/blueblacklargebeam")
|
||||
|
||||
function SWEP:DrawFlashlightsWM()
|
||||
-- if !self.CheapFlashlights then
|
||||
-- self:CreateFlashlightsWM()
|
||||
-- end
|
||||
|
||||
local owner = self:GetOwner()
|
||||
|
||||
for i, k in pairs(self.Attachments) do
|
||||
if !k.Installed then continue end
|
||||
local atttbl = ArcCW.AttachmentTable[k.Installed]
|
||||
|
||||
if !atttbl or !self:GetBuff_Stat("Flashlight", i) then continue end
|
||||
|
||||
local maxz = atttbl.FlashlightFarZ or 512
|
||||
local bone = atttbl.FlashlightBone or "laser"
|
||||
local col = atttbl.FlashlightColor or Color(255, 255, 255)
|
||||
|
||||
if !k.WElement then continue end
|
||||
local model = k.WElement.Model
|
||||
if !IsValid(model) then return end
|
||||
|
||||
local pos, ang, dir
|
||||
|
||||
if !model then
|
||||
pos = owner:EyePos()
|
||||
ang = owner:EyeAngles()
|
||||
dir = ang:Forward()
|
||||
else
|
||||
local att = model:LookupAttachment(bone or "laser")
|
||||
|
||||
att = att == 0 and model:LookupAttachment("muzzle") or att
|
||||
|
||||
if att == 0 then
|
||||
pos = model:GetPos()
|
||||
ang = IsValid(owner) and owner:EyeAngles() or model:GetAngles()
|
||||
dir = ang:Forward()
|
||||
dir_2 = ang:Up()
|
||||
else
|
||||
local attdata = model:GetAttachment(att)
|
||||
pos, ang = attdata.Pos, attdata.Ang
|
||||
dir = -ang:Right()
|
||||
dir_2 = ang:Up()
|
||||
end
|
||||
end
|
||||
|
||||
local maxs = Vector(2, 2, 2)
|
||||
local mins = -maxs
|
||||
|
||||
-- scale volumetric light
|
||||
local tr = util.TraceHull({
|
||||
start = pos,
|
||||
endpos = pos + (dir * maxz),
|
||||
mask = MASK_OPAQUE,
|
||||
mins = mins,
|
||||
maxs = maxs
|
||||
})
|
||||
|
||||
local z = (tr.HitPos - tr.StartPos):Length()
|
||||
-- local s_z = z / ArcCW.VolumetricLightZ
|
||||
|
||||
local xfov = atttbl.FlashlightHFOV or atttbl.FlashlightFOV or 50
|
||||
local yfov = atttbl.FlashlightVFOV or atttbl.FlashlightFOV or 50
|
||||
|
||||
-- local target_x = 128 * (xfov / 90)
|
||||
-- local target_y = 128 * (yfov / 90)
|
||||
|
||||
local target_x = solvetriangle(xfov, z)
|
||||
local target_y = target_x
|
||||
|
||||
if xfov != yfov then
|
||||
target_y = solvetriangle(yfov, z)
|
||||
end
|
||||
|
||||
local vs = EyeAngles():Up()
|
||||
|
||||
local c1 = pos + vs
|
||||
local c4 = pos - vs
|
||||
local c2 = tr.HitPos + (vs * target_y * 0.75)
|
||||
local c3 = tr.HitPos - (vs * target_y * 0.75)
|
||||
|
||||
render.SetMaterial(flashlight_mat)
|
||||
render.DrawQuad(c1,c2,c3,c4, col)
|
||||
|
||||
-- local scale = Matrix()
|
||||
-- scale:Scale(Vector(s_x, s_y, s_z))
|
||||
|
||||
-- k.vlight:SetPos(pos)
|
||||
-- k.vlight:SetAngles(ang + Angle(0, 0, 90))
|
||||
-- k.vlight:EnableMatrix("RenderMultiply", scale)
|
||||
-- k.vlight:SetColor(Color(255, 0, 0, 255))
|
||||
-- k.vlight:SetRenderMode(RENDERMODE_NORMAL)
|
||||
-- k.vlight:SetKeyValue("RenderFX", kRenderFxNone)
|
||||
-- k.vlight:DrawModel()
|
||||
-- place dynamic light to make some light appear
|
||||
|
||||
local dl = DynamicLight(self:EntIndex())
|
||||
|
||||
local delta = (z / maxz)
|
||||
delta = math.Clamp(delta, 0, 1)
|
||||
|
||||
if dl then
|
||||
dl.pos = tr.HitPos
|
||||
dl.r = col.r
|
||||
dl.g = col.g
|
||||
dl.b = col.b
|
||||
dl.brightness = Lerp(delta, atttbl.FlashlightBrightness or 2, 0)
|
||||
-- print(z / maxz)
|
||||
dl.Decay = 1000 / 1
|
||||
dl.dietime = CurTime() + 0.1
|
||||
dl.size = xfov * 5
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:DrawFlashlightsVM()
|
||||
if !self.Flashlights then
|
||||
self:CreateFlashlightsVM()
|
||||
end
|
||||
|
||||
local owner = self:GetOwner()
|
||||
|
||||
for i, k in pairs(self.Flashlights) do
|
||||
local model = (self.Attachments[k.att].VElement or {}).Model
|
||||
|
||||
local pos, ang
|
||||
|
||||
if !model then
|
||||
pos = owner:EyePos()
|
||||
ang = owner:EyeAngles()
|
||||
else
|
||||
local att = model:LookupAttachment(k.bone or "laser")
|
||||
|
||||
att = att == 0 and model:LookupAttachment("muzzle") or att
|
||||
|
||||
if att == 0 then
|
||||
pos = model:GetPos()
|
||||
ang = owner:EyeAngles()
|
||||
else
|
||||
local attdata = model:GetAttachment(att)
|
||||
pos, ang = attdata.Pos, attdata.Ang
|
||||
end
|
||||
end
|
||||
|
||||
local tr = util.TraceLine({
|
||||
start = owner:EyePos(),
|
||||
endpos = owner:EyePos() - ang:Right() * 128,
|
||||
mask = MASK_OPAQUE,
|
||||
filter = LocalPlayer(),
|
||||
})
|
||||
if tr.Fraction < 1 then -- We need to push the flashlight back
|
||||
local tr2 = util.TraceLine({
|
||||
start = owner:EyePos(),
|
||||
endpos = owner:EyePos() + ang:Right() * 128,
|
||||
mask = MASK_OPAQUE,
|
||||
filter = LocalPlayer(),
|
||||
})
|
||||
-- push it as back as the area behind us allows
|
||||
pos = pos + ang:Right() * 128 * math.min(1 - tr.Fraction, tr2.Fraction)
|
||||
end
|
||||
|
||||
ang:RotateAroundAxis(ang:Up(), 90)
|
||||
|
||||
k.light:SetPos(pos)
|
||||
k.light:SetAngles(ang)
|
||||
k.light:Update()
|
||||
|
||||
-- local col = k.col
|
||||
|
||||
-- local dl = DynamicLight(self:EntIndex())
|
||||
|
||||
-- if dl then
|
||||
-- dl.pos = pos
|
||||
-- dl.r = col.r
|
||||
-- dl.g = col.g
|
||||
-- dl.b = col.b
|
||||
-- dl.brightness = k.br or 2
|
||||
-- -- print(z / maxz)
|
||||
-- dl.Decay = 1000 / 0.1
|
||||
-- dl.dietime = CurTime() + 0.1
|
||||
-- dl.size = (k.br or 2) * 64
|
||||
-- end
|
||||
end
|
||||
end
|
||||
468
lua/weapons/arccw_base/cl_presets.lua
Normal file
468
lua/weapons/arccw_base/cl_presets.lua
Normal file
@@ -0,0 +1,468 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
-- atts are comma separated
|
||||
-- optic_mrs,,,perk_quickdraw,ammo_match
|
||||
|
||||
|
||||
|
||||
local function ScreenScaleMulti(input)
|
||||
return ScreenScale(input) * ArcCW.ConVars["hud_size"]:GetFloat()
|
||||
end
|
||||
|
||||
function SWEP:GetPresetBase()
|
||||
return self.PresetBase or self:GetClass()
|
||||
end
|
||||
|
||||
function SWEP:GetPresets()
|
||||
local path = ArcCW.PresetPath .. self:GetPresetBase() .. "/*.txt"
|
||||
|
||||
local files = file.Find(path, "DATA")
|
||||
|
||||
files = table.Add(files, file.Find(ArcCW.PresetPath .. self:GetPresetBase() .. "/*.json", "DATA"))
|
||||
|
||||
return files
|
||||
end
|
||||
|
||||
function SWEP:LoadPreset(presetname)
|
||||
presetname = presetname or "autosave"
|
||||
if presetname == "autosave" then
|
||||
if self:GetNWBool("ArcCW_DisableAutosave", false) then return end
|
||||
if !ArcCW.ConVars["autosave"]:GetBool() then return end
|
||||
end
|
||||
|
||||
if presetname != "autosave" then
|
||||
surface.PlaySound("weapons/arccw/install.wav")
|
||||
end
|
||||
|
||||
-- ???
|
||||
self.Attachments.BaseClass = nil
|
||||
|
||||
local presetTbl
|
||||
|
||||
|
||||
-- New behavior
|
||||
local filename = ArcCW.PresetPath .. self:GetPresetBase() .. "/" .. presetname .. ".json"
|
||||
if file.Exists(filename, "DATA") then
|
||||
presetTbl = util.JSONToTable(file.Read(filename))
|
||||
if presetTbl and presetTbl != {} then
|
||||
for i = 1, table.Count(self.Attachments) do
|
||||
local ok = true
|
||||
|
||||
if !presetTbl[i] or !ArcCW.AttachmentTable[presetTbl[i].Installed or ""] then
|
||||
ok = false
|
||||
end
|
||||
|
||||
if !ok then
|
||||
presetTbl[i] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Legacy behavior
|
||||
filename = ArcCW.PresetPath .. self:GetPresetBase() .. "/" .. presetname .. ".txt"
|
||||
if presetTbl == nil and file.Exists(filename, "DATA") then
|
||||
local f = file.Open(filename, "r", "DATA")
|
||||
if !f then return end
|
||||
|
||||
presetTbl = {}
|
||||
|
||||
for i = 1, table.Count(self.Attachments) do
|
||||
local line = f:ReadLine()
|
||||
if !line then continue end
|
||||
local split = string.Split(string.Trim(line, "\n"), ",")
|
||||
if !ArcCW.AttachmentTable[split[1]] then continue end
|
||||
presetTbl[i] = {
|
||||
Installed = split[1],
|
||||
SlidePos = split[2] and tonumber(split[2]),
|
||||
SightMagnifications = split[3] and tonumber(split[3]),
|
||||
ToggleNum = nil, -- not implemented in legacy preset
|
||||
}
|
||||
end
|
||||
f:Close()
|
||||
end
|
||||
|
||||
if !presetTbl then return end
|
||||
|
||||
net.Start("arccw_applypreset")
|
||||
net.WriteEntity(self)
|
||||
for k, v in pairs(self.Attachments) do
|
||||
local att = (presetTbl[k] or {}).Installed
|
||||
|
||||
if !att or !ArcCW.AttachmentTable[att] then
|
||||
net.WriteUInt(0, ArcCW.GetBitNecessity())
|
||||
continue
|
||||
end
|
||||
|
||||
net.WriteUInt(ArcCW.AttachmentTable[att].ID, ArcCW.GetBitNecessity())
|
||||
|
||||
net.WriteBool(presetTbl[k].SlidePos)
|
||||
if presetTbl[k].SlidePos then
|
||||
net.WriteFloat(presetTbl[k].SlidePos)
|
||||
end
|
||||
|
||||
if ArcCW.AttachmentTable[att].ToggleStats != nil then
|
||||
net.WriteUInt(presetTbl[k].ToggleNum or 1, 8)
|
||||
end
|
||||
v.ToggleNum = presetTbl[k].ToggleNum or 1
|
||||
|
||||
-- not networked
|
||||
self.SightMagnifications[k] = presetTbl[k].SightMagnifications
|
||||
end
|
||||
net.SendToServer()
|
||||
|
||||
--[[]
|
||||
for i = 1, table.Count(self.Attachments) do
|
||||
local att = presetTbl[i]
|
||||
if !att then continue end
|
||||
|
||||
if ArcCW:PlayerGetAtts(self:GetOwner(), att) == 0 then continue end
|
||||
if !self.Attachments[i] then continue end
|
||||
|
||||
-- detect commas
|
||||
-- no commas = do nothing
|
||||
-- commas: If exactly two commas are detected
|
||||
-- try to parse them as slidepos, magnification
|
||||
|
||||
local split = string.Split(att, ",")
|
||||
local sc = table.Count(split)
|
||||
|
||||
local slidepos = 0.5
|
||||
local mag = -1
|
||||
|
||||
if sc == 3 then
|
||||
att = split[1]
|
||||
slidepos = tonumber(split[2])
|
||||
mag = tonumber(split[3])
|
||||
end
|
||||
|
||||
if att == self.Attachments[i].Installed then continue end
|
||||
|
||||
self:Detach(i, true, true)
|
||||
|
||||
if !ArcCW.AttachmentTable[att] then continue end
|
||||
|
||||
self:Attach(i, att, true, true)
|
||||
|
||||
if slidepos != 0.5 then
|
||||
self.Attachments[i].SlidePos = slidepos
|
||||
end
|
||||
|
||||
if mag != -1 then
|
||||
self.SightMagnifications[i] = mag
|
||||
end
|
||||
end
|
||||
|
||||
self:SendAllDetails()
|
||||
|
||||
self:SavePreset()
|
||||
]]
|
||||
end
|
||||
|
||||
function SWEP:SavePreset(presetname)
|
||||
presetname = presetname or "autosave"
|
||||
if presetname == "autosave" and !ArcCW.ConVars["attinv_free"]:GetBool() then return end
|
||||
|
||||
local presetTbl = {}
|
||||
for i, k in pairs(self.Attachments) do
|
||||
if k.Installed then
|
||||
presetTbl[i] = {
|
||||
Installed = k.Installed,
|
||||
SlidePos = k.SlidePos,
|
||||
SightMagnifications = self.SightMagnifications[i],
|
||||
ToggleNum = k.ToggleNum
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
filename = ArcCW.PresetPath .. self:GetPresetBase() .. "/" .. presetname .. ".json"
|
||||
file.CreateDir(ArcCW.PresetPath .. self:GetPresetBase())
|
||||
file.Write(filename, util.TableToJSON(presetTbl))
|
||||
|
||||
local legacy_filename = ArcCW.PresetPath .. self:GetPresetBase() .. "/" .. presetname .. ".txt"
|
||||
if file.Exists(legacy_filename, "DATA") then
|
||||
file.Delete(legacy_filename)
|
||||
end
|
||||
|
||||
-- Legacy presets
|
||||
--[[]
|
||||
local str = ""
|
||||
for i, k in pairs(self.Attachments) do
|
||||
if k.Installed then
|
||||
str = str .. k.Installed
|
||||
if k.SlidePos or self.SightMagnifications[i] then
|
||||
str = str .. "," .. tostring(k.SlidePos or 0.5) .. "," .. tostring(self.SightMagnifications[i] or -1)
|
||||
end
|
||||
end
|
||||
|
||||
str = str .. "\n"
|
||||
end
|
||||
|
||||
filename = ArcCW.PresetPath .. self:GetPresetBase() .. "/" .. filename .. ".txt"
|
||||
|
||||
file.CreateDir(ArcCW.PresetPath .. self:GetPresetBase())
|
||||
file.Write(filename, str)
|
||||
]]
|
||||
end
|
||||
|
||||
function SWEP:CreatePresetSave()
|
||||
if !IsValid(ArcCW.InvHUD) then return end
|
||||
local bg = vgui.Create("DFrame", ArcCW.InvHUD)
|
||||
bg:SetPos(0, 0)
|
||||
bg:SetSize(ScrW(), ScrH())
|
||||
bg:SetText("")
|
||||
bg:SetTitle("")
|
||||
bg:SetDraggable(false)
|
||||
bg:ShowCloseButton(false)
|
||||
bg.Paint = function(span)
|
||||
surface.SetDrawColor(0, 0, 0, 200)
|
||||
surface.DrawRect(0, 0, ScrW(), ScrH())
|
||||
end
|
||||
bg:MakePopup()
|
||||
|
||||
local text = vgui.Create("DTextEntry", bg)
|
||||
text:SetSize(ScreenScaleMulti(256), ScreenScaleMulti(26))
|
||||
text:Center()
|
||||
text:RequestFocus()
|
||||
text:SetFont("ArcCW_24")
|
||||
text:SetText(self.LastPresetName or "")
|
||||
|
||||
local accept = vgui.Create("DButton", bg)
|
||||
accept:SetSize((ScreenScaleMulti(256) - ScreenScaleMulti(2)) / 2, ScreenScaleMulti(14))
|
||||
accept:SetText("")
|
||||
accept:SetPos((ScrW() - ScreenScaleMulti(256)) / 2, ((ScrH() - ScreenScaleMulti(14)) / 2) + ScreenScaleMulti(26) + ScreenScaleMulti(2))
|
||||
|
||||
accept.OnMousePressed = function(spaa, kc)
|
||||
local txt = text:GetText()
|
||||
txt = string.sub(txt, 0, 36)
|
||||
self.LastPresetName = txt
|
||||
self:SavePreset(txt)
|
||||
bg:Close()
|
||||
bg:Remove()
|
||||
|
||||
ArcCW.InvHUD_FormPresets()
|
||||
end
|
||||
|
||||
accept.Paint = function(spaa, w, h)
|
||||
if !self:IsValid() then return end
|
||||
local Bfg_col = Color(255, 255, 255, 255)
|
||||
local Bbg_col = Color(0, 0, 0, 100)
|
||||
|
||||
if spaa:IsHovered() then
|
||||
Bbg_col = Color(255, 255, 255, 100)
|
||||
Bfg_col = Color(0, 0, 0, 255)
|
||||
end
|
||||
|
||||
surface.SetDrawColor(Bbg_col)
|
||||
surface.DrawRect(0, 0, w, h)
|
||||
|
||||
local txt = "Save"
|
||||
|
||||
surface.SetTextColor(Bfg_col)
|
||||
surface.SetTextPos(ScreenScaleMulti(2), ScreenScaleMulti(1))
|
||||
surface.SetFont("ArcCW_12")
|
||||
surface.DrawText(txt)
|
||||
end
|
||||
|
||||
local cancel = vgui.Create("DButton", bg)
|
||||
cancel:SetSize((ScreenScaleMulti(256) - ScreenScaleMulti(2)) / 2, ScreenScaleMulti(14))
|
||||
cancel:SetText("")
|
||||
cancel:SetPos(((ScrW() - ScreenScaleMulti(256)) / 2) + ScreenScaleMulti(128 + 1), ((ScrH() - ScreenScaleMulti(14)) / 2) + ScreenScaleMulti(26) + ScreenScaleMulti(2))
|
||||
|
||||
cancel.OnMousePressed = function(spaa, kc)
|
||||
bg:Close()
|
||||
bg:Remove()
|
||||
end
|
||||
|
||||
cancel.Paint = function(spaa, w, h)
|
||||
if !self:IsValid() then return end
|
||||
local Bfg_col = Color(255, 255, 255, 255)
|
||||
local Bbg_col = Color(0, 0, 0, 100)
|
||||
|
||||
if spaa:IsHovered() then
|
||||
Bbg_col = Color(255, 255, 255, 100)
|
||||
Bfg_col = Color(0, 0, 0, 255)
|
||||
end
|
||||
|
||||
surface.SetDrawColor(Bbg_col)
|
||||
surface.DrawRect(0, 0, w, h)
|
||||
|
||||
local txt = "Cancel"
|
||||
|
||||
surface.SetTextColor(Bfg_col)
|
||||
surface.SetTextPos(ScreenScaleMulti(2), ScreenScaleMulti(1))
|
||||
surface.SetFont("ArcCW_12")
|
||||
surface.DrawText(txt)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:CreatePresetMenu()
|
||||
if !IsValid(ArcCW.InvHUD) then return end
|
||||
|
||||
if !IsValid(ArcCW.InvHUD) then return end
|
||||
local bg = vgui.Create("DFrame", ArcCW.InvHUD)
|
||||
bg:SetPos(0, 0)
|
||||
bg:SetSize(ScrW(), ScrH())
|
||||
bg:SetText("")
|
||||
bg:SetTitle("")
|
||||
bg:SetDraggable(false)
|
||||
bg:ShowCloseButton(false)
|
||||
bg.Paint = function(span)
|
||||
surface.SetDrawColor(0, 0, 0, 200)
|
||||
surface.DrawRect(0, 0, ScrW(), ScrH())
|
||||
end
|
||||
|
||||
local cancel = vgui.Create("DButton", bg)
|
||||
cancel:SetSize(ScreenScaleMulti(128), ScreenScaleMulti(14))
|
||||
cancel:SetText("")
|
||||
cancel:SetPos((ScrW() - ScreenScaleMulti(128)) / 2, ScrH() - ScreenScaleMulti(32))
|
||||
|
||||
cancel.OnMousePressed = function(spaa, kc)
|
||||
bg:Close()
|
||||
bg:Remove()
|
||||
end
|
||||
|
||||
cancel.Paint = function(spaa, w, h)
|
||||
if !self:IsValid() then return end
|
||||
local Bfg_col = Color(255, 255, 255, 255)
|
||||
local Bbg_col = Color(0, 0, 0, 100)
|
||||
|
||||
if spaa:IsHovered() then
|
||||
Bbg_col = Color(255, 255, 255, 100)
|
||||
Bfg_col = Color(0, 0, 0, 255)
|
||||
end
|
||||
|
||||
surface.SetDrawColor(Bbg_col)
|
||||
surface.DrawRect(0, 0, w, h)
|
||||
|
||||
local txt = "Cancel"
|
||||
|
||||
surface.SetTextColor(Bfg_col)
|
||||
surface.SetTextPos(ScreenScaleMulti(2), ScreenScaleMulti(1))
|
||||
surface.SetFont("ArcCW_12")
|
||||
surface.DrawText(txt)
|
||||
end
|
||||
|
||||
local presetsmenu = vgui.Create("DScrollPanel", bg)
|
||||
presetsmenu:SetText("")
|
||||
presetsmenu:SetSize(ScreenScaleMulti(256), ScrH() - ScreenScaleMulti(64))
|
||||
presetsmenu:SetPos((ScrW() - ScreenScaleMulti(256)) / 2, ScreenScaleMulti(8))
|
||||
presetsmenu.Paint = function(span, w, h)
|
||||
end
|
||||
|
||||
local sbar = presetsmenu:GetVBar()
|
||||
sbar.Paint = function() end
|
||||
|
||||
sbar.btnUp.Paint = function(span, w, h)
|
||||
end
|
||||
|
||||
sbar.btnDown.Paint = function(span, w, h)
|
||||
end
|
||||
|
||||
sbar.btnGrip.Paint = function(span, w, h)
|
||||
surface.SetDrawColor(255, 255, 255, 255)
|
||||
surface.DrawRect(0, 0, w, h)
|
||||
end
|
||||
|
||||
local c = 0
|
||||
|
||||
for i, k in pairs(self:GetPresets()) do
|
||||
if string.StripExtension(k) == "autosave" then continue end
|
||||
local preset = vgui.Create("DButton", presetsmenu)
|
||||
preset:SetSize(ScreenScaleMulti(254), ScreenScaleMulti(14))
|
||||
preset:SetText("")
|
||||
preset:Dock(TOP)
|
||||
preset:DockMargin( 0, 0, 0, ScreenScaleMulti(2) )
|
||||
|
||||
preset.PresetName = string.StripExtension(k) --string.sub(k, 1, -5)
|
||||
preset.PresetFile = k
|
||||
|
||||
preset.OnMousePressed = function(spaa, kc)
|
||||
self.LastPresetName = spaa.PresetName
|
||||
self:LoadPreset(spaa.PresetName)
|
||||
bg:Close()
|
||||
bg:Remove()
|
||||
end
|
||||
|
||||
preset.Paint = function(spaa, w, h)
|
||||
if !self:IsValid() then return end
|
||||
local Bfg_col = Color(255, 255, 255, 255)
|
||||
local Bbg_col = Color(0, 0, 0, 100)
|
||||
|
||||
if spaa:IsHovered() then
|
||||
Bbg_col = Color(255, 255, 255, 100)
|
||||
Bfg_col = Color(0, 0, 0, 255)
|
||||
end
|
||||
|
||||
surface.SetDrawColor(Bbg_col)
|
||||
surface.DrawRect(0, 0, w, h)
|
||||
|
||||
surface.SetTextColor(Bfg_col)
|
||||
surface.SetTextPos(ScreenScaleMulti(2), ScreenScaleMulti(1))
|
||||
surface.SetFont("ArcCW_12")
|
||||
surface.DrawText(string.upper(spaa.PresetName))
|
||||
end
|
||||
|
||||
local close = vgui.Create("DButton", preset)
|
||||
close:SetSize(ScreenScaleMulti(16), ScreenScaleMulti(16))
|
||||
close:SetText("")
|
||||
close:Dock(RIGHT)
|
||||
|
||||
close.OnMousePressed = function(spaa, kc)
|
||||
local filename = spaa.PresetFile
|
||||
file.Delete(filename)
|
||||
preset:Remove()
|
||||
end
|
||||
|
||||
close.Paint = function(spaa, w, h)
|
||||
if !self:IsValid() or preset:IsHovered() then return end
|
||||
local Bfg_col = Color(255, 255, 255, 255)
|
||||
local Bbg_col = Color(0, 0, 0, 100)
|
||||
|
||||
if spaa:IsHovered() then
|
||||
Bbg_col = Color(255, 255, 255, 100)
|
||||
Bfg_col = Color(0, 0, 0, 255)
|
||||
end
|
||||
|
||||
surface.SetDrawColor(Bbg_col)
|
||||
surface.DrawRect(0, 0, w, h)
|
||||
|
||||
local w_x, h_x = surface.GetTextSize("×")
|
||||
surface.SetTextColor(Bfg_col)
|
||||
surface.SetTextPos((ScreenScaleMulti(16) - w_x) / 2, (ScreenScaleMulti(16) - h_x) / 2)
|
||||
surface.SetFont("ArcCW_12")
|
||||
surface.DrawText("×")
|
||||
end
|
||||
c = c + 1
|
||||
end
|
||||
|
||||
if c == 0 then
|
||||
local label = vgui.Create("DLabel", presetsmenu)
|
||||
label:SetSize(ScreenScaleMulti(254), ScreenScaleMulti(14))
|
||||
label:SetText("")
|
||||
label:Dock(TOP)
|
||||
label:DockMargin( 0, 0, 0, ScreenScaleMulti(2) )
|
||||
|
||||
label.Paint = function(spaa, w, h)
|
||||
local Bfg_col = Color(255, 255, 255, 255)
|
||||
|
||||
local txt = "No presets found! Go make some!"
|
||||
|
||||
surface.SetTextColor(Bfg_col)
|
||||
surface.SetTextPos(ScreenScaleMulti(2), ScreenScaleMulti(1))
|
||||
surface.SetFont("ArcCW_12")
|
||||
surface.DrawText(txt)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:ClosePresetMenu()
|
||||
end
|
||||
266
lua/weapons/arccw_base/cl_scope.lua
Normal file
266
lua/weapons/arccw_base/cl_scope.lua
Normal file
@@ -0,0 +1,266 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
function SWEP:AdjustMouseSensitivity()
|
||||
if self:GetState() != ArcCW.STATE_SIGHTS then return end
|
||||
|
||||
local threshold = ArcCW.ConVars["adjustsensthreshold"]:GetFloat()
|
||||
|
||||
local irons = self:GetActiveSights() or {}
|
||||
|
||||
local tmag = ((irons.Magnification or 1) + (irons.ScopeMagnification or 0))
|
||||
|
||||
if tmag < threshold then return end
|
||||
|
||||
return 1 / tmag
|
||||
end
|
||||
|
||||
function SWEP:Scroll(var)
|
||||
local irons = self:GetActiveSights()
|
||||
|
||||
if irons.ScrollFunc == ArcCW.SCROLL_ZOOM then
|
||||
if !irons.ScopeMagnificationMin then return end
|
||||
if !irons.ScopeMagnificationMax then return end
|
||||
|
||||
local old = irons.ScopeMagnification
|
||||
|
||||
local minus = var < 0
|
||||
|
||||
var = math.abs(irons.ScopeMagnificationMax - irons.ScopeMagnificationMin)
|
||||
|
||||
var = var / (irons.ZoomLevels or 5)
|
||||
|
||||
if minus then
|
||||
var = var * -1
|
||||
end
|
||||
|
||||
irons.ScopeMagnification = irons.ScopeMagnification - var
|
||||
|
||||
irons.ScopeMagnification = math.Clamp(irons.ScopeMagnification, irons.ScopeMagnificationMin, irons.ScopeMagnificationMax)
|
||||
|
||||
self.SightMagnifications[irons.Slot or 0] = irons.ScopeMagnification
|
||||
|
||||
if old != irons.ScopeMagnification then
|
||||
self:MyEmitSound(irons.ZoomSound or "", 75, math.Rand(95, 105), 1, CHAN_ITEM)
|
||||
end
|
||||
|
||||
-- if !irons.MinZoom then return end
|
||||
-- if !irons.MaxZoom then return end
|
||||
|
||||
-- local old = irons.Magnification
|
||||
|
||||
-- irons.Magnification = irons.Magnification - var
|
||||
|
||||
-- irons.Magnification = math.Clamp(irons.Magnification, irons.MinZoom, irons.MaxZoom)
|
||||
|
||||
-- if old != irons.Magnification then
|
||||
-- self:MyEmitSound(irons.ZoomSound or "", 75, 100, 1, CHAN_ITEM)
|
||||
-- end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local ang0 = Angle(0, 0, 0)
|
||||
|
||||
SWEP.ViewPunchAngle = Angle(ang0)
|
||||
SWEP.ViewPunchVelocity = Angle(ang0)
|
||||
|
||||
function SWEP:OurViewPunch(angle)
|
||||
self.ViewPunchVelocity:Add(angle)
|
||||
for i = 1, 3 do self.ViewPunchVelocity[i] = math.Clamp(self.ViewPunchVelocity[i], -180, 180) end
|
||||
end
|
||||
|
||||
function SWEP:GetOurViewPunchAngles()
|
||||
local a = self:GetOwner():GetViewPunchAngles()
|
||||
for i = 1, 3 do a[i] = a[i] + self.ViewPunchAngle[i] * 10 end
|
||||
return a
|
||||
end
|
||||
|
||||
local function lensqr(ang)
|
||||
return (ang[1] ^ 2) + (ang[2] ^ 2) + (ang[3] ^ 2)
|
||||
end
|
||||
|
||||
-- scraped from source SDK 2013, just like this viewpunch damping code
|
||||
local PUNCH_DAMPING = 9
|
||||
local PUNCH_SPRING_CONSTANT = 120
|
||||
|
||||
function SWEP:DoOurViewPunch()
|
||||
-- if ( player->m_Local.m_vecPunchAngle->LengthSqr() > 0.001 || player->m_Local.m_vecPunchAngleVel->LengthSqr() > 0.001 )
|
||||
|
||||
local vpa = self.ViewPunchAngle
|
||||
local vpv = self.ViewPunchVelocity
|
||||
|
||||
if lensqr(vpa) + lensqr(vpv) > 0.000001 then
|
||||
-- {
|
||||
-- player->m_Local.m_vecPunchAngle += player->m_Local.m_vecPunchAngleVel * gpGlobals->frametime;
|
||||
-- float damping = 1 - (PUNCH_DAMPING * gpGlobals->frametime);
|
||||
|
||||
local ft = FrameTime()
|
||||
|
||||
vpa = vpa + (vpv * ft)
|
||||
local damping = 1 - (PUNCH_DAMPING * ft)
|
||||
|
||||
-- if ( damping < 0 )
|
||||
-- {
|
||||
-- damping = 0;
|
||||
-- }
|
||||
|
||||
if damping < 0 then damping = 0 end
|
||||
|
||||
-- player->m_Local.m_vecPunchAngleVel *= damping;
|
||||
|
||||
vpv = vpv * damping
|
||||
|
||||
-- // torsional spring
|
||||
-- // UNDONE: Per-axis spring constant?
|
||||
-- float springForceMagnitude = PUNCH_SPRING_CONSTANT * gpGlobals->frametime;
|
||||
local springforcemagnitude = PUNCH_SPRING_CONSTANT * ft
|
||||
-- springForceMagnitude = clamp(springForceMagnitude, 0.f, 2.f );
|
||||
springforcemagnitude = math.Clamp(springforcemagnitude, 0, 2)
|
||||
-- player->m_Local.m_vecPunchAngleVel -= player->m_Local.m_vecPunchAngle * springForceMagnitude;
|
||||
vpv = vpv - (vpa * springforcemagnitude)
|
||||
|
||||
-- // don't wrap around
|
||||
-- player->m_Local.m_vecPunchAngle.Init(
|
||||
-- clamp(player->m_Local.m_vecPunchAngle->x, -89.f, 89.f ),
|
||||
-- clamp(player->m_Local.m_vecPunchAngle->y, -179.f, 179.f ),
|
||||
-- clamp(player->m_Local.m_vecPunchAngle->z, -89.f, 89.f ) );
|
||||
-- }
|
||||
|
||||
vpa[1] = math.Clamp(vpa[1], -89.9, 89.9)
|
||||
vpa[2] = math.Clamp(vpa[2], -179.9, 179.9)
|
||||
vpa[3] = math.Clamp(vpa[3], -89.9, 89.9)
|
||||
|
||||
self.ViewPunchAngle = vpa
|
||||
self.ViewPunchVelocity = vpv
|
||||
else
|
||||
self.ViewPunchAngle = Angle(ang0)
|
||||
self.ViewPunchVelocity = Angle(ang0)
|
||||
end
|
||||
end
|
||||
|
||||
-- viewbob during reload and firing shake
|
||||
SWEP.ProceduralViewOffset = Angle(ang0)
|
||||
local procedural_spdlimit = 5
|
||||
local oldangtmp
|
||||
local mzang_fixed,mzang_fixed_last
|
||||
local mzang_velocity = Angle(ang0)
|
||||
local progress = 0
|
||||
local targint,targbool
|
||||
|
||||
function SWEP:CoolView(ply, pos, ang, fov)
|
||||
if !ang then return end
|
||||
if ply != LocalPlayer() then return end
|
||||
if ply:ShouldDrawLocalPlayer() then return end
|
||||
local vm = ply:GetViewModel()
|
||||
if !IsValid(vm) then return end
|
||||
local ftv = FrameTime()
|
||||
|
||||
local gunbone, gbslot = self:GetBuff_Override("LHIK_CamDriver")
|
||||
local lhik_anim_model = gbslot and self.Attachments[gbslot].GodDriver and self.Attachments[gbslot].GodDriver.Model
|
||||
if IsValid(lhik_anim_model) and lhik_anim_model:GetAttachment(gunbone) then
|
||||
local catang = lhik_anim_model:GetAttachment(gunbone).Ang
|
||||
|
||||
catang:Sub( Angle( 0, 90, 90 ) )
|
||||
catang.y = -catang.y
|
||||
local r = catang.r
|
||||
catang.r = -catang.p
|
||||
catang.p = -r
|
||||
|
||||
ang:RotateAroundAxis( ang:Right(), catang.x )
|
||||
ang:RotateAroundAxis( ang:Up(), catang.y )
|
||||
ang:RotateAroundAxis( ang:Forward(), catang.z )
|
||||
|
||||
end
|
||||
|
||||
-- Cam_Offset_Ang might not always be assigned properly. Try not to use it if it's nil, or it'll tilt the player's view.
|
||||
local att = self:GetBuff_Override("Override_CamAttachment", self.CamAttachment) or -1
|
||||
if vm:GetAttachment(att) and self.Cam_Offset_Ang then
|
||||
local attang = vm:WorldToLocalAngles(vm:GetAttachment(att).Ang)
|
||||
attang:Sub(self.Cam_Offset_Ang)
|
||||
ang:Add(attang)
|
||||
return
|
||||
end
|
||||
|
||||
local viewbobintensity = self.ProceduralViewBobIntensity or 0.3
|
||||
|
||||
if viewbobintensity == 0 then return end
|
||||
|
||||
oldpostmp = pos * 1
|
||||
oldangtmp = ang * 1
|
||||
|
||||
targbool = self:GetNextPrimaryFire() - .1 > CurTime()
|
||||
targint = targbool and 1 or 0
|
||||
targint = math.min(targint, 1-math.pow( vm:GetCycle(), 2 ) )
|
||||
progress = Lerp(ftv * 15, progress, targint)
|
||||
|
||||
local angpos = vm:GetAttachment(self.ProceduralViewBobAttachment or self.MuzzleEffectAttachment or 1)
|
||||
|
||||
if angpos and self:GetReloading() then
|
||||
mzang_fixed = vm:WorldToLocalAngles(angpos.Ang)
|
||||
mzang_fixed:Normalize()
|
||||
else return
|
||||
end
|
||||
|
||||
self.ProceduralViewOffset:Normalize()
|
||||
|
||||
if mzang_fixed_last then
|
||||
local delta = mzang_fixed - mzang_fixed_last
|
||||
delta:Normalize()
|
||||
mzang_velocity = mzang_velocity + delta * 2
|
||||
mzang_velocity.p = math.Approach(mzang_velocity.p, -self.ProceduralViewOffset.p * 2, ftv * 20)
|
||||
mzang_velocity.p = math.Clamp(mzang_velocity.p, -procedural_spdlimit, procedural_spdlimit)
|
||||
self.ProceduralViewOffset.p = self.ProceduralViewOffset.p + mzang_velocity.p * ftv
|
||||
self.ProceduralViewOffset.p = math.Clamp(self.ProceduralViewOffset.p, -90, 90)
|
||||
mzang_velocity.y = math.Approach(mzang_velocity.y, -self.ProceduralViewOffset.y * 2, ftv * 20)
|
||||
mzang_velocity.y = math.Clamp(mzang_velocity.y, -procedural_spdlimit, procedural_spdlimit)
|
||||
self.ProceduralViewOffset.y = self.ProceduralViewOffset.y + mzang_velocity.y * ftv
|
||||
self.ProceduralViewOffset.y = math.Clamp(self.ProceduralViewOffset.y, -90, 90)
|
||||
mzang_velocity.r = math.Approach(mzang_velocity.r, -self.ProceduralViewOffset.r * 2, ftv * 20)
|
||||
mzang_velocity.r = math.Clamp(mzang_velocity.r, -procedural_spdlimit, procedural_spdlimit)
|
||||
self.ProceduralViewOffset.r = self.ProceduralViewOffset.r + mzang_velocity.r * ftv
|
||||
self.ProceduralViewOffset.r = math.Clamp(self.ProceduralViewOffset.r, -90, 90)
|
||||
end
|
||||
|
||||
self.ProceduralViewOffset.p = math.Approach(self.ProceduralViewOffset.p, 0, (1 - progress) * ftv * -self.ProceduralViewOffset.p)
|
||||
self.ProceduralViewOffset.y = math.Approach(self.ProceduralViewOffset.y, 0, (1 - progress) * ftv * -self.ProceduralViewOffset.y)
|
||||
self.ProceduralViewOffset.r = math.Approach(self.ProceduralViewOffset.r, 0, (1 - progress) * ftv * -self.ProceduralViewOffset.r)
|
||||
mzang_fixed_last = mzang_fixed
|
||||
local ints = 3 * ArcCW.ConVars["vm_coolview_mult"]:GetFloat() * -viewbobintensity
|
||||
ang:RotateAroundAxis(ang:Right(), Lerp(progress, 0, -self.ProceduralViewOffset.p) * ints)
|
||||
ang:RotateAroundAxis(ang:Up(), Lerp(progress, 0, self.ProceduralViewOffset.y / 2) * ints)
|
||||
ang:RotateAroundAxis(ang:Forward(), Lerp(progress, 0, self.ProceduralViewOffset.r / 3) * ints)
|
||||
|
||||
ang = LerpAngle(0, ang, oldangtmp)
|
||||
end
|
||||
|
||||
function SWEP:CalcView(ply, pos, ang, fov)
|
||||
if !CLIENT then return end
|
||||
|
||||
if ArcCW.ConVars["vm_coolview"]:GetBool() then
|
||||
self:CoolView(ply, pos, ang, fov)
|
||||
end
|
||||
|
||||
if ArcCW.ConVars["shake"]:GetBool() and !engine.IsRecordingDemo() then
|
||||
local de = (0.2 + (self:GetSightDelta()*0.8))
|
||||
ang = ang + (AngleRand() * self.RecoilAmount * 0.006 * de)
|
||||
end
|
||||
|
||||
ang = ang + (self.ViewPunchAngle * 10)
|
||||
|
||||
return pos, ang, fov
|
||||
end
|
||||
|
||||
function SWEP:ShouldGlint()
|
||||
return self:GetBuff_Override("ScopeGlint") and self:GetState() == ArcCW.STATE_SIGHTS
|
||||
end
|
||||
|
||||
function SWEP:DoScopeGlint()
|
||||
end
|
||||
887
lua/weapons/arccw_base/cl_viewmodel.lua
Normal file
887
lua/weapons/arccw_base/cl_viewmodel.lua
Normal file
@@ -0,0 +1,887 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
--[[
|
||||
Please, for the love of god, don't create objects in functions that are called multiple times per frame.
|
||||
The garbage collector will explode and so will players' comptuters.
|
||||
|
||||
That means minimize usage of things that generate new objects, including:
|
||||
calls to Vector() or Angle(); use vector_origin and angle_zero if the value isn't modified
|
||||
arithmetic using +, -, * and / on Vectors and Angles; modifying individual parameters is fine
|
||||
functions like Angle:Right() and Vector:Angle(); however functions like Vector:Add() and Angle:Add() are fine
|
||||
|
||||
Cache them if you use them more than one time!
|
||||
]]
|
||||
|
||||
local mth = math
|
||||
local m_appor = mth.Approach
|
||||
local m_clamp = mth.Clamp
|
||||
local f_lerp = Lerp
|
||||
local srf = surface
|
||||
SWEP.ActualVMData = false
|
||||
local swayxmult, swayymult, swayzmult, swayspeed = 1, 1, 1, 1
|
||||
local lookxmult, lookymult = 1, 1
|
||||
SWEP.VMPos = Vector()
|
||||
SWEP.VMAng = Angle()
|
||||
SWEP.VMPosOffset = Vector()
|
||||
SWEP.VMAngOffset = Angle()
|
||||
SWEP.VMPosOffset_Lerp = Vector()
|
||||
SWEP.VMAngOffset_Lerp = Angle()
|
||||
SWEP.VMLookLerp = Angle()
|
||||
SWEP.StepBob = 0
|
||||
SWEP.StepBobLerp = 0
|
||||
SWEP.StepRandomX = 1
|
||||
SWEP.StepRandomY = 1
|
||||
SWEP.LastEyeAng = Angle()
|
||||
SWEP.SmoothEyeAng = Angle()
|
||||
SWEP.LastVelocity = Vector()
|
||||
SWEP.Velocity_Lerp = Vector()
|
||||
SWEP.VelocityLastDiff = 0
|
||||
SWEP.Breath_Intensity = 1
|
||||
SWEP.Breath_Rate = 1
|
||||
|
||||
-- magic variables
|
||||
local sprint_vec1 = Vector(-2, 5, 2)
|
||||
local sprint_vec2 = Vector(0, 7, 3)
|
||||
local sprint_ang1 = Angle(-15, -15, 0)
|
||||
local spring_ang2 = Angle(-15, 15, -22)
|
||||
local sight_vec1 = Vector(0, 15, -4)
|
||||
local sight_vec2 = Vector(1, 5, -1)
|
||||
local sight_ang1 = Angle(0, 0, -45)
|
||||
local sight_ang2 = Angle(-5, 0, -10)
|
||||
local sextra_vec = Vector(0.0002, 0.001, 0.005)
|
||||
|
||||
local procdraw_vec = Vector(0, 0, -5)
|
||||
local procdraw_ang = Angle(-70, 30, 0)
|
||||
local prochol_ang = Angle(-70, 30, 10)
|
||||
|
||||
local lst = SysTime()
|
||||
local function scrunkly()
|
||||
local ret = (SysTime() - (lst or SysTime())) * GetConVar("host_timescale"):GetFloat()
|
||||
return ret
|
||||
end
|
||||
|
||||
local function LerpC(t, a, b, powa)
|
||||
return a + (b - a) * math.pow(t, powa)
|
||||
end
|
||||
|
||||
local function ApproachMod(usrobj, to, dlt)
|
||||
usrobj[1] = m_appor(usrobj[1], to[1], dlt)
|
||||
usrobj[2] = m_appor(usrobj[2], to[2], dlt)
|
||||
usrobj[3] = m_appor(usrobj[3], to[3], dlt)
|
||||
end
|
||||
|
||||
local function LerpMod(usrobj, to, dlt, clamp_ang)
|
||||
usrobj[1] = f_lerp(dlt, usrobj[1], to[1])
|
||||
usrobj[2] = f_lerp(dlt, usrobj[2], to[2])
|
||||
usrobj[3] = f_lerp(dlt, usrobj[3], to[3])
|
||||
if clamp_ang then
|
||||
for i = 1, 3 do usrobj[i] = math.NormalizeAngle(usrobj[i]) end
|
||||
end
|
||||
end
|
||||
|
||||
local function LerpMod2(from, usrobj, dlt, clamp_ang)
|
||||
usrobj[1] = f_lerp(dlt, from[1], usrobj[1])
|
||||
usrobj[2] = f_lerp(dlt, from[2], usrobj[2])
|
||||
usrobj[3] = f_lerp(dlt, from[3], usrobj[3])
|
||||
if clamp_ang then
|
||||
for i = 1, 3 do usrobj[i] = math.NormalizeAngle(usrobj[i]) end
|
||||
end
|
||||
end
|
||||
|
||||
-- debug for testing garbage count
|
||||
-- TODO: comment this out or something before actually going into main branch
|
||||
local sw = false
|
||||
local tries = {}
|
||||
local totaltries = 1000
|
||||
local sw_start = 0
|
||||
local sw_orig = 0
|
||||
concommand.Add("arccw_dev_stopwatch", function() tries = {} sw = true end)
|
||||
|
||||
local function stopwatch(name)
|
||||
if !sw then return end
|
||||
if name == true then
|
||||
local d = (collectgarbage("count") - sw_orig)
|
||||
if #tries == 0 then print(" total garbage: " .. d) end
|
||||
table.insert(tries, d)
|
||||
if #tries == totaltries then
|
||||
sw = false
|
||||
local average = 0
|
||||
for _, v in ipairs(tries) do average = average + v end
|
||||
average = average / totaltries
|
||||
print("----------------------------------")
|
||||
print("average over " .. totaltries .. " tries: " .. average)
|
||||
end
|
||||
return
|
||||
end
|
||||
local gb = collectgarbage("count")
|
||||
if name then
|
||||
if #tries == 0 then print(name .. ": " .. (gb - sw_start)) end
|
||||
else
|
||||
if #tries == 0 then print("----------------------------------") end
|
||||
sw_orig = gb
|
||||
end
|
||||
sw_start = gb
|
||||
end
|
||||
|
||||
function SWEP:Move_Process(EyePos, EyeAng, velocity)
|
||||
local VMPos, VMAng = self.VMPos, self.VMAng
|
||||
local VMPosOffset, VMAngOffset = self.VMPosOffset, self.VMAngOffset
|
||||
local VMPosOffset_Lerp, VMAngOffset_Lerp = self.VMPosOffset_Lerp, self.VMAngOffset_Lerp
|
||||
local FT = scrunkly()
|
||||
local sightedmult = (self:GetState() == ArcCW.STATE_SIGHTS and 0.05) or 1
|
||||
local sg = self:GetSightDelta()
|
||||
VMPos:Set(EyePos)
|
||||
VMAng:Set(EyeAng)
|
||||
VMPosOffset.x = math.Clamp(velocity.z * 0.0025, -1, 1) * sightedmult
|
||||
VMPosOffset.x = VMPosOffset.x + (velocity.x * 0.001 * sg)
|
||||
VMPosOffset.y = math.Clamp(velocity.y * -0.002, -1, 1) * sightedmult
|
||||
VMPosOffset.z = math.Clamp(VMPosOffset.x * -2, -4, 4)
|
||||
VMPosOffset_Lerp.x = Lerp(8 * FT, VMPosOffset_Lerp.x, VMPosOffset.x)
|
||||
VMPosOffset_Lerp.y = Lerp(8 * FT, VMPosOffset_Lerp.y, VMPosOffset.y)
|
||||
VMPosOffset_Lerp.z = Lerp(8 * FT, VMPosOffset_Lerp.z, VMPosOffset.z)
|
||||
--VMAngOffset.x = math.Clamp(VMPosOffset.x * 8, -4, 4)
|
||||
VMAngOffset.y = VMPosOffset.y
|
||||
VMAngOffset.z = VMPosOffset.y * 0.5 + (VMPosOffset.x * -5) + (velocity.x * -0.005 * sg)
|
||||
VMAngOffset_Lerp.x = LerpC(10 * FT, VMAngOffset_Lerp.x, VMAngOffset.x, 0.75)
|
||||
VMAngOffset_Lerp.y = LerpC(5 * FT, VMAngOffset_Lerp.y, VMAngOffset.y, 0.6)
|
||||
VMAngOffset_Lerp.z = Lerp(25 * FT, VMAngOffset_Lerp.z, VMAngOffset.z)
|
||||
VMPos:Add(VMAng:Up() * VMPosOffset_Lerp.x)
|
||||
VMPos:Add(VMAng:Right() * VMPosOffset_Lerp.y)
|
||||
VMPos:Add(VMAng:Forward() * VMPosOffset_Lerp.z)
|
||||
VMAngOffset_Lerp:Normalize()
|
||||
VMAng:Add(VMAngOffset_Lerp)
|
||||
end
|
||||
|
||||
local stepend = math.pi * 4
|
||||
|
||||
function SWEP:Step_Process(EyePos, EyeAng, velocity)
|
||||
|
||||
local VMPos, VMAng = self.VMPos, self.VMAng
|
||||
local VMPosOffset, VMAngOffset = self.VMPosOffset, self.VMAngOffset
|
||||
local VMPosOffset_Lerp = self.VMPosOffset_Lerp
|
||||
local state = self:GetState()
|
||||
local sprd = self:GetSprintDelta()
|
||||
|
||||
if state == ArcCW.STATE_SPRINT and self:SelectAnimation("idle_sprint") and !self:GetReloading() and !self:CanShootWhileSprint() then
|
||||
velocity = 0
|
||||
else
|
||||
velocity = math.min(velocity:Length(), 400) * Lerp(sprd, 1, 1.25)
|
||||
end
|
||||
|
||||
local delta = math.abs(self.StepBob * 2 / stepend - 1)
|
||||
local FT = scrunkly() --FrameTime()
|
||||
local sightedmult = (state == ArcCW.STATE_SIGHTS and 0.25) or 1
|
||||
local sprintmult = (state == ArcCW.STATE_SPRINT and !self:CanShootWhileSprint() and 2) or 1
|
||||
local pronemult = (self:IsProne() and 10) or 1
|
||||
local onground = self:GetOwner():OnGround()
|
||||
self.StepBob = self.StepBob + (velocity * 0.00015 + (math.pow(delta, 0.01) * 0.03)) * swayspeed * FT * 300
|
||||
|
||||
if self.StepBob >= stepend then
|
||||
self.StepBob = 0
|
||||
self.StepRandomX = math.Rand(1, 1.5)
|
||||
self.StepRandomY = math.Rand(1, 1.5)
|
||||
end
|
||||
|
||||
if velocity == 0 then
|
||||
self.StepBob = 0
|
||||
end
|
||||
|
||||
if onground then
|
||||
-- oh no it says sex tra
|
||||
local sextra = vector_origin
|
||||
if (state == ArcCW.STATE_SPRINT and !self:CanShootWhileSprint() and !self:SelectAnimation("idle_sprint")) or true then
|
||||
sextra = LerpVector(sprd, vector_origin, sextra_vec)
|
||||
end
|
||||
|
||||
VMPosOffset.x = (math.sin(self.StepBob) * velocity * (0.000375 + sextra.x) * sightedmult * swayxmult) * self.StepRandomX
|
||||
VMPosOffset.y = (math.sin(self.StepBob * 0.5) * velocity * (0.0005 + sextra.y) * sightedmult * sprintmult * pronemult * swayymult) * self.StepRandomY
|
||||
VMPosOffset.z = math.sin(self.StepBob * 0.75) * velocity * (0.002 + sextra.z) * sightedmult * pronemult * swayzmult
|
||||
end
|
||||
|
||||
VMPosOffset_Lerp.x = Lerp(32 * FT, VMPosOffset_Lerp.x, VMPosOffset.x)
|
||||
VMPosOffset_Lerp.y = Lerp(4 * FT, VMPosOffset_Lerp.y, VMPosOffset.y)
|
||||
VMPosOffset_Lerp.z = Lerp(2 * FT, VMPosOffset_Lerp.z, VMPosOffset.z)
|
||||
VMAngOffset.x = VMPosOffset_Lerp.x * 2
|
||||
VMAngOffset.y = VMPosOffset_Lerp.y * -7.5
|
||||
VMAngOffset.z = VMPosOffset_Lerp.y * 10
|
||||
VMPos:Add(VMAng:Up() * VMPosOffset_Lerp.x)
|
||||
VMPos:Add(VMAng:Right() * VMPosOffset_Lerp.y)
|
||||
VMPos:Add(VMAng:Forward() * VMPosOffset_Lerp.z)
|
||||
VMAng:Add(VMAngOffset)
|
||||
end
|
||||
|
||||
function SWEP:Breath_Health()
|
||||
local owner = self:GetOwner()
|
||||
if !IsValid(owner) then return end
|
||||
local health = owner:Health()
|
||||
local maxhealth = owner:GetMaxHealth()
|
||||
self.Breath_Intensity = math.Clamp(maxhealth / health, 0, 2)
|
||||
self.Breath_Rate = math.Clamp((maxhealth * 0.5) / health, 1, 1.5)
|
||||
end
|
||||
|
||||
function SWEP:Breath_StateMult()
|
||||
local owner = self:GetOwner()
|
||||
if !IsValid(owner) then return end
|
||||
local sightedmult = (self:GetState() == ArcCW.STATE_SIGHTS and 0.05) or 1
|
||||
self.Breath_Intensity = self.Breath_Intensity * sightedmult
|
||||
end
|
||||
|
||||
function SWEP:Breath_Process(EyePos, EyeAng)
|
||||
local VMPos, VMAng = self.VMPos, self.VMAng
|
||||
local VMPosOffset, VMAngOffset = self.VMPosOffset, self.VMAngOffset
|
||||
-- self:Breath_Health() Snaps around when regenerating
|
||||
self:Breath_StateMult()
|
||||
VMPosOffset.x = (math.sin(CurTime() * 2 * self.Breath_Rate) * 0.1) * self.Breath_Intensity
|
||||
VMPosOffset.y = (math.sin(CurTime() * 2.5 * self.Breath_Rate) * 0.025) * self.Breath_Intensity
|
||||
VMAngOffset.x = VMPosOffset.x * 1.5
|
||||
VMAngOffset.y = VMPosOffset.y * 2
|
||||
VMAngOffset.z = VMPosOffset.y * VMPosOffset.x * -40
|
||||
VMPos:Add(VMAng:Up() * VMPosOffset.x)
|
||||
VMPos:Add(VMAng:Right() * VMPosOffset.y)
|
||||
VMAng:Add(VMAngOffset)
|
||||
end
|
||||
|
||||
function SWEP:Look_Process(EyePos, EyeAng, velocity)
|
||||
local VMPos, VMAng = self.VMPos, self.VMAng
|
||||
local VMPosOffset, VMAngOffset = self.VMPosOffset, self.VMAngOffset
|
||||
local FT = scrunkly()
|
||||
local sightedmult = (self:GetState() == ArcCW.STATE_SIGHTS and 0.25) or 1
|
||||
self.SmoothEyeAng = LerpAngle(0.05, self.SmoothEyeAng, EyeAng - self.LastEyeAng)
|
||||
-- local xd, yd = (velocity.z / 10), (velocity.y / 200)
|
||||
VMPosOffset.x = -self.SmoothEyeAng.x * -0.5 * sightedmult * lookxmult
|
||||
VMPosOffset.y = self.SmoothEyeAng.y * 0.5 * sightedmult * lookymult
|
||||
VMAngOffset.x = VMPosOffset.x * 0.75
|
||||
VMAngOffset.y = VMPosOffset.y * 2.5
|
||||
VMAngOffset.z = VMPosOffset.x * 2 + VMPosOffset.y * -2
|
||||
self.VMLookLerp.y = Lerp(FT * 10, self.VMLookLerp.y, VMAngOffset.y * -1.5 + self.SmoothEyeAng.y)
|
||||
VMAng.y = VMAng.y - self.VMLookLerp.y
|
||||
VMPos:Add(VMAng:Up() * VMPosOffset.x)
|
||||
VMPos:Add(VMAng:Right() * VMPosOffset.y)
|
||||
VMAng:Add(VMAngOffset)
|
||||
end
|
||||
|
||||
function SWEP:GetVMPosition(EyePos, EyeAng)
|
||||
local velocity = self:GetOwner():GetVelocity()
|
||||
velocity = WorldToLocal(velocity, angle_zero, vector_origin, EyeAng)
|
||||
self:Move_Process(EyePos, EyeAng, velocity)
|
||||
stopwatch("Move_Process")
|
||||
self:Step_Process(EyePos, EyeAng, velocity)
|
||||
stopwatch("Step_Process")
|
||||
self:Breath_Process(EyePos, EyeAng)
|
||||
stopwatch("Breath_Process")
|
||||
self:Look_Process(EyePos, EyeAng, velocity)
|
||||
stopwatch("Look_Process")
|
||||
self.LastEyeAng = EyeAng
|
||||
self.LastEyePos = EyePos
|
||||
self.LastVelocity = velocity
|
||||
|
||||
return self.VMPos, self.VMAng
|
||||
end
|
||||
|
||||
SWEP.TheJ = {posa = Vector(), anga = Angle()}
|
||||
local rap_pos = Vector()
|
||||
local rap_ang = Angle()
|
||||
|
||||
local actual
|
||||
local target = {pos = Vector(), ang = Angle()}
|
||||
|
||||
local GunDriverFix = Angle( 0, 90, 90 )
|
||||
|
||||
function SWEP:GetViewModelPosition(pos, ang)
|
||||
if ArcCW.ConVars["dev_benchgun"]:GetBool() then
|
||||
if ArcCW.ConVars["dev_benchgun_custom"]:GetString() then
|
||||
local bgc = ArcCW.ConVars["dev_benchgun_custom"]:GetString()
|
||||
if string.Left(bgc, 6) != "setpos" then return vector_origin, angle_zero end
|
||||
|
||||
bgc = string.TrimLeft(bgc, "setpos ")
|
||||
bgc = string.Replace(bgc, ";setang", "")
|
||||
bgc = string.Explode(" ", bgc)
|
||||
|
||||
return Vector(bgc[1], bgc[2], bgc[3]), Angle(bgc[4], bgc[5], bgc[6])
|
||||
else
|
||||
return vector_origin, angle_zero
|
||||
end
|
||||
end
|
||||
|
||||
stopwatch()
|
||||
|
||||
local owner = self:GetOwner()
|
||||
if !IsValid(owner) or !owner:Alive() then return end
|
||||
local FT = scrunkly()
|
||||
local CT = CurTime()
|
||||
local TargetTick = (1 / FT) / 66.66
|
||||
local cdelta = math.Clamp(math.ease.InOutSine((owner:GetViewOffset().z - owner:GetCurrentViewOffset().z) / (owner:GetViewOffset().z - owner:GetViewOffsetDucked().z)),0,1)
|
||||
|
||||
if TargetTick < 1 then
|
||||
FT = FT * TargetTick
|
||||
end
|
||||
|
||||
local vm = LocalPlayer():GetViewModel()
|
||||
|
||||
local asight = self:GetActiveSights()
|
||||
local state = self:GetState()
|
||||
local sgtd = self:GetSightDelta()
|
||||
local sprd = self:GetSprintDelta()
|
||||
|
||||
local sprinted = self.Sprinted or state == ArcCW.STATE_SPRINT and !self:CanShootWhileSprint()
|
||||
local sighted = self.Sighted or state == ArcCW.STATE_SIGHTS
|
||||
local holstered = self:GetCurrentFiremode().Mode == 0
|
||||
|
||||
if game.SinglePlayer() then
|
||||
sprinted = state == ArcCW.STATE_SPRINT and !self:CanShootWhileSprint()
|
||||
sighted = state == ArcCW.STATE_SIGHTS
|
||||
end
|
||||
|
||||
local oldpos, oldang = Vector(), Angle()
|
||||
oldpos:Set(pos)
|
||||
oldang:Set(ang)
|
||||
ang:Sub(self:GetOurViewPunchAngles())
|
||||
|
||||
actual = self.ActualVMData or {
|
||||
pos = Vector(),
|
||||
ang = Angle(),
|
||||
down = 1,
|
||||
sway = 1,
|
||||
bob = 1,
|
||||
evpos = Vector(),
|
||||
evang = Angle(),
|
||||
}
|
||||
|
||||
local apos, aang = self:GetBuff_Override("Override_ActivePos", self.ActivePos), self:GetBuff_Override("Override_ActiveAng", self.ActiveAng)
|
||||
local cpos, cang = self:GetBuff("CrouchPos", true) or apos, self:GetBuff("CrouchAng", true) or aang
|
||||
target.down = 1
|
||||
target.sway = 2
|
||||
target.bob = 2
|
||||
|
||||
stopwatch("set")
|
||||
|
||||
if self:InBipod() and self:GetBipodAngle() then
|
||||
local bpos = self:GetBuff_Override("Override_InBipodPos", self.InBipodPos)
|
||||
target.pos:Set(asight and asight.Pos or apos)
|
||||
target.ang:Set(asight and asight.Ang or aang)
|
||||
|
||||
local BEA = (self.BipodStartAngle or self:GetBipodAngle()) - owner:EyeAngles()
|
||||
target.pos:Add(BEA:Right() * bpos.x * self.InBipodMult.x)
|
||||
target.pos:Add(BEA:Forward() * bpos.y * self.InBipodMult.y)
|
||||
target.pos:Add(BEA:Up() * bpos.z * self.InBipodMult.z)
|
||||
target.sway = 0.2
|
||||
-- elseif (owner:Crouching() or owner:KeyDown(IN_DUCK)) and !self:GetReloading() then
|
||||
-- target.pos:Set(self:GetBuff("CrouchPos", true) or apos)
|
||||
-- target.ang:Set(self:GetBuff("CrouchAng", true) or aang)
|
||||
elseif self:GetReloading() then
|
||||
target.pos:Set(self:GetBuff("ReloadPos", true) or apos)
|
||||
target.ang:Set(self:GetBuff("ReloadAng", true) or aang)
|
||||
else
|
||||
target.pos:Set(apos)
|
||||
target.ang:Set(aang)
|
||||
LerpMod(target.pos, cpos, cdelta)
|
||||
LerpMod(target.ang, cang, cdelta, true)
|
||||
end
|
||||
if (owner:Crouching() or owner:KeyDown(IN_DUCK)) then target.down = 0 end
|
||||
|
||||
stopwatch("reload, crouch, bipod")
|
||||
|
||||
target.pos.x = target.pos.x + ArcCW.ConVars["vm_right"]:GetFloat()
|
||||
target.pos.y = target.pos.y + ArcCW.ConVars["vm_forward"]:GetFloat()
|
||||
target.pos.z = target.pos.z + ArcCW.ConVars["vm_up"]:GetFloat()
|
||||
|
||||
target.ang.p = target.ang.p + ArcCW.ConVars["vm_pitch"]:GetFloat()
|
||||
target.ang.y = target.ang.y + ArcCW.ConVars["vm_yaw"]:GetFloat()
|
||||
target.ang.r = target.ang.r + ArcCW.ConVars["vm_roll"]:GetFloat()
|
||||
|
||||
if state == ArcCW.STATE_CUSTOMIZE then
|
||||
target.down = 1
|
||||
target.sway = 3
|
||||
target.bob = 1
|
||||
local mx, my = input.GetCursorPos()
|
||||
mx = 2 * mx / ScrW()
|
||||
my = 2 * my / ScrH()
|
||||
target.pos:Set(self:GetBuff_Override("Override_CustomizePos", self.CustomizePos))
|
||||
target.ang:Set(self:GetBuff_Override("Override_CustomizeAng", self.CustomizeAng))
|
||||
target.pos.x = target.pos.x + mx
|
||||
target.pos.z = target.pos.z + my
|
||||
target.ang.y = target.ang.y + my * 2
|
||||
target.ang.r = target.ang.r + mx * 2
|
||||
if self.InAttMenu then
|
||||
target.ang.y = target.ang.y - 5
|
||||
end
|
||||
end
|
||||
|
||||
stopwatch("cust")
|
||||
|
||||
-- Sprinting
|
||||
local hpos, spos = self:GetBuff("HolsterPos", true), self:GetBuff("SprintPos", true)
|
||||
local hang, sang = self:GetBuff("HolsterAng", true), self:GetBuff("SprintAng", true)
|
||||
do
|
||||
local aaaapos = holstered and (hpos or spos) or (spos or hpos)
|
||||
local aaaaang = holstered and (hang or sang) or (sang or hang)
|
||||
|
||||
local sd = (self:GetReloading() and 0) or (self:IsProne() and math.Clamp(owner:GetVelocity():Length() / prone.Config.MoveSpeed, 0, 1)) or (holstered and 1) or (!self:CanShootWhileSprint() and sprd) or 0
|
||||
sd = math.pow(math.sin(sd * math.pi * 0.5), 2)
|
||||
|
||||
local d = math.pow(math.sin(sd * math.pi * 0.5), math.pi)
|
||||
local coolilove = d * math.cos(d * math.pi * 0.5)
|
||||
|
||||
local joffset, jaffset
|
||||
if !sprinted then
|
||||
joffset = sprint_vec2
|
||||
jaffset = spring_ang2
|
||||
else
|
||||
joffset = sprint_vec1
|
||||
jaffset = sprint_ang1
|
||||
end
|
||||
|
||||
LerpMod(target.pos, aaaapos, sd)
|
||||
LerpMod(target.ang, aaaaang, sd, true)
|
||||
for i = 1, 3 do
|
||||
target.pos[i] = target.pos[i] + joffset[i] * coolilove
|
||||
target.ang[i] = target.ang[i] + jaffset[i] * coolilove
|
||||
end
|
||||
|
||||
local fu_sprint = (sprinted and self:SelectAnimation("idle_sprint"))
|
||||
|
||||
target.sway = target.sway * f_lerp(sd, 1, fu_sprint and 0 or 2)
|
||||
target.bob = target.bob * f_lerp(sd, 1, fu_sprint and 0 or 2)
|
||||
end
|
||||
|
||||
stopwatch("sprint")
|
||||
|
||||
-- Sighting
|
||||
if asight then
|
||||
local delta = sgtd
|
||||
delta = math.pow(math.sin(delta * math.pi * 0.5), math.pi)
|
||||
local im = asight.Midpoint
|
||||
local coolilove = delta * math.cos(delta * math.pi * 0.5)
|
||||
|
||||
local joffset, jaffset
|
||||
if !sighted then
|
||||
joffset = sight_vec2
|
||||
jaffset = sight_ang2
|
||||
else
|
||||
joffset = (im and im.Pos or sight_vec1)
|
||||
jaffset = (im and im.Ang or sight_ang1)
|
||||
end
|
||||
|
||||
target.pos.z = target.pos.z - 1
|
||||
LerpMod2(asight.Pos, target.pos, delta)
|
||||
LerpMod2(asight.Ang, target.ang, delta)
|
||||
for i = 1, 3 do
|
||||
target.pos[i] = target.pos[i] + joffset[i] * coolilove
|
||||
target.ang[i] = target.ang[i] + jaffset[i] * coolilove
|
||||
end
|
||||
|
||||
target.evpos = f_lerp(delta, asight.EVPos or vector_origin, vector_origin)
|
||||
target.evang = f_lerp(delta, asight.EVAng or angle_zero, angle_zero)
|
||||
|
||||
target.down = 0
|
||||
target.sway = target.sway * f_lerp(delta, 0.1, 1)
|
||||
target.bob = target.bob * f_lerp(delta, 0.1, 1)
|
||||
end
|
||||
|
||||
stopwatch("sight")
|
||||
|
||||
local deg = self:GetBarrelNearWall()
|
||||
if deg > 0 and ArcCW.ConVars["vm_nearwall"]:GetBool() then
|
||||
LerpMod(target.pos, hpos, deg)
|
||||
LerpMod(target.ang, hang, deg)
|
||||
target.down = 2 * math.max(sgtd, 0.5)
|
||||
end
|
||||
|
||||
if !isangle(target.ang) then
|
||||
target.ang = Angle(target.ang)
|
||||
end
|
||||
|
||||
target.ang.y = target.ang.y + (self:GetFreeAimOffset().y * 0.5)
|
||||
target.ang.p = target.ang.p - (self:GetFreeAimOffset().p * 0.5)
|
||||
|
||||
if self.InProcDraw then
|
||||
self.InProcHolster = false
|
||||
local delta = m_clamp((CT - self.ProcDrawTime) / (0.5 * self:GetBuff_Mult("Mult_DrawTime")), 0, 1)
|
||||
target.pos = LerpVector(delta, procdraw_vec, target.pos)
|
||||
target.ang = LerpAngle(delta, procdraw_ang, target.ang)
|
||||
target.down = target.down
|
||||
target.sway = target.sway
|
||||
target.bob = target.bob
|
||||
end
|
||||
|
||||
if self.InProcHolster then
|
||||
self.InProcDraw = false
|
||||
local delta = 1 - m_clamp((CT - self.ProcHolsterTime) / (0.25 * self:GetBuff_Mult("Mult_DrawTime")), 0, 1)
|
||||
target.pos = LerpVector(delta, procdraw_vec, target.pos)
|
||||
target.ang = LerpAngle(delta, prochol_ang, target.ang)
|
||||
target.down = target.down
|
||||
target.sway = target.sway
|
||||
target.bob = target.bob
|
||||
end
|
||||
|
||||
if self.InProcBash then
|
||||
self.InProcDraw = false
|
||||
local mult = self:GetBuff_Mult("Mult_MeleeTime")
|
||||
local mtime = self.MeleeTime * mult
|
||||
local delta = 1 - m_clamp((CT - self.ProcBashTime) / mtime, 0, 1)
|
||||
|
||||
local bp, ba
|
||||
|
||||
if delta > 0.3 then
|
||||
bp = self:GetBuff_Override("Override_BashPreparePos", self.BashPreparePos)
|
||||
ba = self:GetBuff_Override("Override_BashPrepareAng", self.BashPrepareAng)
|
||||
delta = (delta - 0.5) * 2
|
||||
else
|
||||
bp = self:GetBuff_Override("Override_BashPos", self.BashPos)
|
||||
ba = self:GetBuff_Override("Override_BashAng", self.BashAng)
|
||||
delta = delta * 2
|
||||
end
|
||||
|
||||
LerpMod2(bp, target.pos, delta)
|
||||
LerpMod2(ba, target.ang, delta)
|
||||
|
||||
target.speed = 10
|
||||
|
||||
if delta == 0 then
|
||||
self.InProcBash = false
|
||||
end
|
||||
end
|
||||
|
||||
stopwatch("proc")
|
||||
|
||||
-- local gunbone, gbslot = self:GetBuff_Override("LHIK_GunDriver")
|
||||
-- if gunbone and IsValid(self.Attachments[gbslot].VElement.Model) and self.LHIKGunPos and self.LHIKGunAng then
|
||||
-- local magnitude = 1 --Lerp(sgtd, 0.1, 1)
|
||||
-- local lhik_model = self.Attachments[gbslot].VElement.Model
|
||||
-- local att = lhik_model:GetAttachment(lhik_model:LookupAttachment(gunbone))
|
||||
-- local attang = att.Ang
|
||||
-- local attpos = att.Pos
|
||||
-- attang = lhik_model:WorldToLocalAngles(attang)
|
||||
-- attpos = lhik_model:WorldToLocal(attpos)
|
||||
-- attang:Sub(self.LHIKGunAng)
|
||||
-- attpos:Sub(self.LHIKGunPos)
|
||||
-- attang:Mul(magnitude)
|
||||
-- attpos:Mul(magnitude)
|
||||
-- --target.ang:Add(attang)
|
||||
-- --target.pos:Add(attpos)
|
||||
-- --debugoverlay.Axis(lhik_model:GetPos() + attpos, att.Ang, 8, FrameTime() * 3, true)
|
||||
-- debugoverlay.Axis(lhik_model:GetPos(), att.Ang, 8, FrameTime() * 3, true)
|
||||
-- end
|
||||
|
||||
-- stopwatch("gunbone")
|
||||
|
||||
local vmhit = self.ViewModel_Hit
|
||||
if vmhit then
|
||||
if !vmhit:IsZero() then
|
||||
target.pos.x = target.pos.x + m_clamp(vmhit.y, -1, 1) * 0.25
|
||||
target.pos.y = target.pos.y + vmhit.y
|
||||
target.pos.z = target.pos.z + m_clamp(vmhit.x, -1, 1) * 1
|
||||
target.ang.x = target.ang.x + m_clamp(vmhit.x, -1, 1) * 5
|
||||
target.ang.y = target.ang.y + m_clamp(vmhit.y, -1, 1) * -2
|
||||
target.ang.z = target.ang.z + m_clamp(vmhit.z, -1, 1) * 12.5
|
||||
end
|
||||
|
||||
local spd = vmhit:Length() * 5
|
||||
vmhit.x = m_appor(vmhit.x, 0, FT * spd)
|
||||
vmhit.y = m_appor(vmhit.y, 0, FT * spd)
|
||||
vmhit.z = m_appor(vmhit.z, 0, FT * spd)
|
||||
end
|
||||
|
||||
if ArcCW.ConVars["shakevm"]:GetBool() and !engine.IsRecordingDemo() then
|
||||
target.pos:Add(VectorRand() * self.RecoilAmount * 0.2 * self.RecoilVMShake)
|
||||
end
|
||||
|
||||
stopwatch("vmhit")
|
||||
|
||||
local speed = 15 * FT * (game.SinglePlayer() and 1 or 2)
|
||||
|
||||
LerpMod(actual.pos, target.pos, speed)
|
||||
LerpMod(actual.ang, target.ang, speed, true)
|
||||
LerpMod(actual.evpos, target.evpos or vector_origin, speed)
|
||||
LerpMod(actual.evang, target.evang or angle_zero, speed, true)
|
||||
actual.down = f_lerp(speed, actual.down, target.down)
|
||||
actual.sway = f_lerp(speed, actual.sway, target.sway)
|
||||
actual.bob = f_lerp(speed, actual.bob, target.bob)
|
||||
|
||||
ApproachMod(actual.pos, target.pos, speed * 0.1)
|
||||
ApproachMod(actual.ang, target.ang, speed * 0.1)
|
||||
actual.down = m_appor(actual.down, target.down, speed * 0.1)
|
||||
|
||||
stopwatch("actual -> target")
|
||||
|
||||
local coolsway = ArcCW.ConVars["vm_coolsway"]:GetBool()
|
||||
self.SwayScale = (coolsway and 0) or actual.sway
|
||||
self.BobScale = (coolsway and 0) or actual.bob
|
||||
|
||||
if coolsway then
|
||||
swayxmult = ArcCW.ConVars["vm_sway_zmult"]:GetFloat() or 1
|
||||
swayymult = ArcCW.ConVars["vm_sway_xmult"]:GetFloat() or 1
|
||||
swayzmult = ArcCW.ConVars["vm_sway_ymult"]:GetFloat() or 1
|
||||
swayspeed = ArcCW.ConVars["vm_sway_speedmult"]:GetFloat() or 1
|
||||
lookxmult = ArcCW.ConVars["vm_look_xmult"]:GetFloat() or 1
|
||||
lookymult = ArcCW.ConVars["vm_look_ymult"]:GetFloat() or 1
|
||||
|
||||
local sd = self:GetSightDelta()
|
||||
lookxmult = Lerp(sd, 0, lookxmult)
|
||||
lookymult = Lerp(sd, 0, lookymult)
|
||||
swayxmult = Lerp(sd, 0, swayxmult)
|
||||
swayymult = Lerp(sd, 0, swayymult)
|
||||
swayzmult = Lerp(sd, 0, swayzmult)
|
||||
swayspeed = Lerp(sd, 0, swayspeed)
|
||||
|
||||
stopwatch("before vmposition")
|
||||
local npos, nang = self:GetVMPosition(oldpos, oldang)
|
||||
pos:Set(npos)
|
||||
ang:Set(nang)
|
||||
end
|
||||
|
||||
local old_r, old_f, old_u = oldang:Right(), oldang:Forward(), oldang:Up()
|
||||
pos:Add(math.min(self.RecoilPunchBack, Lerp(sgtd, self.RecoilPunchBackMaxSights or 1, self.RecoilPunchBackMax)) * -old_f)
|
||||
|
||||
ang:RotateAroundAxis(old_r, actual.ang.x)
|
||||
ang:RotateAroundAxis(old_u, actual.ang.y)
|
||||
ang:RotateAroundAxis(old_f, actual.ang.z)
|
||||
ang:RotateAroundAxis(old_r, actual.evang.x)
|
||||
ang:RotateAroundAxis(old_u, actual.evang.y)
|
||||
ang:RotateAroundAxis(old_f, actual.evang.z)
|
||||
|
||||
local new_r, new_f, new_u = ang:Right(), ang:Forward(), ang:Up()
|
||||
old_r:Mul(actual.evpos.x)
|
||||
old_f:Mul(actual.evpos.y)
|
||||
old_u:Mul(actual.evpos.z)
|
||||
pos:Add(old_r)
|
||||
pos:Add(old_f)
|
||||
pos:Add(old_u)
|
||||
new_r:Mul(actual.pos.x)
|
||||
new_f:Mul(actual.pos.y)
|
||||
new_u:Mul(actual.pos.z)
|
||||
pos:Add(new_r)
|
||||
pos:Add(new_f)
|
||||
pos:Add(new_u)
|
||||
|
||||
pos.z = pos.z - actual.down
|
||||
|
||||
ang:Add(self:GetOurViewPunchAngles() * Lerp(sgtd, 1, -1))
|
||||
|
||||
local gunbone, gbslot = self:GetBuff_Override("LHIK_GunDriver")
|
||||
local lhik_model = gbslot and self.Attachments[gbslot].VElement and self.Attachments[gbslot].VElement.Model -- Visual M203 attachment
|
||||
local lhik_anim_model = gbslot and self.Attachments[gbslot].GodDriver and self.Attachments[gbslot].GodDriver.Model -- M203 anim and camera
|
||||
local lhik_refl_model = gbslot and self.Attachments[gbslot].ReflectDriver and self.Attachments[gbslot].ReflectDriver.Model -- Rifle
|
||||
if IsValid(lhik_model) and IsValid(lhik_anim_model) and IsValid(lhik_refl_model) and lhik_anim_model:GetAttachment(lhik_anim_model:LookupAttachment(gunbone)) then
|
||||
local att = lhik_anim_model:LookupAttachment(gunbone)
|
||||
local offset = lhik_anim_model:GetAttachment(att).Pos
|
||||
local affset = lhik_anim_model:GetAttachment(att).Ang
|
||||
|
||||
affset:Sub( GunDriverFix )
|
||||
local r = affset.r
|
||||
affset.r = affset.p
|
||||
affset.p = -r
|
||||
affset.y = -affset.y
|
||||
|
||||
local anchor = self.Attachments[gbslot].VMOffsetPos
|
||||
|
||||
local looku = lhik_refl_model:LookupBone( self.Attachments[gbslot].Bone )
|
||||
local bonp, bona = lhik_refl_model:GetBonePosition( looku )
|
||||
if bonp == lhik_refl_model:GetPos() then
|
||||
bonp = lhik_refl_model:GetBoneMatrix( looku ):GetTranslation()
|
||||
bona = lhik_refl_model:GetBoneMatrix( looku ):GetAngles()
|
||||
end
|
||||
|
||||
if anchor and bonp then -- Not ready / deploying
|
||||
anchor = ( bonp + ( (bona:Forward()*anchor.x) + (bona:Right()*anchor.y) + (bona:Up()*anchor.z) ) )
|
||||
|
||||
debugoverlay.Axis(anchor, angle_zero, 4, FrameTime(), true)
|
||||
|
||||
rap_pos, rap_ang = ArcCW.RotateAroundPoint2(pos, ang, anchor, offset, affset)
|
||||
rap_pos:Sub(pos)
|
||||
rap_ang:Sub(ang)
|
||||
|
||||
pos:Add(rap_pos)
|
||||
ang:Add(rap_ang)
|
||||
end
|
||||
end
|
||||
|
||||
self.ActualVMData = actual
|
||||
|
||||
stopwatch("apply actual")
|
||||
|
||||
stopwatch(true)
|
||||
|
||||
lst = SysTime()
|
||||
return pos, ang
|
||||
end
|
||||
|
||||
function SWEP:ShouldCheapWorldModel()
|
||||
local lp = LocalPlayer()
|
||||
if lp:GetObserverMode() == OBS_MODE_IN_EYE and lp:GetObserverTarget() == self:GetOwner() then return true end
|
||||
if !IsValid(self:GetOwner()) and !ArcCW.ConVars["att_showground"]:GetBool() then return true end
|
||||
|
||||
return !ArcCW.ConVars["att_showothers"]:GetBool()
|
||||
end
|
||||
|
||||
local bird = Material("arccw/hud/arccw_bird.png", "mips smooth")
|
||||
local iw = 32
|
||||
|
||||
function SWEP:DrawWorldModel()
|
||||
local cvar2d3d = ArcCW.ConVars["2d3d"]:GetInt()
|
||||
if !IsValid(self:GetOwner()) and !TTT2
|
||||
and (cvar2d3d == 2 or (cvar2d3d == 1 and LocalPlayer():GetEyeTrace().Entity == self))
|
||||
and (EyePos() - self:WorldSpaceCenter()):LengthSqr() <= 262144 then -- 512^2
|
||||
local ang = LocalPlayer():EyeAngles()
|
||||
ang:RotateAroundAxis(ang:Forward(), 180)
|
||||
ang:RotateAroundAxis(ang:Right(), 90)
|
||||
ang:RotateAroundAxis(ang:Up(), 90)
|
||||
cam.Start3D2D(self:WorldSpaceCenter() + Vector(0, 0, 16), ang, 0.1)
|
||||
|
||||
srf.SetFont("ArcCW_32_Unscaled")
|
||||
local w = srf.GetTextSize(self.PrintName)
|
||||
srf.SetTextPos(-w / 2 + 2, 2)
|
||||
srf.SetTextColor(0, 0, 0, 150)
|
||||
srf.DrawText(self.PrintName)
|
||||
srf.SetTextPos(-w / 2, 0)
|
||||
srf.SetTextColor(255, 255, 255, 255)
|
||||
srf.DrawText(self.PrintName)
|
||||
|
||||
local icons = {}
|
||||
for i, slot in pairs(self.Attachments or {}) do
|
||||
if slot.Installed then
|
||||
local atttbl = ArcCW.AttachmentTable[slot.Installed]
|
||||
if !atttbl then continue end
|
||||
local icon = atttbl.Icon
|
||||
if !icon or icon:IsError() then icon = bird end
|
||||
table.insert(icons, icon)
|
||||
end
|
||||
end
|
||||
|
||||
local ind = math.min(6, #icons)
|
||||
|
||||
surface.SetDrawColor(255, 255, 255)
|
||||
for i = 1, ind do
|
||||
if i == 6 and #icons > 6 then
|
||||
local str = "+" .. (#icons - ind)
|
||||
local strw = srf.GetTextSize(str)
|
||||
srf.SetTextPos(-ind * iw / 2 + (i - 1) * iw + 2 + strw / 2, iw + 14)
|
||||
srf.SetTextColor(0, 0, 0, 150)
|
||||
srf.DrawText(str)
|
||||
srf.SetTextPos(-ind * iw / 2 + (i - 1) * iw + strw / 2, iw + 12)
|
||||
srf.SetTextColor(255, 255, 255, 255)
|
||||
srf.DrawText(str)
|
||||
else
|
||||
local icon = icons[i]
|
||||
surface.SetMaterial(icon)
|
||||
surface.DrawTexturedRect(-ind * iw / 2 + (i - 1) * iw, iw + 12, iw, iw)
|
||||
end
|
||||
end
|
||||
|
||||
-- srf.SetFont("ArcCW_24_Unscaled")
|
||||
-- local count = self:CountAttachments()
|
||||
|
||||
-- if count > 0 then
|
||||
-- local t = tostring(count) .. " Attachments"
|
||||
-- w = srf.GetTextSize(t)
|
||||
-- srf.SetTextPos(-w / 2, 32)
|
||||
-- srf.SetTextColor(255, 255, 255, 255)
|
||||
-- srf.DrawText(t)
|
||||
-- end
|
||||
|
||||
cam.End3D2D()
|
||||
end
|
||||
|
||||
self:DrawCustomModel(true)
|
||||
self:DoLaser(true)
|
||||
|
||||
if self:ShouldGlint() then
|
||||
self:DoScopeGlint()
|
||||
end
|
||||
|
||||
if !self.CertainAboutAtts and !self.AttReqSent and !IsValid(self:GetOwner()) then
|
||||
self.AttReqSent = true
|
||||
-- print(self, "network weapon from cl_viewmodel")
|
||||
-- debugoverlay.Cross(self:GetPos(), 8, 10, color_white, true)
|
||||
-- debugoverlay.EntityTextAtPosition(self:GetPos(), 1, tostring(self) .. " requesting networking data", 10, color_white)
|
||||
net.Start("arccw_rqwpnnet")
|
||||
net.WriteEntity(self)
|
||||
net.SendToServer()
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:ShouldCheapScope()
|
||||
if !ArcCW.ConVars["cheapscopes"]:GetBool() then return end
|
||||
end
|
||||
|
||||
local POSTVMDONE = nil
|
||||
local POSTVMDONE_TIME = 0
|
||||
|
||||
local lst2 = SysTime()
|
||||
function SWEP:PreDrawViewModel(vm)
|
||||
if ArcCW.VM_OverDraw then return end
|
||||
if !vm then return end
|
||||
|
||||
if self:GetState() == ArcCW.STATE_CUSTOMIZE then
|
||||
self:BlurNotWeapon()
|
||||
end
|
||||
|
||||
if ArcCW.ConVars["cheapscopesautoconfig"]:GetBool() then
|
||||
local fps = 1 / (SysTime() - lst2)
|
||||
lst2 = SysTime()
|
||||
local lowfps = fps <= 45
|
||||
ArcCW.ConVars["cheapscopes"]:SetBool(lowfps)
|
||||
ArcCW.ConVars["cheapscopesautoconfig"]:SetBool(false)
|
||||
end
|
||||
|
||||
local asight = self:GetActiveSights()
|
||||
|
||||
if asight and ((ArcCW.ConVars["cheapscopes"]:GetBool() and self:GetSightDelta() < 1 and asight.MagnifiedOptic)
|
||||
or (self:GetSightDelta() < 1 and asight.ScopeTexture)) then
|
||||
-- Necessary to call here since physbullets are not drawn until PreDrawEffects; cheap scope implementation will not allow them to be visible
|
||||
-- Introduces a bug when we try to call GetAttachment on the viewmodel in DrawPhysBullets here, so set a workaround variable to not call it
|
||||
ArcCW:DrawPhysBullets(true)
|
||||
self:FormCheapScope()
|
||||
end
|
||||
|
||||
local coolFOV = self.CurrentViewModelFOV or self.ViewModelFOV
|
||||
|
||||
if ArcCW.VMInRT then
|
||||
local mag = asight.ScopeMagnification
|
||||
coolFOV = self.ViewModelFOV - mag * 4 - (ArcCW.ConVars["vm_add_ads"]:GetFloat() * 3 or 0)
|
||||
ArcCW.VMInRT = false
|
||||
end
|
||||
|
||||
cam.Start3D(EyePos(), EyeAngles(), self:QuickFOVix(coolFOV), nil, nil, nil, nil, 0.5, 1000)
|
||||
cam.IgnoreZ(true)
|
||||
self:DrawCustomModel(false)
|
||||
self:DoLHIK()
|
||||
|
||||
if !ArcCW.Overdraw then
|
||||
self:DoLaser(false, true)
|
||||
end
|
||||
|
||||
-- patrol
|
||||
if POSTVMDONE == false and POSTVMDONE_TIME <= CurTime() then
|
||||
POSTVMDONE_TIME = CurTime() + 1
|
||||
print( "[ArcCW] Warning: PostDrawViewModel failed response!! cam.End3D errors may be inbound!! You may have an addon conflict!!")
|
||||
print( "[ArcCW] Follow the troubleshooting guide at https://github.com/HaodongMo/ArcCW/wiki/Help-&-Troubleshooting#camend3d-errors")
|
||||
end
|
||||
POSTVMDONE = false
|
||||
end
|
||||
|
||||
function SWEP:PostDrawViewModel()
|
||||
POSTVMDONE = true
|
||||
if ArcCW.VM_OverDraw then return end
|
||||
render.SetBlend(1)
|
||||
cam.End3D()
|
||||
cam.Start3D(EyePos(), EyeAngles(), self:QuickFOVix(self.CurrentViewModelFOV or self.ViewModelFOV), nil, nil, nil, nil, 0.5, 1000)
|
||||
cam.IgnoreZ(true)
|
||||
|
||||
if ArcCW.Overdraw then
|
||||
ArcCW.Overdraw = false
|
||||
else
|
||||
--self:DoLaser()
|
||||
self:DoHolosight()
|
||||
end
|
||||
|
||||
cam.End3D()
|
||||
end
|
||||
311
lua/weapons/arccw_base/sh_anim.lua
Normal file
311
lua/weapons/arccw_base/sh_anim.lua
Normal file
@@ -0,0 +1,311 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
SWEP.Cam_Offset_Ang = nil --Angle(0, 0, 0)
|
||||
|
||||
function SWEP:SelectAnimation(anim)
|
||||
if self:GetNWState() == ArcCW.STATE_SIGHTS and self.Animations[anim .. "_iron"] then
|
||||
anim = anim .. "_iron"
|
||||
end
|
||||
|
||||
if self:GetNWState() == ArcCW.STATE_SIGHTS and self.Animations[anim .. "_sights"] then
|
||||
anim = anim .. "_sights"
|
||||
end
|
||||
|
||||
if self:GetNWState() == ArcCW.STATE_SIGHTS and self.Animations[anim .. "_sight"] then
|
||||
anim = anim .. "_sight"
|
||||
end
|
||||
|
||||
if self:GetNWState() == ArcCW.STATE_SPRINT and self.Animations[anim .. "_sprint"] and !self:CanShootWhileSprint() then
|
||||
anim = anim .. "_sprint"
|
||||
end
|
||||
|
||||
if self:InBipod() and self.Animations[anim .. "_bipod"] then
|
||||
anim = anim .. "_bipod"
|
||||
end
|
||||
|
||||
if self:GetState() == ArcCW.STATE_CUSTOMIZE and self.Animations[anim .. "_inspect"] and ((CLIENT and !ArcCW.ConVars["noinspect"]:GetBool()) or (SERVER and self:GetOwner():GetInfoNum("arccw_noinspect", 0))) then
|
||||
anim = anim .. "_inspect"
|
||||
end
|
||||
|
||||
if (self:Clip1() == 0 or (self:HasBottomlessClip() and self:Ammo1() == 0)) and self.Animations[anim .. "_empty"] then
|
||||
anim = anim .. "_empty"
|
||||
end
|
||||
|
||||
if self:GetMalfunctionJam() and self.Animations[anim .. "_jammed"] then
|
||||
anim = anim .. "_jammed"
|
||||
end
|
||||
|
||||
if self:GetBuff_Override("Override_TriggerDelay", self.TriggerDelay) and self:IsTriggerHeld() and self.Animations[anim .. "_trigger"] then
|
||||
anim = anim .. "_trigger"
|
||||
end
|
||||
|
||||
if !self.Animations[anim] then return end
|
||||
|
||||
return anim
|
||||
end
|
||||
|
||||
SWEP.LastAnimStartTime = 0
|
||||
SWEP.LastAnimFinishTime = 0
|
||||
|
||||
function SWEP:PlayAnimationEZ(key, mult, priority)
|
||||
return self:PlayAnimation(key, mult, true, 0, false, false, priority, false)
|
||||
end
|
||||
|
||||
function SWEP:PlayAnimation(key, mult, pred, startfrom, tt, skipholster, priority, absolute)
|
||||
mult = mult or 1
|
||||
pred = pred or false
|
||||
startfrom = startfrom or 0
|
||||
tt = tt or false
|
||||
--skipholster = skipholster or false Unused
|
||||
priority = priority or false
|
||||
absolute = absolute or false
|
||||
if !key then return end
|
||||
|
||||
local ct = CurTime()
|
||||
|
||||
if self:GetPriorityAnim() and !priority then return end
|
||||
|
||||
if game.SinglePlayer() and SERVER and pred then
|
||||
net.Start("arccw_sp_anim")
|
||||
net.WriteString(key)
|
||||
net.WriteFloat(mult)
|
||||
net.WriteFloat(startfrom)
|
||||
net.WriteBool(tt)
|
||||
--net.WriteBool(skipholster) Unused
|
||||
net.WriteBool(priority)
|
||||
net.Send(self:GetOwner())
|
||||
end
|
||||
|
||||
local anim = self.Animations[key]
|
||||
if !anim then return end
|
||||
local tranim = self:GetBuff_Hook("Hook_TranslateAnimation", key)
|
||||
if self.Animations[tranim] then
|
||||
key = tranim
|
||||
anim = self.Animations[tranim]
|
||||
--[[elseif self.Animations[key] then -- Can't do due to backwards compatibility... unless you have a better idea?
|
||||
anim = self.Animations[key]
|
||||
else
|
||||
return]]
|
||||
end
|
||||
|
||||
if anim.ViewPunchTable and CLIENT then
|
||||
for k, v in pairs(anim.ViewPunchTable) do
|
||||
|
||||
if !v.t then continue end
|
||||
|
||||
local st = (v.t * mult) - startfrom
|
||||
|
||||
if isnumber(v.t) and st >= 0 and self:GetOwner():IsPlayer() and (game.SinglePlayer() or IsFirstTimePredicted()) then
|
||||
self:SetTimer(st, function() self:OurViewPunch(v.p or Vector(0, 0, 0)) end, id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if isnumber(anim.ShellEjectAt) then
|
||||
self:SetTimer(anim.ShellEjectAt * mult, function()
|
||||
local num = 1
|
||||
if self.RevolverReload then
|
||||
num = self.Primary.ClipSize - self:Clip1()
|
||||
end
|
||||
for i = 1,num do
|
||||
self:DoShellEject()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
if !self:GetOwner() then return end
|
||||
if !self:GetOwner().GetViewModel then return end
|
||||
local vm = self:GetOwner():GetViewModel()
|
||||
|
||||
if !vm then return end
|
||||
if !IsValid(vm) then return end
|
||||
|
||||
local seq = anim.Source
|
||||
if anim.RareSource and util.SharedRandom("raresource", 0, 1, CurTime()) < (1 / (anim.RareSourceChance or 100)) then
|
||||
seq = anim.RareSource
|
||||
end
|
||||
seq = self:GetBuff_Hook("Hook_TranslateSequence", seq)
|
||||
|
||||
if istable(seq) then
|
||||
seq["BaseClass"] = nil
|
||||
seq = seq[math.Round(util.SharedRandom("randomseq" .. CurTime(), 1, #seq))]
|
||||
end
|
||||
|
||||
if isstring(seq) then
|
||||
seq = vm:LookupSequence(seq)
|
||||
end
|
||||
|
||||
local time = absolute and 1 or self:GetAnimKeyTime(key)
|
||||
--if time == 0 then return end
|
||||
|
||||
local ttime = (time * mult) - startfrom
|
||||
if startfrom > (time * mult) then return end
|
||||
|
||||
if tt then
|
||||
self:SetNextPrimaryFire(ct + ((anim.MinProgress or time) * mult) - startfrom)
|
||||
end
|
||||
|
||||
if anim.LHIK then
|
||||
self.LHIKStartTime = ct
|
||||
self.LHIKEndTime = ct + ttime
|
||||
|
||||
if anim.LHIKTimeline then
|
||||
self.LHIKTimeline = {}
|
||||
|
||||
for i, k in pairs(anim.LHIKTimeline) do
|
||||
table.Add(self.LHIKTimeline, {t = (k.t or 0) * mult, lhik = k.lhik or 1})
|
||||
end
|
||||
else
|
||||
self.LHIKTimeline = {
|
||||
{t = -math.huge, lhik = 1},
|
||||
{t = ((anim.LHIKIn or 0.1) - (anim.LHIKEaseIn or anim.LHIKIn or 0.1)) * mult, lhik = 1},
|
||||
{t = (anim.LHIKIn or 0.1) * mult, lhik = 0},
|
||||
{t = ttime - ((anim.LHIKOut or 0.1) * mult), lhik = 0},
|
||||
{t = ttime - (((anim.LHIKOut or 0.1) - (anim.LHIKEaseOut or anim.LHIKOut or 0.1)) * mult), lhik = 1},
|
||||
{t = math.huge, lhik = 1}
|
||||
}
|
||||
|
||||
if anim.LHIKIn == 0 then
|
||||
self.LHIKTimeline[1].lhik = -math.huge
|
||||
self.LHIKTimeline[2].lhik = -math.huge
|
||||
end
|
||||
|
||||
if anim.LHIKOut == 0 then
|
||||
self.LHIKTimeline[#self.LHIKTimeline - 1].lhik = math.huge
|
||||
self.LHIKTimeline[#self.LHIKTimeline].lhik = math.huge
|
||||
end
|
||||
end
|
||||
else
|
||||
self.LHIKTimeline = nil
|
||||
end
|
||||
|
||||
if anim.LastClip1OutTime then
|
||||
self.LastClipOutTime = ct + ((anim.LastClip1OutTime * mult) - startfrom)
|
||||
end
|
||||
|
||||
if anim.TPAnim then
|
||||
local aseq = self:GetOwner():SelectWeightedSequence(anim.TPAnim)
|
||||
if aseq then
|
||||
self:GetOwner():AddVCDSequenceToGestureSlot( GESTURE_SLOT_ATTACK_AND_RELOAD, aseq, anim.TPAnimStartTime or 0, true )
|
||||
if !game.SinglePlayer() and SERVER then
|
||||
net.Start("arccw_networktpanim")
|
||||
net.WriteEntity(self:GetOwner())
|
||||
net.WriteUInt(aseq, 16)
|
||||
net.WriteFloat(anim.TPAnimStartTime or 0)
|
||||
net.SendPVS(self:GetOwner():GetPos())
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if !(game.SinglePlayer() and CLIENT) and (game.SinglePlayer() or IsFirstTimePredicted() or self.ReadySoundTableHack) then
|
||||
self:PlaySoundTable(anim.SoundTable or {}, 1 / mult, startfrom, key)
|
||||
self.ReadySoundTableHack = nil
|
||||
end
|
||||
|
||||
if seq then
|
||||
vm:SendViewModelMatchingSequence(seq)
|
||||
local dur = vm:SequenceDuration()
|
||||
vm:SetPlaybackRate(math.Clamp(dur / (ttime + startfrom), -4, 12))
|
||||
self.LastAnimStartTime = ct
|
||||
self.LastAnimFinishTime = ct + dur
|
||||
self.LastAnimKey = key
|
||||
end
|
||||
|
||||
-- Grabs the current angle of the cam attachment bone and use it as the common offset for all cambone changes.
|
||||
-- Problem: If this animation interrupted a previous animation with cambone movement,
|
||||
-- it will start with an incorrect offset and snap at the end.
|
||||
-- Therefore this now only ever sets it once.
|
||||
local att = self:GetBuff_Override("Override_CamAttachment", self.CamAttachment)
|
||||
if att and vm:GetAttachment(att) and (anim.ForceCamReset or self.Cam_Offset_Ang == nil) then
|
||||
local ang = vm:GetAttachment(att).Ang
|
||||
ang = vm:WorldToLocalAngles(ang)
|
||||
self.Cam_Offset_Ang = Angle(ang)
|
||||
end
|
||||
|
||||
self:SetNextIdle(CurTime() + ttime)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:PlayIdleAnimation(pred)
|
||||
local ianim = self:SelectAnimation("idle")
|
||||
if self:GetGrenadePrimed() then
|
||||
ianim = self:GetGrenadeAlt() and self:SelectAnimation("pre_throw_hold_alt") or self:SelectAnimation("pre_throw_hold")
|
||||
end
|
||||
|
||||
-- (key, mult, pred, startfrom, tt, skipholster, ignorereload)
|
||||
if self:GetBuff_Override("UBGL_BaseAnims") and self:GetInUBGL()
|
||||
and self.Animations.idle_ubgl_empty and self:Clip2() <= 0 then
|
||||
ianim = "idle_ubgl_empty"
|
||||
elseif self:GetBuff_Override("UBGL_BaseAnims") and self:GetInUBGL() and self.Animations.idle_ubgl then
|
||||
ianim = "idle_ubgl"
|
||||
end
|
||||
|
||||
if self.LastAnimKey ~= ianim then
|
||||
ianim = self:GetBuff_Hook("Hook_IdleReset", ianim) or ianim
|
||||
end
|
||||
|
||||
self:PlayAnimation(ianim, 1, pred, nil, nil, nil, true)
|
||||
end
|
||||
|
||||
function SWEP:GetAnimKeyTime(key, min)
|
||||
if !self:GetOwner() then return 1 end
|
||||
|
||||
local anim = self.Animations[key]
|
||||
|
||||
if !anim then return 1 end
|
||||
|
||||
if self:GetOwner():IsNPC() then return anim.Time or 1 end
|
||||
|
||||
local vm = self:GetOwner():GetViewModel()
|
||||
|
||||
if !vm or !IsValid(vm) then return 1 end
|
||||
|
||||
local t = anim.Time
|
||||
if !t then
|
||||
local tseq = anim.Source
|
||||
|
||||
if istable(tseq) then
|
||||
tseq["BaseClass"] = nil -- god I hate Lua inheritance
|
||||
tseq = tseq[1]
|
||||
end
|
||||
|
||||
if !tseq then return 1 end
|
||||
tseq = vm:LookupSequence(tseq)
|
||||
|
||||
-- to hell with it, just spits wrong on draw sometimes
|
||||
t = vm:SequenceDuration(tseq) or 1
|
||||
end
|
||||
|
||||
if min and anim.MinProgress then
|
||||
t = anim.MinProgress
|
||||
end
|
||||
|
||||
if anim.Mult then
|
||||
t = t * anim.Mult
|
||||
end
|
||||
|
||||
return t
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
net.Receive("arccw_networktpanim", function()
|
||||
local ent = net.ReadEntity()
|
||||
local aseq = net.ReadUInt(16)
|
||||
local starttime = net.ReadFloat()
|
||||
if IsValid(ent) and ent ~= LocalPlayer() and ent:IsPlayer() then
|
||||
ent:AddVCDSequenceToGestureSlot( GESTURE_SLOT_ATTACK_AND_RELOAD, aseq, starttime, true )
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function SWEP:QueueAnimation() end
|
||||
function SWEP:NextAnimation() end
|
||||
1777
lua/weapons/arccw_base/sh_attach.lua
Normal file
1777
lua/weapons/arccw_base/sh_attach.lua
Normal file
File diff suppressed because it is too large
Load Diff
271
lua/weapons/arccw_base/sh_bash.lua
Normal file
271
lua/weapons/arccw_base/sh_bash.lua
Normal file
@@ -0,0 +1,271 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
function SWEP:CanBackstab(melee2, ent)
|
||||
if !self:GetBuff_Override("Override_Backstab", self.Backstab) then return false end
|
||||
local reach = 32 + self:GetBuff_Add("Add_MeleeRange") + (melee2 and self.Melee2Range or self.MeleeRange)
|
||||
|
||||
if (!IsValid(ent)) then
|
||||
local tr = util.TraceLine({
|
||||
start = self:GetOwner():GetShootPos(),
|
||||
endpos = self:GetOwner():GetShootPos() + self:GetOwner():GetAimVector() * reach,
|
||||
filter = {self:GetOwner()},
|
||||
mask = MASK_SHOT_HULL
|
||||
})
|
||||
if tr.Entity:IsPlayer() or tr.Entity:IsNPC() or tr.Entity:IsNextBot() then
|
||||
ent = tr.Entity
|
||||
end
|
||||
end
|
||||
|
||||
if (!IsValid(ent)) then
|
||||
local tr = util.TraceHull({
|
||||
start = self:GetOwner():GetShootPos(),
|
||||
endpos = self:GetOwner():GetShootPos() + self:GetOwner():GetAimVector() * reach,
|
||||
filter = {self:GetOwner()},
|
||||
mins = Vector(-16, -16, -8),
|
||||
maxs = Vector(16, 16, 8),
|
||||
mask = MASK_SHOT_HULL
|
||||
})
|
||||
if tr.Entity:IsPlayer() or tr.Entity:IsNPC() or tr.Entity:IsNextBot() then
|
||||
ent = tr.Entity
|
||||
end
|
||||
end
|
||||
|
||||
if IsValid(ent) then
|
||||
local angle = math.NormalizeAngle(self:GetOwner():GetAngles().y - ent:GetAngles().y)
|
||||
return angle <= 90 and angle >= -90
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:DoLunge(melee2)
|
||||
if ArcCW.ConVars["override_lunge_off"]:GetBool() then return end
|
||||
local var = self:GetBuff_Override("Override_Lunge", self.Lunge)
|
||||
if var == false or var == nil and self.PrimaryBash then return end
|
||||
if !self:GetOwner():IsPlayer() or self:GetOwner():Crouching() then return end
|
||||
|
||||
local reach = 32 + self:GetBuff_Add("Add_MeleeRange") + (melee2 and self.Melee2Range or self.MeleeRange)
|
||||
local tr = self:GetOwner():GetEyeTrace()
|
||||
local tgt = tr.Entity
|
||||
|
||||
if IsValid(tgt) and (tgt:IsPlayer() or tgt:IsNPC() or tgt:IsNextBot()) then
|
||||
|
||||
local dist = (tr.HitPos - tr.StartPos):Length()
|
||||
|
||||
if dist > reach and dist < reach + self:GetBuff("LungeLength") then
|
||||
local dir = tr.Normal
|
||||
dir.z = math.min(dir.z, 0)
|
||||
dir:Normalize()
|
||||
self:GetOwner():SetVelocity(dir * (self:GetOwner():IsOnGround() and 5 or 2.5) * dist)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Bash(melee2)
|
||||
melee2 = melee2 or false
|
||||
if self:GetState() == ArcCW.STATE_SIGHTS
|
||||
or (self:GetState() == ArcCW.STATE_SPRINT and !self:CanShootWhileSprint())
|
||||
or self:GetState() == ArcCW.STATE_CUSTOMIZE then
|
||||
return
|
||||
end
|
||||
if self:GetNextPrimaryFire() > CurTime() or self:GetGrenadePrimed() or self:GetPriorityAnim() then return end
|
||||
|
||||
if !self.CanBash and !self:GetBuff_Override("Override_CanBash") then return end
|
||||
|
||||
self:GetBuff_Hook("Hook_PreBash")
|
||||
|
||||
self.Primary.Automatic = true
|
||||
|
||||
local mult = self:GetBuff_Mult("Mult_MeleeTime")
|
||||
local mt = self.MeleeTime * mult
|
||||
|
||||
if melee2 then
|
||||
mt = self.Melee2Time * mult
|
||||
end
|
||||
|
||||
mt = mt * self:GetBuff_Mult("Mult_MeleeWaitTime")
|
||||
|
||||
local bashanim = "bash"
|
||||
local canbackstab = self:CanBackstab(melee2)
|
||||
|
||||
if melee2 then
|
||||
bashanim = canbackstab and self:SelectAnimation("bash2_backstab") or self:SelectAnimation("bash2") or bashanim
|
||||
else
|
||||
bashanim = canbackstab and self:SelectAnimation("bash_backstab") or self:SelectAnimation("bash") or bashanim
|
||||
end
|
||||
|
||||
bashanim = self:GetBuff_Hook("Hook_SelectBashAnim", bashanim) or bashanim
|
||||
|
||||
if bashanim and self.Animations[bashanim] then
|
||||
if SERVER then self:PlayAnimation(bashanim, mult, true, 0, true) end
|
||||
else
|
||||
self:ProceduralBash()
|
||||
|
||||
self:MyEmitSound(self.MeleeSwingSound, 75, 100, 1, CHAN_USER_BASE + 1)
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
self:OurViewPunch(-self.BashPrepareAng * 0.05)
|
||||
end
|
||||
self:SetNextPrimaryFire(CurTime() + mt )
|
||||
|
||||
if melee2 then
|
||||
if self.HoldtypeActive == "pistol" or self.HoldtypeActive == "revolver" then
|
||||
self:GetOwner():DoAnimationEvent(self.Melee2Gesture or ACT_HL2MP_GESTURE_RANGE_ATTACK_GRENADE)
|
||||
else
|
||||
self:GetOwner():DoAnimationEvent(self.Melee2Gesture or ACT_GMOD_GESTURE_MELEE_SHOVE_2HAND)
|
||||
end
|
||||
else
|
||||
if self.HoldtypeActive == "pistol" or self.HoldtypeActive == "revolver" then
|
||||
self:GetOwner():DoAnimationEvent(self.MeleeGesture or ACT_HL2MP_GESTURE_RANGE_ATTACK_GRENADE)
|
||||
else
|
||||
self:GetOwner():DoAnimationEvent(self.MeleeGesture or ACT_GMOD_GESTURE_MELEE_SHOVE_2HAND)
|
||||
end
|
||||
end
|
||||
|
||||
local mat = self.MeleeAttackTime
|
||||
|
||||
if melee2 then
|
||||
mat = self.Melee2AttackTime
|
||||
end
|
||||
|
||||
mat = mat * self:GetBuff_Mult("Mult_MeleeAttackTime") * math.pow(mult, 1.5)
|
||||
|
||||
self:SetTimer(mat or (0.125 * mt), function()
|
||||
if !IsValid(self) then return end
|
||||
if !IsValid(self:GetOwner()) then return end
|
||||
if self:GetOwner():GetActiveWeapon() != self then return end
|
||||
|
||||
if CLIENT then
|
||||
self:OurViewPunch(-self.BashAng * 0.05)
|
||||
end
|
||||
|
||||
self:MeleeAttack(melee2)
|
||||
end)
|
||||
|
||||
self:DoLunge()
|
||||
end
|
||||
|
||||
function SWEP:MeleeAttack(melee2)
|
||||
local reach = 32 + self:GetBuff_Add("Add_MeleeRange") + self.MeleeRange
|
||||
local dmg = self:GetBuff_Override("Override_MeleeDamage", self.MeleeDamage) or 20
|
||||
|
||||
if melee2 then
|
||||
reach = 32 + self:GetBuff_Add("Add_MeleeRange") + self.Melee2Range
|
||||
dmg = self:GetBuff_Override("Override_MeleeDamage", self.Melee2Damage) or 20
|
||||
end
|
||||
|
||||
dmg = dmg * self:GetBuff_Mult("Mult_MeleeDamage")
|
||||
|
||||
self:GetOwner():LagCompensation(true)
|
||||
|
||||
local filter = {self:GetOwner()}
|
||||
|
||||
table.Add(filter, self.Shields)
|
||||
|
||||
local tr = util.TraceLine({
|
||||
start = self:GetOwner():GetShootPos(),
|
||||
endpos = self:GetOwner():GetShootPos() + self:GetOwner():GetAimVector() * reach,
|
||||
filter = filter,
|
||||
mask = MASK_SHOT_HULL
|
||||
})
|
||||
|
||||
if (!IsValid(tr.Entity)) then
|
||||
tr = util.TraceHull({
|
||||
start = self:GetOwner():GetShootPos(),
|
||||
endpos = self:GetOwner():GetShootPos() + self:GetOwner():GetAimVector() * reach,
|
||||
filter = filter,
|
||||
mins = Vector(-16, -16, -8),
|
||||
maxs = Vector(16, 16, 8),
|
||||
mask = MASK_SHOT_HULL
|
||||
})
|
||||
end
|
||||
|
||||
-- Backstab damage if applicable
|
||||
local backstab = tr.Hit and self:CanBackstab(melee2, tr.Entity)
|
||||
if backstab then
|
||||
if melee2 then
|
||||
local bs_dmg = self:GetBuff_Override("Override_Melee2DamageBackstab", self.Melee2DamageBackstab)
|
||||
if bs_dmg then
|
||||
dmg = bs_dmg * self:GetBuff_Mult("Mult_MeleeDamage")
|
||||
else
|
||||
dmg = dmg * self:GetBuff("BackstabMultiplier") * self:GetBuff_Mult("Mult_MeleeDamage")
|
||||
end
|
||||
else
|
||||
local bs_dmg = self:GetBuff_Override("Override_MeleeDamageBackstab", self.MeleeDamageBackstab)
|
||||
if bs_dmg then
|
||||
dmg = bs_dmg * self:GetBuff_Mult("Mult_MeleeDamage")
|
||||
else
|
||||
dmg = dmg * self:GetBuff("BackstabMultiplier") * self:GetBuff_Mult("Mult_MeleeDamage")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- We need the second part for single player because SWEP:Think is ran shared in SP
|
||||
if !(game.SinglePlayer() and CLIENT) then
|
||||
if tr.Hit then
|
||||
if tr.Entity:IsNPC() or tr.Entity:IsNextBot() or tr.Entity:IsPlayer() then
|
||||
self:MyEmitSound(self.MeleeHitNPCSound, 75, 100, 1, CHAN_USER_BASE + 2)
|
||||
else
|
||||
self:MyEmitSound(self.MeleeHitSound, 75, 100, 1, CHAN_USER_BASE + 2)
|
||||
end
|
||||
|
||||
if tr.MatType == MAT_FLESH or tr.MatType == MAT_ALIENFLESH or tr.MatType == MAT_ANTLION or tr.MatType == MAT_BLOODYFLESH then
|
||||
local fx = EffectData()
|
||||
fx:SetOrigin(tr.HitPos)
|
||||
|
||||
util.Effect("BloodImpact", fx)
|
||||
end
|
||||
else
|
||||
self:MyEmitSound(self.MeleeMissSound, 75, 100, 1, CHAN_USER_BASE + 3)
|
||||
end
|
||||
end
|
||||
|
||||
if SERVER and IsValid(tr.Entity) and (tr.Entity:IsNPC() or tr.Entity:IsPlayer() or tr.Entity:Health() > 0) then
|
||||
local dmginfo = DamageInfo()
|
||||
|
||||
local attacker = self:GetOwner()
|
||||
if !IsValid(attacker) then attacker = self end
|
||||
dmginfo:SetAttacker(attacker)
|
||||
|
||||
local relspeed = (tr.Entity:GetVelocity() - self:GetOwner():GetAbsVelocity()):Length()
|
||||
|
||||
relspeed = relspeed / 225
|
||||
|
||||
relspeed = math.Clamp(relspeed, 1, 1.5)
|
||||
|
||||
dmginfo:SetInflictor(self)
|
||||
dmginfo:SetDamage(dmg * relspeed)
|
||||
dmginfo:SetDamageType(self:GetBuff_Override("Override_MeleeDamageType") or self.MeleeDamageType or DMG_CLUB)
|
||||
|
||||
dmginfo:SetDamageForce(self:GetOwner():GetRight() * -4912 + self:GetOwner():GetForward() * 9989)
|
||||
|
||||
SuppressHostEvents(NULL)
|
||||
tr.Entity:TakeDamageInfo(dmginfo)
|
||||
SuppressHostEvents(self:GetOwner())
|
||||
|
||||
if tr.Entity:GetClass() == "func_breakable_surf" then
|
||||
tr.Entity:Fire("Shatter", "0.5 0.5 256")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if SERVER and IsValid(tr.Entity) then
|
||||
local phys = tr.Entity:GetPhysicsObject()
|
||||
if IsValid(phys) then
|
||||
phys:ApplyForceOffset(self:GetOwner():GetAimVector() * 80 * phys:GetMass(), tr.HitPos)
|
||||
end
|
||||
end
|
||||
|
||||
self:GetBuff_Hook("Hook_PostBash", {tr = tr, dmg = dmg})
|
||||
|
||||
self:GetOwner():LagCompensation(false)
|
||||
end
|
||||
147
lua/weapons/arccw_base/sh_bipod.lua
Normal file
147
lua/weapons/arccw_base/sh_bipod.lua
Normal file
@@ -0,0 +1,147 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
function SWEP:InBipod()
|
||||
local bip = self:GetInBipod()
|
||||
|
||||
-- if !self:CanBipod() then
|
||||
-- self:ExitBipod()
|
||||
-- end
|
||||
|
||||
if IsValid(self:GetOwner()) and self:GetBipodPos() != self:GetOwner():EyePos() then
|
||||
self:ExitBipod()
|
||||
end
|
||||
|
||||
return bip
|
||||
end
|
||||
|
||||
SWEP.CachedCanBipod = true
|
||||
SWEP.CachedCanBipodTime = 0
|
||||
|
||||
local dist = 24
|
||||
function SWEP:CanBipod()
|
||||
if !(self:GetBuff_Override("Bipod") or self.Bipod_Integral) then return false end
|
||||
|
||||
if self:GetOwner():InVehicle() then return false end
|
||||
|
||||
if self.CachedCanBipodTime >= CurTime() then return self.CachedCanBipod end
|
||||
|
||||
local pos = self:GetOwner():EyePos()
|
||||
local angle = self:GetOwner():EyeAngles()
|
||||
if self:GetOwner():GetVelocity():Length() > 0 then
|
||||
return false
|
||||
end
|
||||
|
||||
local rangemult = 2
|
||||
if self:IsProne() then
|
||||
rangemult = rangemult * 1.25
|
||||
end
|
||||
rangemult = rangemult * self:GetBuff_Mult("Mult_BipodRange")
|
||||
|
||||
local tr = util.TraceLine({
|
||||
start = pos,
|
||||
endpos = pos + (angle:Forward() * dist * rangemult),
|
||||
filter = self:GetOwner(),
|
||||
mask = MASK_PLAYERSOLID
|
||||
})
|
||||
|
||||
if tr.Hit then -- check for stuff in front of us
|
||||
return false
|
||||
end
|
||||
|
||||
local maxs = Vector(8, 8, 16)
|
||||
local mins = Vector(-8, -8, 0)
|
||||
|
||||
angle.p = angle.p + 45
|
||||
|
||||
tr = util.TraceHull({
|
||||
start = pos,
|
||||
endpos = pos + (angle:Forward() * dist * rangemult),
|
||||
filter = self:GetOwner(),
|
||||
maxs = maxs,
|
||||
mins = mins,
|
||||
mask = MASK_PLAYERSOLID
|
||||
})
|
||||
|
||||
self.CachedCanBipodTime = CurTime()
|
||||
|
||||
if tr.Hit then
|
||||
local tr2 = util.TraceHull({
|
||||
start = tr.HitPos,
|
||||
endpos = tr.HitPos + Vector(0, 0, -24),
|
||||
filter = self:GetOwner(),
|
||||
maxs = maxs,
|
||||
mins = mins,
|
||||
mask = MASK_PLAYERSOLID
|
||||
})
|
||||
if tr2.Hit then
|
||||
self.CachedCanBipod = true
|
||||
return true, tr2
|
||||
end
|
||||
end
|
||||
|
||||
self.CachedCanBipod = false
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:EnterBipod(sp)
|
||||
if !sp and self:GetInBipod() then return end
|
||||
local can, tr = self:CanBipod()
|
||||
if !sp and !can then return end
|
||||
|
||||
if SERVER and game.SinglePlayer() then self:CallOnClient("EnterBipod", "true") end
|
||||
|
||||
if self.Animations.enter_bipod then
|
||||
self:PlayAnimation("enter_bipod", nil, nil, 0, true)
|
||||
else
|
||||
-- Block actions for a tiny bit even if there is no animation
|
||||
self:SetNextPrimaryFire(CurTime() + 0.25)
|
||||
end
|
||||
|
||||
if CLIENT and self:GetBuff_Override("LHIK") then
|
||||
self:DoLHIKAnimation("enter")
|
||||
end
|
||||
|
||||
local bipodang = tr.HitNormal:Cross(self:GetOwner():EyeAngles():Right()):Angle()
|
||||
|
||||
debugoverlay.Axis(tr.HitPos, tr.HitNormal:Angle(), 16, 5, true)
|
||||
debugoverlay.Line(tr.HitPos, tr.HitPos + bipodang:Forward() * 32, 5, color_white, true)
|
||||
debugoverlay.Line(tr.HitPos, tr.HitPos + self:GetOwner():EyeAngles():Forward() * 32, 5, Color(255, 255, 0), true)
|
||||
|
||||
self:SetBipodPos(self:GetOwner():EyePos())
|
||||
self:SetBipodAngle(bipodang)
|
||||
self.BipodStartAngle = self:GetOwner():EyeAngles()
|
||||
|
||||
if game.SinglePlayer() and CLIENT then return end
|
||||
|
||||
self:MyEmitSound(self.EnterBipodSound)
|
||||
self:SetInBipod(true)
|
||||
end
|
||||
|
||||
function SWEP:ExitBipod(sp)
|
||||
if !sp and !self:GetInBipod() then return end
|
||||
|
||||
if SERVER and game.SinglePlayer() then self:CallOnClient("ExitBipod", "true") end
|
||||
|
||||
if self.Animations.exit_bipod then
|
||||
self:PlayAnimation("exit_bipod", nil, nil, 0, true)
|
||||
else
|
||||
self:SetNextPrimaryFire(CurTime() + 0.25)
|
||||
end
|
||||
|
||||
if CLIENT and self:GetBuff_Override("LHIK") then
|
||||
self:DoLHIKAnimation("exit")
|
||||
end
|
||||
|
||||
if game.SinglePlayer() and CLIENT then return end
|
||||
|
||||
self:MyEmitSound(self.ExitBipodSound)
|
||||
self:SetInBipod(false)
|
||||
end
|
||||
2101
lua/weapons/arccw_base/sh_customize.lua
Normal file
2101
lua/weapons/arccw_base/sh_customize.lua
Normal file
File diff suppressed because it is too large
Load Diff
408
lua/weapons/arccw_base/sh_deploy.lua
Normal file
408
lua/weapons/arccw_base/sh_deploy.lua
Normal file
@@ -0,0 +1,408 @@
|
||||
--[[
|
||||
| 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 ang0 = Angle(0, 0, 0)
|
||||
local dev_alwaysready = ArcCW.ConVars["dev_alwaysready"]
|
||||
|
||||
function SWEP:Deploy()
|
||||
if !IsValid(self:GetOwner()) or self:GetOwner():IsNPC() then
|
||||
return
|
||||
end
|
||||
|
||||
if self.UnReady then
|
||||
local sp = game.SinglePlayer()
|
||||
|
||||
if sp then
|
||||
if SERVER then
|
||||
self:CallOnClient("LoadPreset", "autosave")
|
||||
else
|
||||
self:LoadPreset("autosave")
|
||||
end
|
||||
else
|
||||
if SERVER then
|
||||
-- the server... can't get the client's attachments in time.
|
||||
-- can make it so client has to do a thing and tell the server it's ready,
|
||||
-- and that's probably what i'll do later.
|
||||
else
|
||||
self:LoadPreset("autosave")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:InitTimers()
|
||||
|
||||
self:SetShouldHoldType()
|
||||
|
||||
self:SetReloading(false)
|
||||
self:SetPriorityAnim(false)
|
||||
self:SetInUBGL(false)
|
||||
self:SetMagUpCount(0)
|
||||
self:SetMagUpIn(0)
|
||||
self:SetShotgunReloading(0)
|
||||
self:SetHolster_Time(0)
|
||||
self:SetHolster_Entity(NULL)
|
||||
|
||||
self:SetFreeAimAngle(ang0)
|
||||
self:SetLastAimAngle(ang0)
|
||||
|
||||
self.LHIKAnimation = nil
|
||||
self.CrosshairDelta = 0
|
||||
|
||||
self:SetBurstCount(0)
|
||||
|
||||
self:WepSwitchCleanup()
|
||||
if game.SinglePlayer() then self:CallOnClient("WepSwitchCleanup") end
|
||||
|
||||
if !self:GetOwner():InVehicle() then -- Don't play anim if in vehicle. This can be caused by HL2 level changes
|
||||
local prd = false
|
||||
|
||||
local r_anim = self:SelectAnimation("ready")
|
||||
local d_anim = self:SelectAnimation("draw")
|
||||
|
||||
if (CLIENT and !game.SinglePlayer() and LocalPlayer():IsListenServerHost()) then
|
||||
self.ReadySoundTableHack = true
|
||||
end
|
||||
|
||||
if self.Animations[r_anim] and ( dev_alwaysready:GetBool() or self.UnReady ) then
|
||||
self:PlayAnimation(r_anim, 1, true, 0, false)
|
||||
prd = self.Animations[r_anim].ProcDraw
|
||||
|
||||
self:SetPriorityAnim(CurTime() + self:GetAnimKeyTime(r_anim, true))
|
||||
|
||||
if CLIENT then
|
||||
self:SetTimer(self:GetAnimKeyTime(r_anim, true), function() self.UnReady = false end, "UnReady")
|
||||
end
|
||||
elseif self.Animations[d_anim] then
|
||||
self:PlayAnimation(d_anim, self:GetBuff_Mult("Mult_DrawTime"), true, 0, false)
|
||||
prd = self.Animations[d_anim].ProcDraw
|
||||
|
||||
self:SetPriorityAnim(CurTime() + self:GetAnimKeyTime(d_anim, true) * self:GetBuff_Mult("Mult_DrawTime"))
|
||||
end
|
||||
|
||||
if prd or (!self.Animations[r_anim] and !self.Animations[d_anim]) then
|
||||
self:ProceduralDraw()
|
||||
end
|
||||
end
|
||||
|
||||
self:SetState(ArcCW.STATE_DISABLE)
|
||||
|
||||
if (SERVER or game.SinglePlayer()) and self.UnReady then
|
||||
if SERVER then
|
||||
self:InitialDefaultClip()
|
||||
end
|
||||
self.UnReady = false
|
||||
end
|
||||
|
||||
if self:GetBuff_Override("Override_AutoReload", self.AutoReload) then
|
||||
self:RestoreAmmo()
|
||||
end
|
||||
|
||||
timer.Simple(0, function()
|
||||
if IsValid(self) then self:SetupModel(false) end
|
||||
end)
|
||||
|
||||
if SERVER then
|
||||
self:SetupShields()
|
||||
-- Networking the weapon at this time is too early - entity is not yet valid on client
|
||||
-- Also not a good idea because networking many weapons will cause mass lag (e.g. TTT round setup)
|
||||
-- Instead, make client send a request when it is valid there
|
||||
--self:NetworkWeapon()
|
||||
self:GetOwner():SetSaveValue("m_flNextAttack", 0) -- the magic fix-it-all solution for custom deploy problems including sounds
|
||||
elseif CLIENT and !self.CertainAboutAtts and !self.AttReqSent and IsValid(self:GetOwner()) then
|
||||
-- If client is aware of this weapon and it's not on the ground, ask for attachment info
|
||||
-- If it is not on a player, delay networking until it is rendered (in cl_viewmodel)
|
||||
-- print(self, "network weapon from sh_deploy")
|
||||
self.AttReqSent = true
|
||||
net.Start("arccw_rqwpnnet")
|
||||
net.WriteEntity(self)
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
-- self:RefreshBGs()
|
||||
|
||||
self:GetBuff_Hook("Hook_OnDeploy")
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:ResetCheckpoints()
|
||||
self.CheckpointAnimation = nil
|
||||
|
||||
if game.SinglePlayer() and SERVER then
|
||||
net.Start("arccw_sp_checkpoints")
|
||||
net.Broadcast()
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:InitialDefaultClip()
|
||||
if !self.Primary.Ammo then return end
|
||||
if engine.ActiveGamemode() == "darkrp" then return end -- DarkRP is god's second biggest mistake after gmod
|
||||
|
||||
if self:GetOwner() and self:GetOwner():IsPlayer() then
|
||||
if self:HasBottomlessClip() then
|
||||
self:SetClip1(0)
|
||||
end
|
||||
if self.ForceDefaultAmmo then
|
||||
self:GetOwner():GiveAmmo(self.ForceDefaultAmmo, self.Primary.Ammo)
|
||||
elseif engine.ActiveGamemode() != "terrortown" then
|
||||
self:GetOwner():GiveAmmo(self:GetCapacity() * ArcCW.ConVars["mult_defaultammo"]:GetInt(), self.Primary.Ammo)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Initialize()
|
||||
if SERVER and game.SinglePlayer() and IsValid(self:GetOwner()) and self:GetOwner():IsPlayer() then
|
||||
self:CallOnClient("Initialize")
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
local class = self:GetClass()
|
||||
|
||||
if self.KillIconAlias then
|
||||
killicon.AddAlias(class, self.KillIconAlias)
|
||||
class = self.KillIconAlias
|
||||
end
|
||||
|
||||
local path = "arccw/weaponicons/" .. class
|
||||
local mat = Material(path)
|
||||
|
||||
if !mat:IsError() then
|
||||
|
||||
local tex = mat:GetTexture("$basetexture")
|
||||
if tex then
|
||||
local texpath = tex:GetName()
|
||||
killicon.Add(class, texpath, Color(255, 255, 255))
|
||||
self.WepSelectIcon = surface.GetTextureID(texpath)
|
||||
|
||||
if self.ShootEntity then
|
||||
killicon.Add(self.ShootEntity, texpath, Color(255, 255, 255))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Check for incompatibile addons once
|
||||
if LocalPlayer().ArcCW_IncompatibilityCheck != true and game.SinglePlayer() then
|
||||
LocalPlayer().ArcCW_IncompatibilityCheck = true
|
||||
|
||||
local incompatList = {}
|
||||
local addons = engine.GetAddons()
|
||||
for _, addon in pairs(addons) do
|
||||
if ArcCW.IncompatibleAddons[tostring(addon.wsid)] and addon.mounted then
|
||||
incompatList[tostring(addon.wsid)] = addon
|
||||
end
|
||||
end
|
||||
|
||||
local predrawvmhooks = hook.GetTable().PreDrawViewModel
|
||||
if predrawvmhooks and (predrawvmhooks.DisplayDistancePlaneLS or predrawvmhooks.DisplayDistancePlane) then -- vtools lua breaks arccw with stupid return in vm hook, ya dont need it if you going to play with guns
|
||||
hook.Remove("PreDrawViewModel", "DisplayDistancePlane")
|
||||
hook.Remove("PreDrawViewModel", "DisplayDistancePlaneLS")
|
||||
incompatList["DisplayDistancePlane"] = {
|
||||
title = "Light Sprayer / Scenic Dispenser tool",
|
||||
wsid = "DisplayDistancePlane",
|
||||
nourl = true,
|
||||
}
|
||||
end
|
||||
local shouldDo = true
|
||||
-- If never show again is on, verify we have no new addons
|
||||
if file.Exists("arccw_incompatible.txt", "DATA") then
|
||||
shouldDo = false
|
||||
local oldTbl = util.JSONToTable(file.Read("arccw_incompatible.txt"))
|
||||
for id, addon in pairs(incompatList) do
|
||||
if !oldTbl[id] then shouldDo = true break end
|
||||
end
|
||||
if shouldDo then file.Delete("arccw_incompatible.txt") end
|
||||
end
|
||||
if shouldDo and !table.IsEmpty(incompatList) then
|
||||
ArcCW.MakeIncompatibleWindow(incompatList)
|
||||
elseif !table.IsEmpty(incompatList) then
|
||||
print("ArcCW ignored " .. table.Count(incompatList) .. " incompatible addons. If things break, it's your fault.")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if ArcCW.ConVars["equipmentsingleton"]:GetBool() and self.Throwing then
|
||||
self.Singleton = true
|
||||
self.Primary.ClipSize = -1
|
||||
self.Primary.Ammo = ""
|
||||
end
|
||||
|
||||
self:SetState(0)
|
||||
self:SetClip2(0)
|
||||
self:SetLastLoad(self:Clip1())
|
||||
|
||||
self.Attachments["BaseClass"] = nil
|
||||
|
||||
if !self:GetOwner():IsNPC() then
|
||||
self:SetHoldType(self.HoldtypeActive)
|
||||
end
|
||||
|
||||
local og = weapons.Get(self:GetClass())
|
||||
|
||||
self.RegularClipSize = og.Primary.ClipSize
|
||||
|
||||
self.OldPrintName = self.PrintName
|
||||
|
||||
self:InitTimers()
|
||||
|
||||
if engine.ActiveGamemode() == "terrortown" then
|
||||
self:TTT_Init()
|
||||
end
|
||||
|
||||
hook.Run("ArcCW_WeaponInit", self)
|
||||
|
||||
if (!IsValid(self:GetOwner()) or self:GetOwner():IsNPC()) and self:IsValid() and self.NPC_Initialize then
|
||||
self:NPC_Initialize()
|
||||
else
|
||||
self:AdjustAtts()
|
||||
self:RefreshBGs()
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Holster(wep)
|
||||
if !IsFirstTimePredicted() then return end
|
||||
if self:GetOwner():IsNPC() then return end
|
||||
|
||||
if CLIENT and self:GetOwner() == LocalPlayer() and ArcCW.InvHUD then ArcCW.InvHUD:Remove() end
|
||||
|
||||
if self:GetBurstCount() > 0 and self:Clip1() > self:GetBuff("AmmoPerShot") then return false end
|
||||
|
||||
if CLIENT and LocalPlayer() != self:GetOwner() then
|
||||
return
|
||||
end
|
||||
|
||||
if self:GetGrenadePrimed() then
|
||||
self:GrenadeDrop(true)
|
||||
end
|
||||
|
||||
self:WepSwitchCleanup()
|
||||
if game.SinglePlayer() then self:CallOnClient("WepSwitchCleanup") end
|
||||
|
||||
if wep == self then self:Deploy() return false end
|
||||
if self:GetHolster_Time() > CurTime() then return false end
|
||||
|
||||
self.UnReady = false
|
||||
|
||||
-- Props deploy to NULL, finish holster on NULL too
|
||||
if (self:GetHolster_Time() != 0 and self:GetHolster_Time() <= CurTime()) or !IsValid(wep) then
|
||||
self:SetHolster_Time(0)
|
||||
self:SetHolster_Entity(NULL)
|
||||
self:FinishHolster()
|
||||
self:GetBuff_Hook("Hook_OnHolsterEnd")
|
||||
return true
|
||||
else
|
||||
self:SetHolster_Entity(wep)
|
||||
|
||||
if self:GetGrenadePrimed() then
|
||||
self:Throw()
|
||||
end
|
||||
|
||||
self.Sighted = false
|
||||
self.Sprinted = false
|
||||
self:SetShotgunReloading(0)
|
||||
self:SetMagUpCount(0)
|
||||
self:SetMagUpIn(0)
|
||||
|
||||
local time = 0.25
|
||||
local anim = self:SelectAnimation("holster")
|
||||
if anim then
|
||||
local prd = self.Animations[anim].ProcHolster
|
||||
time = self:GetAnimKeyTime(anim)
|
||||
if prd then
|
||||
self:ProceduralHolster()
|
||||
time = 0.25
|
||||
end
|
||||
self:PlayAnimation(anim, self:GetBuff_Mult("Mult_DrawTime"), true, nil, nil, nil, true)
|
||||
self:SetHolster_Time(CurTime() + time * self:GetBuff_Mult("Mult_DrawTime"))
|
||||
else
|
||||
self:ProceduralHolster()
|
||||
self:SetHolster_Time(CurTime() + time * self:GetBuff_Mult("Mult_DrawTime"))
|
||||
end
|
||||
self:SetPriorityAnim(CurTime() + time * self:GetBuff_Mult("Mult_DrawTime"))
|
||||
self:SetWeaponOpDelay(CurTime() + time * self:GetBuff_Mult("Mult_DrawTime"))
|
||||
|
||||
self:GetBuff_Hook("Hook_OnHolster")
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:FinishHolster()
|
||||
self:KillTimers()
|
||||
|
||||
if CLIENT then
|
||||
self:KillFlashlights()
|
||||
else
|
||||
if self:GetBuff_Override("UBGL_UnloadOnDequip") then
|
||||
local clip = self:Clip2()
|
||||
|
||||
local ammo = self:GetBuff_Override("UBGL_Ammo") or "smg1_grenade"
|
||||
|
||||
if IsValid(self:GetOwner()) then
|
||||
self:GetOwner():GiveAmmo(clip, ammo, true)
|
||||
end
|
||||
|
||||
self:SetClip2(0)
|
||||
end
|
||||
|
||||
self:KillShields()
|
||||
|
||||
local vm = self:GetOwner():GetViewModel()
|
||||
if IsValid(vm) then
|
||||
for i = 0, vm:GetNumBodyGroups() do
|
||||
vm:SetBodygroup(i, 0)
|
||||
end
|
||||
vm:SetSkin(0)
|
||||
vm:SetPlaybackRate(1)
|
||||
end
|
||||
|
||||
if self.Disposable and self:Clip1() == 0 and self:Ammo1() == 0 then
|
||||
self:GetOwner():StripWeapon(self:GetClass())
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- doesn't work if they dont call in prediction blah blah
|
||||
|
||||
function SWEP:ProceduralDraw()
|
||||
if SERVER and self:GetOwner():IsValid() then
|
||||
self:CallOnClient("ProceduralDraw")
|
||||
end
|
||||
|
||||
self.InProcDraw = true
|
||||
self.ProcDrawTime = CurTime()
|
||||
end
|
||||
|
||||
function SWEP:ProceduralHolster()
|
||||
if SERVER and self:GetOwner():IsValid() then
|
||||
self:CallOnClient("ProceduralHolster")
|
||||
end
|
||||
|
||||
self.InProcHolster = true
|
||||
self.ProcHolsterTime = CurTime()
|
||||
end
|
||||
|
||||
function SWEP:WepSwitchCleanup()
|
||||
-- table.Empty(self.EventTable)
|
||||
self.InProcDraw = false
|
||||
self.InProcHolster = false
|
||||
end
|
||||
|
||||
function SWEP:ProceduralBash()
|
||||
if game.SinglePlayer() and self:GetOwner():IsValid() then
|
||||
self:CallOnClient("ProceduralBash")
|
||||
end
|
||||
|
||||
local mult = self:GetBuff_Mult("Mult_MeleeTime")
|
||||
local mt = self.MeleeTime * mult
|
||||
|
||||
self.InProcBash = true
|
||||
self.ProcBashTime = CurTime()
|
||||
self:SetTimer(mt, function()
|
||||
self.InProcBash = false
|
||||
end)
|
||||
end
|
||||
174
lua/weapons/arccw_base/sh_firemodes.lua
Normal file
174
lua/weapons/arccw_base/sh_firemodes.lua
Normal file
@@ -0,0 +1,174 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
function SWEP:ChangeFiremode(pred)
|
||||
pred = pred or true
|
||||
local fmt = self:GetBuff_Override("Override_Firemodes", self.Firemodes)
|
||||
fmt["BaseClass"] = nil
|
||||
|
||||
local check = self:GetBuff_Hook("Hook_ChangeFiremode")
|
||||
if check then return end
|
||||
local count = table.Count(fmt)
|
||||
if count == 1 then return end
|
||||
if self:GetNextPrimaryFire() > CurTime() then return end
|
||||
if self:GetGrenadePrimed() then return end
|
||||
|
||||
local fmi = self:GetFireMode()
|
||||
local lastfmi = fmi
|
||||
|
||||
fmi = fmi + 1
|
||||
|
||||
if fmi > count then
|
||||
fmi = 1
|
||||
end
|
||||
|
||||
local altsafety = SERVER and (self:GetOwner():GetInfo("arccw_altsafety") == "1") or CLIENT and (ArcCW.ConVars["altsafety"]:GetBool())
|
||||
if altsafety and !self:GetOwner():KeyDown(IN_WALK) and fmt[fmi] and fmt[fmi].Mode == 0 then
|
||||
-- Skip safety when walk key is not down
|
||||
fmi = (fmi + 1 > count) and 1 or (fmi + 1)
|
||||
elseif altsafety and self:GetOwner():KeyDown(IN_WALK) then
|
||||
if fmt[lastfmi] and fmt[lastfmi].Mode == 0 then
|
||||
-- Find the first non-safety firemode
|
||||
local nonsafe_fmi = nil
|
||||
for i, fm in pairs(fmt) do
|
||||
if fm.Mode != 0 then nonsafe_fmi = i break end
|
||||
end
|
||||
fmi = nonsafe_fmi or fmi
|
||||
else
|
||||
-- Find the safety firemode
|
||||
local safety_fmi = nil
|
||||
for i, fm in pairs(fmt) do
|
||||
if fm.Mode == 0 then safety_fmi = i break end
|
||||
end
|
||||
fmi = safety_fmi or fmi
|
||||
end
|
||||
end
|
||||
|
||||
if !fmt[fmi] then fmi = 1 end
|
||||
|
||||
local a = tostring(lastfmi) .. "_to_" .. tostring(fmi)
|
||||
|
||||
if !self.Animations[a] then a = "changefiremode" end
|
||||
|
||||
if self.Animations[a] then
|
||||
self:PlayAnimationEZ(a, 1, true)
|
||||
local t = CurTime() + self:GetAnimKeyTime(a, true)
|
||||
self:SetPriorityAnim(t)
|
||||
self:SetNextPrimaryFire(t)
|
||||
end
|
||||
|
||||
local old_inf = self:HasInfiniteAmmo()
|
||||
|
||||
self:SetFireMode(fmi)
|
||||
--timer.Simple(0, function() self:RecalcAllBuffs() end)
|
||||
-- Absolutely, totally, completely ENSURE client has changed the value before attempting recalculation
|
||||
-- Waiting one tick will not work on dedicated servers
|
||||
local id = "ArcCW_RecalcWait_" .. self:EntIndex()
|
||||
timer.Create(id, 0.01, 0, function()
|
||||
if !IsValid(self) then timer.Remove(id) return end
|
||||
if self:GetFireMode() == fmi then
|
||||
self:RecalcAllBuffs()
|
||||
self:GetActiveElements(true)
|
||||
|
||||
-- Timers solve everything!
|
||||
timer.Simple(0.01, function()
|
||||
if !IsValid(self) then return end
|
||||
self:AdjustAmmo(old_inf)
|
||||
if self:GetCurrentFiremode().RestoreAmmo then
|
||||
-- No seriously, they really do
|
||||
timer.Simple(0.01, function()
|
||||
if !IsValid(self) then return end
|
||||
self:RestoreAmmo()
|
||||
end)
|
||||
end
|
||||
end)
|
||||
timer.Remove(id)
|
||||
end
|
||||
end)
|
||||
|
||||
if lastfmi != fmi then
|
||||
local snd = self:GetBuff_Override("Override_FiremodeSound", self.FiremodeSound)
|
||||
if SERVER then
|
||||
if pred then
|
||||
SuppressHostEvents(self:GetOwner())
|
||||
end
|
||||
self:MyEmitSound(snd, 75, 100, 1, CHAN_ITEM + 2)
|
||||
if pred then
|
||||
SuppressHostEvents(NULL)
|
||||
end
|
||||
else
|
||||
self:MyEmitSound(snd, 75, 100, 1, CHAN_ITEM + 2)
|
||||
end
|
||||
end
|
||||
|
||||
self:SetShouldHoldType()
|
||||
|
||||
if self:GetCurrentFiremode().Mode == 0 or self:GetBuff_Hook("Hook_ShouldNotSight") then
|
||||
self:ExitSights()
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetCurrentFiremode()
|
||||
local fmt = self:GetBuff_Override("Override_Firemodes", self.Firemodes)
|
||||
fmt.BaseClass = nil
|
||||
|
||||
if self:GetFireMode() > table.Count(fmt) or self:GetFireMode() < 1 then
|
||||
self:SetFireMode(1)
|
||||
end
|
||||
|
||||
fmt[self:GetFireMode()].BaseClass = nil
|
||||
return fmt[self:GetFireMode()]
|
||||
end
|
||||
|
||||
function SWEP:GetFiremodeName()
|
||||
if self:GetBuff_Hook("Hook_FiremodeName") then return self:GetBuff_Hook("Hook_FiremodeName") end
|
||||
|
||||
local abbrev = ArcCW.ConVars["hud_fcgabbrev"]:GetBool() and ".abbrev" or ""
|
||||
|
||||
if self:GetInUBGL() then
|
||||
return self:GetBuff_Override("UBGL_PrintName") and self:GetBuff_Override("UBGL_PrintName") or ArcCW.GetTranslation("fcg.ubgl" .. abbrev)
|
||||
end
|
||||
|
||||
local fm = self:GetCurrentFiremode()
|
||||
|
||||
if fm.PrintName then
|
||||
local phrase = ArcCW.GetPhraseFromString(fm.PrintName)
|
||||
return phrase and ArcCW.GetTranslation(phrase .. abbrev) or ArcCW.TryTranslation(fm.PrintName)
|
||||
end
|
||||
|
||||
local mode = fm.Mode
|
||||
if mode == 0 then return ArcCW.GetTranslation("fcg.safe" .. abbrev) end
|
||||
if mode == 1 then return ArcCW.GetTranslation("fcg.semi" .. abbrev) end
|
||||
if mode >= 2 then return ArcCW.GetTranslation("fcg.auto" .. abbrev) end
|
||||
if mode < 0 then return string.format(ArcCW.GetTranslation("fcg.burst" .. abbrev), tostring(-mode)) end
|
||||
end
|
||||
|
||||
function SWEP:GetFiremodeBars()
|
||||
if self:GetBuff_Hook("Hook_FiremodeBars") then return self:GetBuff_Hook("Hook_FiremodeBars") end
|
||||
|
||||
if self:GetInUBGL() then
|
||||
return "____-"
|
||||
end
|
||||
|
||||
local fm = self:GetCurrentFiremode()
|
||||
|
||||
if fm.CustomBars then return fm.CustomBars end
|
||||
|
||||
local mode = fm.Mode
|
||||
|
||||
if mode == 0 then return "_____" end
|
||||
if mode == 1 then return "-____" end
|
||||
if mode >= 2 then return "-----" end
|
||||
if mode == -2 then return "--___" end
|
||||
if mode == -3 then return "---__" end
|
||||
if mode == -4 then return "----_" end
|
||||
|
||||
return "-----"
|
||||
end
|
||||
923
lua/weapons/arccw_base/sh_firing.lua
Normal file
923
lua/weapons/arccw_base/sh_firing.lua
Normal file
@@ -0,0 +1,923 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
function SWEP:CanPrimaryAttack()
|
||||
local owner = self:GetOwner()
|
||||
|
||||
-- Should we not fire? But first.
|
||||
if self:GetBuff_Hook("Hook_ShouldNotFireFirst") then return end
|
||||
|
||||
-- We're holstering
|
||||
if IsValid(self:GetHolster_Entity()) then return end
|
||||
if self:GetHolster_Time() > 0 then return end
|
||||
|
||||
-- Disabled (currently used only by deploy)
|
||||
if self:GetState() == ArcCW.STATE_DISABLE then return end
|
||||
|
||||
-- Coostimzing
|
||||
if self:GetState() == ArcCW.STATE_CUSTOMIZE then
|
||||
if CLIENT and ArcCW.Inv_Hidden then
|
||||
ArcCW.Inv_Hidden = false
|
||||
gui.EnableScreenClicker(true)
|
||||
elseif game.SinglePlayer() then
|
||||
-- Kind of ugly hack: in SP this is only called serverside so we ask client to do the same check
|
||||
self:CallOnClient("CanPrimaryAttack")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- A priority animation is playing (reloading, cycling, firemode etc)
|
||||
if self:GetPriorityAnim() then return end
|
||||
|
||||
-- Inoperable, but internally (burst resetting for example)
|
||||
if self:GetWeaponOpDelay() > CurTime() then return end
|
||||
|
||||
-- Safety's on, dipshit
|
||||
if self:GetCurrentFiremode().Mode == 0 then
|
||||
self:ChangeFiremode(false)
|
||||
self:SetNextPrimaryFire(CurTime())
|
||||
self.Primary.Automatic = false
|
||||
return
|
||||
end
|
||||
|
||||
-- If we are an NPC, do our own little methods
|
||||
if owner:IsNPC() then self:NPC_Shoot() return end
|
||||
|
||||
-- If we are in a UBGL, shoot the UBGL, not the gun
|
||||
if self:GetInUBGL() then self:ShootUBGL() return end
|
||||
|
||||
-- Too early, come back later.
|
||||
if self:GetNextPrimaryFire() >= CurTime() then return end
|
||||
|
||||
-- Gun is locked from heat.
|
||||
if self:GetHeatLocked() then return end
|
||||
|
||||
-- Attempting a bash
|
||||
if self:GetState() != ArcCW.STATE_SIGHTS and owner:KeyDown(IN_USE) or self.PrimaryBash then self:Bash() return end
|
||||
|
||||
-- Throwing weapon
|
||||
if self.Throwing then self:PreThrow() return end
|
||||
|
||||
-- Too close to a wall
|
||||
if self:BarrelHitWall() > 0 then return end
|
||||
|
||||
-- Can't shoot while sprinting
|
||||
if self:GetNWState() == ArcCW.STATE_SPRINT and !self:CanShootWhileSprint() then return end
|
||||
|
||||
-- Maximum burst shots
|
||||
if (self:GetBurstCount() or 0) >= self:GetBurstLength() then return end
|
||||
|
||||
-- We need to cycle
|
||||
if self:GetNeedCycle() then return end
|
||||
|
||||
-- If we have a trigger delay, make sure its progress is done
|
||||
if self:GetBuff_Override("Override_TriggerDelay", self.TriggerDelay) and ((!self:GetBuff_Override("Override_TriggerCharge", self.TriggerCharge) and self:GetTriggerDelta() < 1)
|
||||
or (self:GetBuff_Override("Override_TriggerCharge", self.TriggerCharge) and self:IsTriggerHeld())) then
|
||||
return
|
||||
end
|
||||
|
||||
-- Should we not fire?
|
||||
if self:GetBuff_Hook("Hook_ShouldNotFire") then return end
|
||||
|
||||
-- We made it
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:TakePrimaryAmmo(num)
|
||||
if self:HasBottomlessClip() or self:Clip1() <= 0 then
|
||||
if self:Ammo1() <= 0 then return end
|
||||
if self:HasInfiniteAmmo() then return end
|
||||
self:GetOwner():RemoveAmmo(num, self:GetPrimaryAmmoType())
|
||||
return end
|
||||
self:SetClip1(self:Clip1() - num)
|
||||
end
|
||||
|
||||
function SWEP:ApplyRandomSpread(dir, spread)
|
||||
local radius = math.Rand(0, 1)
|
||||
local theta = math.Rand(0, math.rad(360))
|
||||
local bulletang = dir:Angle()
|
||||
local forward, right, up = bulletang:Forward(), bulletang:Right(), bulletang:Up()
|
||||
local x = radius * math.sin(theta)
|
||||
local y = radius * math.cos(theta)
|
||||
|
||||
dir:Set(dir + right * spread * x + up * spread * y)
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
local owner = self:GetOwner()
|
||||
|
||||
self.Primary.Automatic = true
|
||||
|
||||
if !self:CanPrimaryAttack() then return end
|
||||
|
||||
local clip = self:Clip1()
|
||||
local aps = self:GetBuff("AmmoPerShot")
|
||||
|
||||
if self:HasBottomlessClip() then
|
||||
clip = self:Ammo1()
|
||||
if self:HasInfiniteAmmo() then
|
||||
clip = math.huge
|
||||
end
|
||||
end
|
||||
|
||||
if clip < aps then
|
||||
self:SetBurstCount(0)
|
||||
self:DryFire()
|
||||
|
||||
self.Primary.Automatic = false
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local dir = (owner:EyeAngles() + self:GetFreeAimOffset()):Forward() --owner:GetAimVector()
|
||||
local src = self:GetShootSrc()
|
||||
|
||||
if bit.band(util.PointContents(src), CONTENTS_WATER) == CONTENTS_WATER and !(self.CanFireUnderwater or self:GetBuff_Override("Override_CanFireUnderwater")) then
|
||||
self:DryFire()
|
||||
return
|
||||
end
|
||||
|
||||
if self:GetMalfunctionJam() then
|
||||
self:DryFire()
|
||||
return
|
||||
end
|
||||
|
||||
-- Try malfunctioning
|
||||
local mal = self:DoMalfunction(false)
|
||||
if mal == true then
|
||||
local anim = "fire_jammed"
|
||||
self:PlayAnimation(anim, 1, true, 0, true)
|
||||
return
|
||||
end
|
||||
|
||||
self:GetBuff_Hook("Hook_PreFireBullets")
|
||||
|
||||
local desync = ArcCW.ConVars["desync"]:GetBool()
|
||||
local desyncnum = (desync and math.random()) or 0
|
||||
math.randomseed(math.Round(util.SharedRandom(self:GetBurstCount(), -1337, 1337, !game.SinglePlayer() and self:GetOwner():GetCurrentCommand():CommandNumber() or CurTime()) * (self:EntIndex() % 30241)) + desyncnum)
|
||||
|
||||
self.Primary.Automatic = true
|
||||
|
||||
local spread = ArcCW.MOAToAcc * self:GetBuff("AccuracyMOA")
|
||||
local disp = self:GetDispersion() * ArcCW.MOAToAcc / 10
|
||||
|
||||
--dir:Rotate(Angle(0, ArcCW.StrafeTilt(self), 0))
|
||||
--dir = dir + VectorRand() * disp
|
||||
|
||||
self:ApplyRandomSpread(dir, disp)
|
||||
|
||||
if (CLIENT or game.SinglePlayer()) and ArcCW.ConVars["dev_shootinfo"]:GetInt() >= 3 and disp > 0 then
|
||||
local dev_tr = util.TraceLine({
|
||||
start = src,
|
||||
endpos = src + owner:GetAimVector() * 33000,
|
||||
mask = MASK_SHOT,
|
||||
filter = {self, self:GetOwner()}
|
||||
})
|
||||
local dist = (dev_tr.HitPos - src):Length()
|
||||
local r = dist / (1 / math.tan(disp)) -- had to google "trig cheat sheet to figure this one out"
|
||||
local a = owner:GetAimVector():Angle()
|
||||
local r_sqrt = r / math.sqrt(2)
|
||||
debugoverlay.Line(dev_tr.HitPos - a:Up() * r, dev_tr.HitPos + a:Up() * r, 5, color_white, true)
|
||||
debugoverlay.Line(dev_tr.HitPos - a:Right() * r, dev_tr.HitPos + a:Right() * r, 5, color_white, true)
|
||||
debugoverlay.Line(dev_tr.HitPos - a:Right() * r_sqrt - a:Up() * r_sqrt, dev_tr.HitPos + a:Right() * r_sqrt + a:Up() * r_sqrt, 5, color_white, true)
|
||||
debugoverlay.Line(dev_tr.HitPos - a:Right() * r_sqrt + a:Up() * r_sqrt, dev_tr.HitPos + a:Right() * r_sqrt - a:Up() * r_sqrt, 5, color_white, true)
|
||||
debugoverlay.Text(dev_tr.HitPos, math.Round(self:GetDispersion(), 1) .. "MOA (" .. math.Round(disp, 3) .. "°)", 5)
|
||||
end
|
||||
|
||||
local delay = self:GetFiringDelay()
|
||||
|
||||
local curtime = CurTime()
|
||||
local curatt = self:GetNextPrimaryFire()
|
||||
local diff = curtime - curatt
|
||||
|
||||
if diff > engine.TickInterval() or diff < 0 then
|
||||
curatt = curtime
|
||||
end
|
||||
|
||||
self:SetNextPrimaryFire(curatt + delay)
|
||||
self:SetNextPrimaryFireSlowdown(curatt + delay) -- shadow for ONLY fire time
|
||||
|
||||
local num = self:GetBuff("Num")
|
||||
|
||||
num = num + self:GetBuff_Add("Add_Num")
|
||||
|
||||
local tracer = self:GetBuff_Override("Override_Tracer", self.Tracer)
|
||||
local tracernum = self:GetBuff_Override("Override_TracerNum", self.TracerNum)
|
||||
local lastout = self:GetBuff_Override("Override_TracerFinalMag", self.TracerFinalMag)
|
||||
if lastout >= clip then
|
||||
tracernum = 1
|
||||
tracer = self:GetBuff_Override("Override_TracerFinal", self.TracerFinal) or self:GetBuff_Override("Override_Tracer", self.Tracer)
|
||||
end
|
||||
local dmgtable = self.BodyDamageMults
|
||||
dmgtable = self:GetBuff_Override("Override_BodyDamageMults") or dmgtable
|
||||
|
||||
-- drive by is cool
|
||||
src = ArcCW:GetVehicleFireTrace(self:GetOwner(), src, dir) or src
|
||||
|
||||
local bullet = {}
|
||||
bullet.Attacker = owner
|
||||
bullet.Dir = dir
|
||||
bullet.Src = src
|
||||
bullet.Spread = Vector(0, 0, 0) --Vector(spread, spread, spread)
|
||||
bullet.Damage = 0
|
||||
bullet.Num = num
|
||||
|
||||
local sglove = math.ceil(num / 3)
|
||||
bullet.Force = self:GetBuff("Force", true) or math.Clamp( ( (50 / sglove) / ( (self:GetBuff("Damage") + self:GetBuff("DamageMin")) / (self:GetBuff("Num") * 2) ) ) * sglove, 1, 3 )
|
||||
-- Overperforming weapons get the jerf, underperforming gets boost
|
||||
bullet.Distance = self:GetBuff("Distance", true) or 33300
|
||||
-- Setting AmmoType makes the engine look for the tracer effect on the ammo instead of TracerName!
|
||||
--bullet.AmmoType = self.Primary.Ammo
|
||||
bullet.HullSize = self:GetBuff("HullSize")
|
||||
bullet.Tracer = tracernum or 0
|
||||
bullet.TracerName = tracer
|
||||
bullet.Weapon = self
|
||||
bullet.Callback = function(att, tr, dmg)
|
||||
ArcCW:BulletCallback(att, tr, dmg, self)
|
||||
end
|
||||
|
||||
local shootent = self:GetBuff("ShootEntity", true) --self:GetBuff_Override("Override_ShootEntity", self.ShootEntity)
|
||||
local shpatt = self:GetBuff_Override("Override_ShotgunSpreadPattern", self.ShotgunSpreadPattern)
|
||||
local shpattov = self:GetBuff_Override("Override_ShotgunSpreadPatternOverrun", self.ShotgunSpreadPatternOverrun)
|
||||
|
||||
local extraspread = AngleRand() * self:GetDispersion() * ArcCW.MOAToAcc / 10
|
||||
|
||||
local projectiledata = {}
|
||||
|
||||
if shpatt or shpattov or shootent then
|
||||
if shootent then
|
||||
projectiledata.ent = shootent
|
||||
projectiledata.vel = self:GetBuff("MuzzleVelocity")
|
||||
end
|
||||
|
||||
bullet = self:GetBuff_Hook("Hook_FireBullets", bullet)
|
||||
|
||||
if !bullet then return end
|
||||
|
||||
local doent = shootent and num or bullet.Num
|
||||
local minnum = shootent and 1 or 0
|
||||
|
||||
if doent > minnum then
|
||||
for n = 1, bullet.Num do
|
||||
bullet.Num = 1
|
||||
|
||||
local dispers = self:GetBuff_Override("Override_ShotgunSpreadDispersion", self.ShotgunSpreadDispersion)
|
||||
local offset = self:GetShotgunSpreadOffset(n)
|
||||
local calcoff = dispers and (offset * self:GetDispersion() * ArcCW.MOAToAcc / 10) or offset
|
||||
|
||||
local ang = owner:EyeAngles() + self:GetFreeAimOffset()
|
||||
local ang2 = Angle(ang)
|
||||
ang2:RotateAroundAxis(ang:Right(), -1 * calcoff.p)
|
||||
ang2:RotateAroundAxis(ang:Up(), calcoff.y)
|
||||
ang2:RotateAroundAxis(ang:Forward(), calcoff.r)
|
||||
|
||||
if !self:GetBuff_Override("Override_NoRandSpread", self.NoRandSpread) then -- Needs testing
|
||||
ang2 = ang2 + AngleRand() * spread / 5
|
||||
end
|
||||
|
||||
if shootent then
|
||||
projectiledata.ang = ang2
|
||||
|
||||
self:DoPrimaryFire(true, projectiledata)
|
||||
else
|
||||
bullet.Dir = ang2:Forward()
|
||||
|
||||
self:DoPrimaryFire(false, bullet)
|
||||
end
|
||||
end
|
||||
elseif shootent then
|
||||
local ang = owner:EyeAngles() + self:GetFreeAimOffset()
|
||||
|
||||
if !self:GetBuff_Override("Override_NoRandSpread", self.NoRandSpread) then
|
||||
-- ang = (dir + VectorRand() * spread / 5):Angle()
|
||||
|
||||
local newdir = Vector(dir)
|
||||
self:ApplyRandomSpread(newdir, spread / 5)
|
||||
ang = newdir:Angle()
|
||||
end
|
||||
|
||||
projectiledata.ang = ang
|
||||
|
||||
self:DoPrimaryFire(true, projectiledata)
|
||||
end
|
||||
else
|
||||
if !bullet then return end
|
||||
|
||||
for n = 1, bullet.Num do
|
||||
bullet.Num = 1
|
||||
local dirry = Vector(dir.x, dir.y, dir.z)
|
||||
math.randomseed(math.Round(util.SharedRandom(n, -1337, 1337, !game.SinglePlayer() and self:GetOwner():GetCurrentCommand():CommandNumber() or CurTime()) * (self:EntIndex() % 30241)) + desyncnum)
|
||||
if !self:GetBuff_Override("Override_NoRandSpread", self.NoRandSpread) then
|
||||
self:ApplyRandomSpread(dirry, spread)
|
||||
bullet.Dir = dirry
|
||||
end
|
||||
bullet = self:GetBuff_Hook("Hook_FireBullets", bullet) or bullet
|
||||
|
||||
self:DoPrimaryFire(false, bullet)
|
||||
end
|
||||
end
|
||||
|
||||
self:DoRecoil()
|
||||
|
||||
self:SetNthShot(self:GetNthShot() + 1)
|
||||
|
||||
owner:DoAnimationEvent(self:GetBuff_Override("Override_AnimShoot") or self.AnimShoot)
|
||||
|
||||
local shouldsupp = SERVER and !game.SinglePlayer()
|
||||
|
||||
if shouldsupp then SuppressHostEvents(owner) end
|
||||
|
||||
self:DoEffects()
|
||||
|
||||
self:SetBurstCount(self:GetBurstCount() + 1)
|
||||
|
||||
self:TakePrimaryAmmo(aps)
|
||||
|
||||
self:DoShootSound()
|
||||
self:DoPrimaryAnim()
|
||||
|
||||
if self:GetCurrentFiremode().Mode < 0 and self:GetBurstCount() == self:GetBurstLength() then
|
||||
local postburst = (self:GetCurrentFiremode().PostBurstDelay or 0)
|
||||
self:SetWeaponOpDelay(CurTime() + postburst * self:GetBuff_Mult("Mult_PostBurstDelay") + self:GetBuff_Add("Add_PostBurstDelay"))
|
||||
end
|
||||
|
||||
if (self:GetIsManualAction()) and !(self.NoLastCycle and self:Clip1() == 0) then
|
||||
local fireanim = self:GetBuff_Hook("Hook_SelectFireAnimation") or self:SelectAnimation("fire")
|
||||
local firedelay = self.Animations[fireanim].MinProgress or 0
|
||||
self:SetNeedCycle(true)
|
||||
self:SetWeaponOpDelay(CurTime() + (firedelay * self:GetBuff_Mult("Mult_CycleTime")))
|
||||
self:SetNextPrimaryFire(CurTime() + 0.1)
|
||||
end
|
||||
|
||||
self:ApplyAttachmentShootDamage()
|
||||
|
||||
self:AddHeat(self:GetBuff("HeatGain"))
|
||||
|
||||
mal = self:DoMalfunction(true)
|
||||
if mal == true then
|
||||
local anim = "fire_jammed"
|
||||
self:PlayAnimation(anim, 1, true, 0, true)
|
||||
end
|
||||
|
||||
if self:GetCurrentFiremode().Mode == 1 then
|
||||
self.LastTriggerTime = -1 -- Cannot fire again until trigger released
|
||||
self.LastTriggerDuration = 0
|
||||
end
|
||||
|
||||
self:GetBuff_Hook("Hook_PostFireBullets")
|
||||
|
||||
if shouldsupp then SuppressHostEvents(nil) end
|
||||
end
|
||||
|
||||
function SWEP:TryBustDoor(ent, dmg)
|
||||
ArcCW.TryBustDoor(ent, dmg)
|
||||
end
|
||||
|
||||
function SWEP:DoShootSound(sndoverride, dsndoverride, voloverride, pitchoverride)
|
||||
local fsound = self.ShootSound
|
||||
local suppressed = self:GetBuff_Override("Silencer")
|
||||
|
||||
if suppressed then
|
||||
fsound = self.ShootSoundSilenced
|
||||
end
|
||||
|
||||
local firstsound = self.FirstShootSound
|
||||
|
||||
if self:GetBurstCount() == 1 and firstsound then
|
||||
fsound = firstsound
|
||||
|
||||
local firstsil = self.FirstShootSoundSilenced
|
||||
|
||||
if suppressed then
|
||||
fsound = firstsil and firstsil or self.ShootSoundSilenced
|
||||
end
|
||||
end
|
||||
|
||||
local lastsound = self.LastShootSound
|
||||
|
||||
local clip = self:Clip1()
|
||||
|
||||
if clip == 1 and lastsound then
|
||||
fsound = lastsound
|
||||
|
||||
local lastsil = self.LastShootSoundSilenced
|
||||
|
||||
if suppressed then
|
||||
fsound = lastsil and lastsil or self.ShootSoundSilenced
|
||||
end
|
||||
end
|
||||
|
||||
fsound = self:GetBuff_Hook("Hook_GetShootSound", fsound)
|
||||
|
||||
local distancesound = self.DistantShootSound
|
||||
|
||||
if suppressed then
|
||||
distancesound = self.DistantShootSoundSilenced
|
||||
end
|
||||
|
||||
distancesound = self:GetBuff_Hook("Hook_GetDistantShootSound", distancesound)
|
||||
|
||||
local spv = self.ShootPitchVariation
|
||||
local volume = self.ShootVol
|
||||
local pitch = self.ShootPitch * math.Rand(1 - spv, 1 + spv) * self:GetBuff_Mult("Mult_ShootPitch")
|
||||
|
||||
local v = ArcCW.ConVars["weakensounds"]:GetFloat()
|
||||
|
||||
volume = volume - v
|
||||
|
||||
volume = volume * self:GetBuff_Mult("Mult_ShootVol")
|
||||
|
||||
volume = math.Clamp(volume, 51, 149)
|
||||
pitch = math.Clamp(pitch, 0, 255)
|
||||
|
||||
if sndoverride then fsound = sndoverride end
|
||||
if dsndoverride then distancesound = dsndoverride end
|
||||
if voloverride then volume = voloverride end
|
||||
if pitchoverride then pitch = pitchoverride end
|
||||
|
||||
if distancesound then self:MyEmitSound(distancesound, 149, pitch, 0.5, CHAN_WEAPON + 1) end
|
||||
|
||||
if fsound then self:MyEmitSound(fsound, volume, pitch, 1, CHAN_WEAPON) end
|
||||
|
||||
local data = {
|
||||
sound = fsound,
|
||||
volume = volume,
|
||||
pitch = pitch,
|
||||
}
|
||||
|
||||
self:GetBuff_Hook("Hook_AddShootSound", data)
|
||||
end
|
||||
|
||||
function SWEP:GetMuzzleVelocity()
|
||||
local vel = self:GetBuff_Override("Override_PhysBulletMuzzleVelocity", self.PhysBulletMuzzleVelocity)
|
||||
|
||||
if !vel then
|
||||
vel = self:GetBuff("Range") * 3.5
|
||||
|
||||
if self:GetBuff("DamageMin") > self:GetBuff("Damage") then
|
||||
vel = vel * 2
|
||||
end
|
||||
vel = math.Clamp(vel, 200, 1000)
|
||||
end
|
||||
|
||||
vel = vel / ArcCW.HUToM
|
||||
|
||||
vel = vel * self:GetBuff_Mult("Mult_PhysBulletMuzzleVelocity")
|
||||
|
||||
vel = vel * ArcCW.ConVars["bullet_velocity"]:GetFloat()
|
||||
|
||||
return vel
|
||||
end
|
||||
|
||||
function SWEP:DoPrimaryFire(isent, data)
|
||||
local clip = self:Clip1()
|
||||
if self:HasBottomlessClip() then
|
||||
if !self:GetOwner():IsPlayer() then
|
||||
clip = math.huge
|
||||
else
|
||||
clip = self:Ammo1()
|
||||
end
|
||||
end
|
||||
local owner = self:GetOwner()
|
||||
|
||||
local shouldphysical = ArcCW.ConVars["bullet_enable"]:GetBool()
|
||||
|
||||
if self.AlwaysPhysBullet or self:GetBuff_Override("Override_AlwaysPhysBullet") then
|
||||
shouldphysical = true
|
||||
end
|
||||
|
||||
if self.NeverPhysBullet or self:GetBuff_Override("Override_NeverPhysBullet") then
|
||||
shouldphysical = false
|
||||
end
|
||||
|
||||
if isent then
|
||||
self:FireRocket(data.ent, data.vel, data.ang, self.PhysBulletDontInheritPlayerVelocity)
|
||||
else
|
||||
-- if !game.SinglePlayer() and !IsFirstTimePredicted() then return end
|
||||
if !IsFirstTimePredicted() then return end
|
||||
|
||||
if shouldphysical then
|
||||
local tracernum = data.Tracer or 1
|
||||
local phystracer = self:GetBuff_Override("Override_PhysTracerProfile", self.PhysTracerProfile)
|
||||
local lastout = self:GetBuff_Override("Override_TracerFinalMag", self.TracerFinalMag)
|
||||
if lastout >= self:Clip1() then
|
||||
phystracer = self:GetBuff_Override("Override_PhysTracerProfileFinal", self.PhysTracerProfileFinal) or phystracer
|
||||
elseif tracernum == 0 or clip % tracernum != 0 then
|
||||
phystracer = 7
|
||||
end
|
||||
|
||||
local vel = self:GetMuzzleVelocity()
|
||||
|
||||
vel = vel * data.Dir:GetNormalized()
|
||||
|
||||
ArcCW:ShootPhysBullet(self, data.Src, vel, phystracer or 0)
|
||||
else
|
||||
owner:FireBullets(data, true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:DoPrimaryAnim()
|
||||
local anim = "fire"
|
||||
|
||||
local inbipod = self:InBipod()
|
||||
local iron = self:GetState() == ArcCW.STATE_SIGHTS
|
||||
|
||||
-- Needs testing
|
||||
if inbipod then
|
||||
anim = self:SelectAnimation("fire_bipod") or self:SelectAnimation("fire") or anim
|
||||
else
|
||||
anim = self:SelectAnimation("fire") or anim
|
||||
end
|
||||
|
||||
if (self.ProceduralIronFire and iron) or (self.ProceduralRegularFire and !iron) then anim = nil end
|
||||
|
||||
anim = self:GetBuff_Hook("Hook_SelectFireAnimation", anim) or anim
|
||||
|
||||
local time = self:GetBuff_Mult("Mult_FireAnimTime", anim) or 1
|
||||
|
||||
if anim then self:PlayAnimation(anim, time, true, 0, false) end
|
||||
end
|
||||
|
||||
function SWEP:DoPenetration(tr, penleft, alreadypenned)
|
||||
local bullet = {
|
||||
Damage = self:GetDamage((tr.HitPos - tr.StartPos):Length() * ArcCW.HUToM),
|
||||
DamageType = self:GetBuff_Override("Override_DamageType") or self.DamageType,
|
||||
Weapon = self,
|
||||
Penetration = self:GetBuff("Penetration"),
|
||||
Attacker = self:GetOwner(),
|
||||
Travelled = (tr.HitPos - tr.StartPos):Length()
|
||||
}
|
||||
|
||||
ArcCW:DoPenetration(tr, bullet.Damage, bullet, penleft, false, alreadypenned)
|
||||
end
|
||||
|
||||
function SWEP:GetFiringDelay()
|
||||
local delay = (self.Delay * (1 / self:GetBuff_Mult("Mult_RPM")))
|
||||
delay = self:GetBuff_Hook("Hook_ModifyRPM", delay) or delay
|
||||
|
||||
return delay
|
||||
end
|
||||
|
||||
function SWEP:GetShootSrc()
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if !IsValid(owner) then return self:GetPos() end
|
||||
if owner:IsNPC() then return owner:GetShootPos() end
|
||||
|
||||
local dir = owner:EyeAngles()
|
||||
local offset = Vector(0, 0, 0)
|
||||
|
||||
if self:GetOwner():Crouching() then
|
||||
offset = self:GetBuff_Override("Override_BarrelOffsetCrouch") or self.BarrelOffsetCrouch or offset
|
||||
end
|
||||
|
||||
if self:GetNWState() == ArcCW.STATE_SIGHTS then
|
||||
offset = LerpVector(self:GetNWSightDelta(), offset, self:GetBuff_Override("Override_BarrelOffsetSighted", self.BarrelOffsetSighted) or offset)
|
||||
else
|
||||
offset = LerpVector(1 - self:GetNWSightDelta(), offset, self:GetBuff_Override("Override_BarrelOffsetHip", self.BarrelOffsetHip) or offset)
|
||||
end
|
||||
|
||||
local src = owner:EyePos()
|
||||
|
||||
|
||||
src = src + dir:Right() * offset[1]
|
||||
src = src + dir:Forward() * offset[2]
|
||||
src = src + dir:Up() * offset[3]
|
||||
|
||||
return src
|
||||
end
|
||||
|
||||
function SWEP:GetShotgunSpreadOffset(num)
|
||||
local rotate = Angle()
|
||||
local spreadpt = self:GetBuff_Override("Override_ShotgunSpreadPattern") or self.ShotgunSpreadPattern or {}
|
||||
local spreadov = self:GetBuff_Override("Override_ShotgunSpreadPatternOverrun") or self.ShotgunSpreadPatternOverrun or { Angle() }
|
||||
|
||||
if istable(spreadpt) and istable(spreadov) then
|
||||
spreadpt["BaseClass"] = nil
|
||||
spreadov["BaseClass"] = nil
|
||||
|
||||
if num > #spreadpt then
|
||||
if spo then
|
||||
num = num - #spreadpt
|
||||
num = math.fmod(num, #spreadov) + 1
|
||||
rotate = spreadov[num]
|
||||
else
|
||||
num = math.fmod(num, #spreadpt) + 1
|
||||
rotate = spreadpt[num]
|
||||
end
|
||||
else
|
||||
rotate = spreadpt[num]
|
||||
end
|
||||
end
|
||||
|
||||
local rottoang = {}
|
||||
rottoang.num = num
|
||||
rottoang.ang = rotate
|
||||
|
||||
rotate = self:GetBuff_Hook("Hook_ShotgunSpreadOffset", rottoang).ang
|
||||
|
||||
return rotate or Angle()
|
||||
end
|
||||
|
||||
function SWEP:GetDispersion()
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if vrmod and vrmod.IsPlayerInVR(owner) then return 0 end
|
||||
|
||||
local hipdisp = self:GetBuff("HipDispersion")
|
||||
local sights = self:GetState() == ArcCW.STATE_SIGHTS
|
||||
|
||||
local hip = hipdisp
|
||||
|
||||
local sightdisp = self:GetBuff("SightsDispersion")
|
||||
if sights then hip = Lerp(self:GetNWSightDelta(), sightdisp, hipdisp) end
|
||||
|
||||
local speed = owner:GetAbsVelocity():Length()
|
||||
local maxspeed = owner:GetWalkSpeed() * self:GetBuff("SpeedMult")
|
||||
if sights then maxspeed = maxspeed * self:GetBuff("SightedSpeedMult") end
|
||||
speed = math.Clamp(speed / maxspeed, 0, 2)
|
||||
|
||||
if owner:OnGround() or owner:WaterLevel() > 0 and owner:GetMoveType() != MOVETYPE_NOCLIP then
|
||||
hip = hip + speed * self:GetBuff("MoveDispersion")
|
||||
elseif owner:GetMoveType() != MOVETYPE_NOCLIP then
|
||||
hip = hip + math.max(speed * self:GetBuff("MoveDispersion"), self:GetBuff("JumpDispersion"))
|
||||
end
|
||||
|
||||
if self:InBipod() then hip = hip * (self.BipodDispersion * self:GetBuff_Mult("Mult_BipodDispersion")) end
|
||||
|
||||
if ArcCW.ConVars["mult_crouchdisp"]:GetFloat() != 1 and owner:OnGround() and owner:Crouching() then
|
||||
hip = hip * ArcCW.ConVars["mult_crouchdisp"]:GetFloat()
|
||||
end
|
||||
|
||||
if ArcCW.ConVars["freeaim"]:GetInt() == 1 and !sights then
|
||||
hip = hip ^ 0.9
|
||||
end
|
||||
|
||||
--local t = hook.Run("ArcCW_ModDispersion", self, {dispersion = hip})
|
||||
--hip = t and t.dispersion or hip
|
||||
hip = self:GetBuff_Hook("Hook_ModDispersion", hip) or hip
|
||||
|
||||
return hip
|
||||
end
|
||||
|
||||
function SWEP:DoShellEject(atti)
|
||||
local eff = self:GetBuff_Override("Override_ShellEffect") or self.ShellEffect or "arccw_shelleffect"
|
||||
|
||||
if eff == "NONE" then return end
|
||||
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if !IsValid(owner) then return end
|
||||
|
||||
local vm = self
|
||||
|
||||
if !owner:IsNPC() then owner:GetViewModel() end
|
||||
|
||||
local att = vm:GetAttachment(atti or self:GetBuff_Override("Override_CaseEffectAttachment") or self.CaseEffectAttachment or 2)
|
||||
|
||||
if !att then return end
|
||||
|
||||
local pos, ang = att.Pos, att.Ang
|
||||
|
||||
if pos and ang and self.ShellEjectPosCorrection then
|
||||
local up = ang:Up()
|
||||
local right = ang:Right()
|
||||
local forward = ang:Forward()
|
||||
pos = pos + up * self.ShellEjectPosCorrection.z + right * self.ShellEjectPosCorrection.x + forward * self.ShellEjectPosCorrection.y
|
||||
end
|
||||
|
||||
local ed = EffectData()
|
||||
ed:SetOrigin(pos)
|
||||
ed:SetAngles(ang)
|
||||
ed:SetAttachment(atti or self:GetBuff_Override("Override_CaseEffectAttachment") or self.CaseEffectAttachment or 2)
|
||||
ed:SetScale(1)
|
||||
ed:SetEntity(self)
|
||||
ed:SetNormal(ang:Forward())
|
||||
ed:SetMagnitude(100)
|
||||
|
||||
local efov = {}
|
||||
efov.eff = eff
|
||||
efov.fx = ed
|
||||
|
||||
if self:GetBuff_Hook("Hook_PreDoEffects", efov) == true then return end
|
||||
|
||||
util.Effect(eff, ed)
|
||||
end
|
||||
|
||||
function SWEP:DoEffects(att)
|
||||
if !game.SinglePlayer() and !IsFirstTimePredicted() then return end
|
||||
|
||||
local ed = EffectData()
|
||||
ed:SetStart(self:GetShootSrc())
|
||||
ed:SetOrigin(self:GetShootSrc())
|
||||
ed:SetScale(1)
|
||||
ed:SetEntity(self)
|
||||
ed:SetAttachment(att or self:GetBuff_Override("Override_MuzzleEffectAttachment") or self.MuzzleEffectAttachment or 1)
|
||||
|
||||
local efov = {}
|
||||
efov.eff = "arccw_muzzleeffect"
|
||||
efov.fx = ed
|
||||
|
||||
if self:GetBuff_Hook("Hook_PreDoEffects", efov) == true then return end
|
||||
|
||||
util.Effect("arccw_muzzleeffect", ed)
|
||||
end
|
||||
|
||||
function SWEP:DryFire()
|
||||
|
||||
if self.Animations.fire_dry then
|
||||
return self:PlayAnimation("fire_dry", 1, true, 0, true)
|
||||
end
|
||||
self:MyEmitSound(self.ShootDrySound or "weapons/arccw/dryfire.wav", 75, 100, 1, CHAN_ITEM)
|
||||
self:SetNextPrimaryFire(CurTime() + 0.25)
|
||||
end
|
||||
|
||||
function SWEP:DoRecoil()
|
||||
local single = game.SinglePlayer()
|
||||
|
||||
if !single and !IsFirstTimePredicted() then return end
|
||||
|
||||
if single and self:GetOwner():IsValid() and SERVER then self:CallOnClient("DoRecoil") end
|
||||
|
||||
-- math.randomseed(self:GetBurstLength() + (self.Recoil * 409) + (self.RecoilSide * 519))
|
||||
|
||||
local rec = {
|
||||
Recoil = 1,
|
||||
RecoilSide = 1,
|
||||
VisualRecoilMul = 1
|
||||
}
|
||||
rec = self:GetBuff_Hook("Hook_ModifyRecoil", rec) or rec
|
||||
|
||||
local recoil = rec.Recoil
|
||||
local side = rec.RecoilSide
|
||||
local visual = rec.VisualRecoilMul
|
||||
|
||||
local rmul = (recoil or 1) * self:GetBuff_Mult("Mult_Recoil")
|
||||
local recv = (visual or 1) * self:GetBuff_Mult("Mult_VisualRecoilMult")
|
||||
local recs = (side or 1) * self:GetBuff_Mult("Mult_RecoilSide")
|
||||
|
||||
-- local rrange = math.Rand(-recs, recs) * self.RecoilSide
|
||||
|
||||
-- local irec = math.Rand(rrange - 1, rrange + 1)
|
||||
-- local recu = math.Rand(0.5, 1)
|
||||
|
||||
local irec = math.Rand(-1, 1)
|
||||
local recu = 1
|
||||
|
||||
if self:InBipod() then
|
||||
local b = self.BipodRecoil * self:GetBuff_Mult("Mult_BipodRecoil")
|
||||
|
||||
rmul = rmul * b
|
||||
recs = recs * b
|
||||
recv = recv * b
|
||||
end
|
||||
|
||||
local recoiltbl = self:GetBuff_Override("Override_ShotRecoilTable") or self.ShotRecoilTable
|
||||
|
||||
if recoiltbl and recoiltbl[self:GetBurstCount()] then rmul = rmul * recoiltbl[self:GetBurstCount()] end
|
||||
|
||||
if ArcCW.ConVars["mult_crouchrecoil"]:GetFloat() != 1 and self:GetOwner():OnGround() and self:GetOwner():Crouching() then
|
||||
rmul = rmul * ArcCW.ConVars["mult_crouchrecoil"]:GetFloat()
|
||||
end
|
||||
|
||||
local punch = Angle()
|
||||
|
||||
punch = punch + (self:GetBuff_Override("Override_RecoilDirection", self.RecoilDirection) * math.max(self.Recoil, 0.25) * recu * recv * rmul)
|
||||
punch = punch + (self:GetBuff_Override("Override_RecoilDirectionSide", self.RecoilDirectionSide) * math.max(self.RecoilSide, 0.25) * irec * recv * rmul)
|
||||
punch = punch + Angle(0, 0, 90) * math.Rand(-1, 1) * math.Clamp(self.Recoil, 0.25, 1) * recv * rmul * 0.01
|
||||
punch = punch * (self.RecoilPunch or 1) * self:GetBuff_Mult("Mult_RecoilPunch")
|
||||
|
||||
self:SetFreeAimAngle(self:GetFreeAimAngle() - punch)
|
||||
|
||||
if CLIENT then self:OurViewPunch(punch) end
|
||||
|
||||
if CLIENT or single then
|
||||
recv = recv * self.VisualRecoilMult
|
||||
|
||||
self.RecoilAmount = self.RecoilAmount + (self.Recoil * rmul * recu)
|
||||
self.RecoilAmountSide = self.RecoilAmountSide + (self.RecoilSide * irec * recs * rmul)
|
||||
self.RecoilPunchBack = math.Clamp(self.RecoilAmount * recv * 5, 1, 5)
|
||||
|
||||
if self.MaxRecoilBlowback > 0 then
|
||||
self.RecoilPunchBack = math.Clamp(self.RecoilPunchBack, 0, self.MaxRecoilBlowback)
|
||||
end
|
||||
|
||||
self.RecoilPunchSide = self.RecoilSide * 0.1 * irec * recv * rmul
|
||||
self.RecoilPunchUp = self.RecoilRise * 0.1 * recu
|
||||
end
|
||||
|
||||
-- math.randomseed(CurTime() + (self:EntIndex() * 3))
|
||||
end
|
||||
|
||||
function SWEP:GetBurstLength()
|
||||
local clip = self:Clip1()
|
||||
if self:HasBottomlessClip() then
|
||||
clip = self:Ammo1()
|
||||
if self:HasInfiniteAmmo() then
|
||||
clip = math.huge
|
||||
end
|
||||
end
|
||||
--if clip == 0 then return 1 end
|
||||
|
||||
local len = self:GetCurrentFiremode().Mode
|
||||
|
||||
if !len then return self:GetBurstCount() + 10 end
|
||||
|
||||
local hookedlen = self:GetBuff_Hook("Hook_GetBurstLength", len)
|
||||
|
||||
if len == 1 then return 1 end
|
||||
if len >= 2 then return self:GetBurstCount() + 10 end
|
||||
|
||||
if hookedlen != len then return hookedlen end
|
||||
|
||||
if len < 0 then return -len end
|
||||
|
||||
return self:GetBurstCount() + 10
|
||||
end
|
||||
|
||||
function SWEP:FireAnimationEvent(pos, ang, event, options)
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:IsRampupWeapon()
|
||||
local ovr = self:GetBuff_Override("Override_IsRampupWeapon")
|
||||
if ovr != nil then return ovr end
|
||||
return self:GetBuff("Damage") < self:GetBuff("DamageMin")
|
||||
end
|
||||
|
||||
function SWEP:GetMinMaxRange()
|
||||
local decrease = !self:IsRampupWeapon()
|
||||
|
||||
local min = self:GetBuff_Override("Override_RangeMin", self.RangeMin or 0)
|
||||
local max = self:GetBuff_Override("Override_Range", self.Range)
|
||||
local min_add = self:GetBuff_Add("Add_RangeMin")
|
||||
local max_add = self:GetBuff_Add("Add_Range")
|
||||
local min_mult = self:GetBuff_Mult("Mult_RangeMin")
|
||||
local max_mult = self:GetBuff_Mult("Mult_Range")
|
||||
|
||||
if decrease then
|
||||
-- MinRange is also affected by Mult_Range, this is intentional
|
||||
local total_min = math.max((min + min_add) * min_mult * max_mult, 0)
|
||||
return total_min, math.max((max + max_add) * max_mult, total_min)
|
||||
else
|
||||
-- For "rampup weapons" (dmgmin > dmg), range buffs *decrease* range, as it ramps up damage quicker
|
||||
-- After all, +Range is supposed to be a positive buff no matter the kind of gun
|
||||
local total_min = math.max((min - min_add) / min_mult / max_mult, 0)
|
||||
return total_min, math.max((max - max_add) / max_mult, total_min)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetRangeFraction(range)
|
||||
local min, max = self:GetMinMaxRange()
|
||||
if range < min then
|
||||
return 0
|
||||
else
|
||||
return math.Clamp((range - min) / (max - min), 0, 1)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetDamage(range, pellet)
|
||||
local ovr = self:GetBuff_Override("Override_Num")
|
||||
local add = self:GetBuff_Add("Add_Num")
|
||||
local mul = self:GetBuff_Mult("Mult_Num")
|
||||
|
||||
local num = self.Num
|
||||
local nbr = (ovr or num) * mul + add
|
||||
local factor = 1
|
||||
|
||||
-- Total damage should be unchanged regardless of whether the weapon originally fired 1 pellet or > 1
|
||||
-- If pellet is set, we return per-pellet damage instead of total damage
|
||||
if pellet and num == 1 then
|
||||
factor = 1 / ((ovr or 1) * mul + add)
|
||||
elseif num != nbr then
|
||||
factor = num / nbr
|
||||
end
|
||||
|
||||
--factor = ((pellet and num == 1) and (1 / ((ovr or 1) + add))) or ((num != nbr) and (num / nbr)) or 1
|
||||
|
||||
if !pellet then factor = factor * nbr end
|
||||
|
||||
local dmgmax = self:GetBuff("Damage") * factor
|
||||
local dmgmin = self:GetBuff("DamageMin") * factor
|
||||
local delta = self:GetRangeFraction(range)
|
||||
|
||||
local lerped = Lerp(delta, dmgmax, dmgmin)
|
||||
|
||||
return lerped
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
return self.Melee2 and self:Bash(true)
|
||||
end
|
||||
|
||||
function SWEP:CanShootWhileSprint()
|
||||
return ArcCW.ConVars["mult_shootwhilesprinting"]:GetBool() or self:GetBuff_Override("Override_ShootWhileSprint", self.ShootWhileSprint)
|
||||
end
|
||||
73
lua/weapons/arccw_base/sh_freeaim.lua
Normal file
73
lua/weapons/arccw_base/sh_freeaim.lua
Normal file
@@ -0,0 +1,73 @@
|
||||
--[[
|
||||
| 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 ang0 = Angle(0, 0, 0)
|
||||
SWEP.ClientFreeAimAng = Angle(ang0)
|
||||
|
||||
function SWEP:ShouldFreeAim()
|
||||
if self:GetOwner():IsNPC() then return false end
|
||||
if (ArcCW.ConVars["freeaim"]:GetInt() == 0 or self:GetBuff_Override("NeverFreeAim", self.NeverFreeAim)) and !self:GetBuff_Override("AlwaysFreeAim", self.AlwaysFreeAim) then return false end
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:FreeAimMaxAngle()
|
||||
local ang = self.FreeAimAngle and self:GetBuff("FreeAimAngle") or math.Clamp(self:GetBuff("HipDispersion") / 80, 3, 10)
|
||||
return ang
|
||||
end
|
||||
|
||||
function SWEP:ThinkFreeAim()
|
||||
if self:ShouldFreeAim() then
|
||||
local diff = self:GetOwner():EyeAngles() - self:GetLastAimAngle()
|
||||
--diff = diff * 2
|
||||
|
||||
local freeaimang = Angle(self:GetFreeAimAngle())
|
||||
|
||||
local max = self:FreeAimMaxAngle()
|
||||
|
||||
local delta = math.min(self:GetSightDelta(),
|
||||
self:CanShootWhileSprint() and 1 or (1 - self:GetSprintDelta()),
|
||||
self:GetState() == ArcCW.STATE_CUSTOMIZE and 0 or 1)
|
||||
|
||||
max = max * delta
|
||||
|
||||
diff.p = math.NormalizeAngle(diff.p)
|
||||
diff.y = math.NormalizeAngle(diff.y)
|
||||
|
||||
diff = diff * Lerp(delta, 1, 0.25)
|
||||
|
||||
freeaimang.p = math.Clamp(math.NormalizeAngle(freeaimang.p) + math.NormalizeAngle(diff.p), -max, max)
|
||||
freeaimang.y = math.Clamp(math.NormalizeAngle(freeaimang.y) + math.NormalizeAngle(diff.y), -max, max)
|
||||
|
||||
local ang2d = math.atan2(freeaimang.p, freeaimang.y)
|
||||
local mag2d = math.sqrt(math.pow(freeaimang.p, 2) + math.pow(freeaimang.y, 2))
|
||||
|
||||
mag2d = math.min(mag2d, max)
|
||||
|
||||
freeaimang.p = mag2d * math.sin(ang2d)
|
||||
freeaimang.y = mag2d * math.cos(ang2d)
|
||||
|
||||
self:SetFreeAimAngle(freeaimang)
|
||||
|
||||
if CLIENT then
|
||||
self.ClientFreeAimAng = freeaimang
|
||||
end
|
||||
end
|
||||
|
||||
self:SetLastAimAngle(self:GetOwner():EyeAngles())
|
||||
end
|
||||
|
||||
function SWEP:GetFreeAimOffset()
|
||||
if !self:ShouldFreeAim() then return ang0 end
|
||||
if CLIENT then
|
||||
return self.ClientFreeAimAng
|
||||
else
|
||||
return self:GetFreeAimAngle()
|
||||
end
|
||||
end
|
||||
200
lua/weapons/arccw_base/sh_grenade.lua
Normal file
200
lua/weapons/arccw_base/sh_grenade.lua
Normal file
@@ -0,0 +1,200 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
SWEP.GrenadePrimeTime = 0
|
||||
|
||||
function SWEP:PreThrow()
|
||||
|
||||
if self:GetNWState() == ArcCW.STATE_SPRINT and !self:CanShootWhileSprint() then return end
|
||||
|
||||
local bot, inf = self:HasBottomlessClip(), self:HasInfiniteAmmo()
|
||||
local aps = self:GetBuff("AmmoPerShot")
|
||||
|
||||
if !inf and (bot and self:Ammo1() or self:Clip1()) < aps then
|
||||
if self:Ammo1() == 0 and self:Clip1() == 0 and !self:GetBuff_Override("Override_KeepIfEmpty", self.KeepIfEmpty) then
|
||||
self:GetOwner():StripWeapon(self:GetClass())
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if self:GetGrenadePrimed() then return end
|
||||
|
||||
if engine.ActiveGamemode() == "terrortown" and GetRoundState and GetRoundState() == ROUND_PREP and
|
||||
((GetConVar("ttt_no_nade_throw_during_prep") and GetConVar("ttt_no_nade_throw_during_prep"):GetBool())
|
||||
or (GetConVar("ttt_nade_throw_during_prep") and !GetConVar("ttt_nade_throw_during_prep"):GetBool())) then
|
||||
return
|
||||
end
|
||||
|
||||
self.GrenadePrimeTime = CurTime()
|
||||
local alt = self:GetOwner():KeyDown(IN_ATTACK2)
|
||||
self:SetGrenadeAlt(alt)
|
||||
self:SetGrenadePrimed(true)
|
||||
|
||||
local pulltime = self:GetBuff("PullPinTime")
|
||||
local anim = alt and self:SelectAnimation("pre_throw_alt") or self:SelectAnimation("pre_throw")
|
||||
self:PlayAnimation(anim, self.PullPinTime / pulltime, true, 0, true, nil, true)
|
||||
|
||||
self.isCooked = (!alt and self:GetBuff("CookPrimFire", true)) or (alt and self:GetBuff("CookAltFire", true)) or nil
|
||||
|
||||
self:SetNextPrimaryFire(CurTime() + pulltime)
|
||||
self:SetPriorityAnim(CurTime() + pulltime)
|
||||
|
||||
self:SetShouldHoldType()
|
||||
|
||||
self:GetBuff_Hook("Hook_PreThrow")
|
||||
|
||||
if pulltime == 0 then
|
||||
self:Throw()
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Throw()
|
||||
if self:GetNextPrimaryFire() > CurTime() then return end
|
||||
|
||||
local isCooked = self.isCooked
|
||||
self:SetGrenadePrimed(false)
|
||||
self.isCooked = nil
|
||||
|
||||
local alt = self:GetGrenadeAlt()
|
||||
|
||||
local anim = alt and self:SelectAnimation("throw_alt") or self:SelectAnimation("throw")
|
||||
self:PlayAnimation(anim, self:GetBuff_Mult("Mult_ThrowTime"), false, 0, true)
|
||||
|
||||
local animevent = alt and self:GetBuff_Override("Override_AnimShootAlt", self.AnimShootAlt) or self:GetBuff_Override("Override_AnimShoot", self.AnimShoot)
|
||||
self:GetOwner():DoAnimationEvent(animevent)
|
||||
|
||||
local heldtime = CurTime() - self.GrenadePrimeTime
|
||||
|
||||
local mv = 0
|
||||
|
||||
if alt then
|
||||
mv = self:GetBuff("MuzzleVelocityAlt", true) or self:GetBuff("MuzzleVelocity")
|
||||
else
|
||||
mv = self:GetBuff("MuzzleVelocity")
|
||||
local chg = self:GetBuff("WindupTime")
|
||||
if chg > 0 then
|
||||
mv = Lerp(math.Clamp(heldtime / chg, 0, 1), mv * self:GetBuff("WindupMinimum"), mv)
|
||||
end
|
||||
end
|
||||
|
||||
local force = mv * ArcCW.HUToM
|
||||
|
||||
self:SetTimer(self:GetBuff("ShootEntityDelay"), function()
|
||||
|
||||
local ft = self:GetBuff("FuseTime", true)
|
||||
local data = {
|
||||
dodefault = true,
|
||||
force = force,
|
||||
shootentity = self:GetBuff_Override("Override_ShootEntity", self.ShootEntity),
|
||||
fusetime = ft and (ft - (isCooked and heldtime or 0)),
|
||||
}
|
||||
local ovr = self:GetBuff_Hook("Hook_Throw", data)
|
||||
if !ovr or ovr.dodefault then
|
||||
local rocket = self:FireRocket(self:GetBuff_Override("Override_ShootEntity", self.ShootEntity), force / ArcCW.HUToM)
|
||||
if !rocket then return end
|
||||
|
||||
if ft then
|
||||
if isCooked then
|
||||
rocket.FuseTime = ft - heldtime
|
||||
else
|
||||
rocket.FuseTime = ft
|
||||
end
|
||||
else
|
||||
rocket.FuseTime = math.huge
|
||||
end
|
||||
|
||||
local phys = rocket:GetPhysicsObject()
|
||||
|
||||
local inertia = self:GetBuff_Override("Override_ThrowInertia", self.ThrowInertia)
|
||||
if inertia == nil then inertia = ArcCW.ConVars["throwinertia"]:GetBool() end
|
||||
if inertia and mv > 100 then
|
||||
phys:AddVelocity(self:GetOwner():GetVelocity())
|
||||
end
|
||||
|
||||
phys:AddAngleVelocity( Vector(0, 750, 0) )
|
||||
end
|
||||
if !self:HasInfiniteAmmo() then
|
||||
local aps = self:GetBuff("AmmoPerShot")
|
||||
local a1 = self:Ammo1()
|
||||
if self:HasBottomlessClip() or a1 >= aps then
|
||||
self:TakePrimaryAmmo(aps)
|
||||
elseif a1 < aps then
|
||||
self:SetClip1(math.min(self:GetCapacity() + self:GetChamberSize(), self:Clip1() + a1))
|
||||
self:TakePrimaryAmmo(a1)
|
||||
end
|
||||
|
||||
if (self.Singleton or self:Ammo1() == 0) and !self:GetBuff_Override("Override_KeepIfEmpty", self.KeepIfEmpty) then
|
||||
self:GetOwner():StripWeapon(self:GetClass())
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
end)
|
||||
local t = self:GetAnimKeyTime(anim) * self:GetBuff_Mult("Mult_ThrowTime")
|
||||
self:SetPriorityAnim(CurTime() + t)
|
||||
self:SetTimer(t, function()
|
||||
if !self:IsValid() then return end
|
||||
local a = self:SelectAnimation("reload") or self:SelectAnimation("draw")
|
||||
self:PlayAnimation(a, self:GetBuff_Mult("Mult_ReloadTime"), true, 0, nil, nil, true)
|
||||
self:SetPriorityAnim(CurTime() + self:GetAnimKeyTime(a, true) * self:GetBuff_Mult("Mult_ReloadTime"))
|
||||
end)
|
||||
|
||||
self:SetNextPrimaryFire(CurTime() + self:GetFiringDelay())
|
||||
|
||||
self:SetGrenadeAlt(false)
|
||||
|
||||
self:SetShouldHoldType()
|
||||
|
||||
self:GetBuff_Hook("Hook_PostThrow")
|
||||
end
|
||||
|
||||
function SWEP:GrenadeDrop(doammo)
|
||||
local rocket = self:FireRocket(self.ShootEntity, 0)
|
||||
|
||||
if IsValid(rocket) then
|
||||
local phys = rocket:GetPhysicsObject()
|
||||
|
||||
if ArcCW.ConVars["throwinertia"]:GetBool() then
|
||||
phys:AddVelocity(self:GetOwner():GetVelocity())
|
||||
end
|
||||
|
||||
local ft = self:GetBuff_Override("Override_FuseTime") or self.FuseTime
|
||||
|
||||
if ft then
|
||||
if self.isCooked then
|
||||
rocket.FuseTime = ft - (CurTime() - self.GrenadePrimeTime)
|
||||
else
|
||||
rocket.FuseTime = ft
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if doammo then
|
||||
if !self:HasInfiniteAmmo() then
|
||||
local aps = self:GetBuff("AmmoPerShot")
|
||||
local a1 = self:Ammo1()
|
||||
if self:HasBottomlessClip() or a1 >= aps then
|
||||
self:TakePrimaryAmmo(aps)
|
||||
elseif a1 < aps then
|
||||
self:SetClip1(math.min(self:GetCapacity() + self:GetChamberSize(), self:Clip1() + a1))
|
||||
self:TakePrimaryAmmo(a1)
|
||||
end
|
||||
|
||||
if (self.Singleton or self:Ammo1() == 0) and !self:GetBuff_Override("Override_KeepIfEmpty", self.KeepIfEmpty) then
|
||||
self:GetOwner():StripWeapon(self:GetClass())
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
self:SetNextPrimaryFire(CurTime() + 1)
|
||||
self:SetGrenadePrimed(false)
|
||||
end
|
||||
end
|
||||
222
lua/weapons/arccw_base/sh_heat.lua
Normal file
222
lua/weapons/arccw_base/sh_heat.lua
Normal file
@@ -0,0 +1,222 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
SWEP.NextHeatDissipateTime = 0
|
||||
SWEP.Heat = 0
|
||||
|
||||
function SWEP:GetMaxHeat()
|
||||
return self:GetBuff("HeatCapacity")
|
||||
end
|
||||
|
||||
function SWEP:AddHeat(a)
|
||||
local single = game.SinglePlayer()
|
||||
a = tonumber(a)
|
||||
|
||||
if !(self.Jamming or self:GetBuff_Override("Override_Jamming")) then return end
|
||||
|
||||
if single and self:GetOwner():IsValid() and SERVER then self:CallOnClient("AddHeat", a) end
|
||||
-- if !single and !IsFirstTimePredicted() then return end
|
||||
|
||||
local max = self:GetBuff("HeatCapacity")
|
||||
local mult = 1 * self:GetBuff_Mult("Mult_FixTime")
|
||||
local heat = self:GetHeat()
|
||||
local anim = self:SelectAnimation("fix")
|
||||
anim = self:GetBuff_Hook("Hook_SelectFixAnim", anim) or anim
|
||||
local amount = a or 1
|
||||
local t = CurTime() + self:GetAnimKeyTime(anim) * mult
|
||||
self.Heat = math.max(0, heat + amount * ArcCW.ConVars["mult_heat"]:GetFloat())
|
||||
|
||||
self.NextHeatDissipateTime = CurTime() + (self:GetBuff("HeatDelayTime"))
|
||||
local overheat = self.Heat >= max
|
||||
if overheat then
|
||||
local h = self:GetBuff_Hook("Hook_Overheat", self.Heat)
|
||||
if h == true then overheat = false end
|
||||
end
|
||||
if overheat then
|
||||
self.Heat = math.min(self.Heat, max)
|
||||
if self:GetBuff_Override("Override_HeatFix", self.HeatFix) then
|
||||
self.NextHeatDissipateTime = t
|
||||
elseif self:GetBuff_Override("Override_HeatLockout", self.HeatLockout) then
|
||||
self.NextHeatDissipateTime = t
|
||||
end
|
||||
elseif !self:GetBuff_Override("Override_HeatOverflow", self.HeatOverflow) then
|
||||
self.Heat = math.min(self.Heat, max)
|
||||
end
|
||||
|
||||
if single and CLIENT then return end
|
||||
|
||||
self:SetHeat(self.Heat)
|
||||
|
||||
if overheat then
|
||||
|
||||
local ret = self:GetBuff_Hook("Hook_OnOverheat")
|
||||
if ret then return end
|
||||
|
||||
if anim then
|
||||
self:PlayAnimation(anim, mult, true, 0, true)
|
||||
self:SetPriorityAnim(t)
|
||||
self:SetNextPrimaryFire(t)
|
||||
|
||||
if self:GetBuff_Override("Override_HeatFix", self.HeatFix) then
|
||||
self:SetTimer(t - CurTime(),
|
||||
function()
|
||||
self:SetHeat(0)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
if self.HeatLockout or self:GetBuff_Override("Override_HeatLockout") then
|
||||
self:SetHeatLocked(true)
|
||||
end
|
||||
|
||||
self:GetBuff_Hook("Hook_PostOverheat")
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:DoHeat()
|
||||
if self.NextHeatDissipateTime > CurTime() then return end
|
||||
|
||||
--local diss = self.HeatDissipation or 2
|
||||
--diss = diss * self:GetBuff_Mult("Mult_HeatDissipation")
|
||||
local diss = self:GetBuff("HeatDissipation") or 2
|
||||
local ft = FrameTime()
|
||||
self.Heat = self:GetHeat() - (ft * diss)
|
||||
|
||||
self.Heat = math.max(self.Heat, 0)
|
||||
|
||||
self:SetHeat(self.Heat)
|
||||
|
||||
if self.Heat <= 0 and self:GetHeatLocked() then
|
||||
self:SetHeatLocked(false)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:HeatEnabled()
|
||||
return self.Jamming or self:GetBuff_Override("Override_Jamming")
|
||||
end
|
||||
|
||||
function SWEP:MalfunctionEnabled()
|
||||
local cvar = ArcCW.ConVars["malfunction"]:GetInt()
|
||||
return cvar == 2 or (cvar == 1 and self:GetBuff_Override("Override_Malfunction", self.Malfunction))
|
||||
end
|
||||
|
||||
function SWEP:GetMalfunctionAnimation()
|
||||
local anim = self:SelectAnimation("unjam")
|
||||
if !self.Animations[anim] then
|
||||
anim = self:SelectAnimation("fix")
|
||||
anim = self:GetBuff_Hook("Hook_SelectFixAnim", anim) or anim
|
||||
end
|
||||
if !self.Animations[anim] then anim = self:SelectAnimation("cycle") end
|
||||
if !self.Animations[anim] then anim = nil end
|
||||
return anim
|
||||
end
|
||||
|
||||
function SWEP:DoMalfunction(post)
|
||||
|
||||
if !IsFirstTimePredicted() then return end
|
||||
if !self:MalfunctionEnabled() then return false end
|
||||
local shouldpost = self:GetBuff_Override("Override_MalfunctionPostFire", self.MalfunctionPostFire)
|
||||
if post != shouldpost then return false end
|
||||
|
||||
-- Auto calculated malfunction mean
|
||||
if self.MalfunctionMean == nil then
|
||||
local mm
|
||||
if self.Jamming then mm = self.HeatCapacity * 4
|
||||
else mm = self.Primary.ClipSize * 8 end
|
||||
|
||||
if self.ManualAction then
|
||||
-- Manual guns are less likely to jam
|
||||
mm = mm * 2
|
||||
else
|
||||
-- Burst and semi only guns are less likely to jam
|
||||
local a, b = false, false
|
||||
for k, v in pairs(self.Firemodes) do
|
||||
if !v.Mode then continue end
|
||||
if v.Mode == 2 then a = true
|
||||
elseif v.Mode < 0 then b = true end
|
||||
end
|
||||
if !a and b then
|
||||
mm = mm * 1.25
|
||||
elseif !a and !b then
|
||||
mm = mm * 1.5
|
||||
end
|
||||
end
|
||||
self.MalfunctionMean = mm
|
||||
end
|
||||
|
||||
local cvar = math.max(ArcCW.ConVars["mult_malfunction"]:GetFloat(), 0.00000001)
|
||||
local mean = self:GetBuff("MalfunctionMean") / cvar
|
||||
local var = mean * math.Clamp(self:GetBuff("MalfunctionVariance") * math.max(1, math.sqrt(cvar)), 0, 1)
|
||||
local count = (self.ShotsSinceMalfunction or 0)
|
||||
|
||||
if !self.NextMalfunction then
|
||||
math.randomseed(math.Round(util.SharedRandom(count, -1337, 1337, !game.SinglePlayer() and self:GetOwner():GetCurrentCommand():CommandNumber() or CurTime()) * (self:EntIndex() % 30241)))
|
||||
self.NextMalfunction = math.ceil(math.sqrt(-2 * var * math.log(math.random())) * math.cos(2 * math.pi * math.random()))
|
||||
end
|
||||
|
||||
local ret = self:GetBuff_Hook("Hook_Malfunction", count, true)
|
||||
if ret != nil then return ret end
|
||||
|
||||
-- if self:Clip1() <= 1 then return false end -- Don't fucking
|
||||
|
||||
--print(mean, var, count, self.NextMalfunction)
|
||||
if count >= self.NextMalfunction + mean then
|
||||
local ret2 = self:GetBuff_Hook("Hook_OnMalfunction", count, true)
|
||||
if ret2 then return false end
|
||||
|
||||
self:MyEmitSound(self:GetBuff_Override("Override_MalfunctionSound") or self.MalfunctionSound, 75, 100, 1, CHAN_ITEM)
|
||||
|
||||
local wait = self:GetBuff("MalfunctionWait")
|
||||
self:SetNextPrimaryFire(CurTime() + wait)
|
||||
|
||||
local anim = self:GetMalfunctionAnimation()
|
||||
if !anim or self:GetBuff_Override("Override_MalfunctionJam", self.MalfunctionJam) then
|
||||
self:SetMalfunctionJam(true)
|
||||
else
|
||||
self:SetTimer(wait,
|
||||
function()
|
||||
self:MalfunctionClear()
|
||||
end)
|
||||
end
|
||||
|
||||
self:GetBuff_Hook("Hook_PostMalfunction")
|
||||
self.ShotsSinceMalfunction = 0
|
||||
self.NextMalfunction = nil
|
||||
|
||||
self:SetBurstCount(0)
|
||||
|
||||
return true
|
||||
else
|
||||
self.ShotsSinceMalfunction = (self.ShotsSinceMalfunction or 0) + 1
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:MalfunctionClear()
|
||||
|
||||
if self:GetBuff_Override("Override_MalfunctionTakeRound", self.MalfunctionTakeRound) then
|
||||
self:TakePrimaryAmmo(self:GetBuff("AmmoPerShot"))
|
||||
end
|
||||
|
||||
local anim = self:GetMalfunctionAnimation()
|
||||
if anim then
|
||||
self:PlayAnimation(anim, self:GetBuff_Mult("Mult_MalfunctionFixTime"), true, 0, true)
|
||||
local wait = self:GetAnimKeyTime(anim) - 0.01
|
||||
self:SetTimer(wait,
|
||||
function()
|
||||
self:SetMalfunctionJam(false)
|
||||
self:PlayIdleAnimation(true)
|
||||
end)
|
||||
return true
|
||||
else
|
||||
self:SetMalfunctionJam(false)
|
||||
return false
|
||||
end
|
||||
end
|
||||
1063
lua/weapons/arccw_base/sh_model.lua
Normal file
1063
lua/weapons/arccw_base/sh_model.lua
Normal file
File diff suppressed because it is too large
Load Diff
476
lua/weapons/arccw_base/sh_reload.lua
Normal file
476
lua/weapons/arccw_base/sh_reload.lua
Normal file
@@ -0,0 +1,476 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
|
||||
function SWEP:GetReloadTime()
|
||||
-- Only works with classic mag-fed weapons.
|
||||
local mult = self:GetBuff_Mult("Mult_ReloadTime")
|
||||
local anim = self:SelectReloadAnimation()
|
||||
|
||||
if !self.Animations[anim] then return false end
|
||||
|
||||
local full = self:GetAnimKeyTime(anim) * mult
|
||||
local magin = self:GetAnimKeyTime(anim, true) * mult
|
||||
|
||||
return { full, magin }
|
||||
end
|
||||
|
||||
function SWEP:SetClipInfo(load)
|
||||
load = self:GetBuff_Hook("Hook_SetClipInfo", load) or load
|
||||
self.LastLoadClip1 = load - self:Clip1()
|
||||
self.LastClip1 = load
|
||||
end
|
||||
|
||||
function SWEP:Reload()
|
||||
if IsValid(self:GetHolster_Entity()) then return end
|
||||
if self:GetHolster_Time() > 0 then return end
|
||||
|
||||
if self:GetOwner():IsNPC() then
|
||||
return
|
||||
end
|
||||
|
||||
if self:GetState() == ArcCW.STATE_CUSTOMIZE then
|
||||
return
|
||||
end
|
||||
|
||||
-- Switch to UBGL
|
||||
if self:GetBuff_Override("UBGL") and self:GetOwner():KeyDown(IN_USE) then
|
||||
if self:GetInUBGL() then
|
||||
--net.Start("arccw_ubgl")
|
||||
--net.WriteBool(false)
|
||||
--net.SendToServer()
|
||||
|
||||
self:DeselectUBGL()
|
||||
else
|
||||
--net.Start("arccw_ubgl")
|
||||
--net.WriteBool(true)
|
||||
--net.SendToServer()
|
||||
|
||||
self:SelectUBGL()
|
||||
end
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if self:GetInUBGL() then
|
||||
if self:GetNextSecondaryFire() > CurTime() then return end
|
||||
self:ReloadUBGL()
|
||||
return
|
||||
end
|
||||
|
||||
if self:GetNextPrimaryFire() >= CurTime() then return end
|
||||
-- if !game.SinglePlayer() and !IsFirstTimePredicted() then return end
|
||||
|
||||
|
||||
if self.Throwing then return end
|
||||
if self.PrimaryBash then return end
|
||||
|
||||
-- with the lite 3D HUD, you may want to check your ammo without reloading
|
||||
local Lite3DHUD = self:GetOwner():GetInfo("arccw_hud_3dfun") == "1"
|
||||
if self:GetOwner():KeyDown(IN_WALK) and Lite3DHUD then
|
||||
return
|
||||
end
|
||||
|
||||
if self:GetMalfunctionJam() then
|
||||
local r = self:MalfunctionClear()
|
||||
if r then return end
|
||||
end
|
||||
|
||||
if !self:GetMalfunctionJam() and self:Ammo1() <= 0 and !self:HasInfiniteAmmo() then return end
|
||||
|
||||
if self:HasBottomlessClip() then return end
|
||||
|
||||
if self:GetBuff_Hook("Hook_PreReload") then return end
|
||||
|
||||
-- if we must dump our clip when reloading, our reserve ammo should be more than our clip
|
||||
local dumpclip = self:GetBuff_Hook("Hook_ReloadDumpClip")
|
||||
if dumpclip and !self:HasInfiniteAmmo() and self:Clip1() >= self:Ammo1() then
|
||||
return
|
||||
end
|
||||
|
||||
self.LastClip1 = self:Clip1()
|
||||
|
||||
local reserve = self:Ammo1()
|
||||
|
||||
reserve = reserve + self:Clip1()
|
||||
if self:HasInfiniteAmmo() then reserve = self:GetCapacity() + self:Clip1() end
|
||||
|
||||
local clip = self:GetCapacity()
|
||||
|
||||
local chamber = math.Clamp(self:Clip1(), 0, self:GetChamberSize())
|
||||
if self:GetNeedCycle() then chamber = 0 end
|
||||
|
||||
local load = math.Clamp(clip + chamber, 0, reserve)
|
||||
|
||||
if !self:GetMalfunctionJam() and load <= self:Clip1() then return end
|
||||
|
||||
self:SetBurstCount(0)
|
||||
|
||||
local shouldshotgunreload = self:GetBuff_Override("Override_ShotgunReload")
|
||||
local shouldhybridreload = self:GetBuff_Override("Override_HybridReload")
|
||||
|
||||
if shouldshotgunreload == nil then shouldshotgunreload = self.ShotgunReload end
|
||||
if shouldhybridreload == nil then shouldhybridreload = self.HybridReload end
|
||||
|
||||
if shouldhybridreload then
|
||||
shouldshotgunreload = self:Clip1() != 0
|
||||
end
|
||||
|
||||
if shouldshotgunreload and self:GetShotgunReloading() > 0 then return end
|
||||
|
||||
local mult = self:GetBuff_Mult("Mult_ReloadTime")
|
||||
|
||||
if shouldshotgunreload then
|
||||
local anim = "sgreload_start"
|
||||
local insertcount = 0
|
||||
|
||||
local empty = self:Clip1() == 0 --or self:GetNeedCycle()
|
||||
|
||||
if self.Animations.sgreload_start_empty and empty then
|
||||
anim = "sgreload_start_empty"
|
||||
empty = false
|
||||
if (self.Animations.sgreload_start_empty or {}).ForceEmpty == true then
|
||||
empty = true
|
||||
end
|
||||
|
||||
insertcount = (self.Animations.sgreload_start_empty or {}).RestoreAmmo or 1
|
||||
else
|
||||
insertcount = (self.Animations.sgreload_start or {}).RestoreAmmo or 0
|
||||
end
|
||||
|
||||
anim = self:GetBuff_Hook("Hook_SelectReloadAnimation", anim) or anim
|
||||
|
||||
local time = self:GetAnimKeyTime(anim)
|
||||
local time2 = self:GetAnimKeyTime(anim, true)
|
||||
|
||||
if time2 >= time then
|
||||
time2 = 0
|
||||
end
|
||||
|
||||
if insertcount > 0 then
|
||||
self:SetMagUpCount(insertcount)
|
||||
self:SetMagUpIn(CurTime() + time2 * mult)
|
||||
end
|
||||
self:PlayAnimation(anim, mult, true, 0, true, nil, true)
|
||||
|
||||
self:SetReloading(CurTime() + time * mult)
|
||||
|
||||
self:SetShotgunReloading(empty and 4 or 2)
|
||||
else
|
||||
local anim = self:SelectReloadAnimation()
|
||||
|
||||
if !self.Animations[anim] then print("Invalid animation \"" .. anim .. "\"") return end
|
||||
|
||||
self:PlayAnimation(anim, mult, true, 0, false, nil, true)
|
||||
|
||||
local reloadtime = self:GetAnimKeyTime(anim, true) * mult
|
||||
local reloadtime2 = self:GetAnimKeyTime(anim, false) * mult
|
||||
|
||||
self:SetNextPrimaryFire(CurTime() + reloadtime2)
|
||||
self:SetReloading(CurTime() + reloadtime2)
|
||||
|
||||
self:SetMagUpCount(0)
|
||||
self:SetMagUpIn(CurTime() + reloadtime)
|
||||
end
|
||||
|
||||
self:SetClipInfo(load)
|
||||
if game.SinglePlayer() then
|
||||
self:CallOnClient("SetClipInfo", tostring(load))
|
||||
end
|
||||
|
||||
for i, k in pairs(self.Attachments) do
|
||||
if !k.Installed then continue end
|
||||
local atttbl = ArcCW.AttachmentTable[k.Installed]
|
||||
|
||||
if atttbl.DamageOnReload then
|
||||
self:DamageAttachment(i, atttbl.DamageOnReload)
|
||||
end
|
||||
end
|
||||
|
||||
if !self.ReloadInSights then
|
||||
self:ExitSights()
|
||||
self.Sighted = false
|
||||
end
|
||||
|
||||
self:GetBuff_Hook("Hook_PostReload")
|
||||
end
|
||||
|
||||
function SWEP:ReloadTimed()
|
||||
-- yeah my function names are COOL and QUIRKY and you can't say a DAMN thing about it.
|
||||
self:RestoreAmmo(self:GetMagUpCount() != 0 and self:GetMagUpCount())
|
||||
self:SetMagUpCount(0)
|
||||
self:SetLastLoad(self:Clip1())
|
||||
self:SetNthReload(self:GetNthReload() + 1)
|
||||
end
|
||||
|
||||
function SWEP:Unload()
|
||||
if !self:GetOwner():IsPlayer() then return end
|
||||
if SERVER and self:Clip1() != ArcCW.BottomlessMagicNumber then
|
||||
self:GetOwner():GiveAmmo(self:Clip1(), self.Primary.Ammo or "", true)
|
||||
end
|
||||
self:SetClip1(0)
|
||||
end
|
||||
|
||||
function SWEP:HasBottomlessClip()
|
||||
if ArcCW.ConVars["mult_bottomlessclip"]:GetBool() then return true end
|
||||
if self.BottomlessClip or self:GetBuff_Override("Override_BottomlessClip") then return true end
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:HasInfiniteAmmo()
|
||||
if ArcCW.ConVars["mult_infiniteammo"]:GetBool() then return true end
|
||||
if self:GetBuff_Override("Override_InfiniteAmmo", self.InfiniteAmmo) then return true end
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:RestoreAmmo(count)
|
||||
if self:GetOwner():IsNPC() then return end
|
||||
|
||||
local chamber = math.Clamp(self:Clip1(), 0, self:GetChamberSize())
|
||||
if self:GetNeedCycle() then chamber = 0 end
|
||||
|
||||
local clip = self:GetCapacity()
|
||||
|
||||
count = count or (clip + chamber)
|
||||
|
||||
local reserve = (self:HasInfiniteAmmo() and math.huge or self:Ammo1())
|
||||
|
||||
local dumpclip = self:GetBuff_Hook("Hook_ReloadDumpClip")
|
||||
if !dumpclip then
|
||||
reserve = reserve + self:Clip1()
|
||||
end
|
||||
|
||||
local load = math.Clamp(self:Clip1() + count, 0, reserve)
|
||||
load = math.Clamp(load, 0, clip + chamber)
|
||||
reserve = reserve - load
|
||||
|
||||
if !self:HasInfiniteAmmo() then
|
||||
self:GetOwner():SetAmmo(reserve, self.Primary.Ammo, true)
|
||||
end
|
||||
self:SetClip1(load)
|
||||
end
|
||||
|
||||
-- local lastframeclip1 = 0
|
||||
|
||||
SWEP.LastClipOutTime = 0
|
||||
|
||||
function SWEP:GetVisualBullets()
|
||||
local h = self:GetBuff_Hook("Hook_GetVisualBullets")
|
||||
if h then return h end
|
||||
|
||||
local _clip = self:Clip1()
|
||||
local _ammo = self:Ammo1()
|
||||
|
||||
if self:HasInfiniteAmmo() then
|
||||
_ammo = math.huge
|
||||
end
|
||||
if self:HasBottomlessClip() then
|
||||
_clip = _ammo
|
||||
end
|
||||
|
||||
if self.LastClipOutTime > CurTime() then
|
||||
return self.LastClip1_B or _clip
|
||||
else
|
||||
self.LastClip1_B = _clip
|
||||
|
||||
if self:GetReloading() and !(self.ShotgunReload or (self.HybridReload and _clip == 0)) then
|
||||
return math.Clamp(_clip + _ammo, 0, self:GetCapacity() + self:GetChamberSize())
|
||||
else
|
||||
return _clip
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetVisualClip()
|
||||
-- local reserve = self:Ammo1()
|
||||
-- local chamber = math.Clamp(self:Clip1(), 0, self:GetChamberSize())
|
||||
-- local abouttoload = math.Clamp(self:GetCapacity() + chamber, 0, reserve + self:Clip1())
|
||||
|
||||
-- local h = self:GetBuff_Hook("Hook_GetVisualClip")
|
||||
|
||||
-- if h then return h end
|
||||
-- if self.LastClipOutTime > CurTime() then
|
||||
-- return self.LastClip1 or self:Clip1()
|
||||
-- else
|
||||
-- if !self.RevolverReload then
|
||||
-- self.LastClip1 = self:Clip1()
|
||||
-- else
|
||||
-- if self:Clip1() > lastframeclip1 then
|
||||
-- self.LastClip1 = self:Clip1()
|
||||
-- end
|
||||
|
||||
-- lastframeclip1 = self:Clip1()
|
||||
-- end
|
||||
|
||||
-- if self:GetReloading() and !(self.ShotgunReload or (self.HybridReload and self:Clip1() == 0)) then
|
||||
-- return abouttoload
|
||||
-- else
|
||||
-- return self.LastClip1 or self:Clip1()
|
||||
-- end
|
||||
-- end
|
||||
|
||||
local reserve = self:Ammo1()
|
||||
if self:HasInfiniteAmmo() then
|
||||
reserve = math.huge
|
||||
end
|
||||
local chamber = math.Clamp(self:Clip1(), 0, self:GetChamberSize())
|
||||
local abouttoload = math.Clamp(self:GetCapacity() + chamber, 0, reserve + self:Clip1())
|
||||
|
||||
local h = self:GetBuff_Hook("Hook_GetVisualClip")
|
||||
|
||||
if h then return h end
|
||||
|
||||
if self.LastClipOutTime > CurTime() then
|
||||
return self:GetLastLoad() or self:Clip1()
|
||||
end
|
||||
|
||||
if self.RevolverReload then
|
||||
if self:GetReloading() and !(self.ShotgunReload or (self.HybridReload and self:Clip1() == 0)) then
|
||||
return abouttoload
|
||||
else
|
||||
return self:GetLastLoad() or self:Clip1()
|
||||
end
|
||||
else
|
||||
return self:Clip1()
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetVisualLoadAmount()
|
||||
return self.LastLoadClip1 or self:Clip1()
|
||||
end
|
||||
|
||||
function SWEP:SelectReloadAnimation()
|
||||
local ret
|
||||
|
||||
if self.Animations.reload_empty and self:Clip1() == 0 then
|
||||
ret = "reload_empty"
|
||||
else
|
||||
ret = "reload"
|
||||
end
|
||||
|
||||
ret = self:GetBuff_Hook("Hook_SelectReloadAnimation", ret) or ret
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
function SWEP:ReloadInsert(empty)
|
||||
local total = self:GetCapacity()
|
||||
|
||||
-- if !game.SinglePlayer() and !IsFirstTimePredicted() then return end
|
||||
|
||||
if !empty and !self:GetNeedCycle() then
|
||||
total = total + (self:GetBuff("ChamberLoadNonEmpty", true) or self:GetChamberSize())
|
||||
else
|
||||
total = total + (self:GetBuff("ChamberLoadEmpty", true) or 0)
|
||||
end
|
||||
|
||||
local mult = self:GetBuff_Mult("Mult_ReloadTime")
|
||||
|
||||
if self:Clip1() >= total or (self:Ammo1() == 0 and !self:HasInfiniteAmmo()) or ((self:GetShotgunReloading() == 3 or self:GetShotgunReloading() == 5) and self:Clip1() > 0) then
|
||||
local ret = "sgreload_finish"
|
||||
|
||||
if empty then
|
||||
if self.Animations.sgreload_finish_empty then
|
||||
ret = "sgreload_finish_empty"
|
||||
end
|
||||
if self:GetNeedCycle() then
|
||||
self:SetNeedCycle(false)
|
||||
end
|
||||
end
|
||||
|
||||
ret = self:GetBuff_Hook("Hook_SelectReloadAnimation", ret) or ret
|
||||
|
||||
self:PlayAnimation(ret, mult, true, 0, true, nil, true)
|
||||
self:SetReloading(CurTime() + (self:GetAnimKeyTime(ret, true) * mult))
|
||||
|
||||
self:SetTimer(self:GetAnimKeyTime(ret, true) * mult,
|
||||
function()
|
||||
self:SetNthReload(self:GetNthReload() + 1)
|
||||
if self:GetOwner():KeyDown(IN_ATTACK2) then
|
||||
self:EnterSights()
|
||||
end
|
||||
end)
|
||||
|
||||
self:SetShotgunReloading(0)
|
||||
else
|
||||
local insertcount = self:GetBuff_Override("Override_InsertAmount") or 1
|
||||
local insertanim = "sgreload_insert"
|
||||
|
||||
local ret = self:GetBuff_Hook("Hook_SelectInsertAnimation", {count = insertcount, anim = insertanim, empty = empty})
|
||||
|
||||
if ret then
|
||||
insertcount = ret.count
|
||||
insertanim = ret.anim
|
||||
end
|
||||
|
||||
local load = self:GetCapacity() + math.min(self:Clip1(), self:GetChamberSize())
|
||||
if load - self:Clip1() > self:Ammo1() then load = self:Clip1() + self:Ammo1() end
|
||||
self:SetClipInfo(load)
|
||||
if game.SinglePlayer() then
|
||||
self:CallOnClient("SetClipInfo", tostring(load))
|
||||
end
|
||||
|
||||
local time = self:GetAnimKeyTime(insertanim, false)
|
||||
local time2 = self:GetAnimKeyTime(insertanim, true)
|
||||
|
||||
if time2 >= time then
|
||||
time2 = 0
|
||||
end
|
||||
|
||||
self:SetMagUpCount(insertcount)
|
||||
self:SetMagUpIn(CurTime() + time2 * mult)
|
||||
|
||||
self:SetReloading(CurTime() + time * mult)
|
||||
|
||||
self:PlayAnimation(insertanim, mult, true, 0, true, nil, true)
|
||||
self:SetShotgunReloading(empty and 4 or 2)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetCapacity()
|
||||
local clip = self.RegularClipSize or self.Primary.ClipSize
|
||||
|
||||
if !self.RegularClipSize then
|
||||
self.RegularClipSize = self.Primary.ClipSize
|
||||
end
|
||||
|
||||
local level = 1
|
||||
|
||||
if self:GetBuff_Override("MagExtender") then
|
||||
level = level + 1
|
||||
end
|
||||
|
||||
if self:GetBuff_Override("MagReducer") then
|
||||
level = level - 1
|
||||
end
|
||||
|
||||
if level == 0 then
|
||||
clip = self.ReducedClipSize
|
||||
elseif level == 2 then
|
||||
clip = self.ExtendedClipSize
|
||||
end
|
||||
|
||||
clip = self:GetBuff("ClipSize", true, clip) or clip
|
||||
|
||||
local ret = self:GetBuff_Hook("Hook_GetCapacity", clip)
|
||||
|
||||
clip = ret or clip
|
||||
|
||||
clip = math.Clamp(math.Round(clip), 0, math.huge)
|
||||
|
||||
self.Primary.ClipSize = clip
|
||||
|
||||
return clip
|
||||
end
|
||||
|
||||
function SWEP:GetChamberSize()
|
||||
return self:GetBuff("ChamberSize") --(self:GetBuff_Override("Override_ChamberSize") or self.ChamberSize) + self:GetBuff_Add("Add_ChamberSize")
|
||||
end
|
||||
79
lua/weapons/arccw_base/sh_rocket.lua
Normal file
79
lua/weapons/arccw_base/sh_rocket.lua
Normal file
@@ -0,0 +1,79 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
function SWEP:FireRocket(ent, vel, ang, dontinheritvel)
|
||||
if CLIENT then return end
|
||||
|
||||
local rocket = ents.Create(ent)
|
||||
|
||||
ang = ang or (self:GetOwner():EyeAngles() + self:GetFreeAimOffset())
|
||||
|
||||
local src = self:GetShootSrc()
|
||||
|
||||
if !rocket:IsValid() then print("!!! INVALID ROUND " .. ent) return end
|
||||
|
||||
local rocketAng = Angle(ang.p, ang.y, ang.r)
|
||||
if ang and self.ShootEntityAngleCorrection then
|
||||
local up = ang:Up()
|
||||
local right = ang:Right()
|
||||
local forward = ang:Forward()
|
||||
rocketAng:RotateAroundAxis(up, self.ShootEntityAngleCorrection.y)
|
||||
rocketAng:RotateAroundAxis(right, self.ShootEntityAngleCorrection.p)
|
||||
rocketAng:RotateAroundAxis(forward, self.ShootEntityAngleCorrection.r)
|
||||
end
|
||||
|
||||
rocket:SetAngles(rocketAng)
|
||||
rocket:SetPos(src)
|
||||
|
||||
rocket:SetOwner(self:GetOwner())
|
||||
|
||||
rocket.Inflictor = self
|
||||
|
||||
local randfactor = self:GetBuff("DamageRand")
|
||||
local mul = 1
|
||||
if randfactor > 0 then
|
||||
mul = mul * math.Rand(1 - randfactor, 1 + randfactor)
|
||||
end
|
||||
rocket.Damage = self:GetBuff("Damage") * mul
|
||||
|
||||
if self.BlastRadius then
|
||||
local r_randfactor = self:GetBuff("DamageRand")
|
||||
local r_mul = 1
|
||||
if r_randfactor > 0 then
|
||||
r_mul = r_mul * math.Rand(1 - r_randfactor, 1 + r_randfactor)
|
||||
end
|
||||
rocket.BlastRadius = self:GetBuff("BlastRadius") * r_mul
|
||||
end
|
||||
|
||||
local RealVelocity = (!dontinheritvel and self:GetOwner():GetAbsVelocity() or Vector(0, 0, 0)) + ang:Forward() * vel
|
||||
rocket.CurVel = RealVelocity -- for non-physical projectiles that move themselves
|
||||
|
||||
rocket:Spawn()
|
||||
rocket:Activate()
|
||||
if !rocket.NoPhys and rocket:GetPhysicsObject():IsValid() then
|
||||
rocket:SetCollisionGroup(rocket.CollisionGroup or COLLISION_GROUP_DEBRIS)
|
||||
rocket:GetPhysicsObject():SetVelocityInstantaneous(RealVelocity)
|
||||
end
|
||||
|
||||
if rocket.Launch and rocket.SetState then
|
||||
rocket:SetState(1)
|
||||
rocket:Launch()
|
||||
end
|
||||
|
||||
if rocket.ArcCW_Killable == nil then
|
||||
rocket.ArcCW_Killable = true
|
||||
end
|
||||
|
||||
rocket.ArcCWProjectile = true
|
||||
|
||||
self:GetBuff_Hook("Hook_PostFireRocket", rocket)
|
||||
|
||||
return rocket
|
||||
end
|
||||
533
lua/weapons/arccw_base/sh_sights.lua
Normal file
533
lua/weapons/arccw_base/sh_sights.lua
Normal file
@@ -0,0 +1,533 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
SWEP.Sighted = false
|
||||
SWEP.Sprinted = false
|
||||
|
||||
local function linearlerp(a, b, c)
|
||||
return b + (c - b) * a
|
||||
end
|
||||
|
||||
function SWEP:GetSightTime()
|
||||
return self:GetBuff("SightTime")
|
||||
end
|
||||
|
||||
function SWEP:EnterSprint()
|
||||
if engine.ActiveGamemode() == "terrortown" and !(TTT2 and self:GetOwner().isSprinting) then return end
|
||||
if self:GetState() == ArcCW.STATE_SPRINT then return end
|
||||
if self:GetState() == ArcCW.STATE_CUSTOMIZE then return end
|
||||
if self:GetTriggerDelta() > 0 then return end
|
||||
if self:GetGrenadePrimed() and !self:CanShootWhileSprint() then return end
|
||||
self:SetState(ArcCW.STATE_SPRINT)
|
||||
self.Sighted = false
|
||||
self.Sprinted = true
|
||||
|
||||
local ct = CurTime()
|
||||
|
||||
-- self.SwayScale = 1
|
||||
-- self.BobScale = 5
|
||||
|
||||
self:SetShouldHoldType()
|
||||
|
||||
local s = self:CanShootWhileSprint()
|
||||
|
||||
if !s and self:GetNextPrimaryFire() <= ct then
|
||||
self:SetNextPrimaryFire(ct)
|
||||
end
|
||||
|
||||
local anim = self:SelectAnimation("enter_sprint")
|
||||
if anim and !s and self:GetNextSecondaryFire() <= ct then
|
||||
self:PlayAnimation(anim, self:GetBuff("SightTime") / self:GetAnimKeyTime(anim, true), true, nil, false, nil, false, false)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:ExitSprint()
|
||||
if self:GetState() == ArcCW.STATE_IDLE then return end
|
||||
|
||||
local delta = self:GetNWSprintDelta()
|
||||
local ct = CurTime()
|
||||
|
||||
self:SetState(ArcCW.STATE_IDLE)
|
||||
self.Sighted = false
|
||||
self.Sprinted = false
|
||||
|
||||
-- self.SwayScale = 1
|
||||
-- self.BobScale = 1.5
|
||||
|
||||
self:SetShouldHoldType()
|
||||
|
||||
local s = self:CanShootWhileSprint()
|
||||
|
||||
if !s and self:GetNextPrimaryFire() <= ct then
|
||||
self:SetNextPrimaryFire(ct + self:GetSprintTime() * delta)
|
||||
end
|
||||
|
||||
if self:GetOwner():KeyDown(IN_ATTACK2) then
|
||||
self:EnterSights()
|
||||
end
|
||||
|
||||
local anim = self:SelectAnimation("exit_sprint")
|
||||
if anim and !s then -- and self:GetNextSecondaryFire() <= ct
|
||||
self:PlayAnimation(anim, self:GetBuff("SightTime") / self:GetAnimKeyTime(anim, true), true, nil, false, nil, false, false)
|
||||
end
|
||||
end
|
||||
|
||||
-- defined above already?
|
||||
|
||||
function SWEP:EnterSights()
|
||||
local asight = self:GetActiveSights()
|
||||
if !asight then return end
|
||||
if self:GetState() != ArcCW.STATE_IDLE then return end
|
||||
if self:GetCurrentFiremode().Mode == 0 then return end
|
||||
if !self.ReloadInSights and (self:GetReloading() or self:GetOwner():KeyDown(IN_RELOAD)) then return end
|
||||
if self.LockSightsInPriorityAnim and self:GetPriorityAnim() then return end
|
||||
if self:GetBuff_Hook("Hook_ShouldNotSight") then return end
|
||||
if (!game.SinglePlayer() and !IsFirstTimePredicted()) then return end
|
||||
|
||||
self:SetupActiveSights()
|
||||
|
||||
self:SetState(ArcCW.STATE_SIGHTS)
|
||||
self.Sighted = true
|
||||
self.Sprinted = false
|
||||
|
||||
self:SetShouldHoldType()
|
||||
|
||||
self:MyEmitSound(asight.SwitchToSound or "", 75, math.Rand(95, 105), 0.5, CHAN_AUTO)
|
||||
|
||||
local anim = self:SelectAnimation("enter_sight")
|
||||
if anim then
|
||||
self:PlayAnimation(anim, 1 * self:GetBuff_Mult("Mult_SightTime"), true)
|
||||
end
|
||||
|
||||
self:GetBuff_Hook("Hook_SightToggle", true)
|
||||
end
|
||||
|
||||
function SWEP:ExitSights()
|
||||
local asight = self:GetActiveSights()
|
||||
if self:GetState() != ArcCW.STATE_SIGHTS then return end
|
||||
if self.LockSightsInReload and self:GetReloading() then return end
|
||||
if self.LockSightsInPriorityAnim and self:GetPriorityAnim() then return end
|
||||
if (!game.SinglePlayer() and !IsFirstTimePredicted()) then return end
|
||||
|
||||
self:SetState(ArcCW.STATE_IDLE)
|
||||
self.Sighted = false
|
||||
self.Sprinted = false
|
||||
|
||||
self:SetShouldHoldType()
|
||||
|
||||
self:MyEmitSound(asight.SwitchFromSound or "", 75, math.Rand(80, 90), 0.5, CHAN_AUTO)
|
||||
|
||||
if self:InSprint() then
|
||||
self:EnterSprint()
|
||||
end
|
||||
|
||||
self:MyEmitSound(asight.SwitchFromSound or "", 75, math.Rand(80, 90), 0.5, CHAN_AUTO)
|
||||
|
||||
local anim = self:SelectAnimation("exit_sight")
|
||||
if anim then
|
||||
self:PlayAnimation(anim, 1 * self:GetBuff_Mult("Mult_SightTime"), true)
|
||||
end
|
||||
|
||||
self:GetBuff_Hook("Hook_SightToggle", false)
|
||||
end
|
||||
|
||||
function SWEP:GetSprintTime()
|
||||
return self:GetSightTime()
|
||||
end
|
||||
|
||||
SWEP.SightTable = {}
|
||||
SWEP.SightMagnifications = {}
|
||||
|
||||
function SWEP:SetupActiveSights()
|
||||
if !self.IronSightStruct then return end
|
||||
if self:GetBuff_Hook("Hook_ShouldNotSight") then return false end
|
||||
|
||||
if !self:GetOwner():IsPlayer() then return end
|
||||
|
||||
local sighttable = {}
|
||||
local vm = self:GetOwner():GetViewModel()
|
||||
|
||||
if !vm or !vm:IsValid() then return end
|
||||
|
||||
local kbi = self.KeepBaseIrons or true
|
||||
local bif = self.BaseIronsFirst or true
|
||||
|
||||
for i, k in pairs(self.Attachments) do
|
||||
if !k.Installed then continue end
|
||||
|
||||
local atttbl = ArcCW.AttachmentTable[k.Installed]
|
||||
|
||||
local addsights = self:GetBuff_Stat("AdditionalSights", i)
|
||||
if !addsights then continue end
|
||||
|
||||
if !k.KeepBaseIrons and !atttbl.KeepBaseIrons then kbi = false end
|
||||
if !k.BaseIronsFirst and !atttbl.BaseIronsFirst then bif = false end
|
||||
|
||||
for _, s in pairs(addsights) do
|
||||
local stab = table.Copy(s)
|
||||
|
||||
stab.Slot = i
|
||||
|
||||
if stab.HolosightData then atttbl = stab.HolosightData end
|
||||
|
||||
stab.HolosightData = atttbl
|
||||
|
||||
if atttbl.HolosightMagnification then
|
||||
stab.MagnifiedOptic = true
|
||||
stab.ScopeMagnification = atttbl.HolosightMagnification or 1
|
||||
|
||||
if atttbl.HolosightMagnificationMin then
|
||||
stab.ScopeMagnificationMin = atttbl.HolosightMagnificationMin
|
||||
stab.ScopeMagnificationMax = atttbl.HolosightMagnificationMax
|
||||
|
||||
stab.ScopeMagnification = math.max(stab.ScopeMagnificationMax, stab.ScopeMagnificationMin)
|
||||
|
||||
if !i and self.SightMagnifications[0] then
|
||||
stab.ScopeMagnification = self.SightMagnifications[0]
|
||||
elseif self.SightMagnifications[i] then
|
||||
stab.ScopeMagnification = self.SightMagnifications[i]
|
||||
end
|
||||
else
|
||||
stab.ScopeMagnification = atttbl.HolosightMagnification
|
||||
end
|
||||
end
|
||||
|
||||
if atttbl.Holosight then
|
||||
stab.Holosight = true
|
||||
end
|
||||
|
||||
if !k.Bone then return end
|
||||
|
||||
local boneid = vm:LookupBone(k.Bone)
|
||||
|
||||
if !boneid then return end
|
||||
|
||||
if CLIENT then
|
||||
|
||||
if atttbl.HolosightPiece then
|
||||
stab.HolosightPiece = (k.HSPElement or {}).Model
|
||||
end
|
||||
|
||||
if atttbl.Holosight then
|
||||
stab.HolosightModel = (k.VElement or {}).Model
|
||||
end
|
||||
|
||||
local bpos, bang = self:GetFromReference(boneid)
|
||||
|
||||
local offset
|
||||
local offset_ang
|
||||
|
||||
local vmang = Angle()
|
||||
|
||||
offset = k.Offset.vpos or Vector(0, 0, 0)
|
||||
|
||||
local attslot = k
|
||||
|
||||
local delta = attslot.SlidePos or 0.5
|
||||
|
||||
local vmelemod = nil
|
||||
local slidemod = nil
|
||||
|
||||
for _, e in pairs(self:GetActiveElements()) do
|
||||
local ele = self.AttachmentElements[e]
|
||||
|
||||
if !ele then continue end
|
||||
|
||||
if ((ele.AttPosMods or {})[i] or {}).vpos then
|
||||
vmelemod = ele.AttPosMods[i].vpos
|
||||
end
|
||||
|
||||
if ((ele.AttPosMods or {})[i] or {}).slide then
|
||||
slidemod = ele.AttPosMods[i].slide
|
||||
end
|
||||
|
||||
-- Refer to sh_model Line 837
|
||||
if ((ele.AttPosMods or {})[i] or {}).SlideAmount then
|
||||
slidemod = ele.AttPosMods[i].SlideAmount
|
||||
end
|
||||
end
|
||||
|
||||
offset = vmelemod or attslot.Offset.vpos or Vector()
|
||||
|
||||
if slidemod or attslot.SlideAmount then
|
||||
offset = LerpVector(delta, (slidemod or attslot.SlideAmount).vmin, (slidemod or attslot.SlideAmount).vmax)
|
||||
end
|
||||
|
||||
offset_ang = k.Offset.vang or Angle(0, 0, 0)
|
||||
offset_ang = offset_ang + (atttbl.OffsetAng or Angle(0, 0, 0))
|
||||
|
||||
offset_ang = k.VMOffsetAng or offset_ang
|
||||
|
||||
bpos, bang = WorldToLocal(Vector(0, 0, 0), Angle(0, 0, 0), bpos, bang)
|
||||
|
||||
bpos = bpos + bang:Forward() * offset.x
|
||||
bpos = bpos + bang:Right() * offset.y
|
||||
bpos = bpos + bang:Up() * offset.z
|
||||
|
||||
bang:RotateAroundAxis(bang:Right(), offset_ang.p)
|
||||
bang:RotateAroundAxis(bang:Up(), -offset_ang.y)
|
||||
bang:RotateAroundAxis(bang:Forward(), offset_ang.r)
|
||||
|
||||
local vpos = Vector()
|
||||
|
||||
vpos.y = -bpos.x
|
||||
vpos.x = bpos.y
|
||||
vpos.z = -bpos.z
|
||||
|
||||
local corpos = (k.CorrectivePos or Vector(0, 0, 0))
|
||||
|
||||
vpos = vpos + bang:Forward() * corpos.x
|
||||
vpos = vpos + bang:Right() * corpos.y
|
||||
vpos = vpos + bang:Up() * corpos.z
|
||||
|
||||
-- vpos = vpos + (bang:Forward() * s.Pos.x)
|
||||
-- vpos = vpos - (bang:Right() * s.Pos.y)
|
||||
-- vpos = vpos + (bang:Up() * s.Pos.z)
|
||||
|
||||
vmang:Set(-bang)
|
||||
|
||||
bang.r = -bang.r
|
||||
bang.p = -bang.p
|
||||
bang.y = -bang.y
|
||||
|
||||
corang = k.CorrectiveAng or Angle(0, 0, 0)
|
||||
|
||||
bang:RotateAroundAxis(bang:Right(), corang.p)
|
||||
bang:RotateAroundAxis(bang:Up(), corang.y)
|
||||
bang:RotateAroundAxis(bang:Forward(), corang.r)
|
||||
|
||||
-- vpos = LocalToWorld(s.Pos + Vector(0, self.ExtraSightDist or 0, 0), Angle(0, 0, 0), vpos, bang)
|
||||
|
||||
-- local vmf = (vmang):Forward():GetNormalized()
|
||||
-- local vmr = (vmang):Right():GetNormalized()
|
||||
-- local vmu = (vmang):Up():GetNormalized()
|
||||
|
||||
-- print(" ----- vmf, vmr, vmu")
|
||||
-- print(vmf)
|
||||
-- print(vmr)
|
||||
-- print(vmu)
|
||||
|
||||
-- vmf = -vmf
|
||||
-- vmf.x = -vmf.x
|
||||
|
||||
-- local r = vmf.y
|
||||
-- vmf.y = vmf.z
|
||||
-- vmf.z = r
|
||||
|
||||
-- vmr = -vmr
|
||||
-- vmr.y = -vmr.y
|
||||
|
||||
-- -- local r = vmr.y
|
||||
-- -- vmr.y = vmr.z
|
||||
-- -- vmr.z = r
|
||||
|
||||
-- vmu = -vmu
|
||||
-- vmu.z = vmu.z
|
||||
|
||||
-- local evpos = Vector(0, 0, 0)
|
||||
|
||||
-- evpos = evpos + (vmf * (s.Pos.x + k.CorrectivePos.x))
|
||||
-- evpos = evpos - (vmr * (s.Pos.y + (self.ExtraSightDist or 0) + k.CorrectivePos.y))
|
||||
-- evpos = evpos + (vmu * (s.Pos.z + k.CorrectivePos.z))
|
||||
|
||||
-- print(vmang:Forward())
|
||||
|
||||
local evpos = s.Pos
|
||||
|
||||
evpos = evpos * (k.VMScale or Vector(1, 1, 1))
|
||||
|
||||
if atttbl.Holosight and !atttbl.HolosightMagnification then
|
||||
evpos = evpos + Vector(0, k.ExtraSightDist or self.ExtraSightDist or 0, 0)
|
||||
end
|
||||
|
||||
evpos = evpos + (k.CorrectivePos or Vector(0, 0, 0))
|
||||
|
||||
stab.Pos, stab.Ang = vpos, bang
|
||||
|
||||
stab.EVPos = evpos
|
||||
stab.EVAng = s.Ang
|
||||
|
||||
if s.GlobalPos then
|
||||
stab.EVPos = Vector(0, 0, 0)
|
||||
stab.Pos = s.Pos
|
||||
end
|
||||
|
||||
if s.GlobalAng then
|
||||
stab.Ang = Angle(0, 0, 0)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
table.insert(sighttable, stab)
|
||||
end
|
||||
end
|
||||
|
||||
if kbi then
|
||||
local extra = self.ExtraIrons
|
||||
if extra then
|
||||
for _, ot in pairs(extra) do
|
||||
local t = table.Copy(ot)
|
||||
t.IronSight = true
|
||||
if bif then
|
||||
table.insert(sighttable, 1, t)
|
||||
else
|
||||
table.insert(sighttable, t)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local t = table.Copy(self:GetBuff_Override("Override_IronSightStruct") or self.IronSightStruct)
|
||||
t.IronSight = true
|
||||
if bif then
|
||||
table.insert(sighttable, 1, t)
|
||||
else
|
||||
table.insert(sighttable, t)
|
||||
end
|
||||
end
|
||||
|
||||
self.SightTable = sighttable
|
||||
end
|
||||
|
||||
function SWEP:SwitchActiveSights()
|
||||
if table.Count(self.SightTable) == 1 then return end
|
||||
|
||||
self.ActiveSight = (self.ActiveSight or 1) + 1
|
||||
|
||||
if self.ActiveSight > table.Count(self.SightTable) then
|
||||
self.ActiveSight = 1
|
||||
end
|
||||
|
||||
local asight = self:GetActiveSights()
|
||||
|
||||
local tbl = self:GetBuff_Hook("Hook_SwitchActiveSights", {active = self.ActiveSight, asight = asight})
|
||||
|
||||
self.ActiveSight = tbl.active or self.ActiveSight
|
||||
|
||||
if self.ActiveSight > table.Count(self.SightTable) then
|
||||
self.ActiveSight = 1
|
||||
end
|
||||
|
||||
local asight2 = self:GetActiveSights()
|
||||
|
||||
if asight2.SwitchToSound then
|
||||
self:MyEmitSound(asight2.SwitchToSound, 75, math.Rand(95, 105), 0.5, CHAN_VOICE2)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetActiveSights()
|
||||
if (self.ActiveSight or 1) > table.Count(self.SightTable) then
|
||||
self.ActiveSight = 1
|
||||
end
|
||||
|
||||
if table.Count(self.SightTable) == 0 then
|
||||
return self.IronSightStruct
|
||||
else
|
||||
return self.SightTable[self.ActiveSight or 1]
|
||||
end
|
||||
end
|
||||
|
||||
local function ScaleFOVByWidthRatio( fovDegrees, ratio )
|
||||
local halfAngleRadians = fovDegrees * ( 0.5 * math.pi / 180 )
|
||||
local t = math.tan( halfAngleRadians )
|
||||
t = t * ratio
|
||||
local retDegrees = ( 180 / math.pi ) * math.atan( t )
|
||||
return retDegrees * 2
|
||||
end
|
||||
|
||||
function SWEP:QuickFOVix( fov )
|
||||
return ScaleFOVByWidthRatio( fov, (ScrW and ScrW() or 4)/(ScrH and ScrH() or 3)/(4/3) )
|
||||
end
|
||||
|
||||
SWEP.LastTranslateFOV = 0
|
||||
function SWEP:TranslateFOV(fov)
|
||||
local irons = self:GetActiveSights()
|
||||
|
||||
if CLIENT and ArcCW.ConVars["dev_benchgun"]:GetBool() then self.CurrentFOV = fov self.CurrentViewModelFOV = fov return fov end
|
||||
|
||||
self.ApproachFOV = self.ApproachFOV or fov
|
||||
self.CurrentFOV = self.CurrentFOV or fov
|
||||
|
||||
-- Only update every tick (this function is called multiple times per tick)
|
||||
if self.LastTranslateFOV == UnPredictedCurTime() then return self.CurrentFOV end
|
||||
local timed = UnPredictedCurTime() - self.LastTranslateFOV
|
||||
self.LastTranslateFOV = UnPredictedCurTime()
|
||||
|
||||
local app_vm = self.ViewModelFOV + self:GetOwner():GetInfoNum("arccw_vm_fov", 0)
|
||||
if CLIENT then
|
||||
app_vm = app_vm * (LocalPlayer():GetFOV()/GetConVar("fov_desired"):GetInt())
|
||||
end
|
||||
|
||||
if self:GetState() == ArcCW.STATE_SIGHTS then
|
||||
local asight = self:GetActiveSights()
|
||||
local mag = asight and asight.ScopeMagnification or 1
|
||||
|
||||
local delta = math.pow(self:GetSightDelta(), 2)
|
||||
|
||||
if CLIENT then
|
||||
local addads = math.Clamp(ArcCW.ConVars["vm_add_ads"]:GetFloat() or 0, -2, 14)
|
||||
local csratio = math.Clamp(GetConVar("arccw_cheapscopesv2_ratio"):GetFloat() or 0, 0, 1)
|
||||
local pfov = GetConVar("fov_desired"):GetInt()
|
||||
|
||||
if ArcCW.ConVars["cheapscopes"]:GetBool() and mag > 1 then
|
||||
fov = (pfov / (asight and asight.Magnification or 1)) / (mag / (1 + csratio * mag) + (addads or 0) / 3)
|
||||
else
|
||||
fov = ( (pfov / (asight and asight.Magnification or 1)) * (1 - delta)) + (GetConVar("fov_desired"):GetInt() * delta)
|
||||
end
|
||||
|
||||
app_vm = irons.ViewModelFOV or 45
|
||||
|
||||
app_vm = app_vm - (asight.MagnifiedOptic and (addads or 0) * 3 or 0)
|
||||
end
|
||||
end
|
||||
|
||||
self.ApproachFOV = fov
|
||||
|
||||
-- magic number? multiplier of 10 seems similar to previous behavior
|
||||
self.CurrentFOV = math.Approach(self.CurrentFOV, self.ApproachFOV, timed * 10 * (self.CurrentFOV - self.ApproachFOV))
|
||||
|
||||
self.CurrentViewModelFOV = self.CurrentViewModelFOV or self.ViewModelFOV
|
||||
self.CurrentViewModelFOV = math.Approach(self.CurrentViewModelFOV, app_vm, timed * 10 * (self.CurrentViewModelFOV - app_vm))
|
||||
|
||||
return self.CurrentFOV
|
||||
end
|
||||
|
||||
function SWEP:SetShouldHoldType()
|
||||
if self:GetCurrentFiremode().Mode == 0 then
|
||||
self:SetHoldType(self.HoldtypeHolstered)
|
||||
return
|
||||
end
|
||||
|
||||
if IsValid(self:GetOwner()) and self:GetOwner():IsNPC() and self.HoldtypeNPC then
|
||||
self:SetHoldType(self.HoldtypeNPC)
|
||||
return
|
||||
end
|
||||
|
||||
local ht = "normal"
|
||||
|
||||
if self:GetState() == ArcCW.STATE_SIGHTS then
|
||||
ht = self:GetBuff_Override("Override_HoldtypeSights", self.HoldtypeSights)
|
||||
elseif self:GetState() == ArcCW.STATE_SPRINT then
|
||||
if self:CanShootWhileSprint() then
|
||||
ht = self:GetBuff_Override("Override_HoldtypeSprintShoot", self.HoldtypeSprintShoot) or self:GetBuff_Override("Override_HoldtypeActive", self.HoldtypeActive)
|
||||
else
|
||||
ht = self:GetBuff_Override("Override_HoldtypeHolstered", self.HoldtypeHolstered)
|
||||
end
|
||||
elseif self:GetState() == ArcCW.STATE_CUSTOMIZE then
|
||||
ht = self:GetBuff_Override("Override_HoldtypeCustomize", self.HoldtypeCustomize)
|
||||
elseif self:GetCurrentFiremode().Mode == 0 then
|
||||
ht = self:GetBuff_Override("Override_HoldtypeHolstered", self.HoldtypeHolstered)
|
||||
elseif self.Throwing and self:GetGrenadePrimed() then
|
||||
ht = self:GetBuff_Override("Override_HoldtypeSights", self.HoldtypeSights)
|
||||
else
|
||||
ht = self:GetBuff_Override("Override_HoldtypeActive", self.HoldtypeActive)
|
||||
end
|
||||
|
||||
self:SetHoldType(ht)
|
||||
end
|
||||
445
lua/weapons/arccw_base/sh_think.lua
Normal file
445
lua/weapons/arccw_base/sh_think.lua
Normal file
@@ -0,0 +1,445 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
if CLIENT then
|
||||
ArcCW.LastWeapon = nil
|
||||
end
|
||||
|
||||
local vec1 = Vector(1, 1, 1)
|
||||
local vec0 = vec1 * 0
|
||||
local ang0 = Angle(0, 0, 0)
|
||||
|
||||
local lastUBGL = 0
|
||||
function SWEP:Think()
|
||||
if IsValid(self:GetOwner()) and self:GetClass() == "arccw_base" then
|
||||
self:Remove()
|
||||
return
|
||||
end
|
||||
|
||||
local owner = self:GetOwner()
|
||||
|
||||
if !IsValid(owner) or owner:IsNPC() then return end
|
||||
|
||||
if self:GetState() == ArcCW.STATE_DISABLE and !self:GetPriorityAnim() then
|
||||
self:SetState(ArcCW.STATE_IDLE)
|
||||
|
||||
if CLIENT and self.UnReady then
|
||||
self.UnReady = false
|
||||
end
|
||||
end
|
||||
|
||||
for i, v in ipairs(self.EventTable) do
|
||||
for ed, bz in pairs(v) do
|
||||
if ed <= CurTime() then
|
||||
if bz.AnimKey and (bz.AnimKey != self.LastAnimKey or bz.StartTime != self.LastAnimStartTime) then
|
||||
continue
|
||||
end
|
||||
self:PlayEvent(bz)
|
||||
self.EventTable[i][ed] = nil
|
||||
--print(CurTime(), "Event completed at " .. i, ed)
|
||||
if table.IsEmpty(v) and i != 1 then self.EventTable[i] = nil --[[print(CurTime(), "No more events at " .. i .. ", killing")]] end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if CLIENT and (!game.SinglePlayer() and IsFirstTimePredicted() or true)
|
||||
and self:GetOwner() == LocalPlayer() and ArcCW.InvHUD
|
||||
and !ArcCW.Inv_Hidden and ArcCW.Inv_Fade == 0 then
|
||||
ArcCW.InvHUD:Remove()
|
||||
ArcCW.Inv_Fade = 0.01
|
||||
end
|
||||
|
||||
local vm = owner:GetViewModel()
|
||||
|
||||
self.BurstCount = self:GetBurstCount()
|
||||
|
||||
local sg = self:GetShotgunReloading()
|
||||
if (sg == 2 or sg == 4) and owner:KeyPressed(IN_ATTACK) then
|
||||
self:SetShotgunReloading(sg + 1)
|
||||
elseif (sg >= 2) and self:GetReloadingREAL() <= CurTime() then
|
||||
self:ReloadInsert((sg >= 4) and true or false)
|
||||
end
|
||||
|
||||
self:InBipod()
|
||||
|
||||
if self:GetNeedCycle() and !self.Throwing and !self:GetReloading() and self:GetWeaponOpDelay() < CurTime() and self:GetNextPrimaryFire() < CurTime() and -- Adding this delays bolting if the RPM is too low, but removing it may reintroduce the double pump bug. Increasing the RPM allows you to shoot twice on many multiplayer servers. Sure would be convenient if everything just worked nicely
|
||||
(!ArcCW.ConVars["clicktocycle"]:GetBool() and (self:GetCurrentFiremode().Mode == 2 or !owner:KeyDown(IN_ATTACK))
|
||||
or ArcCW.ConVars["clicktocycle"]:GetBool() and (self:GetCurrentFiremode().Mode == 2 or owner:KeyPressed(IN_ATTACK))) then
|
||||
local anim = self:SelectAnimation("cycle")
|
||||
anim = self:GetBuff_Hook("Hook_SelectCycleAnimation", anim) or anim
|
||||
local mult = self:GetBuff_Mult("Mult_CycleTime")
|
||||
local p = self:PlayAnimation(anim, mult, true, 0, true)
|
||||
if p then
|
||||
self:SetNeedCycle(false)
|
||||
self:SetPriorityAnim(CurTime() + self:GetAnimKeyTime(anim, true) * mult)
|
||||
end
|
||||
end
|
||||
|
||||
if self:GetGrenadePrimed() and !(owner:KeyDown(IN_ATTACK) or owner:KeyDown(IN_ATTACK2)) and (!game.SinglePlayer() or SERVER) then
|
||||
self:Throw()
|
||||
end
|
||||
|
||||
if self:GetGrenadePrimed() and self.GrenadePrimeTime > 0 and self.isCooked then
|
||||
local heldtime = (CurTime() - self.GrenadePrimeTime)
|
||||
|
||||
local ft = self:GetBuff_Override("Override_FuseTime") or self.FuseTime
|
||||
|
||||
if ft and (heldtime >= ft) and (!game.SinglePlayer() or SERVER) then
|
||||
self:Throw()
|
||||
end
|
||||
end
|
||||
|
||||
if IsFirstTimePredicted() and self:GetNextPrimaryFire() < CurTime() and owner:KeyReleased(IN_USE) then
|
||||
if self:InBipod() then
|
||||
self:ExitBipod()
|
||||
else
|
||||
self:EnterBipod()
|
||||
end
|
||||
end
|
||||
|
||||
if ((game.SinglePlayer() and SERVER) or (!game.SinglePlayer() and true)) and self:GetBuff_Override("Override_TriggerDelay", self.TriggerDelay) then
|
||||
if owner:KeyReleased(IN_ATTACK) and self:GetBuff_Override("Override_TriggerCharge", self.TriggerCharge) and self:GetTriggerDelta(true) >= 1 then
|
||||
self:PrimaryAttack()
|
||||
else
|
||||
self:DoTriggerDelay()
|
||||
end
|
||||
end
|
||||
|
||||
if self:GetCurrentFiremode().RunawayBurst then
|
||||
|
||||
if self:GetBurstCount() > 0 and ((game.SinglePlayer() and SERVER) or (!game.SinglePlayer() and true)) then
|
||||
self:PrimaryAttack()
|
||||
end
|
||||
|
||||
if self:Clip1() < self:GetBuff("AmmoPerShot") or self:GetBurstCount() == self:GetBurstLength() then
|
||||
self:SetBurstCount(0)
|
||||
if !self:GetCurrentFiremode().AutoBurst then
|
||||
self.Primary.Automatic = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if owner:KeyReleased(IN_ATTACK) then
|
||||
|
||||
if !self:GetCurrentFiremode().RunawayBurst then
|
||||
self:SetBurstCount(0)
|
||||
self.LastTriggerTime = -1 -- Cannot fire again until trigger released
|
||||
self.LastTriggerDuration = 0
|
||||
end
|
||||
|
||||
if self:GetCurrentFiremode().Mode < 0 and !self:GetCurrentFiremode().RunawayBurst then
|
||||
local postburst = self:GetCurrentFiremode().PostBurstDelay or 0
|
||||
|
||||
if (CurTime() + postburst) > self:GetWeaponOpDelay() then
|
||||
--self:SetNextPrimaryFire(CurTime() + postburst)
|
||||
self:SetWeaponOpDelay(CurTime() + postburst * self:GetBuff_Mult("Mult_PostBurstDelay") + self:GetBuff_Add("Add_PostBurstDelay"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if owner and owner:GetInfoNum("arccw_automaticreload", 0) == 1 and self:Clip1() == 0 and !self:GetReloading() and CurTime() > self:GetNextPrimaryFire() + 0.2 then
|
||||
self:Reload()
|
||||
end
|
||||
|
||||
if (!(self:GetBuff_Override("Override_ReloadInSights") or self.ReloadInSights) and (self:GetReloading() or owner:KeyDown(IN_RELOAD))) then
|
||||
if !(self:GetBuff_Override("Override_ReloadInSights") or self.ReloadInSights) and self:GetReloading() then
|
||||
self:ExitSights()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if self:GetBuff_Hook("Hook_ShouldNotSight") and (self.Sighted or self:GetState() == ArcCW.STATE_SIGHTS) then
|
||||
self:ExitSights()
|
||||
elseif self:GetHolster_Time() > 0 then
|
||||
self:ExitSights()
|
||||
else
|
||||
|
||||
-- no it really doesn't, past me
|
||||
local sighted = self:GetState() == ArcCW.STATE_SIGHTS
|
||||
local toggle = owner:GetInfoNum("arccw_toggleads", 0) >= 1
|
||||
local suitzoom = owner:KeyDown(IN_ZOOM)
|
||||
local sp_cl = game.SinglePlayer() and CLIENT
|
||||
|
||||
-- if in singleplayer, client realm should be completely ignored
|
||||
if toggle and !sp_cl then
|
||||
if owner:KeyPressed(IN_ATTACK2) then
|
||||
if sighted then
|
||||
self:ExitSights()
|
||||
elseif !suitzoom then
|
||||
self:EnterSights()
|
||||
end
|
||||
elseif suitzoom and sighted then
|
||||
self:ExitSights()
|
||||
end
|
||||
elseif !toggle then
|
||||
if (owner:KeyDown(IN_ATTACK2) and !suitzoom) and !sighted then
|
||||
self:EnterSights()
|
||||
elseif (!owner:KeyDown(IN_ATTACK2) or suitzoom) and sighted then
|
||||
self:ExitSights()
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if (!game.SinglePlayer() and IsFirstTimePredicted()) or (game.SinglePlayer() and true) then
|
||||
if self:InSprint() and (self:GetState() != ArcCW.STATE_SPRINT) then
|
||||
self:EnterSprint()
|
||||
elseif !self:InSprint() and (self:GetState() == ArcCW.STATE_SPRINT) then
|
||||
self:ExitSprint()
|
||||
end
|
||||
end
|
||||
|
||||
if game.SinglePlayer() or IsFirstTimePredicted() then
|
||||
self:SetSightDelta(math.Approach(self:GetSightDelta(), self:GetState() == ArcCW.STATE_SIGHTS and 0 or 1, FrameTime() / self:GetSightTime()))
|
||||
self:SetSprintDelta(math.Approach(self:GetSprintDelta(), self:GetState() == ArcCW.STATE_SPRINT and 1 or 0, FrameTime() / self:GetSprintTime()))
|
||||
end
|
||||
|
||||
if CLIENT and (game.SinglePlayer() or IsFirstTimePredicted()) then
|
||||
self:ProcessRecoil()
|
||||
end
|
||||
|
||||
if CLIENT and IsValid(vm) then
|
||||
|
||||
for i = 1, vm:GetBoneCount() do
|
||||
vm:ManipulateBoneScale(i, vec1)
|
||||
end
|
||||
|
||||
for i, k in pairs(self:GetBuff_Override("Override_CaseBones", self.CaseBones) or {}) do
|
||||
if !isnumber(i) then continue end
|
||||
for _, b in pairs(istable(k) and k or {k}) do
|
||||
local bone = vm:LookupBone(b)
|
||||
|
||||
if !bone then continue end
|
||||
|
||||
if self:GetVisualClip() >= i then
|
||||
vm:ManipulateBoneScale(bone, vec1)
|
||||
else
|
||||
vm:ManipulateBoneScale(bone, vec0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for i, k in pairs(self:GetBuff_Override("Override_BulletBones", self.BulletBones) or {}) do
|
||||
if !isnumber(i) then continue end
|
||||
for _, b in pairs(istable(k) and k or {k}) do
|
||||
local bone = vm:LookupBone(b)
|
||||
|
||||
if !bone then continue end
|
||||
|
||||
if self:GetVisualBullets() >= i then
|
||||
vm:ManipulateBoneScale(bone, vec1)
|
||||
else
|
||||
vm:ManipulateBoneScale(bone, vec0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for i, k in pairs(self:GetBuff_Override("Override_StripperClipBones", self.StripperClipBones) or {}) do
|
||||
if !isnumber(i) then continue end
|
||||
for _, b in pairs(istable(k) and k or {k}) do
|
||||
local bone = vm:LookupBone(b)
|
||||
|
||||
if !bone then continue end
|
||||
|
||||
if self:GetVisualLoadAmount() >= i then
|
||||
vm:ManipulateBoneScale(bone, vec1)
|
||||
else
|
||||
vm:ManipulateBoneScale(bone, vec0)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:DoHeat()
|
||||
|
||||
self:ThinkFreeAim()
|
||||
|
||||
-- if CLIENT then
|
||||
-- if !IsValid(ArcCW.InvHUD) then
|
||||
-- gui.EnableScreenClicker(false)
|
||||
-- end
|
||||
|
||||
-- if self:GetState() != ArcCW.STATE_CUSTOMIZE then
|
||||
-- self:CloseCustomizeHUD()
|
||||
-- else
|
||||
-- self:OpenCustomizeHUD()
|
||||
-- end
|
||||
-- end
|
||||
|
||||
for i, k in pairs(self.Attachments) do
|
||||
if !k.Installed then continue end
|
||||
local atttbl = ArcCW.AttachmentTable[k.Installed]
|
||||
|
||||
if atttbl.DamagePerSecond then
|
||||
local dmg = atttbl.DamagePerSecond * FrameTime()
|
||||
|
||||
self:DamageAttachment(i, dmg)
|
||||
end
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
self:DoOurViewPunch()
|
||||
end
|
||||
|
||||
if self.Throwing and self:Clip1() == 0 and self:Ammo1() > 0 then
|
||||
self:SetClip1(1)
|
||||
owner:SetAmmo(self:Ammo1() - 1, self.Primary.Ammo)
|
||||
end
|
||||
|
||||
-- self:RefreshBGs()
|
||||
|
||||
if self:GetMagUpIn() != 0 and CurTime() > self:GetMagUpIn() then
|
||||
self:ReloadTimed()
|
||||
self:SetMagUpIn( 0 )
|
||||
end
|
||||
|
||||
if self:HasBottomlessClip() and self:Clip1() != ArcCW.BottomlessMagicNumber then
|
||||
self:Unload()
|
||||
self:SetClip1(ArcCW.BottomlessMagicNumber)
|
||||
elseif !self:HasBottomlessClip() and self:Clip1() == ArcCW.BottomlessMagicNumber then
|
||||
self:SetClip1(0)
|
||||
end
|
||||
|
||||
-- Performing traces in rendering contexts seem to cause flickering with c_hands that have QC attachments(?)
|
||||
-- Since we need to run the trace every tick anyways, do it here instead
|
||||
if CLIENT then
|
||||
self:BarrelHitWall()
|
||||
end
|
||||
|
||||
self:GetBuff_Hook("Hook_Think")
|
||||
|
||||
-- Running this only serverside in SP breaks animation processing and causes CheckpointAnimation to !reset.
|
||||
--if SERVER or !game.SinglePlayer() then
|
||||
self:ProcessTimers()
|
||||
--end
|
||||
|
||||
-- Only reset to idle if we don't need cycle. empty idle animation usually doesn't play nice
|
||||
if self:GetNextIdle() != 0 and self:GetNextIdle() <= CurTime() and !self:GetNeedCycle()
|
||||
and self:GetHolster_Time() == 0 and self:GetShotgunReloading() == 0 then
|
||||
self:SetNextIdle(0)
|
||||
self:PlayIdleAnimation(true)
|
||||
end
|
||||
|
||||
if self:GetUBGLDebounce() and !self:GetOwner():KeyDown(IN_RELOAD) then
|
||||
self:SetUBGLDebounce( false )
|
||||
end
|
||||
end
|
||||
|
||||
local lst = SysTime()
|
||||
|
||||
function SWEP:ProcessRecoil()
|
||||
local owner = self:GetOwner()
|
||||
local ft = (SysTime() - (lst or SysTime())) * GetConVar("host_timescale"):GetFloat()
|
||||
local newang = owner:EyeAngles()
|
||||
-- local r = self.RecoilAmount -- self:GetNWFloat("recoil", 0)
|
||||
-- local rs = self.RecoilAmountSide -- self:GetNWFloat("recoilside", 0)
|
||||
|
||||
local ra = Angle(ang0)
|
||||
|
||||
ra = ra + (self:GetBuff_Override("Override_RecoilDirection", self.RecoilDirection) * self.RecoilAmount * 0.5)
|
||||
ra = ra + (self:GetBuff_Override("Override_RecoilDirectionSide", self.RecoilDirectionSide) * self.RecoilAmountSide * 0.5)
|
||||
|
||||
newang = newang - ra
|
||||
|
||||
local rpb = self.RecoilPunchBack
|
||||
local rps = self.RecoilPunchSide
|
||||
local rpu = self.RecoilPunchUp
|
||||
|
||||
if rpb != 0 then
|
||||
self.RecoilPunchBack = math.Approach(rpb, 0, ft * rpb * 10)
|
||||
end
|
||||
|
||||
if rps != 0 then
|
||||
self.RecoilPunchSide = math.Approach(rps, 0, ft * rps * 5)
|
||||
end
|
||||
|
||||
if rpu != 0 then
|
||||
self.RecoilPunchUp = math.Approach(rpu, 0, ft * rpu * 5)
|
||||
end
|
||||
|
||||
lst = SysTime()
|
||||
end
|
||||
|
||||
function SWEP:InSprint()
|
||||
local owner = self:GetOwner()
|
||||
|
||||
local sm = self.SpeedMult * self:GetBuff_Mult("Mult_SpeedMult") * self:GetBuff_Mult("Mult_MoveSpeed")
|
||||
|
||||
sm = math.Clamp(sm, 0, 1)
|
||||
|
||||
local sprintspeed = owner:GetRunSpeed() * sm
|
||||
local walkspeed = owner:GetWalkSpeed() * sm
|
||||
|
||||
local curspeed = owner:GetVelocity():Length()
|
||||
|
||||
if TTT2 and owner.isSprinting == true then
|
||||
return (owner.sprintProgress or 0) > 0 and owner:KeyDown(IN_SPEED) and !owner:Crouching() and curspeed > walkspeed and owner:OnGround()
|
||||
end
|
||||
|
||||
if !owner:KeyDown(IN_SPEED) or !owner:KeyDown(IN_FORWARD+IN_MOVELEFT+IN_MOVERIGHT+IN_BACK) then return false end
|
||||
if !owner:OnGround() then return false end
|
||||
if owner:Crouching() then return false end
|
||||
if curspeed < Lerp(0.5, walkspeed, sprintspeed) then
|
||||
-- provide some grace time so changing directions won't immediately exit sprint
|
||||
self.LastExitSprintCheck = self.LastExitSprintCheck or CurTime()
|
||||
if self.LastExitSprintCheck < CurTime() - 0.25 then
|
||||
return false
|
||||
end
|
||||
else
|
||||
self.LastExitSprintCheck = nil
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:IsTriggerHeld()
|
||||
return self:GetOwner():KeyDown(IN_ATTACK) and (self:CanShootWhileSprint() or (!self.Sprinted or self:GetState() != ArcCW.STATE_SPRINT)) and (self:GetHolster_Time() < CurTime()) and !self:GetPriorityAnim()
|
||||
end
|
||||
|
||||
SWEP.LastTriggerTime = 0
|
||||
SWEP.LastTriggerDuration = 0
|
||||
function SWEP:GetTriggerDelta(noheldcheck)
|
||||
if self.LastTriggerTime <= 0 or (!noheldcheck and !self:IsTriggerHeld()) then return 0 end
|
||||
return math.Clamp((CurTime() - self.LastTriggerTime) / self.LastTriggerDuration, 0, 1)
|
||||
end
|
||||
|
||||
function SWEP:DoTriggerDelay()
|
||||
local shouldHold = self:IsTriggerHeld()
|
||||
|
||||
local reserve = self:HasBottomlessClip() and self:Ammo1() or self:Clip1()
|
||||
if self.LastTriggerTime == -1 or (!self.TriggerPullWhenEmpty and (reserve < self:GetBuff("AmmoPerShot"))) and self:GetNextPrimaryFire() < CurTime() then
|
||||
if !shouldHold then
|
||||
self.LastTriggerTime = 0 -- Good to fire again
|
||||
self.LastTriggerDuration = 0
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if self:GetBurstCount() > 0 and self:GetCurrentFiremode().Mode == 1 then
|
||||
self.LastTriggerTime = -1 -- Cannot fire again until trigger released
|
||||
self.LastTriggerDuration = 0
|
||||
elseif self:GetNextPrimaryFire() < CurTime() and self.LastTriggerTime > 0 and !shouldHold then
|
||||
-- Attack key is released. Stop the animation and clear progress
|
||||
local anim = self:SelectAnimation("untrigger")
|
||||
if anim then
|
||||
self:PlayAnimation(anim, self:GetBuff_Mult("Mult_TriggerDelayTime"), true, 0)
|
||||
end
|
||||
self.LastTriggerTime = 0
|
||||
self.LastTriggerDuration = 0
|
||||
self:GetBuff_Hook("Hook_OnTriggerRelease")
|
||||
elseif self:GetNextPrimaryFire() < CurTime() and self.LastTriggerTime == 0 and shouldHold then
|
||||
-- We haven't played the animation yet. Pull it!
|
||||
local anim = self:SelectAnimation("trigger")
|
||||
self:PlayAnimation(anim, self:GetBuff_Mult("Mult_TriggerDelayTime"), true, 0, nil, nil, true) -- need to overwrite sprint up
|
||||
self.LastTriggerTime = CurTime()
|
||||
self.LastTriggerDuration = self:GetAnimKeyTime(anim, true) * self:GetBuff_Mult("Mult_TriggerDelayTime")
|
||||
self:GetBuff_Hook("Hook_OnTriggerHeld")
|
||||
end
|
||||
end
|
||||
178
lua/weapons/arccw_base/sh_timers.lua
Normal file
178
lua/weapons/arccw_base/sh_timers.lua
Normal file
@@ -0,0 +1,178 @@
|
||||
--[[
|
||||
| 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 tbl = table
|
||||
local tbl_ins = tbl.insert
|
||||
|
||||
local tick = 0
|
||||
|
||||
function SWEP:InitTimers()
|
||||
self.ActiveTimers = {} -- { { time, id, func } }
|
||||
end
|
||||
|
||||
function SWEP:SetTimer(time, callback, id)
|
||||
if !IsFirstTimePredicted() then return end
|
||||
|
||||
tbl_ins(self.ActiveTimers, { time + CurTime(), id or "", callback })
|
||||
end
|
||||
|
||||
function SWEP:TimerExists(id)
|
||||
for _, v in pairs(self.ActiveTimers) do
|
||||
if v[2] == id then return true end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:KillTimer(id)
|
||||
local keeptimers = {}
|
||||
|
||||
for _, v in pairs(self.ActiveTimers) do
|
||||
if v[2] != id then tbl_ins(keeptimers, v) end
|
||||
end
|
||||
|
||||
self.ActiveTimers = keeptimers
|
||||
end
|
||||
|
||||
function SWEP:KillTimers()
|
||||
self.ActiveTimers = {}
|
||||
end
|
||||
|
||||
function SWEP:ProcessTimers()
|
||||
local keeptimers, UCT = {}, CurTime()
|
||||
|
||||
if CLIENT and UCT == tick then return end
|
||||
|
||||
if !self.ActiveTimers then self:InitTimers() end
|
||||
|
||||
for _, v in pairs(self.ActiveTimers) do
|
||||
if v[1] <= UCT then v[3]() end
|
||||
end
|
||||
|
||||
for _, v in pairs(self.ActiveTimers) do
|
||||
if v[1] > UCT then tbl_ins(keeptimers, v) end
|
||||
end
|
||||
|
||||
self.ActiveTimers = keeptimers
|
||||
end
|
||||
|
||||
local function DoShell(wep, data)
|
||||
if !(IsValid(wep) and IsValid(wep:GetOwner())) then return end
|
||||
|
||||
local att = data.att or wep:GetBuff_Override("Override_CaseEffectAttachment") or wep.CaseEffectAttachment or 2
|
||||
|
||||
if !att then return end
|
||||
|
||||
local getatt = wep:GetAttachment(att)
|
||||
|
||||
if !getatt then return end
|
||||
|
||||
local pos, ang = getatt.Pos, getatt.Ang
|
||||
|
||||
local ed = EffectData()
|
||||
ed:SetOrigin(pos)
|
||||
ed:SetAngles(ang)
|
||||
ed:SetAttachment(att)
|
||||
ed:SetScale(1)
|
||||
ed:SetEntity(wep)
|
||||
ed:SetNormal(ang:Forward())
|
||||
ed:SetMagnitude(data.mag or 100)
|
||||
|
||||
util.Effect(data.e, ed)
|
||||
end
|
||||
|
||||
function SWEP:PlaySoundTable(soundtable, mult, start, key)
|
||||
--if CLIENT and game.SinglePlayer() then return end
|
||||
|
||||
local owner = self:GetOwner()
|
||||
|
||||
start = start or 0
|
||||
mult = 1 / (mult or 1)
|
||||
|
||||
for _, v in pairs(soundtable) do
|
||||
if table.IsEmpty(v) then continue end
|
||||
|
||||
local ttime
|
||||
if v.t then
|
||||
ttime = (v.t * mult) - start
|
||||
else
|
||||
continue
|
||||
end
|
||||
if ttime < 0 then continue end
|
||||
if !(IsValid(self) and IsValid(owner)) then continue end
|
||||
|
||||
local jhon = CurTime() + ttime
|
||||
|
||||
--[[if game.SinglePlayer() then
|
||||
if SERVER then
|
||||
net.Start("arccw_networksound")
|
||||
v.ntttime = ttime
|
||||
net.WriteTable(v)
|
||||
net.WriteEntity(self)
|
||||
net.Send(owner)
|
||||
end
|
||||
end]]
|
||||
|
||||
-- i may go fucking insane
|
||||
if !self.EventTable[1] then self.EventTable[1] = {} end
|
||||
|
||||
for i, de in ipairs(self.EventTable) do
|
||||
if de[jhon] then
|
||||
if !self.EventTable[i + 1] then
|
||||
--[[print(CurTime(), "Occupier at " .. i .. ", creating " .. i+1)]]
|
||||
self.EventTable[i + 1] = {}
|
||||
continue
|
||||
end
|
||||
else
|
||||
self.EventTable[i][jhon] = table.Copy(v)
|
||||
self.EventTable[i][jhon].StartTime = CurTime()
|
||||
self.EventTable[i][jhon].AnimKey = key
|
||||
-- print(CurTime(), "Clean at " .. i)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:PlayEvent(v)
|
||||
if !v or !istable(v) then error("no event to play") end
|
||||
v = self:GetBuff_Hook("Hook_PrePlayEvent", v) or v
|
||||
if v.e and IsFirstTimePredicted() then
|
||||
DoShell(self, v)
|
||||
end
|
||||
|
||||
if v.s then
|
||||
if v.s_km then
|
||||
self:StopSound(v.s)
|
||||
end
|
||||
self:MyEmitSound(v.s, v.l, v.p, v.v, v.c or CHAN_AUTO)
|
||||
end
|
||||
|
||||
if v.bg then
|
||||
self:SetBodygroupTr(v.ind or 0, v.bg)
|
||||
end
|
||||
|
||||
if v.pp then
|
||||
local vm = self:GetOwner():GetViewModel()
|
||||
|
||||
vm:SetPoseParameter(pp, ppv)
|
||||
end
|
||||
|
||||
v = self:GetBuff_Hook("Hook_PostPlayEvent", v) or v
|
||||
end
|
||||
|
||||
|
||||
if CLIENT then
|
||||
net.Receive("arccw_networksound", function(len)
|
||||
local v = net.ReadTable()
|
||||
local wep = net.ReadEntity()
|
||||
|
||||
wep.EventTable[CurTime() + v.ntttime] = v
|
||||
end)
|
||||
end
|
||||
153
lua/weapons/arccw_base/sh_ttt.lua
Normal file
153
lua/weapons/arccw_base/sh_ttt.lua
Normal file
@@ -0,0 +1,153 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
function SWEP:OnRestore()
|
||||
end
|
||||
|
||||
function SWEP:GetHeadshotMultiplier(victim, dmginfo)
|
||||
return 2.5 -- Hey hey hey, don't forget about me!!!
|
||||
end
|
||||
|
||||
function SWEP:IsEquipment()
|
||||
return WEPS.IsEquipment(self)
|
||||
end
|
||||
|
||||
SWEP.IsSilent = false
|
||||
|
||||
-- The OnDrop() hook is useless for this as it happens AFTER the drop. OwnerChange
|
||||
-- does not occur when a drop happens for some reason. Hence this thing.
|
||||
function SWEP:PreDrop()
|
||||
if self.Throwing then
|
||||
if self:GetGrenadePrimed() then
|
||||
self:Throw()
|
||||
end
|
||||
else
|
||||
if SERVER and IsValid(self:GetOwner()) and self.Primary.Ammo != "none" then
|
||||
local ammo = self:Ammo1()
|
||||
|
||||
-- Do not drop ammo if we have another gun that uses this type
|
||||
for _, w in ipairs(self:GetOwner():GetWeapons()) do
|
||||
if IsValid(w) and w != self and w:GetPrimaryAmmoType() == self:GetPrimaryAmmoType() then
|
||||
ammo = 0
|
||||
end
|
||||
end
|
||||
|
||||
self.StoredAmmo = ammo
|
||||
|
||||
if ammo > 0 then
|
||||
self:GetOwner():RemoveAmmo(ammo, self.Primary.Ammo)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
net.Start("arccw_togglecustomize")
|
||||
net.WriteBool(false)
|
||||
net.Send(self:GetOwner())
|
||||
self:ToggleCustomizeHUD(false)
|
||||
end
|
||||
|
||||
function SWEP:DampenDrop()
|
||||
-- For some reason gmod drops guns on death at a speed of 400 units, which
|
||||
-- catapults them away from the body. Here we want people to actually be able
|
||||
-- to find a given corpse's weapon, so we override the velocity here and call
|
||||
-- this when dropping guns on death.
|
||||
local phys = self:GetPhysicsObject()
|
||||
if IsValid(phys) then
|
||||
phys:SetVelocityInstantaneous(Vector(0,0,-75) + phys:GetVelocity() * 0.001)
|
||||
phys:AddAngleVelocity(phys:GetAngleVelocity() * -0.99)
|
||||
end
|
||||
end
|
||||
|
||||
SWEP.StoredAmmo = 0
|
||||
|
||||
-- Picked up by player. Transfer of stored ammo and such.
|
||||
function SWEP:Equip(newowner)
|
||||
if SERVER then
|
||||
if self:IsOnFire() then
|
||||
self:Extinguish()
|
||||
end
|
||||
|
||||
self.fingerprints = self.fingerprints or {}
|
||||
|
||||
if !table.HasValue(self.fingerprints, newowner) then
|
||||
table.insert(self.fingerprints, newowner)
|
||||
end
|
||||
end
|
||||
|
||||
if SERVER and IsValid(newowner) and self.StoredAmmo > 0 and self.Primary.Ammo != "none" then
|
||||
local ammo = newowner:GetAmmoCount(self.Primary.Ammo)
|
||||
local given = math.min(self.StoredAmmo, self.Primary.ClipMax - ammo)
|
||||
|
||||
newowner:GiveAmmo( given, self.Primary.Ammo)
|
||||
self.StoredAmmo = 0
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:WasBought(buyer)
|
||||
if self.TTT_DoNotAttachOnBuy then return end
|
||||
|
||||
for i, k in pairs(self.Attachments) do
|
||||
k.RandomChance = 100
|
||||
end
|
||||
-- if ArcCW.ConVars["ttt_atts"]:GetBool() then
|
||||
-- self:NPC_SetupAttachments()
|
||||
-- end
|
||||
end
|
||||
|
||||
function SWEP:TTT_PostAttachments()
|
||||
self.IsSilent = self:GetBuff_Override("Silencer")
|
||||
|
||||
if !self.IsSilent then
|
||||
self.IsSilent = true
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:TTT_Init()
|
||||
if engine.ActiveGamemode() != "terrortown" then return end
|
||||
|
||||
if SERVER then
|
||||
self.fingerprints = {}
|
||||
end
|
||||
|
||||
if self.Throwing then
|
||||
self.Primary.ClipMax = 0
|
||||
end
|
||||
|
||||
if ArcCW.ConVars["ttt_atts"]:GetBool() then
|
||||
if SERVER then
|
||||
self:NPC_SetupAttachments()
|
||||
end
|
||||
elseif !IsValid(self:GetOwner()) then
|
||||
-- If attachments aren't randomized, client will not need to ask for att info.
|
||||
self.CertainAboutAtts = true
|
||||
end
|
||||
|
||||
if self.ForgetDefaultBehavior then return end
|
||||
|
||||
self.Primary.ClipMax = ArcCW.TTTAmmoToClipMax[self.Primary.Ammo] or self.RegularClipSize * 2 or self.Primary.ClipSize * 2
|
||||
|
||||
-- This will overwrite mag reducers, so give it a bit of time
|
||||
timer.Simple(0.1, function()
|
||||
if !IsValid(self) then return end
|
||||
self:SetClip1(self:GetCapacity() or self.RegularClipSize or self.Primary.ClipSize)
|
||||
self.Primary.DefaultClip = self.ForceDefaultAmmo or self.ForceDefaultClip or self:GetCapacity()
|
||||
end)
|
||||
|
||||
if self.Throwing and self.Primary.Ammo and !self.ForceDefaultClip then
|
||||
self.Primary.Ammo = "none"
|
||||
self.Primary.DefaultClip = 0
|
||||
self:SetClip1(-1)
|
||||
self.Singleton = true
|
||||
end
|
||||
end
|
||||
|
||||
--- TTT2 uses this to populate custom convars in the equip menu
|
||||
function SWEP:AddToSettingsMenu(parent)
|
||||
end
|
||||
173
lua/weapons/arccw_base/sh_ubgl.lua
Normal file
173
lua/weapons/arccw_base/sh_ubgl.lua
Normal file
@@ -0,0 +1,173 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
function SWEP:SelectUBGL()
|
||||
if !self:GetBuff_Override("UBGL") then return end
|
||||
if self:GetReloading() then return end
|
||||
if self:GetNextPrimaryFire() > CurTime() then return end
|
||||
if self:GetNextSecondaryFire() > CurTime() then return end
|
||||
if self:GetUBGLDebounce() then return end
|
||||
self:SetUBGLDebounce( true )
|
||||
|
||||
self:SetInUBGL(true)
|
||||
|
||||
self:SetFireMode(1)
|
||||
|
||||
if CLIENT and (game.SinglePlayer() or (!game.SinglePlayer() and IsFirstTimePredicted())) then
|
||||
-- if !ArcCW:ShouldDrawHUDElement("CHudAmmo") then
|
||||
-- self:GetOwner():ChatPrint("Selected " .. self:GetBuff_Override("UBGL_PrintName") or "UBGL")
|
||||
-- end
|
||||
if !self:GetLHIKAnim() then
|
||||
self:DoLHIKAnimation("enter")
|
||||
end
|
||||
self:MyEmitSound( self:GetBuff_Override("SelectUBGLSound") or self.SelectUBGLSound )
|
||||
end
|
||||
|
||||
if self:GetBuff_Override("UBGL_BaseAnims") and self.Animations.enter_ubgl_empty and self:Clip2() == 0 then
|
||||
self:PlayAnimation("enter_ubgl_empty", 1, true)
|
||||
self:SetNextSecondaryFire(CurTime() + self:GetAnimKeyTime("enter_ubgl_empty"))
|
||||
elseif self:GetBuff_Override("UBGL_BaseAnims") and self.Animations.enter_ubgl then
|
||||
self:PlayAnimation("enter_ubgl", 1, true)
|
||||
self:SetNextSecondaryFire(CurTime() + self:GetAnimKeyTime("enter_ubgl"))
|
||||
else
|
||||
self:PlayAnimationEZ("idle", 1, false)
|
||||
self:SetNextSecondaryFire(CurTime() + 0.1)
|
||||
end
|
||||
|
||||
self:GetBuff_Hook("Hook_OnSelectUBGL")
|
||||
end
|
||||
|
||||
function SWEP:DeselectUBGL()
|
||||
if !self:GetInUBGL() then return end
|
||||
if self:GetReloading() then return end
|
||||
if self:GetNextPrimaryFire() > CurTime() then return end
|
||||
if self:GetNextSecondaryFire() > CurTime() then return end
|
||||
if self:GetUBGLDebounce() then return end
|
||||
self:SetUBGLDebounce( true )
|
||||
|
||||
self:SetInUBGL(false)
|
||||
|
||||
if CLIENT and (game.SinglePlayer() or (!game.SinglePlayer() and IsFirstTimePredicted())) then
|
||||
-- if !ArcCW:ShouldDrawHUDElement("CHudAmmo") then
|
||||
-- self:GetOwner():ChatPrint("Deselected " .. self:GetBuff_Override("UBGL_PrintName") or "UBGL")
|
||||
-- end
|
||||
if !self:GetLHIKAnim() and bong then
|
||||
self:DoLHIKAnimation("exit")
|
||||
end
|
||||
self:MyEmitSound( self:GetBuff_Override("ExitUBGLSound") or self.ExitUBGLSound )
|
||||
end
|
||||
|
||||
if self:GetBuff_Override("UBGL_BaseAnims") and self.Animations.exit_ubgl_empty and self:Clip2() == 0 then
|
||||
self:PlayAnimation("exit_ubgl_empty", 1, true)
|
||||
elseif self:GetBuff_Override("UBGL_BaseAnims") and self.Animations.exit_ubgl then
|
||||
self:PlayAnimation("exit_ubgl", 1, true)
|
||||
else
|
||||
self:PlayAnimationEZ("idle", 1, false)
|
||||
self:SetNextSecondaryFire(CurTime() + 0.1)
|
||||
end
|
||||
|
||||
self:GetBuff_Hook("Hook_OnDeselectUBGL")
|
||||
end
|
||||
|
||||
function SWEP:RecoilUBGL()
|
||||
local single = game.SinglePlayer()
|
||||
|
||||
if !single and !IsFirstTimePredicted() then return end
|
||||
|
||||
if single and self:GetOwner():IsValid() and SERVER then self:CallOnClient("RecoilUBGL") end
|
||||
|
||||
local amt = self:GetBuff_Override("UBGL_Recoil")
|
||||
local amtside = self:GetBuff_Override("UBGL_RecoilSide") or (self:GetBuff_Override("UBGL_Recoil") * 0.5)
|
||||
local amtrise = self:GetBuff_Override("UBGL_RecoilRise") or 1
|
||||
|
||||
local r = math.Rand(-1, 1)
|
||||
local ru = math.Rand(0.75, 1.25)
|
||||
|
||||
local m = 1 * amt
|
||||
local rs = 1 * amtside
|
||||
local vsm = 1
|
||||
|
||||
local vpa = Angle(0, 0, 0)
|
||||
|
||||
vpa = vpa + (Angle(1, 0, 0) * amt * m * vsm)
|
||||
|
||||
vpa = vpa + (Angle(0, 1, 0) * r * amtside * m * vsm)
|
||||
|
||||
if CLIENT then
|
||||
self:OurViewPunch(vpa)
|
||||
end
|
||||
|
||||
if CLIENT or game.SinglePlayer() then
|
||||
|
||||
self.RecoilAmount = self.RecoilAmount + (amt * m)
|
||||
self.RecoilAmountSide = self.RecoilAmountSide + (r * amtside * m * rs)
|
||||
|
||||
self.RecoilPunchBack = amt * 2.5 * m
|
||||
|
||||
if self.MaxRecoilBlowback > 0 then
|
||||
self.RecoilPunchBack = math.Clamp(self.RecoilPunchBack, 0, self.MaxRecoilBlowback)
|
||||
end
|
||||
|
||||
self.RecoilPunchSide = r * rs * m * 0.1 * vsm
|
||||
self.RecoilPunchUp = math.Clamp(ru * amt * m * 0.6 * vsm * amtrise, 0, 0.1)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:ShootUBGL()
|
||||
if self:GetNextSecondaryFire() > CurTime() then return end
|
||||
if self:GetState() == ArcCW.STATE_SPRINT and !self:CanShootWhileSprint() then return false end
|
||||
|
||||
self.Primary.Automatic = self:GetBuff_Override("UBGL_Automatic")
|
||||
|
||||
local ubglammo = self:GetBuff_Override("UBGL_Ammo")
|
||||
|
||||
if self:Clip2() <= 0 and self:GetOwner():GetAmmoCount(ubglammo) <= 0 then
|
||||
self:DeselectUBGL()
|
||||
return
|
||||
end
|
||||
|
||||
if self:Clip2() <= 0 then
|
||||
return
|
||||
end
|
||||
|
||||
self:RecoilUBGL()
|
||||
|
||||
local func, slot = self:GetBuff_Override("UBGL_Fire")
|
||||
|
||||
if func then
|
||||
func(self, self.Attachments[slot].VElement)
|
||||
end
|
||||
|
||||
self:SetNextSecondaryFire(CurTime() + (60 / self:GetBuff_Override("UBGL_RPM")))
|
||||
end
|
||||
|
||||
function SWEP:ReloadUBGL()
|
||||
if self:GetNextSecondaryFire() > CurTime() then return end
|
||||
|
||||
local reloadfunc, slot = self:GetBuff_Override("UBGL_Reload")
|
||||
|
||||
if reloadfunc then
|
||||
reloadfunc(self, self.Attachments[slot].VElement)
|
||||
end
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
|
||||
function SWEP:DoLHIKAnimation(key, time)
|
||||
if game.SinglePlayer() then
|
||||
net.Start("arccw_sp_lhikanim")
|
||||
net.WriteString(key)
|
||||
net.WriteFloat(time or -1)
|
||||
net.Send(self:GetOwner())
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
29
lua/weapons/arccw_base/sh_util.lua
Normal file
29
lua/weapons/arccw_base/sh_util.lua
Normal file
@@ -0,0 +1,29 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
function SWEP:TableRandom(table)
|
||||
return table[math.random(#table)]
|
||||
end
|
||||
|
||||
function SWEP:MyEmitSound(fsound, level, pitch, vol, chan, useWorld)
|
||||
if !fsound then return end
|
||||
|
||||
fsound = self:GetBuff_Hook("Hook_TranslateSound", fsound) or fsound
|
||||
|
||||
if istable(fsound) then fsound = self:TableRandom(fsound) end
|
||||
|
||||
if fsound and fsound != "" then
|
||||
if useWorld then
|
||||
sound.Play(fsound, self:GetOwner():GetShootPos(), level, pitch, vol)
|
||||
else
|
||||
self:EmitSound(fsound, level, pitch, vol, chan or CHAN_AUTO)
|
||||
end
|
||||
end
|
||||
end
|
||||
1000
lua/weapons/arccw_base/shared.lua
Normal file
1000
lua/weapons/arccw_base/shared.lua
Normal file
File diff suppressed because it is too large
Load Diff
415
lua/weapons/arccw_base/sv_npc.lua
Normal file
415
lua/weapons/arccw_base/sv_npc.lua
Normal file
@@ -0,0 +1,415 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
-- NPC integration
|
||||
|
||||
function SWEP:NPC_Initialize()
|
||||
if CLIENT then return end
|
||||
|
||||
if !IsValid(self:GetOwner()) then return end
|
||||
if !self:GetOwner():IsNPC() then return end
|
||||
|
||||
self:NPC_SetupAttachments()
|
||||
|
||||
self:SetHoldType(self.HoldtypeNPC or self:GetBuff_Override("Override_HoldtypeActive") or self.HoldtypeActive)
|
||||
|
||||
self:SetNextPrimaryFire(CurTime())
|
||||
|
||||
self:SetClip1(self:GetCapacity() or self.Primary.ClipSize)
|
||||
|
||||
-- print(self:Clip1())
|
||||
|
||||
local range = self:GetBuff("Range") / ArcCW.HUToM
|
||||
|
||||
if self:GetBuff("DamageMin") >= self:GetBuff("Damage") or (self:GetBuff_Override("Override_ManualAction") or self.ManualAction) and self:GetBuff("Num") == 1 then
|
||||
range = math.max(range, 10000) * 2
|
||||
end
|
||||
|
||||
range = math.Clamp(range, 2048, 36000)
|
||||
|
||||
self:GetOwner():Input("SetMaxLookDistance", nil, nil, range)
|
||||
|
||||
self:SetNextPrimaryFire(CurTime())
|
||||
self:SetNextSecondaryFire(CurTime() + 30)
|
||||
self:GetOwner():NextThink(CurTime())
|
||||
end
|
||||
|
||||
function SWEP:AssignRandomAttToSlot(slot)
|
||||
if slot.DoNotRandomize then return end
|
||||
if slot.Installed then return end
|
||||
|
||||
local att = ArcCW:RollRandomAttachment(true, self, slot)
|
||||
if !att then return end
|
||||
slot.Installed = att
|
||||
|
||||
local atttbl = ArcCW.AttachmentTable[slot.Installed]
|
||||
|
||||
--if !ArcCW:SlotAcceptsAtt(slot.Slot, self, slot.Installed) then return end
|
||||
--if !self:CheckFlags(atttbl.ExcludeFlags, atttbl.RequireFlags) then return end
|
||||
|
||||
if atttbl.MountPositionOverride then
|
||||
slot.SlidePos = atttbl.MountPositionOverride
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:NPC_SetupAttachments()
|
||||
if self:GetOwner():IsNPC() and !ArcCW.ConVars["npc_atts"]:GetBool() then return end
|
||||
|
||||
local pick = self:GetPickX()
|
||||
|
||||
local chance = 25 * ArcCW.ConVars["mult_attchance"]:GetFloat()
|
||||
local chancestep = 0
|
||||
|
||||
if pick > 0 then
|
||||
chancestep = chance / pick
|
||||
--chance = chancestep
|
||||
else
|
||||
pick = 1000
|
||||
end
|
||||
|
||||
local n = 0
|
||||
|
||||
for i, slot in pairs(self.Attachments) do
|
||||
if n > pick then continue end
|
||||
if !self:CheckFlags(slot.ExcludeFlags, slot.RequireFlags) then continue end
|
||||
if math.Rand(0, 100) > (chance * (slot.RandomChance or 1)) then continue end
|
||||
|
||||
if slot.Hidden then continue end
|
||||
|
||||
local s = i
|
||||
|
||||
if slot.MergeSlots then
|
||||
local ss = {i}
|
||||
table.Add(ss, slot.MergeSlots)
|
||||
|
||||
s = table.Random(ss) or i
|
||||
end
|
||||
if !self.Attachments[s] then s = i end
|
||||
|
||||
chance = chance - chancestep
|
||||
|
||||
self:AssignRandomAttToSlot(self.Attachments[s])
|
||||
|
||||
n = n + 1
|
||||
end
|
||||
|
||||
self.ActiveElementCache = nil -- Reset cache so we have the proper attachments to check with
|
||||
for i, slot in pairs(self.Attachments) do
|
||||
if !slot.Installed then continue end
|
||||
local atttbl = ArcCW.AttachmentTable[slot.Installed]
|
||||
if !ArcCW:SlotAcceptsAtt(slot.Slot, self, slot.Installed) then slot.Installed = nil continue end
|
||||
if !self:CheckFlags(slot.ExcludeFlags, slot.RequireFlags) then slot.Installed = nil continue end
|
||||
if !self:CheckFlags(atttbl.ExcludeFlags, atttbl.RequireFlags) then slot.Installed = nil continue end
|
||||
end
|
||||
|
||||
if self:GetBuff_Override("UBGL") and self:GetBuff_Override("UBGL_Capacity") then
|
||||
self:SetClip2(self:GetBuff_Override("UBGL_Capacity"))
|
||||
end
|
||||
|
||||
self:AdjustAtts()
|
||||
self:RefreshBGs()
|
||||
|
||||
if self:GetOwner():IsNPC() then
|
||||
timer.Simple(0.1, function()
|
||||
if !IsValid(self) then return end
|
||||
self:NetworkWeapon()
|
||||
end)
|
||||
else
|
||||
self:NetworkWeapon()
|
||||
self:SetupModel(false)
|
||||
self:SetupModel(true)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:NPC_Shoot()
|
||||
-- if self:GetNextPrimaryFire() > CurTime() then return end
|
||||
|
||||
if !IsValid(self:GetOwner()) then return end
|
||||
if self:Clip1() <= 0 then self:GetOwner():SetSchedule(SCHED_HIDE_AND_RELOAD) return end
|
||||
|
||||
if self:GetOwner().ArcCW_Smoked then return end
|
||||
|
||||
|
||||
self.Primary.Automatic = true
|
||||
|
||||
|
||||
local delay = self:GetFiringDelay()
|
||||
|
||||
if (self:GetBuff_Override("Override_ManualAction") or self.ManualAction) then
|
||||
delay = self:GetAnimKeyTime("cycle", true) * self:GetBuff("CycleTime")
|
||||
end
|
||||
|
||||
local num = self:GetBuff("Num")
|
||||
|
||||
if num > 0 then
|
||||
local spread = ArcCW.MOAToAcc * self:GetBuff("AccuracyMOA")
|
||||
|
||||
local btabl = {
|
||||
Attacker = self:GetOwner(),
|
||||
Damage = 0,
|
||||
Force = 1,
|
||||
Distance = 33000,
|
||||
Num = num,
|
||||
Tracer = self.TracerNum,
|
||||
AmmoType = self.Primary.Ammo,
|
||||
Dir = self:GetOwner():GetAimVector(),
|
||||
Src = self:GetShootSrc(),
|
||||
Spread = Vector(spread, spread, spread),
|
||||
Callback = function(att, tr, dmg)
|
||||
ArcCW:BulletCallback(att, tr, dmg, self)
|
||||
end,
|
||||
--[[]
|
||||
Callback = function(att, tr, dmg)
|
||||
local dist = (tr.HitPos - tr.StartPos):Length() * ArcCW.HUToM
|
||||
|
||||
local pen = self:GetBuff("Penetration")
|
||||
|
||||
-- local frags = math.random(1, self.Frangibility)
|
||||
|
||||
-- for i = 1, frags do
|
||||
-- self:DoPenetration(tr, (self.Penetration / frags) - 0.5, tr.Entity)
|
||||
-- end
|
||||
|
||||
if self.DamageMin > self.Damage then
|
||||
dist = -dist + self.Range + self.Range
|
||||
end
|
||||
|
||||
local m = 1 * self:GetBuff_Mult("Mult_DamageNPC")
|
||||
|
||||
local ret = self:GetBuff_Hook("Hook_BulletHit", {
|
||||
range = dist,
|
||||
damage = self:GetDamage(dist, true) * m,
|
||||
dmgtype = self:GetBuff_Override("Override_DamageType") or self.DamageType,
|
||||
penleft = pen,
|
||||
att = att,
|
||||
tr = tr,
|
||||
dmg = dmg
|
||||
})
|
||||
|
||||
if !ret then return end
|
||||
|
||||
dmg:SetDamageType(ret.dmgtype)
|
||||
dmg:SetDamage(ret.damage)
|
||||
|
||||
if dmg:IsDamageType(DMG_BURN) and hit.range <= self.Range then
|
||||
dmg:SetDamageType(dmg:GetDamageType() - DMG_BURN)
|
||||
|
||||
local fx = EffectData()
|
||||
fx:SetOrigin(tr.HitPos)
|
||||
util.Effect("arccw_incendiaryround", fx)
|
||||
|
||||
util.Decal("FadingScorch", tr.StartPos, tr.HitPos - (tr.HitNormal * 16), self:GetOwner())
|
||||
|
||||
tr.Entity:Ignite(1, 32)
|
||||
end
|
||||
end
|
||||
]]
|
||||
}
|
||||
|
||||
local sp = self:GetBuff_Override("Override_ShotgunSpreadPattern") or self.ShotgunSpreadPattern
|
||||
local spo = self:GetBuff_Override("Override_ShotgunSpreadPatternOverrun") or self.ShotgunSpreadPatternOverrun
|
||||
local se = self:GetBuff_Override("Override_ShootEntity") or self.ShootEntity
|
||||
|
||||
if sp or spo then
|
||||
btabl = self:GetBuff_Hook("Hook_FireBullets", btabl)
|
||||
|
||||
if !btabl then return end
|
||||
if btabl.Num == 0 then return end
|
||||
|
||||
for n = 1, btabl.Num do
|
||||
btabl.Num = 1
|
||||
local ang = self:GetOwner():GetAimVector():Angle() + self:GetShotgunSpreadOffset(n)
|
||||
|
||||
btabl.Dir = ang:Forward()
|
||||
|
||||
self:DoPrimaryFire(false, btabl)
|
||||
end
|
||||
elseif se then
|
||||
self:FireRocket(se, self:GetBuff("MuzzleVelocity"))
|
||||
else
|
||||
self:GetBuff_Hook("Hook_FireBullets", btabl)
|
||||
|
||||
for n = 1, btabl.Num do
|
||||
btabl.Num = 1
|
||||
|
||||
local dispers = self:GetBuff_Override("Override_ShotgunSpreadDispersion", self.ShotgunSpreadDispersion)
|
||||
local offset = self:GetShotgunSpreadOffset(n)
|
||||
local calcoff = dispers and (offset * self:GetDispersion() * ArcCW.MOAToAcc / 10) or offset
|
||||
|
||||
local ang = self:GetOwner():GetAimVector():Angle()
|
||||
-- ang:RotateAroundAxis(ang:Right(), -1 * calcoff.p)
|
||||
-- ang:RotateAroundAxis(ang:Up(), calcoff.y)
|
||||
-- ang:RotateAroundAxis(ang:Forward(), calcoff.r)
|
||||
|
||||
btabl.Dir = ang:Forward()
|
||||
|
||||
self:DoPrimaryFire(false, btabl)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self:DoEffects()
|
||||
|
||||
if !self.RevolverReload then
|
||||
self:DoShellEject()
|
||||
end
|
||||
|
||||
--[[]
|
||||
local ss = self.ShootSound
|
||||
|
||||
if self:GetBuff_Override("Silencer") then
|
||||
ss = self.ShootSoundSilenced
|
||||
end
|
||||
|
||||
ss = self:GetBuff_Hook("Hook_GetShootSound", ss)
|
||||
|
||||
local dss = self.DistantShootSound
|
||||
|
||||
if self:GetBuff_Override("Silencer") then
|
||||
dss = nil
|
||||
end
|
||||
|
||||
dss = self:GetBuff_Hook("Hook_GetDistantShootSound", dss)
|
||||
|
||||
local svol = self:GetBuff("ShootVol")
|
||||
local spitch = self.ShootPitch * math.Rand(0.95, 1.05) * self:GetBuff_Mult("Mult_ShootPitch")
|
||||
|
||||
svol = svol * 0.75
|
||||
|
||||
svol = math.Clamp(svol, 51, 149)
|
||||
spitch = math.Clamp(spitch, 51, 149)
|
||||
|
||||
if dss then
|
||||
-- sound.Play(self.DistantShootSound, self:GetPos(), 149, self.ShootPitch * math.Rand(0.95, 1.05), 1)
|
||||
self:MyEmitSound(dss, 130, spitch, 0.5, CHAN_BODY)
|
||||
end
|
||||
|
||||
if ss then
|
||||
self:MyEmitSound(ss, svol, spitch, 1, CHAN_WEAPON)
|
||||
end
|
||||
]]
|
||||
|
||||
self:DoShootSound()
|
||||
|
||||
self:SetClip1(self:Clip1() - 1)
|
||||
|
||||
self:SetNextPrimaryFire(CurTime() + delay)
|
||||
if delay < 0.1 then
|
||||
self:GetOwner():NextThink(CurTime() + delay)
|
||||
end
|
||||
|
||||
if self:GetBuff_Override("UBGL_NPCFire") and self:GetNextSecondaryFire() < CurTime() then
|
||||
if math.random(0, 100) < (self:GetOwner():GetCurrentWeaponProficiency() + 1) then
|
||||
self:SetNextSecondaryFire(CurTime() + math.random(3, 5))
|
||||
else
|
||||
local func = self:GetBuff_Override("UBGL_NPCFire")
|
||||
if func then
|
||||
func(self)
|
||||
end
|
||||
if self:Clip2() == 0 then
|
||||
self:SetClip2(self.Secondary.ClipSize)
|
||||
self:SetNextSecondaryFire(CurTime() + math.random(300, 600) / (self:GetOwner():GetCurrentWeaponProficiency() + 1))
|
||||
else
|
||||
self:SetNextSecondaryFire(CurTime() + 1 / ((self:GetBuff_Override("UBGL_RPM") or 300) / 60))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetNPCBulletSpread(prof)
|
||||
local mode = self:GetCurrentFiremode()
|
||||
mode = mode.Mode
|
||||
|
||||
if mode < 0 then
|
||||
return 15 / (prof + 1)
|
||||
elseif mode == 1 then
|
||||
if math.Rand(0, 100) < (prof + 5) * 5 then
|
||||
return 5 / (prof + 1)
|
||||
else
|
||||
return 30 / (prof + 1)
|
||||
end
|
||||
elseif mode > 1 then
|
||||
if math.Rand(0, 100) < (prof + 5) * 2 then
|
||||
return 15 / (prof + 1)
|
||||
else
|
||||
return (20 + self:GetBuff("Recoil") * 10) / (prof + 1)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return 15
|
||||
end
|
||||
|
||||
function SWEP:GetNPCBurstSettings()
|
||||
local mode = self:GetCurrentFiremode()
|
||||
mode = mode.Mode
|
||||
|
||||
local delay = self:GetFiringDelay()
|
||||
|
||||
if !mode then return 1, 1, delay end
|
||||
|
||||
if self.ManualAction or self:GetBuff_Override("Override_ManualAction") then
|
||||
return 1, 1, self:GetAnimKeyTime("cycle") * self:GetBuff("CycleTime")
|
||||
end
|
||||
|
||||
if mode < 0 then
|
||||
return -mode, -mode, delay
|
||||
elseif mode == 0 then
|
||||
return 0, 0, delay
|
||||
elseif mode == 1 then
|
||||
local c = self:GetCapacity()
|
||||
return math.ceil(c * 0.075), math.floor(c * math.Rand(0.15, 0.3)), delay + math.Rand(0.2, 0.4)
|
||||
elseif mode >= 2 then
|
||||
if self:GetCurrentFiremode().RunawayBurst then
|
||||
return self:Clip1(), self:Clip1(), delay
|
||||
else
|
||||
return 2, math.floor(2.5 / delay), delay
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:GetNPCRestTimes()
|
||||
local mode = self:GetCurrentFiremode()
|
||||
mode = mode.Mode
|
||||
local postburst = self:GetCurrentFiremode().PostBurstDelay or 0
|
||||
local m = self:GetBuff("Recoil")
|
||||
local rs = self:GetBuff("RecoilSide")
|
||||
|
||||
if !mode then return 0.3, 0.6 end
|
||||
|
||||
local o = m * 0.3 + rs * 0.15
|
||||
if self.ManualAction or self:GetBuff_Override("Override_ManualAction") then
|
||||
local cycle = self:GetAnimKeyTime("cycle") * self:GetBuff("CycleTime")
|
||||
return cycle + 0.1 * o, cycle + 0.2 * o
|
||||
elseif mode < 0 then
|
||||
o = o * 0.5 + postburst * self:GetBuff("PostBurstDelay")
|
||||
end
|
||||
|
||||
return 0.4 * o, 0.6 * o
|
||||
end
|
||||
|
||||
function SWEP:CanBePickedUpByNPCs()
|
||||
return !self.NotForNPCs
|
||||
end
|
||||
|
||||
function SWEP:OnDrop()
|
||||
self.Primary.DefaultClip = 0
|
||||
|
||||
if self.Singleton or self.Primary.ClipSize == -1 then
|
||||
self.Primary.DefaultClip = 1
|
||||
end
|
||||
|
||||
self.UnReady = false
|
||||
-- if engine.ActiveGamemode() == "terrortown" then
|
||||
-- self.UnReady = true
|
||||
-- else
|
||||
-- self.UnReady = false
|
||||
-- end
|
||||
end
|
||||
145
lua/weapons/arccw_base/sv_shield.lua
Normal file
145
lua/weapons/arccw_base/sv_shield.lua
Normal file
@@ -0,0 +1,145 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
SWEP.Shields = {}
|
||||
|
||||
function SWEP:SetupShields()
|
||||
self:KillShields()
|
||||
|
||||
for i, k in pairs(self.Attachments) do
|
||||
if !k then continue end
|
||||
if !k.Installed then continue end
|
||||
|
||||
local atttbl = ArcCW.AttachmentTable[k.Installed]
|
||||
|
||||
if atttbl.ModelIsShield then
|
||||
|
||||
for _, e in pairs(self:GetActiveElements()) do
|
||||
local ele = self.AttachmentElements[e]
|
||||
|
||||
if !ele then continue end
|
||||
|
||||
if ((ele.AttPosMods or {})[i] or {}).wpos then
|
||||
wmelemod = ele.AttPosMods[i].wpos
|
||||
end
|
||||
|
||||
if ((ele.AttPosMods or {})[i] or {}).slide then
|
||||
slidemod = ele.AttPosMods[i].slide
|
||||
end
|
||||
|
||||
-- Refer to sh_model Line 837
|
||||
if ((ele.AttPosMods or {})[i] or {}).SlideAmount then
|
||||
slidemod = ele.AttPosMods[i].SlideAmount
|
||||
end
|
||||
end
|
||||
|
||||
local bonename = atttbl.ShieldBone or "ValveBiped.Bip01_R_Hand"
|
||||
|
||||
local boneindex = self:GetOwner():LookupBone(bonename)
|
||||
|
||||
local bpos, bang = self:GetOwner():GetBonePosition(boneindex)
|
||||
|
||||
local delta = k.SlidePos or 0.5
|
||||
|
||||
local offset = wmelemod or k.Offset.wpos or Vector(0, 0, 0)
|
||||
|
||||
if k.SlideAmount then
|
||||
offset = LerpVector(delta, (slidemod or k.SlideAmount).wmin, (slidemod or k.SlideAmount).wmax)
|
||||
end
|
||||
|
||||
local pos = offset + (atttbl.ShieldCorrectPos or Vector(0, 0, 0))
|
||||
local ang = k.Offset.wang or Angle(0, 0, 0)
|
||||
|
||||
local apos = LocalToWorld(pos, ang, bpos, bang)
|
||||
|
||||
local shield = ents.Create("physics_prop")
|
||||
if !shield then
|
||||
print("!!! Unable to spawn shield!")
|
||||
continue
|
||||
end
|
||||
|
||||
shield.mmRHAe = atttbl.ShieldResistance
|
||||
|
||||
shield:SetModel( atttbl.Model )
|
||||
shield:FollowBone( self:GetOwner(), boneindex )
|
||||
shield:SetPos( apos )
|
||||
shield:SetAngles( self:GetOwner():GetAngles() + ang + (atttbl.ShieldCorrectAng or Angle(0, 0, 0)) )
|
||||
shield:SetCollisionGroup( COLLISION_GROUP_WORLD )
|
||||
shield.Weapon = self
|
||||
if GetConVar("developer"):GetBool() then
|
||||
shield:SetColor( Color(0, 0, 0, 255) )
|
||||
else
|
||||
shield:SetColor( Color(0, 0, 0, 0) )
|
||||
shield:SetRenderMode(RENDERMODE_NONE)
|
||||
end
|
||||
table.insert(self.Shields, shield)
|
||||
shield:Spawn()
|
||||
shield:Activate()
|
||||
|
||||
table.insert(ArcCW.ShieldPropPile, {Weapon = self, Model = shield})
|
||||
|
||||
local phys = shield:GetPhysicsObject()
|
||||
|
||||
phys:SetMass(1000)
|
||||
end
|
||||
end
|
||||
|
||||
for i, k in pairs(self.ShieldProps or {}) do
|
||||
if !k then continue end
|
||||
if !k.Model then continue end
|
||||
|
||||
local bonename = k.Bone or "ValveBiped.Bip01_R_Hand"
|
||||
|
||||
local boneindex = self:GetOwner():LookupBone(bonename)
|
||||
|
||||
local bpos, bang = self:GetOwner():GetBonePosition(boneindex)
|
||||
|
||||
local pos = k.Pos or Vector(0, 0, 0)
|
||||
local ang = k.Ang or Angle(0, 0, 0)
|
||||
|
||||
local apos = LocalToWorld(pos, ang, bpos, bang)
|
||||
|
||||
local shield = ents.Create("physics_prop")
|
||||
if !shield then
|
||||
print("!!! Unable to spawn shield!")
|
||||
continue
|
||||
end
|
||||
|
||||
shield.mmRHAe = k.Resistance
|
||||
|
||||
shield:SetModel( k.Model )
|
||||
shield:FollowBone( self:GetOwner(), boneindex )
|
||||
shield:SetPos( apos )
|
||||
shield:SetAngles( self:GetOwner():GetAngles() + ang )
|
||||
shield:SetCollisionGroup( COLLISION_GROUP_WORLD )
|
||||
shield.Weapon = self
|
||||
if GetConVar("developer"):GetBool() then
|
||||
shield:SetColor( Color(0, 0, 0, 255) )
|
||||
else
|
||||
shield:SetColor( Color(0, 0, 0, 0) )
|
||||
shield:SetRenderMode(RENDERMODE_NONE)
|
||||
end
|
||||
table.insert(self.Shields, shield)
|
||||
shield:Spawn()
|
||||
shield:Activate()
|
||||
|
||||
table.insert(ArcCW.ShieldPropPile, {Weapon = self, Model = shield})
|
||||
|
||||
local phys = shield:GetPhysicsObject()
|
||||
|
||||
phys:SetMass(1000)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:KillShields()
|
||||
for i, k in pairs(self.Shields) do
|
||||
SafeRemoveEntity(k)
|
||||
end
|
||||
end
|
||||
83
lua/weapons/arccw_base_melee/shared.lua
Normal file
83
lua/weapons/arccw_base_melee/shared.lua
Normal file
@@ -0,0 +1,83 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
SWEP.Base = "arccw_base"
|
||||
|
||||
SWEP.Primary.Ammo = "" -- Prevent base "pistol" ammo type from showing up on the HUD of melee weapons
|
||||
|
||||
SWEP.MeleeDamage = 25
|
||||
SWEP.MeleeDamageBackstab = nil -- If not exists, use multiplier on standard damage
|
||||
SWEP.MeleeRange = 16
|
||||
SWEP.MeleeDamageType = DMG_CLUB
|
||||
SWEP.MeleeTime = 0.5
|
||||
SWEP.MeleeGesture = nil
|
||||
SWEP.MeleeAttackTime = 0.2
|
||||
|
||||
SWEP.Melee2 = false
|
||||
SWEP.Melee2Damage = 25
|
||||
SWEP.Melee2DamageBackstab = nil -- If not exists, use multiplier on standard damage
|
||||
SWEP.Melee2Range = 16
|
||||
SWEP.Melee2Time = 0.5
|
||||
SWEP.Melee2Gesture = nil
|
||||
SWEP.Melee2AttackTime = 0.2
|
||||
|
||||
SWEP.Backstab = false
|
||||
SWEP.BackstabMultiplier = 2
|
||||
|
||||
SWEP.NotForNPCs = true
|
||||
|
||||
SWEP.Firemodes = {
|
||||
{
|
||||
Mode = 1,
|
||||
PrintName = "MELEE"
|
||||
},
|
||||
}
|
||||
|
||||
SWEP.HoldtypeHolstered = "normal"
|
||||
SWEP.HoldtypeActive = "melee"
|
||||
|
||||
SWEP.Primary.ClipSize = -1
|
||||
|
||||
SWEP.Animations = {
|
||||
-- ["draw"] = {
|
||||
-- Source = "draw",
|
||||
-- Time = 0.5,
|
||||
-- },
|
||||
-- ["ready"] = {
|
||||
-- Source = "draw",
|
||||
-- Time = 0.5,
|
||||
-- },
|
||||
-- ["bash"] = {
|
||||
-- Source = {"stab", "midslash1", "midslash2", "stab_miss"},
|
||||
-- Time = 0.5,
|
||||
-- },
|
||||
-- ["bash_backstab"] = {
|
||||
-- Source = {"stab_backstab"},
|
||||
-- Time = 0.5,
|
||||
-- },
|
||||
}
|
||||
|
||||
SWEP.IronSightStruct = false
|
||||
|
||||
SWEP.BashPreparePos = Vector(0, 0, 0)
|
||||
SWEP.BashPrepareAng = Angle(0, 0, 0)
|
||||
|
||||
SWEP.BashPos = Vector(0, 0, 0)
|
||||
SWEP.BashAng = Angle(0, 0, 0)
|
||||
|
||||
SWEP.HolsterPos = Vector(0, -1, 0)
|
||||
SWEP.HolsterAng = Angle(-10, 0, 0)
|
||||
|
||||
SWEP.ShootWhileSprint = true
|
||||
|
||||
SWEP.SpeedMult = 1
|
||||
|
||||
SWEP.Secondary.Automatic = true
|
||||
|
||||
107
lua/weapons/arccw_base_nade/shared.lua
Normal file
107
lua/weapons/arccw_base_nade/shared.lua
Normal file
@@ -0,0 +1,107 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
SWEP.Base = "arccw_base"
|
||||
|
||||
SWEP.Throwing = true
|
||||
SWEP.Singleton = false -- for grenades, means that weapons ARE ammo; hold one, use one.
|
||||
|
||||
SWEP.NotForNPCs = true
|
||||
|
||||
SWEP.Delay = 1
|
||||
SWEP.Firemodes = {
|
||||
{
|
||||
Mode = 1,
|
||||
PrintName = "NADE"
|
||||
},
|
||||
}
|
||||
|
||||
SWEP.MuzzleVelocity = 1000
|
||||
SWEP.MuzzleVelocityAlt = nil -- Throwing with alt-fire will use this velocity if exists
|
||||
|
||||
SWEP.PullPinTime = 0.25
|
||||
SWEP.FuseTime = 3.5
|
||||
|
||||
SWEP.WindupTime = 0.5 -- Time to reach max velocity (does not apply for altfire)
|
||||
SWEP.WindupMinimum = 0.25 -- Velocity fraction if released without windup
|
||||
|
||||
SWEP.ShootEntityDelay = 0.25 -- Delay between Throw() call and projectile existing
|
||||
|
||||
SWEP.ThrowInertia = nil -- override default throw intertia settings
|
||||
|
||||
SWEP.CookPrimFire = true
|
||||
SWEP.CookAltFire = true
|
||||
|
||||
SWEP.ChamberSize = 0
|
||||
|
||||
SWEP.HoldtypeHolstered = "normal"
|
||||
SWEP.HoldtypeActive = "slam"
|
||||
SWEP.HoldtypeSights = "grenade"
|
||||
SWEP.HoldtypeCustomize = "slam"
|
||||
|
||||
SWEP.Primary.ClipSize = 1
|
||||
SWEP.Primary.Ammo = "grenade"
|
||||
|
||||
SWEP.AnimShoot = ACT_HL2MP_GESTURE_RANGE_ATTACK_GRENADE
|
||||
SWEP.AnimShootAlt = ACT_HL2MP_GESTURE_RANGE_ATTACK_SLAM
|
||||
|
||||
-- By default, grenades with no ammo will be stripped. Set true to prevent
|
||||
SWEP.KeepIfEmpty = false
|
||||
|
||||
SWEP.Animations = {
|
||||
-- ["draw"] = {
|
||||
-- Source = "draw",
|
||||
-- Time = 0.5,
|
||||
-- },
|
||||
-- ["ready"] = {
|
||||
-- Source = "draw",
|
||||
-- Time = 0.5,
|
||||
-- },
|
||||
-- ["pre_throw"] = {
|
||||
-- Source = "pullpin",
|
||||
-- Time = 0.5,
|
||||
-- },
|
||||
-- ["throw"] = {
|
||||
-- Source = "throw",
|
||||
-- Time = 0.5
|
||||
-- }
|
||||
}
|
||||
|
||||
SWEP.BashPreparePos = Vector(2.187, -7.117, -1)
|
||||
SWEP.BashPrepareAng = Angle(5, -3.652, -19.039)
|
||||
|
||||
SWEP.BashPos = Vector(8.876, 0, 0)
|
||||
SWEP.BashAng = Angle(-16.524, 70, -11.046)
|
||||
|
||||
SWEP.HolsterPos = Vector(0.532, -1, 0)
|
||||
SWEP.HolsterAng = Angle(-10, 0, 0)
|
||||
|
||||
SWEP.IronSightStruct = false
|
||||
|
||||
SWEP.MeleeSwingSound = "weapons/arccw/m249/m249_draw.wav"
|
||||
SWEP.MeleeHitSound = "weapons/arccw/knife/knife_hitwall1.wav"
|
||||
SWEP.MeleeHitNPCSound = "physics/body/body_medium_break2.wav"
|
||||
|
||||
SWEP.ShootWhileSprint = true
|
||||
|
||||
SWEP.SpeedMult = 1
|
||||
|
||||
SWEP.Secondary.Automatic = true
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
self:PrimaryAttack()
|
||||
end
|
||||
|
||||
function SWEP:OnRemove()
|
||||
if engine.ActiveGamemode() != "terrortown" then return end
|
||||
if CLIENT and IsValid(self:GetOwner()) and self:GetOwner() == LocalPlayer() and self:GetOwner():Alive() then
|
||||
RunConsoleCommand("use", "weapon_ttt_unarmed")
|
||||
end
|
||||
end
|
||||
241
lua/weapons/chess_admin_tool.lua
Normal file
241
lua/weapons/chess_admin_tool.lua
Normal file
@@ -0,0 +1,241 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
--Easy placement and saving for Chess boards
|
||||
if SERVER then AddCSLuaFile() end
|
||||
|
||||
SWEP.Base = "weapon_base"
|
||||
|
||||
SWEP.Category = "Game boards"
|
||||
SWEP.Author = "my_hat_stinks"
|
||||
SWEP.Instructions = "Left click to place a board, right click to remove a board, reload for menu"
|
||||
|
||||
SWEP.Spawnable = true
|
||||
SWEP.AdminOnly = true
|
||||
SWEP.AdminSpawnable = true
|
||||
|
||||
SWEP.Slot = 4
|
||||
SWEP.PrintName = "Chess Admin Tool"
|
||||
|
||||
SWEP.ViewModelFOV = 80
|
||||
SWEP.Weight = 5
|
||||
SWEP.AutoSwitchTo = false
|
||||
SWEP.AutoSwitchFrom = false
|
||||
|
||||
SWEP.WorldModel = "models/weapons/w_toolgun.mdl"
|
||||
SWEP.ViewModel = "models/weapons/c_toolgun.mdl"
|
||||
SWEP.UseHands = true
|
||||
|
||||
SWEP.Primary.Recoil = 1
|
||||
SWEP.Primary.Damage = 5
|
||||
SWEP.Primary.NumShots = 1
|
||||
SWEP.Primary.Cone = 0
|
||||
SWEP.Primary.Delay = 1
|
||||
|
||||
SWEP.Primary.ClipSize = -1
|
||||
SWEP.Primary.DefaultClip = -1
|
||||
SWEP.Primary.Automatic = false
|
||||
SWEP.Primary.Ammo = "none"
|
||||
SWEP.Primary.ClipMax = -1
|
||||
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = false
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
SWEP.Secondary.ClipMax = -1
|
||||
|
||||
SWEP.DeploySpeed = 1.5
|
||||
|
||||
SWEP.PrimaryAnim = ACT_VM_PRIMARYATTACK
|
||||
SWEP.ReloadAnim = ACT_VM_RELOAD
|
||||
SWEP.HoldType = "pistol"
|
||||
|
||||
SWEP.GameEntities = {
|
||||
{"Chess", "ent_chess_board", {["board"] = Model("models/props_phx/games/chess/board.mdl"), ["table"] = Model("models/props/de_tides/restaurant_table.mdl")}},
|
||||
{"Draughts/Checkers", "ent_draughts_board", {["board"] = Model("models/props_phx/games/chess/board.mdl"), ["table"] = Model("models/props/de_tides/restaurant_table.mdl")}},
|
||||
}
|
||||
function SWEP:SetupDataTables()
|
||||
self:NetworkVar( "Int", 0, "EntID" )
|
||||
end
|
||||
|
||||
function SWEP:Initialize()
|
||||
self:SetEntID( 1 ) --Chess by default
|
||||
end
|
||||
function SWEP:PrimaryAttack()
|
||||
if SERVER and IsValid( self.Owner ) then
|
||||
if not self.Owner:IsAdmin() then
|
||||
self.Owner:ChatPrint( "You are not allowed to use this tool!" )
|
||||
self:Remove()
|
||||
return
|
||||
end
|
||||
local tr = self.Owner:GetEyeTrace()
|
||||
if tr.Hit and tr.HitPos then
|
||||
local ent = ents.Create( self.GameEntities[self:GetEntID()][2] )
|
||||
ent:SetPos( tr.HitPos )
|
||||
ent:Spawn()
|
||||
end
|
||||
end
|
||||
end
|
||||
function SWEP:SecondaryAttack()
|
||||
if SERVER and IsValid( self.Owner ) then
|
||||
if not self.Owner:IsAdmin() then
|
||||
self.Owner:ChatPrint( "You are not allowed to use this tool!" )
|
||||
self:Remove()
|
||||
return
|
||||
end
|
||||
|
||||
local tr = self.Owner:GetEyeTrace()
|
||||
if IsValid(tr.Entity) and tr.Entity.IsChessEntity then tr.Entity:Remove() end
|
||||
end
|
||||
end
|
||||
function SWEP:Reload()
|
||||
if CLIENT then self:OpenMenu() end
|
||||
end
|
||||
|
||||
function SWEP:OpenMenu()
|
||||
if SERVER then return end
|
||||
if IsValid(self.Menu) then self.Menu:Remove() end
|
||||
|
||||
self.Menu = vgui.Create( "DFrame" )
|
||||
self.Menu:SetTitle( "Chess Admin Tool" )
|
||||
self.Menu:SetSize( 300, 80 )
|
||||
self.Menu:SetPos( ScrW()/2-150, ScrH()/2-50 )
|
||||
self.Menu:MakePopup()
|
||||
|
||||
local drop = vgui.Create( "DComboBox", self.Menu )
|
||||
drop:Dock( TOP )
|
||||
drop:SetValue( "Select Board" )
|
||||
for i=1,#self.GameEntities do
|
||||
drop:AddChoice( self.GameEntities[i][1], i )
|
||||
end
|
||||
drop.OnSelect = function( s, ind, val, data )
|
||||
RunConsoleCommand( "chess_admin_toolent", tostring(data) )
|
||||
end
|
||||
|
||||
local btnpnl = vgui.Create( "DPanel", self.Menu )
|
||||
btnpnl:Dock( BOTTOM )
|
||||
btnpnl:SetTall( 20 )
|
||||
btnpnl.Paint = function() end
|
||||
|
||||
local close = vgui.Create( "DButton", btnpnl )
|
||||
close:SetWidth( 98 )
|
||||
close:Dock( RIGHT )
|
||||
close:SetText( "Close" )
|
||||
close.DoClick = function(s) if IsValid(self) and IsValid(self.Menu) then self.Menu:Remove() end end
|
||||
|
||||
local rem = vgui.Create( "DButton", btnpnl )
|
||||
rem:SetWidth( 98 )
|
||||
rem:Dock( LEFT )
|
||||
rem:SetText( "Remove tool" )
|
||||
rem.DoClick = function(s)
|
||||
RunConsoleCommand( "chess_admin_toolremove" )
|
||||
if IsValid(self) and IsValid(self.Menu) then self.Menu:Remove() end
|
||||
end
|
||||
|
||||
local sv = vgui.Create( "DButton", btnpnl )
|
||||
sv:SetWidth( 98 )
|
||||
sv:Dock( FILL )
|
||||
sv:SetText( "Save boards" )
|
||||
sv.DoClick = function(s)
|
||||
RunConsoleCommand( "chess_save" )
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:OnRemove()
|
||||
if CLIENT and self.Ghosts then
|
||||
for _,v in pairs(self.Ghosts) do if IsValid(v) then v:Remove() end end
|
||||
end
|
||||
end
|
||||
function SWEP:Holster()
|
||||
if CLIENT then
|
||||
if self.Ghosts then
|
||||
for _,v in pairs(self.Ghosts) do if IsValid(v) then v:Remove() end end
|
||||
end
|
||||
return true
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
local function SetToolEnt( tool, index )
|
||||
if tool.GameEntities[index] then tool:SetEntID( index ) end
|
||||
end
|
||||
concommand.Add( "chess_admin_toolent", function(p,c,a)
|
||||
if IsValid(p:GetActiveWeapon()) and p:GetActiveWeapon():GetClass()=="chess_admin_tool" then
|
||||
SetToolEnt( p:GetActiveWeapon(), tonumber(a[1]) )
|
||||
end
|
||||
end)
|
||||
concommand.Add( "chess_admin_toolremove", function(p,c,a)
|
||||
if IsValid(p:GetActiveWeapon()) and p:GetActiveWeapon():GetClass()=="chess_admin_tool" then p:GetActiveWeapon():Remove() end
|
||||
end)
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
surface.CreateFont( "ChessAdmin", {
|
||||
font="Arial", size=40,
|
||||
})
|
||||
local ColBox = Color(0,0,0,150)
|
||||
local ColText = Color(255,255,255,255)
|
||||
local ColGhost = Color(0,255,0,150)
|
||||
function SWEP:DrawHUD()
|
||||
local w,h = ScrW(), ScrH()
|
||||
local txt = "Board: ".. tostring( self.GameEntities[self:GetEntID()][1] )
|
||||
|
||||
surface.SetFont( "ChessAdmin" )
|
||||
local tw, th = surface.GetTextSize( txt )
|
||||
|
||||
surface.SetDrawColor( ColBox )
|
||||
surface.DrawRect( (w/2) - ((tw/2)+3), h - (th+6), tw+6, th+6 )
|
||||
|
||||
draw.DrawText( txt, "ChessAdmin", w/2, h-(th)-3, ColText, TEXT_ALIGN_CENTER )
|
||||
end
|
||||
|
||||
function SWEP:DoGhosts()
|
||||
local tr = self.Owner:GetEyeTrace()
|
||||
if (not tr.Hit) then return end
|
||||
|
||||
self.Ghosts = self.Ghosts or {}
|
||||
local mdltbl = self.GameEntities[self:GetEntID()][3]
|
||||
if not mdltbl then return end
|
||||
|
||||
self.Ghosts[1] = IsValid(self.Ghosts[1]) and self.Ghosts[1] or ClientsideModel( mdltbl.table, RENDERGROUP_BOTH )
|
||||
self.Ghosts[1]:SetPos( tr.HitPos )
|
||||
self.Ghosts[1]:SetRenderMode( RENDERMODE_TRANSALPHA )
|
||||
self.Ghosts[1]:SetColor( ColGhost )
|
||||
|
||||
local h = 30 --(self.Ghosts[1]:OBBMaxs()[3] - self.Ghosts[1]:OBBMins()[3])
|
||||
self.Ghosts[2] = IsValid(self.Ghosts[2]) and self.Ghosts[2] or ClientsideModel( mdltbl.board, RENDERGROUP_BOTH )
|
||||
self.Ghosts[2]:SetPos( tr.HitPos+Vector(0,0,h or 50) )
|
||||
self.Ghosts[2]:SetAngles( Angle(-90,0,0) )
|
||||
self.Ghosts[2]:SetModelScale( 0.35, 0 )
|
||||
self.Ghosts[2]:SetRenderMode( RENDERMODE_TRANSALPHA )
|
||||
self.Ghosts[2]:SetColor( ColGhost )
|
||||
|
||||
self.Ghosts[3] = IsValid(self.Ghosts[3]) and self.Ghosts[3] or ClientsideModel( "models/nova/chair_plastic01.mdl", RENDERGROUP_BOTH )
|
||||
self.Ghosts[3]:SetPos( tr.HitPos+ (self.Ghosts[2]:GetRight()*40) )
|
||||
self.Ghosts[3]:SetRenderMode( RENDERMODE_TRANSALPHA )
|
||||
self.Ghosts[3]:SetColor( ColGhost )
|
||||
|
||||
self.Ghosts[4] = IsValid(self.Ghosts[4]) and self.Ghosts[4] or ClientsideModel( "models/nova/chair_plastic01.mdl", RENDERGROUP_BOTH )
|
||||
self.Ghosts[4]:SetPos( tr.HitPos+ (self.Ghosts[2]:GetRight()*-40) )
|
||||
self.Ghosts[4]:SetAngles( Angle(0,180,0) )
|
||||
self.Ghosts[4]:SetRenderMode( RENDERMODE_TRANSALPHA )
|
||||
self.Ghosts[4]:SetColor( ColGhost )
|
||||
end
|
||||
function SWEP:PostDrawViewModel()
|
||||
if LocalPlayer()~=self.Owner then return self.BaseClass.PostDrawViewModel( self ) end
|
||||
self:DoGhosts()
|
||||
end
|
||||
function SWEP:DrawWorldModel()
|
||||
if LocalPlayer()~=self.Owner then return self.BaseClass.DrawWorldModel( self ) end
|
||||
self:DrawModel()
|
||||
self:DoGhosts()
|
||||
end
|
||||
end
|
||||
312
lua/weapons/gmod_tool/stools/energyball.lua
Normal file
312
lua/weapons/gmod_tool/stools/energyball.lua
Normal file
@@ -0,0 +1,312 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
TOOL.Category = "Matrix_'s Effects"
|
||||
TOOL.Name = "#Energy ball"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
//Default values
|
||||
TOOL.ClientConVar["scale"] = 2
|
||||
TOOL.ClientConVar["emitparticles"] = 1
|
||||
TOOL.ClientConVar["sound"] = 0
|
||||
TOOL.ClientConVar["key"] = 5
|
||||
TOOL.ClientConVar["numpadcontrol"] = 0
|
||||
TOOL.ClientConVar["toggle"] = 0
|
||||
|
||||
//List of all spawned fire entities
|
||||
TOOL.EnergyBalls = {}
|
||||
|
||||
//Add language descriptions
|
||||
if (CLIENT) then
|
||||
language.Add("Tool.energyball.name", "Combine Energy Ball Tool")
|
||||
language.Add("Tool.energyball.desc", "Creates customizable ball of energy")
|
||||
language.Add("Tool.energyball.0", "Left-Click: Create energy ball Right-Click: Remove energy balls")
|
||||
language.Add("Cleanup_Energyballs", "Energy Balls")
|
||||
language.Add("Cleaned_Energyballs", "Cleaned up all Energy Balls")
|
||||
language.Add("SBoxLimit_Energyballs", "You've hit the Energy Balls limit!")
|
||||
language.Add("Undone_EnergyBall", "Energy Ball undone")
|
||||
end
|
||||
|
||||
|
||||
cleanup.Register("EnergyBalls")
|
||||
CreateConVar("sbox_maxenergyballs", 10000, FCVAR_NOTIFY)
|
||||
|
||||
|
||||
|
||||
function TOOL:LeftClick(trace)
|
||||
|
||||
if (CLIENT) then return true end
|
||||
|
||||
|
||||
local scale = math.Round(math.Clamp(self:GetClientNumber("scale"), .32, 15)) //Let's just retreive this here
|
||||
local findenergyballs = ents.FindInSphere( trace.HitPos, scale * scale )
|
||||
local success = false
|
||||
for _, energyball in pairs(findenergyballs) do
|
||||
|
||||
|
||||
if energyball && energyball:IsValid() && !energyball:GetPhysicsObject():IsValid() && energyball:GetClass() == "env_citadel_energy_core" && !energyball:IsPlayer() && !energyball:IsNPC() && !energyball:IsWorld() then
|
||||
|
||||
local DontRunTwice = false
|
||||
|
||||
|
||||
if !energyball.Charged then
|
||||
energyball:Fire("StartCharge", "4", 0)
|
||||
energyball.Charged = true
|
||||
DontRunTwice = true
|
||||
if energyball.Sound then
|
||||
energyball.Sound:Stop()
|
||||
sound.Play( "HL1/ambience/port_suckout1.wav", trace.HitPos, 72, 100 )
|
||||
timer.Simple( 2.62, function() if energyball && energyball.Sound then energyball.Sound:Stop() energyball.Sound = CreateSound(energyball, Sound("npc/combine_gunship/dropship_onground_loop1.wav")) energyball.Sound:PlayEx(0.72, 100) end end )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if !DontRunTwice && energyball.Charged then
|
||||
energyball:Fire("StartDischarge", "2", 0)
|
||||
energyball.Charged = false
|
||||
if energyball.Sound then
|
||||
energyball.Sound:Stop()
|
||||
sound.Play( "HL1/ambience/port_suckin1.wav", trace.HitPos, 72, 100 )
|
||||
energyball.Sound = CreateSound(energyball, Sound("npc/combine_gunship/engine_rotor_loop1.wav"))
|
||||
energyball.Sound:PlayEx(0.62, 100)
|
||||
end
|
||||
end
|
||||
|
||||
success = true
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
if success then return true end
|
||||
|
||||
|
||||
if (!self:GetSWEP():CheckLimit("energyballs")) then return false end
|
||||
|
||||
|
||||
local spawnflags
|
||||
if self:GetClientNumber("numpadcontrol") == 0 then spawnflags = 2 end
|
||||
if math.Round(math.Clamp(self:GetClientNumber("emitparticles"), 0, 1)) == 0 then spawnflags = spawnflags + 1 end
|
||||
|
||||
|
||||
local energyball = ents.Create("env_citadel_energy_core")
|
||||
if !energyball || !energyball:IsValid() then return false end
|
||||
energyball:SetPos(trace.HitPos)
|
||||
energyball:SetKeyValue("angles", tostring(trace.HitNormal:Angle()))
|
||||
energyball:SetKeyValue("scale", tostring(scale))
|
||||
if spawnflags then energyball:SetKeyValue("spawnflags", tostring(spawnflags)) end
|
||||
|
||||
|
||||
energyball:Spawn()
|
||||
energyball:Activate()
|
||||
energyball.Charged = false
|
||||
if trace && trace.Entity && trace.Entity:IsValid() && trace.Entity:GetPhysicsObject():IsValid() && !trace.Entity:IsPlayer() && !trace.Entity:IsWorld() then energyball:SetParent(trace.Entity) end
|
||||
|
||||
|
||||
if math.Round(math.Clamp(self:GetClientNumber("sound"), 0, 1)) == 1 then
|
||||
if self:GetClientNumber("numpadcontrol") == 0 then sound.Play( "weapons/physcannon/superphys_small_zap" .. math.random(1,4) .. ".wav", trace.HitPos, 52, 100 ) end
|
||||
energyball.Sound = CreateSound(energyball, Sound("npc/combine_gunship/engine_rotor_loop1.wav"))
|
||||
if self:GetClientNumber("numpadcontrol") == 0 then energyball.Sound:PlayEx(0.62, 100) end
|
||||
end
|
||||
|
||||
|
||||
self:GetOwner():AddCount("energyballs", energyball)
|
||||
table.insert(self.EnergyBalls, energyball)
|
||||
|
||||
|
||||
undo.Create("EnergyBall")
|
||||
undo.AddEntity(energyball)
|
||||
undo.SetPlayer(self:GetOwner())
|
||||
undo.Finish()
|
||||
cleanup.Add(self:GetOwner(), "EnergyBalls", energyball)
|
||||
|
||||
//Make sure we can control it with numpad
|
||||
if self:GetClientNumber("numpadcontrol") == 1 then
|
||||
self:SetupNumpadControls(energyball)
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
function TOOL:SetupNumpadControls(energyball)
|
||||
|
||||
|
||||
if !energyball || !energyball:IsValid() || self:GetClientInfo("key") == nil || self:GetClientInfo("key") == -1 then return false end
|
||||
|
||||
|
||||
if self:GetClientNumber("toggle") == 0 then
|
||||
|
||||
|
||||
local function StartEmitPlasma(ply, energyball)
|
||||
if !energyball || !energyball:IsValid() then return end
|
||||
|
||||
|
||||
if energyball.Charged then energyball:Fire("StartCharge", "1", 0) end
|
||||
if !energyball.Charged then energyball:Fire("StartDischarge", "1", 0) end
|
||||
|
||||
|
||||
if energyball.Sound then
|
||||
energyball.Sound:Stop()
|
||||
if !energyball.Charged then energyball.Sound = CreateSound(energyball, Sound("npc/combine_gunship/engine_rotor_loop1.wav")) energyball.Sound:PlayEx(0.62, 100) end
|
||||
if energyball.Charged then energyball.Sound = CreateSound(energyball, Sound("npc/combine_gunship/dropship_onground_loop1.wav")) energyball.Sound:PlayEx(0.72, 100) end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
//Register KeyDown functions
|
||||
numpad.Register("StartEmitPlasma", StartEmitPlasma)
|
||||
numpad.OnDown(self:GetOwner(), self:GetClientNumber("key"), "StartEmitPlasma", energyball)
|
||||
|
||||
//Create KeyUp numpad functions
|
||||
local function StopEmitPlasma(ply, energyball)
|
||||
if !energyball || !energyball:IsValid() then return end
|
||||
|
||||
//Stop energy discharge and related sounds
|
||||
if energyball.Sound then energyball.Sound:Stop() end
|
||||
energyball:Fire("Stop", "0.32", 0)
|
||||
|
||||
end
|
||||
|
||||
//Register KeyUp functions
|
||||
numpad.Register("StopEmitPlasma", StopEmitPlasma)
|
||||
numpad.OnUp(self:GetOwner(), self:GetClientNumber("key"), "StopEmitPlasma", energyball)
|
||||
|
||||
end
|
||||
|
||||
//If toggled
|
||||
if self:GetClientNumber("toggle") == 1 then
|
||||
|
||||
energyball.Toggle = false
|
||||
|
||||
//Create KeyDown numpad functions
|
||||
local function ToggleEmitPlasma(ply, energyball)
|
||||
if !energyball || !energyball:IsValid() then return end
|
||||
|
||||
//Start energy discharge
|
||||
if !energyball.Toggle then
|
||||
|
||||
//Energy discharge
|
||||
if energyball.Charged then energyball:Fire("StartCharge", "1", 0) end
|
||||
if !energyball.Charged then energyball:Fire("StartDischarge", "1", 0) end
|
||||
|
||||
//Related sounds
|
||||
if energyball.Sound then
|
||||
energyball.Sound:Stop()
|
||||
if !energyball.Charged then energyball.Sound = CreateSound(energyball, Sound("npc/combine_gunship/engine_rotor_loop1.wav")) energyball.Sound:PlayEx(0.62, 100) end
|
||||
if energyball.Charged then energyball.Sound = CreateSound(energyball, Sound("npc/combine_gunship/dropship_onground_loop1.wav")) energyball.Sound:PlayEx(0.72, 100) end
|
||||
end
|
||||
|
||||
energyball.Toggle = true
|
||||
return
|
||||
end
|
||||
|
||||
//Stop energy discharge and related sounds
|
||||
if energyball.Toggle then
|
||||
if energyball.Sound then sound.Play( "HL1/ambience/port_suckin1.wav", energyball:GetPos(), 62, 100 ) energyball.Sound:Stop() end
|
||||
energyball:Fire("Stop", "0.32", 0)
|
||||
energyball.Toggle = false
|
||||
return
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
//Register KeyDown functions
|
||||
numpad.Register("ToggleEmitPlasma", ToggleEmitPlasma)
|
||||
numpad.OnDown(self:GetOwner(), self:GetClientNumber("key"), "ToggleEmitPlasma", energyball)
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Remove energy balls in radius
|
||||
function TOOL:RightClick(trace)
|
||||
|
||||
//Clients don't need to know about any of this
|
||||
if (CLIENT) then return false end
|
||||
|
||||
//Find energy balls in radius
|
||||
local scale = math.Round(math.Clamp(self:GetClientNumber("scale"), .32, 15))
|
||||
local findenergyballs = ents.FindInSphere(trace.HitPos, scale * scale)
|
||||
for _, energyball in pairs(findenergyballs) do
|
||||
|
||||
//Remove
|
||||
if energyball && energyball:IsValid() && !energyball:GetPhysicsObject():IsValid() && energyball:GetClass() == "env_citadel_energy_core" && !energyball:IsPlayer() && !energyball:IsNPC() && !energyball:IsWorld() then
|
||||
if energyball.Sound then energyball.Sound:Stop() sound.Play( "HL1/ambience/port_suckin1.wav", energyball:GetPos(), 62, 100 ) end
|
||||
energyball:Fire("StartCharge", "2", 0)
|
||||
energyball:Fire("Kill", "", 0.21)
|
||||
//energyball:Fire("Stop", "0.21", 0)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Remove all energy balls
|
||||
function TOOL:Reload()
|
||||
|
||||
//Clients don't need to know about any of this
|
||||
if (CLIENT) then return false end
|
||||
|
||||
//Get all energy balls
|
||||
for x = 1, table.getn(self.EnergyBalls) do
|
||||
local energyball = self.EnergyBalls[x]
|
||||
|
||||
//Remove
|
||||
if energyball && energyball:IsValid() then
|
||||
if energyball.Sound then energyball.Sound:Stop() sound.Play( "HL1/ambience/port_suckin1.wav", energyball:GetPos(), 62, 100 ) end
|
||||
energyball:Fire("StartCharge", "2", 0)
|
||||
energyball:Fire("Kill", "", 0.21)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Precache all sounds
|
||||
function TOOL:Precache()
|
||||
util.PrecacheSound("weapons/physcannon/superphys_small_zap1.wav")
|
||||
util.PrecacheSound("weapons/physcannon/superphys_small_zap2.wav")
|
||||
util.PrecacheSound("weapons/physcannon/superphys_small_zap3.wav")
|
||||
util.PrecacheSound("weapons/physcannon/superphys_small_zap4.wav")
|
||||
util.PrecacheSound("HL1/ambience/port_suckin1.wav")
|
||||
util.PrecacheSound("npc/combine_gunship/dropship_onground_loop1.wav")
|
||||
util.PrecacheSound("npc/combine_gunship/engine_rotor_loop1.wav")
|
||||
end
|
||||
|
||||
|
||||
//Build Tool Menu
|
||||
function TOOL.BuildCPanel(panel)
|
||||
|
||||
//Header
|
||||
panel:AddControl( "Header", { Text = "#Tool.energyball.name", Description = "#Tool.energyball.desc" } )
|
||||
//Max delay
|
||||
panel:AddControl( "Slider", { Label = "Scale", Type = "Integer", Min = "1", Max = "15", Command ="energyball_scale" } )
|
||||
//Emit particles
|
||||
panel:AddControl( "CheckBox", { Label = "Particles", Description = "", Command = "energyball_emitparticles" } )
|
||||
//Make sounds
|
||||
panel:AddControl( "CheckBox", { Label = "Sound", Description = "", Command = "energyball_sound" } )
|
||||
|
||||
//-------------
|
||||
panel:AddControl( "Label", { Text = "________________________________________", Description = "" } )
|
||||
|
||||
//Numpad menu
|
||||
panel:AddControl( "Numpad", { Label = "Numpad Key", Command = "energyball_key", ButtonSize = 22 } )
|
||||
//Use numpad check
|
||||
panel:AddControl( "CheckBox", { Label = "Use numpad", Description = "", Command = "energyball_numpadcontrol" } )
|
||||
//Toggle check
|
||||
panel:AddControl( "CheckBox", { Label = "Toggle", Description = "", Command = "energyball_toggle" } )
|
||||
|
||||
end
|
||||
319
lua/weapons/gmod_tool/stools/env_headcrabcanister.lua
Normal file
319
lua/weapons/gmod_tool/stools/env_headcrabcanister.lua
Normal file
@@ -0,0 +1,319 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Half-Life 2"
|
||||
TOOL.Name = "#tool.env_headcrabcanister"
|
||||
|
||||
TOOL.Model = "models/props_combine/headcrabcannister01b.mdl"
|
||||
|
||||
TOOL.ClientConVar[ "key_fire" ] = "38"
|
||||
TOOL.ClientConVar[ "key_open" ] = "39"
|
||||
TOOL.ClientConVar[ "key_spawn" ] = "40"
|
||||
TOOL.ClientConVar[ "fire_immediately" ] = "0"
|
||||
TOOL.ClientConVar[ "headcrab" ] = "0"
|
||||
|
||||
TOOL.ClientConVar[ "count" ] = "6"
|
||||
TOOL.ClientConVar[ "speed" ] = "3000"
|
||||
TOOL.ClientConVar[ "time" ] = "5"
|
||||
TOOL.ClientConVar[ "height" ] = "0"
|
||||
|
||||
TOOL.ClientConVar[ "damage" ] = "150"
|
||||
TOOL.ClientConVar[ "radius" ] = "750"
|
||||
TOOL.ClientConVar[ "duration" ] = "30"
|
||||
TOOL.ClientConVar[ "smoke" ] = "0"
|
||||
|
||||
TOOL.ClientConVar[ "sf1" ] = "0"
|
||||
TOOL.ClientConVar[ "sf2" ] = "0"
|
||||
TOOL.ClientConVar[ "sf4096" ] = "0"
|
||||
TOOL.ClientConVar[ "sf16384" ] = "0"
|
||||
TOOL.ClientConVar[ "sf32768" ] = "0"
|
||||
TOOL.ClientConVar[ "sf65536" ] = "0"
|
||||
TOOL.ClientConVar[ "sf131072" ] = "0"
|
||||
TOOL.ClientConVar[ "sf262144" ] = "0"
|
||||
TOOL.ClientConVar[ "sf524288" ] = "0"
|
||||
|
||||
cleanup.Register( "env_headcrabcanisters" )
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
CreateConVar( "sbox_maxenv_headcrabcanisters", 4, FCVAR_ARCHIVE )
|
||||
|
||||
numpad.Register( "env_headcrabcanister_fire", function( ply, env_headcrabcanister )
|
||||
if ( !IsValid( env_headcrabcanister ) ) then return false end
|
||||
env_headcrabcanister:Fire( "FireCanister" )
|
||||
end )
|
||||
numpad.Register( "env_headcrabcanister_open", function( ply, env_headcrabcanister )
|
||||
if ( !IsValid( env_headcrabcanister ) ) then return false end
|
||||
env_headcrabcanister:Fire( "OpenCanister" )
|
||||
end )
|
||||
numpad.Register( "env_headcrabcanister_spawn", function( ply, env_headcrabcanister )
|
||||
if ( !IsValid( env_headcrabcanister ) ) then return false end
|
||||
env_headcrabcanister:Fire( "SpawnHeadcrabs" )
|
||||
end )
|
||||
|
||||
function MakeHeadcrabCanister( ply, model, pos, ang, keyFire, keyOpen, keySpawn, fire_immediately, headcrab, count, speed, time, height, damage, radius, duration, spawnflags, smoke, mapCreationID )
|
||||
if ( IsValid( ply ) and !ply:CheckLimit( "env_headcrabcanisters" ) ) then return false end
|
||||
|
||||
if ( tobool( smoke ) ) then duration = -1 end
|
||||
|
||||
fire_immediately = fire_immediately or false
|
||||
headcrab = headcrab or 0
|
||||
count = count or 6
|
||||
speed = speed or 3000
|
||||
time = time or 5
|
||||
height = height or 0
|
||||
damage = damage or 150
|
||||
radius = radius or 750
|
||||
duration = duration or 30
|
||||
spawnflags = spawnflags or 0
|
||||
|
||||
keyOpen = keyOpen or -1
|
||||
keyFire = keyFire or -1
|
||||
keySpawn = keySpawn or -1
|
||||
|
||||
if ( !game.SinglePlayer() ) then
|
||||
headcrab = math.Clamp( headcrab, 0, 2 )
|
||||
count = math.Clamp( count, 0, 10 )
|
||||
time = math.Clamp( time, 0, 30 )
|
||||
height = math.Clamp( height, 0, 10240 )
|
||||
damage = math.Clamp( damage, 0, 256 )
|
||||
radius = math.Clamp( radius, 0, 1024 )
|
||||
duration = math.Clamp( duration, 0, 90 )
|
||||
end
|
||||
|
||||
local env_headcrabcanister = ents.Create( "env_headcrabcanister" )
|
||||
if ( !IsValid( env_headcrabcanister ) ) then return false end
|
||||
env_headcrabcanister:SetPos( pos )
|
||||
env_headcrabcanister:SetAngles( ang )
|
||||
env_headcrabcanister:SetKeyValue( "HeadcrabType", headcrab )
|
||||
env_headcrabcanister:SetKeyValue( "HeadcrabCount", count )
|
||||
env_headcrabcanister:SetKeyValue( "FlightSpeed", speed )
|
||||
env_headcrabcanister:SetKeyValue( "FlightTime", time )
|
||||
env_headcrabcanister:SetKeyValue( "StartingHeight", height )
|
||||
env_headcrabcanister:SetKeyValue( "Damage", damage )
|
||||
env_headcrabcanister:SetKeyValue( "DamageRadius", radius )
|
||||
env_headcrabcanister:SetKeyValue( "SmokeLifetime", duration )
|
||||
env_headcrabcanister:SetKeyValue( "spawnflags", spawnflags )
|
||||
env_headcrabcanister:Spawn()
|
||||
env_headcrabcanister:Activate()
|
||||
|
||||
env_headcrabcanister.NumpadFire = numpad.OnDown( ply, keyFire, "env_headcrabcanister_fire", env_headcrabcanister )
|
||||
env_headcrabcanister.NumpadOpen = numpad.OnDown( ply, keyOpen, "env_headcrabcanister_open", env_headcrabcanister )
|
||||
env_headcrabcanister.NumpadSpawn = numpad.OnDown( ply, keySpawn, "env_headcrabcanister_spawn", env_headcrabcanister )
|
||||
|
||||
if ( tobool( fire_immediately ) ) then env_headcrabcanister:Fire( "FireCanister" ) end
|
||||
|
||||
table.Merge( env_headcrabcanister:GetTable(), {
|
||||
ply = ply,
|
||||
keyFire = keyFire,
|
||||
keyOpen = keyOpen,
|
||||
keySpawn = keySpawn,
|
||||
fire_immediately = fire_immediately,
|
||||
headcrab = headcrab,
|
||||
count = count,
|
||||
speed = speed,
|
||||
time = time,
|
||||
height = height,
|
||||
damage = damage,
|
||||
radius = radius,
|
||||
duration = duration,
|
||||
spawnflags = spawnflags,
|
||||
smoke = smoke,
|
||||
MapCreationID = mapCreationID
|
||||
} )
|
||||
|
||||
if ( IsValid( ply ) ) then
|
||||
ply:AddCount( "env_headcrabcanisters", env_headcrabcanister )
|
||||
ply:AddCleanup( "env_headcrabcanisters", env_headcrabcanister )
|
||||
end
|
||||
|
||||
DoPropSpawnedEffect( env_headcrabcanister )
|
||||
|
||||
if ( Wire_CreateOutputs and !mapCreationID ) then
|
||||
env_headcrabcanister.Inputs = Wire_CreateInputs( env_headcrabcanister, { "Open", "Spawn" } )
|
||||
|
||||
function env_headcrabcanister:TriggerInput( name, value )
|
||||
if ( name == "Open" and value > 0 ) then self:Fire( "OpenCanister" ) end
|
||||
if ( name == "Spawn" and value > 0 ) then self:Fire( "SpawnHeadcrabs" ) end
|
||||
end
|
||||
|
||||
rb655_hl2_CopyWireModMethods( env_headcrabcanister )
|
||||
end
|
||||
|
||||
return env_headcrabcanister
|
||||
end
|
||||
|
||||
duplicator.RegisterEntityClass( "env_headcrabcanister", MakeHeadcrabCanister, "model", "pos", "ang", "keyFire", "keyOpen", "keySpawn", "fire_immediately", "headcrab", "count", "speed", "time", "height", "damage", "radius", "duration", "spawnflags", "smoke", "MapCreationID" )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:IntrnlGetSF( str )
|
||||
return math.Clamp( self:GetClientNumber( str ), 0, 1 )
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( trace.HitSky or !trace.HitPos or trace.HitNormal.z < 0 ) then return false end
|
||||
if ( IsValid( trace.Entity ) and ( trace.Entity:GetClass() == "env_headcrabcanister" or trace.Entity:IsPlayer() or trace.Entity:IsNPC() ) ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
|
||||
local spawnflags = 0
|
||||
spawnflags = self:IntrnlGetSF( "sf1" ) + self:IntrnlGetSF( "sf2" ) * 2 + self:IntrnlGetSF( "sf4096" ) * 4096 + self:IntrnlGetSF( "sf16384" ) * 16384
|
||||
spawnflags = spawnflags + self:IntrnlGetSF( "sf32768" ) * 32768 + self:IntrnlGetSF( "sf65536" ) * 65536 + self:IntrnlGetSF( "sf131072" ) * 131072
|
||||
spawnflags = spawnflags + self:IntrnlGetSF( "sf262144" ) * 262144 + self:IntrnlGetSF( "sf524288" ) * 524288
|
||||
|
||||
local ang = Angle( math.sin( CurTime() ) * 16 - 55, trace.HitNormal:Angle().y, 0 )
|
||||
if ( trace.HitNormal.z > 0.9999 ) then ang.y = ply:GetAngles().y end
|
||||
|
||||
local env_headcrabcanister = MakeHeadcrabCanister(
|
||||
ply,
|
||||
self.Model,
|
||||
trace.HitPos,
|
||||
ang,
|
||||
self:GetClientNumber( "key_fire" ),
|
||||
self:GetClientNumber( "key_open" ),
|
||||
self:GetClientNumber( "key_spawn" ),
|
||||
self:GetClientNumber( "fire_immediately" ),
|
||||
self:GetClientNumber( "headcrab" ),
|
||||
self:GetClientNumber( "count" ),
|
||||
self:GetClientNumber( "speed" ),
|
||||
self:GetClientNumber( "time" ),
|
||||
self:GetClientNumber( "height" ),
|
||||
self:GetClientNumber( "damage" ),
|
||||
self:GetClientNumber( "radius" ),
|
||||
self:GetClientNumber( "duration" ),
|
||||
spawnflags,
|
||||
self:GetClientNumber( "smoke" )
|
||||
)
|
||||
|
||||
undo.Create( "env_headcrabcanister" )
|
||||
undo.AddEntity( env_headcrabcanister )
|
||||
undo.SetPlayer( ply )
|
||||
undo.Finish()
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:UpdateGhostEntity( ent, ply )
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local trace = ply:GetEyeTrace()
|
||||
|
||||
if ( !trace.Hit or trace.HitNormal.z < 0 ) then ent:SetNoDraw( true ) return end
|
||||
if ( IsValid( trace.Entity ) and ( trace.Entity:GetClass() == "env_headcrabcanister" or trace.Entity:IsPlayer() or trace.Entity:IsNPC() ) ) then ent:SetNoDraw( true ) return end
|
||||
|
||||
local min = ent:OBBMins()
|
||||
local ang = Angle( math.sin( CurTime() ) * 16 - 55, trace.HitNormal:Angle().y, 0 )
|
||||
if ( trace.HitNormal.z > 0.9999 ) then
|
||||
ang.y = ply:GetAngles().y
|
||||
ent:SetPos( trace.HitPos - trace.HitNormal * min.z - Vector( 0, 0, 16 ) )
|
||||
else
|
||||
ent:SetPos( trace.HitPos - trace.HitNormal )
|
||||
end
|
||||
|
||||
ent:SetAngles( ang )
|
||||
ent:SetNoDraw( false )
|
||||
end
|
||||
|
||||
function TOOL:Think()
|
||||
if ( !IsValid( self.GhostEntity ) or self.GhostEntity:GetModel() != self.Model ) then
|
||||
self:MakeGhostEntity( self.Model, Vector( 0, 0, 0 ), Angle( 0, 0, 0 ) )
|
||||
end
|
||||
|
||||
self:UpdateGhostEntity( self.GhostEntity, self:GetOwner() )
|
||||
end
|
||||
|
||||
|
||||
list.Set( "HeadcrabModels", "#npc_headcrab", { env_headcrabcanister_headcrab = "0" } )
|
||||
list.Set( "HeadcrabModels", "#npc_headcrab_fast", { env_headcrabcanister_headcrab = "1" } )
|
||||
list.Set( "HeadcrabModels", "#npc_headcrab_poison", { env_headcrabcanister_headcrab = "2" } )
|
||||
|
||||
if ( SERVER ) then return end
|
||||
|
||||
TOOL.Information = { { name = "left" } }
|
||||
|
||||
language.Add( "tool.env_headcrabcanister", "Headcrab Canisters" )
|
||||
language.Add( "tool.env_headcrabcanister.name", "Headcrab Canister Tool" )
|
||||
language.Add( "tool.env_headcrabcanister.desc", "Spawn headcrab canisters" )
|
||||
language.Add( "tool.env_headcrabcanister.left", "Spawn a headcrab canister" )
|
||||
|
||||
language.Add( "tool.env_headcrabcanister.fire", "Fire Headcrab Canister" )
|
||||
language.Add( "tool.env_headcrabcanister.fire_immediately", "Fire on spawn" )
|
||||
|
||||
language.Add( "tool.env_headcrabcanister.open", "Open The Canister" )
|
||||
language.Add( "tool.env_headcrabcanister.spawn", "Spawn headcrabs" )
|
||||
|
||||
language.Add( "tool.env_headcrabcanister.headcrab", "Headcrab Type" )
|
||||
language.Add( "tool.env_headcrabcanister.count", "Headcrab count:" )
|
||||
language.Add( "tool.env_headcrabcanister.speed", "Flight speed:" )
|
||||
language.Add( "tool.env_headcrabcanister.time", "Flight time:" )
|
||||
language.Add( "tool.env_headcrabcanister.height", "Starting height:" )
|
||||
language.Add( "tool.env_headcrabcanister.damage", "Impact damage:" )
|
||||
language.Add( "tool.env_headcrabcanister.radius", "Damage radius:" )
|
||||
language.Add( "tool.env_headcrabcanister.duration", "Smoke duration:" )
|
||||
language.Add( "tool.env_headcrabcanister.smoke", "Always smoke" )
|
||||
|
||||
language.Add( "tool.env_headcrabcanister.sf1", "No impact sound" )
|
||||
language.Add( "tool.env_headcrabcanister.sf2", "No launch sound" )
|
||||
language.Add( "tool.env_headcrabcanister.sf4096", "Start impacted" )
|
||||
language.Add( "tool.env_headcrabcanister.sf16384", "Wait for input to open" )
|
||||
language.Add( "tool.env_headcrabcanister.sf32768", "Wait for input to spawn headcrabs" )
|
||||
language.Add( "tool.env_headcrabcanister.sf65536", "No smoke" )
|
||||
language.Add( "tool.env_headcrabcanister.sf131072", "No shake" )
|
||||
language.Add( "tool.env_headcrabcanister.sf262144", "Remove on impact" )
|
||||
language.Add( "tool.env_headcrabcanister.sf524288", "No impact effects" )
|
||||
|
||||
language.Add( "Cleanup_env_headcrabcanisters", "Headcrab Canisters" )
|
||||
language.Add( "Cleaned_env_headcrabcanisters", "Cleaned up all Headcrab Canisters" )
|
||||
language.Add( "SBoxLimit_env_headcrabcanisters", "You've hit the Headcrab Canisters limit!" )
|
||||
language.Add( "Undone_env_headcrabcanister", "Headcrab Canister undone" )
|
||||
|
||||
language.Add( "max_env_headcrabcanisters", "Max Headcrab Canisters:" )
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( panel )
|
||||
panel:AddControl( "ComboBox", { MenuButton = 1, Folder = "env_headcrabcanister", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
panel:AddControl( "Numpad", { Label = "#tool.env_headcrabcanister.fire", Command = "env_headcrabcanister_key_fire" } )
|
||||
panel:AddControl( "Checkbox", { Label = "#tool.env_headcrabcanister.fire_immediately", Command = "env_headcrabcanister_fire_immediately" } )
|
||||
|
||||
panel:AddControl( "Numpad", { Label = "#tool.env_headcrabcanister.open", Command = "env_headcrabcanister_key_open", Label2 = "#tool.env_headcrabcanister.spawn", Command2 = "env_headcrabcanister_key_spawn" } )
|
||||
panel:AddControl( "Checkbox", { Label = "#tool.env_headcrabcanister.sf16384", Command = "env_headcrabcanister_sf16384" } )
|
||||
panel:AddControl( "Checkbox", { Label = "#tool.env_headcrabcanister.sf32768", Command = "env_headcrabcanister_sf32768" } )
|
||||
|
||||
panel:AddControl( "ListBox", { Label = "#tool.env_headcrabcanister.headcrab", Height = 68, Options = list.Get( "HeadcrabModels" ) } )
|
||||
|
||||
panel:AddControl( "Slider", { Label = "#tool.env_headcrabcanister.count", Max = 10, Command = "env_headcrabcanister_count" } )
|
||||
|
||||
panel:AddControl( "Slider", { Label = "#tool.env_headcrabcanister.speed", Type = "Float", Min = 1, Max = 8192, Command = "env_headcrabcanister_speed" } )
|
||||
panel:AddControl( "Slider", { Label = "#tool.env_headcrabcanister.time", Type = "Float", Max = 30, Command = "env_headcrabcanister_time" } )
|
||||
|
||||
panel:AddControl( "Slider", { Label = "#tool.env_headcrabcanister.height", Type = "Float", Max = 10240, Command = "env_headcrabcanister_height" } )
|
||||
|
||||
panel:AddControl( "Slider", { Label = "#tool.env_headcrabcanister.damage", Type = "Float", Max = 256, Command = "env_headcrabcanister_damage" } )
|
||||
panel:AddControl( "Slider", { Label = "#tool.env_headcrabcanister.radius", Type = "Float", Max = 1024, Command = "env_headcrabcanister_radius" } )
|
||||
|
||||
panel:AddControl( "Slider", { Label = "#tool.env_headcrabcanister.duration", Type = "Float", Max = 90, Command = "env_headcrabcanister_duration" } )
|
||||
panel:AddControl( "Checkbox", { Label = "#tool.env_headcrabcanister.smoke", Command = "env_headcrabcanister_smoke" } )
|
||||
|
||||
panel:AddControl( "Checkbox", { Label = "#tool.env_headcrabcanister.sf2", Command = "env_headcrabcanister_sf2" } )
|
||||
panel:AddControl( "Checkbox", { Label = "#tool.env_headcrabcanister.sf1", Command = "env_headcrabcanister_sf1" } )
|
||||
panel:AddControl( "Checkbox", { Label = "#tool.env_headcrabcanister.sf65536", Command = "env_headcrabcanister_sf65536" } )
|
||||
panel:AddControl( "Checkbox", { Label = "#tool.env_headcrabcanister.sf131072", Command = "env_headcrabcanister_sf131072" } )
|
||||
|
||||
panel:AddControl( "Checkbox", { Label = "#tool.env_headcrabcanister.sf524288", Command = "env_headcrabcanister_sf524288" } )
|
||||
panel:AddControl( "Checkbox", { Label = "#tool.env_headcrabcanister.sf4096", Command = "env_headcrabcanister_sf4096" } )
|
||||
panel:AddControl( "Checkbox", { Label = "#tool.env_headcrabcanister.sf262144", Command = "env_headcrabcanister_sf262144" } )
|
||||
end
|
||||
221
lua/weapons/gmod_tool/stools/fire.lua
Normal file
221
lua/weapons/gmod_tool/stools/fire.lua
Normal file
@@ -0,0 +1,221 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
TOOL.Category = "Matrix_'s Effects"
|
||||
TOOL.Name = "#Fire"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
//Default values
|
||||
TOOL.ClientConVar["lifetime"] = 4
|
||||
TOOL.ClientConVar["infinite"] = 0
|
||||
TOOL.ClientConVar["size"] = 64
|
||||
TOOL.ClientConVar["smoke"] = 1
|
||||
TOOL.ClientConVar["glow"] = 1
|
||||
TOOL.ClientConVar["makesound"] = 1
|
||||
TOOL.ClientConVar["drop"] = 1
|
||||
TOOL.ClientConVar["key"] = 5
|
||||
TOOL.ClientConVar["numpadcontrol"] = 0
|
||||
|
||||
//List of all spawned fire entities
|
||||
TOOL.Fires = {}
|
||||
|
||||
//Add language descriptions
|
||||
if (CLIENT) then
|
||||
language.Add("Tool.fire.name", "Fire Tool")
|
||||
language.Add("Tool.fire.desc", "Creates customizable fire")
|
||||
language.Add("Tool.fire.0", "Left-Click: Make a fire Right-Click: Extinguish fire")
|
||||
language.Add("Cleanup_Fire", "Fires")
|
||||
language.Add("Cleaned_Fire", "Cleaned up all Fires")
|
||||
language.Add("SBoxLimit_fires", "You've hit the Fires limit!")
|
||||
language.Add("Undone_Fire", "Fire undone")
|
||||
end
|
||||
|
||||
//Sandbox-related stuff
|
||||
cleanup.Register("Fire")
|
||||
CreateConVar("sbox_maxfires", 10000, FCVAR_NOTIFY)
|
||||
|
||||
|
||||
//Make a fire
|
||||
function TOOL:LeftClick(trace)
|
||||
|
||||
//Clients don't need to know about any of this
|
||||
if (CLIENT) then return true end
|
||||
|
||||
//Check current spawnlimits
|
||||
if (!self:GetSWEP():CheckLimit("fires")) then return false end
|
||||
|
||||
//Retreive settings
|
||||
local spawnflags = 128 //Delete on extinguish
|
||||
local lifetime = math.Round(math.Clamp(self:GetClientNumber("lifetime"), 1, 512))
|
||||
local size = math.Round(math.Clamp(self:GetClientNumber("size"), 32, 128))
|
||||
if math.Round(math.Clamp(self:GetClientNumber("infinite"), 0, 1)) == 1 then spawnflags = spawnflags + 1 end
|
||||
if math.Round(math.Clamp(self:GetClientNumber("smoke"), 0, 1)) == 0 then spawnflags = spawnflags + 2 end
|
||||
if math.Round(math.Clamp(self:GetClientNumber("glow"), 0, 1)) == 0 then spawnflags = spawnflags + 32 end
|
||||
if math.Round(math.Clamp(self:GetClientNumber("drop"), 0, 1)) == 0 then spawnflags = spawnflags + 16 end
|
||||
|
||||
//Create fire and assign settings
|
||||
local fire = ents.Create("env_fire")
|
||||
if !fire || !fire:IsValid() then return false end
|
||||
fire:SetPos(trace.HitPos)
|
||||
fire:SetKeyValue("health", tostring(lifetime))
|
||||
fire:SetKeyValue("firesize", tostring(size))
|
||||
fire:SetKeyValue("fireattack", tostring(math.random(0.72,1.32)))
|
||||
fire:SetKeyValue("damagescale", "-1")
|
||||
fire:SetKeyValue("ignitionpoint", "1200") //Don't ignite from nearby fire
|
||||
fire:SetKeyValue("spawnflags", tostring(spawnflags))
|
||||
|
||||
//Spawn fire
|
||||
fire:Spawn()
|
||||
fire:Activate()
|
||||
if math.Round(math.Clamp(self:GetClientNumber("numpadcontrol"), 0, 1)) == 0 then fire:Fire("StartFire","",0) end
|
||||
|
||||
//Make fire emit burning sounds
|
||||
if math.Round(math.Clamp(self:GetClientNumber("makesound"), 0, 1)) == 1 then
|
||||
if math.Round(math.Clamp(self:GetClientNumber("numpadcontrol"), 0, 1)) == 0 then sound.Play( "ambient/fire/ignite.wav", trace.HitPos, 72, 100 ) end
|
||||
fire.Sound = CreateSound(fire, Sound("ambient/fire/fire_small_loop" .. math.random(1,2) .. ".wav"))
|
||||
if math.Round(math.Clamp(self:GetClientNumber("numpadcontrol"), 0, 1)) == 0 then fire.Sound:PlayEx(0.82, 100) end
|
||||
if math.Round(math.Clamp(self:GetClientNumber("infinite"), 0, 1)) == 0 then timer.Simple( (lifetime+1), function() if fire && fire:IsValid() then fire.Sound:Stop() end end ) end
|
||||
end
|
||||
|
||||
//Add to relevant lists
|
||||
self:GetOwner():AddCount("fires", fire)
|
||||
table.insert(self.Fires, fire)
|
||||
|
||||
//Make sure we can undo
|
||||
undo.Create("Fire")
|
||||
undo.AddEntity(fire)
|
||||
undo.SetPlayer(self:GetOwner())
|
||||
undo.Finish()
|
||||
cleanup.Add(self:GetOwner(), "Fire", fire)
|
||||
|
||||
//Make sure we can control it with numpad
|
||||
if math.Round(math.Clamp(self:GetClientNumber("numpadcontrol"), 0, 1)) == 1 then
|
||||
self:SetupNumpadControls(fire)
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Setup numpad controls
|
||||
function TOOL:SetupNumpadControls(fire)
|
||||
|
||||
//Safeguards
|
||||
if !fire || !fire:IsValid() || self:GetClientInfo("key") == nil || self:GetClientInfo("key") == -1 then return false end
|
||||
|
||||
//Retrieve tool settings
|
||||
local infinite = math.Round(math.Clamp(self:GetClientNumber("infinite"), 0, 1))
|
||||
local lifetime = math.Round(math.Clamp(self:GetClientNumber("lifetime"), 1, 512))
|
||||
|
||||
//Create KeyDown numpad functions
|
||||
local function StartEmitFire(ply, fire, infinite, lifetime)
|
||||
if fire.Started || !fire || !fire:IsValid() then return end
|
||||
|
||||
//Start fire and related sounds
|
||||
if fire.Sound then fire.Sound:Stop() end
|
||||
sound.Play( "ambient/fire/ignite.wav", fire:GetPos(), 72, 100 )
|
||||
fire.Sound = CreateSound(fire, Sound("ambient/fire/fire_small_loop" .. math.random(1,2) .. ".wav"))
|
||||
if infinite == 0 then timer.Simple( (lifetime+1), function() if fire && fire:IsValid() then fire.Sound:Stop() end end ) end
|
||||
fire.Sound:PlayEx(0.82, 100)
|
||||
fire:Fire("StartFire", "", 0)
|
||||
|
||||
fire.Started = true
|
||||
|
||||
end
|
||||
|
||||
//Register KeyDown functions
|
||||
numpad.Register("StartEmitFire", StartEmitFire)
|
||||
numpad.OnDown(self:GetOwner(), self:GetClientNumber("key"), "StartEmitFire", fire, infinite, lifetime)
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Extinguish fire in radius
|
||||
function TOOL:RightClick(trace)
|
||||
|
||||
//Clients don't need to know about any of this
|
||||
if (CLIENT) then return false end
|
||||
|
||||
//Find fire in radius
|
||||
local findfire = ents.FindInSphere(trace.HitPos, 42)
|
||||
for _, fire in pairs(findfire) do
|
||||
|
||||
//Extinguish
|
||||
if fire && fire:IsValid() && !fire:GetPhysicsObject():IsValid() && fire:GetClass() == "env_fire" && !fire:IsPlayer() && !fire:IsNPC() && !fire:IsWorld() then
|
||||
if fire.Sound then sound.Play( "ambient/levels/canals/toxic_slime_sizzle3.wav", fire:GetPos(), 68, 100 ) fire.Sound:Stop() end
|
||||
fire:Fire("Extinguish", "", 0)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Extinguish all fires
|
||||
function TOOL:Reload()
|
||||
|
||||
//Clients don't need to know about any of this
|
||||
if (CLIENT) then return false end
|
||||
|
||||
//Get all on-going fires
|
||||
for x = 1, table.getn(self.Fires) do
|
||||
local fire = self.Fires[x]
|
||||
|
||||
//Extinguish
|
||||
if fire && fire:IsValid() then
|
||||
if fire.Sound then sound.Play( "ambient/levels/canals/toxic_slime_sizzle3.wav", fire:GetPos(), 64, 100 ) fire.Sound:Stop() end
|
||||
fire:Fire("Extinguish", "", 0)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Precache all sounds
|
||||
function TOOL:Precache()
|
||||
util.PrecacheSound("ambient/fire/ignite.wav")
|
||||
util.PrecacheSound("ambient/fire/fire_small_loop1.wav")
|
||||
util.PrecacheSound("ambient/fire/fire_small_loop2.wav")
|
||||
util.PrecacheSound("ambient/levels/canals/toxic_slime_sizzle3.wav")
|
||||
end
|
||||
|
||||
|
||||
//Build Tool Menu
|
||||
function TOOL.BuildCPanel(panel)
|
||||
|
||||
//Header
|
||||
panel:AddControl( "Header", { Text = "#Tool.fire.name", Description = "#Tool.fire.desc" } )
|
||||
//Lifetime
|
||||
panel:AddControl( "Slider", { Label = "Lifetime", Type = "Integer", Min = "1", Max = "60", Command ="fire_lifetime" } )
|
||||
//Infite lifetime
|
||||
panel:AddControl( "CheckBox", { Label = "Infinite", Description = "Burn infinitely", Command = "fire_infinite" } )
|
||||
//Size
|
||||
panel:AddControl( "Slider", { Label = "Size", Type = "Integer", Min = "32", Max = "128", Command ="fire_size" } )
|
||||
//Smoke
|
||||
panel:AddControl( "CheckBox", { Label = "Smoke", Description = "", Command = "fire_smoke" } )
|
||||
//Glow
|
||||
panel:AddControl( "CheckBox", { Label = "Glow", Description = "", Command = "fire_glow" } )
|
||||
//Sound
|
||||
panel:AddControl( "CheckBox", { Label = "Sound", Description = "", Command = "fire_makesound" } )
|
||||
//Drop to ground
|
||||
panel:AddControl( "CheckBox", { Label = "Drop to ground", Description = "", Command = "fire_drop" } )
|
||||
|
||||
//-------------
|
||||
panel:AddControl( "Label", { Text = "________________________________________", Description = "" } )
|
||||
|
||||
//Numpad menu
|
||||
panel:AddControl( "Numpad", { Label = "Numpad Key", Command = "fire_key", ButtonSize = 22 } )
|
||||
//Use numpad check
|
||||
panel:AddControl( "CheckBox", { Label = "Ignite with numpad", Description = "", Command = "fire_numpadcontrol" } )
|
||||
|
||||
end
|
||||
213
lua/weapons/gmod_tool/stools/glow.lua
Normal file
213
lua/weapons/gmod_tool/stools/glow.lua
Normal file
@@ -0,0 +1,213 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
TOOL.Category = "Matrix_'s Effects"
|
||||
TOOL.Name = "#Glow"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
//Default values
|
||||
TOOL.ClientConVar["color_r"] = 255
|
||||
TOOL.ClientConVar["color_g"] = 255
|
||||
TOOL.ClientConVar["color_b"] = 255
|
||||
TOOL.ClientConVar["verticalsize"] = 32
|
||||
TOOL.ClientConVar["horizontalsize"] = 32
|
||||
TOOL.ClientConVar["mindist"] = 16
|
||||
TOOL.ClientConVar["maxdist"] = 256
|
||||
TOOL.ClientConVar["outermaxdist"] = 2048
|
||||
TOOL.ClientConVar["glowthrough"] = 0
|
||||
TOOL.ClientConVar["toobject"] = 0
|
||||
|
||||
//List of all spawned fire entities
|
||||
TOOL.Glows = {}
|
||||
|
||||
//Add language descriptions
|
||||
if (CLIENT) then
|
||||
language.Add("Tool.glow.name", "Glow Tool")
|
||||
language.Add("Tool.glow.desc", "Creates customizable light glow")
|
||||
language.Add("Tool.glow.0", "Left-Click: Create glow Right-Click: Remove glow")
|
||||
language.Add("Cleanup_Glows", "Glows")
|
||||
language.Add("Cleaned_Glows", "Cleaned up all Glows")
|
||||
language.Add("SBoxLimit_glows", "You've hit the Glows limit!")
|
||||
language.Add("Undone_Glow", "Glow undone")
|
||||
end
|
||||
|
||||
//Sandbox-related stuff
|
||||
cleanup.Register("Glows")
|
||||
CreateConVar("sbox_maxglows", 10000, FCVAR_NOTIFY)
|
||||
|
||||
|
||||
//Create sparks
|
||||
function TOOL:LeftClick(trace)
|
||||
|
||||
//Clients don't need to know about any of this
|
||||
if (CLIENT) then return true end
|
||||
|
||||
//Check current spawnlimits
|
||||
if (!self:GetSWEP():CheckLimit("glows")) then return false end
|
||||
|
||||
//Find and remove attached glows
|
||||
if math.Round(math.Clamp(self:GetClientNumber("toobject"), 0, 1)) == 1 && trace.Entity && trace.Entity:IsValid() && !trace.Entity:IsPlayer() && !trace.Entity:IsWorld() && trace.Entity.Glow && trace.Entity.Glow:IsValid() then
|
||||
trace.Entity.Glow:Fire("Kill", "", 0)
|
||||
end
|
||||
|
||||
//Retreive settings
|
||||
local color_r = math.Round(math.Clamp(self:GetClientNumber("color_r"), 0, 255))
|
||||
local color_g = math.Round(math.Clamp(self:GetClientNumber("color_g"), 0, 255))
|
||||
local color_b = math.Round(math.Clamp(self:GetClientNumber("color_b"), 0, 255))
|
||||
local verticalsize = math.Round(math.Clamp(self:GetClientNumber("verticalsize"), 1, 256))
|
||||
local horizontalsize = math.Round(math.Clamp(self:GetClientNumber("horizontalsize"), 1, 256))
|
||||
local mindist = math.Round(math.Clamp(self:GetClientNumber("mindist"), 1, 8192))
|
||||
local maxdist = math.Round(math.Clamp(self:GetClientNumber("maxdist"), 1, 8192))
|
||||
local outermaxdist = math.Round(math.Clamp(self:GetClientNumber("outermaxdist"), 1, 8192))
|
||||
|
||||
//Original distance formula
|
||||
//local mindist = maxdist / 16
|
||||
//local outermaxdist = maxdist * 8
|
||||
|
||||
//Create glow and assign settings
|
||||
local glow = ents.Create("env_lightglow")
|
||||
if !glow || !glow:IsValid() then return false end
|
||||
glow:SetPos(trace.HitPos)
|
||||
//glow:SetAngles(self:GetOwner():GetAngles())
|
||||
glow:SetKeyValue("HDRColorScale", "1")
|
||||
glow:SetKeyValue("rendercolor", "" .. tostring(color_r) .. " " .. tostring(color_g) .. " " .. tostring(color_b) .. "")
|
||||
glow:SetKeyValue("VerticalGlowSize", tostring(verticalsize))
|
||||
glow:SetKeyValue("HorizontalGlowSize", tostring(horizontalsize))
|
||||
glow:SetKeyValue("MaxDist", tostring(maxdist))
|
||||
glow:SetKeyValue("MinDist", tostring(mindist))
|
||||
glow:SetKeyValue("OuterMaxDist", tostring(outermaxdist))
|
||||
if math.Round(math.Clamp(self:GetClientNumber("glowthrough"), 0, 1)) == 1 then glow:SetKeyValue("GlowProxySize", tostring( (verticalsize + horizontalsize) / 3 )) else glow:SetKeyValue("GlowProxySize", "0") end
|
||||
//glow:SetKeyValue("spawnflags", "1")
|
||||
|
||||
//Center to object if told to
|
||||
if math.Round(math.Clamp(self:GetClientNumber("toobject"), 0, 1)) == 1 && trace.Entity && trace.Entity:IsValid() && !trace.Entity:IsPlayer() && !trace.Entity:IsWorld() then
|
||||
glow:SetPos(trace.Entity:LocalToWorld(trace.Entity:OBBCenter()))
|
||||
glow:SetKeyValue("GlowProxySize", tostring(trace.Entity:BoundingRadius()))
|
||||
trace.Entity.Glow = glow
|
||||
end
|
||||
|
||||
//Spawn glow
|
||||
glow:Spawn()
|
||||
glow:Activate()
|
||||
if trace && trace.Entity && trace.Entity:IsValid() && trace.Entity:GetPhysicsObject():IsValid() && !trace.Entity:IsPlayer() && !trace.Entity:IsWorld() then glow:SetParent(trace.Entity) end
|
||||
//WorldSound( "weapons/ar2/ar2_reload_push.wav", trace.HitPos, 72, 100 )
|
||||
|
||||
//Add to relevant lists
|
||||
self:GetOwner():AddCount("glows", glow)
|
||||
table.insert(self.Glows, glow)
|
||||
|
||||
//Make sure we can undo
|
||||
undo.Create("Glow")
|
||||
undo.AddEntity(glow)
|
||||
undo.SetPlayer(self:GetOwner())
|
||||
undo.Finish()
|
||||
cleanup.Add(self:GetOwner(), "Glows", glow)
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Remove sparks in radius
|
||||
function TOOL:RightClick(trace)
|
||||
|
||||
//Clients don't need to know about any of this
|
||||
if (CLIENT) then return false end
|
||||
|
||||
//Find and remove attached glows
|
||||
if trace.Entity && trace.Entity:IsValid() && trace.Entity.Glow && trace.Entity.Glow:IsValid() then
|
||||
trace.Entity.Glow:Fire("Kill", "", 0)
|
||||
end
|
||||
|
||||
//Find glows in radius
|
||||
local findglows = ents.FindInSphere( trace.HitPos, ((math.Round(math.Clamp(self:GetClientNumber("verticalsize"), 1, 256)) + math.Round(math.Clamp(self:GetClientNumber("horizontalsize"), 1, 256)))/2) )
|
||||
for _, glow in pairs(findglows) do
|
||||
|
||||
//Remove
|
||||
if glow && glow:IsValid() && !glow:GetPhysicsObject():IsValid() && glow:GetClass() == "env_lightglow" && !glow:IsPlayer() && !glow:IsNPC() && !glow:IsWorld() then
|
||||
glow:Fire("Kill", "", 0)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Remove all sparks
|
||||
function TOOL:Reload()
|
||||
|
||||
//Clients don't need to know about any of this
|
||||
if (CLIENT) then return false end
|
||||
|
||||
//Get all glows
|
||||
for x = 1, table.getn(self.Glows) do
|
||||
local glow = self.Glows[x]
|
||||
|
||||
//Remove
|
||||
if glow && glow:IsValid() then
|
||||
glow:Fire("Kill", "", 0)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Build Tool Menu
|
||||
function TOOL.BuildCPanel(panel)
|
||||
|
||||
//Header
|
||||
panel:AddControl( "Header", { Text = "#Tool.glow.name", Description = "#Tool.glow.desc" } )
|
||||
|
||||
//Build preset menu and declare default preset
|
||||
local params = { Label = "#Presets", MenuButton = 1, Folder = "glow", Options = {}, CVars = {} }
|
||||
|
||||
//Declare default preset
|
||||
params.Options.default = {
|
||||
glow_color_r = 255,
|
||||
glow_color_g = 255,
|
||||
glow_color_b = 255,
|
||||
glow_verticalsize = 32,
|
||||
glow_horizontalsize = 32,
|
||||
glow_maxdist = 16,
|
||||
glow_maxdist = 256,
|
||||
glow_outermaxdist = 2048,
|
||||
}
|
||||
|
||||
//Declare console variables
|
||||
table.insert( params.CVars, "glow_color_r" )
|
||||
table.insert( params.CVars, "glow_color_g" )
|
||||
table.insert( params.CVars, "glow_color_b" )
|
||||
table.insert( params.CVars, "glow_verticalsize" )
|
||||
table.insert( params.CVars, "glow_horizontalsize" )
|
||||
table.insert( params.CVars, "glow_mindist" )
|
||||
table.insert( params.CVars, "glow_maxdist" )
|
||||
table.insert( params.CVars, "glow_outermaxdist" )
|
||||
|
||||
//All done
|
||||
panel:AddControl( "ComboBox", params )
|
||||
|
||||
//Color picker
|
||||
panel:AddControl( "Color", { Label = "Glow color", Red = "glow_color_r", Green = "glow_color_g", Blue = "glow_color_b", ShowAlpha = "0", ShowHSV = "1", ShowRGB = "1", Multiplier = "255" } )
|
||||
//Vertical Size
|
||||
panel:AddControl( "Slider", { Label = "Vertical Size", Type = "Float", Min = "1", Max = "256", Command ="glow_verticalsize" } )
|
||||
//Horizontal Size
|
||||
panel:AddControl( "Slider", { Label = "Horizontal Size", Type = "Float", Min = "1", Max = "256", Command ="glow_horizontalsize" } )
|
||||
//Minimum Distance Scale
|
||||
panel:AddControl( "Slider", { Label = "Minimum Visibility Distance", Type = "Float", Min = "1", Max = "1024", Command ="glow_mindist" } )
|
||||
//Visibility Distance Scale
|
||||
panel:AddControl( "Slider", { Label = "Optimal Visibility Distance", Type = "Float", Min = "1", Max = "1024", Command ="glow_maxdist" } )
|
||||
//Maximum Distance Scale
|
||||
panel:AddControl( "Slider", { Label = "Maximum Visibility Distance", Type = "Float", Min = "1", Max = "1024", Command ="glow_outermaxdist" } )
|
||||
//Glow through object
|
||||
panel:AddControl( "CheckBox", { Label = "Glow through object", Description = "", Command = "glow_glowthrough" } )
|
||||
//Center to object
|
||||
panel:AddControl( "CheckBox", { Label = "Center to object", Description = "", Command = "glow_toobject" } )
|
||||
|
||||
end
|
||||
243
lua/weapons/gmod_tool/stools/headcrabcanister.lua
Normal file
243
lua/weapons/gmod_tool/stools/headcrabcanister.lua
Normal file
@@ -0,0 +1,243 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
// STool by Nekres ( 4ndy )
|
||||
TOOL.Category = "Half-Life 2"
|
||||
TOOL.Name = "#tool.headcrabcanister"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
TOOL.ClientConVar["damage"] = 130 --damage of each canister
|
||||
TOOL.ClientConVar["damage_radius"] = 700 --explode radius of canister
|
||||
TOOL.ClientConVar["speed"] = 3000 --speed of cannister while fly in
|
||||
TOOL.ClientConVar["height"] = 2000 --how high in the sky. 0 means height from the skybox
|
||||
TOOL.ClientConVar["flight_time"] = 5 --how long the cannister 'fly in'
|
||||
TOOL.ClientConVar["smoke"] = -1 --smoke lifetime of the cannister. -1 means always smoke
|
||||
TOOL.ClientConVar["headcrab_type"] = "models/headcrabclassic.mdl"
|
||||
TOOL.ClientConVar["headcrab_count"] = 4
|
||||
TOOL.ClientConVar["height_skybox"] = "0"
|
||||
TOOL.ClientConVar["smoke_always"] = "0"
|
||||
|
||||
TOOL.ClientConVar["fire"] = "38"
|
||||
TOOL.ClientConVar["solid"] = "37"
|
||||
|
||||
cleanup.Register("prop_headcrabcanister")
|
||||
|
||||
if (CLIENT) then
|
||||
language.Add("tool.headcrabcanister", "Headcrabcanister")
|
||||
language.Add("tool.headcrabcanister.name", "Headcrabcanister Tool")
|
||||
language.Add("tool.headcrabcanister.desc", "Spawn a Headcrabcanister")
|
||||
language.Add("tool.headcrabcanister.0", "Left click to spawn an custom adjusted Headcrabcanister.")
|
||||
|
||||
language.Add("tool.headcrabcanister.fire", "Fire Canister")
|
||||
language.Add("tool.headcrabcanister.solid", "Toggle Solid")
|
||||
language.Add("tool.headcrabcanister.headcrab_type", "Headcrab Type")
|
||||
language.Add("tool.headcrabcanister.headcrab_count", "Headcrab Count")
|
||||
language.Add("tool.headcrabcanister.headcrab_count.help", "Number of headcrabs to spawn on impact.")
|
||||
|
||||
language.Add("tool.headcrabcanister.damage", "Damage")
|
||||
language.Add("tool.headcrabcanister.damage.help", "Max damage the canister applies on impact.")
|
||||
|
||||
language.Add("tool.headcrabcanister.damage_radius", "Damage Radius")
|
||||
language.Add("tool.headcrabcanister.damage_radius.help", "Max radius of the impact damage for the canister.")
|
||||
|
||||
language.Add("tool.headcrabcanister.speed", "Flight Speed")
|
||||
language.Add("tool.headcrabcanister.speed.help", "Speed to fly through the air.")
|
||||
|
||||
language.Add("tool.headcrabcanister.height", "Starting Height")
|
||||
language.Add("tool.headcrabcanister.height.help", "Relative height from the landing position at which the canister should be launched.")
|
||||
language.Add("tool.headcrabcanister.height_skybox", "Start from skybox height")
|
||||
|
||||
language.Add("tool.headcrabcanister.flight_time", "Flight Time")
|
||||
language.Add("tool.headcrabcanister.flight_time.help", "Time to fly through the air in seconds.")
|
||||
|
||||
language.Add("tool.headcrabcanister.smoke", "Smoke Duration")
|
||||
language.Add("tool.headcrabcanister.smoke.help", "Duration that the canister smokes in seconds.")
|
||||
language.Add("tool.headcrabcanister.smoke_always", "Always smoke")
|
||||
language.Add("tool.headcrabcanister.reset", "Reset Settings")
|
||||
|
||||
language.Add("Cleanup_prop_headcrabcanister", "Headcrabcanister")
|
||||
language.Add("Cleaned_prop_headcrabcanister", "Cleaned up all Headcrabcanister")
|
||||
language.Add("SBoxLimit_prop_headcrabcanister", "You've hit the Headcrabcanister limit!")
|
||||
language.Add("Undone_prop_headcrabcanister", "Headcrabcanister undone")
|
||||
|
||||
language.Add("env_headcrabcanister", "Headcrabcanister")
|
||||
|
||||
concommand.Add("headcrabcanister_reset", function(ply)
|
||||
RunConsoleCommand("headcrabcanister_damage", "130")
|
||||
RunConsoleCommand("headcrabcanister_damage_radius", "700")
|
||||
RunConsoleCommand("headcrabcanister_speed", "3000")
|
||||
RunConsoleCommand("headcrabcanister_height", "2000")
|
||||
RunConsoleCommand("headcrabcanister_flight_time", "5")
|
||||
RunConsoleCommand("headcrabcanister_smoke", "-1")
|
||||
RunConsoleCommand("headcrabcanister_headcrab_type", "models/headcrabclassic.mdl")
|
||||
RunConsoleCommand("headcrabcanister_headcrab_count", "4")
|
||||
RunConsoleCommand("headcrabcanister_height_skybox", "0")
|
||||
RunConsoleCommand("headcrabcanister_smoke_always", "0")
|
||||
RunConsoleCommand("headcrabcanister_fire", "38")
|
||||
RunConsoleCommand("headcrabcanister_solid", "37")
|
||||
end)
|
||||
end
|
||||
|
||||
if (SERVER) then
|
||||
CreateConVar("sbox_maxheadcrabcanisters", 10)
|
||||
|
||||
numpad.Register("headcrabcanister_fire", function(ply, prop_headcrabcanister, activate)
|
||||
if (!IsValid(prop_headcrabcanister)) then return false end
|
||||
prop_headcrabcanister:Launch()
|
||||
end)
|
||||
numpad.Register("headcrabcanister_solid", function(ply, prop_headcrabcanister, activate)
|
||||
if (!IsValid(prop_headcrabcanister)) then return false end
|
||||
if (prop_headcrabcanister.solid) then
|
||||
prop_headcrabcanister:DrawShadow(false)
|
||||
prop_headcrabcanister:SetNotSolid(true)
|
||||
prop_headcrabcanister:SetNoDraw(true)
|
||||
prop_headcrabcanister.solid = false
|
||||
else
|
||||
prop_headcrabcanister:DrawShadow(true)
|
||||
prop_headcrabcanister:SetNotSolid(false)
|
||||
prop_headcrabcanister:SetNoDraw(false)
|
||||
prop_headcrabcanister.solid = true
|
||||
end
|
||||
end)
|
||||
|
||||
function MakeHeadcrabcanister(ply, pos, ang, keyFire, keySolid, settings)
|
||||
if (!ply:CheckLimit("headcrabcanisters")) then return false end
|
||||
|
||||
local prop_headcrabcanister = ents.Create("prop_headcrabcanister")
|
||||
if (!prop_headcrabcanister:IsValid()) then return false end
|
||||
|
||||
prop_headcrabcanister:SetAngles( Angle(-75, ang.y, 90) )
|
||||
prop_headcrabcanister:SetPos(pos)
|
||||
prop_headcrabcanister:Spawn()
|
||||
prop_headcrabcanister:Activate()
|
||||
prop_headcrabcanister.solid = true
|
||||
prop_headcrabcanister.Activate = numpad.OnDown(ply, keyFire, "headcrabcanister_fire", prop_headcrabcanister)
|
||||
prop_headcrabcanister.ToggleSolid = numpad.OnDown(ply, keySolid, "headcrabcanister_solid", prop_headcrabcanister)
|
||||
|
||||
table.Merge(prop_headcrabcanister:GetTable(), {
|
||||
ply = ply,
|
||||
keyFire = keyFire,
|
||||
keySolid = keySolid,
|
||||
settings = settings,
|
||||
})
|
||||
|
||||
ply:AddCount("headcrabcanisters", prop_headcrabcanister)
|
||||
|
||||
DoPropSpawnedEffect(prop_headcrabcanister)
|
||||
|
||||
return prop_headcrabcanister
|
||||
end
|
||||
|
||||
duplicator.RegisterEntityClass("prop_headcrabcanister", MakeHeadcrabcanister, "pos", "ang", "keyFire", "keySolid", "settings")
|
||||
end
|
||||
|
||||
function TOOL:LeftClick(trace)
|
||||
if (trace.HitSky or !trace.HitPos or IsValid(trace.Entity) and (trace.Entity:IsPlayer() or trace.Entity:IsNPC())) then return false end
|
||||
if (CLIENT) then return true end
|
||||
|
||||
local Tbl = { }
|
||||
Tbl["damage"] = self:GetClientNumber("damage")
|
||||
Tbl["damage_radius"] = self:GetClientNumber("damage_radius")
|
||||
Tbl["speed"] = self:GetClientNumber("speed")
|
||||
Tbl["height"] = self:GetClientNumber("height")
|
||||
Tbl["flight_time"] = self:GetClientNumber("flight_time")
|
||||
Tbl["smoke"] = self:GetClientNumber("smoke")
|
||||
Tbl["headcrab_count"] = self:GetClientNumber("headcrab_count")
|
||||
|
||||
if (self:GetClientInfo("height_skybox") != "0") then
|
||||
Tbl["height"] = 0
|
||||
end
|
||||
if (self:GetClientInfo("smoke_always") != "0") then
|
||||
Tbl["smoke"] = -1
|
||||
end
|
||||
if (self:GetClientInfo("headcrab_type") == "models/headcrabclassic.mdl") then
|
||||
Tbl["headcrab_type"] = "0"
|
||||
elseif (self:GetClientInfo("headcrab_type") == "models/headcrab.mdl") then
|
||||
Tbl["headcrab_type"] = "1"
|
||||
elseif (self:GetClientInfo("headcrab_type") == "models/headcrabblack.mdl") then
|
||||
Tbl["headcrab_type"] = "2"
|
||||
end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
|
||||
// Update existing Headcrabcanister
|
||||
if (trace.Entity:GetClass() == "prop_headcrabcanister") then
|
||||
table.Merge(trace.Entity:GetTable(), {
|
||||
ply = ply,
|
||||
keyFire = self:GetClientInfo("fire"),
|
||||
keySolid = self:GetClientInfo("solid"),
|
||||
settings = Tbl,
|
||||
})
|
||||
return true
|
||||
end
|
||||
|
||||
// Create a new Headcrabcanister
|
||||
local ang = trace.HitNormal:Angle()
|
||||
ang.pitch = ang.pitch - 270
|
||||
|
||||
local prop_headcrabcanister = MakeHeadcrabcanister(ply, trace.HitPos, ang, self:GetClientNumber("fire"), self:GetClientNumber("solid"), Tbl)
|
||||
|
||||
undo.Create("prop_headcrabcanister")
|
||||
undo.AddEntity(prop_headcrabcanister)
|
||||
undo.SetPlayer(ply)
|
||||
undo.Finish()
|
||||
|
||||
ply:AddCleanup("prop_headcrabcanister", prop_headcrabcanister)
|
||||
|
||||
return true
|
||||
end
|
||||
function TOOL:UpdateGhostHeadcrabcanister(ent,player)
|
||||
if (!ent or !ent:IsValid()) then return end
|
||||
|
||||
local tr = util.GetPlayerTrace(player, player:GetAimVector())
|
||||
local trace = util.TraceLine(tr)
|
||||
|
||||
if (!trace.Hit) then return end
|
||||
|
||||
if (trace.Entity && (trace.Entity:GetClass() == "prop_headcrabcanister" || trace.Entity:IsPlayer()) || trace.Entity:IsNPC()) then
|
||||
ent:SetNoDraw(true)
|
||||
return
|
||||
end
|
||||
|
||||
local Ang = trace.HitNormal:Angle()
|
||||
Ang.pitch = Ang.pitch - 270
|
||||
|
||||
local min = ent:OBBMins()
|
||||
ent:SetPos(trace.HitPos - trace.HitNormal)
|
||||
|
||||
ent:SetAngles(Angle(-75, Ang.y, 90 ))
|
||||
ent:SetNoDraw(false)
|
||||
end
|
||||
|
||||
function TOOL:Think()
|
||||
if (!self.GhostEntity || !self.GhostEntity:IsValid()) then
|
||||
self:MakeGhostEntity("models/props_combine/headcrabcannister01b.mdl", Vector(0, 0, 0), Angle(0, 0, 0))
|
||||
end
|
||||
|
||||
self:UpdateGhostHeadcrabcanister(self.GhostEntity, self:GetOwner())
|
||||
end
|
||||
function TOOL.BuildCPanel(panel)
|
||||
panel:AddControl("Numpad", {Label = "#tool.headcrabcanister.fire", Label2 = "#tool.headcrabcanister.solid", Command = "headcrabcanister_fire", Command2 = "headcrabcanister_solid"})
|
||||
panel:AddControl("PropSelect", {Label = "#tool.headcrabcanister.headcrab_type", Height = 1, ConVar = "headcrabcanister_headcrab_type", Models = list.Get("HeadcrabTypes")})
|
||||
panel:AddControl("Slider", {Label = "#tool.headcrabcanister.headcrab_count", Type = "Integer", Min = 0, Max = 10, Command = "headcrabcanister_headcrab_count", Help = true})
|
||||
panel:AddControl("Slider", {Label = "#tool.headcrabcanister.damage", Type = "Integer", Min = 0, Max = 1000, Command = "headcrabcanister_damage", Help = true})
|
||||
panel:AddControl("Slider", {Label = "#tool.headcrabcanister.damage_radius", Type = "Integer", Min = 10, Max = 1000, Command = "headcrabcanister_damage_radius", Help = true})
|
||||
panel:AddControl("Slider", {Label = "#tool.headcrabcanister.speed", Type = "Integer", Min = 500, Max = 5000, Command = "headcrabcanister_speed", Help = true})
|
||||
panel:AddControl("Slider", {Label = "#tool.headcrabcanister.height", Type = "Integer", Min = 1000, Max = 10000, Command = "headcrabcanister_height", Help = true})
|
||||
panel:AddControl("Checkbox", {Label = "#tool.headcrabcanister.height_skybox", Command = "headcrabcanister_height_skybox"})
|
||||
panel:AddControl("Slider", {Label = "#tool.headcrabcanister.flight_time", Type = "Integer", Min = 1, Max = 10, Command = "headcrabcanister_flight_time", Help = true})
|
||||
panel:AddControl("Slider", {Label = "#tool.headcrabcanister.smoke", Type = "Integer", Min = 5, Max = 120, Command = "headcrabcanister_smoke", Help = true})
|
||||
panel:AddControl("Checkbox", {Label = "#tool.headcrabcanister.smoke_always", Command = "headcrabcanister_smoke_always"})
|
||||
panel:AddControl("Button", {Label = "#tool.headcrabcanister.reset", Command = "headcrabcanister_reset"})
|
||||
end
|
||||
list.Set("HeadcrabTypes", "models/headcrabclassic.mdl", {})
|
||||
list.Set("HeadcrabTypes", "models/headcrab.mdl", {})
|
||||
list.Set("HeadcrabTypes", "models/headcrabblack.mdl", {})
|
||||
228
lua/weapons/gmod_tool/stools/imagetool.lua
Normal file
228
lua/weapons/gmod_tool/stools/imagetool.lua
Normal file
@@ -0,0 +1,228 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
--[[
|
||||
© AsterionStaff 2022.
|
||||
This script was created from the developers of the AsterionTeam.
|
||||
You can get more information from one of the links below:
|
||||
Site - https://asterion.games
|
||||
Discord - https://discord.gg/CtfS8r5W3M
|
||||
|
||||
developer(s):
|
||||
Selenter - https://steamcommunity.com/id/selenter
|
||||
|
||||
——— Chop your own wood and it will warm you twice.
|
||||
]]--
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
TOOL.Name = "Image Tool" -- Название
|
||||
TOOL.Category = "Asterion Tools" -- Категория
|
||||
TOOL.Information = { -- Дополнительная информация
|
||||
{name = "left", stage = 0},
|
||||
{name = "right", stage = 0},
|
||||
}
|
||||
|
||||
-- Стандартные конвары
|
||||
TOOL.ClientConVar.url = "https://i.imgur.com/4vyQ6Hl.png"
|
||||
TOOL.ClientConVar.width = 100
|
||||
TOOL.ClientConVar.height = 100
|
||||
TOOL.ClientConVar.scale = 40
|
||||
TOOL.ClientConVar.brightness = 255
|
||||
TOOL.ClientConVar.alpha = 255
|
||||
|
||||
-- Добавляем язык
|
||||
if CLIENT then
|
||||
language.Add("tool.imagetool.name", "Image Tool")
|
||||
language.Add("tool.imagetool.desc", "Allows you to create pictures in the world")
|
||||
language.Add("tool.imagetool.left", "With the left mouse button you can create a picture.")
|
||||
language.Add("tool.imagetool.right", "With the right mouse button you can delete the picture next to.")
|
||||
end
|
||||
|
||||
-- Левая кнопка мыши
|
||||
function TOOL:LeftClick()
|
||||
if CLIENT then return true end
|
||||
|
||||
local client = self:GetOwner()
|
||||
|
||||
-- Пытаемся получить данные из тулгана
|
||||
local data = ImageTool:GetToolData(client)
|
||||
if !data then return end
|
||||
|
||||
ImageTool:AddImage(data)
|
||||
|
||||
-- я ненавижу predicted хуки!!! (приходится передавать по net-у, т.к. в одиночке этот хук не обрабатывается на клиенте)
|
||||
net.Start("image.SaveImage")
|
||||
net.WriteString(data.url)
|
||||
net.Send(client)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-- Правая кнопка мыши
|
||||
function TOOL:RightClick(trace)
|
||||
if CLIENT then return true end
|
||||
|
||||
local client = self:GetOwner()
|
||||
|
||||
-- Пытаемся получить данные из тулгана
|
||||
local data = ImageTool:GetToolData(client)
|
||||
if !data then return end
|
||||
|
||||
ImageTool:RemoveImage(data)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-- C менюшка
|
||||
function TOOL.BuildCPanel(CPanel)
|
||||
CPanel:AddControl("Header",{
|
||||
Description = "This Tool will help you put the pictures you need on your map. In the field with the URL, indicate the link to the picture, then you can put it in the world."
|
||||
})
|
||||
|
||||
CPanel:AddControl("TextBox", {
|
||||
Label = " URL Link to picture",
|
||||
Command = "imagetool_url"
|
||||
})
|
||||
|
||||
local URLDesc = vgui.Create("DLabel")
|
||||
URLDesc:SetText("In this field you must specify the URL of the image you want to put in the world.")
|
||||
URLDesc:SetWrap(true)
|
||||
URLDesc:SetAutoStretchVertical(true)
|
||||
URLDesc:SetTextColor(Color(10,149,255))
|
||||
CPanel:AddPanel(URLDesc)
|
||||
|
||||
local NoticePanel = vgui.Create("DLabel")
|
||||
NoticePanel:SetText("If your picture is not loaded, then we recommend using IMGUR to publish pictures.")
|
||||
NoticePanel:SetWrap(true)
|
||||
NoticePanel:SetAutoStretchVertical(true)
|
||||
NoticePanel:SetTextColor(Color(255,10,10,255))
|
||||
CPanel:AddPanel(NoticePanel)
|
||||
|
||||
CPanel:AddControl("Slider", {
|
||||
Label = "Image Width:",
|
||||
Command = "imagetool_width",
|
||||
Min = 0,
|
||||
Max = 10000
|
||||
})
|
||||
|
||||
local WidthDesc = vgui.Create("DLabel")
|
||||
WidthDesc:SetText("In this slider, you can specify the size of the picture you need in width.")
|
||||
WidthDesc:SetWrap(true)
|
||||
WidthDesc:SetAutoStretchVertical(true)
|
||||
WidthDesc:SetTextColor(Color(10,149,255))
|
||||
CPanel:AddPanel(WidthDesc)
|
||||
|
||||
CPanel:AddControl("Slider", {
|
||||
Label = "Image Height:",
|
||||
Command = "imagetool_height",
|
||||
Min = 0,
|
||||
Max = 10000
|
||||
})
|
||||
|
||||
local HeightDesc = vgui.Create("DLabel")
|
||||
HeightDesc:SetText("In this slider, you can specify the size of the picture you need in height.")
|
||||
HeightDesc:SetWrap(true)
|
||||
HeightDesc:SetAutoStretchVertical(true)
|
||||
HeightDesc:SetTextColor(Color(10,149,255))
|
||||
CPanel:AddPanel(HeightDesc)
|
||||
|
||||
CPanel:AddControl("Slider", {
|
||||
Label = "Image Scale:",
|
||||
Command = "imagetool_scale",
|
||||
Min = 0,
|
||||
Max = 100
|
||||
})
|
||||
|
||||
local ScaleDesc = vgui.Create("DLabel")
|
||||
ScaleDesc:SetText("In this slider, you can resize the picture in height and width at the same time.")
|
||||
ScaleDesc:SetWrap(true)
|
||||
ScaleDesc:SetAutoStretchVertical(true)
|
||||
ScaleDesc:SetTextColor(Color(10,149,255))
|
||||
CPanel:AddPanel(ScaleDesc)
|
||||
|
||||
CPanel:AddControl("Slider", {
|
||||
Label = "Image Brightness:",
|
||||
Command = "imagetool_brightness",
|
||||
Min = 0,
|
||||
Max = 255
|
||||
})
|
||||
|
||||
local BrightnessDesc = vgui.Create("DLabel")
|
||||
BrightnessDesc:SetText("In this slider, you can change the brightness of the picture, it is very suitable if you need to place the picture in a dark place.")
|
||||
BrightnessDesc:SetWrap(true)
|
||||
BrightnessDesc:SetAutoStretchVertical(true)
|
||||
BrightnessDesc:SetTextColor(Color(10,149,255))
|
||||
CPanel:AddPanel(BrightnessDesc)
|
||||
|
||||
CPanel:AddControl("Slider", {
|
||||
Label = "Image Alpha:",
|
||||
Command = "imagetool_alpha",
|
||||
Min = 0,
|
||||
Max = 255
|
||||
})
|
||||
|
||||
local AlphaDesc = vgui.Create("DLabel")
|
||||
AlphaDesc:SetText("This slider allows you to change the transparency of your images.")
|
||||
AlphaDesc:SetWrap(true)
|
||||
AlphaDesc:SetAutoStretchVertical(true)
|
||||
AlphaDesc:SetTextColor(Color(10,149,255))
|
||||
CPanel:AddPanel(AlphaDesc)
|
||||
|
||||
local ImageSize = vgui.Create("DButton")
|
||||
ImageSize:SetText("Set the size settings as in the picture")
|
||||
ImageSize.DoClick = function()
|
||||
local l = "imagetool_"
|
||||
|
||||
local data = ImageTool:GetToolData(LocalPlayer())
|
||||
if !data then return end
|
||||
|
||||
local uniqueID = util.CRC(data.url)
|
||||
|
||||
local material = ImageTool.cacheMaterials[uniqueID]
|
||||
if material then
|
||||
local width = material:Width()
|
||||
local height = material:Height()
|
||||
|
||||
RunConsoleCommand(l .. "width", width)
|
||||
RunConsoleCommand(l .. "height", height)
|
||||
end
|
||||
end
|
||||
CPanel:AddPanel(ImageSize)
|
||||
|
||||
local ResetButton = vgui.Create("DButton")
|
||||
ResetButton:SetText("Restore default settings")
|
||||
ResetButton.DoClick = function()
|
||||
local l = "imagetool_"
|
||||
|
||||
RunConsoleCommand(l .. "url", "https://i.imgur.com/4vyQ6Hl.png")
|
||||
RunConsoleCommand(l .. "width", 100)
|
||||
RunConsoleCommand(l .. "height", 100)
|
||||
RunConsoleCommand(l .. "scale", 40)
|
||||
RunConsoleCommand(l .. "brightness", 255)
|
||||
end
|
||||
CPanel:AddPanel(ResetButton)
|
||||
|
||||
CPanel:AddControl("Header",{
|
||||
Description = "Your image history:"
|
||||
})
|
||||
|
||||
local historyPanel = vgui.Create("DScrollPanel")
|
||||
historyPanel:SetTall(300)
|
||||
historyPanel.Paint = function(_, w, h)
|
||||
surface.SetDrawColor(0, 0, 0)
|
||||
surface.DrawOutlinedRect(0, 0, w, h)
|
||||
end
|
||||
CPanel:AddPanel(historyPanel)
|
||||
|
||||
ImageTool.historyPanel = historyPanel
|
||||
ImageTool:LoadingHistory()
|
||||
end
|
||||
162
lua/weapons/gmod_tool/stools/item_ammo_crate.lua
Normal file
162
lua/weapons/gmod_tool/stools/item_ammo_crate.lua
Normal file
@@ -0,0 +1,162 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Half-Life 2"
|
||||
TOOL.Name = "#tool.item_ammo_crate"
|
||||
|
||||
TOOL.ClientConVar[ "type" ] = "0"
|
||||
|
||||
local ToolModels = {}
|
||||
ToolModels[ 0 ] = "models/items/ammocrate_pistol.mdl"
|
||||
ToolModels[ 1 ] = "models/items/ammocrate_smg1.mdl"
|
||||
ToolModels[ 2 ] = "models/items/ammocrate_ar2.mdl"
|
||||
ToolModels[ 3 ] = "models/items/ammocrate_rockets.mdl"
|
||||
ToolModels[ 4 ] = "models/items/ammocrate_buckshot.mdl"
|
||||
ToolModels[ 5 ] = "models/items/ammocrate_grenade.mdl"
|
||||
ToolModels[ 6 ] = "models/items/ammocrate_357.mdl"
|
||||
ToolModels[ 7 ] = "models/items/ammocrate_crossbow.mdl"
|
||||
ToolModels[ 8 ] = "models/items/ammocrate_ar2.mdl"
|
||||
ToolModels[ 9 ] = "models/items/ammocrate_smg2.mdl"
|
||||
ToolModels[ 10 ] = "models/items/ammocrate_smg1.mdl"
|
||||
|
||||
cleanup.Register( "item_ammo_crates" )
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
local rb655_force_downloads = CreateConVar( "rb655_force_downloads", "0", FCVAR_ARCHIVE )
|
||||
if ( rb655_force_downloads:GetFloat() > 0 ) then
|
||||
|
||||
resource.AddFile( "models/items/ammocrate_357.mdl" )
|
||||
resource.AddFile( "models/items/ammocrate_crossbow.mdl" )
|
||||
|
||||
end
|
||||
|
||||
CreateConVar( "sbox_maxitem_ammo_crates", 10, FCVAR_ARCHIVE + FCVAR_REPLICATED + FCVAR_NOTIFY )
|
||||
|
||||
function MakeAmmoCrate( ply, model, pos, ang, type )
|
||||
if ( IsValid( ply ) and !ply:CheckLimit( "item_ammo_crates" ) ) then return nil end
|
||||
|
||||
type = tonumber( type ) or 0
|
||||
|
||||
local item_ammo_crate = ents.Create( "item_ammo_crate" )
|
||||
if ( !IsValid( item_ammo_crate ) ) then return nil end
|
||||
item_ammo_crate:SetPos( pos )
|
||||
item_ammo_crate:SetAngles( ang )
|
||||
item_ammo_crate:SetKeyValue( "AmmoType", math.Clamp( type, 0, 9 ) )
|
||||
item_ammo_crate:Spawn()
|
||||
item_ammo_crate:Activate()
|
||||
item_ammo_crate:SetModel( model )
|
||||
|
||||
table.Merge( item_ammo_crate:GetTable(), {
|
||||
ply = ply,
|
||||
type = type
|
||||
} )
|
||||
|
||||
if ( IsValid( ply ) ) then
|
||||
ply:AddCount( "item_ammo_crates", item_ammo_crate )
|
||||
ply:AddCleanup( "item_ammo_crates", item_ammo_crate )
|
||||
end
|
||||
|
||||
DoPropSpawnedEffect( item_ammo_crate )
|
||||
|
||||
return item_ammo_crate
|
||||
end
|
||||
|
||||
duplicator.RegisterEntityClass( "item_ammo_crate", MakeAmmoCrate, "model", "pos", "ang", "type" )
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
if ( trace.HitSky or !trace.HitPos or trace.HitNormal.z < 0.7 ) then return false end
|
||||
if ( IsValid( trace.Entity ) and ( trace.Entity:GetClass() == "item_ammo_crate" or trace.Entity:IsPlayer() or trace.Entity:IsNPC() ) ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
|
||||
local ang = trace.HitNormal:Angle()
|
||||
ang.p = ang.p - 270
|
||||
if ( trace.HitNormal.z > 0.9999 ) then ang.y = ply:GetAngles().y + 180 end
|
||||
|
||||
local type = self:GetClientNumber( "type" )
|
||||
if ( type == 10 ) then type = math.random( 0, 9 ) end
|
||||
|
||||
local item_ammo_crate = MakeAmmoCrate( ply, ToolModels[ type ], trace.HitPos + trace.HitNormal * 16, ang, type )
|
||||
|
||||
undo.Create( "item_ammo_crate" )
|
||||
undo.AddEntity( item_ammo_crate )
|
||||
undo.SetPlayer( ply )
|
||||
undo.Finish()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:UpdateGhostEntity( ent, ply )
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local trace = ply:GetEyeTrace()
|
||||
|
||||
if ( !trace.Hit or trace.HitNormal.z < 0.7 ) then ent:SetNoDraw( true ) return end
|
||||
if ( IsValid( trace.Entity ) and ( trace.Entity:GetClass() == "item_ammo_crate" or trace.Entity:IsPlayer() ) ) then ent:SetNoDraw( true ) return end
|
||||
|
||||
local ang = trace.HitNormal:Angle()
|
||||
ang.p = ang.p - 270
|
||||
if ( trace.HitNormal.z > 0.9999 ) then ang.y = ply:GetAngles().y + 180 end
|
||||
|
||||
local min = ent:OBBMins()
|
||||
ent:SetPos( trace.HitPos - trace.HitNormal * min.z )
|
||||
|
||||
ent:SetAngles( ang )
|
||||
ent:SetNoDraw( false )
|
||||
end
|
||||
|
||||
function TOOL:Think()
|
||||
if ( !IsValid( self.GhostEntity ) or self.GhostEntity:GetModel() != ToolModels[ self:GetClientNumber( "type" ) ] ) then
|
||||
self:MakeGhostEntity( ToolModels[ self:GetClientNumber( "type" ) ], Vector( 0, 0, 0 ), Angle( 0, 0, 0 ) )
|
||||
end
|
||||
self:UpdateGhostEntity( self.GhostEntity, self:GetOwner() )
|
||||
end
|
||||
|
||||
list.Set( "AmmoCrateTypes", "#Pistol_ammo", { item_ammo_crate_type = "0" } )
|
||||
list.Set( "AmmoCrateTypes", "#Buckshot_ammo", { item_ammo_crate_type = "4" } )
|
||||
list.Set( "AmmoCrateTypes", "#SMG1_grenade_ammo", { item_ammo_crate_type = "9" } )
|
||||
|
||||
list.Set( "AmmoCrateTypes", "#SMG1_ammo", { item_ammo_crate_type = "1" } )
|
||||
list.Set( "AmmoCrateTypes", "#AR2_ammo", { item_ammo_crate_type = "2" } )
|
||||
list.Set( "AmmoCrateTypes", "#RPG_round_ammo", { item_ammo_crate_type = "3" } )
|
||||
list.Set( "AmmoCrateTypes", "#Buckshot_ammo", { item_ammo_crate_type = "4" } )
|
||||
list.Set( "AmmoCrateTypes", "#Grenade_ammo", { item_ammo_crate_type = "5" } )
|
||||
list.Set( "AmmoCrateTypes", "#357_ammo", { item_ammo_crate_type = "6" } )
|
||||
list.Set( "AmmoCrateTypes", "#XBowBolt_ammo", { item_ammo_crate_type = "7" } )
|
||||
list.Set( "AmmoCrateTypes", "#AR2AltFire_ammo", { item_ammo_crate_type = "8" } )
|
||||
list.Set( "AmmoCrateTypes", "#SMG1_grenade_ammo", { item_ammo_crate_type = "9" } )
|
||||
list.Set( "AmmoCrateTypes", "#tool.item_ammo_crate.random", { item_ammo_crate_type = "10" } )
|
||||
|
||||
if ( SERVER ) then return end
|
||||
|
||||
TOOL.Information = { { name = "left" } }
|
||||
|
||||
language.Add( "tool.item_ammo_crate", "Ammo Crates" )
|
||||
language.Add( "tool.item_ammo_crate.name", "Ammo Crate Tool" )
|
||||
language.Add( "tool.item_ammo_crate.desc", "Spawn crates full of ammo for resupply" )
|
||||
language.Add( "tool.item_ammo_crate.left", "Spawn an ammo crate" )
|
||||
|
||||
language.Add( "tool.item_ammo_crate.type", "Ammo Crate Type" )
|
||||
language.Add( "tool.item_ammo_crate.random", "Random" )
|
||||
|
||||
language.Add( "Cleanup_item_ammo_crates", "Ammo Crates" )
|
||||
language.Add( "Cleaned_item_ammo_crates", "Cleaned up all Ammo Crates" )
|
||||
language.Add( "SBoxLimit_item_ammo_crates", "You've hit the Ammo Crate limit!" )
|
||||
language.Add( "Undone_item_ammo_crate", "Ammo Crate undone" )
|
||||
|
||||
language.Add( "max_item_ammo_crates", "Max Ammo Crates:" )
|
||||
|
||||
function TOOL.BuildCPanel( panel )
|
||||
panel:AddControl( "ListBox", { Label = "#tool.item_ammo_crate.type", Options = list.Get( "AmmoCrateTypes" ), Height = 204 } )
|
||||
end
|
||||
150
lua/weapons/gmod_tool/stools/item_charger_spawner.lua
Normal file
150
lua/weapons/gmod_tool/stools/item_charger_spawner.lua
Normal file
@@ -0,0 +1,150 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Half-Life 2"
|
||||
TOOL.Name = "#tool.item_charger_spawner"
|
||||
|
||||
TOOL.ClientConVar[ "type" ] = "0"
|
||||
--TOOL.ClientConVar[ "citadel" ] = "0"
|
||||
|
||||
list.Set( "ChargerTypes", "#item_suitcharger", { item_charger_spawner_type = 0, model = "models/props_combine/suit_charger001.mdl", classname = "item_suitcharger" } )
|
||||
list.Set( "ChargerTypes", "#item_healthcharger", { item_charger_spawner_type = 1, model = "models/props_combine/health_charger001.mdl", classname = "item_healthcharger" } )
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
--[[duplicator.RegisterEntityModifier( "rb655_citadel_charger", function( ply, ent, data )
|
||||
ent:SetKeyValue( "spawnflags", 8192 )
|
||||
end )]]
|
||||
|
||||
function MakeHalfLifeCharger( ply, entry, pos, ang --[[, isCitadel]] )
|
||||
|
||||
-- Ask the gamemode if it's ok to spawn this
|
||||
if ( !gamemode.Call( "PlayerSpawnSENT", ply, entry.classname ) ) then return end
|
||||
|
||||
-- Spawn it!
|
||||
local item_charger = ents.Create( entry.classname )
|
||||
if ( !IsValid( item_charger ) ) then return nil end
|
||||
item_charger:SetPos( pos )
|
||||
item_charger:SetAngles( ang )
|
||||
--[[if ( isCitadel ) then
|
||||
duplicator.StoreEntityModifier( item_charger, "rb655_citadel_charger", {} )
|
||||
duplicator.ApplyEntityModifiers( ply, item_charger )
|
||||
end]]
|
||||
item_charger:Spawn()
|
||||
item_charger:Activate()
|
||||
|
||||
DoPropSpawnedEffect( item_charger )
|
||||
|
||||
-- Pretend we are a SENT
|
||||
if ( IsValid( ply ) ) then
|
||||
gamemode.Call( "PlayerSpawnedSENT", ply, item_charger )
|
||||
end
|
||||
|
||||
undo.Create( "SENT" )
|
||||
undo.SetPlayer( ply )
|
||||
undo.AddEntity( item_charger )
|
||||
undo.SetCustomUndoText( "Undone " .. entry.classname )
|
||||
undo.Finish( "Scripted Entity (" .. tostring( entry.classname ) .. ")" )
|
||||
|
||||
ply:AddCleanup( "sents", item_charger )
|
||||
item_charger:SetVar( "Player", ply )
|
||||
|
||||
return item_charger
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( trace.HitSky or !trace.HitPos ) then return false end
|
||||
if ( IsValid( trace.Entity ) and ( trace.Entity:IsPlayer() or trace.Entity:IsNPC() ) ) then return false end
|
||||
|
||||
local entry = self:GetSelectedEntry()
|
||||
if ( !entry ) then return false end
|
||||
|
||||
if ( IsValid( trace.Entity ) and trace.Entity:GetClass() == entry.classname ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
--local isCitadel = self:GetClientNumber( "citadel" ) != 0
|
||||
|
||||
local ply = self:GetOwner()
|
||||
local ang = trace.HitNormal:Angle()
|
||||
MakeHalfLifeCharger( ply, entry, trace.HitPos, ang --[[, isCitadel]] )
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:GetSelectedEntry()
|
||||
|
||||
local t = self:GetClientNumber( "type" )
|
||||
|
||||
local options = list.Get( "ChargerTypes" )
|
||||
for label, tab in pairs( options ) do
|
||||
if ( tab.item_charger_spawner_type == t ) then return tab end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Think()
|
||||
|
||||
local entry = self:GetSelectedEntry()
|
||||
if ( !entry ) then
|
||||
if ( IsValid( self.GhostEntity ) ) then self.GhostEntity:SetNoDraw( true ) end
|
||||
return
|
||||
end
|
||||
|
||||
if ( !IsValid( self.GhostEntity ) or self.GhostEntity:GetModel() != entry.model ) then
|
||||
self:MakeGhostEntity( entry.model, Vector( 0, 0, 0 ), Angle( 0, 0, 0 ) )
|
||||
end
|
||||
|
||||
self:UpdateGhostEntity( self.GhostEntity, self:GetOwner(), entry )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:UpdateGhostEntity( ent, ply, entry )
|
||||
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local trace = ply:GetEyeTrace()
|
||||
|
||||
if ( !trace.Hit or !entry ) then ent:SetNoDraw( true ) return end
|
||||
if ( IsValid( trace.Entity ) and ( trace.Entity:GetClass() == entry.classname or trace.Entity:IsPlayer() or trace.Entity:IsNPC() ) ) then ent:SetNoDraw( true ) return end
|
||||
|
||||
ent:SetPos( trace.HitPos )
|
||||
|
||||
local ang = trace.HitNormal:Angle()
|
||||
ent:SetAngles( ang )
|
||||
|
||||
ent:SetNoDraw( false )
|
||||
|
||||
end
|
||||
|
||||
|
||||
if ( SERVER ) then return end
|
||||
|
||||
TOOL.Information = { { name = "left" } }
|
||||
|
||||
language.Add( "tool.item_charger_spawner", "Charger Spawner" )
|
||||
language.Add( "tool.item_charger_spawner.name", "Charger Spawner" )
|
||||
language.Add( "tool.item_charger_spawner.desc", "Allows precision spawning of the suit & health chargers." )
|
||||
language.Add( "tool.item_charger_spawner.left", "Spawn a charger" )
|
||||
|
||||
language.Add( "tool.item_charger_spawner.type", "Charger Spawner Type" )
|
||||
--language.Add( "tool.item_charger_spawner.citadel", "Citadel Suit Charger" )
|
||||
|
||||
function TOOL.BuildCPanel( panel )
|
||||
panel:AddControl( "ListBox", { Label = "#tool.item_charger_spawner.type", Options = list.Get( "ChargerTypes" ), Height = 128 } )
|
||||
|
||||
-- I can't be bothered to get it to work well with duplicator, so fuck it
|
||||
--panel:CheckBox( "#tool.item_charger_spawner.citadel", "item_charger_spawner_citadel" )
|
||||
end
|
||||
314
lua/weapons/gmod_tool/stools/item_item_crate.lua
Normal file
314
lua/weapons/gmod_tool/stools/item_item_crate.lua
Normal file
@@ -0,0 +1,314 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Half-Life 2"
|
||||
TOOL.Name = "#tool.item_item_crate"
|
||||
|
||||
TOOL.Models = {}
|
||||
TOOL.Models[ "models/items/item_item_crate.mdl" ] = 0
|
||||
TOOL.Models[ "models/items/item_beacon_crate.mdl" ] = 1
|
||||
|
||||
TOOL.ClientConVar[ "model" ] = "models/items/item_item_crate.mdl"
|
||||
TOOL.ClientConVar[ "item" ] = "item_healthkit"
|
||||
TOOL.ClientConVar[ "amount" ] = "3"
|
||||
TOOL.ClientConVar[ "health" ] = "25"
|
||||
|
||||
TOOL.ClientConVar[ "desired_health" ] = "100"
|
||||
TOOL.ClientConVar[ "desired_armor" ] = "30"
|
||||
TOOL.ClientConVar[ "desired_pistol" ] = "50"
|
||||
TOOL.ClientConVar[ "desired_smg1" ] = "50"
|
||||
TOOL.ClientConVar[ "desired_smg1_alt" ] = "10"
|
||||
TOOL.ClientConVar[ "desired_ar2" ] = "40"
|
||||
TOOL.ClientConVar[ "desired_shotgun" ] = "50"
|
||||
TOOL.ClientConVar[ "desired_rpg" ] = "0"
|
||||
TOOL.ClientConVar[ "desired_grenade" ] = "10"
|
||||
TOOL.ClientConVar[ "desired_357" ] = "0"
|
||||
TOOL.ClientConVar[ "desired_crossbow" ] = "0"
|
||||
TOOL.ClientConVar[ "desired_ar2_alt" ] = "0"
|
||||
|
||||
cleanup.Register( "item_item_crates" )
|
||||
|
||||
if ( SERVER ) then
|
||||
CreateConVar( "sbox_maxitem_item_crates", 8, FCVAR_ARCHIVE + FCVAR_REPLICATED + FCVAR_NOTIFY )
|
||||
|
||||
function MakeItemCrate( ply, pos, ang, appearance, class, amount, health, dynamic_values )
|
||||
if ( IsValid( ply ) and !ply:CheckLimit( "item_item_crates" ) ) then return nil end
|
||||
|
||||
local item_item_crate = ents.Create( "item_item_crate" )
|
||||
if ( !IsValid( item_item_crate ) ) then return false end
|
||||
item_item_crate:SetPos( pos )
|
||||
item_item_crate:SetAngles( ang )
|
||||
|
||||
-- Map placed entity fix
|
||||
class = class or "item_dynamic_ressuply"
|
||||
appearance = appearance or 0
|
||||
amount = tonumber( amount ) or 1
|
||||
dynamic_values = dynamic_values or {}
|
||||
|
||||
if ( class == "item_dynamic_resupply" ) then
|
||||
local item_dynamic_resupply = ents.Create( "item_dynamic_resupply" )
|
||||
item_dynamic_resupply:SetKeyValue( "targetname", "rb655_item_dynamic_resupply" .. item_dynamic_resupply:EntIndex() )
|
||||
for i, n in pairs( dynamic_values ) do
|
||||
item_dynamic_resupply:SetKeyValue( i, n )
|
||||
end
|
||||
item_item_crate:SetKeyValue( "SpecificResupply", "rb655_item_dynamic_resupply" .. item_dynamic_resupply:EntIndex() )
|
||||
item_item_crate:DeleteOnRemove( item_dynamic_resupply )
|
||||
end
|
||||
|
||||
item_item_crate:SetKeyValue( "CrateAppearance", appearance )
|
||||
item_item_crate:SetKeyValue( "ItemClass", class )
|
||||
item_item_crate:SetKeyValue( "ItemCount", math.Clamp( amount , 1, 25 ) )
|
||||
|
||||
item_item_crate:Spawn()
|
||||
item_item_crate:Activate()
|
||||
|
||||
if ( health ) then item_item_crate:Fire( "SetHealth", math.Clamp( health, 1, 100 ) ) end
|
||||
|
||||
if ( appearance and appearance == 1 ) then -- Episode 2 Jalopy radar thingy
|
||||
local t = ents.Create( "info_radar_target" )
|
||||
t:SetPos( item_item_crate:GetPos() )
|
||||
t:SetKeyValue( "mode", 0 )
|
||||
t:SetKeyValue( "type", 0 )
|
||||
t:SetKeyValue( "radius", 1200 )
|
||||
t:Spawn()
|
||||
t:Activate()
|
||||
t:Fire( "Enable" )
|
||||
t:SetParent( item_item_crate )
|
||||
end
|
||||
|
||||
table.Merge( item_item_crate:GetTable(), {
|
||||
ply = ply,
|
||||
appearance = appearance,
|
||||
class = class,
|
||||
amount = amount,
|
||||
health = health,
|
||||
dynamic_values = dynamic_values,
|
||||
} )
|
||||
|
||||
if ( IsValid( ply ) ) then
|
||||
ply:AddCount( "item_item_crates", item_item_crate )
|
||||
ply:AddCleanup( "item_item_crates", item_item_crate )
|
||||
end
|
||||
|
||||
DoPropSpawnedEffect( item_item_crate )
|
||||
|
||||
return item_item_crate
|
||||
end
|
||||
|
||||
duplicator.RegisterEntityClass( "item_item_crate", MakeItemCrate, "pos", "ang", "appearance", "class", "amount", "health", "dynamic_values" )
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
if ( trace.HitSky or !trace.HitPos or IsValid( trace.Entity ) and ( trace.Entity:IsPlayer() or trace.Entity:IsNPC() ) ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
local ang = trace.HitNormal:Angle()
|
||||
ang.pitch = ang.pitch - 270
|
||||
|
||||
if ( trace.HitNormal.z > 0.9999 ) then ang.y = ply:GetAngles().y + 90 end
|
||||
|
||||
local item = self:GetClientInfo( "item" )
|
||||
if ( item == "" ) then
|
||||
local t = {}
|
||||
for k, v in pairs( list.Get( "ItemCrateItems" ) ) do
|
||||
if ( k == "#tool.item_item_crate.random" ) then continue end
|
||||
table.insert( t, v.item_item_crate_item )
|
||||
end
|
||||
|
||||
item = t[ math.random( 1, #t ) ]
|
||||
end
|
||||
|
||||
local contains = false
|
||||
for k, v in pairs( list.Get( "ItemCrateItems" ) ) do
|
||||
if ( !v.item_item_crate_item ) then continue end
|
||||
if ( item != v.item_item_crate_item ) then continue end
|
||||
contains = true
|
||||
end
|
||||
|
||||
if ( !contains ) then return end
|
||||
|
||||
local dynamic_values = {
|
||||
DesiredHealth = self:GetClientInfo( "desired_health" ) / 100,
|
||||
DesiredArmor = self:GetClientInfo( "desired_armor" ) / 100,
|
||||
DesiredAmmoPistol = self:GetClientInfo( "desired_pistol" ) / 100,
|
||||
DesiredAmmoSMG1 = self:GetClientInfo( "desired_smg1" ) / 100,
|
||||
DesiredAmmoSMG1_Grenade = self:GetClientInfo( "desired_smg1_alt" ) / 100,
|
||||
DesiredAmmoAR2 = self:GetClientInfo( "desired_ar2" ) / 100,
|
||||
DesiredAmmoBuckshot = self:GetClientInfo( "desired_shotgun" ) / 100,
|
||||
DesiredAmmoRPG_Round = self:GetClientInfo( "desired_rpg" ) / 100,
|
||||
DesiredAmmoGrenade = self:GetClientInfo( "desired_grenade" ) / 100,
|
||||
DesiredAmmo357 = self:GetClientInfo( "desired_357" ) / 100,
|
||||
DesiredAmmoCrossbow = self:GetClientInfo( "desired_crossbow" ) / 100,
|
||||
DesiredAmmoAR2_AltFire = self:GetClientInfo( "desired_ar2_alt" ) / 100
|
||||
}
|
||||
|
||||
local item_item_crate = MakeItemCrate( ply, trace.HitPos, ang, self.Models[ self:GetClientInfo( "model" ) ], item, self:GetClientNumber( "amount" ), self:GetClientNumber( "health" ), dynamic_values )
|
||||
|
||||
undo.Create( "item_item_crate" )
|
||||
undo.AddEntity( item_item_crate )
|
||||
undo.SetPlayer( ply )
|
||||
undo.Finish()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:UpdateGhostEntity( ent, ply )
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local trace = ply:GetEyeTrace()
|
||||
|
||||
if ( !trace.Hit ) then return end
|
||||
if ( IsValid( trace.Entity ) and ( trace.Entity:GetClass() == "item_item_crate" or trace.Entity:IsPlayer() ) ) then ent:SetNoDraw( true ) return end
|
||||
|
||||
local ang = trace.HitNormal:Angle()
|
||||
ang.pitch = ang.pitch - 270
|
||||
|
||||
if ( trace.HitNormal.z > 0.9999 ) then ang.y = ply:GetAngles().y + 90 end
|
||||
|
||||
local min = ent:OBBMins()
|
||||
ent:SetPos( trace.HitPos - trace.HitNormal * min.z )
|
||||
|
||||
ent:SetAngles( ang )
|
||||
ent:SetNoDraw( false )
|
||||
end
|
||||
|
||||
function TOOL:Think()
|
||||
if ( !IsValid( self.GhostEntity ) or self.GhostEntity:GetModel() != self:GetClientInfo( "model" ) ) then
|
||||
self:MakeGhostEntity( self:GetClientInfo( "model" ), Vector( 0, 0, 0 ), Angle( 0, 0, 0 ) )
|
||||
end
|
||||
|
||||
self:UpdateGhostEntity( self.GhostEntity, self:GetOwner() )
|
||||
end
|
||||
|
||||
list.Set( "ItemCrateModels", "models/items/item_item_crate.mdl", {} )
|
||||
list.Set( "ItemCrateModels", "models/items/item_beacon_crate.mdl", {} )
|
||||
|
||||
list.Set( "ItemCrateItems", "#item_ammo_pistol", { item_item_crate_item = "item_ammo_pistol" } )
|
||||
list.Set( "ItemCrateItems", "#item_ammo_pistol_large", { item_item_crate_item = "item_ammo_pistol_large" } )
|
||||
list.Set( "ItemCrateItems", "#item_ammo_smg1", { item_item_crate_item = "item_ammo_smg1" } )
|
||||
list.Set( "ItemCrateItems", "#item_ammo_smg1_large", { item_item_crate_item = "item_ammo_smg1_large" } )
|
||||
list.Set( "ItemCrateItems", "#item_ammo_smg1_grenade", { item_item_crate_item = "item_ammo_smg1_grenade" } )
|
||||
list.Set( "ItemCrateItems", "#item_ammo_ar2", { item_item_crate_item = "item_ammo_ar2" } )
|
||||
list.Set( "ItemCrateItems", "#item_ammo_ar2_large", { item_item_crate_item = "item_ammo_ar2_large" } )
|
||||
list.Set( "ItemCrateItems", "#item_ammo_ar2_altfire", { item_item_crate_item = "item_ammo_ar2_altfire" } )
|
||||
list.Set( "ItemCrateItems", "#item_ammo_357", { item_item_crate_item = "item_ammo_357" } )
|
||||
list.Set( "ItemCrateItems", "#item_ammo_357_large", { item_item_crate_item = "item_ammo_357_large" } )
|
||||
list.Set( "ItemCrateItems", "#item_ammo_crossbow", { item_item_crate_item = "item_ammo_crossbow" } )
|
||||
list.Set( "ItemCrateItems", "#item_rpg_round", { item_item_crate_item = "item_rpg_round" } )
|
||||
list.Set( "ItemCrateItems", "#item_box_buckshot", { item_item_crate_item = "item_box_buckshot" } )
|
||||
list.Set( "ItemCrateItems", "#item_battery", { item_item_crate_item = "item_battery" } )
|
||||
list.Set( "ItemCrateItems", "#item_healthvial", { item_item_crate_item = "item_healthvial" } )
|
||||
list.Set( "ItemCrateItems", "#item_healthkit", { item_item_crate_item = "item_healthkit" } )
|
||||
list.Set( "ItemCrateItems", "#item_grubnugget", { item_item_crate_item = "item_grubnugget" } )
|
||||
list.Set( "ItemCrateItems", "#item_dynamic_resupply", { item_item_crate_item = "item_dynamic_resupply" } )
|
||||
list.Set( "ItemCrateItems", "#tool.item_item_crate.random", { item_item_crate_item = "" } )
|
||||
|
||||
list.Set( "ItemCrateItems", "#weapon_crowbar", { item_item_crate_item = "weapon_crowbar" } )
|
||||
list.Set( "ItemCrateItems", "#weapon_stunstick", { item_item_crate_item = "weapon_stunstick" } )
|
||||
list.Set( "ItemCrateItems", "#weapon_physcannon", { item_item_crate_item = "weapon_physcannon" } )
|
||||
list.Set( "ItemCrateItems", "#weapon_physgun", { item_item_crate_item = "weapon_physgun" } )
|
||||
list.Set( "ItemCrateItems", "#weapon_pistol", { item_item_crate_item = "weapon_pistol" } )
|
||||
list.Set( "ItemCrateItems", "#weapon_357", { item_item_crate_item = "weapon_357" } )
|
||||
list.Set( "ItemCrateItems", "#weapon_smg1", { item_item_crate_item = "weapon_smg1" } )
|
||||
list.Set( "ItemCrateItems", "#weapon_ar2", { item_item_crate_item = "weapon_ar2" } )
|
||||
list.Set( "ItemCrateItems", "#weapon_shotgun", { item_item_crate_item = "weapon_shotgun" } )
|
||||
list.Set( "ItemCrateItems", "#weapon_crossbow", { item_item_crate_item = "weapon_crossbow" } )
|
||||
list.Set( "ItemCrateItems", "#weapon_rpg", { item_item_crate_item = "weapon_rpg" } )
|
||||
list.Set( "ItemCrateItems", "#weapon_frag", { item_item_crate_item = "weapon_frag" } )
|
||||
|
||||
if ( SERVER ) then return end
|
||||
|
||||
TOOL.Information = { { name = "left" } }
|
||||
|
||||
concommand.Add( "item_item_crate_reset", function()
|
||||
RunConsoleCommand( "item_item_crate_desired_health", "100" )
|
||||
RunConsoleCommand( "item_item_crate_desired_armor", "30" )
|
||||
RunConsoleCommand( "item_item_crate_desired_pistol", "50" )
|
||||
RunConsoleCommand( "item_item_crate_desired_smg1", "50" )
|
||||
RunConsoleCommand( "item_item_crate_desired_smg1_alt", "10" )
|
||||
RunConsoleCommand( "item_item_crate_desired_ar2", "40" )
|
||||
RunConsoleCommand( "item_item_crate_desired_shotgun", "50" )
|
||||
RunConsoleCommand( "item_item_crate_desired_rpg", "0" )
|
||||
RunConsoleCommand( "item_item_crate_desired_grenade", "10" )
|
||||
RunConsoleCommand( "item_item_crate_desired_357", "0" )
|
||||
RunConsoleCommand( "item_item_crate_desired_crossbow", "0" )
|
||||
RunConsoleCommand( "item_item_crate_desired_ar2_alt", "0" )
|
||||
end )
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
language.Add( "tool.item_item_crate", "Item Crates" )
|
||||
language.Add( "tool.item_item_crate.name", "Item Crate Tool" )
|
||||
language.Add( "tool.item_item_crate.desc", "Spawn item crates" )
|
||||
language.Add( "tool.item_item_crate.left", "Spawn an item crate" )
|
||||
|
||||
language.Add( "tool.item_item_crate.model", "Crate Model" )
|
||||
|
||||
language.Add( "tool.item_item_crate.contents", "Crate Contents" )
|
||||
language.Add( "tool.item_item_crate.random", "Random Item" )
|
||||
|
||||
language.Add( "tool.item_item_crate.amount", "Content Amount:" )
|
||||
language.Add( "tool.item_item_crate.amount.help", "The amount of items to put into item crate." )
|
||||
language.Add( "tool.item_item_crate.health", "Crate Health:" )
|
||||
language.Add( "tool.item_item_crate.health.help", "Amount of damage the item crate can take before it will break." )
|
||||
|
||||
language.Add( "tool.item_item_crate.edit", "Edit Dynamic Resupply Item Values" )
|
||||
language.Add( "tool.item_item_crate.back", "Return back" )
|
||||
language.Add( "tool.item_item_crate.reset", "Reset to defaults" )
|
||||
|
||||
language.Add( "Cleanup_item_item_crates", "Item Crates" )
|
||||
language.Add( "Cleaned_item_item_crates", "Cleaned up all Item Crates" )
|
||||
language.Add( "SBoxLimit_item_item_crates", "You've hit the Item Crates limit!" )
|
||||
language.Add( "Undone_item_item_crate", "Item Crate undone" )
|
||||
|
||||
language.Add( "max_item_item_crates", "Max Item Crates:" )
|
||||
|
||||
language.Add( "tool.item_item_crate.desired_health", "Health:" )
|
||||
language.Add( "tool.item_item_crate.desired_armor", "Armor:" )
|
||||
language.Add( "tool.item_item_crate.desired_pistol", "Pistol ammo:" )
|
||||
language.Add( "tool.item_item_crate.desired_smg1", "SMG1 ammo:" )
|
||||
language.Add( "tool.item_item_crate.desired_smg1_alt", "SMG1 Grenades:" )
|
||||
language.Add( "tool.item_item_crate.desired_ar2", "AR2 ammo:" )
|
||||
language.Add( "tool.item_item_crate.desired_shotgun", "Shotgun Ammo:" )
|
||||
language.Add( "tool.item_item_crate.desired_rpg", "RPG Rounds:" )
|
||||
language.Add( "tool.item_item_crate.desired_grenade", "Grenades:" )
|
||||
language.Add( "tool.item_item_crate.desired_357", ".357 Ammo:" )
|
||||
language.Add( "tool.item_item_crate.desired_crossbow", "Crossbow Ammo:" )
|
||||
language.Add( "tool.item_item_crate.desired_ar2_alt", "AR2 Energy Balls:" )
|
||||
language.Add( "tool.item_item_crate.desired_ar2_alt.help", "A dynamic ressuply item. When the player enters the PVS of this entity, it will determine the item most needed by the player, spawn one of those items, and remove itself. To determine which item the player most needs, it calculates which of the Desired Health/Armor/Ammo ratios the player is farthest from.\n\nIf the player is above all the desired levels, then no item will be spawned." )
|
||||
|
||||
function TOOL.BuildCPanel( panel )
|
||||
panel:AddControl( "ComboBox", { MenuButton = 1, Folder = "item_item_crate", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
panel:AddControl( "PropSelect", { Label = "#tool.item_item_crate.model", Height = 1, ConVar = "item_item_crate_model", Models = list.Get( "ItemCrateModels" ) } )
|
||||
panel:AddControl( "ListBox", { Label = "#tool.item_item_crate.contents", Height = 256, Options = list.Get( "ItemCrateItems" ) } )
|
||||
|
||||
panel:AddControl( "Slider", { Label = "#tool.item_item_crate.amount", Min = 1, Max = 25, Command = "item_item_crate_amount", Help = true } )
|
||||
panel:AddControl( "Slider", { Label = "#tool.item_item_crate.health", Min = 1, Max = 100, Command = "item_item_crate_health", Help = true } )
|
||||
|
||||
panel:Help( "#tool.item_item_crate.desired_ar2_alt.help" )
|
||||
|
||||
panel:AddControl( "Slider", { Label = "#tool.item_item_crate.desired_health", Max = 100, Command = "item_item_crate_desired_health" } )
|
||||
panel:AddControl( "Slider", { Label = "#tool.item_item_crate.desired_armor", Max = 100, Command = "item_item_crate_desired_armor" } )
|
||||
panel:AddControl( "Slider", { Label = "#tool.item_item_crate.desired_pistol", Max = 100, Command = "item_item_crate_desired_pistol" } )
|
||||
panel:AddControl( "Slider", { Label = "#tool.item_item_crate.desired_smg1", Max = 100, Command = "item_item_crate_desired_smg1" } )
|
||||
panel:AddControl( "Slider", { Label = "#tool.item_item_crate.desired_smg1_alt", Max = 100, Command = "item_item_crate_desired_smg1_alt" } )
|
||||
panel:AddControl( "Slider", { Label = "#tool.item_item_crate.desired_ar2", Max = 100, Command = "item_item_crate_desired_ar2" } )
|
||||
panel:AddControl( "Slider", { Label = "#tool.item_item_crate.desired_shotgun", Max = 100, Command = "item_item_crate_desired_shotgun" } )
|
||||
panel:AddControl( "Slider", { Label = "#tool.item_item_crate.desired_rpg", Max = 100, Command = "item_item_crate_desired_rpg" } )
|
||||
panel:AddControl( "Slider", { Label = "#tool.item_item_crate.desired_grenade", Max = 100, Command = "item_item_crate_desired_grenade" } )
|
||||
panel:AddControl( "Slider", { Label = "#tool.item_item_crate.desired_357", Max = 100, Command = "item_item_crate_desired_357" } )
|
||||
panel:AddControl( "Slider", { Label = "#tool.item_item_crate.desired_crossbow", Max = 100, Command = "item_item_crate_desired_crossbow" } )
|
||||
panel:AddControl( "Slider", { Label = "#tool.item_item_crate.desired_ar2_alt", Max = 100, Command = "item_item_crate_desired_ar2_alt" } )
|
||||
|
||||
panel:Button( "#tool.item_item_crate.reset", "item_item_crate_reset" )
|
||||
end
|
||||
418
lua/weapons/gmod_tool/stools/ladder.lua
Normal file
418
lua/weapons/gmod_tool/stools/ladder.lua
Normal file
@@ -0,0 +1,418 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile();
|
||||
|
||||
TOOL.Category = "Construction"
|
||||
TOOL.Name = "Ladders"
|
||||
TOOL.ClientConVar["laddername"] = "";
|
||||
TOOL.ClientConVar["model"] = "models/props_c17/metalladder001.mdl";
|
||||
TOOL.Information = {
|
||||
{name = "left", stage = 0},
|
||||
{name = "right", stage = 0},
|
||||
{name = "left_next", stage = 1, icon = "gui/lmb.png"}
|
||||
};
|
||||
|
||||
/*
|
||||
ladderOptions is a list of approved models that can be used in the tool.
|
||||
Prevents people from using console to set the model to something that won't work.
|
||||
|
||||
Parameters:
|
||||
- origin: Where is the origin of the ladder in relation to the bottom? If the ladder's :GetPos() is in the center, find the unit distance between the bottom and center.
|
||||
See the third ladder in the table.
|
||||
- height: How many units tall is this ladder?
|
||||
- ladderOffset: How many units away from the wall should the ladder entity be placed?
|
||||
- propOffset: How many units away from the wall should the ladder props be placed?
|
||||
*/
|
||||
|
||||
local ladderOptions = {
|
||||
["models/props_c17/metalladder001.mdl"] = {
|
||||
origin = vector_origin,
|
||||
height = 127.5,
|
||||
ladderOffset = 25,
|
||||
propOffset = 2.5
|
||||
},
|
||||
|
||||
["models/props_c17/metalladder002.mdl"] = {
|
||||
origin = vector_origin,
|
||||
height = 127.5,
|
||||
ladderOffset = 30
|
||||
},
|
||||
|
||||
["models/props/cs_militia/ladderrung.mdl"] = {
|
||||
origin = Vector(0, 0, 63.75),
|
||||
height = 127.5,
|
||||
ladderOffset = 25
|
||||
},
|
||||
|
||||
["models/props/cs_militia/ladderwood.mdl"] = {
|
||||
origin = Vector(0, 0, 74),
|
||||
height = 147,
|
||||
ladderOffset = 20,
|
||||
propOffset = 1
|
||||
},
|
||||
};
|
||||
|
||||
cleanup.Register("ladders");
|
||||
cleanup.Register("ladder_dismounts");
|
||||
|
||||
if (SERVER) then
|
||||
if (!ConVarExists("sbox_maxladders")) then
|
||||
CreateConVar("sbox_maxladders", 5, {FCVAR_ARCHIVE, FCVAR_REPLICATED}, "Maximum number of ladders which can be created by users.");
|
||||
end;
|
||||
|
||||
if (!ConVarExists("sbox_maxladder_dismounts")) then
|
||||
CreateConVar("sbox_maxladder_dismounts", 10, {FCVAR_ARCHIVE, FCVAR_REPLICATED}, "Maximum number of dismount points which can be created by users. Recommended to be double the number of ladders (two for each ladder).");
|
||||
end;
|
||||
end;
|
||||
|
||||
/*
|
||||
Helper function to get segments on a line.
|
||||
*/
|
||||
|
||||
local function GetSegments(p1, p2, segLength, bInclusive)
|
||||
local points = {};
|
||||
local distance = p1:Distance(p2);
|
||||
local norm = (p2 - p1):GetNormalized();
|
||||
|
||||
local total = math.floor(distance / segLength);
|
||||
local nextPos = p1;
|
||||
|
||||
if (bInclusive) then
|
||||
table.insert(points, p1);
|
||||
end;
|
||||
|
||||
for i = 1, total do
|
||||
nextPos = nextPos + norm * segLength;
|
||||
table.insert(points, nextPos);
|
||||
end;
|
||||
|
||||
if (bInclusive) then
|
||||
table.insert(points, p2);
|
||||
end;
|
||||
|
||||
return points;
|
||||
end;
|
||||
|
||||
/*
|
||||
Ladder Creation
|
||||
*/
|
||||
do
|
||||
local dismountHull = {
|
||||
mins = Vector(-16, -16, 0),
|
||||
maxs = Vector(16, 16, 4)
|
||||
};
|
||||
|
||||
function TOOL:LeftClick(trace)
|
||||
if (IsValid(trace.Entity) and trace.Entity:IsPlayer()) then return false; end;
|
||||
if (CLIENT) then return true; end;
|
||||
if (!self:GetOwner():CheckLimit("ladders")) then return false; end;
|
||||
|
||||
-- If we haven't selected a first point...
|
||||
if (self:GetStage() == 0) then
|
||||
-- Retrieve the physics object of any hit entity. Made useless by previous code, but /something/ needs to go into SetObject...
|
||||
-- As well, retrieve a modified version of the surface normal. This normal is always horizontal and only rotates around the Y axis. Yay straight ladders.
|
||||
local physObj = trace.Entity:GetPhysicsObjectNum(trace.PhysicsBone);
|
||||
local normal = Angle(0, trace.HitNormal:Angle().y, 0):Forward();
|
||||
|
||||
-- Clear out any junk that could possibly be left over, and store our data.
|
||||
self:ClearObjects();
|
||||
self:SetObject(1, trace.Entity, trace.HitPos, physObj, trace.PhysicsBone, normal);
|
||||
|
||||
-- Move to the next stage.
|
||||
self:SetStage(1);
|
||||
else
|
||||
-- Same as before, and check how far away the ladder entity needs to be created, based on which model we're using.
|
||||
local physObj = trace.Entity:GetPhysicsObjectNum(trace.PhysicsBone);
|
||||
local normal = Angle(0, trace.HitNormal:Angle().y, 0):Forward();
|
||||
local model = self:GetClientInfo("model");
|
||||
|
||||
-- If the user is being maLICIOUS and trying to use a model not on the list, default to the standard ladder.
|
||||
if (!ladderOptions[model]) then
|
||||
model = "models/props_c17/metalladder001.mdl";
|
||||
end;
|
||||
|
||||
local options = ladderOptions[model];
|
||||
local offset = options.ladderOffset;
|
||||
|
||||
-- Store the data of our second click.
|
||||
self:SetObject(2, trace.Entity, trace.HitPos, physObj, trace.PhysicsBone, normal);
|
||||
|
||||
-- Define the top and bottom points of our func_useableladder.
|
||||
local top = self:GetPos(1) + self:GetNormal(1) * offset;
|
||||
local bottom = Vector(self:GetPos(1).x, self:GetPos(1).y, self:GetPos(2).z + 5) + self:GetNormal(1) * offset;
|
||||
|
||||
-- Create a table to hold all of the created prop_physics. This is used later for undo.AddEntity, and for dismount parenting.
|
||||
-- Then, retrieve all of the segment points in a straight line from top to bottom of the ladder.
|
||||
local ladderProps = {};
|
||||
local fixOffset = options.height - options.origin.z;
|
||||
local topPos = self:GetPos(1) - Vector(0, 0, fixOffset);
|
||||
local bottomPos = Vector(self:GetPos(1).x, self:GetPos(1).y, self:GetPos(2).z) + options.origin + Vector(0, 0, 1);
|
||||
local points = GetSegments(topPos, bottomPos, options.height, true);
|
||||
|
||||
-- If our bottom point manages to be higher than our top, remove it.
|
||||
if (topPos.z < bottomPos.z) then
|
||||
table.remove(points);
|
||||
end;
|
||||
|
||||
-- Start our undo stack.
|
||||
undo.Create("Ladder");
|
||||
|
||||
-- If a point is too close for whatever reason, remove it.
|
||||
for i = 1, #points do
|
||||
if (points[i - 1]) then
|
||||
if (points[i - 1]:Distance(points[i]) < 30) then
|
||||
table.remove(points, i);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
-- For every point in our table of segments, create a prop_physics, destroy its physics object, and add it to the undo stack.
|
||||
for k, pos in pairs(points) do
|
||||
local ladder = ents.Create("prop_physics");
|
||||
ladder:SetPos(pos + self:GetNormal(1) * (options.propOffset or 0));
|
||||
ladder:SetAngles(self:GetNormal(1):Angle());
|
||||
ladder:SetModel(model);
|
||||
ladder:Spawn();
|
||||
|
||||
ladder:GetPhysicsObject():EnableMotion(false);
|
||||
ladder:PhysicsDestroy();
|
||||
|
||||
table.insert(ladderProps, ladder);
|
||||
undo.AddEntity(ladder);
|
||||
end;
|
||||
|
||||
-- Create the actual ladder entity.
|
||||
local ladderEnt = ents.Create("func_useableladder");
|
||||
ladderEnt:SetPos(LerpVector(0.5, top, bottom));
|
||||
ladderEnt:SetKeyValue("point0", tostring(bottom));
|
||||
ladderEnt:SetKeyValue("point1", tostring(top));
|
||||
|
||||
local targetName = self:GetClientInfo("laddername");
|
||||
|
||||
if (!targetName or targetName == "") then
|
||||
targetName = ladderEnt:EntIndex();
|
||||
end;
|
||||
|
||||
ladderEnt:SetKeyValue("targetname", "zladder_" .. targetName);
|
||||
ladderEnt:SetParent(ladderProps[1]);
|
||||
ladderEnt:Spawn();
|
||||
|
||||
ladderEnt:CallOnRemove("cleanup", function(ladder)
|
||||
if (!ladder.props) then return; end;
|
||||
|
||||
for k, v in pairs(ladder.props) do
|
||||
SafeRemoveEntity(v);
|
||||
end;
|
||||
end);
|
||||
|
||||
-- Store all the props on the ladder entity.
|
||||
ladderEnt.propTable = {};
|
||||
ladderEnt.props = {};
|
||||
ladderEnt.model = model;
|
||||
|
||||
-- Store our normal on the ladder.
|
||||
ladderEnt.normal = self:GetNormal(1);
|
||||
|
||||
-- Let our hook inside lua/autorun know that the props here have a ladder attached, so disallow +USE on them.
|
||||
for k, v in pairs(ladderProps) do
|
||||
v.ladder = ladderEnt;
|
||||
|
||||
v:DrawShadow(false);
|
||||
v:SetCollisionGroup(COLLISION_GROUP_WORLD);
|
||||
|
||||
table.insert(ladderEnt.propTable, {
|
||||
origin = v:GetPos(),
|
||||
angles = v:GetAngles()
|
||||
});
|
||||
|
||||
table.insert(ladderEnt.props, v);
|
||||
|
||||
v:SetNWEntity("ladder", ladderEnt);
|
||||
end;
|
||||
|
||||
local topTrace = util.TraceHull({
|
||||
start = self:GetPos(1) - self:GetNormal(1) * 17 + Vector(0, 0, 5),
|
||||
endpos = self:GetPos(1) - self:GetNormal(1) * 17 - Vector(0, 0, 15),
|
||||
mins = dismountHull.mins,
|
||||
maxs = dismountHull.maxs,
|
||||
filter = function(ent) if (ent:IsPlayer() or ent:IsNPC()) then return false; else return true; end; end;
|
||||
});
|
||||
|
||||
if (topTrace.Hit and !topTrace.AllSolid and !topTrace.StartSolid) then
|
||||
local topDismount = ents.Create("info_ladder_dismount");
|
||||
topDismount:SetPos(topTrace.HitPos);
|
||||
topDismount:Spawn();
|
||||
topDismount:SetParent(ladderEnt);
|
||||
topDismount:SetName("zdismount_" .. topDismount:EntIndex());
|
||||
end;
|
||||
|
||||
local bottomTrace = util.TraceHull({
|
||||
start = bottom + self:GetNormal(1) * 34 + Vector(0, 0, 5),
|
||||
endpos = bottom + self:GetNormal(1) * 34 - Vector(0, 0, 15),
|
||||
mins = dismountHull.mins,
|
||||
maxs = dismountHull.maxs,
|
||||
filter = function(ent) if (ent:IsPlayer() or ent:IsNPC()) then return false; else return true; end; end;
|
||||
});
|
||||
|
||||
if (bottomTrace.Hit and !bottomTrace.AllSolid and !bottomTrace.StartSolid) then
|
||||
local bottomDismount = ents.Create("info_ladder_dismount");
|
||||
bottomDismount:SetPos(bottomTrace.HitPos);
|
||||
bottomDismount:Spawn();
|
||||
bottomDismount:SetParent(ladderEnt);
|
||||
bottomDismount:SetName("zdismount_" .. bottomDismount:EntIndex());
|
||||
end;
|
||||
|
||||
-- Push the ladder entity onto our undo stack.
|
||||
undo.AddEntity(ladderEnt);
|
||||
|
||||
-- Set the undo owner, the text, and close the stack.
|
||||
undo.SetPlayer(self:GetOwner());
|
||||
undo.SetCustomUndoText("Undone Ladder");
|
||||
undo.Finish();
|
||||
|
||||
-- Calling CFuncLadder::Activate will force the ladder to search for dismount points near the top and bottom.
|
||||
ladderEnt:Activate();
|
||||
|
||||
-- We've finished making our ladder, so go back to stage 0, clear any objects, and add 1 to our cleanup count.
|
||||
self:SetStage(0);
|
||||
self:ClearObjects();
|
||||
|
||||
self:GetOwner():AddCount("ladders", ladderEnt);
|
||||
self:GetOwner():AddCleanup("ladders", ladderEnt);
|
||||
end;
|
||||
|
||||
return true;
|
||||
end;
|
||||
|
||||
/*
|
||||
Dismount Placing
|
||||
*/
|
||||
|
||||
function TOOL:RightClick(trace)
|
||||
if (IsValid(trace.Entity) and trace.Entity:IsPlayer()) then return false; end;
|
||||
if (self:GetStage() > 0) then return false; end;
|
||||
if (CLIENT) then return true; end;
|
||||
if (!self:GetOwner():CheckLimit("ladder_dismounts")) then return false; end;
|
||||
|
||||
-- Perform a hull trace the size of a dismount spot to determine a safe place to put it. If the dismount is intersecting with ANY geometry-
|
||||
-- the engine will consider it blocked, and the player cannot use it.
|
||||
local hullTrace = util.TraceHull({
|
||||
start = trace.HitPos + trace.HitNormal * 16,
|
||||
endpos = trace.HitPos - trace.HitNormal * 10,
|
||||
mins = dismountHull.mins,
|
||||
maxs = dismountHull.maxs
|
||||
});
|
||||
|
||||
if (!hullTrace.Hit) then return false; end;
|
||||
|
||||
-- targetName will be the name of the ladder this dismount is going to attach to.
|
||||
local targetName = self:GetClientInfo("laddername");
|
||||
local dismount = ents.Create("info_ladder_dismount");
|
||||
dismount:SetPos(hullTrace.HitPos);
|
||||
dismount:SetKeyValue("targetname", "zdismount_" .. dismount:EntIndex());
|
||||
|
||||
-- If targetName was specified, set the key value. m_target tells the engine that this dismount spot only works for ladders whose names equal this.
|
||||
if (targetName and targetName != "") then
|
||||
dismount:SetKeyValue("target", "zladder_" .. targetName);
|
||||
end;
|
||||
|
||||
dismount:Spawn();
|
||||
|
||||
-- Loop through all entities on the map. If it's a ladder, and it has our custom prefix, then check if its entity name is equal to our current name.
|
||||
-- If so, parent it, so that when the ladder is removed, it cleans up the dismount.
|
||||
for k, v in pairs(ents.GetAll()) do
|
||||
if (v:GetClass() == "func_useableladder" and v:GetName():find("zladder_")) then
|
||||
if (targetName and targetName != "") then
|
||||
if (v:GetName() == "zladder_" .. targetName) then
|
||||
dismount:SetParent(v);
|
||||
end;
|
||||
end;
|
||||
|
||||
-- CFuncLadder::Activate, so dismount points for ladders are updated.
|
||||
v:Activate();
|
||||
end;
|
||||
end;
|
||||
|
||||
-- Create our undo stack, push the dismount point, assign ownership, then finish.
|
||||
undo.Create("Ladder Dismount");
|
||||
undo.AddEntity(dismount);
|
||||
undo.SetPlayer(self:GetOwner());
|
||||
undo.SetCustomUndoText("Undone Ladder Dismount");
|
||||
undo.Finish();
|
||||
|
||||
-- Add the dismount point to our cleanup count.
|
||||
self:GetOwner():AddCount("ladder_dismounts", dismount);
|
||||
self:GetOwner():AddCleanup("ladder_dismounts", dismount);
|
||||
|
||||
return true;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TOOL:Think()
|
||||
end
|
||||
|
||||
/*
|
||||
Holster
|
||||
Clear stored objects and reset state
|
||||
*/
|
||||
|
||||
function TOOL:Holster()
|
||||
self:ClearObjects();
|
||||
self:SetStage(0);
|
||||
end;
|
||||
|
||||
/*
|
||||
Control Panel
|
||||
*/
|
||||
|
||||
function TOOL.BuildCPanel(CPanel)
|
||||
local modelTable = {};
|
||||
|
||||
for k, v in pairs(ladderOptions) do
|
||||
modelTable[k] = {};
|
||||
end;
|
||||
|
||||
CPanel:AddControl("Header", {
|
||||
Description = "#tool.ladder.desc"
|
||||
});
|
||||
|
||||
CPanel:AddControl("TextBox", {
|
||||
Label = "Ladder Name",
|
||||
Command = "ladder_laddername"
|
||||
});
|
||||
|
||||
CPanel:AddControl("PropSelect", {
|
||||
Label = "Select a model to use",
|
||||
ConVar = "ladder_model",
|
||||
Height = 1,
|
||||
Width = 3,
|
||||
Models = modelTable
|
||||
});
|
||||
|
||||
end;
|
||||
|
||||
/*
|
||||
Language strings
|
||||
*/
|
||||
|
||||
if (CLIENT) then
|
||||
language.Add("tool.ladder.name", "Ladders");
|
||||
language.Add("tool.ladder.left", "Select the top point for your ladder.");
|
||||
language.Add("tool.ladder.right", "Place a dismount point.");
|
||||
language.Add("tool.ladder.left_next", "Now left click anywhere lower than your first point to determine the height.");
|
||||
language.Add("tool.ladder.desc", "Create ladders, duh.");
|
||||
|
||||
language.Add("Cleaned_ladders", "Cleaned up all Ladders");
|
||||
language.Add("Cleanup_ladders", "Ladders");
|
||||
|
||||
language.Add("Cleaned_ladder_dismounts", "Cleaned up all Ladder Dismounts");
|
||||
language.Add("Cleanup_ladder_dismounts", "Ladder Dismounts");
|
||||
end;
|
||||
221
lua/weapons/gmod_tool/stools/mannable_changemodel.lua
Normal file
221
lua/weapons/gmod_tool/stools/mannable_changemodel.lua
Normal file
@@ -0,0 +1,221 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
TOOL.Category = "Jakub Baku Mannables"
|
||||
TOOL.Name = "#tool.mannable_changemodel.name"
|
||||
|
||||
TOOL.ClientConVar[ "model" ] = "models/airboatgun.mdl"
|
||||
TOOL.ClientConVar[ "hidegun" ] = 0
|
||||
TOOL.ClientConVar[ "bone" ] = 0
|
||||
|
||||
TOOL.ClientConVar[ "posx" ] = 0
|
||||
TOOL.ClientConVar[ "posy" ] = 0
|
||||
TOOL.ClientConVar[ "posz" ] = 0
|
||||
TOOL.ClientConVar[ "scalex" ] = 0
|
||||
TOOL.ClientConVar[ "scaley" ] = 0
|
||||
TOOL.ClientConVar[ "scalez" ] = 0
|
||||
TOOL.ClientConVar[ "rotx" ] = 0
|
||||
TOOL.ClientConVar[ "roty" ] = 0
|
||||
TOOL.ClientConVar[ "rotz" ] = 0
|
||||
|
||||
if(CLIENT) then
|
||||
language.Add("tool.mannable_changemodel.name", "Change Emplacement Model" )
|
||||
language.Add("tool.mannable_changemodel.desc", "Left click to select entity, right click to sample, reload to apply" )
|
||||
language.Add("tool.mannable_changemodel.0", "REMEMBER TO APPLY (RELOAD)" )
|
||||
language.Add("tool.mannable_changemodel.help", "Edit the settings" )
|
||||
|
||||
local functions = {
|
||||
["retrieve"] = function()
|
||||
local ent = net.ReadEntity()
|
||||
|
||||
if(!IsValid(ent)) then return end
|
||||
|
||||
if(IsValid(ent._CustomGunModel)) then
|
||||
RunConsoleCommand("mannable_changemodel_model", ent._CustomGunModel:GetModel())
|
||||
end
|
||||
|
||||
local mat = ent._GunModelMatrix
|
||||
|
||||
if(mat) then
|
||||
local pos = mat:GetTranslation()
|
||||
local scale = mat:GetScale()
|
||||
local rot = mat:GetAngles()
|
||||
|
||||
RunConsoleCommand("mannable_changemodel_posx", tostring(pos.x))
|
||||
RunConsoleCommand("mannable_changemodel_posy", tostring(pos.y))
|
||||
RunConsoleCommand("mannable_changemodel_posz", tostring(pos.z))
|
||||
RunConsoleCommand("mannable_changemodel_scalex", tostring(scale.x))
|
||||
RunConsoleCommand("mannable_changemodel_scaley", tostring(scale.y))
|
||||
RunConsoleCommand("mannable_changemodel_scalez", tostring(scale.z))
|
||||
RunConsoleCommand("mannable_changemodel_rotx", tostring(rot.pitch))
|
||||
RunConsoleCommand("mannable_changemodel_roty", tostring(rot.yaw))
|
||||
RunConsoleCommand("mannable_changemodel_rotz", tostring(rot.roll))
|
||||
end
|
||||
end,
|
||||
["updent"] = function()
|
||||
local ent = net.ReadEntity()
|
||||
local mdl = net.ReadString()
|
||||
local mat = net.ReadMatrix()
|
||||
local bone = net.ReadInt(32)
|
||||
|
||||
if(!IsValid(ent) or ent.Base != "ent_mannable_bakubase") then return end
|
||||
|
||||
ent:SetupCustomModel(mdl, bone)
|
||||
ent._GunModelMatrix = mat
|
||||
end
|
||||
}
|
||||
|
||||
net.Receive("mannable_tool_changemodel", function(len, ply)
|
||||
local command = net.ReadString()
|
||||
|
||||
if(isfunction(functions[command])) then
|
||||
functions[command]()
|
||||
end
|
||||
end)
|
||||
|
||||
function TOOL:Think()
|
||||
local ent = self:GetWeapon():GetNWEntity("ent")
|
||||
if(!IsValid(ent) or ent.Base != "ent_mannable_bakubase") then return end
|
||||
|
||||
local mat = Matrix()
|
||||
mat:SetTranslation(Vector(
|
||||
self:GetClientNumber("posx"),
|
||||
self:GetClientNumber("posy"),
|
||||
self:GetClientNumber("posz")
|
||||
))
|
||||
mat:SetScale(Vector(self:GetClientNumber("scalex"),
|
||||
self:GetClientNumber("scaley"),
|
||||
self:GetClientNumber("scalez")))
|
||||
mat:SetAngles(Angle(self:GetClientNumber("rotx"),
|
||||
self:GetClientNumber("roty"),
|
||||
self:GetClientNumber("rotz")))
|
||||
|
||||
ent._GunModelMatrix = mat
|
||||
end
|
||||
|
||||
local FacePoser = surface.GetTextureID( "gui/faceposer_indicator" )
|
||||
|
||||
function TOOL:DrawHUD()
|
||||
|
||||
if ( GetConVarNumber( "gmod_drawtooleffects" ) == 0 ) then return end
|
||||
|
||||
local selected = self:GetWeapon():GetNWEntity("ent")
|
||||
|
||||
if ( !IsValid( selected ) ) then return end
|
||||
|
||||
local pos = selected:GetPos()
|
||||
|
||||
local scrpos = pos:ToScreen()
|
||||
if ( !scrpos.visible ) then return end
|
||||
|
||||
-- Work out the side distance to give a rough headsize box..
|
||||
local player_eyes = LocalPlayer():EyeAngles()
|
||||
local side = ( pos + player_eyes:Right() * 20 ):ToScreen()
|
||||
local size = math.abs( side.x - scrpos.x ) * 0.5
|
||||
|
||||
surface.SetDrawColor( 255, 255, 255, 255 )
|
||||
surface.SetTexture( FacePoser )
|
||||
surface.DrawTexturedRect( scrpos.x - size, scrpos.y - size, size * 2, size * 2 )
|
||||
|
||||
end
|
||||
else
|
||||
util.AddNetworkString("mannable_tool_changemodel")
|
||||
|
||||
function TOOL:ApplySettings()
|
||||
local ent = self:GetWeapon():GetNWEntity("ent")
|
||||
|
||||
if(!IsValid(ent) or ent.Base != "ent_mannable_bakubase") then return end
|
||||
|
||||
local mdl = self:GetClientInfo("model")
|
||||
local mat = Matrix()
|
||||
mat:SetTranslation(Vector(
|
||||
self:GetClientNumber("posx"),
|
||||
self:GetClientNumber("posy"),
|
||||
self:GetClientNumber("posz")
|
||||
))
|
||||
mat:SetScale(Vector(self:GetClientNumber("scalex"),
|
||||
self:GetClientNumber("scaley"),
|
||||
self:GetClientNumber("scalez")))
|
||||
mat:SetAngles(Angle(self:GetClientNumber("rotx"),
|
||||
self:GetClientNumber("roty"),
|
||||
self:GetClientNumber("rotz")))
|
||||
local bone = self:GetClientNumber("bone")
|
||||
|
||||
net.Start("mannable_tool_changemodel")
|
||||
net.WriteString("updent")
|
||||
net.WriteEntity(ent)
|
||||
net.WriteString(mdl)
|
||||
net.WriteMatrix(mat)
|
||||
net.WriteInt(bone, 32)
|
||||
net.Broadcast()
|
||||
|
||||
ent._HideGunModel = self:GetClientNumber("hidegun") > 0
|
||||
|
||||
if(ent._HideGunModel) then
|
||||
ent:SetModel("models/props_combine/bunker_gun01_nogun.mdl")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
if(!IsValid(trace.Entity) or trace.Entity.Base != "ent_mannable_bakubase") then return false end
|
||||
if(CLIENT) then return true end
|
||||
|
||||
net.Start("mannable_tool_changemodel")
|
||||
net.WriteString("retrieve")
|
||||
net.WriteEntity(trace.Entity)
|
||||
net.Send(self:GetOwner())
|
||||
|
||||
self:GetWeapon():SetNWEntity("ent", trace.Entity)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
if(!IsValid(trace.Entity) or trace.Entity.Base != "ent_mannable_bakubase") then return false end
|
||||
if(CLIENT) then return true end
|
||||
|
||||
net.Start("mannable_tool_changemodel")
|
||||
net.WriteString("retrieve")
|
||||
net.WriteEntity(trace.Entity)
|
||||
net.Send(self:GetOwner())
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:Reload(trace)
|
||||
if(!IsValid(trace.Entity) or self:GetWeapon():GetNWEntity("ent") != trace.Entity) then return false end
|
||||
if(CLIENT) then return true end
|
||||
|
||||
self:ApplySettings()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
CPanel:AddControl( "Header", { Description = "#tool.mannable_changemodel.help" } )
|
||||
|
||||
CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "mannable_changemodel", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
CPanel:AddControl( "CheckBox", { Label = "Hide gun model", Command = "mannable_changemodel_hidegun" } )
|
||||
|
||||
CPanel:AddControl( "TextBox", { Label = "Custom gun model", Command = "mannable_changemodel_model" } )
|
||||
CPanel:AddControl( "Label", { text = "Position, rotation, scale" } )
|
||||
CPanel:AddControl( "Slider", { Label = "Pos X", Command = "mannable_changemodel_posx", min = -50, max = 50, type = "float" } )
|
||||
CPanel:AddControl( "Slider", { Label = "Pos Y", Command = "mannable_changemodel_posy", min = -50, max = 50, type = "float" } )
|
||||
CPanel:AddControl( "Slider", { Label = "Pos Z", Command = "mannable_changemodel_posz", min = -50, max = 50, type = "float" } )
|
||||
CPanel:AddControl( "Slider", { Label = "Scale X", Command = "mannable_changemodel_scalex", min = -50, max = 50, type = "float" } )
|
||||
CPanel:AddControl( "Slider", { Label = "Scale Y", Command = "mannable_changemodel_scaley", min = -50, max = 50, type = "float" } )
|
||||
CPanel:AddControl( "Slider", { Label = "Scale Z", Command = "mannable_changemodel_scalez", min = -50, max = 50, type = "float" } )
|
||||
CPanel:AddControl( "Slider", { Label = "Rotation X", Command = "mannable_changemodel_rotx", min = 0, max = 360, type = "float" } )
|
||||
CPanel:AddControl( "Slider", { Label = "Rotation Y", Command = "mannable_changemodel_roty", min = 0, max = 360, type = "float" } )
|
||||
CPanel:AddControl( "Slider", { Label = "Rotation Z", Command = "mannable_changemodel_rotz", min = 0, max = 360, type = "float" } )
|
||||
end
|
||||
64
lua/weapons/gmod_tool/stools/nocollideworld.lua
Normal file
64
lua/weapons/gmod_tool/stools/nocollideworld.lua
Normal file
@@ -0,0 +1,64 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
TOOL.Category = "Construction"
|
||||
TOOL.Name = "#No Collide World"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
if CLIENT then
|
||||
language.Add("Tool.nocollideworld.name", "No Collide World")
|
||||
language.Add("Tool.nocollideworld.desc", "Make a prop not collide with anything, including the world")
|
||||
language.Add("Tool.nocollideworld.0", "Left click on an object to make it not collide with anything. Right click to return an object to normal.")
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if (!trace.Entity ) then return end
|
||||
if (!trace.Entity:IsValid()) then return end
|
||||
if (trace.Entity:IsPlayer()) then return end
|
||||
|
||||
local PhysObj = trace.Entity:GetPhysicsObject()
|
||||
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
if ( trace.Entity.CollisionGroup != COLLISION_GROUP_WORLD && PhysObj:IsCollisionEnabled() ) then
|
||||
|
||||
trace.Entity:SetCollisionGroup( COLLISION_GROUP_WORLD )
|
||||
trace.Entity.CollisionGroup = COLLISION_GROUP_WORLD
|
||||
PhysObj:EnableCollisions(false)
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
if (!trace.Entity ) then return end
|
||||
if (!trace.Entity:IsValid()) then return end
|
||||
if (trace.Entity:IsPlayer()) then return end
|
||||
|
||||
local PhysObj = trace.Entity:GetPhysicsObject()
|
||||
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
if ( trace.Entity.CollisionGroup == COLLISION_GROUP_WORLD && !PhysObj:IsCollisionEnabled() ) then
|
||||
|
||||
trace.Entity:SetCollisionGroup( COLLISION_GROUP_NONE )
|
||||
trace.Entity.CollisionGroup = COLLISION_GROUP_NONE
|
||||
PhysObj:EnableCollisions(true)
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
804
lua/weapons/gmod_tool/stools/particlecontrol.lua
Normal file
804
lua/weapons/gmod_tool/stools/particlecontrol.lua
Normal file
@@ -0,0 +1,804 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
TOOL.Category = "Particle Controller"
|
||||
TOOL.Name = "Adv. Particle Control"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
TOOL.HighlightedEnt = nil
|
||||
|
||||
TOOL.ClientConVar[ "effectname" ] = "env_fire_large"
|
||||
TOOL.ClientConVar[ "mode_beam" ] = "0"
|
||||
TOOL.beamattach1 = 0
|
||||
TOOL.beamattach2 = 0
|
||||
TOOL.ClientConVar[ "utileffect_scale" ] = "1"
|
||||
TOOL.ClientConVar[ "utileffect_magnitude" ] = "1"
|
||||
TOOL.ClientConVar[ "utileffect_radius" ] = "10"
|
||||
TOOL.ClientConVar[ "color_enabled" ] = "0"
|
||||
TOOL.ClientConVar[ "color_r" ] = "255"
|
||||
TOOL.ClientConVar[ "color_g" ] = "20"
|
||||
TOOL.ClientConVar[ "color_b" ] = "0"
|
||||
TOOL.ClientConVar[ "color_outofone" ] = "0"
|
||||
|
||||
TOOL.ClientConVar[ "attachnum" ] = "0"
|
||||
TOOL.ClientConVar[ "repeatrate" ] = "0"
|
||||
TOOL.ClientConVar[ "repeatsafety" ] = "1"
|
||||
|
||||
TOOL.ClientConVar[ "propmodel" ] = "models/hunter/plates/plate.mdl"
|
||||
TOOL.ClientConVar[ "propangle" ] = "1"
|
||||
TOOL.ClientConVar[ "propinvis" ] = "0"
|
||||
|
||||
TOOL.ClientConVar[ "numpadkey" ] = "52"
|
||||
TOOL.ClientConVar[ "toggle" ] = "1"
|
||||
TOOL.ClientConVar[ "starton" ] = "1"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "info1", stage = 1, icon = "gui/info.png" },
|
||||
{ name = "left0", stage = 0, icon = "gui/lmb.png" },
|
||||
{ name = "left1", stage = 1, icon = "gui/lmb.png" },
|
||||
{ name = "middle01", icon = "gui/mmb.png" },
|
||||
{ name = "right0", stage = 0, icon = "gui/rmb.png" },
|
||||
{ name = "right1", stage = 1, icon = "gui/rmb.png" },
|
||||
{ name = "reload0", stage = 0, icon = "gui/r.png" },
|
||||
{ name = "reload1", stage = 1, icon = "gui/r.png" },
|
||||
}
|
||||
|
||||
if ( CLIENT ) then
|
||||
language.Add( "tool.particlecontrol.name", "Advanced Particle Controller" )
|
||||
language.Add( "tool.particlecontrol.desc", "Attach particle effects to things" )
|
||||
language.Add( "tool.particlecontrol.help", "Particles are used for all sorts of different special effects. You can attach them to models and turn them on and off with a key." )
|
||||
|
||||
language.Add( "tool.particlecontrol.info1", "BEAM EFFECT: Attaches to two points" )
|
||||
language.Add( "tool.particlecontrol.left0", "Add an effect to an object" )
|
||||
language.Add( "tool.particlecontrol.left1", "Add the other end to an object" )
|
||||
language.Add( "tool.particlecontrol.middle01", "Scroll through an object's attachments" )
|
||||
language.Add( "tool.particlecontrol.right0", "Attach a new prop with the effect on it" )
|
||||
language.Add( "tool.particlecontrol.right1", "Attach a new prop and add the other end to it" )
|
||||
language.Add( "tool.particlecontrol.reload0", "Remove all effects from an object" )
|
||||
language.Add( "tool.particlecontrol.reload1", "Cancel beam effect" )
|
||||
end
|
||||
|
||||
util.PrecacheSound("weapons/pistol/pistol_empty.wav")
|
||||
|
||||
|
||||
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
local effectname = self:GetClientInfo( "effectname", 0 )
|
||||
local attachnum = self:GetClientNumber( "attachnum", 0 )
|
||||
|
||||
local repeatrate = self:GetClientNumber( "repeatrate", 0 )
|
||||
local repeatsafety = self:GetClientNumber( "repeatsafety", 0 )
|
||||
|
||||
local numpadkey = self:GetClientNumber( "numpadkey", 0 )
|
||||
local toggle = self:GetClientNumber( "toggle", 0 )
|
||||
local starton = self:GetClientNumber( "starton", 0 )
|
||||
|
||||
local utileffectinfo = Vector( self:GetClientNumber( "utileffect_scale", 0 ), self:GetClientNumber( "utileffect_magnitude", 0 ), self:GetClientNumber( "utileffect_radius", 0 ) )
|
||||
local colorinfo = nil
|
||||
if self:GetClientNumber( "color_enabled", 0 ) == 1 then
|
||||
if self:GetClientNumber( "color_outofone", 0 ) == 1 then
|
||||
colorinfo = Color( self:GetClientNumber( "color_r", 0 ), self:GetClientNumber( "color_g", 0 ), self:GetClientNumber( "color_b", 0 ), 1 ) //we're using the alpha value to store color_outofone
|
||||
else
|
||||
colorinfo = Color( self:GetClientNumber( "color_r", 0 ), self:GetClientNumber( "color_g", 0 ), self:GetClientNumber( "color_b", 0 ), 0 )
|
||||
end
|
||||
end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
|
||||
|
||||
|
||||
if self:GetClientNumber( "mode_beam", 0 ) == 0 then
|
||||
//Not a beam, attach the effect to one entity
|
||||
if ( trace.Entity:IsValid() ) then
|
||||
if CLIENT then return true end
|
||||
if trace.Entity:GetClass() == "prop_effect" and trace.Entity.AttachedEntity then trace.Entity = trace.Entity.AttachedEntity end
|
||||
AttachParticleControllerNormal( ply, trace.Entity, { NewTable = {
|
||||
EffectName = effectname,
|
||||
AttachNum = attachnum,
|
||||
|
||||
RepeatRate = repeatrate,
|
||||
RepeatSafety = repeatsafety,
|
||||
|
||||
Toggle = toggle,
|
||||
StartOn = starton,
|
||||
NumpadKey = numpadkey,
|
||||
|
||||
UtilEffectInfo = utileffectinfo,
|
||||
ColorInfo = colorinfo
|
||||
} } )
|
||||
return true
|
||||
end
|
||||
else
|
||||
//It's a beam, attach the effect between two entities
|
||||
local iNum = self:NumObjects()
|
||||
|
||||
if ( trace.Entity:IsValid() ) then
|
||||
//if CLIENT then return true end
|
||||
if trace.Entity:GetClass() == "prop_effect" and trace.Entity.AttachedEntity then trace.Entity = trace.Entity.AttachedEntity end
|
||||
|
||||
self:SetObject( iNum + 1, trace.Entity, trace.HitPos, nil, nil, trace.HitNormal )
|
||||
if iNum == 0 then
|
||||
self.beamattach1 = attachnum
|
||||
else
|
||||
self.beamattach2 = attachnum
|
||||
end
|
||||
|
||||
if ( iNum > 0 ) then
|
||||
if ( CLIENT ) then
|
||||
self:ClearObjects()
|
||||
return true
|
||||
end
|
||||
|
||||
local Ent1, Ent2 = self:GetEnt(1), self:GetEnt(2)
|
||||
local constraint = constraint.AttachParticleControllerBeam( Ent1, Ent2, {
|
||||
EffectName = effectname,
|
||||
AttachNum = self.beamattach1,
|
||||
AttachNum2 = self.beamattach2,
|
||||
|
||||
RepeatRate = repeatrate,
|
||||
RepeatSafety = repeatsafety,
|
||||
|
||||
Toggle = toggle,
|
||||
StartOn = starton,
|
||||
NumpadKey = numpadkey,
|
||||
|
||||
UtilEffectInfo = utileffectinfo,
|
||||
ColorInfo = colorinfo
|
||||
}, ply )
|
||||
|
||||
self:ClearObjects()
|
||||
else
|
||||
self:SetStage( iNum+1 )
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
local effectname = self:GetClientInfo( "effectname", 0 )
|
||||
local attachnum = self:GetClientNumber( "attachnum", 0 )
|
||||
|
||||
local repeatrate = self:GetClientNumber( "repeatrate", 0 )
|
||||
local repeatsafety = self:GetClientNumber( "repeatsafety", 0 )
|
||||
|
||||
local numpadkey = self:GetClientNumber( "numpadkey", 0 )
|
||||
local toggle = self:GetClientNumber( "toggle", 0 )
|
||||
local starton = self:GetClientNumber( "starton", 0 )
|
||||
|
||||
local utileffectinfo = Vector( self:GetClientNumber( "utileffect_scale", 0 ), self:GetClientNumber( "utileffect_magnitude", 0 ), self:GetClientNumber( "utileffect_radius", 0 ) )
|
||||
local colorinfo = nil
|
||||
if self:GetClientNumber( "color_enabled", 0 ) == 1 then
|
||||
if self:GetClientNumber( "color_outofone", 0 ) == 1 then
|
||||
colorinfo = Color( self:GetClientNumber( "color_r", 0 ), self:GetClientNumber( "color_g", 0 ), self:GetClientNumber( "color_b", 0 ), 1 ) //we're using the alpha value to store color_outofone
|
||||
else
|
||||
colorinfo = Color( self:GetClientNumber( "color_r", 0 ), self:GetClientNumber( "color_g", 0 ), self:GetClientNumber( "color_b", 0 ), 0 )
|
||||
end
|
||||
end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
|
||||
|
||||
|
||||
local propmodel = self:GetClientInfo( "propmodel", 0 )
|
||||
local propangle = self:GetClientNumber( "propangle", 0 )
|
||||
//propangle 1: spawn upright
|
||||
//propangle 2: spawn at surface angle
|
||||
|
||||
if !util.IsValidModel(propmodel) then return false end
|
||||
if !util.IsValidProp(propmodel) then return false end
|
||||
if CLIENT then return true end
|
||||
|
||||
prop = ents.Create( "prop_physics" )
|
||||
prop:SetModel( propmodel )
|
||||
prop:SetPos( trace.HitPos - trace.HitNormal * prop:OBBMins().z )
|
||||
if propangle == 1 then prop:SetAngles(Angle(0,trace.HitNormal:Angle().y,0)) else prop:SetAngles(trace.HitNormal:Angle()) end
|
||||
prop:SetCollisionGroup(20) //COLLISION_GROUP_NONE, nocollide with everything except world
|
||||
prop:Spawn()
|
||||
|
||||
local shouldweweld = true //don't weld if...
|
||||
if ( !util.IsValidPhysicsObject(prop, 0) ) then shouldweweld = false end //the prop doesn't have a phys object
|
||||
if ( !trace.Entity:IsValid() ) then shouldweweld = false end //the thing we clicked on doesn't exist/is the world
|
||||
if ( trace.Entity && trace.Entity:IsPlayer() ) then shouldweweld = false end //the thing we clicked on is a player
|
||||
if ( !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then shouldweweld = false end //the thing we clicked on doesn't have a phys object
|
||||
if shouldweweld == true then
|
||||
local const = constraint.Weld( prop, trace.Entity, 0, trace.PhysicsBone, 0, true, true )
|
||||
else
|
||||
if util.IsValidPhysicsObject(prop, 0) then prop:GetPhysicsObject():EnableMotion(false) end
|
||||
end
|
||||
|
||||
if self:GetClientNumber( "propinvis", 0 ) == 1 then
|
||||
prop:SetRenderMode(1) //we need to change the render mode so the transparency actually shows up
|
||||
prop:SetColor( Color(255,255,255,0) )
|
||||
duplicator.StoreEntityModifier( prop, "colour", { Color = Color(255,255,255,0), RenderMode = 1, RenderFX = 0 } )
|
||||
end
|
||||
|
||||
undo.Create( "prop" )
|
||||
undo.AddEntity( prop )
|
||||
undo.SetPlayer( ply )
|
||||
undo.Finish( "Prop ("..tostring(propmodel)..")" )
|
||||
|
||||
|
||||
|
||||
if ( !prop:IsValid() ) then return false end
|
||||
if self:GetClientNumber( "mode_beam", 0 ) == 0 then
|
||||
//Not a beam, attach the effect to one entity.
|
||||
AttachParticleControllerNormal( ply, prop, { NewTable = {
|
||||
EffectName = effectname,
|
||||
AttachNum = attachnum,
|
||||
|
||||
RepeatRate = repeatrate,
|
||||
RepeatSafety = repeatsafety,
|
||||
|
||||
Toggle = toggle,
|
||||
StartOn = starton,
|
||||
NumpadKey = numpadkey,
|
||||
|
||||
UtilEffectInfo = utileffectinfo,
|
||||
ColorInfo = colorinfo
|
||||
} } )
|
||||
else
|
||||
//It's a beam, attach the effect between two entities
|
||||
local iNum = self:NumObjects()
|
||||
|
||||
self:SetObject( iNum + 1, prop, trace.HitPos, nil, nil, trace.HitNormal )
|
||||
if iNum == 0 then
|
||||
self.beamattach1 = attachnum
|
||||
else
|
||||
self.beamattach2 = attachnum
|
||||
end
|
||||
|
||||
if ( iNum > 0 ) then
|
||||
if ( CLIENT ) then
|
||||
self:ClearObjects()
|
||||
return true
|
||||
end
|
||||
|
||||
local Ent1, Ent2 = self:GetEnt(1), self:GetEnt(2)
|
||||
local constraint = constraint.AttachParticleControllerBeam( Ent1, Ent2, {
|
||||
EffectName = effectname,
|
||||
AttachNum = self.beamattach1,
|
||||
AttachNum2 = self.beamattach2,
|
||||
|
||||
RepeatRate = repeatrate,
|
||||
RepeatSafety = repeatsafety,
|
||||
|
||||
Toggle = toggle,
|
||||
StartOn = starton,
|
||||
NumpadKey = numpadkey,
|
||||
|
||||
UtilEffectInfo = utileffectinfo,
|
||||
ColorInfo = colorinfo
|
||||
}, ply )
|
||||
|
||||
self:ClearObjects()
|
||||
else
|
||||
self:SetStage( iNum+1 )
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
|
||||
//if we've selected something for a beam effect, then let us deselect it with reload
|
||||
if self:GetClientNumber( "mode_beam", 0 ) != 0 and self:NumObjects() > 0 then
|
||||
//self:GetEnt(1)
|
||||
self:ClearObjects()
|
||||
self:SetStage(0)
|
||||
return true
|
||||
end
|
||||
|
||||
if ( trace.Entity:IsValid() ) then
|
||||
local fx = false
|
||||
|
||||
if trace.Entity:GetClass() == "prop_effect" and trace.Entity.AttachedEntity then trace.Entity = trace.Entity.AttachedEntity end
|
||||
|
||||
for _, asdf in pairs( ents:GetAll() ) do
|
||||
if asdf:GetClass() == "particlecontroller_normal" then
|
||||
if asdf:GetParent() == trace.Entity then
|
||||
if SERVER then asdf:Remove() end
|
||||
fx = true
|
||||
end
|
||||
if IsValid(asdf:GetTargetEnt2()) then
|
||||
if asdf:GetTargetEnt2() == trace.Entity or asdf:GetTargetEnt2():GetParent() == trace.Entity then
|
||||
if SERVER then asdf:Remove() end
|
||||
fx = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if SERVER then
|
||||
duplicator.ClearEntityModifier( trace.Entity, "DupeParticleControllerNormal" )
|
||||
constraint.RemoveConstraints( trace.Entity, "AttachParticleControllerBeam" )
|
||||
end
|
||||
|
||||
return fx
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
if CLIENT then
|
||||
|
||||
local colorborder = Color(0,0,0,255)
|
||||
local colorselect = Color(0,255,0,255)
|
||||
local colorunselect = Color(255,255,255,255)
|
||||
|
||||
function TOOL:DrawHUD()
|
||||
local pl = LocalPlayer()
|
||||
local tr = pl:GetEyeTrace()
|
||||
local attachnum = self:GetClientNumber( "attachnum", 0 )
|
||||
|
||||
local function DrawHighlightAttachments(ent)
|
||||
|
||||
//If there aren't any attachments, then draw the model origin as selected and stop here:
|
||||
if !ent:GetAttachments() or !ent:GetAttachments()[1] then
|
||||
local _pos,_ang = ent:GetPos(), ent:GetAngles()
|
||||
local _pos = _pos:ToScreen()
|
||||
local textpos = {x = _pos.x+5,y = _pos.y-5}
|
||||
|
||||
draw.RoundedBox(0,_pos.x - 3,_pos.y - 3,6,6,colorborder)
|
||||
draw.RoundedBox(0,_pos.x - 1,_pos.y - 1,2,2,colorselect)
|
||||
draw.SimpleTextOutlined("0: (origin)","Default",textpos.x,textpos.y,colorselect,TEXT_ALIGN_LEFT,TEXT_ALIGN_BOTTOM,2,colorborder)
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
//Draw the unselected model origin, if applicable:
|
||||
if ent:GetAttachments()[attachnum] then
|
||||
local _pos,_ang = ent:GetPos(), ent:GetAngles()
|
||||
local _pos = _pos:ToScreen()
|
||||
local textpos = {x = _pos.x+5,y = _pos.y-5}
|
||||
|
||||
draw.RoundedBox(0,_pos.x - 2,_pos.y - 2,4,4,colorborder)
|
||||
draw.RoundedBox(0,_pos.x - 1,_pos.y - 1,2,2,colorunselect)
|
||||
draw.SimpleTextOutlined("0: (origin)","Default",textpos.x,textpos.y,colorunselect,TEXT_ALIGN_LEFT,TEXT_ALIGN_BOTTOM,1,colorborder)
|
||||
end
|
||||
|
||||
//Draw the unselected attachment points:
|
||||
for _, table in pairs(ent:GetAttachments()) do
|
||||
local _pos,_ang = ent:GetAttachment(table.id).Pos,ent:GetAttachment(table.id).Ang
|
||||
local _pos = _pos:ToScreen()
|
||||
local textpos = {x = _pos.x+5,y = _pos.y-5}
|
||||
|
||||
if table.id != attachnum then
|
||||
draw.RoundedBox(0,_pos.x - 2,_pos.y - 2,4,4,colorborder)
|
||||
draw.RoundedBox(0,_pos.x - 1,_pos.y - 1,2,2,colorunselect)
|
||||
draw.SimpleTextOutlined(table.id ..": ".. table.name,"Default",textpos.x,textpos.y,colorunselect,TEXT_ALIGN_LEFT,TEXT_ALIGN_BOTTOM,1,colorborder)
|
||||
end
|
||||
end
|
||||
|
||||
//Draw the selected attachment point or model origin last, so it renders above all the others:
|
||||
if !ent:GetAttachments()[attachnum] then
|
||||
//Model origin
|
||||
local _pos,_ang = ent:GetPos(), ent:GetAngles()
|
||||
local _pos = _pos:ToScreen()
|
||||
local textpos = {x = _pos.x+5,y = _pos.y-5}
|
||||
|
||||
draw.RoundedBox(0,_pos.x - 3,_pos.y - 3,6,6,colorborder)
|
||||
draw.RoundedBox(0,_pos.x - 1,_pos.y - 1,2,2,colorselect)
|
||||
draw.SimpleTextOutlined("0: (origin)","Default",textpos.x,textpos.y,colorselect,TEXT_ALIGN_LEFT,TEXT_ALIGN_BOTTOM,2,colorborder)
|
||||
else
|
||||
//Attachment
|
||||
local _pos,_ang = ent:GetAttachment(attachnum).Pos,ent:GetAttachment(attachnum).Ang
|
||||
local _pos = _pos:ToScreen()
|
||||
local textpos = {x = _pos.x+5,y = _pos.y-5}
|
||||
|
||||
draw.RoundedBox(0,_pos.x - 3,_pos.y - 3,6,6,colorborder)
|
||||
draw.RoundedBox(0,_pos.x - 1,_pos.y - 1,2,2,colorselect)
|
||||
draw.SimpleTextOutlined(attachnum ..": ".. ent:GetAttachments()[attachnum].name,"Default",textpos.x,textpos.y,colorselect,TEXT_ALIGN_LEFT,TEXT_ALIGN_BOTTOM,2,colorborder)
|
||||
end
|
||||
end
|
||||
|
||||
if IsValid(tr.Entity) and tr.Entity == self.HighlightedEnt then
|
||||
DrawHighlightAttachments(self.HighlightedEnt)
|
||||
return end
|
||||
|
||||
if IsValid(tr.Entity) and tr.Entity != self.HighlightedEnt then
|
||||
//unhighlight the old ent if it exists
|
||||
if self.HighlightedEnt != nil then
|
||||
self.HighlightedEnt = nil
|
||||
end
|
||||
|
||||
//highlight the new ent
|
||||
self.HighlightedEnt = tr.Entity
|
||||
end
|
||||
|
||||
if !IsValid(tr.Entity) and self.HighlightedEnt != nil then
|
||||
self.HighlightedEnt = nil
|
||||
end
|
||||
end
|
||||
|
||||
function TOOL:Holster()
|
||||
if self.HighlightedEnt != nil then
|
||||
self.HighlightedEnt = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
//All credit for the toolgun scroll wheel code goes to the Wiremod devs. You guys are the best.
|
||||
local function get_active_tool(ply, tool)
|
||||
-- find toolgun
|
||||
local activeWep = ply:GetActiveWeapon()
|
||||
if not IsValid(activeWep) or activeWep:GetClass() ~= "gmod_tool" or activeWep.Mode ~= tool then return end
|
||||
|
||||
return activeWep:GetToolObject(tool)
|
||||
end
|
||||
|
||||
local function hookfunc( ply, bind, pressed )
|
||||
if not pressed then return end
|
||||
if bind == "invnext" then
|
||||
local self = get_active_tool(ply, "particlecontrol")
|
||||
if not self then return end
|
||||
|
||||
return self:ScrollDown(ply:GetEyeTraceNoCursor())
|
||||
elseif bind == "invprev" then
|
||||
local self = get_active_tool(ply, "particlecontrol")
|
||||
if not self then return end
|
||||
|
||||
return self:ScrollUp(ply:GetEyeTraceNoCursor())
|
||||
end
|
||||
end
|
||||
|
||||
if game.SinglePlayer() then -- wtfgarry (have to have a delay in single player or the hook won't get added)
|
||||
timer.Simple(5,function() hook.Add( "PlayerBindPress", "particlecontrol_playerbindpress", hookfunc ) end)
|
||||
else
|
||||
hook.Add( "PlayerBindPress", "particlecontrol_playerbindpress", hookfunc )
|
||||
end
|
||||
//End shamefully copied code here.
|
||||
|
||||
function TOOL:Scroll(trace,dir)
|
||||
if !IsValid(self.HighlightedEnt) then return end
|
||||
|
||||
local attachcount = 0
|
||||
if self.HighlightedEnt:GetAttachments() then attachcount = table.Count(self.HighlightedEnt:GetAttachments()) end
|
||||
local oldattachnum = self:GetClientNumber( "attachnum", 0 )
|
||||
if oldattachnum > attachcount then oldattachnum = 0 end
|
||||
local attachnum = oldattachnum + dir
|
||||
|
||||
if attachnum < 0 then attachnum = attachcount end
|
||||
if attachnum > attachcount then attachnum = 0 end
|
||||
RunConsoleCommand("particlecontrol_attachnum", tostring(attachnum))
|
||||
self:GetOwner():EmitSound("weapons/pistol/pistol_empty.wav")
|
||||
return true
|
||||
end
|
||||
function TOOL:ScrollUp(trace) return self:Scroll(trace,-1) end
|
||||
function TOOL:ScrollDown(trace) return self:Scroll(trace,1) end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
if SERVER then
|
||||
|
||||
local function SpawnParticleControllerNormal(ply, ent, DataTable)
|
||||
|
||||
if DataTable == nil or DataTable == {} or DataTable.EffectName == nil or ent == nil or !IsValid(ent) then return end
|
||||
|
||||
|
||||
local ParticleControlNormal = ents.Create( "particlecontroller_normal" )
|
||||
ParticleControlNormal:SetPos(ent:GetPos())
|
||||
ParticleControlNormal:SetAngles(ent:GetAngles())
|
||||
ParticleControlNormal:SetParent(ent)
|
||||
ent:DeleteOnRemove(ParticleControlNormal)
|
||||
|
||||
ParticleControlNormal:SetTargetEnt(ent)
|
||||
ParticleControlNormal:SetEffectName(DataTable.EffectName)
|
||||
ParticleControlNormal:SetAttachNum(DataTable.AttachNum)
|
||||
ParticleControlNormal:SetUtilEffectInfo(DataTable.UtilEffectInfo)
|
||||
if DataTable.ColorInfo != nil then ParticleControlNormal:SetColor(DataTable.ColorInfo) else ParticleControlNormal:SetColor( Color(0,0,0,0) ) end
|
||||
|
||||
ParticleControlNormal:SetRepeatRate(DataTable.RepeatRate)
|
||||
if DataTable.RepeatSafety == 1 or DataTable.RepeatSafety == true then ParticleControlNormal:SetRepeatSafety(true) else ParticleControlNormal:SetRepeatSafety(false) end
|
||||
|
||||
|
||||
if DataTable.StartOn == 1 or DataTable.StartOn == true then ParticleControlNormal:SetActive(true) else ParticleControlNormal:SetActive(false) end
|
||||
if DataTable.Toggle == 1 or DataTable.Toggle == true then ParticleControlNormal:SetToggle(true) else ParticleControlNormal:SetToggle(false) end
|
||||
ParticleControlNormal:SetNumpadKey(DataTable.NumpadKey)
|
||||
|
||||
numpad.OnDown( ply, DataTable.NumpadKey, "Particle_Press", ParticleControlNormal )
|
||||
numpad.OnUp( ply, DataTable.NumpadKey, "Particle_Release", ParticleControlNormal )
|
||||
ParticleControlNormal:SetNumpadState("")
|
||||
|
||||
|
||||
ParticleControlNormal:Spawn()
|
||||
ParticleControlNormal:Activate()
|
||||
|
||||
end
|
||||
|
||||
|
||||
function AttachParticleControllerNormal( ply, ent, Data )
|
||||
|
||||
if Data.NewTable then
|
||||
SpawnParticleControllerNormal(ply, ent, Data.NewTable)
|
||||
|
||||
local dupetable = {}
|
||||
if ent.EntityMods and ent.EntityMods.DupeParticleControllerNormal then dupetable = ent.EntityMods.DupeParticleControllerNormal end
|
||||
table.insert(dupetable, Data.NewTable)
|
||||
duplicator.StoreEntityModifier( ent, "DupeParticleControllerNormal", dupetable )
|
||||
return end
|
||||
|
||||
end
|
||||
|
||||
|
||||
function DupeParticleControllerNormal( ply, ent, Data )
|
||||
|
||||
//due to a problem with the easy bonemerge tool that causes entity modifiers to be applied TWICE, we need to remove the effects that were added the first time
|
||||
for _, asdf in pairs( ents:GetAll() ) do
|
||||
if asdf:GetClass() == "particlecontroller_normal" and asdf:GetParent() == ent then
|
||||
asdf:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
for _, DataTable in pairs (Data) do
|
||||
SpawnParticleControllerNormal(ply, ent, DataTable)
|
||||
end
|
||||
|
||||
end
|
||||
duplicator.RegisterEntityModifier( "DupeParticleControllerNormal", DupeParticleControllerNormal )
|
||||
|
||||
|
||||
|
||||
|
||||
//we have to redefine some of the constraint functions here because they're local functions that don't exist outside of constraints.lua
|
||||
//not sure how well these'll work, one of them is ripped straight from the nocollide world tool which uses the same trick for its custom constraints
|
||||
local MAX_CONSTRAINTS_PER_SYSTEM = 100
|
||||
local function CreateConstraintSystem()
|
||||
local System = ents.Create("phys_constraintsystem")
|
||||
if !IsValid(System) then return end
|
||||
System:SetKeyValue("additionaliterations", GetConVarNumber("gmod_physiterations"))
|
||||
System:Spawn()
|
||||
System:Activate()
|
||||
return System
|
||||
end
|
||||
local function FindOrCreateConstraintSystem( Ent1, Ent2 )
|
||||
local System = nil
|
||||
Ent2 = Ent2 or Ent1
|
||||
-- Does Ent1 have a constraint system?
|
||||
if ( !Ent1:IsWorld() && Ent1:GetTable().ConstraintSystem && Ent1:GetTable().ConstraintSystem:IsValid() ) then
|
||||
System = Ent1:GetTable().ConstraintSystem
|
||||
end
|
||||
-- Don't add to this system - we have too many constraints on it already.
|
||||
if ( System && System:IsValid() && System:GetVar( "constraints", 0 ) > MAX_CONSTRAINTS_PER_SYSTEM ) then System = nil end
|
||||
-- Does Ent2 have a constraint system?
|
||||
if ( !System && !Ent2:IsWorld() && Ent2:GetTable().ConstraintSystem && Ent2:GetTable().ConstraintSystem:IsValid() ) then
|
||||
System = Ent2:GetTable().ConstraintSystem
|
||||
end
|
||||
-- Don't add to this system - we have too many constraints on it already.
|
||||
if ( System && System:IsValid() && System:GetVar( "constraints", 0 ) > MAX_CONSTRAINTS_PER_SYSTEM ) then System = nil end
|
||||
-- No constraint system yet (Or they're both full) - make a new one
|
||||
if ( !System || !System:IsValid() ) then
|
||||
--Msg("New Constrant System\n")
|
||||
System = CreateConstraintSystem()
|
||||
end
|
||||
Ent1.ConstraintSystem = System
|
||||
Ent2.ConstraintSystem = System
|
||||
System.UsedEntities = System.UsedEntities or {}
|
||||
table.insert( System.UsedEntities, Ent1 )
|
||||
table.insert( System.UsedEntities, Ent2 )
|
||||
local ConstraintNum = System:GetVar( "constraints", 0 )
|
||||
System:SetVar( "constraints", ConstraintNum + 1 )
|
||||
--Msg("System has "..tostring( System:GetVar( "constraints", 0 ) ).." constraints\n")
|
||||
return System
|
||||
end
|
||||
//end ripped constraint functions here.
|
||||
|
||||
//multiple-point "beam" effects use a constraint so the duplicator can group the two entities together
|
||||
function constraint.AttachParticleControllerBeam( Ent1, Ent2, Data, ply )
|
||||
if !Ent1 or !Ent2 then return end
|
||||
|
||||
//onStartConstraint( Ent1, Ent2 )
|
||||
local system = FindOrCreateConstraintSystem( Ent1, Ent2 )
|
||||
SetPhysConstraintSystem( system )
|
||||
|
||||
//create a dummy ent for the constraint functions to use
|
||||
local Constraint = ents.Create("logic_collision_pair")
|
||||
Constraint:Spawn()
|
||||
Constraint:Activate()
|
||||
|
||||
|
||||
|
||||
local ParticleControlBeam = ents.Create( "particlecontroller_normal" )
|
||||
ParticleControlBeam:SetPos(Ent1:GetPos())
|
||||
ParticleControlBeam:SetAngles(Ent1:GetAngles())
|
||||
ParticleControlBeam:SetParent(Ent1)
|
||||
Ent1:DeleteOnRemove(ParticleControlBeam)
|
||||
Ent2:DeleteOnRemove(ParticleControlBeam)
|
||||
|
||||
ParticleControlBeam:SetTargetEnt(Ent1)
|
||||
ParticleControlBeam:SetTargetEnt2(Ent2)
|
||||
ParticleControlBeam:SetEffectName(Data.EffectName)
|
||||
ParticleControlBeam:SetAttachNum(Data.AttachNum)
|
||||
ParticleControlBeam:SetAttachNum2(Data.AttachNum2)
|
||||
ParticleControlBeam:SetUtilEffectInfo(Data.UtilEffectInfo)
|
||||
if Data.ColorInfo != nil then ParticleControlBeam:SetColor(Data.ColorInfo) else ParticleControlBeam:SetColor( Color(0,0,0,0) ) end
|
||||
|
||||
ParticleControlBeam:SetRepeatRate(Data.RepeatRate)
|
||||
if Data.RepeatSafety == 1 or Data.RepeatSafety == true then ParticleControlBeam:SetRepeatSafety(true) else ParticleControlBeam:SetRepeatSafety(false) end
|
||||
|
||||
if Data.StartOn == 1 or Data.StartOn == true then ParticleControlBeam:SetActive(true) else ParticleControlBeam:SetActive(false) end
|
||||
if Data.Toggle == 1 or Data.Toggle == true then ParticleControlBeam:SetToggle(true) else ParticleControlBeam:SetToggle(false) end
|
||||
ParticleControlBeam:SetNumpadKey(Data.NumpadKey)
|
||||
|
||||
numpad.OnDown( ply, Data.NumpadKey, "Particle_Press", ParticleControlBeam )
|
||||
numpad.OnUp( ply, Data.NumpadKey, "Particle_Release", ParticleControlBeam )
|
||||
ParticleControlBeam:SetNumpadState("")
|
||||
|
||||
ParticleControlBeam:Spawn()
|
||||
ParticleControlBeam:Activate()
|
||||
|
||||
|
||||
|
||||
//onFinishConstraint( Ent1, Ent2 )
|
||||
SetPhysConstraintSystem( NULL )
|
||||
|
||||
constraint.AddConstraintTable( Ent1, Constraint, Ent2 )
|
||||
|
||||
local ctable =
|
||||
{
|
||||
Type = "AttachParticleControllerBeam",
|
||||
Ent1 = Ent1,
|
||||
Ent2 = Ent2,
|
||||
Data = Data,
|
||||
ply = ply,
|
||||
}
|
||||
|
||||
Constraint:SetTable( ctable )
|
||||
|
||||
return Constraint
|
||||
end
|
||||
duplicator.RegisterConstraint( "AttachParticleControllerBeam", constraint.AttachParticleControllerBeam, "Ent1", "Ent2", "Data", "ply" )
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
//we're still testing out a lot of stuff with the cpanel, so let's add a way to refresh it by reselecting the tool
|
||||
--[[
|
||||
TOOL.ClientConVar[ "refresh" ] = 1
|
||||
function TOOL:Think()
|
||||
if SERVER then return end
|
||||
if self:GetClientNumber("refresh") == 1 then
|
||||
RunConsoleCommand("particlecontrol_refresh", "0");
|
||||
//refresh the cpanel
|
||||
local panel = controlpanel.Get( "particlecontrol" )
|
||||
if ( !panel ) then return end
|
||||
panel:ClearControls()
|
||||
self.BuildCPanel(panel)
|
||||
end
|
||||
end
|
||||
function TOOL:Deploy()
|
||||
RunConsoleCommand("particlecontrol_refresh", "1");
|
||||
end
|
||||
]]
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
ConVarsDefault["particlecontrol_attachnum"] = nil //don't save the attachnum in presets, it's used by the other tools too
|
||||
|
||||
function TOOL.BuildCPanel(panel)
|
||||
|
||||
panel:AddControl( "Header", { Description = "#tool.particlecontrol.help" } )
|
||||
|
||||
//Presets
|
||||
panel:AddControl( "ComboBox", {
|
||||
MenuButton = 1,
|
||||
Folder = "particlecontrol",
|
||||
Options = {
|
||||
[ "#preset.default" ] = ConVarsDefault
|
||||
},
|
||||
CVars = table.GetKeys( ConVarsDefault )
|
||||
} )
|
||||
|
||||
|
||||
|
||||
AddParticleBrowser(panel, {
|
||||
name = "Effect",
|
||||
commands = {
|
||||
effectname = "particlecontrol_effectname",
|
||||
mode_beam = "particlecontrol_mode_beam",
|
||||
color = "particlecontrol_color",
|
||||
utileffect = "particlecontrol_utileffect",
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
|
||||
//panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
|
||||
|
||||
|
||||
panel:AddControl("Slider", {
|
||||
Label = "Attachment",
|
||||
Type = "Integer",
|
||||
Min = "0",
|
||||
Max = "10",
|
||||
Command = "particlecontrol_attachnum",
|
||||
})
|
||||
panel:ControlHelp( "Attachment point on the model to use. Set to 0 to attach to the model origin or to attach model-covering effects to the entire model." )
|
||||
|
||||
panel:AddControl("Slider", {
|
||||
Label = "Repeat Rate",
|
||||
Type = "Float",
|
||||
Min = "0",
|
||||
Max = "5",
|
||||
Command = "particlecontrol_repeatrate",
|
||||
})
|
||||
panel:ControlHelp( "How often the effect plays. Set to 0 to not repeat." )
|
||||
|
||||
panel:AddControl( "CheckBox", { Label = "Repeat Safety", Command = "particlecontrol_repeatsafety" } )
|
||||
panel:ControlHelp( "If on, effects are removed before being repeated. This stops them from piling up endlessly, but can also cause small problems, like effects being cut off. You should probably keep this on unless you know what you're doing." )
|
||||
|
||||
|
||||
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
|
||||
|
||||
|
||||
local modellist = { Label = "Prop", ConVar = "particlecontrol_propmodel", Category = "Prop", Height = 1, Models = {} }
|
||||
modellist.Models["models/hunter/plates/plate025x025.mdl"] = {}
|
||||
modellist.Models["models/hunter/plates/plate.mdl"] = {}
|
||||
modellist.Models["models/weapons/w_smg1.mdl"] = {}
|
||||
modellist.Models["models/props_junk/popcan01a.mdl"] = {}
|
||||
panel:AddControl( "PropSelect", modellist )
|
||||
|
||||
panel:AddControl( "ComboBox", {
|
||||
Label = "Prop Angle",
|
||||
MenuButton = "0",
|
||||
Options = {
|
||||
["Spawn upright"] = { particlecontrol_propangle = "1" },
|
||||
["Spawn at surface angle"] = { particlecontrol_propangle = "2" }
|
||||
}
|
||||
})
|
||||
|
||||
panel:AddControl( "CheckBox", { Label = "Invisible prop (particles only)", Command = "particlecontrol_propinvis" } )
|
||||
|
||||
|
||||
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
|
||||
|
||||
|
||||
panel:AddControl( "Numpad", {
|
||||
Label = "Effect Key",
|
||||
Command = "particlecontrol_numpadkey",
|
||||
})
|
||||
|
||||
panel:AddControl( "CheckBox", { Label = "Toggle", Command = "particlecontrol_toggle" } )
|
||||
|
||||
panel:AddControl( "CheckBox", { Label = "Start on?", Command = "particlecontrol_starton" } )
|
||||
|
||||
end
|
||||
893
lua/weapons/gmod_tool/stools/particlecontrol_proj.lua
Normal file
893
lua/weapons/gmod_tool/stools/particlecontrol_proj.lua
Normal file
@@ -0,0 +1,893 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
TOOL.Category = "Particle Controller"
|
||||
TOOL.Name = "ParCtrl - Projectiles"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
TOOL.HighlightedEnt = nil
|
||||
|
||||
TOOL.ClientConVar[ "projfx_enabled" ] = "1"
|
||||
TOOL.ClientConVar[ "projfx_effectname" ] = "Rocket_Smoke"
|
||||
TOOL.ClientConVar[ "projfx_utileffect_scale" ] = "1"
|
||||
TOOL.ClientConVar[ "projfx_utileffect_magnitude" ] = "1"
|
||||
TOOL.ClientConVar[ "projfx_utileffect_radius" ] = "10"
|
||||
TOOL.ClientConVar[ "projfx_color_enabled" ] = "0"
|
||||
TOOL.ClientConVar[ "projfx_color_r" ] = "255"
|
||||
TOOL.ClientConVar[ "projfx_color_g" ] = "20"
|
||||
TOOL.ClientConVar[ "projfx_color_b" ] = "0"
|
||||
TOOL.ClientConVar[ "projfx_color_outofone" ] = "0"
|
||||
|
||||
TOOL.ClientConVar[ "impactfx_enabled" ] = "1"
|
||||
TOOL.ClientConVar[ "impactfx_effectname" ] = "!UTILEFFECT!Explosion!FLAG4!"
|
||||
TOOL.ClientConVar[ "impactfx_utileffect_scale" ] = "1"
|
||||
TOOL.ClientConVar[ "impactfx_utileffect_magnitude" ] = "1"
|
||||
TOOL.ClientConVar[ "impactfx_utileffect_radius" ] = "10"
|
||||
TOOL.ClientConVar[ "impactfx_color_enabled" ] = "0"
|
||||
TOOL.ClientConVar[ "impactfx_color_r" ] = "255"
|
||||
TOOL.ClientConVar[ "impactfx_color_g" ] = "20"
|
||||
TOOL.ClientConVar[ "impactfx_color_b" ] = "0"
|
||||
TOOL.ClientConVar[ "impactfx_color_outofone" ] = "0"
|
||||
|
||||
//TOOL.ClientConVar[ "attachnum" ] = "1" //we're using the standard tool's attachnum var instead so that the selected attachment stays consistent when swapping between tools
|
||||
TOOL.ClientConVar[ "repeatrate" ] = "0.80"
|
||||
TOOL.ClientConVar[ "projmodel" ] = "models/weapons/w_missile.mdl"
|
||||
TOOL.ClientConVar[ "projmodel_skin" ] = "0"
|
||||
TOOL.ClientConVar[ "projmodel_attachnum" ] = "1"
|
||||
TOOL.ClientConVar[ "projmodel_material" ] = ""
|
||||
TOOL.ClientConVar[ "projmodel_invis" ] = "0"
|
||||
TOOL.ClientConVar[ "impactfx_effectlifetime" ] = "1.0"
|
||||
|
||||
TOOL.ClientConVar[ "projent_spread" ] = "0.04"
|
||||
TOOL.ClientConVar[ "projent_velocity" ] = "1000"
|
||||
TOOL.ClientConVar[ "projent_gravity" ] = "0"
|
||||
TOOL.ClientConVar[ "projent_angle" ] = "0"
|
||||
TOOL.ClientConVar[ "projent_spin" ] = "0"
|
||||
TOOL.ClientConVar[ "projent_demomanfix" ] = "0"
|
||||
TOOL.ClientConVar[ "projent_lifetime_prehit" ] = "10"
|
||||
TOOL.ClientConVar[ "projent_lifetime_posthit" ] = "0"
|
||||
TOOL.ClientConVar[ "projent_serverside" ] = "0"
|
||||
|
||||
TOOL.ClientConVar[ "propmodel" ] = "models/weapons/w_smg1.mdl"
|
||||
TOOL.ClientConVar[ "propangle" ] = "2"
|
||||
TOOL.ClientConVar[ "propinvis" ] = "0"
|
||||
|
||||
TOOL.ClientConVar[ "numpadkey" ] = "52"
|
||||
TOOL.ClientConVar[ "toggle" ] = "1"
|
||||
TOOL.ClientConVar[ "starton" ] = "1"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left0", stage = 0, icon = "gui/lmb.png" },
|
||||
{ name = "middle0", stage = 0, icon = "gui/mmb.png" },
|
||||
{ name = "right0", stage = 0, icon = "gui/rmb.png" },
|
||||
{ name = "reload0", stage = 0, icon = "gui/r.png" },
|
||||
}
|
||||
|
||||
if ( CLIENT ) then
|
||||
language.Add( "tool.particlecontrol_proj.name", "Adv. Particle Controller - Projectiles" )
|
||||
language.Add( "tool.particlecontrol_proj.desc", "Attach projectile effects to things" )
|
||||
language.Add( "tool.particlecontrol_proj.help", "Projectile effects launch props that have one particle attached to them, and another particle that plays once they expire, either on impact or on a timer." )
|
||||
|
||||
language.Add( "tool.particlecontrol_proj.left0", "Add a projectile effect to an object" )
|
||||
language.Add( "tool.particlecontrol_proj.middle0", "Scroll through an object's attachments" )
|
||||
language.Add( "tool.particlecontrol_proj.right0", "Attach a new prop with the projectile effect on it" )
|
||||
language.Add( "tool.particlecontrol_proj.reload0", "Remove all projectile effects from an object" )
|
||||
end
|
||||
|
||||
util.PrecacheSound("weapons/pistol/pistol_empty.wav")
|
||||
|
||||
|
||||
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
local projinfo = nil
|
||||
if self:GetClientNumber( "projfx_enabled", 0 ) == 1 then
|
||||
projinfo = {
|
||||
effectname = self:GetClientInfo( "projfx_effectname", 0 ),
|
||||
utileffectinfo = Vector( self:GetClientNumber( "projfx_utileffect_scale", 0 ), self:GetClientNumber( "projfx_utileffect_magnitude", 0 ), self:GetClientNumber( "projfx_utileffect_radius", 0 ) ),
|
||||
}
|
||||
if self:GetClientNumber( "projfx_color_enabled", 0 ) == 1 then
|
||||
if self:GetClientNumber( "projfx_color_outofone", 0 ) == 1 then
|
||||
projinfo.colorinfo = Color( self:GetClientNumber( "projfx_color_r", 0 ), self:GetClientNumber( "projfx_color_g", 0 ), self:GetClientNumber( "projfx_color_b", 0 ), 1 ) //we're using the alpha value to store color_outofone
|
||||
else
|
||||
projinfo.colorinfo = Color( self:GetClientNumber( "projfx_color_r", 0 ), self:GetClientNumber( "projfx_color_g", 0 ), self:GetClientNumber( "projfx_color_b", 0 ), 0 )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local impactinfo = nil
|
||||
if self:GetClientNumber( "impactfx_enabled", 0 ) == 1 then
|
||||
impactinfo = {
|
||||
effectname = self:GetClientInfo( "impactfx_effectname", 0 ),
|
||||
utileffectinfo = Vector( self:GetClientNumber( "impactfx_utileffect_scale", 0 ), self:GetClientNumber( "impactfx_utileffect_magnitude", 0 ), self:GetClientNumber( "impactfx_utileffect_radius", 0 ) ),
|
||||
}
|
||||
if self:GetClientNumber( "impactfx_color_enabled", 0 ) == 1 then
|
||||
if self:GetClientNumber( "impactfx_color_outofone", 0 ) == 1 then
|
||||
impactinfo.colorinfo = Color( self:GetClientNumber( "impactfx_color_r", 0 ), self:GetClientNumber( "impactfx_color_g", 0 ), self:GetClientNumber( "impactfx_color_b", 0 ), 1 ) //we're using the alpha value to store color_outofone
|
||||
else
|
||||
impactinfo.colorinfo = Color( self:GetClientNumber( "impactfx_color_r", 0 ), self:GetClientNumber( "impactfx_color_g", 0 ), self:GetClientNumber( "impactfx_color_b", 0 ), 0 )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local attachnum = self:GetOwner():GetInfoNum( "particlecontrol_attachnum", 0 ) //use the standard tool's attachnum var
|
||||
local repeatrate = self:GetClientNumber( "repeatrate", 0 )
|
||||
local projmodel = self:GetClientInfo( "projmodel", 0 )
|
||||
local projmodel_skin = self:GetClientNumber( "projmodel_skin", 0 )
|
||||
local projmodel_attachnum = self:GetClientNumber( "projmodel_attachnum", 0 )
|
||||
local projmodel_material = self:GetClientInfo( "projmodel_material", 0 )
|
||||
local projmodel_invis = self:GetClientNumber( "projmodel_invis", 0 )
|
||||
local impactfx_effectlifetime = self:GetClientNumber( "impactfx_effectlifetime", 0 )
|
||||
|
||||
local projent_spread = self:GetClientNumber( "projent_spread", 0 )
|
||||
local projent_velocity = self:GetClientNumber( "projent_velocity", 0 )
|
||||
local projent_gravity = self:GetClientNumber( "projent_gravity", 0 )
|
||||
local projent_angle = self:GetClientNumber( "projent_angle", 0 )
|
||||
local projent_spin = self:GetClientNumber( "projent_spin", 0 )
|
||||
local projent_demomanfix = self:GetClientNumber( "projent_demomanfix", 0 )
|
||||
local projent_lifetime_prehit = self:GetClientNumber( "projent_lifetime_prehit", 0 )
|
||||
local projent_lifetime_posthit = self:GetClientNumber( "projent_lifetime_posthit", 0 )
|
||||
local projent_serverside = self:GetClientNumber( "projent_serverside", 0 )
|
||||
|
||||
local numpadkey = self:GetClientNumber( "numpadkey", 0 )
|
||||
local toggle = self:GetClientNumber( "toggle", 0 )
|
||||
local starton = self:GetClientNumber( "starton", 0 )
|
||||
|
||||
local ply = self:GetOwner()
|
||||
|
||||
|
||||
|
||||
if ( trace.Entity:IsValid() ) then
|
||||
if CLIENT then return true end
|
||||
if trace.Entity:GetClass() == "prop_effect" and trace.Entity.AttachedEntity then trace.Entity = trace.Entity.AttachedEntity end
|
||||
AttachParticleControllerProj( ply, trace.Entity, { NewTable = {
|
||||
ProjFXInfo = projinfo,
|
||||
ImpactFXInfo = impactinfo,
|
||||
|
||||
AttachNum = attachnum,
|
||||
RepeatRate = repeatrate,
|
||||
ProjModel = projmodel,
|
||||
ProjModel_Skin = projmodel_skin,
|
||||
ProjModel_AttachNum = projmodel_attachnum,
|
||||
ProjModel_Material = projmodel_material,
|
||||
ProjModel_Invis = projmodel_invis,
|
||||
ImpactFX_EffectLifetime = impactfx_effectlifetime,
|
||||
|
||||
ProjEnt_Spread = projent_spread,
|
||||
ProjEnt_Velocity = projent_velocity,
|
||||
ProjEnt_Gravity = projent_gravity,
|
||||
ProjEnt_Angle = projent_angle,
|
||||
ProjEnt_Spin = projent_spin,
|
||||
ProjEnt_DemomanFix = projent_demomanfix,
|
||||
ProjEnt_Lifetime_PreHit = projent_lifetime_prehit,
|
||||
ProjEnt_Lifetime_PostHit = projent_lifetime_posthit,
|
||||
ProjEnt_Serverside = projent_serverside,
|
||||
|
||||
NumpadKey = numpadkey,
|
||||
Toggle = toggle,
|
||||
StartOn = starton,
|
||||
} } )
|
||||
return true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
local projinfo = nil
|
||||
if self:GetClientNumber( "projfx_enabled", 0 ) == 1 then
|
||||
projinfo = {
|
||||
effectname = self:GetClientInfo( "projfx_effectname", 0 ),
|
||||
utileffectinfo = Vector( self:GetClientNumber( "projfx_utileffect_scale", 0 ), self:GetClientNumber( "projfx_utileffect_magnitude", 0 ), self:GetClientNumber( "projfx_utileffect_radius", 0 ) ),
|
||||
}
|
||||
if self:GetClientNumber( "projfx_color_enabled", 0 ) == 1 then
|
||||
if self:GetClientNumber( "projfx_color_outofone", 0 ) == 1 then
|
||||
projinfo.colorinfo = Color( self:GetClientNumber( "projfx_color_r", 0 ), self:GetClientNumber( "projfx_color_g", 0 ), self:GetClientNumber( "projfx_color_b", 0 ), 1 ) //we're using the alpha value to store color_outofone
|
||||
else
|
||||
projinfo.colorinfo = Color( self:GetClientNumber( "projfx_color_r", 0 ), self:GetClientNumber( "projfx_color_g", 0 ), self:GetClientNumber( "projfx_color_b", 0 ), 0 )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local impactinfo = nil
|
||||
if self:GetClientNumber( "impactfx_enabled", 0 ) == 1 then
|
||||
impactinfo = {
|
||||
effectname = self:GetClientInfo( "impactfx_effectname", 0 ),
|
||||
utileffectinfo = Vector( self:GetClientNumber( "impactfx_utileffect_scale", 0 ), self:GetClientNumber( "impactfx_utileffect_magnitude", 0 ), self:GetClientNumber( "impactfx_utileffect_radius", 0 ) ),
|
||||
}
|
||||
if self:GetClientNumber( "impactfx_color_enabled", 0 ) == 1 then
|
||||
if self:GetClientNumber( "impactfx_color_outofone", 0 ) == 1 then
|
||||
impactinfo.colorinfo = Color( self:GetClientNumber( "impactfx_color_r", 0 ), self:GetClientNumber( "impactfx_color_g", 0 ), self:GetClientNumber( "impactfx_color_b", 0 ), 1 ) //we're using the alpha value to store color_outofone
|
||||
else
|
||||
impactinfo.colorinfo = Color( self:GetClientNumber( "impactfx_color_r", 0 ), self:GetClientNumber( "impactfx_color_g", 0 ), self:GetClientNumber( "impactfx_color_b", 0 ), 0 )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local attachnum = self:GetOwner():GetInfoNum( "particlecontrol_attachnum", 0 ) //use the standard tool's attachnum var
|
||||
local repeatrate = self:GetClientNumber( "repeatrate", 0 )
|
||||
local projmodel = self:GetClientInfo( "projmodel", 0 )
|
||||
local projmodel_skin = self:GetClientNumber( "projmodel_skin", 0 )
|
||||
local projmodel_attachnum = self:GetClientNumber( "projmodel_attachnum", 0 )
|
||||
local projmodel_material = self:GetClientInfo( "projmodel_material", 0 )
|
||||
local projmodel_invis = self:GetClientNumber( "projmodel_invis", 0 )
|
||||
local impactfx_effectlifetime = self:GetClientNumber( "impactfx_effectlifetime", 0 )
|
||||
|
||||
local projent_spread = self:GetClientNumber( "projent_spread", 0 )
|
||||
local projent_velocity = self:GetClientNumber( "projent_velocity", 0 )
|
||||
local projent_gravity = self:GetClientNumber( "projent_gravity", 0 )
|
||||
local projent_angle = self:GetClientNumber( "projent_angle", 0 )
|
||||
local projent_spin = self:GetClientNumber( "projent_spin", 0 )
|
||||
local projent_demomanfix = self:GetClientNumber( "projent_demomanfix", 0 )
|
||||
local projent_lifetime_prehit = self:GetClientNumber( "projent_lifetime_prehit", 0 )
|
||||
local projent_lifetime_posthit = self:GetClientNumber( "projent_lifetime_posthit", 0 )
|
||||
local projent_serverside = self:GetClientNumber( "projent_serverside", 0 )
|
||||
|
||||
local numpadkey = self:GetClientNumber( "numpadkey", 0 )
|
||||
local toggle = self:GetClientNumber( "toggle", 0 )
|
||||
local starton = self:GetClientNumber( "starton", 0 )
|
||||
|
||||
local ply = self:GetOwner()
|
||||
|
||||
|
||||
|
||||
local propmodel = self:GetClientInfo( "propmodel", 0 )
|
||||
local propangle = self:GetClientNumber( "propangle", 0 )
|
||||
//propangle 1: spawn upright
|
||||
//propangle 2: spawn at surface angle
|
||||
|
||||
if !util.IsValidModel(propmodel) then return false end
|
||||
if !util.IsValidProp(propmodel) then return false end
|
||||
if CLIENT then return true end
|
||||
|
||||
prop = ents.Create( "prop_physics" )
|
||||
prop:SetModel( propmodel )
|
||||
prop:SetPos( trace.HitPos - trace.HitNormal * prop:OBBMins().z )
|
||||
if propangle == 1 then prop:SetAngles(Angle(0,trace.HitNormal:Angle().y,0)) else prop:SetAngles(trace.HitNormal:Angle()) end
|
||||
prop:SetCollisionGroup(COLLISION_GROUP_NONE)
|
||||
prop:Spawn()
|
||||
|
||||
local shouldweweld = true //don't weld if...
|
||||
if ( !util.IsValidPhysicsObject(prop, 0) ) then shouldweweld = false end //the prop doesn't have a phys object
|
||||
if ( !trace.Entity:IsValid() ) then shouldweweld = false end //the thing we clicked on doesn't exist/is the world
|
||||
if ( trace.Entity && trace.Entity:IsPlayer() ) then shouldweweld = false end //the thing we clicked on is a player
|
||||
if ( !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then shouldweweld = false end //the thing we clicked on doesn't have a phys object
|
||||
if shouldweweld == true then
|
||||
local const = constraint.Weld( prop, trace.Entity, 0, trace.PhysicsBone, 0, true, true )
|
||||
else
|
||||
if util.IsValidPhysicsObject(prop, 0) then prop:GetPhysicsObject():EnableMotion(false) end
|
||||
end
|
||||
|
||||
if self:GetClientNumber( "propinvis", 0 ) == 1 then
|
||||
prop:SetRenderMode(1) //we need to change the render mode so the transparency actually shows up
|
||||
prop:SetColor( Color(255,255,255,0) )
|
||||
duplicator.StoreEntityModifier( prop, "colour", { Color = Color(255,255,255,0), RenderMode = 1, RenderFX = 0 } )
|
||||
end
|
||||
|
||||
undo.Create( "prop" )
|
||||
undo.AddEntity( prop )
|
||||
undo.SetPlayer( ply )
|
||||
undo.Finish( "Prop ("..tostring(propmodel)..")" )
|
||||
|
||||
|
||||
|
||||
if ( prop:IsValid() ) then
|
||||
AttachParticleControllerProj( ply, prop, { NewTable = {
|
||||
ProjFXInfo = projinfo,
|
||||
ImpactFXInfo = impactinfo,
|
||||
|
||||
AttachNum = attachnum,
|
||||
RepeatRate = repeatrate,
|
||||
ProjModel = projmodel,
|
||||
ProjModel_Skin = projmodel_skin,
|
||||
ProjModel_AttachNum = projmodel_attachnum,
|
||||
ProjModel_Material = projmodel_material,
|
||||
ProjModel_Invis = projmodel_invis,
|
||||
ImpactFX_EffectLifetime = impactfx_effectlifetime,
|
||||
|
||||
ProjEnt_Spread = projent_spread,
|
||||
ProjEnt_Velocity = projent_velocity,
|
||||
ProjEnt_Gravity = projent_gravity,
|
||||
ProjEnt_Angle = projent_angle,
|
||||
ProjEnt_Spin = projent_spin,
|
||||
ProjEnt_DemomanFix = projent_demomanfix,
|
||||
ProjEnt_Lifetime_PreHit = projent_lifetime_prehit,
|
||||
ProjEnt_Lifetime_PostHit = projent_lifetime_posthit,
|
||||
ProjEnt_Serverside = projent_serverside,
|
||||
|
||||
NumpadKey = numpadkey,
|
||||
Toggle = toggle,
|
||||
StartOn = starton,
|
||||
} } )
|
||||
return true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
|
||||
if ( trace.Entity:IsValid() ) then
|
||||
local fx = false
|
||||
|
||||
if trace.Entity:GetClass() == "prop_effect" and trace.Entity.AttachedEntity then trace.Entity = trace.Entity.AttachedEntity end
|
||||
|
||||
for _, asdf in pairs( ents:GetAll() ) do
|
||||
if asdf:GetClass() == "particlecontroller_proj" and asdf:GetParent() == trace.Entity then
|
||||
if SERVER then asdf:Remove() end
|
||||
fx = true
|
||||
end
|
||||
end
|
||||
if SERVER then
|
||||
duplicator.ClearEntityModifier( trace.Entity, "DupeParticleControllerProj" )
|
||||
end
|
||||
|
||||
return fx
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
if CLIENT then
|
||||
|
||||
local colorborder = Color(0,0,0,255)
|
||||
local colorselect = Color(0,255,0,255)
|
||||
local colorunselect = Color(255,255,255,255)
|
||||
|
||||
function TOOL:DrawHUD()
|
||||
local pl = LocalPlayer()
|
||||
local tr = pl:GetEyeTrace()
|
||||
local attachnum = self:GetOwner():GetInfoNum( "particlecontrol_attachnum", 0 ) //use the standard tool's attachnum var
|
||||
|
||||
local function DrawHighlightAttachments(ent)
|
||||
|
||||
//If there aren't any attachments, then draw the model origin as selected and stop here:
|
||||
if !ent:GetAttachments() or !ent:GetAttachments()[1] then
|
||||
local _pos,_ang = ent:GetPos(), ent:GetAngles()
|
||||
local _pos = _pos:ToScreen()
|
||||
local textpos = {x = _pos.x+5,y = _pos.y-5}
|
||||
|
||||
draw.RoundedBox(0,_pos.x - 3,_pos.y - 3,6,6,colorborder)
|
||||
draw.RoundedBox(0,_pos.x - 1,_pos.y - 1,2,2,colorselect)
|
||||
draw.SimpleTextOutlined("0: (origin)","Default",textpos.x,textpos.y,colorselect,TEXT_ALIGN_LEFT,TEXT_ALIGN_BOTTOM,2,colorborder)
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
//Draw the unselected model origin, if applicable:
|
||||
if ent:GetAttachments()[attachnum] then
|
||||
local _pos,_ang = ent:GetPos(), ent:GetAngles()
|
||||
local _pos = _pos:ToScreen()
|
||||
local textpos = {x = _pos.x+5,y = _pos.y-5}
|
||||
|
||||
draw.RoundedBox(0,_pos.x - 2,_pos.y - 2,4,4,colorborder)
|
||||
draw.RoundedBox(0,_pos.x - 1,_pos.y - 1,2,2,colorunselect)
|
||||
draw.SimpleTextOutlined("0: (origin)","Default",textpos.x,textpos.y,colorunselect,TEXT_ALIGN_LEFT,TEXT_ALIGN_BOTTOM,1,colorborder)
|
||||
end
|
||||
|
||||
//Draw the unselected attachment points:
|
||||
for _, table in pairs(ent:GetAttachments()) do
|
||||
local _pos,_ang = ent:GetAttachment(table.id).Pos,ent:GetAttachment(table.id).Ang
|
||||
local _pos = _pos:ToScreen()
|
||||
local textpos = {x = _pos.x+5,y = _pos.y-5}
|
||||
|
||||
if table.id != attachnum then
|
||||
draw.RoundedBox(0,_pos.x - 2,_pos.y - 2,4,4,colorborder)
|
||||
draw.RoundedBox(0,_pos.x - 1,_pos.y - 1,2,2,colorunselect)
|
||||
draw.SimpleTextOutlined(table.id ..": ".. table.name,"Default",textpos.x,textpos.y,colorunselect,TEXT_ALIGN_LEFT,TEXT_ALIGN_BOTTOM,1,colorborder)
|
||||
end
|
||||
end
|
||||
|
||||
//Draw the selected attachment point or model origin last, so it renders above all the others:
|
||||
if !ent:GetAttachments()[attachnum] then
|
||||
//Model origin
|
||||
local _pos,_ang = ent:GetPos(), ent:GetAngles()
|
||||
local _pos = _pos:ToScreen()
|
||||
local textpos = {x = _pos.x+5,y = _pos.y-5}
|
||||
|
||||
draw.RoundedBox(0,_pos.x - 3,_pos.y - 3,6,6,colorborder)
|
||||
draw.RoundedBox(0,_pos.x - 1,_pos.y - 1,2,2,colorselect)
|
||||
draw.SimpleTextOutlined("0: (origin)","Default",textpos.x,textpos.y,colorselect,TEXT_ALIGN_LEFT,TEXT_ALIGN_BOTTOM,2,colorborder)
|
||||
else
|
||||
//Attachment
|
||||
local _pos,_ang = ent:GetAttachment(attachnum).Pos,ent:GetAttachment(attachnum).Ang
|
||||
local _pos = _pos:ToScreen()
|
||||
local textpos = {x = _pos.x+5,y = _pos.y-5}
|
||||
|
||||
draw.RoundedBox(0,_pos.x - 3,_pos.y - 3,6,6,colorborder)
|
||||
draw.RoundedBox(0,_pos.x - 1,_pos.y - 1,2,2,colorselect)
|
||||
draw.SimpleTextOutlined(attachnum ..": ".. ent:GetAttachments()[attachnum].name,"Default",textpos.x,textpos.y,colorselect,TEXT_ALIGN_LEFT,TEXT_ALIGN_BOTTOM,2,colorborder)
|
||||
end
|
||||
end
|
||||
|
||||
if IsValid(tr.Entity) and tr.Entity == self.HighlightedEnt then
|
||||
DrawHighlightAttachments(self.HighlightedEnt)
|
||||
return end
|
||||
|
||||
if IsValid(tr.Entity) and tr.Entity != self.HighlightedEnt then
|
||||
//unhighlight the old ent if it exists
|
||||
if self.HighlightedEnt != nil then
|
||||
self.HighlightedEnt = nil
|
||||
end
|
||||
|
||||
//highlight the new ent
|
||||
self.HighlightedEnt = tr.Entity
|
||||
end
|
||||
|
||||
if !IsValid(tr.Entity) and self.HighlightedEnt != nil then
|
||||
self.HighlightedEnt = nil
|
||||
end
|
||||
end
|
||||
|
||||
function TOOL:Holster()
|
||||
if self.HighlightedEnt != nil then
|
||||
self.HighlightedEnt = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
//All credit for the toolgun scroll wheel code goes to the Wiremod devs. You guys are the best.
|
||||
local function get_active_tool(ply, tool)
|
||||
-- find toolgun
|
||||
local activeWep = ply:GetActiveWeapon()
|
||||
if not IsValid(activeWep) or activeWep:GetClass() ~= "gmod_tool" or activeWep.Mode ~= tool then return end
|
||||
|
||||
return activeWep:GetToolObject(tool)
|
||||
end
|
||||
|
||||
local function hookfunc( ply, bind, pressed )
|
||||
if not pressed then return end
|
||||
if bind == "invnext" then
|
||||
local self = get_active_tool(ply, "particlecontrol_proj")
|
||||
if not self then return end
|
||||
|
||||
return self:ScrollDown(ply:GetEyeTraceNoCursor())
|
||||
elseif bind == "invprev" then
|
||||
local self = get_active_tool(ply, "particlecontrol_proj")
|
||||
if not self then return end
|
||||
|
||||
return self:ScrollUp(ply:GetEyeTraceNoCursor())
|
||||
end
|
||||
end
|
||||
|
||||
if game.SinglePlayer() then -- wtfgarry (have to have a delay in single player or the hook won't get added)
|
||||
timer.Simple(5,function() hook.Add( "PlayerBindPress", "particlecontrol_proj_playerbindpress", hookfunc ) end)
|
||||
else
|
||||
hook.Add( "PlayerBindPress", "particlecontrol_proj_playerbindpress", hookfunc )
|
||||
end
|
||||
//End shamefully copied code here.
|
||||
|
||||
function TOOL:Scroll(trace,dir)
|
||||
if !IsValid(self.HighlightedEnt) then return end
|
||||
|
||||
local attachcount = 0
|
||||
if self.HighlightedEnt:GetAttachments() then attachcount = table.Count(self.HighlightedEnt:GetAttachments()) end
|
||||
local oldattachnum = self:GetOwner():GetInfoNum( "particlecontrol_attachnum", 0 ) //use the standard tool's attachnum var
|
||||
if oldattachnum > attachcount then oldattachnum = 0 end
|
||||
local attachnum = oldattachnum + dir
|
||||
|
||||
if attachnum < 0 then attachnum = attachcount end
|
||||
if attachnum > attachcount then attachnum = 0 end
|
||||
RunConsoleCommand("particlecontrol_attachnum", tostring(attachnum)) //use the standard tool's attachnum var
|
||||
self:GetOwner():EmitSound("weapons/pistol/pistol_empty.wav")
|
||||
return true
|
||||
end
|
||||
function TOOL:ScrollUp(trace) return self:Scroll(trace,-1) end
|
||||
function TOOL:ScrollDown(trace) return self:Scroll(trace,1) end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
if SERVER then
|
||||
|
||||
local function SpawnParticleControllerProj(ply, ent, DataTable)
|
||||
|
||||
if DataTable == nil or DataTable == {} or DataTable.ProjModel == nil or ent == nil or !IsValid(ent) then return end
|
||||
|
||||
|
||||
local ParticleControlProj = ents.Create( "particlecontroller_proj" )
|
||||
ParticleControlProj:SetPos(ent:GetPos())
|
||||
ParticleControlProj:SetAngles(ent:GetAngles())
|
||||
ParticleControlProj:SetParent(ent)
|
||||
ent:DeleteOnRemove(ParticleControlProj)
|
||||
|
||||
ParticleControlProj:SetTargetEnt(ent)
|
||||
|
||||
|
||||
if DataTable.ProjFXInfo != nil then
|
||||
ParticleControlProj:SetProjFX_EffectName(DataTable.ProjFXInfo.effectname)
|
||||
ParticleControlProj:SetProjFX_UtilEffectInfo(DataTable.ProjFXInfo.utileffectinfo)
|
||||
if DataTable.ProjFXInfo.colorinfo != nil then
|
||||
local projfxcolor = Vector(DataTable.ProjFXInfo.colorinfo.r, DataTable.ProjFXInfo.colorinfo.g, DataTable.ProjFXInfo.colorinfo.b)
|
||||
if DataTable.ProjFXInfo.colorinfo.a then
|
||||
projfxcolor = projfxcolor / 255
|
||||
end
|
||||
ParticleControlProj:SetProjFX_ColorInfo( projfxcolor )
|
||||
else
|
||||
ParticleControlProj:SetProjFX_ColorInfo( Vector(0,0,0) )
|
||||
end
|
||||
else
|
||||
ParticleControlProj:SetProjFX_EffectName("")
|
||||
end
|
||||
|
||||
if DataTable.ImpactFXInfo != nil then
|
||||
ParticleControlProj:SetImpactFX_EffectName(DataTable.ImpactFXInfo.effectname)
|
||||
ParticleControlProj:SetImpactFX_UtilEffectInfo(DataTable.ImpactFXInfo.utileffectinfo)
|
||||
if DataTable.ImpactFXInfo.colorinfo != nil then
|
||||
local impactfxcolor = Vector(DataTable.ImpactFXInfo.colorinfo.r, DataTable.ImpactFXInfo.colorinfo.g, DataTable.ImpactFXInfo.colorinfo.b)
|
||||
if DataTable.ImpactFXInfo.colorinfo.a then
|
||||
impactfxcolor = impactfxcolor / 255
|
||||
end
|
||||
ParticleControlProj:SetImpactFX_ColorInfo( impactfxcolor )
|
||||
else
|
||||
ParticleControlProj:SetImpactFX_ColorInfo( Vector(0,0,0) )
|
||||
end
|
||||
else
|
||||
ParticleControlProj:SetImpactFX_EffectName("")
|
||||
end
|
||||
|
||||
ParticleControlProj:SetAttachNum(DataTable.AttachNum)
|
||||
ParticleControlProj:SetRepeatRate(DataTable.RepeatRate)
|
||||
|
||||
ParticleControlProj:SetProjModel(DataTable.ProjModel)
|
||||
ParticleControlProj:SetSkin(DataTable.ProjModel_Skin) //also use the controller ent to store the skin
|
||||
ParticleControlProj:SetProjModel_AttachNum(DataTable.ProjModel_AttachNum)
|
||||
ParticleControlProj:SetMaterial(DataTable.ProjModel_Material) //and the material
|
||||
ParticleControlProj:SetProjModel_Invis( tobool(DataTable.ProjModel_Invis) )
|
||||
ParticleControlProj:SetImpactFX_EffectLifetime(DataTable.ImpactFX_EffectLifetime)
|
||||
|
||||
ParticleControlProj:SetProjEnt_Spread(DataTable.ProjEnt_Spread)
|
||||
ParticleControlProj:SetProjEnt_Velocity(DataTable.ProjEnt_Velocity)
|
||||
ParticleControlProj:SetProjEnt_Gravity( tobool(DataTable.ProjEnt_Gravity) )
|
||||
ParticleControlProj:SetProjEnt_Angle(DataTable.ProjEnt_Angle)
|
||||
ParticleControlProj:SetProjEnt_Spin(DataTable.ProjEnt_Spin)
|
||||
ParticleControlProj:SetProjEnt_DemomanFix( tobool(DataTable.ProjEnt_DemomanFix) )
|
||||
ParticleControlProj:SetProjEnt_Lifetime_PreHit(DataTable.ProjEnt_Lifetime_PreHit)
|
||||
ParticleControlProj:SetProjEnt_Lifetime_PostHit(DataTable.ProjEnt_Lifetime_PostHit)
|
||||
ParticleControlProj:SetProjEnt_Serverside( tobool(DataTable.ProjEnt_Serverside) )
|
||||
|
||||
|
||||
ParticleControlProj:SetActive( tobool(DataTable.StartOn) )
|
||||
ParticleControlProj:SetToggle( tobool(DataTable.Toggle) )
|
||||
ParticleControlProj:SetNumpadKey(DataTable.NumpadKey)
|
||||
|
||||
numpad.OnDown( ply, DataTable.NumpadKey, "Particle_Press", ParticleControlProj )
|
||||
numpad.OnUp( ply, DataTable.NumpadKey, "Particle_Release", ParticleControlProj )
|
||||
ParticleControlProj:SetNumpadState("")
|
||||
|
||||
|
||||
ParticleControlProj:Spawn()
|
||||
ParticleControlProj:Activate()
|
||||
|
||||
end
|
||||
|
||||
|
||||
function AttachParticleControllerProj( ply, ent, Data )
|
||||
|
||||
if Data.NewTable then
|
||||
SpawnParticleControllerProj(ply, ent, Data.NewTable)
|
||||
|
||||
local dupetable = {}
|
||||
if ent.EntityMods and ent.EntityMods.DupeParticleControllerProj then dupetable = ent.EntityMods.DupeParticleControllerProj end
|
||||
table.insert(dupetable, Data.NewTable)
|
||||
duplicator.StoreEntityModifier( ent, "DupeParticleControllerProj", dupetable )
|
||||
return end
|
||||
|
||||
end
|
||||
|
||||
|
||||
function DupeParticleControllerProj( ply, ent, Data )
|
||||
|
||||
//due to a problem with the easy bonemerge tool that causes entity modifiers to be applied TWICE, we need to remove the effects that were added the first time
|
||||
for _, asdf in pairs( ents:GetAll() ) do
|
||||
if asdf:GetClass() == "particlecontroller_proj" and asdf:GetParent() == ent then
|
||||
asdf:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
for _, DataTable in pairs (Data) do
|
||||
SpawnParticleControllerProj(ply, ent, DataTable)
|
||||
end
|
||||
|
||||
end
|
||||
duplicator.RegisterEntityModifier( "DupeParticleControllerProj", DupeParticleControllerProj )
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
//we're still testing out a lot of stuff with the cpanel, so let's add a way to refresh it by reselecting the tool
|
||||
--[[
|
||||
TOOL.ClientConVar[ "refresh" ] = 1
|
||||
function TOOL:Think()
|
||||
if SERVER then return end
|
||||
if self:GetClientNumber("refresh") == 1 then
|
||||
RunConsoleCommand("particlecontrol_proj_refresh", "0");
|
||||
//refresh the cpanel
|
||||
local panel = controlpanel.Get( "particlecontrol_proj" )
|
||||
if ( !panel ) then return end
|
||||
panel:ClearControls()
|
||||
self.BuildCPanel(panel)
|
||||
end
|
||||
end
|
||||
function TOOL:Deploy()
|
||||
RunConsoleCommand("particlecontrol_proj_refresh", "1");
|
||||
end
|
||||
]]
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel(panel)
|
||||
|
||||
panel:AddControl( "Header", { Description = "#tool.particlecontrol_proj.help" } )
|
||||
|
||||
//Presets
|
||||
panel:AddControl( "ComboBox", {
|
||||
MenuButton = 1,
|
||||
Folder = "particlecontrol_proj",
|
||||
Options = {
|
||||
//[ "#preset.default" ] = ConVarsDefault
|
||||
[ "Example: Generic Rockets" ] = ConVarsDefault,
|
||||
[ "Example: TF2 Rockets" ] = { particlecontrol_proj_impactfx_color_b = "0", particlecontrol_proj_impactfx_color_enabled = "0", particlecontrol_proj_impactfx_color_g = "20", particlecontrol_proj_impactfx_color_outofone = "0", particlecontrol_proj_impactfx_color_r = "255", particlecontrol_proj_impactfx_effectlifetime = "1.000000", particlecontrol_proj_impactfx_effectname = "ExplosionCore_Wall", particlecontrol_proj_impactfx_enabled = "1", particlecontrol_proj_impactfx_utileffect_magnitude = "1", particlecontrol_proj_impactfx_utileffect_radius = "10", particlecontrol_proj_impactfx_utileffect_scale = "1", particlecontrol_proj_numpadkey = "52", particlecontrol_proj_projent_angle = "0", particlecontrol_proj_projent_demomanfix = "0", particlecontrol_proj_projent_gravity = "0", particlecontrol_proj_projent_lifetime_posthit = "0.000000", particlecontrol_proj_projent_lifetime_prehit = "10.000000", particlecontrol_proj_projent_serverside = "0", particlecontrol_proj_projent_spin = "0",
|
||||
particlecontrol_proj_projent_spread = "0", particlecontrol_proj_projent_velocity = "1100.000000", particlecontrol_proj_projfx_color_b = "0", particlecontrol_proj_projfx_color_enabled = "0", particlecontrol_proj_projfx_color_g = "20", particlecontrol_proj_projfx_color_outofone = "0", particlecontrol_proj_projfx_color_r = "255", particlecontrol_proj_projfx_effectname = "rockettrail", particlecontrol_proj_projfx_enabled = "1", particlecontrol_proj_projfx_utileffect_magnitude = "1", particlecontrol_proj_projfx_utileffect_radius = "10", particlecontrol_proj_projfx_utileffect_scale = "1", particlecontrol_proj_projmodel = "models/weapons/w_models/w_rocket.mdl", particlecontrol_proj_projmodel_attachnum = "1", particlecontrol_proj_projmodel_invis = "0", particlecontrol_proj_projmodel_skin = "0", particlecontrol_proj_propangle = "2", particlecontrol_proj_propinvis = "0", particlecontrol_proj_propmodel = "models/weapons/w_smg1.mdl", particlecontrol_proj_repeatrate = "0.800000",
|
||||
particlecontrol_proj_starton = "1", particlecontrol_proj_toggle = "1" },
|
||||
[ "Example: TF2 Grenades, red" ] = { particlecontrol_proj_impactfx_color_b = "0", particlecontrol_proj_impactfx_color_enabled = "0", particlecontrol_proj_impactfx_color_g = "20", particlecontrol_proj_impactfx_color_outofone = "0", particlecontrol_proj_impactfx_color_r = "255", particlecontrol_proj_impactfx_effectlifetime = "1.000000", particlecontrol_proj_impactfx_effectname = "ExplosionCore_MidAir", particlecontrol_proj_impactfx_enabled = "1", particlecontrol_proj_impactfx_utileffect_magnitude = "1", particlecontrol_proj_impactfx_utileffect_radius = "10", particlecontrol_proj_impactfx_utileffect_scale = "1", particlecontrol_proj_numpadkey = "52", particlecontrol_proj_projent_angle = "0", particlecontrol_proj_projent_demomanfix = "0", particlecontrol_proj_projent_gravity = "1", particlecontrol_proj_projent_lifetime_posthit = "2.300000", particlecontrol_proj_projent_lifetime_prehit = "2.300000", particlecontrol_proj_projent_serverside = "0", particlecontrol_proj_projent_spin = "4",
|
||||
particlecontrol_proj_projent_spread = "0", particlecontrol_proj_projent_velocity = "1217.000000", particlecontrol_proj_projfx_color_b = "0", particlecontrol_proj_projfx_color_enabled = "0", particlecontrol_proj_projfx_color_g = "20", particlecontrol_proj_projfx_color_outofone = "0", particlecontrol_proj_projfx_color_r = "255", particlecontrol_proj_projfx_effectname = "pipebombtrail_red", particlecontrol_proj_projfx_enabled = "1", particlecontrol_proj_projfx_utileffect_magnitude = "1", particlecontrol_proj_projfx_utileffect_radius = "10", particlecontrol_proj_projfx_utileffect_scale = "1", particlecontrol_proj_projmodel = "models/weapons/w_models/w_grenade_grenadelauncher.mdl", particlecontrol_proj_projmodel_attachnum = "0", particlecontrol_proj_projmodel_invis = "0", particlecontrol_proj_projmodel_skin = "0", particlecontrol_proj_propangle = "2", particlecontrol_proj_propinvis = "0", particlecontrol_proj_propmodel = "models/weapons/w_smg1.mdl", particlecontrol_proj_repeatrate = "0.600000",
|
||||
particlecontrol_proj_starton = "1", particlecontrol_proj_toggle = "1" },
|
||||
[ "Example: TF2 Grenades, blue" ] = { particlecontrol_proj_impactfx_color_b = "0", particlecontrol_proj_impactfx_color_enabled = "0", particlecontrol_proj_impactfx_color_g = "20", particlecontrol_proj_impactfx_color_outofone = "0", particlecontrol_proj_impactfx_color_r = "255", particlecontrol_proj_impactfx_effectlifetime = "1.000000", particlecontrol_proj_impactfx_effectname = "ExplosionCore_MidAir", particlecontrol_proj_impactfx_enabled = "1", particlecontrol_proj_impactfx_utileffect_magnitude = "1", particlecontrol_proj_impactfx_utileffect_radius = "10", particlecontrol_proj_impactfx_utileffect_scale = "1", particlecontrol_proj_numpadkey = "52", particlecontrol_proj_projent_angle = "0", particlecontrol_proj_projent_demomanfix = "0", particlecontrol_proj_projent_gravity = "1", particlecontrol_proj_projent_lifetime_posthit = "2.300000", particlecontrol_proj_projent_lifetime_prehit = "2.300000", particlecontrol_proj_projent_serverside = "0", particlecontrol_proj_projent_spin = "4",
|
||||
particlecontrol_proj_projent_spread = "0", particlecontrol_proj_projent_velocity = "1217.000000", particlecontrol_proj_projfx_color_b = "0", particlecontrol_proj_projfx_color_enabled = "0", particlecontrol_proj_projfx_color_g = "20", particlecontrol_proj_projfx_color_outofone = "0", particlecontrol_proj_projfx_color_r = "255", particlecontrol_proj_projfx_effectname = "pipebombtrail_blue", particlecontrol_proj_projfx_enabled = "1", particlecontrol_proj_projfx_utileffect_magnitude = "1", particlecontrol_proj_projfx_utileffect_radius = "10", particlecontrol_proj_projfx_utileffect_scale = "1", particlecontrol_proj_projmodel = "models/weapons/w_models/w_grenade_grenadelauncher.mdl", particlecontrol_proj_projmodel_attachnum = "0", particlecontrol_proj_projmodel_invis = "0", particlecontrol_proj_projmodel_skin = "1", particlecontrol_proj_propangle = "2", particlecontrol_proj_propinvis = "0", particlecontrol_proj_propmodel = "models/weapons/w_smg1.mdl", particlecontrol_proj_repeatrate = "0.600000",
|
||||
particlecontrol_proj_starton = "1", particlecontrol_proj_toggle = "1" },
|
||||
},
|
||||
CVars = table.GetKeys( ConVarsDefault )
|
||||
} )
|
||||
|
||||
|
||||
|
||||
panel:AddControl( "Checkbox", { Label = "Enable projectile effects?", Command = "particlecontrol_proj_projfx_enabled" } )
|
||||
|
||||
AddParticleBrowser(panel, {
|
||||
name = "Projectile Effect",
|
||||
commands = {
|
||||
effectname = "particlecontrol_proj_projfx_effectname",
|
||||
color = "particlecontrol_proj_projfx_color",
|
||||
utileffect = "particlecontrol_proj_projfx_utileffect",
|
||||
|
||||
enabled = "particlecontrol_proj_projfx_enabled",
|
||||
},
|
||||
})
|
||||
|
||||
panel:AddControl( "Checkbox", { Label = "Enable impact/expire effects?", Command = "particlecontrol_proj_impactfx_enabled" } )
|
||||
|
||||
AddParticleBrowser(panel, {
|
||||
name = "Impact/Expire Effect",
|
||||
commands = {
|
||||
effectname = "particlecontrol_proj_impactfx_effectname",
|
||||
color = "particlecontrol_proj_impactfx_color",
|
||||
utileffect = "particlecontrol_proj_impactfx_utileffect",
|
||||
|
||||
enabled = "particlecontrol_proj_impactfx_enabled",
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
|
||||
//panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
|
||||
|
||||
|
||||
panel:AddControl("Slider", {
|
||||
Label = "Attachment",
|
||||
Type = "Integer",
|
||||
Min = "0",
|
||||
Max = "10",
|
||||
Command = "particlecontrol_attachnum", //use the standard tool's attachnum var
|
||||
})
|
||||
panel:ControlHelp( "Attachment point on the model to fire projectiles from. Set to 0 to fire from the model origin." )
|
||||
|
||||
panel:AddControl("Slider", {
|
||||
Label = "Repeat Rate",
|
||||
Type = "Float",
|
||||
Min = "0",
|
||||
Max = "1",
|
||||
Command = "particlecontrol_proj_repeatrate"
|
||||
})
|
||||
panel:ControlHelp( "How often the projectile fires. Set to 0 to not repeat." )
|
||||
|
||||
|
||||
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
|
||||
|
||||
|
||||
local projmodellist = { Label = "Projectile Model:", ConVar = "particlecontrol_proj_projmodel", Category = "Projectile Model", Height = 1, Models = {} }
|
||||
projmodellist.Models["models/hunter/plates/plate.mdl"] = {}
|
||||
projmodellist.Models["models/weapons/w_missile.mdl"] = {}
|
||||
projmodellist.Models["models/weapons/w_models/w_rocket.mdl"] = {}
|
||||
projmodellist.Models["models/weapons/w_models/w_grenade_grenadelauncher.mdl"] = {}
|
||||
|
||||
panel:AddControl( "PropSelect", projmodellist )
|
||||
|
||||
local projmodelentry = vgui.Create( "DTextEntry", panel )
|
||||
projmodelentry:SetConVar( "particlecontrol_proj_projmodel" )
|
||||
panel:AddItem(projmodelentry)
|
||||
|
||||
panel:AddControl("Slider", {
|
||||
Label = "Projectile Skin",
|
||||
Type = "Integer",
|
||||
Min = "0",
|
||||
Max = "10",
|
||||
Command = "particlecontrol_proj_projmodel_skin",
|
||||
})
|
||||
|
||||
panel:AddControl("Slider", {
|
||||
Label = "Projectile Attachment",
|
||||
Type = "Integer",
|
||||
Min = "0",
|
||||
Max = "10",
|
||||
Command = "particlecontrol_proj_projmodel_attachnum",
|
||||
})
|
||||
panel:ControlHelp( "Attachment point on the projectile to attach the effect to. Set to 0 to attach to model origin." )
|
||||
|
||||
panel:AddControl("TextBox", {
|
||||
Label = "Projectile Material",
|
||||
Description = "",
|
||||
MaxLength = 255,
|
||||
Text = "",
|
||||
Command = "particlecontrol_proj_projmodel_material",
|
||||
})
|
||||
|
||||
panel:AddControl( "Checkbox", { Label = "Invisible projectiles (particles only)", Command = "particlecontrol_proj_projmodel_invis" } )
|
||||
|
||||
|
||||
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
|
||||
|
||||
|
||||
panel:AddControl("Slider", {
|
||||
Label = "Projectile Spread",
|
||||
Type = "Float",
|
||||
Min = "0",
|
||||
Max = "1",
|
||||
Command = "particlecontrol_proj_projent_spread"
|
||||
})
|
||||
panel:ControlHelp( "Each unit is 90 degrees of spread - you can type in 2 for 180 degrees or even 4 for 360 degrees." )
|
||||
|
||||
panel:AddControl("Slider", {
|
||||
Label = "Projectile Velocity",
|
||||
Type = "Float",
|
||||
Min = "0",
|
||||
Max = "3000",
|
||||
Command = "particlecontrol_proj_projent_velocity"
|
||||
})
|
||||
//panel:ControlHelp( "" )
|
||||
|
||||
panel:AddControl( "Checkbox", { Label = "Projectile Gravity", Command = "particlecontrol_proj_projent_gravity" } )
|
||||
|
||||
panel:AddControl( "ComboBox", {
|
||||
Label = "Projectile Angle",
|
||||
MenuButton = "0",
|
||||
Options = {
|
||||
["Forward"] = { particlecontrol_proj_projent_angle = 0 },
|
||||
["Left"] = { particlecontrol_proj_projent_angle = 1 },
|
||||
["Right"] = { particlecontrol_proj_projent_angle = 2 },
|
||||
["Up"] = { particlecontrol_proj_projent_angle = 3 },
|
||||
["Down"] = { particlecontrol_proj_projent_angle = 4 },
|
||||
["Back"] = { particlecontrol_proj_projent_angle = 5 },
|
||||
}
|
||||
})
|
||||
|
||||
panel:AddControl( "ComboBox", {
|
||||
Label = "Projectile Spin",
|
||||
MenuButton = "0",
|
||||
Options = {
|
||||
["Don't spin"] = { particlecontrol_proj_projent_spin = 0 },
|
||||
["Spin pitch"] = { particlecontrol_proj_projent_spin = 1 },
|
||||
["Spin yaw"] = { particlecontrol_proj_projent_spin = 2 },
|
||||
["Spin roll"] = { particlecontrol_proj_projent_spin = 3 },
|
||||
["Spin random"] = { particlecontrol_proj_projent_spin = 4 },
|
||||
}
|
||||
})
|
||||
|
||||
panel:AddControl( "Checkbox", { Label = "Demoman Weapon Fix", Command = "particlecontrol_proj_projent_demomanfix" } )
|
||||
panel:ControlHelp( "Demoman weapon props have their muzzle attachment at an angle for some reason. Use this to fix it." )
|
||||
|
||||
panel:AddControl("Slider", {
|
||||
Label = "Lifetime",
|
||||
Type = "Float",
|
||||
Min = "0",
|
||||
Max = "10",
|
||||
Command = "particlecontrol_proj_projent_lifetime_prehit"
|
||||
})
|
||||
panel:ControlHelp( "How long projectiles last after being launched." )
|
||||
|
||||
panel:AddControl("Slider", {
|
||||
Label = "Lifetime (after impact)",
|
||||
Type = "Float",
|
||||
Min = "0",
|
||||
Max = "10",
|
||||
Command = "particlecontrol_proj_projent_lifetime_posthit"
|
||||
})
|
||||
panel:ControlHelp( "How long projectiles last after hitting something. Set to 0 to expire on impact." ) //TODO: how to explain that lifetime before hit and lifetime after hit are separate timers?
|
||||
|
||||
panel:AddControl( "Checkbox", { Label = "Serverside projectiles?", Command = "particlecontrol_proj_projent_serverside" } )
|
||||
panel:ControlHelp( "Use serverside props for projectiles. These will collide properly with everything instead of passing through, but they'll also put a lot more stress on the game (meaning more lag), and they'll show up in the wrong spot if bonemerged. Only turn this on if you need it." )
|
||||
|
||||
panel:AddControl("Slider", {
|
||||
Label = "Impact Effect Lifetime",
|
||||
Type = "Float",
|
||||
Min = "0.5",
|
||||
Max = "5",
|
||||
Command = "particlecontrol_proj_impactfx_effectlifetime"
|
||||
})
|
||||
//panel:ControlHelp( "Number of seconds before impact effects are removed." )
|
||||
|
||||
|
||||
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
|
||||
|
||||
|
||||
local modellist = { Label = "Prop:", ConVar = "particlecontrol_proj_propmodel", Category = "Prop", Height = 1, Models = {} }
|
||||
modellist.Models["models/hunter/plates/plate025x025.mdl"] = {}
|
||||
modellist.Models["models/hunter/plates/plate.mdl"] = {}
|
||||
modellist.Models["models/weapons/w_smg1.mdl"] = {}
|
||||
modellist.Models["models/weapons/w_models/w_rocketlauncher.mdl"] = {}
|
||||
|
||||
panel:AddControl( "PropSelect", modellist )
|
||||
|
||||
panel:AddControl( "ComboBox", {
|
||||
Label = "Prop Angle",
|
||||
MenuButton = "0",
|
||||
Options = {
|
||||
["Spawn upright"] = { particlecontrol_proj_propangle = "1" },
|
||||
["Spawn at surface angle"] = { particlecontrol_proj_propangle = "2" }
|
||||
}
|
||||
})
|
||||
|
||||
panel:AddControl( "Checkbox", { Label = "Invisible prop (particles only)", Command = "particlecontrol_proj_propinvis" } )
|
||||
|
||||
|
||||
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
|
||||
|
||||
|
||||
panel:AddControl( "Numpad", {
|
||||
Label = "Effect Key",
|
||||
Command = "particlecontrol_proj_numpadkey",
|
||||
ButtonSize = 22
|
||||
})
|
||||
|
||||
panel:AddControl( "Checkbox", { Label = "Toggle", Command = "particlecontrol_proj_toggle" } )
|
||||
|
||||
panel:AddControl( "Checkbox", { Label = "Start on?", Command = "particlecontrol_proj_starton" } )
|
||||
|
||||
end
|
||||
712
lua/weapons/gmod_tool/stools/particlecontrol_tracer.lua
Normal file
712
lua/weapons/gmod_tool/stools/particlecontrol_tracer.lua
Normal file
@@ -0,0 +1,712 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
TOOL.Category = "Particle Controller"
|
||||
TOOL.Name = "ParCtrl - Tracers"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
TOOL.HighlightedEnt = nil
|
||||
|
||||
TOOL.ClientConVar[ "effectname" ] = "!UTILEFFECT!AR2Tracer"
|
||||
//TOOL.ClientConVar[ "utileffect_scale" ] = "1"
|
||||
//TOOL.ClientConVar[ "utileffect_magnitude" ] = "1"
|
||||
//TOOL.ClientConVar[ "utileffect_radius" ] = "10"
|
||||
TOOL.ClientConVar[ "color_enabled" ] = "0"
|
||||
TOOL.ClientConVar[ "color_r" ] = "255"
|
||||
TOOL.ClientConVar[ "color_g" ] = "20"
|
||||
TOOL.ClientConVar[ "color_b" ] = "0"
|
||||
TOOL.ClientConVar[ "color_outofone" ] = "0"
|
||||
|
||||
TOOL.ClientConVar[ "impactfx_enabled" ] = "1"
|
||||
TOOL.ClientConVar[ "impactfx_effectname" ] = "!UTILEFFECT!AR2Impact"
|
||||
TOOL.ClientConVar[ "impactfx_utileffect_scale" ] = "1"
|
||||
TOOL.ClientConVar[ "impactfx_utileffect_magnitude" ] = "1"
|
||||
TOOL.ClientConVar[ "impactfx_utileffect_radius" ] = "10"
|
||||
TOOL.ClientConVar[ "impactfx_color_enabled" ] = "0"
|
||||
TOOL.ClientConVar[ "impactfx_color_r" ] = "255"
|
||||
TOOL.ClientConVar[ "impactfx_color_g" ] = "20"
|
||||
TOOL.ClientConVar[ "impactfx_color_b" ] = "0"
|
||||
TOOL.ClientConVar[ "impactfx_color_outofone" ] = "0"
|
||||
|
||||
//TOOL.ClientConVar[ "attachnum" ] = "1" //we're using the standard tool's attachnum var instead so that the selected attachment stays consistent when swapping between tools
|
||||
TOOL.ClientConVar[ "repeatrate" ] = "0.1"
|
||||
TOOL.ClientConVar[ "effectlifetime" ] = "1.0"
|
||||
|
||||
TOOL.ClientConVar[ "tracerspread" ] = "0.02"
|
||||
TOOL.ClientConVar[ "tracercount" ] = "1"
|
||||
TOOL.ClientConVar[ "leavebulletholes" ] = "1"
|
||||
|
||||
TOOL.ClientConVar[ "propmodel" ] = "models/weapons/w_smg1.mdl"
|
||||
TOOL.ClientConVar[ "propangle" ] = "2"
|
||||
TOOL.ClientConVar[ "propinvis" ] = "0"
|
||||
|
||||
TOOL.ClientConVar[ "numpadkey" ] = "52"
|
||||
TOOL.ClientConVar[ "toggle" ] = "1"
|
||||
TOOL.ClientConVar[ "starton" ] = "1"
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "left0", stage = 0, icon = "gui/lmb.png" },
|
||||
{ name = "middle0", stage = 0, icon = "gui/mmb.png" },
|
||||
{ name = "right0", stage = 0, icon = "gui/rmb.png" },
|
||||
{ name = "reload0", stage = 0, icon = "gui/r.png" },
|
||||
}
|
||||
|
||||
if ( CLIENT ) then
|
||||
language.Add( "tool.particlecontrol_tracer.name", "Adv. Particle Controller - Tracers" )
|
||||
language.Add( "tool.particlecontrol_tracer.desc", "Attach tracer effects to things" )
|
||||
language.Add( "tool.particlecontrol_tracer.help", "Tracer effects are particles that fire out like bullets, with one end at the attachment and the other end where the \"bullet\" hits something." )
|
||||
|
||||
language.Add( "tool.particlecontrol_tracer.left0", "Add a tracer effect to an object" )
|
||||
language.Add( "tool.particlecontrol_tracer.middle0", "Scroll through an object's attachments" )
|
||||
language.Add( "tool.particlecontrol_tracer.right0", "Attach a new prop with the tracer effect on it" )
|
||||
language.Add( "tool.particlecontrol_tracer.reload0", "Remove all tracer effects from an object" )
|
||||
end
|
||||
|
||||
util.PrecacheSound("weapons/pistol/pistol_empty.wav")
|
||||
|
||||
|
||||
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
local effectname = self:GetClientInfo( "effectname", 0 )
|
||||
local attachnum = self:GetOwner():GetInfoNum( "particlecontrol_attachnum", 0 ) //use the standard tool's attachnum var
|
||||
|
||||
local repeatrate = self:GetClientNumber( "repeatrate", 0 )
|
||||
|
||||
local numpadkey = self:GetClientNumber( "numpadkey", 0 )
|
||||
local toggle = self:GetClientNumber( "toggle", 0 )
|
||||
local starton = self:GetClientNumber( "starton", 0 )
|
||||
|
||||
//local utileffectinfo = Vector( self:GetClientNumber( "utileffect_scale", 0 ), self:GetClientNumber( "utileffect_magnitude", 0 ), self:GetClientNumber( "utileffect_radius", 0 ) )
|
||||
local colorinfo = nil
|
||||
if self:GetClientNumber( "color_enabled", 0 ) == 1 then
|
||||
if self:GetClientNumber( "color_outofone", 0 ) == 1 then
|
||||
colorinfo = Color( self:GetClientNumber( "color_r", 0 ), self:GetClientNumber( "color_g", 0 ), self:GetClientNumber( "color_b", 0 ), 1 ) //we're using the alpha value to store color_outofone
|
||||
else
|
||||
colorinfo = Color( self:GetClientNumber( "color_r", 0 ), self:GetClientNumber( "color_g", 0 ), self:GetClientNumber( "color_b", 0 ), 0 )
|
||||
end
|
||||
end
|
||||
|
||||
local tracerspread = self:GetClientNumber( "tracerspread", 0 )
|
||||
local tracercount = self:GetClientNumber( "tracercount", 0 )
|
||||
local leavebulletholes = self:GetClientNumber( "leavebulletholes", 0 )
|
||||
local effectlifetime = self:GetClientNumber( "effectlifetime", 0 )
|
||||
|
||||
local impactinfo = nil
|
||||
if self:GetClientNumber( "impactfx_enabled", 0 ) == 1 then
|
||||
impactinfo = {
|
||||
effectname = self:GetClientInfo( "impactfx_effectname", 0 ),
|
||||
utileffectinfo = Vector( self:GetClientNumber( "impactfx_utileffect_scale", 0 ), self:GetClientNumber( "impactfx_utileffect_magnitude", 0 ), self:GetClientNumber( "impactfx_utileffect_radius", 0 ) ),
|
||||
}
|
||||
if self:GetClientNumber( "impactfx_color_enabled", 0 ) == 1 then
|
||||
if self:GetClientNumber( "impactfx_color_outofone", 0 ) == 1 then
|
||||
impactinfo.colorinfo = Color( self:GetClientNumber( "impactfx_color_r", 0 ), self:GetClientNumber( "impactfx_color_g", 0 ), self:GetClientNumber( "impactfx_color_b", 0 ), 1 ) //we're using the alpha value to store color_outofone
|
||||
else
|
||||
impactinfo.colorinfo = Color( self:GetClientNumber( "impactfx_color_r", 0 ), self:GetClientNumber( "impactfx_color_g", 0 ), self:GetClientNumber( "impactfx_color_b", 0 ), 0 )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
|
||||
|
||||
|
||||
if ( trace.Entity:IsValid() ) then
|
||||
if CLIENT then return true end
|
||||
if trace.Entity:GetClass() == "prop_effect" and trace.Entity.AttachedEntity then trace.Entity = trace.Entity.AttachedEntity end
|
||||
AttachParticleControllerTracer( ply, trace.Entity, { NewTable = {
|
||||
EffectName = effectname,
|
||||
AttachNum = attachnum,
|
||||
|
||||
RepeatRate = repeatrate,
|
||||
|
||||
Toggle = toggle,
|
||||
StartOn = starton,
|
||||
NumpadKey = numpadkey,
|
||||
|
||||
ColorInfo = colorinfo,
|
||||
|
||||
TracerSpread = tracerspread,
|
||||
TracerCount = tracercount,
|
||||
LeaveBulletHoles = leavebulletholes,
|
||||
EffectLifetime = effectlifetime,
|
||||
|
||||
ImpactInfo = impactinfo,
|
||||
} } )
|
||||
return true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
local effectname = self:GetClientInfo( "effectname", 0 )
|
||||
local attachnum = self:GetOwner():GetInfoNum( "particlecontrol_attachnum", 0 ) //use the standard tool's attachnum var
|
||||
|
||||
local repeatrate = self:GetClientNumber( "repeatrate", 0 )
|
||||
|
||||
local numpadkey = self:GetClientNumber( "numpadkey", 0 )
|
||||
local toggle = self:GetClientNumber( "toggle", 0 )
|
||||
local starton = self:GetClientNumber( "starton", 0 )
|
||||
|
||||
//local utileffectinfo = Vector( self:GetClientNumber( "utileffect_scale", 0 ), self:GetClientNumber( "utileffect_magnitude", 0 ), self:GetClientNumber( "utileffect_radius", 0 ) )
|
||||
local colorinfo = nil
|
||||
if self:GetClientNumber( "color_enabled", 0 ) == 1 then
|
||||
if self:GetClientNumber( "color_outofone", 0 ) == 1 then
|
||||
colorinfo = Color( self:GetClientNumber( "color_r", 0 ), self:GetClientNumber( "color_g", 0 ), self:GetClientNumber( "color_b", 0 ), 1 ) //we're using the alpha value to store color_outofone
|
||||
else
|
||||
colorinfo = Color( self:GetClientNumber( "color_r", 0 ), self:GetClientNumber( "color_g", 0 ), self:GetClientNumber( "color_b", 0 ), 0 )
|
||||
end
|
||||
end
|
||||
|
||||
local tracerspread = self:GetClientNumber( "tracerspread", 0 )
|
||||
local tracercount = self:GetClientNumber( "tracercount", 0 )
|
||||
local leavebulletholes = self:GetClientNumber( "leavebulletholes", 0 )
|
||||
local effectlifetime = self:GetClientNumber( "effectlifetime", 0 )
|
||||
|
||||
local impactinfo = nil
|
||||
if self:GetClientNumber( "impactfx_enabled", 0 ) == 1 then
|
||||
impactinfo = {
|
||||
effectname = self:GetClientInfo( "impactfx_effectname", 0 ),
|
||||
utileffectinfo = Vector( self:GetClientNumber( "impactfx_utileffect_scale", 0 ), self:GetClientNumber( "impactfx_utileffect_magnitude", 0 ), self:GetClientNumber( "impactfx_utileffect_radius", 0 ) ),
|
||||
}
|
||||
if self:GetClientNumber( "impactfx_color_enabled", 0 ) == 1 then
|
||||
if self:GetClientNumber( "impactfx_color_outofone", 0 ) == 1 then
|
||||
impactinfo.colorinfo = Color( self:GetClientNumber( "impactfx_color_r", 0 ), self:GetClientNumber( "impactfx_color_g", 0 ), self:GetClientNumber( "impactfx_color_b", 0 ), 1 ) //we're using the alpha value to store color_outofone
|
||||
else
|
||||
impactinfo.colorinfo = Color( self:GetClientNumber( "impactfx_color_r", 0 ), self:GetClientNumber( "impactfx_color_g", 0 ), self:GetClientNumber( "impactfx_color_b", 0 ), 0 )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
|
||||
|
||||
|
||||
local propmodel = self:GetClientInfo( "propmodel", 0 )
|
||||
local propangle = self:GetClientNumber( "propangle", 0 )
|
||||
//propangle 1: spawn upright
|
||||
//propangle 2: spawn at surface angle
|
||||
|
||||
if !util.IsValidModel(propmodel) then return false end
|
||||
if !util.IsValidProp(propmodel) then return false end
|
||||
if CLIENT then return true end
|
||||
|
||||
prop = ents.Create( "prop_physics" )
|
||||
prop:SetModel( propmodel )
|
||||
prop:SetPos( trace.HitPos - trace.HitNormal * prop:OBBMins().z )
|
||||
if propangle == 1 then prop:SetAngles(Angle(0,trace.HitNormal:Angle().y,0)) else prop:SetAngles(trace.HitNormal:Angle()) end
|
||||
prop:SetCollisionGroup(20) //COLLISION_GROUP_NONE, nocollide with everything except world
|
||||
prop:Spawn()
|
||||
|
||||
local shouldweweld = true //don't weld if...
|
||||
if ( !util.IsValidPhysicsObject(prop, 0) ) then shouldweweld = false end //the prop doesn't have a phys object
|
||||
if ( !trace.Entity:IsValid() ) then shouldweweld = false end //the thing we clicked on doesn't exist/is the world
|
||||
if ( trace.Entity && trace.Entity:IsPlayer() ) then shouldweweld = false end //the thing we clicked on is a player
|
||||
if ( !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then shouldweweld = false end //the thing we clicked on doesn't have a phys object
|
||||
if shouldweweld == true then
|
||||
local const = constraint.Weld( prop, trace.Entity, 0, trace.PhysicsBone, 0, true, true )
|
||||
else
|
||||
if util.IsValidPhysicsObject(prop, 0) then prop:GetPhysicsObject():EnableMotion(false) end
|
||||
end
|
||||
|
||||
if self:GetClientNumber( "propinvis", 0 ) == 1 then
|
||||
prop:SetRenderMode(1) //we need to change the render mode so the transparency actually shows up
|
||||
prop:SetColor( Color(255,255,255,0) )
|
||||
duplicator.StoreEntityModifier( prop, "colour", { Color = Color(255,255,255,0), RenderMode = 1, RenderFX = 0 } )
|
||||
end
|
||||
|
||||
undo.Create( "prop" )
|
||||
undo.AddEntity( prop )
|
||||
undo.SetPlayer( ply )
|
||||
undo.Finish( "Prop ("..tostring(propmodel)..")" )
|
||||
|
||||
|
||||
|
||||
if ( prop:IsValid() ) then
|
||||
AttachParticleControllerTracer( ply, prop, { NewTable = {
|
||||
EffectName = effectname,
|
||||
AttachNum = attachnum,
|
||||
|
||||
RepeatRate = repeatrate,
|
||||
|
||||
Toggle = toggle,
|
||||
StartOn = starton,
|
||||
NumpadKey = numpadkey,
|
||||
|
||||
ColorInfo = colorinfo,
|
||||
|
||||
TracerSpread = tracerspread,
|
||||
TracerCount = tracercount,
|
||||
LeaveBulletHoles = leavebulletholes,
|
||||
EffectLifetime = effectlifetime,
|
||||
|
||||
ImpactInfo = impactinfo,
|
||||
} } )
|
||||
return true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
|
||||
if ( trace.Entity:IsValid() ) then
|
||||
local fx = false
|
||||
|
||||
if trace.Entity:GetClass() == "prop_effect" and trace.Entity.AttachedEntity then trace.Entity = trace.Entity.AttachedEntity end
|
||||
|
||||
for _, asdf in pairs( ents:GetAll() ) do
|
||||
if asdf:GetClass() == "particlecontroller_tracer" and asdf:GetParent() == trace.Entity then
|
||||
if SERVER then asdf:Remove() end
|
||||
fx = true
|
||||
end
|
||||
end
|
||||
if SERVER then
|
||||
duplicator.ClearEntityModifier( trace.Entity, "DupeParticleControllerTracer" )
|
||||
end
|
||||
|
||||
return fx
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
if CLIENT then
|
||||
|
||||
local colorborder = Color(0,0,0,255)
|
||||
local colorselect = Color(0,255,0,255)
|
||||
local colorunselect = Color(255,255,255,255)
|
||||
|
||||
function TOOL:DrawHUD()
|
||||
local pl = LocalPlayer()
|
||||
local tr = pl:GetEyeTrace()
|
||||
local attachnum = self:GetOwner():GetInfoNum( "particlecontrol_attachnum", 0 ) //use the standard tool's attachnum var
|
||||
|
||||
local function DrawHighlightAttachments(ent)
|
||||
|
||||
//If there aren't any attachments, then draw the model origin as selected and stop here:
|
||||
if !ent:GetAttachments() or !ent:GetAttachments()[1] then
|
||||
local _pos,_ang = ent:GetPos(), ent:GetAngles()
|
||||
local _pos = _pos:ToScreen()
|
||||
local textpos = {x = _pos.x+5,y = _pos.y-5}
|
||||
|
||||
draw.RoundedBox(0,_pos.x - 3,_pos.y - 3,6,6,colorborder)
|
||||
draw.RoundedBox(0,_pos.x - 1,_pos.y - 1,2,2,colorselect)
|
||||
draw.SimpleTextOutlined("0: (origin)","Default",textpos.x,textpos.y,colorselect,TEXT_ALIGN_LEFT,TEXT_ALIGN_BOTTOM,2,colorborder)
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
//Draw the unselected model origin, if applicable:
|
||||
if ent:GetAttachments()[attachnum] then
|
||||
local _pos,_ang = ent:GetPos(), ent:GetAngles()
|
||||
local _pos = _pos:ToScreen()
|
||||
local textpos = {x = _pos.x+5,y = _pos.y-5}
|
||||
|
||||
draw.RoundedBox(0,_pos.x - 2,_pos.y - 2,4,4,colorborder)
|
||||
draw.RoundedBox(0,_pos.x - 1,_pos.y - 1,2,2,colorunselect)
|
||||
draw.SimpleTextOutlined("0: (origin)","Default",textpos.x,textpos.y,colorunselect,TEXT_ALIGN_LEFT,TEXT_ALIGN_BOTTOM,1,colorborder)
|
||||
end
|
||||
|
||||
//Draw the unselected attachment points:
|
||||
for _, table in pairs(ent:GetAttachments()) do
|
||||
local _pos,_ang = ent:GetAttachment(table.id).Pos,ent:GetAttachment(table.id).Ang
|
||||
local _pos = _pos:ToScreen()
|
||||
local textpos = {x = _pos.x+5,y = _pos.y-5}
|
||||
|
||||
if table.id != attachnum then
|
||||
draw.RoundedBox(0,_pos.x - 2,_pos.y - 2,4,4,colorborder)
|
||||
draw.RoundedBox(0,_pos.x - 1,_pos.y - 1,2,2,colorunselect)
|
||||
draw.SimpleTextOutlined(table.id ..": ".. table.name,"Default",textpos.x,textpos.y,colorunselect,TEXT_ALIGN_LEFT,TEXT_ALIGN_BOTTOM,1,colorborder)
|
||||
end
|
||||
end
|
||||
|
||||
//Draw the selected attachment point or model origin last, so it renders above all the others:
|
||||
if !ent:GetAttachments()[attachnum] then
|
||||
//Model origin
|
||||
local _pos,_ang = ent:GetPos(), ent:GetAngles()
|
||||
local _pos = _pos:ToScreen()
|
||||
local textpos = {x = _pos.x+5,y = _pos.y-5}
|
||||
|
||||
draw.RoundedBox(0,_pos.x - 3,_pos.y - 3,6,6,colorborder)
|
||||
draw.RoundedBox(0,_pos.x - 1,_pos.y - 1,2,2,colorselect)
|
||||
draw.SimpleTextOutlined("0: (origin)","Default",textpos.x,textpos.y,colorselect,TEXT_ALIGN_LEFT,TEXT_ALIGN_BOTTOM,2,colorborder)
|
||||
else
|
||||
//Attachment
|
||||
local _pos,_ang = ent:GetAttachment(attachnum).Pos,ent:GetAttachment(attachnum).Ang
|
||||
local _pos = _pos:ToScreen()
|
||||
local textpos = {x = _pos.x+5,y = _pos.y-5}
|
||||
|
||||
draw.RoundedBox(0,_pos.x - 3,_pos.y - 3,6,6,colorborder)
|
||||
draw.RoundedBox(0,_pos.x - 1,_pos.y - 1,2,2,colorselect)
|
||||
draw.SimpleTextOutlined(attachnum ..": ".. ent:GetAttachments()[attachnum].name,"Default",textpos.x,textpos.y,colorselect,TEXT_ALIGN_LEFT,TEXT_ALIGN_BOTTOM,2,colorborder)
|
||||
end
|
||||
end
|
||||
|
||||
if IsValid(tr.Entity) and tr.Entity == self.HighlightedEnt then
|
||||
DrawHighlightAttachments(self.HighlightedEnt)
|
||||
return end
|
||||
|
||||
if IsValid(tr.Entity) and tr.Entity != self.HighlightedEnt then
|
||||
//unhighlight the old ent if it exists
|
||||
if self.HighlightedEnt != nil then
|
||||
self.HighlightedEnt = nil
|
||||
end
|
||||
|
||||
//highlight the new ent
|
||||
self.HighlightedEnt = tr.Entity
|
||||
end
|
||||
|
||||
if !IsValid(tr.Entity) and self.HighlightedEnt != nil then
|
||||
self.HighlightedEnt = nil
|
||||
end
|
||||
end
|
||||
|
||||
function TOOL:Holster()
|
||||
if self.HighlightedEnt != nil then
|
||||
self.HighlightedEnt = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
//All credit for the toolgun scroll wheel code goes to the Wiremod devs. You guys are the best.
|
||||
local function get_active_tool(ply, tool)
|
||||
-- find toolgun
|
||||
local activeWep = ply:GetActiveWeapon()
|
||||
if not IsValid(activeWep) or activeWep:GetClass() ~= "gmod_tool" or activeWep.Mode ~= tool then return end
|
||||
|
||||
return activeWep:GetToolObject(tool)
|
||||
end
|
||||
|
||||
local function hookfunc( ply, bind, pressed )
|
||||
if not pressed then return end
|
||||
if bind == "invnext" then
|
||||
local self = get_active_tool(ply, "particlecontrol_tracer")
|
||||
if not self then return end
|
||||
|
||||
return self:ScrollDown(ply:GetEyeTraceNoCursor())
|
||||
elseif bind == "invprev" then
|
||||
local self = get_active_tool(ply, "particlecontrol_tracer")
|
||||
if not self then return end
|
||||
|
||||
return self:ScrollUp(ply:GetEyeTraceNoCursor())
|
||||
end
|
||||
end
|
||||
|
||||
if game.SinglePlayer() then -- wtfgarry (have to have a delay in single player or the hook won't get added)
|
||||
timer.Simple(5,function() hook.Add( "PlayerBindPress", "particlecontrol_tracer_playerbindpress", hookfunc ) end)
|
||||
else
|
||||
hook.Add( "PlayerBindPress", "particlecontrol_tracer_playerbindpress", hookfunc )
|
||||
end
|
||||
//End shamefully copied code here.
|
||||
|
||||
function TOOL:Scroll(trace,dir)
|
||||
if !IsValid(self.HighlightedEnt) then return end
|
||||
|
||||
local attachcount = 0
|
||||
if self.HighlightedEnt:GetAttachments() then attachcount = table.Count(self.HighlightedEnt:GetAttachments()) end
|
||||
local oldattachnum = self:GetOwner():GetInfoNum( "particlecontrol_attachnum", 0 ) //use the standard tool's attachnum var
|
||||
if oldattachnum > attachcount then oldattachnum = 0 end
|
||||
local attachnum = oldattachnum + dir
|
||||
|
||||
if attachnum < 0 then attachnum = attachcount end
|
||||
if attachnum > attachcount then attachnum = 0 end
|
||||
RunConsoleCommand("particlecontrol_attachnum", tostring(attachnum)) //use the standard tool's attachnum var
|
||||
self:GetOwner():EmitSound("weapons/pistol/pistol_empty.wav")
|
||||
return true
|
||||
end
|
||||
function TOOL:ScrollUp(trace) return self:Scroll(trace,-1) end
|
||||
function TOOL:ScrollDown(trace) return self:Scroll(trace,1) end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
if SERVER then
|
||||
|
||||
local function SpawnParticleControllerTracer(ply, ent, DataTable)
|
||||
|
||||
if DataTable == nil or DataTable == {} or DataTable.EffectName == nil or ent == nil or !IsValid(ent) then return end
|
||||
|
||||
|
||||
local ParticleControlTracer = ents.Create( "particlecontroller_tracer" )
|
||||
ParticleControlTracer:SetPos(ent:GetPos())
|
||||
ParticleControlTracer:SetAngles(ent:GetAngles())
|
||||
ParticleControlTracer:SetParent(ent)
|
||||
ent:DeleteOnRemove(ParticleControlTracer)
|
||||
|
||||
ParticleControlTracer:SetTargetEnt(ent)
|
||||
ParticleControlTracer:SetEffectName(DataTable.EffectName)
|
||||
ParticleControlTracer:SetAttachNum(DataTable.AttachNum)
|
||||
//ParticleControlTracer:SetUtilEffectInfo(DataTable.UtilEffectInfo)
|
||||
if DataTable.ColorInfo != nil then ParticleControlTracer:SetColor(DataTable.ColorInfo) else ParticleControlTracer:SetColor( Color(0,0,0,0) ) end
|
||||
|
||||
ParticleControlTracer:SetTracerSpread(DataTable.TracerSpread)
|
||||
ParticleControlTracer:SetTracerCount(DataTable.TracerCount)
|
||||
if DataTable.LeaveBulletHoles == 1 or DataTable.LeaveBulletHoles == true then ParticleControlTracer:SetLeaveBulletHoles(true) else ParticleControlTracer:SetLeaveBulletHoles(false) end
|
||||
ParticleControlTracer:SetEffectLifetime(DataTable.EffectLifetime or 1.00) //old dupes will have nil
|
||||
|
||||
if DataTable.ImpactInfo != nil then
|
||||
ParticleControlTracer:SetImpact_EffectName(DataTable.ImpactInfo.effectname)
|
||||
ParticleControlTracer:SetImpact_UtilEffectInfo(DataTable.ImpactInfo.utileffectinfo)
|
||||
if DataTable.ImpactInfo.colorinfo != nil then
|
||||
local impactcolor = Vector(DataTable.ImpactInfo.colorinfo.r, DataTable.ImpactInfo.colorinfo.g, DataTable.ImpactInfo.colorinfo.b)
|
||||
if DataTable.ImpactInfo.colorinfo.a then
|
||||
impactcolor = impactcolor / 255
|
||||
end
|
||||
ParticleControlTracer:SetImpact_ColorInfo( impactcolor )
|
||||
else
|
||||
ParticleControlTracer:SetImpact_ColorInfo( Vector(0,0,0) )
|
||||
end
|
||||
else
|
||||
ParticleControlTracer:SetImpact_EffectName("")
|
||||
end
|
||||
|
||||
ParticleControlTracer:SetRepeatRate(DataTable.RepeatRate)
|
||||
|
||||
|
||||
if DataTable.StartOn == 1 or DataTable.StartOn == true then ParticleControlTracer:SetActive(true) else ParticleControlTracer:SetActive(false) end
|
||||
if DataTable.Toggle == 1 or DataTable.Toggle == true then ParticleControlTracer:SetToggle(true) else ParticleControlTracer:SetToggle(false) end
|
||||
ParticleControlTracer:SetNumpadKey(DataTable.NumpadKey)
|
||||
|
||||
numpad.OnDown( ply, DataTable.NumpadKey, "Particle_Press", ParticleControlTracer )
|
||||
numpad.OnUp( ply, DataTable.NumpadKey, "Particle_Release", ParticleControlTracer )
|
||||
ParticleControlTracer:SetNumpadState("")
|
||||
|
||||
|
||||
ParticleControlTracer:Spawn()
|
||||
ParticleControlTracer:Activate()
|
||||
|
||||
end
|
||||
|
||||
|
||||
function AttachParticleControllerTracer( ply, ent, Data )
|
||||
|
||||
if Data.NewTable then
|
||||
SpawnParticleControllerTracer(ply, ent, Data.NewTable)
|
||||
|
||||
local dupetable = {}
|
||||
if ent.EntityMods and ent.EntityMods.DupeParticleControllerTracer then dupetable = ent.EntityMods.DupeParticleControllerTracer end
|
||||
table.insert(dupetable, Data.NewTable)
|
||||
duplicator.StoreEntityModifier( ent, "DupeParticleControllerTracer", dupetable )
|
||||
return end
|
||||
|
||||
end
|
||||
|
||||
|
||||
function DupeParticleControllerTracer( ply, ent, Data )
|
||||
|
||||
//due to a problem with the easy bonemerge tool that causes entity modifiers to be applied TWICE, we need to remove the effects that were added the first time
|
||||
for _, asdf in pairs( ents:GetAll() ) do
|
||||
if asdf:GetClass() == "particlecontroller_tracer" and asdf:GetParent() == ent then
|
||||
asdf:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
for _, DataTable in pairs (Data) do
|
||||
SpawnParticleControllerTracer(ply, ent, DataTable)
|
||||
end
|
||||
|
||||
end
|
||||
duplicator.RegisterEntityModifier( "DupeParticleControllerTracer", DupeParticleControllerTracer )
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
//we're still testing out a lot of stuff with the cpanel, so let's add a way to refresh it by reselecting the tool
|
||||
--[[
|
||||
TOOL.ClientConVar[ "refresh" ] = 1
|
||||
function TOOL:Think()
|
||||
if SERVER then return end
|
||||
if self:GetClientNumber("refresh") == 1 then
|
||||
RunConsoleCommand("particlecontrol_tracer_refresh", "0");
|
||||
//refresh the cpanel
|
||||
local panel = controlpanel.Get( "particlecontrol_tracer" )
|
||||
if ( !panel ) then return end
|
||||
panel:ClearControls()
|
||||
self.BuildCPanel(panel)
|
||||
end
|
||||
end
|
||||
function TOOL:Deploy()
|
||||
RunConsoleCommand("particlecontrol_tracer_refresh", "1");
|
||||
end
|
||||
]]
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel(panel)
|
||||
|
||||
panel:AddControl( "Header", { Description = "#tool.particlecontrol_tracer.help" } )
|
||||
|
||||
//Presets
|
||||
panel:AddControl( "ComboBox", {
|
||||
MenuButton = 1,
|
||||
Folder = "particlecontrol_tracer",
|
||||
Options = {
|
||||
//[ "#preset.default" ] = ConVarsDefault
|
||||
[ "Example: Pulse Rifle" ] = ConVarsDefault,
|
||||
[ "Example: Generic Bullets" ] = { particlecontrol_tracer_color_b = "0", particlecontrol_tracer_color_enabled = "0", particlecontrol_tracer_color_g = "20", particlecontrol_tracer_color_outofone = "0", particlecontrol_tracer_color_r = "255", particlecontrol_tracer_effectlifetime = "1.000000", particlecontrol_tracer_effectname = "!UTILEFFECT!Tracer", particlecontrol_tracer_impactfx_color_b = "0", particlecontrol_tracer_impactfx_color_enabled = "0", particlecontrol_tracer_impactfx_color_g = "20", particlecontrol_tracer_impactfx_color_outofone = "0", particlecontrol_tracer_impactfx_color_r = "255", particlecontrol_tracer_impactfx_effectname = "!UTILEFFECT!AR2Impact", particlecontrol_tracer_impactfx_enabled = "0", particlecontrol_tracer_impactfx_utileffect_magnitude = "1", particlecontrol_tracer_impactfx_utileffect_radius = "10", particlecontrol_tracer_impactfx_utileffect_scale = "1", particlecontrol_tracer_leavebulletholes = "1", particlecontrol_tracer_numpadkey = "52",
|
||||
particlecontrol_tracer_propangle = "2", particlecontrol_tracer_propinvis = "0", particlecontrol_tracer_propmodel = "models/weapons/w_smg1.mdl", particlecontrol_tracer_repeatrate = "0.080000", particlecontrol_tracer_starton = "1", particlecontrol_tracer_toggle = "1", particlecontrol_tracer_tracercount = "1", particlecontrol_tracer_tracerspread = "0.050000" },
|
||||
[ "Example: Toolgun" ] = { particlecontrol_tracer_color_b = "0", particlecontrol_tracer_color_enabled = "0", particlecontrol_tracer_color_g = "20", particlecontrol_tracer_color_outofone = "0", particlecontrol_tracer_color_r = "255", particlecontrol_tracer_effectlifetime = "1.000000", particlecontrol_tracer_effectname = "!UTILEFFECT!ToolTracer", particlecontrol_tracer_impactfx_color_b = "0", particlecontrol_tracer_impactfx_color_enabled = "0", particlecontrol_tracer_impactfx_color_g = "20", particlecontrol_tracer_impactfx_color_outofone = "0", particlecontrol_tracer_impactfx_color_r = "255", particlecontrol_tracer_impactfx_effectname = "!UTILEFFECT!selection_indicator", particlecontrol_tracer_impactfx_enabled = "1", particlecontrol_tracer_impactfx_utileffect_magnitude = "1", particlecontrol_tracer_impactfx_utileffect_radius = "10", particlecontrol_tracer_impactfx_utileffect_scale = "1", particlecontrol_tracer_leavebulletholes = "0", particlecontrol_tracer_numpadkey = "52",
|
||||
particlecontrol_tracer_propangle = "2", particlecontrol_tracer_propinvis = "0", particlecontrol_tracer_propmodel = "models/weapons/w_smg1.mdl", particlecontrol_tracer_repeatrate = "1", particlecontrol_tracer_starton = "1", particlecontrol_tracer_toggle = "1", particlecontrol_tracer_tracercount = "1", particlecontrol_tracer_tracerspread = "0" },
|
||||
},
|
||||
CVars = table.GetKeys( ConVarsDefault )
|
||||
} )
|
||||
|
||||
|
||||
|
||||
AddParticleBrowserTracer(panel, {
|
||||
name = "Tracer Effect",
|
||||
commands = {
|
||||
effectname = "particlecontrol_tracer_effectname",
|
||||
color = "particlecontrol_tracer_color",
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
|
||||
//panel:AddControl( "Label", { Text = "" } )
|
||||
//panel:AddControl( "Label", { Text = "" } )
|
||||
|
||||
|
||||
|
||||
panel:AddControl( "Checkbox", { Label = "Enable impact effects?", Command = "particlecontrol_tracer_impactfx_enabled" } )
|
||||
|
||||
AddParticleBrowser(panel, {
|
||||
name = "Impact Effect",
|
||||
commands = {
|
||||
effectname = "particlecontrol_tracer_impactfx_effectname",
|
||||
color = "particlecontrol_tracer_impactfx_color",
|
||||
utileffect = "particlecontrol_tracer_impactfx_utileffect",
|
||||
|
||||
enabled = "particlecontrol_tracer_impactfx_enabled",
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
|
||||
//panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
|
||||
|
||||
|
||||
panel:AddControl("Slider", {
|
||||
Label = "Attachment",
|
||||
Type = "Integer",
|
||||
Min = "0",
|
||||
Max = "10",
|
||||
Command = "particlecontrol_attachnum", //use the standard tool's attachnum var
|
||||
})
|
||||
panel:ControlHelp( "Attachment point on the model to fire tracers from. Set to 0 to fire from the model origin." )
|
||||
|
||||
panel:AddControl("Slider", {
|
||||
Label = "Repeat Rate",
|
||||
Type = "Float",
|
||||
Min = "0",
|
||||
Max = "1",
|
||||
Command = "particlecontrol_tracer_repeatrate"
|
||||
})
|
||||
panel:ControlHelp( "How often the tracer fires. Set to 0 to not repeat." )
|
||||
|
||||
|
||||
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
|
||||
|
||||
|
||||
panel:AddControl("Slider", {
|
||||
Label = "Tracer Spread",
|
||||
Type = "Float",
|
||||
Min = "0",
|
||||
Max = "1",
|
||||
Command = "particlecontrol_tracer_tracerspread"
|
||||
})
|
||||
panel:ControlHelp( "Each unit is 90 degrees of spread - you can type in 2 for 180 degrees or even 4 for 360 degrees." )
|
||||
|
||||
panel:AddControl("Slider", {
|
||||
Label = "Tracers per shot",
|
||||
Type = "Integer",
|
||||
Min = "1",
|
||||
Max = "10",
|
||||
Command = "particlecontrol_tracer_tracercount"
|
||||
})
|
||||
|
||||
panel:AddControl( "Checkbox", { Label = "Leave bullet holes?", Command = "particlecontrol_tracer_leavebulletholes" } )
|
||||
|
||||
panel:AddControl("Slider", {
|
||||
Label = "Effect Lifetime",
|
||||
Type = "Float",
|
||||
Min = "0.5",
|
||||
Max = "5",
|
||||
Command = "particlecontrol_tracer_effectlifetime"
|
||||
})
|
||||
//panel:ControlHelp( "Number of seconds before tracer and impact effects are removed." )
|
||||
|
||||
|
||||
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
|
||||
|
||||
|
||||
local modellist = { Label = "Prop:", ConVar = "particlecontrol_tracer_propmodel", Category = "Prop", Height = 1, Models = {} }
|
||||
modellist.Models["models/hunter/plates/plate025x025.mdl"] = {}
|
||||
modellist.Models["models/hunter/plates/plate.mdl"] = {}
|
||||
modellist.Models["models/weapons/w_smg1.mdl"] = {}
|
||||
modellist.Models["models/weapons/w_models/w_shotgun.mdl"] = {}
|
||||
|
||||
panel:AddControl( "PropSelect", modellist )
|
||||
|
||||
panel:AddControl( "ComboBox", {
|
||||
Label = "Prop Angle",
|
||||
MenuButton = "0",
|
||||
Options = {
|
||||
["Spawn upright"] = { particlecontrol_tracer_propangle = "1" },
|
||||
["Spawn at surface angle"] = { particlecontrol_tracer_propangle = "2" }
|
||||
}
|
||||
})
|
||||
|
||||
panel:AddControl( "Checkbox", { Label = "Invisible prop (particles only)", Command = "particlecontrol_tracer_propinvis" } )
|
||||
|
||||
|
||||
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
panel:AddControl( "Label", { Text = "" } )
|
||||
|
||||
|
||||
|
||||
panel:AddControl( "Numpad", {
|
||||
Label = "Effect Key",
|
||||
Command = "particlecontrol_tracer_numpadkey",
|
||||
ButtonSize = 22
|
||||
})
|
||||
|
||||
panel:AddControl( "Checkbox", { Label = "Toggle", Command = "particlecontrol_tracer_toggle" } )
|
||||
|
||||
panel:AddControl( "Checkbox", { Label = "Start on?", Command = "particlecontrol_tracer_starton" } )
|
||||
|
||||
end
|
||||
1643
lua/weapons/gmod_tool/stools/precision.lua
Normal file
1643
lua/weapons/gmod_tool/stools/precision.lua
Normal file
File diff suppressed because it is too large
Load Diff
619
lua/weapons/gmod_tool/stools/prop_door.lua
Normal file
619
lua/weapons/gmod_tool/stools/prop_door.lua
Normal file
@@ -0,0 +1,619 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Original idea by High6
|
||||
|
||||
TOOL.Category = "Half-Life 2"
|
||||
TOOL.Name = "#tool.prop_door"
|
||||
|
||||
TOOL.ClientConVar[ "model" ] = "models/props_c17/door01_left.mdl"
|
||||
TOOL.ClientConVar[ "type" ] = "1"
|
||||
TOOL.ClientConVar[ "key_open" ] = "38"
|
||||
TOOL.ClientConVar[ "key_close" ] = "39"
|
||||
TOOL.ClientConVar[ "key_lock" ] = "40"
|
||||
TOOL.ClientConVar[ "key_unlock" ] = "41"
|
||||
|
||||
TOOL.ClientConVar[ "auto_close" ] = "1"
|
||||
TOOL.ClientConVar[ "auto_close_delay" ] = "4"
|
||||
|
||||
TOOL.ClientConVar[ "skin" ] = "1"
|
||||
|
||||
TOOL.ClientConVar[ "r_double" ] = "0"
|
||||
TOOL.ClientConVar[ "r_hardware" ] = "1"
|
||||
TOOL.ClientConVar[ "r_distance" ] = "90"
|
||||
TOOL.ClientConVar[ "r_speed" ] = "100"
|
||||
TOOL.ClientConVar[ "breakable" ] = "0"
|
||||
|
||||
local gDoorUniqueID = 0
|
||||
|
||||
cleanup.Register( "prop_doors" )
|
||||
|
||||
local minsZ = {}
|
||||
minsZ[ "models/props/portal_door_combined.mdl" ] = -18.421800613403
|
||||
minsZ[ "models/props_mining/elevator01_cagedoor.mdl" ] = 0
|
||||
minsZ[ "models/props_mining/techgate01.mdl" ] = -3.0040739147807e-05
|
||||
minsZ[ "models/props_combine/combine_door01.mdl" ] = -96.376152038574
|
||||
minsZ[ "models/combine_gate_vehicle.mdl" ] = -30.216606140137
|
||||
minsZ[ "models/combine_gate_citizen.mdl" ] = -30.00006103515
|
||||
minsZ[ "models/props_lab/elevatordoor.mdl" ] = -1
|
||||
--minsZ[ "models/props_doors/doorklab01.mdl" ] = -5.004433631897
|
||||
|
||||
function TOOL:FixDynamicPos( mdl, pos, ang, minz )
|
||||
|
||||
-- This is UGLY AF
|
||||
if ( --[[!minz &&]] minsZ[ mdl ] ) then minz = minsZ[ mdl ] else minz = 0 end
|
||||
|
||||
local ent = self:GetOwner()
|
||||
|
||||
if ( mdl == "models/props_mining/elevator01_cagedoor.mdl" ) then
|
||||
ang:RotateAroundAxis( Vector( 0, 0, 1 ), -90 )
|
||||
else
|
||||
pos = pos - Vector( 0, 0, minz )
|
||||
end
|
||||
|
||||
if ( mdl == "models/props_combine/combine_door01.mdl" ) then
|
||||
ang:RotateAroundAxis( Vector( 0, 0, 1 ), -90 )
|
||||
end
|
||||
if ( mdl == "models/props_mining/techgate01.mdl" or mdl == "models/props_mining/techgate01_outland03.mdl" ) then
|
||||
ang:RotateAroundAxis( Vector( 0, 0, 1 ), -90 )
|
||||
pos = pos - ent:GetRight() * 80
|
||||
end
|
||||
|
||||
if ( mdl == "models/props/portal_door_combined.mdl" ) then
|
||||
pos = pos - ent:GetUp() * 21
|
||||
ang:RotateAroundAxis( Vector( 0, 0, 1 ), -180 )
|
||||
end
|
||||
|
||||
return pos, ang
|
||||
end
|
||||
|
||||
function TOOL:FixRotatingPos( ent )
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local e = ent
|
||||
|
||||
local min = ent:OBBMins()
|
||||
local max = ent:OBBMaxs()
|
||||
local pos = ent:GetPos()
|
||||
local ang = ent:GetAngles()
|
||||
|
||||
local typ = self:GetClientNumber( "type" )
|
||||
local doubl = self:GetClientNumber( "r_double" ) + 1
|
||||
|
||||
if ( typ == 1 or typ == 3 ) then pos = pos + ent:GetRight() * ( max.y / 2.01 ) * doubl end
|
||||
if ( typ == 2 ) then pos = pos + ent:GetRight() * ( max.y / 3.1 ) * doubl end
|
||||
|
||||
-- L4D2 doors
|
||||
if ( typ == 4 ) then pos = pos + ent:GetRight() * ( max.y / 2.34 ) * doubl end -- This really should be more dynamic!
|
||||
if ( typ == 5 ) then pos = pos + ent:GetRight() * ( max.y / 2.04 ) * doubl end
|
||||
if ( typ == 6 ) then pos = pos + ent:GetRight() * ( max.y / 2.21 ) * doubl end
|
||||
if ( typ == 7 ) then pos = pos + ent:GetRight() * ( max.y / 2.057 ) * doubl end
|
||||
if ( typ == 8 ) then pos = pos + ent:GetRight() * ( max.y / 2.07 ) * doubl end
|
||||
if ( typ == 9 ) then pos = pos + ent:GetRight() * ( max.y / 2.067 ) * doubl end
|
||||
if ( typ == 10 ) then pos = pos + ent:GetRight() * ( max.y / 2.081 ) * doubl end
|
||||
|
||||
e:SetPos( pos - Vector( 0, 0, min.z ) )
|
||||
e:SetAngles( ang )
|
||||
e:Activate()
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
CreateConVar( "sbox_maxprop_doors", 10, FCVAR_ARCHIVE + FCVAR_REPLICATED + FCVAR_NOTIFY )
|
||||
|
||||
numpad.Register( "prop_door_open", function( ply, prop_door ) if ( !IsValid( prop_door ) ) then return false end prop_door:Fire( "Open" ) end )
|
||||
numpad.Register( "prop_door_close", function( ply, prop_door ) if ( !IsValid( prop_door ) ) then return false end prop_door:Fire( "Close" ) end )
|
||||
numpad.Register( "prop_door_lock", function( ply, prop_door ) if ( !IsValid( prop_door ) ) then return false end prop_door:Fire( "Lock" ) end )
|
||||
numpad.Register( "prop_door_unlock", function( ply, prop_door ) if ( !IsValid( prop_door ) ) then return false end prop_door:Fire( "Unlock" ) end )
|
||||
|
||||
local function ApplyWireModSupport( door, mapCreationID )
|
||||
if ( Wire_CreateOutputs and !mapCreationID ) then
|
||||
--door.Outputs = Wire_CreateOutputs( door, { "OnClosed", "OnOpened", "OnLocked", "OnUnlocked" } )
|
||||
door.Inputs = Wire_CreateInputs( door, { "Open", "Lock" } )
|
||||
|
||||
function door:TriggerInput( name, value )
|
||||
if ( name == "Open" ) then self:Fire( value != 0 and "Open" or "Close" ) end
|
||||
if ( name == "Lock" ) then self:Fire( value != 0 and "Lock" or "Unlock" ) end
|
||||
end
|
||||
|
||||
rb655_hl2_CopyWireModMethods( door )
|
||||
end
|
||||
end
|
||||
|
||||
local function EnsureNameIsUnique( input )
|
||||
local doors = ents.FindByName( input )
|
||||
if ( #doors > 1 ) then
|
||||
--ErrorNoHalt( "Map already has 2 doors with name ", input , "\n" )
|
||||
-- Could probably use a while loop here...
|
||||
return EnsureNameIsUnique( input .. "_2" )
|
||||
end
|
||||
|
||||
return input
|
||||
end
|
||||
|
||||
local function RotatingDoorPostDupe( door )
|
||||
|
||||
function door:PreEntityCopy()
|
||||
self.rb655_door_opened = self:GetInternalVariable( "m_eDoorState" ) != 0
|
||||
self.rb655_door_locked = self:GetInternalVariable( "m_bLocked" )
|
||||
end
|
||||
|
||||
function door:OnDuplicated( table )
|
||||
|
||||
-- On duplicaton, if was opened, make it open
|
||||
if ( table.rb655_door_opened ) then self:Fire( "Open" ) end
|
||||
if ( table.rb655_door_locked ) then self:Fire( "Lock" ) end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function MakeDoorRotating( ply, model, pos, ang, _oSkin, keyOpen, keyClose, keyLock, keyUnlock, _oHardware, _oDistance, _oSpeed, _oReturnDelay, breakable, _oTargetName, data, mapCreationID )
|
||||
|
||||
if ( IsValid( ply ) and !ply:CheckLimit( "prop_doors" ) ) then return nil end
|
||||
|
||||
local prop_door_rotating = ents.Create( "prop_door_rotating" )
|
||||
if ( !IsValid( prop_door_rotating ) ) then return false end
|
||||
|
||||
prop_door_rotating:SetModel( model )
|
||||
prop_door_rotating:SetPos( pos )
|
||||
|
||||
if ( data and data.initialAngles ) then ang = data.initialAngles end
|
||||
prop_door_rotating:SetAngles( ang )
|
||||
|
||||
RotatingDoorPostDupe( prop_door_rotating )
|
||||
ApplyWireModSupport( prop_door_rotating, mapCreationID )
|
||||
|
||||
keyOpen = keyOpen or -1
|
||||
keyClose = keyClose or -1
|
||||
keyLock = keyLock or -1
|
||||
keyUnlock = keyUnlock or -1
|
||||
|
||||
local targetname = _oTargetName or ""
|
||||
if ( data and data.targetname ) then targetname = data.targetname end
|
||||
local hardware = _oHardware or 1
|
||||
if ( data and data.hardware ) then hardware = data.hardware end
|
||||
local distance = _oDistance or 90
|
||||
if ( data and data.distance ) then distance = data.distance end
|
||||
local speed = _oSpeed or 100
|
||||
if ( data and data.speed ) then speed = data.speed end
|
||||
local returndelay = _oReturnDelay or 4
|
||||
if ( data and data.returndelay ) then returndelay = data.returndelay end
|
||||
local skin = _oSkin or 0
|
||||
if ( data and data.skin ) then skin = data.skin end
|
||||
|
||||
local spawnflags = 8192
|
||||
--if ( data and data.spawnflags ) then spawnflags = data.spawnflags end
|
||||
local ajarangles
|
||||
if ( data and data.ajarangles ) then ajarangles = data.ajarangles end
|
||||
local axis
|
||||
if ( data and data.axis ) then axis = data.axis end
|
||||
local spawnpos
|
||||
if ( data and data.spawnpos ) then spawnpos = data.spawnpos end
|
||||
|
||||
if ( targetname and targetname:len() > 0 ) then
|
||||
-- We gotta make sure there are no more than 2 doors with the same name, because only 2 can be linked at a time.
|
||||
targetname = EnsureNameIsUnique( targetname )
|
||||
|
||||
prop_door_rotating:SetKeyValue( "targetname", targetname )
|
||||
end
|
||||
|
||||
prop_door_rotating:SetKeyValue( "hardware", hardware )
|
||||
prop_door_rotating:SetKeyValue( "distance", distance )
|
||||
prop_door_rotating:SetKeyValue( "speed", speed )
|
||||
prop_door_rotating:SetKeyValue( "returndelay", returndelay )
|
||||
prop_door_rotating:SetKeyValue( "spawnflags", spawnflags )
|
||||
if ( ajarangles ) then prop_door_rotating:SetKeyValue( "ajarangles", ajarangles ) end
|
||||
if ( axis ) then prop_door_rotating:SetKeyValue( "axis", axis ) end
|
||||
if ( spawnpos ) then prop_door_rotating:SetKeyValue( "spawnpos", spawnpos ) end
|
||||
|
||||
prop_door_rotating:Spawn()
|
||||
prop_door_rotating:Activate()
|
||||
|
||||
prop_door_rotating:SetSkin( skin )
|
||||
|
||||
if ( breakable ) then prop_door_rotating:Fire( "SetBreakable" ) end
|
||||
|
||||
numpad.OnDown( ply, keyOpen, "prop_door_open", prop_door_rotating )
|
||||
numpad.OnDown( ply, keyClose, "prop_door_close", prop_door_rotating )
|
||||
numpad.OnDown( ply, keyLock, "prop_door_lock", prop_door_rotating )
|
||||
numpad.OnDown( ply, keyUnlock, "prop_door_unlock", prop_door_rotating )
|
||||
|
||||
table.Merge( prop_door_rotating:GetTable(), {
|
||||
ply = ply,
|
||||
keyOpen = keyOpen,
|
||||
keyClose = keyClose,
|
||||
keyLock = keyLock,
|
||||
keyUnlock = keyUnlock,
|
||||
breakable = breakable,
|
||||
MapCreationID = mapCreationID,
|
||||
|
||||
rb655_dupe_data = {
|
||||
spawnflags = spawnflags,
|
||||
ajarangles = ajarangles,
|
||||
skin = skin,
|
||||
axis = axis,
|
||||
initialAngles = ang,
|
||||
spawnpos = spawnpos,
|
||||
hardware = hardware,
|
||||
distance = distance,
|
||||
speed = speed,
|
||||
returndelay = returndelay,
|
||||
targetname = targetname,
|
||||
|
||||
--[[slavename = slavename,
|
||||
state = 0,
|
||||
opendir = opendir,
|
||||
forceclosed = forceclosed,
|
||||
|
||||
soundopenoverride = soundopenoverride,
|
||||
soundcloseoverride = soundcloseoverride,
|
||||
soundmoveoverride = soundmoveoverride,
|
||||
soundlockedoverride = soundlockedoverride,
|
||||
soundunlockedoverride = soundunlockedoverride,]]
|
||||
|
||||
}
|
||||
} )
|
||||
|
||||
if ( IsValid( ply ) ) then
|
||||
ply:AddCount( "prop_doors", prop_door_rotating )
|
||||
ply:AddCleanup( "prop_doors", prop_door_rotating )
|
||||
end
|
||||
|
||||
DoPropSpawnedEffect( prop_door_rotating )
|
||||
|
||||
return prop_door_rotating
|
||||
|
||||
end
|
||||
duplicator.RegisterEntityClass( "prop_door_rotating", MakeDoorRotating, "model", "pos", "ang", "skin", "keyOpen", "keyClose", "keyLock", "keyUnlock", "rHardware", "rDistance", "rSpeed", "auto_close_delay", "breakable", "targetname", "rb655_dupe_data", "MapCreationID" )
|
||||
|
||||
function MakeDoorDynamic( ply, model, pos, ang, keyOpen, keyClose, keyLock, keyUnlock, auto_close_delay, skin, mapCreationID )
|
||||
|
||||
if ( IsValid( ply ) and !ply:CheckLimit( "prop_doors" ) ) then return false end
|
||||
|
||||
local prop_door_dynamic = ents.Create( "prop_door_dynamic" )
|
||||
if ( !IsValid( prop_door_dynamic ) ) then return false end
|
||||
|
||||
prop_door_dynamic:SetModel( model )
|
||||
prop_door_dynamic:SetPos( pos )
|
||||
prop_door_dynamic:SetAngles( ang )
|
||||
|
||||
ApplyWireModSupport( prop_door_dynamic, mapCreationID )
|
||||
|
||||
prop_door_dynamic:Spawn()
|
||||
prop_door_dynamic:Activate()
|
||||
|
||||
prop_door_dynamic:SetSkin( skin or 0 )
|
||||
prop_door_dynamic:SetCloseDelay( auto_close_delay )
|
||||
|
||||
numpad.OnDown( ply, keyOpen, "prop_door_open", prop_door_dynamic )
|
||||
numpad.OnDown( ply, keyClose, "prop_door_close", prop_door_dynamic )
|
||||
numpad.OnDown( ply, keyLock, "prop_door_lock", prop_door_dynamic )
|
||||
numpad.OnDown( ply, keyUnlock, "prop_door_unlock", prop_door_dynamic )
|
||||
|
||||
table.Merge( prop_door_dynamic:GetTable(), {
|
||||
ply = ply,
|
||||
keyOpen = keyOpen,
|
||||
keyClose = keyClose,
|
||||
keyLock = keyLock,
|
||||
keyUnlock = keyUnlock,
|
||||
auto_close_delay = auto_close_delay,
|
||||
skin = skin,
|
||||
MapCreationID = mapCreationID
|
||||
} )
|
||||
|
||||
if ( IsValid( ply ) ) then
|
||||
ply:AddCount( "prop_doors", prop_door_dynamic )
|
||||
ply:AddCleanup( "prop_doors", prop_door_dynamic )
|
||||
end
|
||||
|
||||
DoPropSpawnedEffect( prop_door_dynamic )
|
||||
|
||||
return prop_door_dynamic
|
||||
|
||||
end
|
||||
duplicator.RegisterEntityClass( "prop_door_dynamic", MakeDoorDynamic, "model", "pos", "ang", "keyOpen", "keyClose", "keyLock", "keyUnlock", "auto_close_delay", "skin", "MapCreationID" )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
|
||||
if ( trace.HitSky or !trace.HitPos ) then return false end
|
||||
if ( IsValid( trace.Entity ) ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
|
||||
local ang = Angle( 0, ply:GetAngles().y, 0 )
|
||||
|
||||
local auto_close_delay = self:GetClientNumber( "auto_close_delay" )
|
||||
if ( self:GetClientNumber( "auto_close" ) <= 0 ) then auto_close_delay = -1 end
|
||||
|
||||
local mdl = self:GetClientInfo( "model" )
|
||||
local kO = self:GetClientNumber( "key_open" )
|
||||
local kC = self:GetClientNumber( "key_close" )
|
||||
local kL = self:GetClientNumber( "key_lock" )
|
||||
local kU = self:GetClientNumber( "key_unlock" )
|
||||
|
||||
local doorSkin = self:GetClientNumber( "skin" ) - 1
|
||||
|
||||
local rH = math.Clamp( self:GetClientNumber( "r_hardware" ), 1, 3 )
|
||||
local rD = self:GetClientNumber( "r_distance" )
|
||||
local rS = self:GetClientNumber( "r_speed" )
|
||||
local breakable = self:GetClientNumber( "breakable", 0 ) > 0
|
||||
|
||||
local prop_door
|
||||
local prop_door2
|
||||
if ( self:GetClientNumber( "type" ) == 0 ) then
|
||||
local pos, angD = self:FixDynamicPos( mdl, trace.HitPos, ang )
|
||||
|
||||
prop_door = MakeDoorDynamic( ply, mdl, pos, angD, kO, kC, kL, kU, auto_close_delay, doorSkin )
|
||||
else
|
||||
prop_door = MakeDoorRotating( ply, mdl, trace.HitPos, ang, doorSkin, kO, kC, kL, kU, rH, rD, rS, auto_close_delay, breakable )
|
||||
self:FixRotatingPos( prop_door )
|
||||
|
||||
if ( self:GetClientNumber( "r_double" ) == 1 ) then
|
||||
local ang2 = Angle( ang ) -- Make a copy
|
||||
ang2:RotateAroundAxis( Vector( 0, 0, 1 ), 180 )
|
||||
|
||||
local name = "rb655_door_" .. gDoorUniqueID
|
||||
gDoorUniqueID = gDoorUniqueID + 1
|
||||
|
||||
prop_door2 = MakeDoorRotating( ply, mdl, trace.HitPos, ang2, doorSkin, kO, kC, kL, kU, rH, rD, rS, auto_close_delay, breakable, name )
|
||||
prop_door:SetKeyValue( "targetname", name )
|
||||
prop_door.rb655_dupe_data.targetname = name
|
||||
|
||||
self:FixRotatingPos( prop_door2 )
|
||||
end
|
||||
end
|
||||
|
||||
undo.Create( "prop_door" )
|
||||
undo.AddEntity( prop_door )
|
||||
undo.AddEntity( prop_door2 )
|
||||
undo.SetPlayer( ply )
|
||||
undo.Finish()
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function TOOL:UpdateGhostEntity( ent, ply )
|
||||
|
||||
if ( !IsValid( ent ) or !IsValid( ply ) ) then return end
|
||||
|
||||
local trace = ply:GetEyeTrace()
|
||||
|
||||
if ( IsValid( trace.Entity ) or !trace.Hit ) then ent:SetNoDraw( true ) return end
|
||||
|
||||
ent:SetPos( trace.HitPos )
|
||||
ent:SetAngles( Angle( 0, ply:GetAngles().y, 0 ) )
|
||||
ent:SetSkin( self:GetClientNumber( "skin" ) - 1 )
|
||||
|
||||
ent:SetBodygroup( 1, self:GetClientNumber( "r_hardware" ) )
|
||||
|
||||
if ( self:GetClientNumber( "type" ) == 0 ) then
|
||||
local pos, angD = self:FixDynamicPos( ent:GetModel(), ent:GetPos(), ent:GetAngles(), ent:OBBMins().z )
|
||||
|
||||
ent:SetPos( pos )
|
||||
ent:SetAngles( angD )
|
||||
else
|
||||
self:FixRotatingPos( ent )
|
||||
end
|
||||
|
||||
ent:SetNoDraw( false )
|
||||
|
||||
end
|
||||
|
||||
function TOOL:MakeGhostEntity( model, pos, angle )
|
||||
util.PrecacheModel( model )
|
||||
|
||||
if ( SERVER and !game.SinglePlayer() ) then return end -- We do ghosting serverside in single player
|
||||
if ( CLIENT and game.SinglePlayer() ) then return end -- It's done clientside in multiplayer
|
||||
|
||||
self:ReleaseGhostEntity() -- Release the old ghost entity
|
||||
|
||||
--if ( !util.IsValidProp( model ) ) then return end -- Don't allow ragdolls/effects to be ghosts
|
||||
|
||||
if ( CLIENT ) then self.GhostEntity = ents.CreateClientProp( model )
|
||||
else self.GhostEntity = ents.Create( "prop_dynamic" ) end
|
||||
|
||||
if ( !IsValid( self.GhostEntity ) ) then self.GhostEntity = nil return end -- If there's too many entities we might not spawn..
|
||||
|
||||
self.GhostEntity:SetModel( model )
|
||||
self.GhostEntity:SetPos( pos )
|
||||
self.GhostEntity:SetAngles( angle )
|
||||
self.GhostEntity:Spawn()
|
||||
|
||||
self.GhostEntity:SetSolid( SOLID_VPHYSICS )
|
||||
self.GhostEntity:SetMoveType( MOVETYPE_NONE )
|
||||
self.GhostEntity:SetNotSolid( true )
|
||||
self.GhostEntity:SetRenderMode( RENDERMODE_TRANSALPHA )
|
||||
self.GhostEntity:SetColor( Color( 255, 255, 255, 150 ) )
|
||||
end
|
||||
|
||||
local OldMDL = GetConVarString( "prop_door_model" )
|
||||
function TOOL:Think()
|
||||
if ( CLIENT and OldMDL != GetConVarString( "prop_door_model" ) ) then
|
||||
OldMDL = GetConVarString( "prop_door_model" )
|
||||
if ( LocalPlayer():GetTool() and LocalPlayer():GetTool( "prop_door" ) ) then LocalPlayer():GetTool():UpdateControlPanel() end
|
||||
end
|
||||
|
||||
if ( !IsValid( self.GhostEntity ) or self.GhostEntity:GetModel() != self:GetClientInfo( "model" ) ) then
|
||||
self:MakeGhostEntity( self:GetClientInfo( "model" ), Vector( 0, 0, 0 ), Angle( 0, 0, 0 ) )
|
||||
end
|
||||
self:UpdateGhostEntity( self.GhostEntity, self:GetOwner() )
|
||||
end
|
||||
|
||||
--[[
|
||||
Types
|
||||
0 - Dynamic door
|
||||
1 - Normal door
|
||||
2 - Normal slim door
|
||||
3 - Normal door but with a 3rd option for door handle
|
||||
]]
|
||||
|
||||
list.Set( "DoorModels", "models/props_c17/door01_left.mdl", { prop_door_type = 1 } )
|
||||
list.Set( "DoorModels", "models/props_c17/door02_double.mdl", { prop_door_type = 2 } )
|
||||
list.Set( "DoorModels", "models/props_doors/door03_slotted_left.mdl", { prop_door_type = 1 } )
|
||||
|
||||
list.Set( "DoorModels", "models/props_combine/combine_door01.mdl", { prop_door_type = 0 } )
|
||||
list.Set( "DoorModels", "models/combine_gate_vehicle.mdl", { prop_door_type = 0 } )
|
||||
list.Set( "DoorModels", "models/combine_gate_citizen.mdl", { prop_door_type = 0 } )
|
||||
|
||||
list.Set( "DoorModels", "models/props_lab/elevatordoor.mdl", { prop_door_type = 0 } )
|
||||
list.Set( "DoorModels", "models/props_doors/doorklab01.mdl", { prop_door_type = 0 } )
|
||||
|
||||
if ( IsMounted( "episodic" ) ) then list.Set( "DoorModels", "models/props_c17/door03_left.mdl", { prop_door_type = 3 } ) end
|
||||
if ( IsMounted( "zps" ) ) then list.Set( "DoorModels", "models/props_corpsington/doors/swingdoor01.mdl", { prop_door_type = 1 } ) end
|
||||
--if ( IsMounted( "portal" ) ) then list.Set( "DoorModels", "models/props/round_elevator_doors.mdl", { prop_door_type = 0 } ) end -- Fucked up angles & collisions
|
||||
|
||||
if ( IsMounted( "portal2" ) ) then
|
||||
list.Set( "DoorModels", "models/props/portal_door_combined.mdl", { prop_door_type = 0 } )
|
||||
end
|
||||
|
||||
if ( IsMounted( "left4dead2" ) or IsMounted( "left4dead" ) ) then
|
||||
list.Set( "DoorModels", "models/props_doors/doormainmetal01.mdl", { prop_door_type = 7 } )
|
||||
list.Set( "DoorModels", "models/props_doors/doormainmetalsmall01.mdl", { prop_door_type = 1 } )
|
||||
|
||||
list.Set( "DoorModels", "models/props_doors/doorfreezer01.mdl", { prop_door_type = 6 } )
|
||||
|
||||
list.Set( "DoorModels", "models/props_doors/doormainmetalwindow01.mdl", { prop_door_type = 10 } )
|
||||
list.Set( "DoorModels", "models/props_doors/doormainmetalwindowsmall01.mdl", { prop_door_type = 1 } )
|
||||
|
||||
list.Set( "DoorModels", "models/props_doors/doormain01.mdl", { prop_door_type = 1 } )
|
||||
list.Set( "DoorModels", "models/props_doors/doormain01_airport.mdl", { prop_door_type = 7 } )
|
||||
list.Set( "DoorModels", "models/props_doors/doormain01_airport_small.mdl", { prop_door_type = 8 } )
|
||||
list.Set( "DoorModels", "models/props_doors/doormain01_small.mdl", { prop_door_type = 9 } )
|
||||
end
|
||||
|
||||
if ( IsMounted( "left4dead2" ) ) then
|
||||
list.Set( "DoorModels", "models/props_downtown/door_interior_128_01.mdl", { prop_door_type = 1 } )
|
||||
list.Set( "DoorModels", "models/props_downtown/metal_door_112.mdl", { prop_door_type = 1 } )
|
||||
list.Set( "DoorModels", "models/props_doors/door_rotate_112.mdl", { prop_door_type = 1 } )
|
||||
list.Set( "DoorModels", "models/props_doors/door_sliding_112.mdl", { prop_door_type = 1 } )
|
||||
|
||||
-- Escape doors
|
||||
list.Set( "DoorModels", "models/props_doors/checkpoint_door_-01.mdl", { prop_door_type = 4 } )
|
||||
list.Set( "DoorModels", "models/props_doors/checkpoint_door_-02.mdl", { prop_door_type = 5 } )
|
||||
list.Set( "DoorModels", "models/props_doors/checkpoint_door_01.mdl", { prop_door_type = 6 } )
|
||||
list.Set( "DoorModels", "models/props_doors/checkpoint_door_02.mdl", { prop_door_type = 5 } )
|
||||
|
||||
-- Wood
|
||||
list.Set( "DoorModels", "models/props_doors/doormain_rural01.mdl", { prop_door_type = 9 } )
|
||||
list.Set( "DoorModels", "models/props_doors/doormain_rural01_small.mdl", { prop_door_type = 9 } )
|
||||
end
|
||||
|
||||
if ( IsMounted( "left4dead2" ) or IsMounted( "csgo" ) ) then
|
||||
list.Set( "DoorModels", "models/props_downtown/door_interior_112_01.mdl", { prop_door_type = 1 } )
|
||||
list.Set( "DoorModels", "models/props_downtown/metal_door_112.mdl", { prop_door_type = 1 } )
|
||||
end
|
||||
if ( IsMounted( "left4dead2" ) or IsMounted( "left4dead" ) or IsMounted( "csgo" ) ) then
|
||||
list.Set( "DoorModels", "models/props_doors/doorglassmain01.mdl", { prop_door_type = 10 } )
|
||||
list.Set( "DoorModels", "models/props_doors/doorglassmain01_small.mdl", { prop_door_type = 10 } )
|
||||
end
|
||||
|
||||
if ( IsMounted( "ep2" ) ) then
|
||||
list.Set( "DoorModels", "models/props_mining/elevator01_cagedoor.mdl", { prop_door_type = 0 } )
|
||||
list.Set( "DoorModels", "models/props_mining/techgate01.mdl", { prop_door_type = 0 } )
|
||||
-- list.Set( "DoorModels", "models/props_mining/techgate01_outland03.mdl", { prop_door_type = 0 } )
|
||||
-- list.Set( "DoorModels", "models/props_silo/silo_elevator_door.mdl", { prop_door_type = 0 } ) -- No collisions
|
||||
end
|
||||
|
||||
if ( SERVER ) then return end
|
||||
|
||||
TOOL.Information = { { name = "left" } }
|
||||
|
||||
language.Add( "tool.prop_door", "Doors" )
|
||||
language.Add( "tool.prop_door.name", "Door Tool" )
|
||||
language.Add( "tool.prop_door.desc", "Spawn a variety of doors" )
|
||||
language.Add( "tool.prop_door.left", "Spawn a door" )
|
||||
|
||||
language.Add( "tool.prop_door.model", "Door Model:" )
|
||||
language.Add( "tool.prop_door.key_open", "Open door" )
|
||||
language.Add( "tool.prop_door.key_close", "Close door" )
|
||||
language.Add( "tool.prop_door.key_lock", "Lock door" )
|
||||
language.Add( "tool.prop_door.key_unlock", "Unlock door" )
|
||||
language.Add( "tool.prop_door.auto_close", "Auto close" )
|
||||
language.Add( "tool.prop_door.auto_close_delay", "Auto close delay:" )
|
||||
language.Add( "tool.prop_door.skin", "Door skin:" )
|
||||
|
||||
language.Add( "tool.prop_door.specific", "Door specific options" )
|
||||
|
||||
language.Add( "tool.prop_door.r_double", "Make double doors" )
|
||||
language.Add( "tool.prop_door.breakable", "Make breakable (if model supports it)" )
|
||||
language.Add( "tool.prop_door.r_hardware", "Hardware Type" )
|
||||
language.Add( "tool.prop_door.r_distance", "Rotation distance:" )
|
||||
language.Add( "tool.prop_door.r_speed", "Open speed:" )
|
||||
|
||||
language.Add( "tool.prop_door.lever", "Lever" )
|
||||
language.Add( "tool.prop_door.pushbar", "Push Bar" )
|
||||
language.Add( "tool.prop_door.keypad", "Lever with Keypad" )
|
||||
|
||||
language.Add( "Cleanup_prop_doors", "Doors" )
|
||||
language.Add( "Cleaned_prop_doors", "Cleaned up all Doors" )
|
||||
language.Add( "SBoxLimit_prop_doors", "You've hit the Door limit!" )
|
||||
language.Add( "Undone_prop_door", "Door undone" )
|
||||
|
||||
language.Add( "max_prop_doors", "Max Doors:" )
|
||||
|
||||
function TOOL:UpdateControlPanel( index )
|
||||
local panel = controlpanel.Get( "prop_door" )
|
||||
if ( !panel ) then Msg( "Couldn't find prop_door panel!" ) return end
|
||||
|
||||
panel:ClearControls()
|
||||
self.BuildCPanel( panel )
|
||||
end
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( panel )
|
||||
panel:AddControl( "ComboBox", { MenuButton = 1, Folder = "prop_door", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
panel:AddControl( "PropSelect", { Label = "#tool.prop_door.model", Height = 3, ConVar = "prop_door_model", Models = list.Get( "DoorModels" ) } )
|
||||
panel:AddControl( "Numpad", { Label = "#tool.prop_door.key_open", Label2 = "#tool.prop_door.key_close", Command = "prop_door_key_open", Command2 = "prop_door_key_close" } )
|
||||
panel:AddControl( "Numpad", { Label = "#tool.prop_door.key_lock", Label2 = "#tool.prop_door.key_unlock", Command = "prop_door_key_lock", Command2 = "prop_door_key_unlock" } )
|
||||
|
||||
panel:AddControl( "Checkbox", { Label = "#tool.prop_door.auto_close", Command = "prop_door_auto_close" } )
|
||||
panel:AddControl( "Slider", { Label = "#tool.prop_door.auto_close_delay", Type = "Float", Min = 0, Max = 32, Command = "prop_door_auto_close_delay" } )
|
||||
|
||||
local typ = GetConVarNumber( "prop_door_type" )
|
||||
local numSkins = NumModelSkins( GetConVarString( "prop_door_model" ) )
|
||||
|
||||
if ( typ == 0 and numSkins <= 1 ) then return end
|
||||
|
||||
panel:Help( "#tool.prop_door.specific" )
|
||||
|
||||
if ( numSkins > 1 ) then
|
||||
panel:AddControl( "Slider", { Label = "#tool.prop_door.skin", Min = 1, Max = numSkins, Command = "prop_door_skin" } )
|
||||
end
|
||||
|
||||
if ( typ == 0 ) then return end
|
||||
|
||||
panel:AddControl( "Checkbox", { Label = "#tool.prop_door.r_double", Command = "prop_door_r_double" } )
|
||||
|
||||
panel:AddControl( "Checkbox", { Label = "#tool.prop_door.breakable", Command = "prop_door_breakable" } )
|
||||
|
||||
local r_hard = GetConVarNumber( "prop_door_r_hardware" )
|
||||
if ( ( typ != 3 and r_hard == 3 ) or ( typ == 2 and r_hard != 1 ) ) then LocalPlayer():ConCommand( "prop_door_r_hardware 1" ) end
|
||||
|
||||
local r_hardware = {
|
||||
["#tool.prop_door.lever"] = { prop_door_r_hardware = "1" },
|
||||
["#tool.prop_door.pushbar"] = { prop_door_r_hardware = "2" }
|
||||
}
|
||||
|
||||
if ( typ == 3 ) then r_hardware["#tool.prop_door.keypad"] = { prop_door_r_hardware = "3" } end
|
||||
|
||||
if ( typ != 2 ) then
|
||||
panel:AddControl( "ListBox", { Label = "#tool.prop_door.r_hardware", Height = 68, Options = r_hardware } )
|
||||
end
|
||||
|
||||
panel:AddControl( "Slider", { Label = "#tool.prop_door.r_distance", Type = "Float", Min = 72, Max = 128, Command = "prop_door_r_distance" } )
|
||||
panel:AddControl( "Slider", { Label = "#tool.prop_door.r_speed", Type = "Float", Min = 48, Max = 256, Command = "prop_door_r_speed" } )
|
||||
end
|
||||
241
lua/weapons/gmod_tool/stools/prop_npc_crate.lua
Normal file
241
lua/weapons/gmod_tool/stools/prop_npc_crate.lua
Normal file
@@ -0,0 +1,241 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
// STool by Nekres ( 4ndy )
|
||||
TOOL.Category = "Half-Life 2"
|
||||
TOOL.Name = "#tool.prop_npc_crate"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
TOOL.Models = {}
|
||||
TOOL.Models["models/props_junk/wood_crate001a.mdl"] = 0
|
||||
TOOL.Models["models/props_junk/wood_crate001a_damaged.mdl"] = 1
|
||||
TOOL.Models["models/props_junk/wood_crate002a.mdl"] = 2
|
||||
TOOL.Models["models/items/item_item_crate.mdl"] = 3
|
||||
TOOL.Models["models/items/item_beacon_crate.mdl"] = 4
|
||||
TOOL.Models["models/props_junk/cardboard_box001a.mdl"] = 5
|
||||
TOOL.Models["models/props_junk/cardboard_box001b.mdl"] = 6
|
||||
TOOL.Models["models/props_junk/cardboard_box002a.mdl"] = 7
|
||||
TOOL.Models["models/props_junk/cardboard_box002b.mdl"] = 8
|
||||
TOOL.Models["models/props_junk/cardboard_box003a.mdl"] = 9
|
||||
TOOL.Models["models/props_junk/cardboard_box003b.mdl"] = 10
|
||||
TOOL.Models["models/props_junk/cardboard_box004a.mdl"] = 11
|
||||
|
||||
TOOL.ClientConVar["model"] = "models/props_junk/wood_crate001a.mdl"
|
||||
TOOL.ClientConVar["npc"] = "npc_headcrab_poison"
|
||||
TOOL.ClientConVar["health"] = "25"
|
||||
|
||||
cleanup.Register("prop_npc_crate")
|
||||
|
||||
if (CLIENT) then
|
||||
language.Add("tool.prop_npc_crate", "NPC Crate")
|
||||
language.Add("tool.prop_npc_crate.name", "NPC Crate Tool")
|
||||
language.Add("tool.prop_npc_crate.desc", "Spawn crates with an NPC in them")
|
||||
language.Add("tool.prop_npc_crate.0", "Left click to spawn an custom adjusted NPC Crate. Right to pack an existing NPC in a custom crate.")
|
||||
|
||||
language.Add("tool.prop_npc_crate.model", "Crate Model")
|
||||
language.Add("tool.prop_npc_crate.npc", "Crate NPC")
|
||||
language.Add("tool.prop_npc_crate.health", "Crate Health")
|
||||
language.Add("tool.prop_npc_crate.health.help", "Amount of damage the npc crate can take before it will break.")
|
||||
|
||||
language.Add("Cleanup_prop_npc_crate", "NPC Crates")
|
||||
language.Add("Cleaned_prop_npc_crate", "Cleaned up all NPC Crates")
|
||||
language.Add("SBoxLimit_prop_npc_crate", "You've hit the NPC Crates limit!")
|
||||
language.Add("Undone_prop_npc_crate", "NPC Crate undone")
|
||||
|
||||
language.Add("prop_npc_crate", "NPC Crate")
|
||||
|
||||
language.Add("#combine_mine", "Combine Mine")
|
||||
language.Add("combine_mine", "Combine Mine")
|
||||
language.Add("#npc_fastzombie_torso", "Fast Zombie Torso")
|
||||
language.Add("#grenade_helicopter", "Helicopter Grenade")
|
||||
language.Add("grenade_helicopter", "Helicopter Grenade")
|
||||
end
|
||||
|
||||
if (SERVER) then
|
||||
CreateConVar("sbox_maxprop_npc_crates", 10)
|
||||
|
||||
function MakeNpcCrate(ply, pos, ang, model, health, npc, npcTbl)
|
||||
if (!ply:CheckLimit("prop_npc_crates")) then return false end
|
||||
|
||||
local prop_npc_crate = ents.Create("prop_npc_crate")
|
||||
if (!prop_npc_crate:IsValid()) then return false end
|
||||
|
||||
prop_npc_crate:Initialize(model, math.Clamp(health, 1, 100), npc)
|
||||
|
||||
prop_npc_crate:SetPos(Vector(pos.x, pos.y, pos.z - prop_npc_crate:OBBMins().z))
|
||||
prop_npc_crate:SetAngles(ang)
|
||||
|
||||
prop_npc_crate:Spawn()
|
||||
prop_npc_crate:Activate()
|
||||
|
||||
table.Merge(prop_npc_crate:GetTable(), {
|
||||
ply = ply,
|
||||
model = model,
|
||||
health = health,
|
||||
npc = npc,
|
||||
npcTbl = npcTbl,
|
||||
})
|
||||
|
||||
ply:AddCount("prop_npc_crates", prop_npc_crate)
|
||||
|
||||
DoPropSpawnedEffect(prop_npc_crate)
|
||||
|
||||
return prop_npc_crate
|
||||
end
|
||||
|
||||
duplicator.RegisterEntityClass("prop_npc_crate", MakeNpcCrate, "pos", "ang", "model", "health", "npc", "npcTbl")
|
||||
end
|
||||
|
||||
function TOOL:LeftClick(trace)
|
||||
if (trace.HitSky or !trace.HitPos or IsValid(trace.Entity) and (trace.Entity:IsPlayer() or trace.Entity:IsNPC())) then return false end
|
||||
if (CLIENT) then return true end
|
||||
|
||||
local Tbl = { }
|
||||
Tbl["wep"] = ""
|
||||
Tbl["citType"] = ""
|
||||
Tbl["citMed"] = 0
|
||||
Tbl["skin"] = nil
|
||||
Tbl["model"] = nil
|
||||
|
||||
local ply = self:GetOwner()
|
||||
|
||||
// Update existing NPC Crate
|
||||
if (trace.Entity:GetClass() == "prop_npc_crate") then
|
||||
trace.Entity:Initialize(self:GetClientInfo("model"), self:GetClientNumber("health"), self:GetClientInfo("npc"))
|
||||
table.Merge(trace.Entity:GetTable(), {
|
||||
ply = ply,
|
||||
model = self:GetClientInfo("model"),
|
||||
health = self:GetClientNumber("health"),
|
||||
npc = self:GetClientInfo("npc"),
|
||||
npcTbl = Tbl,
|
||||
})
|
||||
return true
|
||||
end
|
||||
|
||||
// Create a new NPC Crate
|
||||
local ang = trace.HitNormal:Angle()
|
||||
ang.pitch = ang.pitch - 270
|
||||
|
||||
local prop_npc_crate = MakeNpcCrate(ply, trace.HitPos, ang, self:GetClientInfo("model"), self:GetClientNumber("health"), self:GetClientInfo("npc"), Tbl)
|
||||
|
||||
undo.Create("prop_npc_crate")
|
||||
undo.AddEntity(prop_npc_crate)
|
||||
undo.SetPlayer(ply)
|
||||
undo.Finish()
|
||||
|
||||
ply:AddCleanup("prop_npc_crate", prop_npc_crate)
|
||||
|
||||
return true
|
||||
end
|
||||
function TOOL:RightClick(trace)
|
||||
if (trace.HitSky or !trace.HitPos or IsValid(trace.Entity) and (trace.Entity:IsPlayer())) then return false end
|
||||
if (!trace.Entity:IsNPC()) then return false end
|
||||
if (CLIENT) then return true end
|
||||
|
||||
local npc = trace.Entity
|
||||
local ply = self:GetOwner()
|
||||
local ang = trace.HitNormal:Angle()
|
||||
|
||||
local npcTbl = {}
|
||||
|
||||
local wep = ""
|
||||
local possibleWep = ents.FindInSphere(npc:GetPos(),0.01)
|
||||
for k, v in pairs(possibleWep) do
|
||||
if string.find(v:GetClass(),"weapon_") == 1 then
|
||||
wep = v:GetClass()
|
||||
end
|
||||
end
|
||||
local citType = ""
|
||||
local citMed = 0
|
||||
if (npc:GetClass() == "npc_citizen") then
|
||||
citType = string.sub(npc:GetModel(),21,21)
|
||||
if (string.sub(npc:GetModel(),22,22) == "m") then citMed = 1 end
|
||||
end
|
||||
|
||||
npcTbl["wep"] = wep
|
||||
npcTbl["citType"] = citType
|
||||
npcTbl["citMed"] = citMed
|
||||
npcTbl["skin"] = npc:GetSkin()
|
||||
npcTbl["model"] = npc:GetModel()
|
||||
|
||||
local prop_npc_crate = MakeNpcCrate(ply, npc:GetPos(), Angle(0, ang.y, 0), self:GetClientInfo("model"), self:GetClientNumber("health"), npc:GetClass(), npcTbl)
|
||||
npc:Remove()
|
||||
|
||||
undo.Create("prop_npc_crate")
|
||||
undo.AddEntity(prop_npc_crate)
|
||||
undo.SetPlayer(ply)
|
||||
undo.Finish()
|
||||
|
||||
ply:AddCleanup("prop_npc_crate", prop_npc_crate)
|
||||
return true
|
||||
end
|
||||
function TOOL:UpdateGhostNpcCrate(ent,player)
|
||||
if (!ent or !ent:IsValid()) then return end
|
||||
|
||||
local tr = util.GetPlayerTrace(player, player:GetAimVector())
|
||||
local trace = util.TraceLine(tr)
|
||||
|
||||
if (!trace.Hit) then return end
|
||||
|
||||
if (trace.Entity && (trace.Entity:GetClass() == "prop_npc_crate" || trace.Entity:IsPlayer()) || trace.Entity:IsNPC()) then
|
||||
ent:SetNoDraw(true)
|
||||
return
|
||||
end
|
||||
|
||||
local Ang = trace.HitNormal:Angle()
|
||||
Ang.pitch = Ang.pitch - 270
|
||||
|
||||
local min = ent:OBBMins()
|
||||
ent:SetPos(trace.HitPos - trace.HitNormal * min.z)
|
||||
|
||||
ent:SetAngles(Ang)
|
||||
ent:SetNoDraw(false)
|
||||
end
|
||||
|
||||
function TOOL:Think()
|
||||
if (!self.GhostEntity || !self.GhostEntity:IsValid() || self.GhostEntity:GetModel() != self:GetClientInfo("model")) then
|
||||
self:MakeGhostEntity(self:GetClientInfo("model"), Vector(0, 0, 0), Angle(0, 0, 0))
|
||||
end
|
||||
|
||||
self:UpdateGhostNpcCrate(self.GhostEntity, self:GetOwner())
|
||||
end
|
||||
function TOOL.BuildCPanel(panel)
|
||||
panel:AddControl("PropSelect", {Label = "#tool.prop_npc_crate.model", Height = 3, ConVar = "prop_npc_crate_model", Models = list.Get("NpcCrateModels")})
|
||||
panel:AddControl("ListBox", {Label = "#tool.prop_npc_crate.npc", Height = 237, Options = list.Get("NpcCrateNpcs")})
|
||||
panel:AddControl("Slider", {Label = "#tool.prop_npc_crate.health", Type = "Integer", Min = 1, Max = 100, Command = "prop_npc_crate_health", Help = true})
|
||||
end
|
||||
|
||||
list.Set("NpcCrateModels", "models/props_junk/wood_crate001a.mdl", {})
|
||||
list.Set("NpcCrateModels", "models/props_junk/wood_crate001a_damaged.mdl", {})
|
||||
list.Set("NpcCrateModels", "models/props_junk/wood_crate002a.mdl", {})
|
||||
list.Set("NpcCrateModels", "models/items/item_item_crate.mdl", {})
|
||||
list.Set("NpcCrateModels", "models/items/item_beacon_crate.mdl", {})
|
||||
list.Set("NpcCrateModels", "models/props_junk/cardboard_box001a.mdl", {})
|
||||
list.Set("NpcCrateModels", "models/props_junk/cardboard_box001b.mdl", {})
|
||||
list.Set("NpcCrateModels", "models/props_junk/cardboard_box002a.mdl", {})
|
||||
list.Set("NpcCrateModels", "models/props_junk/cardboard_box002b.mdl", {})
|
||||
list.Set("NpcCrateModels", "models/props_junk/cardboard_box003a.mdl", {})
|
||||
list.Set("NpcCrateModels", "models/props_junk/cardboard_box003b.mdl", {})
|
||||
list.Set("NpcCrateModels", "models/props_junk/cardboard_box004a.mdl", {})
|
||||
|
||||
list.Set("NpcCrateNpcs", "#npc_headcrab", {prop_npc_crate_npc = "npc_headcrab"})
|
||||
list.Set("NpcCrateNpcs", "#npc_headcrab_fast", {prop_npc_crate_npc = "npc_headcrab_fast"})
|
||||
list.Set("NpcCrateNpcs", "#npc_headcrab_poison", {prop_npc_crate_npc = "npc_headcrab_black"})
|
||||
list.Set("NpcCrateNpcs", "#npc_zombie", {prop_npc_crate_npc = "npc_zombie"})
|
||||
list.Set("NpcCrateNpcs", "#npc_zombie_torso", {prop_npc_crate_npc = "npc_zombie_torso"})
|
||||
list.Set("NpcCrateNpcs", "#npc_fastzombie", {prop_npc_crate_npc = "npc_fastzombie"})
|
||||
list.Set("NpcCrateNpcs", "#npc_fastzombie_torso", {prop_npc_crate_npc = "npc_fastzombie_torso"})
|
||||
list.Set("NpcCrateNpcs", "#npc_poisonzombie", {prop_npc_crate_npc = "npc_poisonzombie"})
|
||||
list.Set("NpcCrateNpcs", "#npc_manhack", {prop_npc_crate_npc = "npc_manhack"})
|
||||
list.Set("NpcCrateNpcs", "#npc_crow", {prop_npc_crate_npc = "npc_crow"})
|
||||
list.Set("NpcCrateNpcs", "#combine_mine", {prop_npc_crate_npc = "combine_mine"})
|
||||
list.Set("NpcCrateNpcs", "#npc_rollermine", {prop_npc_crate_npc = "npc_rollermine"})
|
||||
list.Set("NpcCrateNpcs", "#grenade_helicopter", {prop_npc_crate_npc = "grenade_helicopter"})
|
||||
196
lua/weapons/gmod_tool/stools/prop_thumper.lua
Normal file
196
lua/weapons/gmod_tool/stools/prop_thumper.lua
Normal file
@@ -0,0 +1,196 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Half-Life 2"
|
||||
TOOL.Name = "#tool.prop_thumper"
|
||||
|
||||
TOOL.ClientConVar["model" ] = "models/props_combine/CombineThumper002.mdl"
|
||||
TOOL.ClientConVar[ "dustscale" ] = "128"
|
||||
TOOL.ClientConVar[ "activate" ] = "38"
|
||||
TOOL.ClientConVar[ "deactivate" ] = "39"
|
||||
|
||||
cleanup.Register( "prop_thumpers" )
|
||||
|
||||
if ( SERVER ) then
|
||||
CreateConVar( "sbox_maxprop_thumpers", 10, FCVAR_ARCHIVE + FCVAR_REPLICATED + FCVAR_NOTIFY )
|
||||
|
||||
numpad.Register( "prop_thumper_on", function( ply, prop_thumper )
|
||||
if ( !IsValid( prop_thumper ) ) then return false end
|
||||
prop_thumper:Fire( "Enable" )
|
||||
end )
|
||||
|
||||
numpad.Register( "prop_thumper_off", function( ply, prop_thumper )
|
||||
if ( !IsValid( prop_thumper ) ) then return false end
|
||||
prop_thumper:Fire( "Disable" )
|
||||
end )
|
||||
|
||||
function MakeThumper( ply, model, pos, ang, keyOn, keyOff, dustscale, targetname, mapCreationID )
|
||||
if ( IsValid( ply ) and !ply:CheckLimit( "prop_thumpers" ) ) then return nil end
|
||||
|
||||
local prop_thumper = ents.Create( "prop_thumper" )
|
||||
if ( !IsValid( prop_thumper ) ) then return false end
|
||||
|
||||
prop_thumper:SetPos( pos )
|
||||
prop_thumper:SetAngles( ang )
|
||||
|
||||
keyOn = keyOn or -1
|
||||
keyOff = keyOff or -1
|
||||
dustscale = tonumber( dustscale ) or 128
|
||||
|
||||
if ( model == "models/props_combine/combinethumper001a.mdl" ) then
|
||||
local vec1 = Vector( -64, 72, 256 )
|
||||
vec1:Rotate( ang )
|
||||
local Lpos = pos + vec1
|
||||
|
||||
local ladder = ents.Create("func_useableladder")
|
||||
ladder:SetPos( Lpos )
|
||||
ladder:SetAngles( ang )
|
||||
ladder:SetKeyValue( "targetname", "rb655_ThumperLadder_" .. prop_thumper:EntIndex() )
|
||||
ladder:SetKeyValue( "point0", Lpos.x .. " " .. Lpos.y .. " " .. Lpos.z )
|
||||
ladder:SetKeyValue( "point1", Lpos.x .. " " .. Lpos.y .. " " .. ( Lpos.z - 252 ) )
|
||||
ladder:Spawn()
|
||||
|
||||
prop_thumper:DeleteOnRemove( ladder )
|
||||
ladder:DeleteOnRemove( prop_thumper )
|
||||
end
|
||||
|
||||
if ( targetname ) then prop_thumper:SetKeyValue( "targetname", targetname ) end
|
||||
if ( dustscale ) then prop_thumper:SetKeyValue( "dustscale", math.Clamp( dustscale, 64, 1024 ) ) end
|
||||
prop_thumper:SetModel( model )
|
||||
prop_thumper:Spawn()
|
||||
prop_thumper:Activate()
|
||||
|
||||
prop_thumper.NumpadOn = numpad.OnDown( ply, keyOn, "prop_thumper_on", prop_thumper )
|
||||
prop_thumper.NumpadOff = numpad.OnDown( ply, keyOff, "prop_thumper_off", prop_thumper )
|
||||
|
||||
table.Merge( prop_thumper:GetTable(), {
|
||||
ply = ply,
|
||||
keyOn = keyOn,
|
||||
keyOff = keyOff,
|
||||
dustscale = dustscale,
|
||||
targetname = targetname,
|
||||
MapCreationID = mapCreationID
|
||||
} )
|
||||
|
||||
if ( IsValid( ply ) ) then
|
||||
ply:AddCount( "prop_thumpers", prop_thumper )
|
||||
ply:AddCleanup( "prop_thumpers", prop_thumper )
|
||||
end
|
||||
|
||||
DoPropSpawnedEffect( prop_thumper )
|
||||
|
||||
if ( Wire_CreateOutputs and !mapCreationID ) then
|
||||
prop_thumper.Inputs = Wire_CreateInputs( prop_thumper, { "Turn On" } )
|
||||
|
||||
function prop_thumper:TriggerInput( name, value )
|
||||
if ( name == "Turn On" ) then self:Fire( value != 0 and "Enable" or "Disable" ) end
|
||||
end
|
||||
|
||||
rb655_hl2_CopyWireModMethods( prop_thumper )
|
||||
end
|
||||
|
||||
return prop_thumper
|
||||
end
|
||||
|
||||
duplicator.RegisterEntityClass( "prop_thumper", MakeThumper, "model", "pos", "ang", "keyOn", "keyOff", "dustscale", "targetname", "MapCreationID" )
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
if ( trace.HitSky or !trace.HitPos or trace.HitNormal.z < 0.98 ) then return false end
|
||||
if ( IsValid( trace.Entity ) and ( trace.Entity:GetClass() == "prop_thumper" or trace.Entity:IsPlayer() or trace.Entity:IsNPC() ) ) then return false end
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
|
||||
local ang = trace.HitNormal:Angle()
|
||||
ang.pitch = ang.pitch - 270
|
||||
|
||||
if ( trace.HitNormal.z > 0.9999 ) then ang.y = ply:GetAngles().y + 90 end
|
||||
|
||||
local prop_thumper = MakeThumper( ply, self:GetClientInfo( "model" ),
|
||||
trace.HitPos, ang,
|
||||
self:GetClientNumber( "activate" ),
|
||||
self:GetClientNumber( "deactivate" ),
|
||||
self:GetClientNumber( "dustscale" ),
|
||||
self:GetClientNumber( "distance" )
|
||||
)
|
||||
|
||||
undo.Create( "prop_thumper" )
|
||||
undo.AddEntity( prop_thumper )
|
||||
undo.SetPlayer( ply )
|
||||
undo.Finish()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:UpdateGhostEntity( ent, ply )
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local trace = ply:GetEyeTrace()
|
||||
|
||||
if ( !trace.Hit or trace.HitNormal.z < 0.98 or IsValid( trace.Entity ) and ( trace.Entity:GetClass() == "prop_thumper" or trace.Entity:IsPlayer() or trace.Entity:IsNPC() ) ) then
|
||||
ent:SetNoDraw( true )
|
||||
return
|
||||
end
|
||||
|
||||
local ang = trace.HitNormal:Angle()
|
||||
ang.pitch = ang.pitch - 270
|
||||
|
||||
if ( trace.HitNormal.z > 0.9999 ) then ang.y = ply:GetAngles().y + 90 end
|
||||
|
||||
local min = ent:OBBMins()
|
||||
ent:SetPos( trace.HitPos - trace.HitNormal * min.z )
|
||||
|
||||
ent:SetAngles( ang )
|
||||
ent:SetNoDraw( false )
|
||||
end
|
||||
|
||||
function TOOL:Think()
|
||||
if ( !IsValid( self.GhostEntity ) or self.GhostEntity:GetModel() != self:GetClientInfo( "model" ) ) then
|
||||
self:MakeGhostEntity( self:GetClientInfo( "model" ), Vector( 0, 0, 0 ), Angle( 0, 0, 0 ) )
|
||||
end
|
||||
self:UpdateGhostEntity( self.GhostEntity, self:GetOwner() )
|
||||
end
|
||||
|
||||
list.Set( "ThumperModels", "models/props_combine/CombineThumper001a.mdl", {} )
|
||||
list.Set( "ThumperModels", "models/props_combine/CombineThumper002.mdl", {} )
|
||||
|
||||
if ( SERVER ) then return end
|
||||
|
||||
TOOL.Information = { { name = "left" } }
|
||||
|
||||
language.Add( "tool.prop_thumper", "Thumpers" )
|
||||
language.Add( "tool.prop_thumper.name", "Thumper Tool" )
|
||||
language.Add( "tool.prop_thumper.desc", "Spawn thumpers from Half-Life 2" )
|
||||
language.Add( "tool.prop_thumper.left", "Spawn a thumper" )
|
||||
|
||||
language.Add( "tool.prop_thumper.model", "Thumper Model:" )
|
||||
language.Add( "tool.prop_thumper.dustscale", "Thumper dust size:" )
|
||||
language.Add( "tool.prop_thumper.dustscale.help", "The scale of dust produced when thumper hits ground." )
|
||||
language.Add( "tool.prop_thumper.activate", "Activate Thumper" )
|
||||
language.Add( "tool.prop_thumper.deactivate", "Deactivate Thumper" )
|
||||
|
||||
language.Add( "Cleanup_prop_thumpers", "Thumpers" )
|
||||
language.Add( "Cleaned_prop_thumpers", "Cleaned up all Thumpers" )
|
||||
language.Add( "SBoxLimit_prop_thumpers", "You've hit the Thumper limit!" )
|
||||
language.Add( "Undone_prop_thumper", "Thumper undone" )
|
||||
|
||||
language.Add( "max_prop_thumpers", "Max Thumpers:" )
|
||||
|
||||
local ConVarsDefault = TOOL:BuildConVarList()
|
||||
|
||||
function TOOL.BuildCPanel( panel )
|
||||
panel:AddControl( "ComboBox", { MenuButton = 1, Folder = "prop_thumper", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } )
|
||||
|
||||
panel:AddControl( "PropSelect", { Label = "#tool.prop_thumper.model", Height = 1, ConVar = "prop_thumper_model", Models = list.Get( "ThumperModels" ) } )
|
||||
panel:AddControl( "Numpad", { Label = "#tool.prop_thumper.activate", Label2 = "#tool.prop_thumper.deactivate", Command = "prop_thumper_activate", Command2 = "prop_thumper_deactivate" } )
|
||||
panel:AddControl( "Slider", { Label = "#tool.prop_thumper.dustscale", Min = 64, Max = 1024, Command = "prop_thumper_dustscale", Help = true } )
|
||||
end
|
||||
480
lua/weapons/gmod_tool/stools/rb655_easy_animation.lua
Normal file
480
lua/weapons/gmod_tool/stools/rb655_easy_animation.lua
Normal file
@@ -0,0 +1,480 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Robotboy655"
|
||||
TOOL.Name = "#tool.rb655_easy_animation.name"
|
||||
TOOL.AnimationArray = {}
|
||||
|
||||
TOOL.ClientConVar[ "anim" ] = ""
|
||||
TOOL.ClientConVar[ "speed" ] = "1.0"
|
||||
TOOL.ClientConVar[ "delay" ] = "0"
|
||||
TOOL.ClientConVar[ "nohide" ] = "0"
|
||||
TOOL.ClientConVar[ "loop" ] = "0"
|
||||
TOOL.ClientConVar[ "noglow" ] = "0"
|
||||
|
||||
TOOL.ServerConVar[ "nobbox_sv" ] = "0"
|
||||
CreateConVar( "rb655_easy_animation_nobbox_sv", "0", FCVAR_ARCHIVE )
|
||||
|
||||
local function MakeNiceName( str )
|
||||
local newname = {}
|
||||
for _, s in pairs( string.Explode( "_", string.Replace( str, " ", "_" ) ) ) do
|
||||
if ( string.len( s ) == 0 ) then continue end
|
||||
if ( string.len( s ) == 1 ) then table.insert( newname, string.upper( s ) ) continue end
|
||||
table.insert( newname, string.upper( string.Left( s, 1 ) ) .. string.Right( s, string.len( s ) - 1 ) ) -- Ugly way to capitalize first letters.
|
||||
end
|
||||
|
||||
return table.concat( newname, " " )
|
||||
end
|
||||
|
||||
local function IsEntValid( ent )
|
||||
if ( !IsValid( ent ) or ent:IsWorld() ) then return false end
|
||||
if ( table.Count( ent:GetSequenceList() or {} ) != 0 ) then return true end
|
||||
return false
|
||||
end
|
||||
|
||||
local function PlayAnimationBase( ent, anim, speed )
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
-- HACK: This is not perfect, but it will have to do
|
||||
if ( ent:GetClass() == "prop_dynamic" ) then
|
||||
ent:Fire( "SetAnimation", anim )
|
||||
ent:Fire( "SetPlaybackRate", math.Clamp( tonumber( speed ), 0.05, 3.05 ) )
|
||||
return
|
||||
end
|
||||
|
||||
ent:ResetSequence( ent:LookupSequence( anim ) )
|
||||
ent:ResetSequenceInfo()
|
||||
ent:SetCycle( 0 )
|
||||
ent:SetPlaybackRate( math.Clamp( tonumber( speed ), 0.05, 3.05 ) )
|
||||
|
||||
end
|
||||
|
||||
local UniqueID = 0
|
||||
function PlayAnimation( ply, ent, anim, speed, delay, loop, isPreview )
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
delay = tonumber( delay ) or 0
|
||||
loop = tobool( loop ) or false
|
||||
|
||||
UniqueID = UniqueID + 1
|
||||
local tid = "rb655_animation_loop_" .. ply:UniqueID() .. "-" .. UniqueID
|
||||
|
||||
if ( isPreview ) then tid = "rb655_animation_loop_preview" .. ply:UniqueID() end
|
||||
|
||||
timer.Create( tid, delay, 1, function()
|
||||
PlayAnimationBase( ent, anim, speed )
|
||||
if ( loop == true and IsValid( ent ) ) then
|
||||
timer.Adjust( tid, ent:SequenceDuration() / speed, 0, function()
|
||||
if ( !IsValid( ent ) ) then timer.Remove( tid ) return end
|
||||
PlayAnimationBase( ent, anim, speed )
|
||||
end )
|
||||
end
|
||||
end )
|
||||
end
|
||||
|
||||
function TOOL:GetSelectedEntity()
|
||||
return self:GetWeapon():GetNWEntity( 1 )
|
||||
end
|
||||
|
||||
function TOOL:SetSelectedEntity( ent )
|
||||
if ( IsValid( ent ) and ent:GetClass() == "prop_effect" ) then ent = ent.AttachedEntity end
|
||||
if ( !IsValid( ent ) ) then ent = NULL end
|
||||
|
||||
if ( self:GetSelectedEntity() == ent ) then return end
|
||||
|
||||
self:GetWeapon():SetNWEntity( 1, ent )
|
||||
end
|
||||
|
||||
local gOldCVar1 = GetConVarNumber( "ai_disabled" )
|
||||
local gOldCVar2 = GetConVarNumber( "rb655_easy_animation_nohide" )
|
||||
|
||||
local gLastSelectedEntity = NULL
|
||||
function TOOL:Think()
|
||||
local ent = self:GetSelectedEntity()
|
||||
if ( !IsValid( ent ) ) then self:SetSelectedEntity( NULL ) end
|
||||
|
||||
if ( CLIENT ) then
|
||||
if ( gOldCVar1 != GetConVarNumber( "ai_disabled" ) or gOldCVar2 != GetConVarNumber( "rb655_easy_animation_nohide" ) ) then
|
||||
gOldCVar1 = GetConVarNumber( "ai_disabled" )
|
||||
gOldCVar2 = GetConVarNumber( "rb655_easy_animation_nohide" )
|
||||
if ( IsEntValid( ent ) and ent:IsNPC() ) then self:UpdateControlPanel() end
|
||||
end
|
||||
if ( ent:EntIndex() == gLastSelectedEntity ) then return end
|
||||
gLastSelectedEntity = ent:EntIndex()
|
||||
self:UpdateControlPanel()
|
||||
RunConsoleCommand( "rb655_easy_animation_anim", "" )
|
||||
end
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
if ( SERVER ) then self:SetSelectedEntity( trace.Entity ) end
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
if ( SERVER ) then
|
||||
if ( #self.AnimationArray <= 0 and IsValid( self:GetSelectedEntity() ) ) then
|
||||
self:GetSelectedEntity():SetPlaybackRate( 0 )
|
||||
elseif ( #self.AnimationArray > 0 ) then
|
||||
for id, t in pairs( self.AnimationArray ) do
|
||||
if ( IsValid( t.ent ) ) then t.ent:SetPlaybackRate( 0 ) end
|
||||
end
|
||||
end
|
||||
|
||||
-- Destroy all timers.
|
||||
for i = 0, UniqueID do timer.Remove( "rb655_animation_loop_" .. self:GetOwner():UniqueID() .. "-" .. i ) UniqueID = 0 end
|
||||
timer.Remove( "rb655_animation_loop_preview" .. self:GetOwner():UniqueID() )
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
util.AddNetworkString( "rb655_easy_animation_array" )
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
local ent = self:GetSelectedEntity()
|
||||
local anim = self:GetClientInfo( "anim" )
|
||||
|
||||
for i = 0, UniqueID do timer.Remove( "rb655_animation_loop_" .. self:GetOwner():UniqueID() .. "-" .. i ) UniqueID = 0 end
|
||||
timer.Remove( "rb655_animation_loop_preview" .. self:GetOwner():UniqueID() )
|
||||
|
||||
if ( #self.AnimationArray > 0 ) then
|
||||
for id, t in pairs( self.AnimationArray ) do
|
||||
if ( !IsEntValid( t.ent ) or string.len( string.Trim( t.anim ) ) == 0 ) then continue end
|
||||
PlayAnimation( self:GetOwner(), t.ent, t.anim, t.speed, t.delay, t.loop )
|
||||
end
|
||||
else
|
||||
if ( !IsEntValid( ent ) or string.len( string.Trim( anim ) ) == 0 ) then return end
|
||||
PlayAnimation( self:GetOwner(), ent, anim, self:GetClientInfo( "speed" ), self:GetClientInfo( "delay" ), self:GetClientInfo( "loop" ), true )
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
concommand.Add( "rb655_easy_animation_anim_do", function( ply, cmd, args )
|
||||
local tool = ply:GetTool( "rb655_easy_animation" )
|
||||
if ( !tool ) then return end
|
||||
|
||||
local ent = tool:GetSelectedEntity()
|
||||
if ( !IsEntValid( ent ) ) then return end
|
||||
|
||||
for i = 0, UniqueID do timer.Remove( "rb655_animation_loop_" .. ply:UniqueID() .. "-" .. i ) UniqueID = 0 end
|
||||
timer.Remove( "rb655_animation_loop_preview" .. ply:UniqueID() )
|
||||
|
||||
PlayAnimation( ply, ent, args[ 1 ] or "", ply:GetTool( "rb655_easy_animation" ):GetClientInfo( "speed" ), 0, ply:GetTool():GetClientInfo( "loop" ), true )
|
||||
end )
|
||||
|
||||
concommand.Add( "rb655_easy_animation_set_pp", function( ply, cmd, args )
|
||||
local tool = ply:GetTool( "rb655_easy_animation" )
|
||||
if ( !tool ) then return end
|
||||
|
||||
local ent = tool:GetSelectedEntity()
|
||||
if ( !IsEntValid( ent ) ) then return end
|
||||
|
||||
local pp_name = ent:GetPoseParameterName( math.floor( tonumber( args[ 1 ] ) ) )
|
||||
if ( !pp_name ) then return end
|
||||
|
||||
ent:SetPoseParameter( pp_name, tonumber( args[ 2 ] ) )
|
||||
end )
|
||||
|
||||
concommand.Add( "rb655_easy_animation_add", function( ply, cmd, args )
|
||||
local tool = ply:GetTool( "rb655_easy_animation" )
|
||||
if ( !tool ) then return end
|
||||
local e = tool:GetSelectedEntity()
|
||||
local a = tool:GetClientInfo( "anim" )
|
||||
local s = tool:GetClientInfo( "speed" )
|
||||
local d = tool:GetClientInfo( "delay" )
|
||||
local l = tool:GetClientInfo( "loop" )
|
||||
if ( !IsEntValid( e ) or string.len( string.Trim( a ) ) == 0 ) then return end
|
||||
|
||||
table.insert( tool.AnimationArray, {ent = e, anim = a, speed = s, delay = d, loop = l, ei = e:EntIndex()} )
|
||||
net.Start( "rb655_easy_animation_array" )
|
||||
net.WriteTable( tool.AnimationArray )
|
||||
net.Send( ply )
|
||||
end )
|
||||
|
||||
concommand.Add( "rb655_easy_animation_rid", function( ply, cmd, args ) -- rid is for RemoveID
|
||||
local tool = ply:GetTool( "rb655_easy_animation" )
|
||||
if ( !tool.AnimationArray[ tonumber( args[ 1 ] ) ] ) then return end
|
||||
if ( tool.AnimationArray[ tonumber( args[ 1 ] ) ].ei != tonumber( args[ 2 ] ) and tonumber( args[ 2 ] ) != 0 ) then return end
|
||||
|
||||
table.remove( tool.AnimationArray, tonumber( args[ 1 ] ) )
|
||||
net.Start( "rb655_easy_animation_array" )
|
||||
net.WriteTable( tool.AnimationArray )
|
||||
net.Send( ply )
|
||||
end )
|
||||
end
|
||||
|
||||
if ( SERVER ) then return end
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "info", stage = 1 },
|
||||
{ name = "left" },
|
||||
{ name = "right" },
|
||||
{ name = "reload" },
|
||||
}
|
||||
|
||||
language.Add( "tool.rb655_easy_animation.left", "Play all animations" )
|
||||
language.Add( "tool.rb655_easy_animation.right", "Select an object to play animations on" )
|
||||
language.Add( "tool.rb655_easy_animation.reload", "Pause currently playing animation(s)" )
|
||||
|
||||
language.Add( "tool.rb655_easy_animation.name", "Easy Animation Tool" )
|
||||
language.Add( "tool.rb655_easy_animation.desc", "Easy animations for everyone" )
|
||||
language.Add( "tool.rb655_easy_animation.1", "Use context menu to play animations" )
|
||||
|
||||
language.Add( "tool.rb655_easy_animation.animations", "Animations" )
|
||||
language.Add( "tool.rb655_easy_animation.add", "Add current selection" )
|
||||
language.Add( "tool.rb655_easy_animation.add.help", "\nIf you want to play animations on multiple entities at one:\n1) Select entity\n2) Select animation from the list, if the entity has any.\n3) Configure sliders to your desire.\n4) Click \"Add current selection\"\n5) Do 1-4 steps as many times as you wish.\n6) Left-click\n\nYou cannot play two animations on the same entity at the same time. The last animation will cut off the first one." )
|
||||
language.Add( "tool.rb655_easy_animation.speed", "Animation Speed" )
|
||||
language.Add( "tool.rb655_easy_animation.speed.help", "How fast the animation will play." )
|
||||
language.Add( "tool.rb655_easy_animation.delay", "Delay" )
|
||||
language.Add( "tool.rb655_easy_animation.delay.help", "The time between you left-click and the animation is played." )
|
||||
language.Add( "tool.rb655_easy_animation.loop", "Loop Animation" )
|
||||
language.Add( "tool.rb655_easy_animation.loop.help", "Play animation again when it ends." )
|
||||
language.Add( "tool.rb655_easy_animation.nohide", "Do not filter animations" )
|
||||
language.Add( "tool.rb655_easy_animation.nohide.help", "Enabling this option will show you the full list of animations available for selected entity. Please note, that this list can be so long, that GMod may freeze for a few seconds. For this reason we hide a bunch of animations deemed \"useless\" by default, such as gestures and other delta animations." )
|
||||
language.Add( "tool.rb655_easy_animation.poseparam.help", "The sliders above are the Pose Parameters. They affect how certain animations look, for example the direction for Team Fortress 2 run animations, etc." )
|
||||
language.Add( "tool.rb655_easy_animation.poseparam.badent", "Changing Pose Parameters is only supported on Animatable props!" )
|
||||
|
||||
language.Add( "tool.rb655_easy_animation.ai", "NPC is selected, but NPC thinking is not disabled! Without that the NPC will reset its animations every frame." )
|
||||
language.Add( "tool.rb655_easy_animation.ragdoll", "Ragdolls cannot be animated! Open context menu (Hold C) > right click on ragdoll > Make Animatable" )
|
||||
language.Add( "tool.rb655_easy_animation.prop", "Props cannot be animated properly! Open context menu (Hold C) > right click on entity > Make Animatable" )
|
||||
language.Add( "tool.rb655_easy_animation.badent", "This entity does not have any animations." )
|
||||
language.Add( "tool.rb655_easy_animation.noent", "No entity selected." )
|
||||
|
||||
language.Add( "tool.rb655_easy_animation.noglow", "Don't render glow/halo around models" )
|
||||
language.Add( "tool.rb655_easy_animation.noglow.help", "Don't render glow/halo around models when they are selected, and don't draw bounding boxes below animated models. Bounding boxes are a helper for when animations make the ragdolls go outside of their bounding box making them unselectable.\n" )
|
||||
|
||||
language.Add( "tool.rb655_easy_animation.property", "Make Animatable" )
|
||||
language.Add( "tool.rb655_easy_animation.property_bodyxy", "Animate Movement Pose Parameters" )
|
||||
language.Add( "tool.rb655_easy_animation.property_damageragdoll", "Ragdoll/Gib on Damage" )
|
||||
language.Add( "tool.rb655_easy_animation.property_ragdoll", "Make Ragdoll" )
|
||||
language.Add( "prop_animatable", "Animatable Entity" )
|
||||
|
||||
function TOOL:GetStage()
|
||||
if ( IsValid( self:GetSelectedEntity() ) ) then return 1 end
|
||||
return 0
|
||||
end
|
||||
|
||||
net.Receive( "rb655_easy_animation_array", function( len )
|
||||
local tool = LocalPlayer():GetTool( "rb655_easy_animation" )
|
||||
tool.AnimationArray = net.ReadTable()
|
||||
if ( CLIENT ) then tool:UpdateControlPanel() end
|
||||
end )
|
||||
|
||||
function TOOL:UpdateControlPanel( index )
|
||||
local panel = controlpanel.Get( "rb655_easy_animation" )
|
||||
if ( !panel ) then MsgN( "Couldn't find rb655_easy_animation panel!" ) return end
|
||||
|
||||
panel:ClearControls()
|
||||
self.BuildCPanel( panel, self:GetSelectedEntity() )
|
||||
end
|
||||
|
||||
local clr_err = Color( 200, 0, 0 )
|
||||
function TOOL.BuildCPanel( panel, ent )
|
||||
|
||||
local tool = LocalPlayer() and LocalPlayer():GetTool( "rb655_easy_animation" )
|
||||
local nohide = false
|
||||
|
||||
if ( tool ) then
|
||||
if ( !IsValid( ent ) ) then ent = tool:GetSelectedEntity() end
|
||||
nohide = tool:GetClientNumber( "nohide" ) != 0
|
||||
end
|
||||
|
||||
if ( !IsValid( ent ) ) then
|
||||
|
||||
panel:AddControl( "Label", { Text = "#tool.rb655_easy_animation.noent" } ):SetTextColor( clr_err )
|
||||
|
||||
elseif ( IsEntValid( ent ) ) then
|
||||
|
||||
local fine = true
|
||||
|
||||
if ( GetConVarNumber( "ai_disabled" ) == 0 and ent:IsNPC() ) then panel:AddControl( "Label", {Text = "#tool.rb655_easy_animation.ai"} ):SetTextColor( clr_err ) fine = false end
|
||||
if ( ent:GetClass() == "prop_ragdoll" ) then panel:AddControl( "Label", { Text = "#tool.rb655_easy_animation.ragdoll" } ):SetTextColor( clr_err ) fine = false end
|
||||
if ( ent:GetClass() == "prop_physics" or ent:GetClass() == "prop_physics_multiplayer" or ent:GetClass() == "prop_physics_override" ) then panel:AddControl( "Label", { Text = "#tool.rb655_easy_animation.prop" } ):SetTextColor( clr_err ) end
|
||||
|
||||
local t = {}
|
||||
local badBegginings = { "g_", "p_", "e_", "b_", "bg_", "hg_", "tc_", "aim_", "turn", "gest_", "pose_", "pose_", "auto_", "layer_", "posture", "bodyaccent", "a_" }
|
||||
local badStrings = { "gesture", "posture", "_trans_", "_rot_", "gest", "aim", "bodyflex_", "delta", "ragdoll", "spine", "arms" }
|
||||
for k, v in SortedPairsByValue( ent:GetSequenceList() ) do
|
||||
local isbad = false
|
||||
|
||||
for i, s in pairs( badStrings ) do if ( string.find( string.lower( v ), s, 1, true ) != nil ) then isbad = true break end end
|
||||
if ( isbad == true and !nohide ) then continue end
|
||||
|
||||
for i, s in pairs( badBegginings ) do if ( s == string.Left( string.lower( v ), string.len( s ) ) ) then isbad = true break end end
|
||||
if ( isbad == true and !nohide ) then continue end
|
||||
|
||||
language.Add( "rb655_anim_" .. v, MakeNiceName( v ) )
|
||||
t[ "#rb655_anim_" .. v ] = { rb655_easy_animation_anim = v, rb655_easy_animation_anim_do = v }
|
||||
end
|
||||
|
||||
if ( fine ) then
|
||||
local filter = panel:AddControl( "TextBox", { Label = "#spawnmenu.quick_filter_tool" } )
|
||||
filter:SetUpdateOnType( true )
|
||||
|
||||
local animList = panel:AddControl( "ListBox", { Label = "#tool.rb655_easy_animation.animations", Options = t, Height = 225 } )
|
||||
|
||||
-- patch the function to take into account visiblity
|
||||
function animList:DataLayout()
|
||||
local y = 0
|
||||
for k, Line in ipairs( self.Sorted ) do
|
||||
if ( !Line:IsVisible() ) then continue end
|
||||
|
||||
Line:SetPos( 1, y )
|
||||
Line:SetSize( self:GetWide() - 2, self.m_iDataHeight )
|
||||
Line:DataLayout( self )
|
||||
|
||||
Line:SetAltLine( k % 2 == 1 )
|
||||
|
||||
y = y + Line:GetTall()
|
||||
end
|
||||
|
||||
return y
|
||||
end
|
||||
|
||||
filter.OnValueChange = function( s, txt )
|
||||
for id, pnl in pairs( animList:GetCanvas():GetChildren() ) do
|
||||
if ( !pnl:GetValue( 1 ):lower():find( txt:lower(), 1, true ) ) then
|
||||
pnl:SetVisible( false )
|
||||
else
|
||||
pnl:SetVisible( true )
|
||||
end
|
||||
end
|
||||
animList:SetDirty( true )
|
||||
animList:InvalidateLayout()
|
||||
end
|
||||
end
|
||||
|
||||
elseif ( !IsEntValid( ent ) ) then
|
||||
|
||||
panel:AddControl( "Label", { Text = "#tool.rb655_easy_animation.badent" } ):SetTextColor( clr_err )
|
||||
|
||||
end
|
||||
|
||||
if ( IsValid( ent ) and ent:GetClass() == "prop_animatable" ) then
|
||||
for k = 0, ent:GetNumPoseParameters() - 1 do
|
||||
local min, max = ent:GetPoseParameterRange( k )
|
||||
local name = ent:GetPoseParameterName( k )
|
||||
|
||||
local ctrl = panel:NumSlider( name, nil, min, max, 2 )
|
||||
ctrl:SetHeight( 11 ) -- This makes the controls all bunched up like how we want
|
||||
ctrl:DockPadding( 0, -6, 0, -4 ) -- Try to make the lower part of the text visible
|
||||
ctrl:SetValue( math.Remap( ent:GetPoseParameter( name ), 0, 1, min, max ) )
|
||||
|
||||
ctrl.OnValueChanged = function( self, value )
|
||||
RunConsoleCommand( "rb655_easy_animation_set_pp", k, value )
|
||||
|
||||
--ent:SetPoseParameter( ent:GetPoseParameterName( k ), math.Remap( value, min, max, 0, 1 ) )
|
||||
ent:SetPoseParameter( ent:GetPoseParameterName( k ), value )
|
||||
end
|
||||
end
|
||||
|
||||
if ( ent:GetNumPoseParameters() > 0 ) then
|
||||
panel:ControlHelp( "#tool.rb655_easy_animation.poseparam.help" ):DockMargin( 32, 8, 32, 8 )
|
||||
end
|
||||
|
||||
elseif ( IsValid( ent ) and ent:GetClass() != "prop_animatable" and ent:GetNumPoseParameters() > 0 ) then
|
||||
local errlbl = panel:ControlHelp( "#tool.rb655_easy_animation.poseparam.badent" )
|
||||
errlbl:DockMargin( 32, 8, 32, 8 )
|
||||
errlbl:SetTextColor( clr_err )
|
||||
end
|
||||
|
||||
local pnl = vgui.Create( "DPanelList" )
|
||||
pnl:SetHeight( 225 )
|
||||
pnl:EnableHorizontal( false )
|
||||
pnl:EnableVerticalScrollbar()
|
||||
pnl:SetSpacing( 2 )
|
||||
pnl:SetPadding( 2 )
|
||||
Derma_Hook( pnl, "Paint", "Paint", "Panel" ) -- Awesome GWEN background
|
||||
|
||||
if ( tool and tool.AnimationArray ) then
|
||||
for i, d in pairs( tool.AnimationArray ) do
|
||||
local s = vgui.Create( "RAnimEntry" )
|
||||
s:SetInfo( i, d.ent, d.anim, d.speed, d.delay, d.loop )
|
||||
pnl:AddItem( s )
|
||||
end
|
||||
end
|
||||
|
||||
panel:AddPanel( pnl )
|
||||
|
||||
panel:AddControl( "Button", { Label = "#tool.rb655_easy_animation.add", Command = "rb655_easy_animation_add" } )
|
||||
panel:ControlHelp( "#tool.rb655_easy_animation.add.help" )
|
||||
panel:AddControl( "Slider", { Label = "#tool.rb655_easy_animation.speed", Type = "Float", Min = 0.05, Max = 3.05, Command = "rb655_easy_animation_speed", Help = true } )
|
||||
panel:AddControl( "Slider", { Label = "#tool.rb655_easy_animation.delay", Type = "Float", Min = 0, Max = 32, Command = "rb655_easy_animation_delay", Help = true } )
|
||||
panel:AddControl( "Checkbox", { Label = "#tool.rb655_easy_animation.loop", Command = "rb655_easy_animation_loop", Help = true } )
|
||||
panel:AddControl( "Checkbox", { Label = "#tool.rb655_easy_animation.nohide", Command = "rb655_easy_animation_nohide", Help = true } )
|
||||
panel:AddControl( "Checkbox", { Label = "#tool.rb655_easy_animation.noglow", Command = "rb655_easy_animation_noglow", Help = true } )
|
||||
end
|
||||
|
||||
function TOOL:DrawHUD()
|
||||
local ent = self:GetSelectedEntity()
|
||||
if ( !IsValid( ent ) or tobool( self:GetClientNumber( "noglow" ) ) ) then return end
|
||||
|
||||
local t = { ent }
|
||||
if ( ent.GetActiveWeapon ) then table.insert( t, ent:GetActiveWeapon() ) end
|
||||
halo.Add( t, HSVToColor( ( CurTime() * 3 ) % 360, math.abs( math.sin( CurTime() / 2 ) ), 1 ), 2, 2, 1 )
|
||||
end
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
self.ent = nil
|
||||
self.anim = "attack01"
|
||||
self.id = 0
|
||||
self.eid = 0
|
||||
self.speed = 1
|
||||
self.delay = 0
|
||||
self.loop = false
|
||||
|
||||
self.rem = vgui.Create( "DImageButton", self )
|
||||
self.rem:SetImage( "icon16/cross.png" )
|
||||
self.rem:SetSize( 16, 16 )
|
||||
self.rem:SetPos( 4, 4 )
|
||||
self.rem.DoClick = function()
|
||||
self:RemoveFull()
|
||||
end
|
||||
end
|
||||
|
||||
function PANEL:RemoveFull()
|
||||
self.rem:Remove()
|
||||
self:Remove()
|
||||
RunConsoleCommand( "rb655_easy_animation_rid", self.id, self.eid )
|
||||
end
|
||||
|
||||
function PANEL:Paint( w, h )
|
||||
draw.RoundedBox( 2, 0, 0, w, h, Color( 50, 50, 50, 225 ) )
|
||||
if ( !self.ent or !IsValid( self.ent ) ) then self:RemoveFull() return end
|
||||
|
||||
surface.SetFont( "DermaDefault" )
|
||||
draw.SimpleText( "#" .. self.ent:GetClass(), "DermaDefault", 24, 0, Color( 255, 255, 255, 255 ) )
|
||||
draw.SimpleText( "#rb655_anim_" .. self.anim, "DermaDefault", 24, 10, Color( 255, 255, 255, 255 ) )
|
||||
|
||||
local tW = surface.GetTextSize( "#" .. self.ent:GetClass() )
|
||||
draw.SimpleText( " #" .. self.ent:EntIndex(), "DermaDefault", 24 + tW, 0, Color( 255, 255, 255, 255 ) )
|
||||
|
||||
local tW2 = surface.GetTextSize( "#rb655_anim_" .. self.anim )
|
||||
local t = " [ S: " .. self.speed .. ", D: " .. self.delay
|
||||
if ( self.loop ) then t = t .. ", Looping" end
|
||||
draw.SimpleText( t .. " ]", "DermaDefault", 24 + tW2, 10, Color( 255, 255, 255, 255 ) )
|
||||
end
|
||||
|
||||
function PANEL:SetInfo( id, e, a, s, d, l )
|
||||
self.id = id
|
||||
self.eid = e:EntIndex()
|
||||
self.ent = e
|
||||
self.anim = a
|
||||
self.speed = s
|
||||
self.delay = d
|
||||
self.loop = tobool( l )
|
||||
end
|
||||
|
||||
vgui.Register( "RAnimEntry", PANEL, "Panel" )
|
||||
208
lua/weapons/gmod_tool/stools/rb655_easy_bodygroup.lua
Normal file
208
lua/weapons/gmod_tool/stools/rb655_easy_bodygroup.lua
Normal file
@@ -0,0 +1,208 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Robotboy655"
|
||||
TOOL.Name = "#tool.rb655_easy_bodygroup.name"
|
||||
|
||||
local gLastSelecetedEntity = NULL
|
||||
|
||||
local MaxBodyGroups = 72
|
||||
|
||||
TOOL.ClientConVar[ "noglow" ] = "0"
|
||||
TOOL.ClientConVar[ "skin" ] = "0"
|
||||
for i = 0, MaxBodyGroups do TOOL.ClientConVar[ "group" .. i ] = "1" end
|
||||
|
||||
local function MakeNiceName( str )
|
||||
local newname = {}
|
||||
|
||||
for _, s in pairs( string.Explode( "_", str ) ) do
|
||||
if ( string.len( s ) == 1 ) then table.insert( newname, string.upper( s ) ) continue end
|
||||
table.insert( newname, string.upper( string.Left( s, 1 ) ) .. string.Right( s, string.len( s ) - 1 ) ) -- Ugly way to capitalize first letters.
|
||||
end
|
||||
|
||||
return string.Implode( " ", newname )
|
||||
end
|
||||
|
||||
local function IsEntValid( ent )
|
||||
if ( !IsValid( ent ) or ent:IsWorld() ) then return false end
|
||||
if ( ( ent:SkinCount() or 0 ) > 1 ) then return true end
|
||||
if ( ( ent:GetNumBodyGroups() or 0 ) > 1) then return true end
|
||||
if ( ( ent:GetBodygroupCount( 0 ) or 0 ) > 1 ) then return true end
|
||||
return false
|
||||
end
|
||||
|
||||
local function SetBodygroup( _, ent, t )
|
||||
ent:SetBodygroup( t.group, t.id )
|
||||
end
|
||||
for i = 0, MaxBodyGroups do duplicator.RegisterEntityModifier( "bodygroup" .. i, SetBodygroup ) end -- We only have this so old dupes will work
|
||||
|
||||
function TOOL:GetSelecetedEntity()
|
||||
return self:GetWeapon():GetNWEntity( "rb655_bodygroup_entity" )
|
||||
end
|
||||
|
||||
function TOOL:SetSelecetedEntity( ent )
|
||||
if ( IsValid( ent ) && ent:GetClass() == "prop_effect" ) then ent = ent.AttachedEntity end
|
||||
if ( !IsValid( ent ) ) then ent = NULL end
|
||||
|
||||
if ( self:GetSelecetedEntity() == ent ) then return end
|
||||
|
||||
self:GetWeapon():SetNWEntity( "rb655_bodygroup_entity", ent )
|
||||
end
|
||||
|
||||
-- The whole Ready system is to make sure it have time to sync the console vars. Not the best idea, but it does work.
|
||||
if ( SERVER ) then
|
||||
TOOL.Ready = 0
|
||||
|
||||
util.AddNetworkString( "rb655_easy_bodygroup_ready" )
|
||||
|
||||
net.Receive( "rb655_easy_bodygroup_ready", function( len, ply )
|
||||
local tool = ply:GetTool( "rb655_easy_bodygroup" )
|
||||
if ( tool && net.ReadEntity() == tool:GetSelecetedEntity() ) then tool.Ready = 1 end
|
||||
end )
|
||||
|
||||
--[[concommand.Add( "rb655_easy_bodygroup_group", function( ply, cmd, args )
|
||||
local wep = ply:GetWeapon( "gmod_tool" )
|
||||
if ( !IsValid( wep ) ) then return end
|
||||
|
||||
local tool = wep:GetToolObject( "rb655_easy_bodygroup" )
|
||||
local group = tonumber( args[ 1 ] )
|
||||
local value = tonumber( args[ 2 ] )
|
||||
|
||||
ply.BodygroupToolValues = ply.BodygroupToolValues or {}
|
||||
ply.BodygroupToolValues[ group ] = value
|
||||
end )]]
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Think()
|
||||
local ent = self:GetSelecetedEntity()
|
||||
if ( !IsValid( ent ) ) then self:SetSelecetedEntity( NULL ) end
|
||||
|
||||
if ( CLIENT ) then
|
||||
if ( ent:EntIndex() == gLastSelecetedEntity ) then return end
|
||||
gLastSelecetedEntity = ent:EntIndex()
|
||||
self:UpdateControlPanel()
|
||||
return
|
||||
end
|
||||
|
||||
if ( !IsEntValid( ent ) ) then return end
|
||||
if ( self.Ready == 0 ) then return end
|
||||
if ( self.Ready > 0 && self.Ready < 50 ) then self.Ready = self.Ready + 1 return end -- Another ugly workaround
|
||||
|
||||
if ( ent:SkinCount() > 1 ) then ent:SetSkin( self:GetClientNumber( "skin" ) ) end
|
||||
|
||||
for i = 0, ent:GetNumBodyGroups() - 1 do
|
||||
if ( ent:GetBodygroupCount( i ) <= 1 ) then continue end
|
||||
if ( ent:GetBodygroup( i ) == self:GetClientNumber( "group" .. i ) ) then continue end
|
||||
SetBodygroup( nil, ent, { group = i, id = self:GetClientNumber( "group" .. i ) } )
|
||||
|
||||
-- if ( ent:GetBodygroup( i ) == self:GetOwner().BodygroupToolValues[ i ] ) then continue end
|
||||
-- SetBodygroup( nil, ent, { group = i, id = self:GetOwner().BodygroupToolValues[ i ] } )
|
||||
end
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
if ( SERVER && trace.Entity != self:GetSelecetedEntity() ) then
|
||||
self.Ready = 0
|
||||
self:SetSelecetedEntity( trace.Entity )
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:RightClick( trace ) return self:LeftClick( trace ) end
|
||||
|
||||
function TOOL:Reload()
|
||||
if ( SERVER ) then
|
||||
self.Ready = 0
|
||||
self:SetSelecetedEntity( self:GetOwner() )
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
if ( SERVER ) then return end
|
||||
|
||||
TOOL.Information = {
|
||||
{ name = "info", stage = 1 },
|
||||
{ name = "left" },
|
||||
{ name = "reload" },
|
||||
}
|
||||
|
||||
language.Add( "tool.rb655_easy_bodygroup.left", "Select an object to edit" )
|
||||
language.Add( "tool.rb655_easy_bodygroup.reload", "Select yourself" )
|
||||
|
||||
language.Add( "tool.rb655_easy_bodygroup.name", "Easy Bodygroup Tool" )
|
||||
language.Add( "tool.rb655_easy_bodygroup.desc", "Eases change of bodygroups and skins" )
|
||||
language.Add( "tool.rb655_easy_bodygroup.1", "Use context menu to edit bodygroups or skins" )
|
||||
|
||||
language.Add( "tool.rb655_easy_bodygroup.noglow", "Don't render glow/halo around models" )
|
||||
language.Add( "tool.rb655_easy_bodygroup.skin", "Skin" )
|
||||
language.Add( "tool.rb655_easy_bodygroup.badent", "This entity does not have any skins or bodygroups." )
|
||||
language.Add( "tool.rb655_easy_bodygroup.noent", "No entity selected." )
|
||||
|
||||
function TOOL:GetStage()
|
||||
if ( IsValid( self:GetSelecetedEntity() ) ) then return 1 end
|
||||
return 0
|
||||
end
|
||||
|
||||
function TOOL:UpdateControlPanel( index )
|
||||
local panel = controlpanel.Get( "rb655_easy_bodygroup" )
|
||||
if ( !panel ) then MsgN( "Couldn't find rb655_easy_bodygroup panel!" ) return end
|
||||
|
||||
panel:ClearControls()
|
||||
self.BuildCPanel( panel, self:GetSelecetedEntity() )
|
||||
end
|
||||
|
||||
-- We don't use the normal automatic stuff because we need to leave out the noglow convar
|
||||
local ConVarsDefault = {}
|
||||
ConVarsDefault[ "rb655_easy_bodygroup_skin" ] = 0
|
||||
for i = 0, MaxBodyGroups do ConVarsDefault[ "rb655_easy_bodygroup_group" .. i ] = 0 end
|
||||
|
||||
function TOOL.BuildCPanel( panel, ent )
|
||||
panel:AddControl( "Checkbox", { Label = "#tool.rb655_easy_bodygroup.noglow", Command = "rb655_easy_bodygroup_noglow" } )
|
||||
|
||||
if ( !IsValid( ent ) ) then panel:AddControl( "Label", { Text = "#tool.rb655_easy_bodygroup.noent" } ) return end
|
||||
if ( !IsEntValid( ent ) ) then panel:AddControl( "Label", { Text = "#tool.rb655_easy_bodygroup.badent" } ) return end
|
||||
|
||||
panel:AddControl( "ComboBox", {
|
||||
MenuButton = 1,
|
||||
Folder = "rb655_ez_bg_" .. ent:GetModel():lower():Replace( "/", "_" ):StripExtension():sub( 8 ), -- Some hacky bussiness
|
||||
Options = { [ "#preset.default" ] = ConVarsDefault },
|
||||
CVars = table.GetKeys( ConVarsDefault )
|
||||
} )
|
||||
|
||||
if ( ent:SkinCount() > 1 ) then
|
||||
LocalPlayer():ConCommand( "rb655_easy_bodygroup_skin " .. ent:GetSkin() )
|
||||
panel:AddControl( "Slider", { Label = "#tool.rb655_easy_bodygroup.skin", Max = ent:SkinCount() - 1, Command = "rb655_easy_bodygroup_skin" } )
|
||||
end
|
||||
|
||||
for k = 0, ent:GetNumBodyGroups() - 1 do
|
||||
if ( ent:GetBodygroupCount( k ) <= 1 ) then continue end
|
||||
LocalPlayer():ConCommand( "rb655_easy_bodygroup_group" .. k .. " " .. ent:GetBodygroup( k ) )
|
||||
panel:AddControl( "Slider", { Label = MakeNiceName( ent:GetBodygroupName( k ) ), Max = ent:GetBodygroupCount( k ) - 1, Command = "rb655_easy_bodygroup_group" .. k } )
|
||||
|
||||
-- LocalPlayer():ConCommand( "rb655_easy_bodygroup_group " .. k .. " " .. ent:GetBodygroup( k ) )
|
||||
-- local ctrl = panel:NumSlider( MakeNiceName( ent:GetBodygroupName( k ) ), "", 0, ent:GetBodygroupCount( k ) - 1, 0 )
|
||||
-- function ctrl:OnValueChanged( val ) RunConsoleCommand( "rb655_easy_bodygroup_group", k, self.Scratch:GetTextValue() ) end
|
||||
end
|
||||
|
||||
net.Start( "rb655_easy_bodygroup_ready" )
|
||||
net.WriteEntity( ent )
|
||||
net.SendToServer()
|
||||
end
|
||||
|
||||
function TOOL:DrawHUD()
|
||||
local ent = self:GetSelecetedEntity()
|
||||
if ( !IsValid( ent ) or tobool( self:GetClientNumber( "noglow" ) ) ) then return end
|
||||
|
||||
local t = { ent }
|
||||
if ( ent.GetActiveWeapon ) then table.insert( t, ent:GetActiveWeapon() ) end
|
||||
halo.Add( t, HSVToColor( ( CurTime() * 3 ) % 360, math.abs( math.sin( CurTime() / 2 ) ), 1 ), 2, 2, 1 )
|
||||
end
|
||||
108
lua/weapons/gmod_tool/stools/resizer.lua
Normal file
108
lua/weapons/gmod_tool/stools/resizer.lua
Normal file
@@ -0,0 +1,108 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Poser"
|
||||
TOOL.Name = "#Resizer"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
if (CLIENT) then
|
||||
|
||||
language.Add("Tool.resizer.name","Resizer")
|
||||
language.Add("Tool.resizer.desc","Resizes props/ragdolls/NPCs")
|
||||
language.Add("Tool.resizer.0","Click on an object to resize it. Right click to reset.")
|
||||
|
||||
CreateClientConVar( "resizer_xsize", "2", false, true )
|
||||
CreateClientConVar( "resizer_ysize", "2", false, true )
|
||||
CreateClientConVar( "resizer_zsize", "2", false, true )
|
||||
CreateClientConVar( "resizer_xyzsize", "2", false, false )
|
||||
CreateClientConVar( "resizer_allbones", "0", false, true )
|
||||
|
||||
local function _resizer_xyzcallback(cvar, prevValue, newValue)
|
||||
RunConsoleCommand("resizer_xsize", newValue);
|
||||
RunConsoleCommand("resizer_ysize", newValue);
|
||||
RunConsoleCommand("resizer_zsize", newValue);
|
||||
end
|
||||
cvars.AddChangeCallback("resizer_xyzsize", _resizer_xyzcallback)
|
||||
|
||||
end --[[ if (CLIENT) then ]]--
|
||||
|
||||
local _resizer_double_fix = false
|
||||
|
||||
function TOOL:RightClick( trace )
|
||||
if (trace.HitNonWorld && trace.Entity != nil && trace.Entity != 0) then
|
||||
if (SERVER) then
|
||||
|
||||
//props | ragdolls | npcs
|
||||
if (trace.Entity:GetClass() == "prop_physics" || trace.Entity:GetClass() == "prop_ragdoll" || trace.Entity:IsNPC()) then
|
||||
for i=0, trace.Entity:GetBoneCount() do
|
||||
trace.Entity:ManipulateBoneScale( i, Vector(1, 1, 1) )
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function TOOL:LeftClick( trace )
|
||||
if (trace.HitNonWorld && trace.Entity != nil && trace.Entity != 0) then
|
||||
if (SERVER) then
|
||||
local scale = Vector( tonumber( self:GetOwner():GetInfo("resizer_xsize")),
|
||||
tonumber( self:GetOwner():GetInfo("resizer_ysize")),
|
||||
tonumber( self:GetOwner():GetInfo("resizer_zsize")) )
|
||||
|
||||
//props
|
||||
if (trace.Entity:GetClass() == "prop_physics") then
|
||||
for i=0, trace.Entity:GetBoneCount() do
|
||||
trace.Entity:ManipulateBoneScale( i, scale )
|
||||
end
|
||||
end
|
||||
|
||||
//ragdolls and npcs
|
||||
if (trace.Entity:GetClass() == "prop_ragdoll" || trace.Entity:IsNPC()) then
|
||||
if ( tonumber(self:GetOwner():GetInfo("resizer_allbones")) > 0 ) then
|
||||
for i=0, trace.Entity:GetBoneCount() do
|
||||
trace.Entity:ManipulateBoneScale( i, scale )
|
||||
end
|
||||
else
|
||||
local Bone = trace.Entity:TranslatePhysBoneToBone( trace.PhysicsBone )
|
||||
trace.Entity:ManipulateBoneScale( Bone, scale )
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
CPanel:AddControl( "Header", { Text = "Resizer", Description = "Does not resize the hitbox or shadow." } )
|
||||
|
||||
CPanel:AddControl( "ComboBox", {
|
||||
|
||||
Label = "#tool.presets",
|
||||
MenuButton = 1,
|
||||
Folder = "resizer",
|
||||
Options = { Default = { resizer_xsize = '1', resizer_ysize='1', resizer_zsize='1', resizer_xyzsize='1'} },
|
||||
CVars = { "resizer_xsize", "resizer_ysize", "resizer_zsize", "resizer_xyzsize"}
|
||||
})
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "X size", Type = "Float", Command = "resizer_xsize", Min = "0.01", Max = "10" } )
|
||||
CPanel:AddControl( "Slider", { Label = "Y size", Type = "Float", Command = "resizer_ysize", Min = "0.01", Max = "10" } )
|
||||
CPanel:AddControl( "Slider", { Label = "Z size", Type = "Float", Command = "resizer_zsize", Min = "0.01", Max = "10" } )
|
||||
CPanel:AddControl( "Slider", { Label = "XYZ", Type = "Float", Command = "resizer_xyzsize", Min = "0.01", Max = "10" } )
|
||||
|
||||
CPanel:AddControl( "Checkbox", { Label = "Resize all bones of ragdolls/NPCs at once", Command = "resizer_allbones" } )
|
||||
end
|
||||
492
lua/weapons/gmod_tool/stools/smartweld.lua
Normal file
492
lua/weapons/gmod_tool/stools/smartweld.lua
Normal file
@@ -0,0 +1,492 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
--[[
|
||||
Smart Weld
|
||||
Created by: Stalker (STEAM_0:1:18093014) - Contact for support
|
||||
Originally by Duncan Stead (Dunk) - Dont contact for support
|
||||
]]
|
||||
|
||||
TOOL.AllowedClasses = {
|
||||
prop_physics = true,
|
||||
prop_physics_multiplayer = true,
|
||||
prop_ragdoll = true,
|
||||
prop_effect = true,
|
||||
prop_vehicle = true,
|
||||
prop_vehicle_jeep = true,
|
||||
prop_vehicle_airboat = true,
|
||||
prop_vehicle_apc = true,
|
||||
prop_vehicle_crane = true,
|
||||
prop_vehicle_prisoner_pod = true
|
||||
}
|
||||
|
||||
TOOL.AllowedBaseClasses = {
|
||||
base_anim = true,
|
||||
base_entity = true,
|
||||
base_gmodentity = true,
|
||||
base_wire_entity = true, -- Wiremod
|
||||
sent_sakarias_scar_base = true, -- SCars
|
||||
base_rd3_entity = true -- Spacebuild
|
||||
}
|
||||
|
||||
TOOL.Category = "Constraints"
|
||||
TOOL.Name = "Weld - Smart"
|
||||
TOOL.ClientConVar["selectradius"] = 100
|
||||
TOOL.ClientConVar["nocollide"] = 1
|
||||
TOOL.ClientConVar["freeze"] = 0
|
||||
TOOL.ClientConVar["clearwelds"] = 1
|
||||
TOOL.ClientConVar["strength"] = 0
|
||||
TOOL.ClientConVar["world"] = 0
|
||||
TOOL.ClientConVar["maxweldsperprop"]= 10 -- Only for when you weld more than 127 props at once
|
||||
TOOL.ClientConVar["color_r"] = 0
|
||||
TOOL.ClientConVar["color_g"] = 255
|
||||
TOOL.ClientConVar["color_b"] = 0
|
||||
TOOL.ClientConVar["color_a"] = 255
|
||||
TOOL.SelectedProps = {}
|
||||
|
||||
-- These don't exist on the server in singleplayer but we need them there.
|
||||
if game.SinglePlayer() then
|
||||
NOTIFY_GENERIC = 0
|
||||
NOTIFY_ERROR = 1
|
||||
NOTIFY_UNDO = 2
|
||||
NOTIFY_HINT = 3
|
||||
NOTIFY_CLEANUP = 4
|
||||
end
|
||||
|
||||
cleanup.Register("smartweld")
|
||||
|
||||
if CLIENT then
|
||||
TOOL.Information = {
|
||||
{name = "left"},
|
||||
{name = "leftuse"},
|
||||
{name = "right", stage = 2},
|
||||
{name = "rightuse", stage = 2},
|
||||
{name = "reload", stage = 2},
|
||||
}
|
||||
|
||||
language.Add("tool.smartweld.name", "Weld - Smart")
|
||||
language.Add("tool.smartweld.desc", "Automatically welds selected props")
|
||||
|
||||
language.Add("tool.smartweld.left", "Select or deselect a prop")
|
||||
language.Add("tool.smartweld.leftuse", "Auto-Selects the props in a set radius")
|
||||
language.Add("tool.smartweld.right", "Welds the selected props")
|
||||
language.Add("tool.smartweld.rightuse", "Welds all the props to the one you\'re looking at")
|
||||
language.Add("tool.smartweld.reload", "Clears the current selection")
|
||||
|
||||
language.Add("tool.smartweld.selectoutsideradius", "Auto-Select Radius:")
|
||||
language.Add("tool.smartweld.selectoutsideradius.help", "The auto-select radius, anything beyond this value wont be selected.")
|
||||
language.Add("tool.smartweld.maxweldsperprop", "Max welds per prop")
|
||||
language.Add("tool.smartweld.maxweldsperprop.help", "The maximum welds per prop. This only works if you are welding more than 127 props at once. Higher than 10 not recommended, 15 maximum.")
|
||||
language.Add("tool.smartweld.strength", "Force Limit:")
|
||||
language.Add("tool.smartweld.strength.help", "The strength of the welds created. Use 0 for unbreakable welds.")
|
||||
language.Add("tool.smartweld.world", "Weld everything to world")
|
||||
language.Add("tool.smartweld.world.help", "Turning this on will weld everything to the world. Useful for making something totally immovable.")
|
||||
language.Add("tool.smartweld.nocollide", "No-collide")
|
||||
language.Add("tool.smartweld.nocollide.help", "Whether all props should no-collide each other when welded.")
|
||||
language.Add("tool.smartweld.freeze", "Auto-freeze")
|
||||
language.Add("tool.smartweld.freeze.help", "Whether all selected props should be frozen after the weld.")
|
||||
language.Add("tool.smartweld.clearwelds", "Remove old welds")
|
||||
language.Add("tool.smartweld.clearwelds.help", "If a selected prop has any welds already on it this will remove them first.")
|
||||
language.Add("tool.smartweld.color", "Selection color")
|
||||
language.Add("tool.smartweld.color.help", "Modify the selection color, it\'s useful for grouping.")
|
||||
language.Add("Undone_smartweld", "Undone Smart-Weld")
|
||||
language.Add("Cleanup_smartweld", "Smart Welds")
|
||||
language.Add("Cleaned_smartweld", "Smart-Welds Cleared")
|
||||
end
|
||||
|
||||
function TOOL.BuildCPanel(panel)
|
||||
panel:SetName("Smart Weld")
|
||||
|
||||
panel:AddControl("Header", {
|
||||
Text = "",
|
||||
Description = "Automatically welds selected props."
|
||||
})
|
||||
|
||||
-- Outside Radius
|
||||
panel:AddControl("Slider", {
|
||||
Label = "#tool.smartweld.selectoutsideradius",
|
||||
Help = "#tool.smartweld.selectoutsideradius",
|
||||
Type = "float",
|
||||
Min = "0",
|
||||
Max = "1000",
|
||||
Command = "smartweld_selectradius"
|
||||
})
|
||||
|
||||
-- Force Limit
|
||||
panel:AddControl("Slider", {
|
||||
Label = "#tool.smartweld.strength",
|
||||
Help = "#tool.smartweld.strength",
|
||||
Type = "float",
|
||||
Min = "0",
|
||||
Max = "10000",
|
||||
Command = "smartweld_strength"
|
||||
})
|
||||
|
||||
-- Max Welds Per Prop
|
||||
panel:AddControl("Slider", {
|
||||
Label = "#tool.smartweld.maxweldsperprop",
|
||||
Help = "#tool.smartweld.maxweldsperprop",
|
||||
Type = "Integer",
|
||||
Min = "1",
|
||||
Max = "10",
|
||||
Command = "smartweld_maxweldsperprop"
|
||||
})
|
||||
|
||||
-- Weld to each other or all to world
|
||||
panel:AddControl("Checkbox", {
|
||||
Label = "#tool.smartweld.world",
|
||||
Help = "#tool.smartweld.world",
|
||||
Command = "smartweld_world"
|
||||
})
|
||||
|
||||
-- No-Collide Props While Welding
|
||||
panel:AddControl("Checkbox", {
|
||||
Label = "#tool.smartweld.nocollide",
|
||||
Help = "#tool.smartweld.nocollide",
|
||||
Command = "smartweld_nocollide"
|
||||
})
|
||||
|
||||
-- Freeze Props When Welded
|
||||
panel:AddControl("Checkbox", {
|
||||
Label = "#tool.smartweld.freeze",
|
||||
Help = "#tool.smartweld.freeze",
|
||||
Command = "smartweld_freeze"
|
||||
})
|
||||
|
||||
-- Clear Previous Welds Before Welding
|
||||
panel:AddControl("Checkbox", {
|
||||
Label = "#tool.smartweld.clearwelds",
|
||||
Help = "#tool.smartweld.clearwelds",
|
||||
Command = "smartweld_clearwelds"
|
||||
})
|
||||
|
||||
-- Color
|
||||
panel:AddControl("Color", {
|
||||
Label = "#tool.smartweld.color",
|
||||
Help = "#tool.smartweld.color",
|
||||
Red = "smartweld_color_r",
|
||||
Green = "smartweld_color_g",
|
||||
Blue = "smartweld_color_b",
|
||||
Alpha = "smartweld_color_a"
|
||||
})
|
||||
end
|
||||
|
||||
-- Micro Optimizations!
|
||||
local ipairs = ipairs
|
||||
local IsValid = IsValid
|
||||
local Weld = constraint.Weld
|
||||
local AddEntity = undo.AddEntity
|
||||
local Cleanup = cleanup.Add
|
||||
|
||||
-- Clears selected props when you die or holster the tool.
|
||||
function TOOL:Holster()
|
||||
if CLIENT or game.SinglePlayer() then
|
||||
for k, v in ipairs(self.SelectedProps) do
|
||||
if IsValid(v.ent) then
|
||||
v.ent:SetColor(v.col)
|
||||
end
|
||||
end
|
||||
end
|
||||
self.SelectedProps = {}
|
||||
self:SetStage(1)
|
||||
end
|
||||
|
||||
-- Pretty much deselects all
|
||||
function TOOL:Reload()
|
||||
if IsFirstTimePredicted() and self.SelectedProps and #self.SelectedProps > 0 then
|
||||
self:Holster()
|
||||
self:Notify("Prop Selection Cleared", NOTIFY_CLEANUP)
|
||||
end
|
||||
end
|
||||
|
||||
-- Does some validity checks then either selects or deselects the prop.
|
||||
function TOOL:LeftClick(tr)
|
||||
if IsFirstTimePredicted() and IsValid(tr.Entity) and not tr.Entity:IsPlayer() then
|
||||
if SERVER and not util.IsValidPhysicsObject(tr.Entity, tr.PhysicsBone) then
|
||||
return false
|
||||
end
|
||||
|
||||
if self:GetOwner():KeyDown(IN_USE) then
|
||||
return self:AutoSelect(tr.Entity)
|
||||
end
|
||||
|
||||
return self:HandleProp(tr)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Auto-selects props
|
||||
function TOOL:AutoSelect(ent)
|
||||
if not IsValid(ent) then return false end
|
||||
local preAutoSelect = #self.SelectedProps
|
||||
|
||||
local selectRadius = self:GetClientNumber("selectradius")
|
||||
local radiusProps = ents.FindInSphere(ent:GetPos(), selectRadius)
|
||||
if #radiusProps < 1 then return false end
|
||||
|
||||
local numNearProps = 0
|
||||
|
||||
for i = 1, #radiusProps do
|
||||
if self:IsAllowedEnt(ent) and not self:PropHasBeenSelected(radiusProps[i]) then
|
||||
self:SelectProp(radiusProps[i])
|
||||
|
||||
numNearProps = numNearProps + 1
|
||||
end
|
||||
end
|
||||
|
||||
self:Notify(#self.SelectedProps-preAutoSelect .." prop(s) have been auto-selected.", NOTIFY_GENERIC)
|
||||
end
|
||||
|
||||
-- Decides if we should select or deselect the specified entity.
|
||||
function TOOL:HandleProp(tr)
|
||||
if #self.SelectedProps == 0 then
|
||||
self:SelectProp(tr.Entity, tr.PhysicsBone)
|
||||
else
|
||||
for k, v in ipairs(self.SelectedProps) do
|
||||
if v.ent == tr.Entity then
|
||||
self:DeselectProp(tr.Entity)
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
self:SelectProp(tr.Entity, tr.PhysicsBone)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-- Deselects the chosen prop.
|
||||
function TOOL:DeselectProp(ent)
|
||||
for k, v in ipairs(self.SelectedProps) do
|
||||
if v.ent == ent then
|
||||
if CLIENT or game.SinglePlayer() then
|
||||
ent:SetColor(v.col)
|
||||
end
|
||||
table.remove(self.SelectedProps, k)
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-- Adds prop to props table and sets its color.
|
||||
function TOOL:SelectProp(entity, hitBoneNum)
|
||||
if self:IsAllowedEnt(entity) then
|
||||
if #self.SelectedProps == 0 then
|
||||
self:SetStage(2)
|
||||
end
|
||||
|
||||
local boneNum = entity:IsRagdoll() and hitBoneNum or 0
|
||||
|
||||
table.insert(self.SelectedProps, {
|
||||
ent = entity,
|
||||
col = entity:GetColor(),
|
||||
bone = boneNum
|
||||
})
|
||||
|
||||
if CLIENT or game.SinglePlayer() then
|
||||
entity:SetColor(Color(self:GetClientNumber("color_r", 0), self:GetClientNumber("color_g", 0), self:GetClientNumber("color_b", 0), self:GetClientNumber("color_a", 255)))
|
||||
end
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Handles the welding
|
||||
function TOOL:RightClick(tr)
|
||||
if #self.SelectedProps <= 1 then
|
||||
self:Notify((#self.SelectedProps == 1 and "Select at least one more prop to weld." or "No props selected!"), NOTIFY_GENERIC)
|
||||
return false
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
undo.Create("smartweld")
|
||||
|
||||
self:PreWeld()
|
||||
self:PerformWeld(tr)
|
||||
|
||||
undo.SetPlayer(self:GetOwner())
|
||||
undo.Finish()
|
||||
end
|
||||
|
||||
self:FinishWelding(tr.Entity)
|
||||
return false
|
||||
end
|
||||
|
||||
-- Does stuff that should happen before welding such as clearing old welds or freezing all the props.
|
||||
function TOOL:PreWeld()
|
||||
local freezeProps = self:GetClientNumber("freeze")
|
||||
local removeOldWelds = self:GetClientNumber("clearwelds")
|
||||
|
||||
for k, v in ipairs(self.SelectedProps) do
|
||||
if IsValid(v.ent) then
|
||||
if removeOldWelds == 1 then
|
||||
constraint.RemoveConstraints(v.ent, "Weld")
|
||||
end
|
||||
|
||||
if freezeProps == 1 then
|
||||
local physobj = v.ent:GetPhysicsObject()
|
||||
if IsValid(physobj) then
|
||||
physobj:EnableMotion(false)
|
||||
self:GetOwner():AddFrozenPhysicsObject(v.ent, physobj)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Decides what kind of weld to perform and then does it.
|
||||
function TOOL:PerformWeld(tr)
|
||||
local weldToWorld = tobool(self:GetClientNumber("world"))
|
||||
local nocollide = tobool(self:GetClientNumber("nocollide"))
|
||||
local weldForceLimit = math.floor(self:GetClientNumber("strength"))
|
||||
local ply = self:GetOwner()
|
||||
|
||||
if #self.SelectedProps < 2 then
|
||||
return
|
||||
end
|
||||
|
||||
if weldToWorld then
|
||||
local world = game.GetWorld()
|
||||
|
||||
for _, v in ipairs(self.SelectedProps) do
|
||||
local weld = Weld(v.ent, world, 0, 0, weldForceLimit, nocollide, false)
|
||||
AddEntity(weld)
|
||||
Cleanup(ply, "smartweld", weld)
|
||||
end
|
||||
elseif self:GetOwner():KeyDown(IN_USE) then -- Weld all to one
|
||||
for _, v in ipairs(self.SelectedProps) do
|
||||
local weld = Weld(v.ent, tr.Entity, v.bone, tr.PhysicsBone, weldForceLimit, nocollide, false)
|
||||
AddEntity(weld)
|
||||
Cleanup(ply, "smartweld", weld)
|
||||
end
|
||||
elseif #self.SelectedProps < 128 then
|
||||
for i = 1, #self.SelectedProps do
|
||||
local firstprop = self.SelectedProps[i]
|
||||
|
||||
for k = i+1, #self.SelectedProps do
|
||||
local secondprop = self.SelectedProps[k]
|
||||
|
||||
if IsValid(firstprop.ent) and IsValid(secondprop.ent) then
|
||||
local weld = Weld(firstprop.ent, secondprop.ent, firstprop.bone, secondprop.bone, weldForceLimit, nocollide, false)
|
||||
AddEntity(weld)
|
||||
Cleanup(ply, "smartweld", weld)
|
||||
end
|
||||
end
|
||||
end
|
||||
else -- There is a source engine limit with welding more than 127 props so we have to work around it by welding to the closest props.
|
||||
local function AreLinked(prop_one, prop_two)
|
||||
return self.SelectedProps[prop_two][prop_one] == true or self.SelectedProps[prop_one][prop_two] == true
|
||||
end
|
||||
|
||||
local function LinkProps(id_one, prop_one, id_two)
|
||||
local weld = Weld(prop_one.ent, self.SelectedProps[id_two].ent, 0, 0, weldForceLimit, nocollide, false)
|
||||
AddEntity(weld)
|
||||
Cleanup(ply, "smartweld", weld)
|
||||
|
||||
-- This kinda makes a mess in the SelectedProps table but we clear it right after this function anyways.
|
||||
self.SelectedProps[id_one][id_two] = true
|
||||
self.SelectedProps[id_two][id_one] = true
|
||||
end
|
||||
|
||||
local maxweldsperprop = math.min(self:GetClientNumber("maxweldsperprop"), 15)
|
||||
|
||||
for i, v in ipairs(self.SelectedProps) do
|
||||
self.SelectedProps[i][i] = true
|
||||
|
||||
for _ = 1, maxweldsperprop do
|
||||
local closestdistance = math.huge
|
||||
local closestprop_id = -1
|
||||
|
||||
for j, d in ipairs(self.SelectedProps) do
|
||||
if not AreLinked(i, j) then
|
||||
local distance = (v.ent:GetPos() - d.ent:GetPos()):LengthSqr()
|
||||
if distance < closestdistance then
|
||||
closestdistance = distance
|
||||
closestprop_id = j
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if closestprop_id ~= -1 then
|
||||
LinkProps(i, v, closestprop_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function TOOL:FinishWelding(entity)
|
||||
if CLIENT or game.SinglePlayer() then
|
||||
local numProps = 0
|
||||
|
||||
for k, v in ipairs(self.SelectedProps) do
|
||||
if IsValid(v.ent) then
|
||||
v.ent:SetColor(v.col)
|
||||
numProps = numProps + 1
|
||||
end
|
||||
end
|
||||
|
||||
if self:GetOwner():KeyDown(IN_USE) then -- If they chose to weld all to one prop this will correct the count.
|
||||
if not self:PropHasBeenSelected(entity) then
|
||||
numProps = numProps + 1
|
||||
end
|
||||
self:Notify("Weld complete! ".. numProps .." props have been welded to a single prop.", NOTIFY_GENERIC)
|
||||
elseif tobool(self:GetClientNumber("world")) then
|
||||
self:Notify("Weld complete! ".. numProps .." props have been welded to the world.", NOTIFY_GENERIC)
|
||||
else
|
||||
self:Notify("Weld complete! ".. numProps .." props have been welded to each other.", NOTIFY_GENERIC)
|
||||
end
|
||||
end
|
||||
self.SelectedProps = {}
|
||||
self:SetStage(1)
|
||||
end
|
||||
|
||||
-- Checks if a prop has already been selected.
|
||||
function TOOL:PropHasBeenSelected(ent)
|
||||
for k, v in ipairs(self.SelectedProps) do
|
||||
if ent == v.ent then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-- Decides if we want to weld the entity or not.
|
||||
function TOOL:IsAllowedEnt(ent)
|
||||
if IsValid(ent) then
|
||||
local ply = SERVER and self:GetOwner() or self.Owner
|
||||
local class = ent:GetClass()
|
||||
local tr = ply:GetEyeTrace()
|
||||
tr.Entity = ent
|
||||
|
||||
if (not hook.Run("CanTool", ply, tr, "smartweld")) or ((not self.AllowedBaseClasses[ent.Base]) and (not self.AllowedClasses[class])) then
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-- Puts one of those annoying notifications to the lower right of the screen.
|
||||
function TOOL:Notify(text, notifyType)
|
||||
if IsFirstTimePredicted() then
|
||||
if CLIENT and IsValid(self.Owner) then
|
||||
notification.AddLegacy(text, notifyType, 5)
|
||||
surface.PlaySound("buttons/button15.wav")
|
||||
elseif game.SinglePlayer() then
|
||||
self:GetOwner():SendLua("GAMEMODE:AddNotify(\"".. text .."\", ".. tostring(notifyType) ..", 5)") -- Because singleplayer is doodoo.
|
||||
self:GetOwner():SendLua("surface.PlaySound(\"buttons/button15.wav\")")
|
||||
end
|
||||
end
|
||||
end
|
||||
317
lua/weapons/gmod_tool/stools/smoke.lua
Normal file
317
lua/weapons/gmod_tool/stools/smoke.lua
Normal file
@@ -0,0 +1,317 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
TOOL.Category = "Matrix_'s Effects"
|
||||
TOOL.Name = "#Smoke"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
//Default values
|
||||
TOOL.ClientConVar["color_r"] = 0
|
||||
TOOL.ClientConVar["color_g"] = 0
|
||||
TOOL.ClientConVar["color_b"] = 0
|
||||
TOOL.ClientConVar["color_a"] = 21
|
||||
TOOL.ClientConVar["material"] = "particle/smokesprites_0001.vmt"
|
||||
TOOL.ClientConVar["spreadbase"] = 6
|
||||
TOOL.ClientConVar["spreadspeed"] = 8
|
||||
TOOL.ClientConVar["speed"] = 32
|
||||
TOOL.ClientConVar["startsize"] = 32
|
||||
TOOL.ClientConVar["endsize"] = 32
|
||||
TOOL.ClientConVar["roll"] = 8
|
||||
TOOL.ClientConVar["numparticles"] = 32
|
||||
TOOL.ClientConVar["jetlength"] = 256
|
||||
TOOL.ClientConVar["twist"] = 6
|
||||
TOOL.ClientConVar["key"] = 5
|
||||
TOOL.ClientConVar["numpadcontrol"] = 0
|
||||
TOOL.ClientConVar["toggle"] = 0
|
||||
|
||||
//List of all spawned fire entities
|
||||
TOOL.Smokes = {}
|
||||
|
||||
//Add language descriptions
|
||||
if (CLIENT) then
|
||||
language.Add("Tool.smoke.name", "Smoke Tool")
|
||||
language.Add("Tool.smoke.desc", "Creates customizable smoke")
|
||||
language.Add("Tool.smoke.0", "Left-Click: Create smoke Right-Click: Remove smoke")
|
||||
language.Add("Cleanup_Smokes", "Smoke")
|
||||
language.Add("Cleaned_Smoke", "Cleaned up all Smoke")
|
||||
language.Add("SBoxLimit_Smokes", "You've hit the Smoke limit!")
|
||||
language.Add("Undone_Smoke", "Smoke undone")
|
||||
end
|
||||
|
||||
//Sandbox-related stuff
|
||||
cleanup.Register("Smokes")
|
||||
CreateConVar("sbox_maxsmokes", 10000, FCVAR_NOTIFY)
|
||||
|
||||
|
||||
//Create smoke
|
||||
function TOOL:LeftClick(trace)
|
||||
|
||||
//Clients don't need to know about any of this
|
||||
if (CLIENT) then return true end
|
||||
|
||||
//Check current spawnlimits
|
||||
if (!self:GetSWEP():CheckLimit("smokes")) then return false end
|
||||
|
||||
//Retreive settings
|
||||
local color_r = math.Round(math.Clamp(self:GetClientNumber("color_r"), 0, 255))
|
||||
local color_g = math.Round(math.Clamp(self:GetClientNumber("color_g"), 0, 255))
|
||||
local color_b = math.Round(math.Clamp(self:GetClientNumber("color_b"), 0, 255))
|
||||
local color_a = math.Round(math.Clamp(self:GetClientNumber("color_a"), 0, 255))
|
||||
local basespread = math.Clamp(self:GetClientNumber("spreadbase"), 0, 1024)
|
||||
local spreadspeed = math.Round(math.Clamp(self:GetClientNumber("spreadspeed"), 0, 1024))
|
||||
local speed = math.Round(math.Clamp(self:GetClientNumber("speed"), 0, 2048))
|
||||
local startsize = math.Clamp(self:GetClientNumber("startsize"), 0, 512)
|
||||
local endsize = math.Clamp(self:GetClientNumber("endsize"), 0, 512)
|
||||
local roll = math.Clamp(self:GetClientNumber("roll"), 0, 1024)
|
||||
local rate = math.Round(math.Clamp(self:GetClientNumber("numparticles"), 0, 512))
|
||||
local jetlength = math.Round(math.Clamp(self:GetClientNumber("jetlength"), 0, 4096))
|
||||
local twist = math.Clamp(self:GetClientNumber("twist"), 0, 1024)
|
||||
|
||||
//Create smoke and assign settings
|
||||
local smoke = ents.Create("env_smokestack")
|
||||
if !smoke || !smoke:IsValid() then return false end
|
||||
smoke:SetPos(trace.HitPos)
|
||||
if self:GetClientNumber("numpadcontrol") == 0 then smoke:SetKeyValue("InitialState", "1") else smoke:SetKeyValue("InitialState", "0") end
|
||||
smoke:SetKeyValue("WindAngle", "0 0 0")
|
||||
smoke:SetKeyValue("WindSpeed", "0")
|
||||
smoke:SetKeyValue("rendercolor", "" .. tostring(color_r) .. " " .. tostring(color_g) .. " " .. tostring(color_b) .. "")
|
||||
smoke:SetKeyValue("renderamt", "" .. tostring(color_a) .. "")
|
||||
smoke:SetKeyValue("SmokeMaterial", self:GetClientInfo("material"))
|
||||
smoke:SetKeyValue("BaseSpread", tostring(basespread))
|
||||
smoke:SetKeyValue("SpreadSpeed", tostring(spreadspeed))
|
||||
smoke:SetKeyValue("Speed", tostring(speed))
|
||||
smoke:SetKeyValue("StartSize", tostring(startsize))
|
||||
smoke:SetKeyValue("EndSize", tostring(endsize))
|
||||
smoke:SetKeyValue("roll", tostring(roll))
|
||||
smoke:SetKeyValue("Rate", tostring(rate))
|
||||
smoke:SetKeyValue("JetLength", tostring(jetlength))
|
||||
smoke:SetKeyValue("twist", tostring(twist))
|
||||
|
||||
//Spawn smoke
|
||||
smoke:Spawn()
|
||||
smoke:Activate()
|
||||
if trace && trace.Entity && trace.Entity:IsValid() && trace.Entity:GetPhysicsObject():IsValid() && !trace.Entity:IsPlayer() && !trace.Entity:IsWorld() then smoke:SetParent(trace.Entity) end
|
||||
|
||||
//Add to relevant lists
|
||||
self:GetOwner():AddCount("smokes", smoke)
|
||||
table.insert(self.Smokes, smoke)
|
||||
|
||||
//Make sure we can undo
|
||||
undo.Create("Smoke")
|
||||
undo.AddEntity(smoke)
|
||||
undo.SetPlayer(self:GetOwner())
|
||||
undo.Finish()
|
||||
cleanup.Add(self:GetOwner(), "Smokes", smoke)
|
||||
|
||||
//Make sure we can control it with numpad
|
||||
if self:GetClientNumber("numpadcontrol") == 1 then
|
||||
self:SetupNumpadControls(smoke)
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Setup numpad controls
|
||||
function TOOL:SetupNumpadControls(smoke)
|
||||
|
||||
//Safeguards
|
||||
if !smoke || !smoke:IsValid() || self:GetClientInfo("key") == nil || self:GetClientInfo("key") == -1 then return false end
|
||||
|
||||
//If not toggled
|
||||
if self:GetClientNumber("toggle") == 0 then
|
||||
|
||||
//Create KeyDown numpad functions
|
||||
local function StartEmitSmoke(ply, smoke)
|
||||
if !smoke || !smoke:IsValid() then return end
|
||||
|
||||
//Start smoke
|
||||
smoke:Fire("TurnOn", "", 0)
|
||||
|
||||
end
|
||||
|
||||
//Register KeyDown functions
|
||||
numpad.Register("StartEmitSmoke", StartEmitSmoke)
|
||||
numpad.OnDown(self:GetOwner(), self:GetClientNumber("key"), "StartEmitSmoke", smoke)
|
||||
|
||||
//Create KeyUp numpad functions
|
||||
local function StopEmitSmoke(ply, smoke)
|
||||
if !smoke || !smoke:IsValid() then return end
|
||||
|
||||
//Stop smoke
|
||||
smoke:Fire("TurnOff", "", 0)
|
||||
|
||||
end
|
||||
|
||||
//Register KeyUp functions
|
||||
numpad.Register("StopEmitSmoke", StopEmitSmoke)
|
||||
numpad.OnUp(self:GetOwner(), self:GetClientNumber("key"), "StopEmitSmoke", smoke)
|
||||
|
||||
end
|
||||
|
||||
//If toggled
|
||||
if self:GetClientNumber("toggle") == 1 then
|
||||
|
||||
smoke.Toggle = false
|
||||
|
||||
//Create KeyDown numpad functions
|
||||
local function ToggleEmitSmoke(ply, smoke)
|
||||
if !smoke || !smoke:IsValid() then return end
|
||||
|
||||
//Start smoke
|
||||
if !smoke.Toggle then
|
||||
smoke:Fire("TurnOn", "", 0)
|
||||
smoke.Toggle = true
|
||||
return
|
||||
end
|
||||
|
||||
//Stop smoke
|
||||
if discharge.Toggle then
|
||||
smoke:Fire("TurnOff", "", 0)
|
||||
smoke.Toggle = false
|
||||
return
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
//Register KeyDown functions
|
||||
numpad.Register("ToggleEmitSmoke", ToggleEmitSmoke)
|
||||
numpad.OnDown(self:GetOwner(), self:GetClientNumber("key"), "ToggleEmitSmoke", smoke)
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Remove smoke in radius
|
||||
function TOOL:RightClick(trace)
|
||||
|
||||
//Clients don't need to know about any of this
|
||||
if (CLIENT) then return false end
|
||||
|
||||
//Find smoke in radius
|
||||
local findsmoke = ents.FindInSphere(trace.HitPos, 128)
|
||||
for _, smoke in pairs(findsmoke) do
|
||||
|
||||
//Remove
|
||||
if smoke && smoke:IsValid() && !smoke:GetPhysicsObject():IsValid() && smoke:GetClass() == "env_smokestack" && !smoke:IsPlayer() && !smoke:IsNPC() && !smoke:IsWorld() then
|
||||
smoke:Fire("TurnOff", "", 0)
|
||||
smoke:Fire("Kill", "", 6)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Remove all smoke
|
||||
function TOOL:Reload()
|
||||
|
||||
//Clients don't need to know about any of this
|
||||
if (CLIENT) then return false end
|
||||
|
||||
//Get all smoke
|
||||
for x = 1, table.getn(self.Smokes) do
|
||||
local smoke = self.Smokes[x]
|
||||
|
||||
//Remove
|
||||
if smoke && smoke:IsValid() then
|
||||
smoke:Fire("TurnOff", "", 0)
|
||||
smoke:Fire("Kill", "", 6)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Build Tool Menu
|
||||
function TOOL.BuildCPanel(panel)
|
||||
|
||||
//Header
|
||||
panel:AddControl( "Header", { Text = "#Tool.smoke.name", Description = "#Tool.smoke.desc" } )
|
||||
|
||||
//Build preset menu and declare default preset
|
||||
local params = { Label = "#Presets", MenuButton = 1, Folder = "smoke", Options = {}, CVars = {} }
|
||||
|
||||
//Declare default preset
|
||||
params.Options.default = {
|
||||
smoke_color_r = 0,
|
||||
smoke_color_g = 0,
|
||||
smoke_color_b = 0,
|
||||
smoke_color_a = 21,
|
||||
smoke_material = "particle/smokesprites_0001.vmt",
|
||||
smoke_spreadbase = 6,
|
||||
smoke_spreadspeed = 8,
|
||||
smoke_speed = 32,
|
||||
smoke_startsize = 32,
|
||||
smoke_endsize = 32,
|
||||
smoke_roll = 8,
|
||||
smoke_numparticles = 32,
|
||||
smoke_jetlength = 256,
|
||||
smoke_twist = 6,
|
||||
}
|
||||
|
||||
//Declare console variables
|
||||
table.insert( params.CVars, "smoke_color_r" )
|
||||
table.insert( params.CVars, "smoke_color_g" )
|
||||
table.insert( params.CVars, "smoke_color_b" )
|
||||
table.insert( params.CVars, "smoke_color_a" )
|
||||
table.insert( params.CVars, "smoke_material" )
|
||||
table.insert( params.CVars, "smoke_spreadbase" )
|
||||
table.insert( params.CVars, "smoke_spreadspeed" )
|
||||
table.insert( params.CVars, "smoke_speed" )
|
||||
table.insert( params.CVars, "smoke_startsize" )
|
||||
table.insert( params.CVars, "smoke_endsize" )
|
||||
table.insert( params.CVars, "smoke_roll" )
|
||||
table.insert( params.CVars, "smoke_numparticles" )
|
||||
table.insert( params.CVars, "smoke_jetlength" )
|
||||
table.insert( params.CVars, "smoke_twist" )
|
||||
|
||||
//All done
|
||||
panel:AddControl( "ComboBox", params )
|
||||
|
||||
//Color picker
|
||||
panel:AddControl( "Color", { Label = "Smoke color", Red = "smoke_color_r", Green = "smoke_color_g", Blue = "smoke_color_b", Alpha = "smoke_color_a", ShowAlpha = "1", ShowHSV = "1", ShowRGB = "1", Multiplier = "255" } )
|
||||
//Smoke base size
|
||||
panel:AddControl( "Slider", { Label = "Smoke base size", Type = "Integer", Min = "0", Max = "64", Command ="smoke_spreadbase" } )
|
||||
//Spread speed
|
||||
panel:AddControl( "Slider", { Label = "Spread speed", Type = "Integer", Min = "0", Max = "32", Command ="smoke_spreadspeed" } )
|
||||
//Particle speed
|
||||
panel:AddControl( "Slider", { Label = "Particle speed", Type = "Integer", Min = "0", Max = "128", Command ="smoke_speed" } )
|
||||
//Particle start size
|
||||
panel:AddControl( "Slider", { Label = "Particle start size", Type = "Integer", Min = "0", Max = "64", Command ="smoke_startsize" } )
|
||||
//Particle end size
|
||||
panel:AddControl( "Slider", { Label = "Particle end size", Type = "Integer", Min = "0", Max = "64", Command ="smoke_endsize" } )
|
||||
//Particle roll
|
||||
panel:AddControl( "Slider", { Label = "Particle roll", Type = "Integer", Min = "0", Max = "256", Command ="smoke_roll" } )
|
||||
//Number of particles
|
||||
panel:AddControl( "Slider", { Label = "Number of particles", Type = "Integer", Min = "0", Max = "64", Command ="smoke_numparticles" } )
|
||||
//Height
|
||||
panel:AddControl( "Slider", { Label = "Height", Type = "Integer", Min = "0", Max = "512", Command ="smoke_jetlength" } )
|
||||
//Twist effect
|
||||
panel:AddControl( "Slider", { Label = "Twist effect", Type = "Integer", Min = "0", Max = "256", Command ="smoke_twist" } )
|
||||
//Material Picker
|
||||
local materials = {"particle/smokesprites_0001.vmt", "particle/particle_smokegrenade.vmt", "particle/SmokeStack.vmt"}
|
||||
panel:MatSelect( "smoke_material", materials, true, 0.33, 0.33 )
|
||||
|
||||
//-------------
|
||||
panel:AddControl( "Label", { Text = "________________________________________", Description = "" } )
|
||||
|
||||
//Numpad menu
|
||||
panel:AddControl( "Numpad", { Label = "Numpad Key", Command = "smoke_key", ButtonSize = 22 } )
|
||||
//Use numpad check
|
||||
panel:AddControl( "CheckBox", { Label = "Use numpad", Description = "", Command = "smoke_numpadcontrol" } )
|
||||
//Toggle check
|
||||
panel:AddControl( "CheckBox", { Label = "Toggle", Description = "", Command = "smoke_toggle" } )
|
||||
|
||||
end
|
||||
218
lua/weapons/gmod_tool/stools/smoke_trail.lua
Normal file
218
lua/weapons/gmod_tool/stools/smoke_trail.lua
Normal file
@@ -0,0 +1,218 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
TOOL.Category = "Matrix_'s Effects"
|
||||
TOOL.Name = "#Smoke - Trail"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
//Default values
|
||||
TOOL.ClientConVar["color_r"] = 132
|
||||
TOOL.ClientConVar["color_g"] = 132
|
||||
TOOL.ClientConVar["color_b"] = 132
|
||||
TOOL.ClientConVar["color_a"] = 142
|
||||
TOOL.ClientConVar["spawnradius"] = 8
|
||||
TOOL.ClientConVar["lifetime"] = 3
|
||||
TOOL.ClientConVar["startsize"] = 32
|
||||
TOOL.ClientConVar["endsize"] = 52
|
||||
TOOL.ClientConVar["minspeed"] = 4
|
||||
TOOL.ClientConVar["maxspeed"] = 8
|
||||
TOOL.ClientConVar["mindirectedspeed"] = 0
|
||||
TOOL.ClientConVar["maxdirectedspeed"] = 0
|
||||
TOOL.ClientConVar["spawnrate"] = 16
|
||||
|
||||
//List of all spawned fire entities
|
||||
TOOL.Smokes = {}
|
||||
|
||||
//Add language descriptions
|
||||
if (CLIENT) then
|
||||
language.Add("Tool.smoke_trail.name", "Smoke Trail Tool")
|
||||
language.Add("Tool.smoke_trail.desc", "Creates customizable smoke trails")
|
||||
language.Add("Tool.smoke_trail.0", "Left-Click: Attach smoke trail Right-Click: Remove trail")
|
||||
language.Add("Cleanup_SmokeTrails", "Smoke Trails")
|
||||
language.Add("Cleaned_SmokeTrail", "Cleaned up all Smoke Trails")
|
||||
language.Add("SBoxLimit_SmokeTrails", "You've hit the Smoke Trails limit!")
|
||||
language.Add("Undone_SmokeTrail", "Smoke Trail undone")
|
||||
end
|
||||
|
||||
//Sandbox-related stuff
|
||||
cleanup.Register("SmokeTrails")
|
||||
CreateConVar("sbox_maxsmoketrails", 10000, FCVAR_NOTIFY)
|
||||
|
||||
|
||||
//Create smoke
|
||||
function TOOL:LeftClick(trace)
|
||||
|
||||
//Clients don't need to know about any of this
|
||||
if (CLIENT) then return true end
|
||||
|
||||
//Check current spawnlimits
|
||||
if (!self:GetSWEP():CheckLimit("smoketrails")) then return false end
|
||||
|
||||
//Retreive settings
|
||||
local color_r = math.Round(math.Clamp(self:GetClientNumber("color_r"), 0, 255))
|
||||
local color_g = math.Round(math.Clamp(self:GetClientNumber("color_g"), 0, 255))
|
||||
local color_b = math.Round(math.Clamp(self:GetClientNumber("color_b"), 0, 255))
|
||||
local color_a = math.Clamp((math.Round(self:GetClientNumber("color_a")) / 255), 0, 255)
|
||||
local spawnradius = math.Clamp(self:GetClientNumber("spawnradius"), 0, 128)
|
||||
local lifetime = math.Clamp(self:GetClientNumber("lifetime"), 1, 16)
|
||||
local startsize = math.Clamp(self:GetClientNumber("startsize"), 0, 128)
|
||||
local endsize = math.Clamp(self:GetClientNumber("endsize"), 0, 128)
|
||||
local minspeed = math.Clamp(self:GetClientNumber("minspeed"), 0, 128)
|
||||
local maxspeed = math.Clamp(self:GetClientNumber("maxspeed"), 0, 128)
|
||||
local mindirectedspeed = math.Clamp(self:GetClientNumber("mindirectedspeed"), 0, 256)
|
||||
local maxdirectedspeed = math.Clamp(self:GetClientNumber("maxdirectedspeed"), 0, 256)
|
||||
local spawnrate = math.Clamp(self:GetClientNumber("spawnrate"), 1, 128)
|
||||
|
||||
//Create smoke trail and assign settings
|
||||
local smoke = ents.Create("env_smoketrail")
|
||||
if !smoke || !smoke:IsValid() then return false end
|
||||
smoke:SetPos(trace.HitPos)
|
||||
smoke:SetKeyValue("angles", tostring(trace.HitNormal:Angle()))
|
||||
smoke:SetKeyValue("emittime", "16384")
|
||||
smoke:SetKeyValue("startcolor", "" .. tostring(color_r) .. " " .. tostring(color_g) .. " " .. tostring(color_b) .. "")
|
||||
smoke:SetKeyValue("endcolor", "" .. tostring(color_r) .. " " .. tostring(color_g) .. " " .. tostring(color_b) .. "")
|
||||
smoke:SetKeyValue("opacity", tostring(color_a))
|
||||
smoke:SetKeyValue("spawnradius", tostring(spawnradius))
|
||||
smoke:SetKeyValue("lifetime", tostring(lifetime))
|
||||
smoke:SetKeyValue("startsize", tostring(startsize))
|
||||
smoke:SetKeyValue("endsize", tostring(endsize))
|
||||
smoke:SetKeyValue("minspeed", tostring(minspeed))
|
||||
smoke:SetKeyValue("maxspeed", tostring(maxspeed))
|
||||
smoke:SetKeyValue("mindirectedspeed", tostring(mindirectedspeed))
|
||||
smoke:SetKeyValue("maxdirectedspeed", tostring(maxdirectedspeed))
|
||||
smoke:SetKeyValue("spawnrate", tostring(spawnrate))
|
||||
|
||||
//Spawn trail
|
||||
smoke:Spawn()
|
||||
smoke:Activate()
|
||||
if trace && trace.Entity && trace.Entity:IsValid() && trace.Entity:GetPhysicsObject():IsValid() && !trace.Entity:IsPlayer() && !trace.Entity:IsWorld() then smoke:SetParent(trace.Entity) end
|
||||
|
||||
//Add to relevant lists
|
||||
self:GetOwner():AddCount("smoketrails", smoke)
|
||||
table.insert(self.Smokes, smoke)
|
||||
|
||||
//Make sure we can undo
|
||||
undo.Create("SmokeTrail")
|
||||
undo.AddEntity(smoke)
|
||||
undo.SetPlayer(self:GetOwner())
|
||||
undo.Finish()
|
||||
cleanup.Add(self:GetOwner(), "SmokeTrails", smoke)
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Remove trails in radius
|
||||
function TOOL:RightClick(trace)
|
||||
|
||||
//Clients don't need to know about any of this
|
||||
if (CLIENT) then return false end
|
||||
|
||||
//Find smoke in radius
|
||||
local findsmoke = ents.FindInSphere(trace.HitPos, 64)
|
||||
for _, smoke in pairs(findsmoke) do
|
||||
|
||||
//Remove
|
||||
if smoke && smoke:IsValid() && !smoke:GetPhysicsObject():IsValid() && smoke:GetClass() == "env_smoketrail" && !smoke:IsPlayer() && !smoke:IsNPC() && !smoke:IsWorld() then
|
||||
smoke:Fire("Kill", "", 0)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Remove all smoke
|
||||
function TOOL:Reload()
|
||||
|
||||
//Clients don't need to know about any of this
|
||||
if (CLIENT) then return false end
|
||||
|
||||
//Get all smoke
|
||||
for x = 1, table.getn(self.Smokes) do
|
||||
local smoke = self.Smokes[x]
|
||||
|
||||
//Remove
|
||||
if smoke && smoke:IsValid() then
|
||||
smoke:Fire("Kill", "", 0)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Build Tool Menu
|
||||
function TOOL.BuildCPanel(panel)
|
||||
|
||||
//Header
|
||||
panel:AddControl( "Header", { Text = "#Tool.smoke_trail.name", Description = "#Tool.smoke_trail.desc" } )
|
||||
|
||||
//Build preset menu and declare default preset
|
||||
local params = { Label = "#Presets", MenuButton = 1, Folder = "smoke_trail", Options = {}, CVars = {} }
|
||||
|
||||
//Declare default preset
|
||||
params.Options.default = {
|
||||
smoke_trail_color_r = 132,
|
||||
smoke_trail_color_g = 132,
|
||||
smoke_trail_color_b = 132,
|
||||
smoke_trail_color_a = 142,
|
||||
smoke_trail_spawnradius = 8,
|
||||
smoke_trail_lifetime = 3,
|
||||
smoke_trail_startsize = 32,
|
||||
smoke_trail_endsize = 52,
|
||||
smoke_trail_minspeed = 4,
|
||||
smoke_trail_maxspeed = 8,
|
||||
smoke_trail_mindirectedspeed = 0,
|
||||
smoke_trail_maxdirectedspeed = 0,
|
||||
smoke_trail_spawnrate = 16,
|
||||
}
|
||||
|
||||
//Declare console variables
|
||||
table.insert( params.CVars, "smoke_trail_color_r" )
|
||||
table.insert( params.CVars, "smoke_trail_color_g" )
|
||||
table.insert( params.CVars, "smoke_trail_color_b" )
|
||||
table.insert( params.CVars, "smoke_trail_color_a" )
|
||||
table.insert( params.CVars, "smoke_trail_spawnradius" )
|
||||
table.insert( params.CVars, "smoke_trail_lifetime" )
|
||||
table.insert( params.CVars, "smoke_trail_startsize" )
|
||||
table.insert( params.CVars, "smoke_trail_endsize" )
|
||||
table.insert( params.CVars, "smoke_trail_minspeed" )
|
||||
table.insert( params.CVars, "smoke_trail_maxspeed" )
|
||||
table.insert( params.CVars, "smoke_trail_mindirectedspeed" )
|
||||
table.insert( params.CVars, "smoke_trail_maxdirectedspeed" )
|
||||
table.insert( params.CVars, "smoke_trail_spawnrate" )
|
||||
|
||||
//All done
|
||||
panel:AddControl( "ComboBox", params )
|
||||
|
||||
//Color picker
|
||||
panel:AddControl( "Color", { Label = "Smoke color", Red = "smoke_trail_color_r", Green = "smoke_trail_color_g", Blue = "smoke_trail_color_b", Alpha = "smoke_trail_color_a", ShowAlpha = "1", ShowHSV = "1", ShowRGB = "1", Multiplier = "255" } )
|
||||
|
||||
//Spread base
|
||||
panel:AddControl( "Slider", { Label = "Spread base", Type = "Integer", Min = "0", Max = "32", Command ="smoke_trail_spawnradius" } )
|
||||
//Trail length
|
||||
panel:AddControl( "Slider", { Label = "Trail length", Type = "Integer", Min = "1", Max = "8", Command ="smoke_trail_lifetime" } )
|
||||
//Particle start size
|
||||
panel:AddControl( "Slider", { Label = "Particle start size", Type = "Integer", Min = "0", Max = "128", Command ="smoke_trail_startsize" } )
|
||||
//Particle end size
|
||||
panel:AddControl( "Slider", { Label = "Particle end size", Type = "Integer", Min = "0", Max = "128", Command ="smoke_trail_endsize" } )
|
||||
//Minimum particle spread
|
||||
panel:AddControl( "Slider", { Label = "Minimum particle spread", Type = "Integer", Min = "0", Max = "64", Command ="smoke_trail_minspeed" } )
|
||||
//Maximum particle spread
|
||||
panel:AddControl( "Slider", { Label = "Maximum particle spread", Type = "Integer", Min = "0", Max = "64", Command ="smoke_trail_maxspeed" } )
|
||||
//Minimum directional speed
|
||||
panel:AddControl( "Slider", { Label = "Minimum directional speed", Type = "Integer", Min = "0", Max = "256", Command ="smoke_trail_mindirectedspeed" } )
|
||||
//Maximum directional speed
|
||||
panel:AddControl( "Slider", { Label = "Maximum directional speed", Type = "Integer", Min = "0", Max = "256", Command ="smoke_trail_maxdirectedspeed" } )
|
||||
//Number of particles
|
||||
panel:AddControl( "Slider", { Label = "Number of particles", Type = "Integer", Min = "1", Max = "32", Command ="smoke_trail_spawnrate" } )
|
||||
|
||||
end
|
||||
261
lua/weapons/gmod_tool/stools/sparks.lua
Normal file
261
lua/weapons/gmod_tool/stools/sparks.lua
Normal file
@@ -0,0 +1,261 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
TOOL.Category = "Matrix_'s Effects"
|
||||
TOOL.Name = "#Sparks"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
//Default values
|
||||
TOOL.ClientConVar["maxdelay"] = 2
|
||||
TOOL.ClientConVar["magnitude"] = 2
|
||||
TOOL.ClientConVar["traillength"] = 2
|
||||
TOOL.ClientConVar["glow"] = 1
|
||||
TOOL.ClientConVar["makesound"] = 1
|
||||
TOOL.ClientConVar["key"] = 5
|
||||
TOOL.ClientConVar["numpadcontrol"] = 0
|
||||
TOOL.ClientConVar["toggle"] = 0
|
||||
|
||||
//List of all spawned fire entities
|
||||
TOOL.Sparks = {}
|
||||
|
||||
//Add language descriptions
|
||||
if (CLIENT) then
|
||||
language.Add("Tool.sparks.name", "Sparks Tool")
|
||||
language.Add("Tool.sparks.desc", "Creates customizable sparks")
|
||||
language.Add("Tool.sparks.0", "Left-Click: Create sparks Right-Click: Remove sparks")
|
||||
language.Add("Cleanup_Sparks", "Sparks")
|
||||
language.Add("Cleaned_Sparks", "Cleaned up all Sparks")
|
||||
language.Add("SBoxLimit_sparks", "You've hit the Sparks limit!")
|
||||
language.Add("Undone_Sparks", "Sparks undone")
|
||||
end
|
||||
|
||||
//Sandbox-related stuff
|
||||
cleanup.Register("Sparks")
|
||||
CreateConVar("sbox_maxsparks", 10000, FCVAR_NOTIFY)
|
||||
|
||||
|
||||
//Create sparks
|
||||
function TOOL:LeftClick(trace)
|
||||
|
||||
//Clients don't need to know about any of this
|
||||
if (CLIENT) then return true end
|
||||
|
||||
//Check current spawnlimits
|
||||
if (!self:GetSWEP():CheckLimit("sparks")) then return false end
|
||||
|
||||
//Retreive settings
|
||||
local spawnflags = 512 //Directional
|
||||
if self:GetClientNumber("numpadcontrol") == 0 then spawnflags = spawnflags + 64 end
|
||||
local maxdelay = math.Round(math.Clamp(self:GetClientNumber("maxdelay"), .12, 120)) //Integer
|
||||
local magnitude = math.Round(math.Clamp(self:GetClientNumber("magnitude"), .5, 15)) //Integer
|
||||
local traillength = math.Round(math.Clamp(self:GetClientNumber("traillength"), .12, 15)) //Float or Integer?
|
||||
if math.Round(math.Clamp(self:GetClientNumber("glow"), 0, 1)) == 1 then spawnflags = spawnflags + 128 end
|
||||
if math.Round(math.Clamp(self:GetClientNumber("makesound"), 0, 1)) == 0 then spawnflags = spawnflags + 256 end
|
||||
|
||||
//Create sparks and assign settings
|
||||
local sparks = ents.Create("env_spark")
|
||||
if !sparks || !sparks:IsValid() then return false end
|
||||
sparks:SetPos(trace.HitPos)
|
||||
sparks:SetKeyValue("angles", tostring(trace.HitNormal:Angle()))
|
||||
sparks:SetKeyValue("MaxDelay", tostring(maxdelay))
|
||||
sparks:SetKeyValue("Magnitude", tostring(magnitude))
|
||||
sparks:SetKeyValue("TrailLength", tostring(traillength))
|
||||
sparks:SetKeyValue("spawnflags", tostring(spawnflags))
|
||||
|
||||
//Spawn sparks
|
||||
sparks:Spawn()
|
||||
sparks:Activate()
|
||||
if trace && trace.Entity && trace.Entity:IsValid() && trace.Entity:GetPhysicsObject():IsValid() && !trace.Entity:IsPlayer() && !trace.Entity:IsWorld() then sparks:SetParent(trace.Entity) end
|
||||
|
||||
//Add to relevant lists
|
||||
self:GetOwner():AddCount("sparks", sparks)
|
||||
table.insert(self.Sparks, sparks)
|
||||
|
||||
//Make sure we can undo
|
||||
undo.Create("Sparks")
|
||||
undo.AddEntity(sparks)
|
||||
undo.SetPlayer(self:GetOwner())
|
||||
undo.Finish()
|
||||
cleanup.Add(self:GetOwner(), "Sparks", sparks)
|
||||
|
||||
//Make sure we can control it with numpad
|
||||
if self:GetClientNumber("numpadcontrol") == 1 then
|
||||
self:SetupNumpadControls(sparks)
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Setup numpad controls
|
||||
function TOOL:SetupNumpadControls(sparks)
|
||||
|
||||
//Safeguards
|
||||
if !sparks || !sparks:IsValid() || self:GetClientInfo("key") == nil || self:GetClientInfo("key") == -1 then return false end
|
||||
|
||||
//If not toggled
|
||||
if self:GetClientNumber("toggle") == 0 then
|
||||
|
||||
//Create KeyDown numpad functions
|
||||
local function StartEmitSparks(ply, sparks)
|
||||
if !sparks || !sparks:IsValid() then return end
|
||||
|
||||
//Start sparks
|
||||
sparks:Fire("SparkOnce", "", 0)
|
||||
sparks:Fire("StartSpark", "", 0)
|
||||
|
||||
end
|
||||
|
||||
//Register KeyDown functions
|
||||
numpad.Register("StartEmitSparks", StartEmitSparks)
|
||||
numpad.OnDown(self:GetOwner(), self:GetClientNumber("key"), "StartEmitSparks", sparks)
|
||||
|
||||
//Create KeyUp numpad functions
|
||||
local function StopEmitSparks(ply, sparks)
|
||||
if !sparks || !sparks:IsValid() then return end
|
||||
|
||||
//Stop sparks
|
||||
sparks:Fire("StopSpark", "", 0)
|
||||
|
||||
end
|
||||
|
||||
//Register KeyUp functions
|
||||
numpad.Register("StopEmitSparks", StopEmitSparks)
|
||||
numpad.OnUp(self:GetOwner(), self:GetClientNumber("key"), "StopEmitSparks", sparks)
|
||||
|
||||
end
|
||||
|
||||
//If toggled
|
||||
if self:GetClientNumber("toggle") == 1 then
|
||||
|
||||
sparks.Toggle = false
|
||||
|
||||
//Create KeyDown numpad functions
|
||||
local function ToggleEmitSparks(ply, sparks)
|
||||
if !sparks || !sparks:IsValid() then return end
|
||||
|
||||
//Start sparks
|
||||
if !sparks.Toggle then
|
||||
sparks:Fire("StartSpark", "", 0)
|
||||
sparks.Toggle = true
|
||||
return
|
||||
end
|
||||
|
||||
//Stop sparks
|
||||
if sparks.Toggle then
|
||||
sparks:Fire("StopSpark", "", 0)
|
||||
sparks.Toggle = false
|
||||
return
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
//Register KeyDown functions
|
||||
numpad.Register("ToggleEmitSparks", ToggleEmitSparks)
|
||||
numpad.OnDown(self:GetOwner(), self:GetClientNumber("key"), "ToggleEmitSparks", sparks)
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Remove sparks in radius
|
||||
function TOOL:RightClick(trace)
|
||||
|
||||
//Clients don't need to know about any of this
|
||||
if (CLIENT) then return false end
|
||||
|
||||
//Find sparks in radius
|
||||
local findsparks = ents.FindInSphere(trace.HitPos, 32)
|
||||
for _, sparks in pairs(findsparks) do
|
||||
|
||||
//Remove
|
||||
if sparks && sparks:IsValid() && !sparks:GetPhysicsObject():IsValid() && sparks:GetClass() == "env_spark" && !sparks:IsPlayer() && !sparks:IsNPC() && !sparks:IsWorld() then
|
||||
sparks:Fire("SparkOnce","",0)
|
||||
sparks:Fire("Kill", "", 0)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Remove all sparks
|
||||
function TOOL:Reload()
|
||||
|
||||
//Clients don't need to know about any of this
|
||||
if (CLIENT) then return false end
|
||||
|
||||
//Get all sparks
|
||||
for x = 1, table.getn(self.Sparks) do
|
||||
local sparks = self.Sparks[x]
|
||||
|
||||
//Remove
|
||||
if sparks && sparks:IsValid() then
|
||||
sparks:Fire("Kill", "", 0)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Build Tool Menu
|
||||
function TOOL.BuildCPanel(panel)
|
||||
|
||||
//Header
|
||||
panel:AddControl( "Header", { Text = "#Tool.sparks.name", Description = "#Tool.sparks.desc" } )
|
||||
|
||||
//Build preset menu and declare default preset
|
||||
local params = { Label = "#Presets", MenuButton = 1, Folder = "sparks", Options = {}, CVars = {} }
|
||||
|
||||
//Declare default preset
|
||||
params.Options.default = {
|
||||
sparks_maxdelay = 2,
|
||||
sparks_magnitude = 2,
|
||||
sparks_traillength = 2,
|
||||
sparks_glow = 1,
|
||||
sparks_makesound = 1,
|
||||
}
|
||||
|
||||
//Declare console variables
|
||||
table.insert( params.CVars, "sparks_maxdelay" )
|
||||
table.insert( params.CVars, "sparks_magnitude" )
|
||||
table.insert( params.CVars, "sparks_traillength" )
|
||||
table.insert( params.CVars, "sparks_glow" )
|
||||
table.insert( params.CVars, "sparks_makesound" )
|
||||
|
||||
//All done
|
||||
panel:AddControl( "ComboBox", params )
|
||||
|
||||
//Max delay
|
||||
panel:AddControl( "Slider", { Label = "Max Delay", Type = "Float", Min = "0", Max = "30", Command ="sparks_maxdelay" } )
|
||||
//Magnitude
|
||||
panel:AddControl( "Slider", { Label = "Magnitude", Type = "Float", Min = "0", Max = "10", Command ="sparks_magnitude" } )
|
||||
//Trail length
|
||||
panel:AddControl( "Slider", { Label = "Trail Length", Type = "Float", Min = "0", Max = "10", Command ="sparks_traillength" } )
|
||||
//Glow
|
||||
panel:AddControl( "CheckBox", { Label = "Glow", Description = "", Command = "sparks_glow" } )
|
||||
//Sound
|
||||
panel:AddControl( "CheckBox", { Label = "Sound", Description = "", Command = "sparks_makesound" } )
|
||||
|
||||
//-------------
|
||||
panel:AddControl( "Label", { Text = "________________________________________", Description = "" } )
|
||||
|
||||
//Numpad menu
|
||||
panel:AddControl( "Numpad", { Label = "Numpad Key", Command = "sparks_key", ButtonSize = 22 } )
|
||||
//Use numpad check
|
||||
panel:AddControl( "CheckBox", { Label = "Use numpad", Description = "", Command = "sparks_numpadcontrol" } )
|
||||
//Toggle check
|
||||
panel:AddControl( "CheckBox", { Label = "Toggle", Description = "", Command = "sparks_toggle" } )
|
||||
|
||||
end
|
||||
470
lua/weapons/gmod_tool/stools/stacker.lua
Normal file
470
lua/weapons/gmod_tool/stools/stacker.lua
Normal file
@@ -0,0 +1,470 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
TOOL.Category = "Construction"
|
||||
TOOL.Name = "#Tool.stacker.name"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
TOOL.ClientConVar[ "freeze" ] = "0"
|
||||
TOOL.ClientConVar[ "weld" ] = "0"
|
||||
TOOL.ClientConVar[ "nocollide" ] = "0"
|
||||
TOOL.ClientConVar[ "mode" ] = "1"
|
||||
TOOL.ClientConVar[ "dir" ] = "1"
|
||||
TOOL.ClientConVar[ "count" ] = "1"
|
||||
TOOL.ClientConVar[ "model" ] = ""
|
||||
TOOL.ClientConVar[ "offsetx" ] = "0"
|
||||
TOOL.ClientConVar[ "offsety" ] = "0"
|
||||
TOOL.ClientConVar[ "offsetz" ] = "0"
|
||||
TOOL.ClientConVar[ "rotp" ] = "0"
|
||||
TOOL.ClientConVar[ "roty" ] = "0"
|
||||
TOOL.ClientConVar[ "rotr" ] = "0"
|
||||
TOOL.ClientConVar[ "recalc" ] = "0"
|
||||
TOOL.ClientConVar[ "ghostall" ] = "1"
|
||||
TOOL.ClientConVar[ "halo" ] = "0"
|
||||
|
||||
if SERVER then
|
||||
util.AddNetworkString("StackGhost")
|
||||
util.AddNetworkString("UnstackGhost")
|
||||
end
|
||||
|
||||
if ( CLIENT ) then
|
||||
language.Add( "Tool.stacker.name", "Stacker" )
|
||||
language.Add( "Tool.stacker.desc", "Stacks Props Easily" )
|
||||
language.Add( "Tool.stacker.0", "Click To Stack The Prop You're Pointing At." )
|
||||
language.Add( "Undone_stacker", "Undone Stacked Prop(s)" )
|
||||
end
|
||||
|
||||
function TOOL:Holster()
|
||||
self:ReleaseGhostStack()
|
||||
end
|
||||
|
||||
function TOOL:Deploy()
|
||||
// self.StackedEnts = {}
|
||||
end
|
||||
|
||||
function TOOL:LeftClick(trace)
|
||||
if !trace.Entity || !trace.Entity:IsValid() || trace.Entity:GetClass() != "prop_physics" then return false end
|
||||
if CLIENT then return true end
|
||||
|
||||
local Freeze = self:GetClientNumber( "freeze" ) == 1
|
||||
local Weld = self:GetClientNumber( "weld" ) == 1
|
||||
local NoCollide = self:GetClientNumber( "nocollide" ) == 1
|
||||
local Mode = self:GetClientNumber( "mode" )
|
||||
local Dir = self:GetClientNumber( "dir" )
|
||||
local Count = self:GetClientNumber( "count" )
|
||||
local OffsetX = self:GetClientNumber( "offsetx" )
|
||||
local OffsetY = self:GetClientNumber( "offsety" )
|
||||
local OffsetZ = self:GetClientNumber( "offsetz" )
|
||||
local RotP = self:GetClientNumber( "rotp" )
|
||||
local RotY = self:GetClientNumber( "roty" )
|
||||
local RotR = self:GetClientNumber( "rotr" )
|
||||
local Recalc = self:GetClientNumber( "recalc" ) == 1
|
||||
local Offset = Vector(OffsetX, OffsetY, OffsetZ)
|
||||
local Rot = Angle(RotP, RotY, RotR)
|
||||
|
||||
local ply = self:GetOwner()
|
||||
local Ent = trace.Entity
|
||||
|
||||
local NewVec = Ent:GetPos()
|
||||
local NewAng = Ent:GetAngles()
|
||||
local LastEnt = Ent
|
||||
|
||||
//SimpleAdmin:Broadcast("COUNT IS " .. Count)
|
||||
if Count <= 0 then return false end
|
||||
|
||||
undo.Create("stacker")
|
||||
for i=1, Count, 1 do
|
||||
if (!self:GetSWEP():CheckLimit("props")) then break end
|
||||
|
||||
if i == 1 || (Mode == 2 && Recalc == true) then
|
||||
StackDir, Height, ThisOffset = self:StackerCalcPos(LastEnt, Mode, Dir, Offset)
|
||||
end
|
||||
|
||||
NewVec = NewVec + StackDir * Height + ThisOffset
|
||||
NewAng = NewAng + Rot
|
||||
|
||||
if !Ent:IsInWorld() then
|
||||
return false //Who put just break here? Seriously? Giving the player no hint he/she's not supposed to do that?
|
||||
end
|
||||
|
||||
// local EntList = ents.FindInSphere(NewVec, .2) //Searching in a sphere and find props
|
||||
// local PropValid = true //Flag if prop is found or not
|
||||
// for k, v in pairs(EntList) do //For loop
|
||||
// if (v:IsValid() && v:GetClass() == "prop_physics" && (v == LastEnt )) then//|| v:GetPos() == NewVec)) then
|
||||
// if (self:IsInGhostStack(v)) then continue end
|
||||
// PropValid = false
|
||||
// end
|
||||
// end
|
||||
// if !PropValid then return false end
|
||||
|
||||
NewEnt = ents.Create("prop_physics")
|
||||
NewEnt:SetModel(Ent:GetModel())
|
||||
NewEnt:SetColor(Ent:GetColor())
|
||||
NewEnt:SetPos(NewVec)
|
||||
NewEnt:SetAngles(NewAng)
|
||||
NewEnt:Spawn()
|
||||
if Freeze then
|
||||
ply:AddFrozenPhysicsObject(NewEnt, NewEnt:GetPhysicsObject()) //Fix so you can mass-unfreeze
|
||||
NewEnt:GetPhysicsObject():EnableMotion(false)
|
||||
else
|
||||
NewEnt:GetPhysicsObject():Wake()
|
||||
end
|
||||
|
||||
if Weld then
|
||||
local WeldEnt = constraint.Weld( LastEnt, NewEnt, 0, 0, 0 )
|
||||
undo.AddEntity(WeldEnt)
|
||||
end
|
||||
|
||||
if NoCollide then
|
||||
local NoCollideEnt = constraint.NoCollide(LastEnt, NewEnt, 0, 0)
|
||||
undo.AddEntity(NoCollideEnt)
|
||||
end
|
||||
|
||||
LastEnt = NewEnt
|
||||
undo.AddEntity(NewEnt)
|
||||
ply:AddCount("props", NewEnt)
|
||||
ply:AddCleanup("props", NewEnt)
|
||||
|
||||
if PropDefender && PropDefender.Player && PropDefender.Player.Give then
|
||||
PropDefender.Player.Give(ply, NewEnt, false)
|
||||
end
|
||||
|
||||
//table.insert(self.StackedEnts, NewEnt)
|
||||
end
|
||||
undo.SetPlayer(ply)
|
||||
undo.Finish()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:StackerCalcPos(lastent, mode, dir, offset)
|
||||
local forward = Vector(1,0,0):Angle()
|
||||
local pos = lastent:GetPos()
|
||||
local ang = lastent:GetAngles()
|
||||
|
||||
local lower, upper = lastent:WorldSpaceAABB( )
|
||||
local glower = lastent:OBBMins()
|
||||
local gupper = lastent:OBBMaxs()
|
||||
|
||||
local stackdir = Vector(0,0,1)
|
||||
local height = math.abs(upper.z - lower.z)
|
||||
|
||||
if mode == 1 then // Relative to world
|
||||
if dir == 1 then
|
||||
stackdir = forward:Up()
|
||||
height = math.abs(upper.z - lower.z)
|
||||
elseif dir == 2 then
|
||||
stackdir = forward:Up() * -1
|
||||
height = math.abs(upper.z - lower.z)
|
||||
elseif dir == 3 then
|
||||
stackdir = forward:Forward()
|
||||
height = math.abs(upper.x - lower.x)
|
||||
elseif dir == 4 then
|
||||
stackdir = forward:Forward() * -1
|
||||
height = math.abs(upper.x - lower.x)
|
||||
elseif dir == 5 then
|
||||
stackdir = forward:Right()
|
||||
height = math.abs(upper.y - lower.y)
|
||||
elseif dir == 6 then
|
||||
stackdir = forward:Right() * -1
|
||||
height = math.abs(upper.y - lower.y)
|
||||
end
|
||||
elseif mode == 2 then // Relative to prop
|
||||
forward = ang
|
||||
if dir == 1 then
|
||||
stackdir = forward:Up()
|
||||
offset = forward:Up() * offset.X + forward:Forward() * -1 * offset.Z + forward:Right() * offset.Y
|
||||
height = math.abs(gupper.z - glower.z)
|
||||
elseif dir == 2 then
|
||||
stackdir = forward:Up() * -1
|
||||
offset = forward:Up() * -1 * offset.X + forward:Forward() * offset.Z + forward:Right() * offset.Y
|
||||
height = math.abs(gupper.z - glower.z)
|
||||
elseif dir == 3 then
|
||||
stackdir = forward:Forward()
|
||||
offset = forward:Forward() * offset.X + forward:Up() * offset.Z + forward:Right() * offset.Y
|
||||
height = math.abs(gupper.x - glower.x)
|
||||
elseif dir == 4 then
|
||||
stackdir = forward:Forward() * -1
|
||||
offset = forward:Forward() * -1 * offset.X + forward:Up() * offset.Z + forward:Right() * -1 * offset.Y
|
||||
height = math.abs(gupper.x - glower.x)
|
||||
elseif dir == 5 then
|
||||
stackdir = forward:Right()
|
||||
offset = forward:Right() * offset.X + forward:Up() * offset.Z + forward:Forward() * -1 * offset.Y
|
||||
height = math.abs(gupper.y - glower.y)
|
||||
elseif dir == 6 then
|
||||
stackdir = forward:Right() * -1
|
||||
offset = forward:Right() * -1 * offset.X + forward:Up() * offset.Z + forward:Forward() * offset.Y
|
||||
height = math.abs(gupper.y - glower.y)
|
||||
end
|
||||
end //offset = (stackdir:Angle():Up() * offset.Z) + (stackdir:Angle():Forward() * offset.X) + (stackdir:Angle():Right() * offset.Y)
|
||||
|
||||
return stackdir, height, offset
|
||||
end
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
CPanel:AddControl("Header", { Text = "#Tool.stacker.name", Description = "#Tool.stacker.desc" })
|
||||
|
||||
CPanel:AddControl( "Checkbox", { Label = "Freeze Props", Command = "stacker_freeze" } )
|
||||
CPanel:AddControl( "Checkbox", { Label = "Weld Props", Command = "stacker_weld" } )
|
||||
CPanel:AddControl( "Checkbox", { Label = "No Collide Props", Command = "stacker_nocollide" } )
|
||||
|
||||
local params = {Label = "Relative To:", MenuButton = "0", Options = {}}
|
||||
params.Options["World"] = {stacker_mode = "1"}
|
||||
params.Options["Prop"] = {stacker_mode = "2"}
|
||||
CPanel:AddControl( "ComboBox", params )
|
||||
|
||||
local params = {Label = "Stack Direction", MenuButton = "0", Options = {}}
|
||||
params.Options["Up"] = {stacker_dir = "1"}
|
||||
params.Options["Down"] = {stacker_dir = "2"}
|
||||
params.Options["Front"] = {stacker_dir = "3"}
|
||||
params.Options["Behind"] = {stacker_dir = "4"}
|
||||
params.Options["Right"] = {stacker_dir = "5"}
|
||||
params.Options["Left"] = {stacker_dir = "6"}
|
||||
CPanel:AddControl( "ComboBox", params )
|
||||
|
||||
CPanel:AddControl( "Slider", { Label = "Count",
|
||||
Type = "Integer",
|
||||
Min = 1,
|
||||
Max = 100,
|
||||
Command = "stacker_count",
|
||||
Description = "How many props to stack."} )
|
||||
|
||||
CPanel:AddControl( "Header", { Text = "Advanced Options", Description = "These options are for advanced users. Leave them all default (0) if you don't understand what they do." } )
|
||||
CPanel:AddControl( "Button", { Label = "Reset Advanced Options",
|
||||
Command = "stacker_resetoffsets",
|
||||
Text = "Reset"} )
|
||||
CPanel:AddControl( "Slider", { Label = "Offset X (forward/back)",
|
||||
Type = "Float",
|
||||
Min = -1000,
|
||||
Max = 1000,
|
||||
Value = 0,
|
||||
Command = "stacker_offsetx"} )
|
||||
CPanel:AddControl( "Slider", { Label = "Offset Y (right/left)",
|
||||
Type = "Float",
|
||||
Min = -1000,
|
||||
Max = 1000,
|
||||
Value = 0,
|
||||
Command = "stacker_offsety"} )
|
||||
CPanel:AddControl( "Slider", { Label = "Offset Z (up/down)",
|
||||
Type = "Float",
|
||||
Min = -1000,
|
||||
Max = 1000,
|
||||
Value = 0,
|
||||
Command = "stacker_offsetz"} )
|
||||
CPanel:AddControl( "Slider", { Label = "Rotate Pitch",
|
||||
Type = "Float",
|
||||
Min = -360,
|
||||
Max = 360,
|
||||
Value = 0,
|
||||
Command = "stacker_rotp"} )
|
||||
CPanel:AddControl( "Slider", { Label = "Rotate Yaw",
|
||||
Type = "Float",
|
||||
Min = -360,
|
||||
Max = 360,
|
||||
Value = 0,
|
||||
Command = "stacker_roty"} )
|
||||
CPanel:AddControl( "Slider", { Label = "Rotate Roll",
|
||||
Type = "Float",
|
||||
Min = -360,
|
||||
Max = 360,
|
||||
Value = 0,
|
||||
Command = "stacker_rotr"} )
|
||||
CPanel:AddControl( "Checkbox", { Label = "Stack relative to new rotation", Command = "stacker_recalc", Description = "If this is checked, each item in the stack will be stacked relative to the previous item in the stack. This allows you to create curved stacks." } )
|
||||
CPanel:AddControl("Checkbox", {Label = "Ghost ALL of the props?", Command = "stacker_ghostall", Description = "Ghost all of the props specified by count"})
|
||||
CPanel:AddControl("Checkbox", {Label = "Give ghosted props halos?", Command = "stacker_halo", Description = "Give the ghost a halo"})
|
||||
end
|
||||
|
||||
if (CLIENT) then
|
||||
local function ResetOffsets(ply, command, arguments)
|
||||
-- Reset all of the offset options to 0
|
||||
LocalPlayer():ConCommand("stacker_offsetx 0\n")
|
||||
LocalPlayer():ConCommand("stacker_offsety 0\n")
|
||||
LocalPlayer():ConCommand("stacker_offsetz 0\n")
|
||||
LocalPlayer():ConCommand("stacker_rotp 0\n")
|
||||
LocalPlayer():ConCommand("stacker_roty 0\n")
|
||||
LocalPlayer():ConCommand("stacker_rotr 0\n")
|
||||
LocalPlayer():ConCommand("stacker_recalc 0\n")
|
||||
end
|
||||
concommand.Add( "stacker_resetoffsets", ResetOffsets )
|
||||
end
|
||||
|
||||
function TOOL:UpdateGhostStack(ent)
|
||||
if (!ent || !ent:IsValid() || !self:CheckGhostStack()) then return end
|
||||
|
||||
local mode = self:GetClientNumber( "mode" )
|
||||
local dir = self:GetClientNumber( "dir" )
|
||||
local offsetx = self:GetClientNumber( "offsetx" )
|
||||
local offsety = self:GetClientNumber( "offsety" )
|
||||
local offsetz = self:GetClientNumber( "offsetz" )
|
||||
local rotp = self:GetClientNumber( "rotp" )
|
||||
local roty = self:GetClientNumber( "roty" )
|
||||
local rotr = self:GetClientNumber( "rotr" )
|
||||
local offset = Vector(offsetx, offsety, offsetz)
|
||||
local rot = Angle(rotp, roty, rotr)
|
||||
local count = self:GetClientNumber("count")
|
||||
local recalc = self:GetClientNumber( "recalc" ) == 1
|
||||
|
||||
local NewEnt = ent
|
||||
local NewVec = NewEnt:GetPos()
|
||||
local NewAng = NewEnt:GetAngles()
|
||||
|
||||
local stackdir, height, thisoffset
|
||||
|
||||
for k,v in pairs(self.GhostStack) do
|
||||
if k == 1 || (mode == 2 && recalc == true) then
|
||||
stackdir, height, thisoffset = self:StackerCalcPos(NewEnt, mode, dir, offset)
|
||||
end
|
||||
|
||||
NewVec = NewVec + stackdir * height + thisoffset
|
||||
NewAng = NewAng + rot
|
||||
|
||||
v:SetAngles(NewAng)
|
||||
v:SetPos(NewVec)
|
||||
v:SetNoDraw(false)
|
||||
NewEnt = v
|
||||
//SimpleAdmin:Broadcast(k .. ": " .. tostring(NewAng) .. " : " .. tostring(NewVec) .. " : " .. tostring(v) .. ".")
|
||||
end
|
||||
end
|
||||
|
||||
function TOOL:CheckGhostStack() //Returns if stack is ok
|
||||
if !self.GhostStack then return false end
|
||||
local count = self:GetClientNumber("count")
|
||||
for k,v in pairs(self.GhostStack) do
|
||||
if (!v || !v:IsValid()) then //if something in the table doesn't exist or it's a null entity tell em it's not ok
|
||||
return false
|
||||
end
|
||||
end
|
||||
if (table.Count(self.GhostStack) != count && (self:GetClientNumber("ghostall") == 1)) then
|
||||
return false
|
||||
elseif (table.Count(self.GhostStack) != 1 && (self:GetClientNumber("ghostall") == 0)) then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:IsInGhostStack(ent)
|
||||
if !self.GhostStack then return false end
|
||||
for k,v in pairs(self.GhostStack) do
|
||||
if (ent == v) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function TOOL:CreateGhostStack(prop, pos, ang)
|
||||
if(self.GhostStack) then self:ReleaseGhostStack() end
|
||||
self.GhostStack = {}
|
||||
|
||||
if (SERVER && !game.SinglePlayer()) then return false end
|
||||
if (CLIENT && game.SinglePlayer()) then return false end
|
||||
|
||||
local Halo = self:GetClientNumber("halo") == 1
|
||||
local Count = self:GetClientNumber("count")
|
||||
local GhostAll = (self:GetClientNumber("ghostall") == 1)
|
||||
if (!GhostAll && Count != 0) then
|
||||
Count = 1
|
||||
end
|
||||
|
||||
for i = 1, Count, 1 do
|
||||
local Ghost
|
||||
|
||||
if ( CLIENT ) then
|
||||
Ghost = ents.CreateClientProp(prop)
|
||||
else
|
||||
Ghost = ents.Create("prop_physics")
|
||||
end
|
||||
|
||||
if (!Ghost:IsValid()) then
|
||||
Ghost = nil
|
||||
return
|
||||
end
|
||||
|
||||
Ghost:SetModel(prop)
|
||||
Ghost:SetPos(pos)
|
||||
Ghost:SetAngles(ang)
|
||||
Ghost:Spawn()
|
||||
|
||||
Ghost:SetSolid(SOLID_VPHYSICS)
|
||||
Ghost:SetMoveType(MOVETYPE_NONE)
|
||||
Ghost:SetNotSolid(true)
|
||||
Ghost:SetRenderMode(RENDERMODE_TRANSALPHA)
|
||||
Ghost:SetColor(Color(255, 255, 255, 150))
|
||||
|
||||
table.insert(self.GhostStack, Ghost)
|
||||
if SERVER && Halo then
|
||||
net.Start("StackGhost")
|
||||
net.WriteTable({self.GhostStack})
|
||||
net.Send(self:GetOwner())
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function TOOL:ReleaseGhostStack()
|
||||
if !self.GhostStack then return end
|
||||
for k,v in pairs(self.GhostStack) do
|
||||
if !v || !v:IsValid() then continue end
|
||||
v:Remove()
|
||||
end
|
||||
if SERVER then
|
||||
net.Start("UnstackGhost")
|
||||
net.WriteDouble(1)
|
||||
net.Send(self:GetOwner())
|
||||
end
|
||||
table.Empty(self.GhostStack)
|
||||
end
|
||||
|
||||
function TOOL:Think()
|
||||
local ply = self:GetOwner()
|
||||
local trace = ply:GetEyeTrace()
|
||||
local stacked = false
|
||||
if (IsValid(trace.Entity) && trace.Hit && trace.Entity:GetClass() == "prop_physics") then
|
||||
self.NewEnt = trace.Entity
|
||||
if (self.NewEnt:IsValid() && self.NewEnt != self.LastEnt) then
|
||||
//SimpleAdmin:Broadcast("Creating new stack.")
|
||||
stacked = self:CreateGhostStack(self.NewEnt:GetModel(), Vector(0,0,0), Angle(0,0,0))
|
||||
if stacked then self.LastEnt = self.NewEnt end
|
||||
end
|
||||
if (!self:CheckGhostStack()) then
|
||||
//SimpleAdmin:Broadcast("Releasing old stack.")
|
||||
self:ReleaseGhostStack()
|
||||
self.LastEnt = nil
|
||||
end
|
||||
elseif ((IsValid(trace.Entity) && trace.Entity:GetClass() != "prop_physics" && self.LastEnt != nil) || !IsValid(trace.Entity)) then
|
||||
//SimpleAdmin:Broadcast("Releasing old stack.")
|
||||
self:ReleaseGhostStack()
|
||||
self.LastEnt = nil
|
||||
end
|
||||
if (self.LastEnt != nil && self.LastEnt:IsValid()) then
|
||||
//SimpleAdmin:Broadcast("Updating old stack.")
|
||||
self:UpdateGhostStack(self.LastEnt)
|
||||
end
|
||||
if CLIENT then
|
||||
//MsgN(tostring(table.Count(self.GhostStack)) .. " : " .. tostring(table.Count(self)))
|
||||
if (!GhostStack || table.Count(GhostStack) <= 0) then return end
|
||||
for k, v in pairs(GhostStack) do
|
||||
halo.Add({v}, Color(181, 0, 217))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function StackGhost()
|
||||
local tbl = net.ReadTable()
|
||||
GhostStack = tbl[1]
|
||||
end
|
||||
net.Receive("StackGhost", StackGhost)
|
||||
|
||||
function UnstackGhost()
|
||||
if !GhostStack then return end
|
||||
table.Empty(GhostStack)
|
||||
end
|
||||
net.Receive("UnstackGhost", UnstackGhost)
|
||||
1691
lua/weapons/gmod_tool/stools/stacker_improved.lua
Normal file
1691
lua/weapons/gmod_tool/stools/stacker_improved.lua
Normal file
File diff suppressed because it is too large
Load Diff
104
lua/weapons/gmod_tool/stools/starfield.lua
Normal file
104
lua/weapons/gmod_tool/stools/starfield.lua
Normal file
@@ -0,0 +1,104 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
if !game.SinglePlayer() then TOOL.AddToMenu = false return end //Not available in Multiplayer, don't add this. Enables for all players, feel free to adapt this one yourself.
|
||||
|
||||
TOOL.Category = "Matrix_'s Effects"
|
||||
TOOL.Name = "#Starfield"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
//Default values
|
||||
TOOL.ClientConVar["magnitude"] = 4
|
||||
|
||||
//Add language descriptions
|
||||
if (CLIENT) then
|
||||
language.Add("Tool.starfield.name", "Starfield Tool")
|
||||
language.Add("Tool.starfield.desc", "Creates a starfield effect")
|
||||
language.Add("Tool.starfield.0", "Left-Click: Update starfield layer Right-Click: Remove effect")
|
||||
language.Add("Cleanup_Starfields", "Starfield Effects")
|
||||
language.Add("Cleaned_Starfields", "Cleaned up all Starfield Effects")
|
||||
language.Add("Undone_Starfield", "Starfield Effect undone")
|
||||
end
|
||||
|
||||
//Sandbox-related stuff
|
||||
cleanup.Register("Starfields")
|
||||
|
||||
//Add starfield layer
|
||||
function TOOL:LeftClick(trace)
|
||||
|
||||
//Only serverside now
|
||||
if (CLIENT) then return false end
|
||||
|
||||
//Get all entities on the level
|
||||
for _, fire in pairs(ents.GetAll()) do
|
||||
|
||||
//Kill all starfields
|
||||
if fire && fire:IsValid() && !fire:GetPhysicsObject():IsValid() && fire:GetClass() == "env_starfield" && !fire:IsPlayer() && !fire:IsNPC() && !fire:IsWorld() then
|
||||
fire:Fire("Kill", "", 0)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
//Retreive settings
|
||||
local magnitude = math.Clamp(self:GetClientNumber("magnitude"), 1, 128)
|
||||
|
||||
//Create effect layer and assign settings
|
||||
local starfield = ents.Create("env_starfield")
|
||||
if !starfield || !starfield:IsValid() then return false end
|
||||
starfield:SetPos(self:GetOwner():GetPos())
|
||||
//starfield:SetParent(self:GetOwner())
|
||||
|
||||
//Spawn effect
|
||||
starfield:Spawn()
|
||||
starfield:Activate()
|
||||
starfield:Fire("SetDensity", tostring(magnitude), 0)
|
||||
starfield:Fire("TurnOn", "", 0)
|
||||
|
||||
//Make sure we can undo
|
||||
undo.Create("Starfield")
|
||||
undo.AddEntity(starfield)
|
||||
undo.SetPlayer(self:GetOwner())
|
||||
undo.Finish()
|
||||
cleanup.Add(self:GetOwner(), "Starfields", starfield)
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Extinguish fire in radius
|
||||
function TOOL:RightClick(trace)
|
||||
|
||||
//Only serverside now
|
||||
if (CLIENT) then return false end
|
||||
|
||||
//Get all entities on the level
|
||||
for _, fire in pairs(ents.GetAll()) do
|
||||
|
||||
//Kill all starfields
|
||||
if fire && fire:IsValid() && !fire:GetPhysicsObject():IsValid() && fire:GetClass() == "env_starfield" && !fire:IsPlayer() && !fire:IsNPC() && !fire:IsWorld() then
|
||||
fire:Fire("Kill", "", 0)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
//Build Tool Menu
|
||||
function TOOL.BuildCPanel(panel)
|
||||
|
||||
//Header
|
||||
panel:AddControl( "Header", { Text = "#Tool.starfield.name", Description = "#Tool.starfield.desc" } )
|
||||
|
||||
//Magnitude
|
||||
panel:AddControl( "Slider", { Label = "Magnitude", Type = "Integer", Min = "1", Max = "128", Command ="starfield_magnitude" } )
|
||||
|
||||
end
|
||||
344
lua/weapons/gmod_tool/stools/steam.lua
Normal file
344
lua/weapons/gmod_tool/stools/steam.lua
Normal file
@@ -0,0 +1,344 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
TOOL.Category = "Matrix_'s Effects"
|
||||
TOOL.Name = "#Steam"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
//Default values
|
||||
TOOL.ClientConVar["color_r"] = 150
|
||||
TOOL.ClientConVar["color_g"] = 150
|
||||
TOOL.ClientConVar["color_b"] = 150
|
||||
TOOL.ClientConVar["color_a"] = 200
|
||||
TOOL.ClientConVar["jetlength"] = 150
|
||||
TOOL.ClientConVar["spreadspeed"] = 21
|
||||
TOOL.ClientConVar["speed"] = 200
|
||||
TOOL.ClientConVar["startsize"] = 16
|
||||
TOOL.ClientConVar["endsize"] = 32
|
||||
TOOL.ClientConVar["rate"] = 32
|
||||
TOOL.ClientConVar["rollspeed"] = 12
|
||||
TOOL.ClientConVar["emissive"] = 1
|
||||
TOOL.ClientConVar["heatwave"] = 1
|
||||
TOOL.ClientConVar["makesound"] = 1
|
||||
TOOL.ClientConVar["key"] = 5
|
||||
TOOL.ClientConVar["numpadcontrol"] = 0
|
||||
TOOL.ClientConVar["toggle"] = 0
|
||||
|
||||
//List of all spawned fire entities
|
||||
TOOL.Steams = {}
|
||||
|
||||
//Add language descriptions
|
||||
if (CLIENT) then
|
||||
language.Add("Tool.steam.name", "Steam Tool")
|
||||
language.Add("Tool.steam.desc", "Creates customizable steam")
|
||||
language.Add("Tool.steam.0", "Left-Click: Create steam Right-Click: Remove steam")
|
||||
language.Add("Cleanup_Steams", "Steams")
|
||||
language.Add("Cleaned_Steams", "Cleaned up all Steams")
|
||||
language.Add("SBoxLimit_Steams", "You've hit the Steams limit!")
|
||||
language.Add("Undone_Steam", "Steam undone")
|
||||
end
|
||||
|
||||
//Sandbox-related stuff
|
||||
cleanup.Register("Steams")
|
||||
CreateConVar("sbox_maxsteams", 10000, FCVAR_NOTIFY)
|
||||
|
||||
|
||||
//Create steam
|
||||
function TOOL:LeftClick(trace)
|
||||
|
||||
//Clients don't need to know about any of this
|
||||
if (CLIENT) then return true end
|
||||
|
||||
//Check current spawnlimits
|
||||
if (!self:GetSWEP():CheckLimit("steams")) then return false end
|
||||
|
||||
//Retreive settings
|
||||
local color_r = math.Round(math.Clamp(self:GetClientNumber("color_r"), 0, 255))
|
||||
local color_g = math.Round(math.Clamp(self:GetClientNumber("color_g"), 0, 255))
|
||||
local color_b = math.Round(math.Clamp(self:GetClientNumber("color_b"), 0, 255))
|
||||
local color_a = math.Round(math.Clamp(self:GetClientNumber("color_a"), 0, 255))
|
||||
local jetlength = math.Round(math.Clamp(self:GetClientNumber("jetlength"), 8, 1024))
|
||||
local spreadspeed = math.Round(math.Clamp(self:GetClientNumber("spreadspeed"), 0, 1024))
|
||||
local speed = math.Round(math.Clamp(self:GetClientNumber("speed"), 0, 4096))
|
||||
local startsize = math.Round(math.Clamp(self:GetClientNumber("startsize"), 0, 128))
|
||||
local endsize = math.Round(math.Clamp(self:GetClientNumber("endsize"), 0, 128))
|
||||
local rate = math.Round(math.Clamp(self:GetClientNumber("rate"), 1, 2048))
|
||||
local rollspeed = math.Clamp(self:GetClientNumber("rollspeed"), 0, 128)
|
||||
|
||||
//Create steam and assign settings
|
||||
local steam = ents.Create("env_steam")
|
||||
if !steam || !steam:IsValid() then return false end
|
||||
steam:SetPos(trace.HitPos)
|
||||
if self:GetClientNumber("numpadcontrol") == 0 then steam:SetKeyValue("InitialState", "1") else steam:SetKeyValue("InitialState", "0") end
|
||||
steam:SetKeyValue("angles", tostring(trace.HitNormal:Angle()))
|
||||
steam:SetKeyValue("rendercolor", "" .. tostring(color_r) .. " " .. tostring(color_g) .. " " .. tostring(color_b) .. "")
|
||||
steam:SetKeyValue("renderamt", "" .. tostring(color_a) .. "")
|
||||
steam:SetKeyValue("JetLength", tostring(jetlength))
|
||||
steam:SetKeyValue("SpreadSpeed", tostring(spreadspeed))
|
||||
steam:SetKeyValue("Speed", tostring(speed))
|
||||
steam:SetKeyValue("StartSize", tostring(startsize))
|
||||
steam:SetKeyValue("EndSize", tostring(endsize))
|
||||
steam:SetKeyValue("Rate", tostring(rate))
|
||||
steam:SetKeyValue("rollspeed", tostring(rollspeed))
|
||||
if math.Round(math.Clamp(self:GetClientNumber("emissive"), 0, 1)) == 1 then steam:SetKeyValue("spawnflags", "1") end
|
||||
if math.Round(math.Clamp(self:GetClientNumber("heatwave"), 0, 1)) == 1 then steam:SetKeyValue("type", "1") else steam:SetKeyValue("type", "0") end
|
||||
|
||||
//Make steam emit hissing sounds
|
||||
if math.Round(math.Clamp(self:GetClientNumber("makesound"), 0, 1)) == 1 then
|
||||
steam.MakesSound = true
|
||||
if math.Round(math.Clamp(self:GetClientNumber("heatwave"), 0, 1)) == 1 then steam.Heatwave = true steam.Sound = CreateSound(steam, Sound("ambient/gas/cannister_loop.wav")) else steam.Sound = CreateSound(steam, Sound("ambient/gas/steam2.wav")) end
|
||||
if self:GetClientNumber("numpadcontrol") == 0 then sound.Play( "HL1/ambience/steamburst1.wav", trace.HitPos, 60, 100 ) steam.Sound:PlayEx(0.42, 100) end
|
||||
end
|
||||
|
||||
//Spawn steam
|
||||
steam:Spawn()
|
||||
steam:Activate()
|
||||
if trace && trace.Entity && trace.Entity:IsValid() && trace.Entity:GetPhysicsObject():IsValid() && !trace.Entity:IsPlayer() && !trace.Entity:IsWorld() then steam:SetParent(trace.Entity) end
|
||||
|
||||
//Add to relevant lists
|
||||
self:GetOwner():AddCount("steams", steam)
|
||||
table.insert(self.Steams, steam)
|
||||
|
||||
//Make sure we can undo
|
||||
undo.Create("Steam")
|
||||
undo.AddEntity(steam)
|
||||
undo.SetPlayer(self:GetOwner())
|
||||
undo.Finish()
|
||||
cleanup.Add(self:GetOwner(), "Steams", steam)
|
||||
|
||||
//Make sure we can control it with numpad
|
||||
if self:GetClientNumber("numpadcontrol") == 1 then
|
||||
self:SetupNumpadControls(steam)
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Setup numpad controls
|
||||
function TOOL:SetupNumpadControls(steam)
|
||||
|
||||
//Safeguards
|
||||
if !steam || !steam:IsValid() || self:GetClientInfo("key") == nil || self:GetClientInfo("key") == -1 then return false end
|
||||
|
||||
//If not toggled
|
||||
if self:GetClientNumber("toggle") == 0 then
|
||||
|
||||
//Create KeyDown numpad functions
|
||||
local function StartEmitSteam(ply, steam)
|
||||
if !steam || !steam:IsValid() then return end
|
||||
|
||||
//Start steam and related sounds
|
||||
if steam.MakesSound then
|
||||
if steam.Sound then steam.Sound:Stop() end
|
||||
if steam.Heatwave then steam.Sound = CreateSound(steam, Sound("ambient/gas/cannister_loop.wav")) end
|
||||
if !steam.Heatwave then steam.Sound = CreateSound(steam, Sound("ambient/gas/steam2.wav")) end
|
||||
steam.Sound:PlayEx(0.42, 100)
|
||||
end
|
||||
steam:Fire("TurnOn", "", 0)
|
||||
|
||||
end
|
||||
|
||||
//Register KeyDown functions
|
||||
numpad.Register("StartEmitSteam", StartEmitSteam)
|
||||
numpad.OnDown(self:GetOwner(), self:GetClientNumber("key"), "StartEmitSteam", steam)
|
||||
|
||||
//Create KeyUp numpad functions
|
||||
local function StopEmitSteam(ply, steam)
|
||||
if !steam || !steam:IsValid() then return end
|
||||
|
||||
//Stop steam and related sounds
|
||||
if steam.Sound then steam.Sound:Stop() end
|
||||
steam:Fire("TurnOff", "", 0)
|
||||
|
||||
end
|
||||
|
||||
//Register KeyUp functions
|
||||
numpad.Register("StopEmitSteam", StopEmitSteam)
|
||||
numpad.OnUp(self:GetOwner(), self:GetClientNumber("key"), "StopEmitSteam", steam)
|
||||
|
||||
end
|
||||
|
||||
//If toggled
|
||||
if self:GetClientNumber("toggle") == 1 then
|
||||
|
||||
steam.Toggle = false
|
||||
|
||||
//Create KeyDown numpad functions
|
||||
local function ToggleEmitSteam(ply, steam)
|
||||
if !steam || !steam:IsValid() then return end
|
||||
|
||||
//Start steam and related sounds
|
||||
if !steam.Toggle then
|
||||
if steam.MakesSound then
|
||||
if steam.Sound then steam.Sound:Stop() end
|
||||
if steam.Heatwave then steam.Sound = CreateSound(steam, Sound("ambient/gas/cannister_loop.wav")) end
|
||||
if !steam.Heatwave then steam.Sound = CreateSound(steam, Sound("ambient/gas/steam2.wav")) end
|
||||
sound.Play( "HL1/ambience/steamburst1.wav", steam:GetPos(), 60, 100 )
|
||||
steam.Sound:PlayEx(0.42, 100)
|
||||
end
|
||||
steam:Fire("TurnOn", "", 0)
|
||||
steam.Toggle = true
|
||||
return
|
||||
end
|
||||
|
||||
//Stop steam and related sounds
|
||||
if steam.Toggle then
|
||||
if steam.Sound then steam.Sound:Stop() end
|
||||
steam:Fire("TurnOff", "", 0)
|
||||
steam.Toggle = false
|
||||
return
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
//Register KeyDown functions
|
||||
numpad.Register("ToggleEmitSteam", ToggleEmitSteam)
|
||||
numpad.OnDown(self:GetOwner(), self:GetClientNumber("key"), "ToggleEmitSteam", steam)
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Remove steam in radius
|
||||
function TOOL:RightClick(trace)
|
||||
|
||||
//Clients don't need to know about any of this
|
||||
if (CLIENT) then return false end
|
||||
|
||||
//Find steam in radius
|
||||
local findsteam = ents.FindInSphere(trace.HitPos, 32)
|
||||
for _, steam in pairs(findsteam) do
|
||||
|
||||
//Remove
|
||||
if steam && steam:IsValid() && !steam:GetPhysicsObject():IsValid() && steam:GetClass() == "env_steam" && !steam:IsPlayer() && !steam:IsNPC() && !steam:IsWorld() then
|
||||
if steam.Sound then steam.Sound:Stop() end
|
||||
steam:Fire("TurnOff", "", 0)
|
||||
steam:Fire("Kill", "", 6)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Remove all steam
|
||||
function TOOL:Reload()
|
||||
|
||||
//Clients don't need to know about any of this
|
||||
if (CLIENT) then return false end
|
||||
|
||||
//Get all steam objects
|
||||
for x = 1, table.getn(self.Steams) do
|
||||
local steam = self.Steams[x]
|
||||
|
||||
//Remove
|
||||
if steam && steam:IsValid() then
|
||||
if steam.Sound then steam.Sound:Stop() end
|
||||
steam:Fire("TurnOff", "", 0)
|
||||
steam:Fire("Kill", "", 6)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Precache all sounds
|
||||
function TOOL:Precache()
|
||||
util.PrecacheSound("HL1/ambience/steamburst1.wav")
|
||||
util.PrecacheSound("ambient/gas/cannister_loop.wav")
|
||||
util.PrecacheSound("ambient/gas/steam2.wav")
|
||||
end
|
||||
|
||||
|
||||
//Build Tool Menu
|
||||
function TOOL.BuildCPanel(panel)
|
||||
|
||||
//Header
|
||||
panel:AddControl( "Header", { Text = "#Tool.steam.name", Description = "#Tool.steam.desc" } )
|
||||
|
||||
//Build preset menu and declare default preset
|
||||
local params = { Label = "#Presets", MenuButton = 1, Folder = "steam", Options = {}, CVars = {} }
|
||||
|
||||
//Declare default preset
|
||||
params.Options.default = {
|
||||
steam_color_r = 150,
|
||||
steam_color_g = 150,
|
||||
steam_color_b = 150,
|
||||
steam_color_a = 200,
|
||||
steam_jetlength = 150,
|
||||
steam_spreadspeed = 21,
|
||||
steam_speed = 200,
|
||||
steam_startsize = 16,
|
||||
steam_endsize = 32,
|
||||
steam_rate = 32,
|
||||
steam_rollspeed = 12,
|
||||
steam_emissive = 1,
|
||||
steam_heatwave = 1,
|
||||
steam_makesound = 1,
|
||||
}
|
||||
|
||||
//Declare console variables
|
||||
table.insert( params.CVars, "steam_color_r" )
|
||||
table.insert( params.CVars, "steam_color_g" )
|
||||
table.insert( params.CVars, "steam_color_b" )
|
||||
table.insert( params.CVars, "steam_color_a" )
|
||||
table.insert( params.CVars, "steam_jetlength" )
|
||||
table.insert( params.CVars, "steam_spreadspeed" )
|
||||
table.insert( params.CVars, "steam_speed" )
|
||||
table.insert( params.CVars, "steam_startsize" )
|
||||
table.insert( params.CVars, "steam_endsize" )
|
||||
table.insert( params.CVars, "steam_rate" )
|
||||
table.insert( params.CVars, "steam_rollspeed" )
|
||||
table.insert( params.CVars, "steam_emissive" )
|
||||
table.insert( params.CVars, "steam_heatwave" )
|
||||
table.insert( params.CVars, "steam_makesound" )
|
||||
|
||||
//All done
|
||||
panel:AddControl( "ComboBox", params )
|
||||
|
||||
//Color picker
|
||||
panel:AddControl( "Color", { Label = "Steam color", Red = "steam_color_r", Green = "steam_color_g", Blue = "steam_color_b", Alpha = "steam_color_a", ShowAlpha = "1", ShowHSV = "1", ShowRGB = "1", Multiplier = "255" } )
|
||||
//Jet length
|
||||
panel:AddControl( "Slider", { Label = "Jet length", Type = "Integer", Min = "1", Max = "512", Command ="steam_jetlength" } )
|
||||
//Spread speed
|
||||
panel:AddControl( "Slider", { Label = "Spread speed", Type = "Integer", Min = "0", Max = "128", Command ="steam_spreadspeed" } )
|
||||
//Linear speed
|
||||
panel:AddControl( "Slider", { Label = "Linear speed", Type = "Integer", Min = "0", Max = "4096", Command ="steam_speed" } )
|
||||
//Particle start size
|
||||
panel:AddControl( "Slider", { Label = "Particle start size", Type = "Integer", Min = "0", Max = "128", Command ="steam_startsize" } )
|
||||
//Particle end size
|
||||
panel:AddControl( "Slider", { Label = "Particle end size", Type = "Integer", Min = "0", Max = "128", Command ="steam_endsize" } )
|
||||
//Particle spawn rate
|
||||
panel:AddControl( "Slider", { Label = "Particle spawn rate", Type = "Integer", Min = "1", Max = "64", Command ="steam_rate" } )
|
||||
//Particle roll speed
|
||||
panel:AddControl( "Slider", { Label = "Particle roll speed", Type = "Integer", Min = "0", Max = "32", Command ="steam_rollspeed" } )
|
||||
//Emissive
|
||||
panel:AddControl( "CheckBox", { Label = "Emissive", Description = "", Command = "steam_emissive" } )
|
||||
//Heatwave
|
||||
panel:AddControl( "CheckBox", { Label = "Heatwave", Description = "", Command = "steam_heatwave" } )
|
||||
//Sound
|
||||
panel:AddControl( "CheckBox", { Label = "Sound", Description = "", Command = "steam_makesound" } )
|
||||
|
||||
//-------------
|
||||
panel:AddControl( "Label", { Text = "________________________________________", Description = "" } )
|
||||
|
||||
//Numpad menu
|
||||
panel:AddControl( "Numpad", { Label = "Numpad Key", Command = "steam_key", ButtonSize = 22 } )
|
||||
//Use numpad check
|
||||
panel:AddControl( "CheckBox", { Label = "Use numpad", Description = "", Command = "steam_numpadcontrol" } )
|
||||
//Toggle check
|
||||
panel:AddControl( "CheckBox", { Label = "Toggle", Description = "", Command = "steam_toggle" } )
|
||||
|
||||
end
|
||||
436
lua/weapons/gmod_tool/stools/submaterial.lua
Normal file
436
lua/weapons/gmod_tool/stools/submaterial.lua
Normal file
@@ -0,0 +1,436 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
TOOL.Category = "Render"
|
||||
TOOL.Name = "SubMaterial"--"#tool.material.name"
|
||||
if CLIENT then
|
||||
language.Add( "tool.submaterial.name", "SubMaterial Tool" )
|
||||
language.Add( "tool.submaterial.desc", "Allow to override submaterials of model." )
|
||||
language.Add( "tool.submaterial.0", "Wheel Up/Down: Select target part, Primary: Apply material, Secondary: Set default material, Reload: Copy material" )
|
||||
language.Add( "tool.submaterial.help", "Select material here, type known material string or use HUD to copy materials" )
|
||||
end
|
||||
TOOL.ClientConVar[ "override" ] = "debug/env_cubemap_model"
|
||||
TOOL.ClientConVar[ "index" ] = 0
|
||||
|
||||
--
|
||||
-- Duplicator function
|
||||
--
|
||||
local function SetSubMaterial( Player, Entity, Data )
|
||||
|
||||
if ( SERVER ) then
|
||||
local Mats=Entity:GetMaterials()
|
||||
local MatCount=table.Count(Mats)
|
||||
for i=0,MatCount-1 do
|
||||
local si="SubMaterialOverride_"..tostring(i)
|
||||
-- Block exploitable material in multiplayer and remove empty strings
|
||||
if Data[si] and ((!game.SinglePlayer() && string.lower(Data[si]) == "pp/copy" ) or Data[si] == "" ) then
|
||||
Data[si]=nil
|
||||
end
|
||||
Entity:SetSubMaterial( i, Data[si] or "")
|
||||
end
|
||||
duplicator.ClearEntityModifier( Entity, "submaterial")
|
||||
if (table.Count(Data) > 0) then duplicator.StoreEntityModifier( Entity, "submaterial", Data ) end
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
duplicator.RegisterEntityModifier( "submaterial", SetSubMaterial )
|
||||
|
||||
local function UpdateSubMat(Player, Entity, Index, Material)
|
||||
local Mats=Entity:GetMaterials()
|
||||
local MatCount=table.Count(Mats)
|
||||
if Index < 0 or Index >= MatCount then return end
|
||||
local Data={}
|
||||
for i=0,MatCount-1 do
|
||||
local mat=Entity:GetSubMaterial(i)
|
||||
if i==Index then mat=Material end
|
||||
if mat and mat ~= "" then Data["SubMaterialOverride_"..tostring(i)]=mat end
|
||||
end
|
||||
return SetSubMaterial(Player, Entity, Data)
|
||||
end
|
||||
|
||||
|
||||
-- Original set material funct
|
||||
local function SetMaterial( Player, Entity, Data )
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
--
|
||||
-- Make sure this is in the 'allowed' list in multiplayer - to stop people using exploits
|
||||
--
|
||||
--if ( !game.SinglePlayer() && !list.Contains( "OverrideMaterials", Data.MaterialOverride ) && Data.MaterialOverride != "" ) then return end
|
||||
if not Data.MaterialOverride or (Data.MaterialOverride and (!game.SinglePlayer() && string.lower(Data.MaterialOverride) == "pp/copy" )) then
|
||||
return
|
||||
end
|
||||
Entity:SetMaterial( Data.MaterialOverride )
|
||||
duplicator.StoreEntityModifier( Entity, "material", Data )
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
--and we will override it because original function eats most of materials even not exploitable! :(
|
||||
duplicator.RegisterEntityModifier( "material", SetMaterial )
|
||||
|
||||
|
||||
--
|
||||
-- Left click applies the current material
|
||||
--
|
||||
function TOOL:LeftClick( trace )
|
||||
if ( !IsValid( trace.Entity ) ) then return end
|
||||
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
local ent = trace.Entity
|
||||
if ( IsValid( ent.AttachedEntity ) ) then ent = ent.AttachedEntity end
|
||||
|
||||
local mat = self:GetClientInfo( "override" )
|
||||
local index = self:GetClientNumber( "index" , 0)
|
||||
if index < 1 then
|
||||
SetMaterial( self:GetOwner(), ent, { MaterialOverride = mat } )
|
||||
else
|
||||
UpdateSubMat( self:GetOwner(), ent, index-1, mat )
|
||||
end
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Right click reverts the material
|
||||
--
|
||||
function TOOL:RightClick( trace )
|
||||
|
||||
if ( !IsValid( trace.Entity ) ) then return end
|
||||
|
||||
if ( CLIENT ) then return true end
|
||||
|
||||
local ent = trace.Entity
|
||||
if ( IsValid( ent.AttachedEntity ) ) then ent = ent.AttachedEntity end
|
||||
local index = self:GetClientNumber( "index" , 0)
|
||||
if index < 1 then
|
||||
SetMaterial( self:GetOwner(), ent, { MaterialOverride = "" } )
|
||||
else
|
||||
UpdateSubMat( self:GetOwner(), ent, index-1, "" )
|
||||
end
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
----- Damn Dirty fix... Thx for Wire Advanced tool developer
|
||||
|
||||
local function get_active_tool(ply, tool)
|
||||
-- find toolgun
|
||||
local activeWep = ply:GetActiveWeapon()
|
||||
if not IsValid(activeWep) or activeWep:GetClass() ~= "gmod_tool" or activeWep.Mode ~= tool then return end
|
||||
|
||||
return activeWep:GetToolObject(tool)
|
||||
end
|
||||
|
||||
if game.SinglePlayer() then -- wtfgarry (these functions don't get called clientside in single player so we need this hack to fix it)
|
||||
if SERVER then
|
||||
util.AddNetworkString( "submaterial_wtfgarry" )
|
||||
local function send( ply, funcname )
|
||||
net.Start( "submaterial_wtfgarry" )
|
||||
net.WriteString( funcname )
|
||||
net.Send( ply )
|
||||
end
|
||||
|
||||
--function TOOL:LeftClick() send( self:GetOwner(), "LeftClick" ) end
|
||||
--function TOOL:RightClick() send( self:GetOwner(), "RightClick" ) end
|
||||
function TOOL:Reload() send( self:GetOwner(), "Reload" ) end
|
||||
elseif CLIENT then
|
||||
net.Receive( "submaterial_wtfgarry", function( len )
|
||||
local funcname = net.ReadString()
|
||||
local tool = get_active_tool( LocalPlayer(), "submaterial" )
|
||||
if not tool then return end
|
||||
tool[funcname]( tool, LocalPlayer():GetEyeTrace() )
|
||||
end)
|
||||
end
|
||||
end
|
||||
-----------------------------
|
||||
if CLIENT then
|
||||
|
||||
|
||||
TOOL.AimEnt = nil
|
||||
TOOL.HudData = {}
|
||||
TOOL.SelIndx = 1
|
||||
TOOL.ToolMatString = ""
|
||||
|
||||
function TOOL:Reload( trace )
|
||||
|
||||
if ( !IsValid( trace.Entity ) ) then return end
|
||||
|
||||
--if ( CLIENT ) then return true end
|
||||
|
||||
local ent = trace.Entity
|
||||
if ( IsValid( ent.AttachedEntity ) ) then ent = ent.AttachedEntity end
|
||||
|
||||
--local index = self:GetClientNumber( "index" , 0)
|
||||
local mat=self.HudData.EntCurMatString--""
|
||||
|
||||
if !mat or mat ~= "" then
|
||||
RunConsoleCommand("submaterial_override",mat)
|
||||
end
|
||||
--LocalPlayer():ChatPrint("Material ".. (((self.SelIndx < 1) and "[Global]") or tostring(self.SelIndx)).." copied: "..mat)
|
||||
--else LocalPlayer():ChatPrint("Empty material!") end
|
||||
--end
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
function TOOL:Scroll(trace,dir)
|
||||
if !IsValid(self.AimEnt) then return end
|
||||
local Mats=self.AimEnt:GetMaterials()
|
||||
local MatCount=table.Count(Mats)
|
||||
self.SelIndx = self.SelIndx + dir
|
||||
if(self.SelIndx<0) then self.SelIndx = MatCount end
|
||||
if(self.SelIndx>MatCount) then self.SelIndx = 0 end
|
||||
RunConsoleCommand("submaterial_index",tostring(self.SelIndx))
|
||||
return true
|
||||
--self.HudData.EntCurMat=Material(self.AimEnt:GetMaterials()[self.SelIndx])
|
||||
|
||||
end
|
||||
function TOOL:ScrollUp(trace) return self:Scroll(trace,-1) end
|
||||
function TOOL:ScrollDown(trace) return self:Scroll(trace,1) end
|
||||
|
||||
|
||||
|
||||
---- Thx wire_adv dev again...
|
||||
local function hookfunc( ply, bind, pressed )
|
||||
if not pressed then return end
|
||||
if bind == "invnext" then
|
||||
local self = get_active_tool(ply, "submaterial")
|
||||
if not self then return end
|
||||
|
||||
return self:ScrollDown(ply:GetEyeTraceNoCursor())
|
||||
elseif bind == "invprev" then
|
||||
local self = get_active_tool(ply, "submaterial")
|
||||
if not self then return end
|
||||
|
||||
return self:ScrollUp(ply:GetEyeTraceNoCursor())
|
||||
end
|
||||
end
|
||||
|
||||
if game.SinglePlayer() then -- wtfgarry (have to have a delay in single player or the hook won't get added)
|
||||
timer.Simple(5,function() hook.Add( "PlayerBindPress", "submat_tool_playerbindpress", hookfunc ) end)
|
||||
else
|
||||
hook.Add( "PlayerBindPress", "submat_tool_playerbindpress", hookfunc )
|
||||
end
|
||||
--------------------------------------------------
|
||||
|
||||
|
||||
local function FixVertexLitMaterial(Mat)
|
||||
|
||||
--
|
||||
-- If it's a vertexlitgeneric material we need to change it to be
|
||||
-- UnlitGeneric so it doesn't go dark when we enter a dark room
|
||||
-- and flicker all about
|
||||
--
|
||||
if not Mat then return Mat end
|
||||
local strImage = Mat:GetName()
|
||||
|
||||
if ( string.find( Mat:GetShader(), "VertexLitGeneric" ) || string.find( Mat:GetShader(), "Cable" ) ) then
|
||||
|
||||
local t = Mat:GetString( "$basetexture" )
|
||||
|
||||
if ( t ) then
|
||||
|
||||
local params = {}
|
||||
params[ "$basetexture" ] = t
|
||||
params[ "$vertexcolor" ] = 1
|
||||
params[ "$vertexalpha" ] = 1
|
||||
|
||||
Mat = CreateMaterial( strImage .. "_hud_fx", "UnlitGeneric", params )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return Mat
|
||||
|
||||
end
|
||||
|
||||
function TOOL:Think( )
|
||||
local ent=LocalPlayer():GetEyeTraceNoCursor().Entity
|
||||
if ( IsValid( ent.AttachedEntity ) ) then ent = ent.AttachedEntity end
|
||||
if self.AimEnt ~= ent then
|
||||
|
||||
self.AimEnt=ent
|
||||
if IsValid(self.AimEnt) then
|
||||
self.SelIndx=0
|
||||
RunConsoleCommand("submaterial_index",tostring(self.SelIndx))
|
||||
self.HudData.Mats=self.AimEnt:GetMaterials()
|
||||
|
||||
end
|
||||
--print("ThinkUpdate "..tostring(self.AimEnt))
|
||||
end
|
||||
|
||||
if IsValid(self.AimEnt) then
|
||||
self.HudData.CurMats=table.Copy(self.HudData.Mats)
|
||||
self.HudData.OvrMats={}
|
||||
|
||||
local MatCount=table.Count(self.HudData.Mats)
|
||||
for i=1,MatCount do
|
||||
local mat=self.AimEnt:GetSubMaterial(i-1)
|
||||
if mat and mat ~= "" then self.HudData.OvrMats[i]=mat end
|
||||
end
|
||||
table.Merge(self.HudData.CurMats,self.HudData.OvrMats)
|
||||
self.HudData.GlobalMat=self.AimEnt:GetMaterial()
|
||||
local EntCurMatString=self.HudData.GlobalMat
|
||||
local EntOrigMatString=self.HudData.GlobalMat
|
||||
if self.SelIndx > 0 then EntCurMatString=self.HudData.CurMats[self.SelIndx]; EntOrigMatString=self.HudData.Mats[self.SelIndx] end
|
||||
if self.HudData.EntCurMatString~=EntCurMatString then
|
||||
self.HudData.EntCurMatString=EntCurMatString
|
||||
self.HudData.EntCurMat=FixVertexLitMaterial(Material(EntCurMatString))
|
||||
end
|
||||
if self.HudData.EntOrigMatString~=EntOrigMatString then
|
||||
self.HudData.EntOrigMatString=EntOrigMatString
|
||||
self.HudData.EntOrigMat=FixVertexLitMaterial(Material(EntOrigMatString))
|
||||
end
|
||||
end
|
||||
|
||||
if IsValid(self.AimEnt) and self.ToolMatString~=GetConVarString("submaterial_override") then
|
||||
self.ToolMatString=GetConVarString("submaterial_override")
|
||||
self.HudData.ToolMat=FixVertexLitMaterial(Material(self.ToolMatString))
|
||||
end
|
||||
|
||||
end
|
||||
function TOOL:DrawHUD( )
|
||||
if IsValid(self.AimEnt) then
|
||||
|
||||
---- List
|
||||
local Rg=ScrW()/2-50
|
||||
local MaxW = 0
|
||||
local TextH = 0
|
||||
surface.SetFont("ChatFont")
|
||||
local Hdr=tostring(self.AimEnt)..": "..tostring(table.Count(self.HudData.Mats)).." materials"
|
||||
MaxW,TextH=surface.GetTextSize(Hdr)
|
||||
local HdrH = TextH+5
|
||||
for _,s in pairs(self.HudData.CurMats) do
|
||||
local ts,_=surface.GetTextSize(s)
|
||||
if MaxW<ts then MaxW=ts end
|
||||
end
|
||||
local LH=4*2+HdrH+TextH*(1+table.Count(self.HudData.Mats))
|
||||
local LW=4*2+MaxW
|
||||
local LL=Rg-LW
|
||||
local LT=ScrH()/2-LH/2
|
||||
surface.SetDrawColor(Color(64,64,95,191))
|
||||
--surface.SetMaterial(self.HudData.EntCurMat)
|
||||
surface.DrawRect(LL, LT, LW, LH)
|
||||
surface.SetTextColor(Color(255,255,255,255))
|
||||
surface.SetTextPos(LL+4,LT+4)
|
||||
surface.DrawText(Hdr)
|
||||
surface.SetDrawColor(Color(255,255,255,255))
|
||||
surface.DrawLine(LL+3,LT+4+TextH+3,Rg-3,LT+4+TextH+3)
|
||||
|
||||
surface.SetDrawColor(Color(0,127,0,191))
|
||||
surface.DrawRect(LL+3, LT+4+HdrH+TextH*self.SelIndx, LW-3-3, TextH)
|
||||
|
||||
local s="<none>"
|
||||
if not self.HudData.GlobalMat or self.HudData.GlobalMat == "" then
|
||||
surface.SetTextColor(Color(255,255,255,255))
|
||||
else surface.SetTextColor(Color(0,0,255,255)); s=self.HudData.GlobalMat end
|
||||
|
||||
surface.SetTextPos(LL+4,LT+4+HdrH)
|
||||
surface.DrawText(s)
|
||||
|
||||
|
||||
|
||||
for i,s in pairs(self.HudData.CurMats) do
|
||||
if self.HudData.OvrMats[i] then surface.SetTextColor(Color(255,0,0,255)) else surface.SetTextColor(Color(255,255,255,255)) end
|
||||
surface.SetTextPos(LL+4,LT+4+HdrH+TextH*i)
|
||||
surface.DrawText(s)
|
||||
end
|
||||
---- Info box
|
||||
|
||||
|
||||
--local MaxW = 0
|
||||
local StrToolInfo = "Tool material:"
|
||||
local StrOrigMatInfo = "Model original material:"
|
||||
local StrCurMatInfo = "Model current material:"
|
||||
local MaxW,_=surface.GetTextSize(StrToolInfo)
|
||||
local ts,_=surface.GetTextSize(StrOrigMatInfo)
|
||||
if MaxW<ts then MaxW=ts end
|
||||
local ts,_=surface.GetTextSize(StrCurMatInfo)
|
||||
if MaxW<ts then MaxW=ts end
|
||||
local ts,_=surface.GetTextSize(self.ToolMatString)
|
||||
if MaxW<ts then MaxW=ts end
|
||||
local ts,_=surface.GetTextSize(self.HudData.EntOrigMatString)
|
||||
if MaxW<ts then MaxW=ts end
|
||||
local ts,_=surface.GetTextSize(self.HudData.EntCurMatString)
|
||||
if MaxW<ts then MaxW=ts end
|
||||
|
||||
local IL=ScrW()/2+50
|
||||
local IH=4*4+(64)*3
|
||||
local IT=ScrH()/2-IH/2
|
||||
surface.SetDrawColor(Color(64,64,95,191))
|
||||
surface.DrawRect(IL, IT, 76+MaxW, IH) -- 4+64+4+MaxW+4
|
||||
|
||||
surface.SetTextColor(Color(255,255,255,255))
|
||||
|
||||
surface.SetDrawColor(Color(255,255,255,255))
|
||||
if self.HudData.ToolMat then
|
||||
surface.SetMaterial(self.HudData.ToolMat)
|
||||
surface.DrawTexturedRect(IL+4, IT+4, 64, 64)
|
||||
end
|
||||
surface.SetTextPos(IL+4+64+4,IT+8)
|
||||
surface.DrawText(StrToolInfo)
|
||||
surface.SetTextPos(IL+4+64+4,IT+8+TextH)
|
||||
surface.DrawText(self.ToolMatString)
|
||||
surface.SetTextPos(IL+4+64+4,IT+8+TextH*2)
|
||||
surface.DrawText(self.SelIndx==0 and "[Global]" or "Index: "..self.SelIndx-1)
|
||||
|
||||
|
||||
|
||||
if self.HudData.EntOrigMat then
|
||||
surface.SetMaterial(self.HudData.EntOrigMat)
|
||||
surface.DrawTexturedRect(IL+4, IT+4+(64+4), 64, 64)
|
||||
end
|
||||
surface.SetTextPos(IL+4+64+4,IT+8+64+4)
|
||||
surface.DrawText(StrOrigMatInfo)
|
||||
surface.SetTextPos(IL+4+64+4,IT+8+64+4+TextH)
|
||||
surface.DrawText(self.HudData.EntOrigMatString)
|
||||
|
||||
if self.HudData.EntCurMat then
|
||||
surface.SetMaterial(self.HudData.EntCurMat)
|
||||
surface.DrawTexturedRect(IL+4, IT+4+(64+4)*2, 64, 64)
|
||||
end
|
||||
surface.SetTextPos(IL+4+64+4,IT+8+(64+4)*2)
|
||||
surface.DrawText(StrCurMatInfo)
|
||||
surface.SetTextPos(IL+4+64+4,IT+8+(64+4)*2+TextH)
|
||||
surface.DrawText(self.HudData.EntCurMatString)
|
||||
|
||||
|
||||
-- surface.SetMaterial(nil)
|
||||
|
||||
|
||||
--draw.RoundedBox( 2, ScrW()/2-50, ScrH()/2-50, 100, 100, Color(255,255,255,255) )
|
||||
|
||||
-- print("DrawHUD "..tostring(self.AimEnt))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
function TOOL.BuildCPanel( CPanel )
|
||||
|
||||
--CPanel:AddControl( "Slider", { Label = "Index", Command = "submaterial_index", Type = "Integer", Min = 0, Max = 15} )
|
||||
CPanel:AddControl( "Header", { Description = "#tool.submaterial.help" } )
|
||||
|
||||
CPanel:AddControl( "TextBox", { Label = "Mat:", Command = "submaterial_override", MaxLength = "48"} )
|
||||
CPanel:MatSelect( "submaterial_override", list.Get( "OverrideMaterials" ), true, 64, 64 )
|
||||
|
||||
end
|
||||
291
lua/weapons/gmod_tool/stools/tesla.lua
Normal file
291
lua/weapons/gmod_tool/stools/tesla.lua
Normal file
@@ -0,0 +1,291 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
TOOL.Category = "Matrix_'s Effects"
|
||||
TOOL.Name = "#Tesla"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
//Default values
|
||||
TOOL.ClientConVar["dischargeradius"] = 256
|
||||
TOOL.ClientConVar["dischargeinterval"] = 1.5
|
||||
TOOL.ClientConVar["beamcount"] = 2
|
||||
TOOL.ClientConVar["beamthickness"] = 6
|
||||
TOOL.ClientConVar["beamlifetime"] = 0.052
|
||||
TOOL.ClientConVar["sound"] = 1
|
||||
TOOL.ClientConVar["key"] = 5
|
||||
TOOL.ClientConVar["numpadcontrol"] = 0
|
||||
TOOL.ClientConVar["toggle"] = 0
|
||||
|
||||
//List of all spawned fire entities
|
||||
TOOL.Discharges = {}
|
||||
|
||||
//Add language descriptions
|
||||
if (CLIENT) then
|
||||
language.Add("Tool.tesla.name", "Tesla Discharge Tool")
|
||||
language.Add("Tool.tesla.desc", "Creates electric discharges")
|
||||
language.Add("Tool.tesla.0", "Left-Click: Create an electric discharge Right-Click: Remove discharge")
|
||||
language.Add("Cleanup_Discharges", "Tesla Discharges")
|
||||
language.Add("Cleaned_Discharges", "Cleaned up all Discharges")
|
||||
language.Add("SBoxLimit_discharges", "You've hit the Discharges limit!")
|
||||
language.Add("Undone_Discharge", "Tesla Discharge undone")
|
||||
end
|
||||
|
||||
//Sandbox-related stuff
|
||||
cleanup.Register("Discharges")
|
||||
CreateConVar("sbox_maxdischarges", 10000, FCVAR_NOTIFY)
|
||||
|
||||
|
||||
//Create discharge
|
||||
function TOOL:LeftClick(trace)
|
||||
|
||||
//Clients don't need to know about any of this
|
||||
if (CLIENT) then return true end
|
||||
|
||||
//Check current spawnlimits
|
||||
if (!self:GetSWEP():CheckLimit("discharges")) then return false end
|
||||
|
||||
//Retreive settings
|
||||
local dischargeradius = math.Round(math.Clamp(self:GetClientNumber("dischargeradius"), 1, 2048))
|
||||
local dischargeinterval = math.Clamp(self:GetClientNumber("dischargeinterval"), 0.012, 8)
|
||||
local beamcount = math.Clamp(self:GetClientNumber("beamcount"), 1, 32)
|
||||
local beamthickness = math.Clamp(self:GetClientNumber("beamthickness"), 0.12, 16)
|
||||
local beamlifetime = math.Clamp(self:GetClientNumber("beamlifetime"), 0.052, 8)
|
||||
|
||||
//Create discharge and assign settings
|
||||
local discharge = ents.Create("point_tesla")
|
||||
if !discharge || !discharge:IsValid() then return false end
|
||||
discharge:SetPos(trace.HitPos)
|
||||
discharge:SetKeyValue("texture", "trails/laser.vmt")
|
||||
discharge:SetKeyValue("m_Color", "255 255 255")
|
||||
discharge:SetKeyValue("m_flRadius", tostring(dischargeradius))
|
||||
discharge:SetKeyValue("interval_min", tostring(dischargeinterval * 0.75))
|
||||
discharge:SetKeyValue("interval_max", tostring(dischargeinterval * 1.25))
|
||||
discharge:SetKeyValue("beamcount_min", tostring(math.Round(beamcount * 0.75)))
|
||||
discharge:SetKeyValue("beamcount_max", tostring(math.Round(beamcount * 1.25)))
|
||||
discharge:SetKeyValue("thick_min", tostring(beamthickness * 0.75))
|
||||
discharge:SetKeyValue("thick_max", tostring(beamthickness*1.25))
|
||||
discharge:SetKeyValue("lifetime_min", tostring(beamlifetime * 0.75))
|
||||
discharge:SetKeyValue("lifetime_max", tostring(beamlifetime * 1.25))
|
||||
|
||||
//Emit sounds
|
||||
if math.Round(math.Clamp(self:GetClientNumber("sound"), 0, 1)) == 1 then
|
||||
discharge:SetKeyValue("m_SoundName", tostring("weapons/physcannon/superphys_small_zap" .. math.random(1,4) .. ".wav"))
|
||||
if self:GetClientNumber("numpadcontrol") == 0 then
|
||||
sound.Play( "ambient/energy/weld" .. math.random(1,2) .. ".wav", trace.HitPos, 64, 100 )
|
||||
discharge:Fire("DoSpark", "", 0)
|
||||
end
|
||||
end
|
||||
|
||||
//Spawn discharge
|
||||
discharge:Spawn()
|
||||
discharge:Activate()
|
||||
if trace && trace.Entity && trace.Entity:IsValid() && trace.Entity:GetPhysicsObject():IsValid() && !trace.Entity:IsPlayer() && !trace.Entity:IsWorld() then discharge:SetParent(trace.Entity) end
|
||||
if self:GetClientNumber("numpadcontrol") == 0 then discharge:Fire("TurnOn", "", 0) end
|
||||
|
||||
//Add to relevant lists
|
||||
self:GetOwner():AddCount("discharges", discharge)
|
||||
table.insert(self.Discharges, discharge)
|
||||
|
||||
//Make sure we can undo
|
||||
undo.Create("Discharge")
|
||||
undo.AddEntity(discharge)
|
||||
undo.SetPlayer(self:GetOwner())
|
||||
undo.Finish()
|
||||
cleanup.Add(self:GetOwner(), "Discharges", discharge)
|
||||
|
||||
//Make sure we can control it with numpad
|
||||
if self:GetClientNumber("numpadcontrol") == 1 then
|
||||
self:SetupNumpadControls(discharge)
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Setup numpad controls
|
||||
function TOOL:SetupNumpadControls(discharge)
|
||||
|
||||
//Safeguards
|
||||
if !discharge || !discharge:IsValid() || self:GetClientInfo("key") == nil || self:GetClientInfo("key") == -1 then return false end
|
||||
|
||||
//If not toggled
|
||||
if self:GetClientNumber("toggle") == 0 then
|
||||
|
||||
//Create KeyDown numpad functions
|
||||
local function StartEmitDischarge(ply, discharge)
|
||||
if !discharge || !discharge:IsValid() then return end
|
||||
|
||||
//Start discharge
|
||||
discharge:Fire("DoSpark", "", 0)
|
||||
discharge:Fire("TurnOn", "", 0)
|
||||
|
||||
end
|
||||
|
||||
//Register KeyDown functions
|
||||
numpad.Register("StartEmitDischarge", StartEmitDischarge)
|
||||
numpad.OnDown(self:GetOwner(), self:GetClientNumber("key"), "StartEmitDischarge", discharge)
|
||||
|
||||
//Create KeyUp numpad functions
|
||||
local function StopEmitDischarge(ply, discharge)
|
||||
if !discharge || !discharge:IsValid() then return end
|
||||
|
||||
//Stop discharge
|
||||
discharge:Fire("TurnOff", "", 0)
|
||||
|
||||
end
|
||||
|
||||
//Register KeyUp functions
|
||||
numpad.Register("StopEmitDischarge", StopEmitDischarge)
|
||||
numpad.OnUp(self:GetOwner(), self:GetClientNumber("key"), "StopEmitDischarge", discharge)
|
||||
|
||||
end
|
||||
|
||||
//If toggled
|
||||
if self:GetClientNumber("toggle") == 1 then
|
||||
|
||||
discharge.Toggle = false
|
||||
|
||||
//Create KeyDown numpad functions
|
||||
local function ToggleEmitDischarge(ply, discharge)
|
||||
if !discharge || !discharge:IsValid() then return end
|
||||
|
||||
//Start discharge
|
||||
if !discharge.Toggle then
|
||||
discharge:Fire("TurnOn", "", 0)
|
||||
discharge.Toggle = true
|
||||
return
|
||||
end
|
||||
|
||||
//Stop discharge
|
||||
if discharge.Toggle then
|
||||
discharge:Fire("TurnOff", "", 0)
|
||||
discharge.Toggle = false
|
||||
return
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
//Register KeyDown functions
|
||||
numpad.Register("ToggleEmitDischarge", ToggleEmitDischarge)
|
||||
numpad.OnDown(self:GetOwner(), self:GetClientNumber("key"), "ToggleEmitDischarge", discharge)
|
||||
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Remove discharges in radius
|
||||
function TOOL:RightClick(trace)
|
||||
|
||||
//Clients don't need to know about any of this
|
||||
if (CLIENT) then return false end
|
||||
|
||||
//Find discharges in radius
|
||||
local finddischarges = ents.FindInSphere(trace.HitPos, 16)
|
||||
for _, discharge in pairs(finddischarges) do
|
||||
|
||||
//Remove
|
||||
if discharge && discharge:IsValid() && !discharge:GetPhysicsObject():IsValid() && discharge:GetClass() == "point_tesla" && !discharge:IsPlayer() && !discharge:IsNPC() && !discharge:IsWorld() then
|
||||
discharge:Fire("DoSpark", "", 0)
|
||||
discharge:Fire("Kill", "", 0)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Remove all discharges
|
||||
function TOOL:Reload()
|
||||
|
||||
//Clients don't need to know about any of this
|
||||
if (CLIENT) then return false end
|
||||
|
||||
//Get all discharges
|
||||
for x = 1, table.getn(self.Discharges) do
|
||||
local discharge = self.Discharges[x]
|
||||
|
||||
//Remove
|
||||
if discharge && discharge:IsValid() then
|
||||
discharge:Fire("Kill", "", 0)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Precache all sounds
|
||||
function TOOL:Precache()
|
||||
util.PrecacheSound("weapons/physcannon/superphys_small_zap1.wav")
|
||||
util.PrecacheSound("weapons/physcannon/superphys_small_zap2.wav")
|
||||
util.PrecacheSound("weapons/physcannon/superphys_small_zap3.wav")
|
||||
util.PrecacheSound("weapons/physcannon/superphys_small_zap4.wav")
|
||||
util.PrecacheSound("ambient/energy/weld1.wav")
|
||||
util.PrecacheSound("ambient/energy/weld2.wav")
|
||||
end
|
||||
|
||||
|
||||
//Build Tool Menu
|
||||
function TOOL.BuildCPanel(panel)
|
||||
|
||||
//Header
|
||||
panel:AddControl( "Header", { Text = "#Tool.tesla.name", Description = "#Tool.tesla.desc" } )
|
||||
|
||||
//Build preset menu and declare default preset
|
||||
local params = { Label = "#Presets", MenuButton = 1, Folder = "tesla", Options = {}, CVars = {} }
|
||||
|
||||
//Declare default preset
|
||||
params.Options.default = {
|
||||
tesla_dischargeradius = 256,
|
||||
tesla_dischargeinterval = 1.5,
|
||||
tesla_beamcount = 2,
|
||||
tesla_beamthickness = 6,
|
||||
tesla_beamlifetime = 0.052,
|
||||
tesla_sound = 1,
|
||||
}
|
||||
|
||||
//Declare console variables
|
||||
table.insert( params.CVars, "tesla_dischargeradius" )
|
||||
table.insert( params.CVars, "tesla_dischargeinterval" )
|
||||
table.insert( params.CVars, "tesla_beamcount" )
|
||||
table.insert( params.CVars, "tesla_beamthickness" )
|
||||
table.insert( params.CVars, "tesla_beamlifetime" )
|
||||
table.insert( params.CVars, "tesla_sound" )
|
||||
|
||||
//All done
|
||||
panel:AddControl( "ComboBox", params )
|
||||
|
||||
//Discharge radius
|
||||
panel:AddControl( "Slider", { Label = "Discharge Radius", Type = "Float", Min = "1", Max = "2048", Command ="tesla_dischargeradius" } )
|
||||
//Discharge Interval
|
||||
panel:AddControl( "Slider", { Label = "Discharge Interval", Type = "Float", Min = "0", Max = "8", Command ="tesla_dischargeinterval" } )
|
||||
//Beam Count
|
||||
panel:AddControl( "Slider", { Label = "Beam Count", Type = "Float", Min = "1", Max = "32", Command ="tesla_beamcount" } )
|
||||
//Beam Thickness
|
||||
panel:AddControl( "Slider", { Label = "Beam Thickness", Type = "Float", Min = "0", Max = "16", Command ="tesla_beamthickness" } )
|
||||
//Beam Lifetime
|
||||
panel:AddControl( "Slider", { Label = "Beam Lifetime", Type = "Float", Min = "0", Max = "8", Command ="tesla_beamlifetime" } )
|
||||
//Sound
|
||||
panel:AddControl( "CheckBox", { Label = "Sound", Description = "", Command = "tesla_sound" } )
|
||||
|
||||
//-------------
|
||||
panel:AddControl( "Label", { Text = "________________________________________", Description = "" } )
|
||||
|
||||
//Numpad menu
|
||||
panel:AddControl( "Numpad", { Label = "Numpad Key", Command = "tesla_key", ButtonSize = 22 } )
|
||||
//Use numpad check
|
||||
panel:AddControl( "CheckBox", { Label = "Use numpad", Description = "", Command = "tesla_numpadcontrol" } )
|
||||
//Toggle check
|
||||
panel:AddControl( "CheckBox", { Label = "Toggle", Description = "", Command = "tesla_toggle" } )
|
||||
|
||||
end
|
||||
87
lua/weapons/gmod_tool/stools/test_tool_d2k.lua
Normal file
87
lua/weapons/gmod_tool/stools/test_tool_d2k.lua
Normal file
@@ -0,0 +1,87 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
if game.SinglePlayer || !game.SinglePlayer() then TOOL.AddToMenu = false return end //Example file, don't run it
|
||||
|
||||
//Generic entity spawning script used for testing whether they work or not
|
||||
|
||||
TOOL.AddToMenu = false //We're not testing anything right now
|
||||
|
||||
TOOL.Category = "Effects"
|
||||
TOOL.Name = "TESTING"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
//Add language descriptions
|
||||
if (CLIENT) then
|
||||
language.Add("Tool.test.name", "Testing Tool")
|
||||
language.Add("Tool.test.desc", "Creates random stuff")
|
||||
language.Add("Tool.test.0", "Left-Click: Make something")
|
||||
language.Add("Cleanup_test", "Test Entities")
|
||||
language.Add("Cleaned_test", "Cleaned up all Test Entities")
|
||||
language.Add("Undone_test", "Test Entity undone")
|
||||
end
|
||||
|
||||
//Sandbox-related stuff
|
||||
cleanup.Register("test")
|
||||
|
||||
|
||||
//Make a test entity
|
||||
function TOOL:LeftClick(trace)
|
||||
|
||||
//Clients don't need to know about any of this
|
||||
if (CLIENT) then return true end
|
||||
|
||||
//Create entity and assign settings
|
||||
local entity = ents.Create("env_smoketrail")
|
||||
if !entity || !entity:IsValid() then return false end
|
||||
entity:SetPos(trace.HitPos)
|
||||
entity:SetKeyValue("angles", tostring(trace.HitNormal:Angle()))
|
||||
entity:SetKeyValue("opacity", "0.52") //Float
|
||||
entity:SetKeyValue("spawnrate", "16") //Float
|
||||
entity:SetKeyValue("lifetime", "2") //Float
|
||||
entity:SetKeyValue("startcolor", "255 255 255")
|
||||
entity:SetKeyValue("endcolor", "255 255 255")
|
||||
entity:SetKeyValue("emittime", "16384") //Float
|
||||
entity:SetKeyValue("minspeed", "4") //Float
|
||||
entity:SetKeyValue("maxspeed", "16") //Float
|
||||
entity:SetKeyValue("mindirectedspeed", "16") //Float
|
||||
entity:SetKeyValue("maxdirectedspeed", "64") //Float
|
||||
entity:SetKeyValue("startsize", "32") //Float
|
||||
entity:SetKeyValue("endsize", "100") //Float
|
||||
entity:SetKeyValue("spawnradius", "16") //Float
|
||||
entity:SetKeyValue("firesprite", "effects/muzzleflash2")
|
||||
entity:SetKeyValue("smokesprite", "particle/smokesprites_0001.vmt")
|
||||
|
||||
//Spawn it
|
||||
entity:Spawn()
|
||||
entity:Activate()
|
||||
//entity:Fire("Start","",0)
|
||||
//entity:Fire("TurnOn","",0)
|
||||
|
||||
//Parent if needed
|
||||
if trace && trace.Entity && trace.Entity:IsValid() && trace.Entity:GetPhysicsObject():IsValid() && !trace.Entity:IsPlayer() && !trace.Entity:IsWorld() then entity:SetParent(trace.Entity) end
|
||||
|
||||
//Make sure we can undo
|
||||
undo.Create("Test")
|
||||
undo.AddEntity(entity)
|
||||
undo.SetPlayer(self:GetOwner())
|
||||
undo.Finish()
|
||||
cleanup.Add(self:GetOwner(), "Test", entity)
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
//Build Tool Menu
|
||||
function TOOL.BuildCPanel(panel)
|
||||
panel:AddControl( "Header", { Text = "#Tool.test.name", Description = "#Tool.test.desc" } )
|
||||
end
|
||||
251
lua/weapons/gmod_tool/stools/trigger.lua
Normal file
251
lua/weapons/gmod_tool/stools/trigger.lua
Normal file
@@ -0,0 +1,251 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
// STool by Nekres ( 4ndy )
|
||||
TOOL.Category = "Half-Life 2"
|
||||
TOOL.Name = "#tool.trigger"
|
||||
TOOL.Command = nil
|
||||
TOOL.ConfigName = ""
|
||||
|
||||
TOOL.ClientConVar["type"] = "0"
|
||||
TOOL.ClientConVar["toggle_type"] = "0"
|
||||
|
||||
TOOL.ClientConVar["allow_players"] = "1"
|
||||
TOOL.ClientConVar["allow_npcs"] = "0"
|
||||
TOOL.ClientConVar["allow_props"] = "0"
|
||||
|
||||
TOOL.ClientConVar["output1"] = "0"
|
||||
TOOL.ClientConVar["output2"] = "0"
|
||||
|
||||
TOOL.ClientConVar["target_index"] = "0"
|
||||
TOOL.ClientConVar["target_input"] = "Break"
|
||||
TOOL.ClientConVar["target_parameter"] = "<none>"
|
||||
TOOL.ClientConVar["target_delay"] = "0.001"
|
||||
|
||||
TOOL.ClientConVar["solid"] = "37"
|
||||
|
||||
cleanup.Register("prop_trigger")
|
||||
|
||||
if (CLIENT) then
|
||||
language.Add("tool.trigger", "Trigger")
|
||||
language.Add("tool.trigger.name", "Trigger Tool")
|
||||
language.Add("tool.trigger.desc", "Turn a prop into a trigger")
|
||||
language.Add("tool.trigger.0", "Left click to turn a prop into a trigger. Right to set an entity's index as target.")
|
||||
|
||||
language.Add("tool.trigger.type", "Trigger Type:")
|
||||
language.Add("tool.trigger.toggle_type", "Toggle Type:")
|
||||
|
||||
language.Add("tool.trigger.output1", "Output 1")
|
||||
language.Add("tool.trigger.output2", "Output 2")
|
||||
|
||||
language.Add("tool.trigger.solid", "Toggle Solid")
|
||||
|
||||
language.Add("Cleanup_prop_trigger", "Prop Trigger")
|
||||
language.Add("Cleaned_prop_trigger", "Cleaned up all Prop Trigger")
|
||||
language.Add("SBoxLimit_prop_trigger", "You've hit the Prop Trigger limit!")
|
||||
language.Add("Undone_prop_trigger", "Prop Trigger undone")
|
||||
|
||||
language.Add("trigger", "Prop Trigger")
|
||||
language.Add("tool.trigger.trigger_multiple", "Multiple")
|
||||
language.Add("tool.trigger.trigger_once", "Once")
|
||||
|
||||
language.Add("tool.trigger.toggle_none", "Do Not Toggle")
|
||||
language.Add("tool.trigger.toggle_touch", "Active While Touching")
|
||||
language.Add("tool.trigger.toggle_always", "On / Off Switch")
|
||||
|
||||
language.Add("tool.trigger.target", "Target Index:")
|
||||
language.Add("tool.trigger.target_input", "Input To Fire:")
|
||||
language.Add("tool.trigger.target_parameter", "Parameter:")
|
||||
language.Add("tool.trigger.target_delay", "Delay:")
|
||||
language.Add("tool.trigger.target_delay.help", "After a Delay in Seconds of ..")
|
||||
|
||||
language.Add("tool.trigger.allow_players", "Trigger On Player")
|
||||
language.Add("tool.trigger.allow_npcs", "Trigger On NPCs")
|
||||
language.Add("tool.trigger.allow_props", "Trigger On Props")
|
||||
language.Add("tool.trigger.reset", "Reset Settings")
|
||||
|
||||
concommand.Add("trigger_reset", function(ply)
|
||||
RunConsoleCommand("trigger_type", "0")
|
||||
RunConsoleCommand("trigger_toggle_type", "0")
|
||||
RunConsoleCommand("trigger_allow_players", "1")
|
||||
RunConsoleCommand("trigger_allow_npcs", "0")
|
||||
RunConsoleCommand("trigger_allow_props", "0")
|
||||
RunConsoleCommand("trigger_output1", "0")
|
||||
RunConsoleCommand("trigger_output2", "0")
|
||||
RunConsoleCommand("trigger_solid", "37")
|
||||
RunConsoleCommand("trigger_target_index", "0")
|
||||
RunConsoleCommand("trigger_target_input", "\r")
|
||||
RunConsoleCommand("trigger_target_parameter", "<none>")
|
||||
RunConsoleCommand("trigger_target_delay", "0.001")
|
||||
end)
|
||||
end
|
||||
if (SERVER) then
|
||||
CreateConVar("sbox_maxtriggers", 10)
|
||||
|
||||
numpad.Register("trigger_solid", function(ply, prop_trigger, activate)
|
||||
if (!IsValid(prop_trigger)) then return false end
|
||||
if (prop_trigger.solid) then
|
||||
prop_trigger:DrawShadow(false)
|
||||
prop_trigger:SetNotSolid(true)
|
||||
prop_trigger:SetNoDraw(true)
|
||||
|
||||
prop_trigger:SetTrigger(true)
|
||||
prop_trigger.solid = false
|
||||
else
|
||||
prop_trigger:DrawShadow(true)
|
||||
prop_trigger:SetNotSolid(false)
|
||||
prop_trigger:SetNoDraw(false)
|
||||
|
||||
prop_trigger:SetTrigger(false)
|
||||
prop_trigger.solid = true
|
||||
end
|
||||
end)
|
||||
|
||||
function MakePropTrigger(ply, pos, ang, model, keySolid, settings)
|
||||
if (!ply:CheckLimit("triggers")) then return false end
|
||||
|
||||
local prop_trigger = ents.Create("prop_trigger")
|
||||
if (!prop_trigger:IsValid()) then return false end
|
||||
|
||||
prop_trigger:Initialize(model)
|
||||
|
||||
prop_trigger:SetOwner(ply)
|
||||
prop_trigger:SetPos(pos)
|
||||
prop_trigger:SetAngles(ang)
|
||||
|
||||
prop_trigger:Spawn()
|
||||
prop_trigger:Activate()
|
||||
prop_trigger.solid = true
|
||||
prop_trigger.ToggleSolid = numpad.OnDown(ply, keySolid, "trigger_solid", prop_trigger)
|
||||
|
||||
table.Merge(prop_trigger:GetTable(), {
|
||||
ply = ply,
|
||||
model = model,
|
||||
keySolid = keySolid,
|
||||
settings = settings,
|
||||
})
|
||||
|
||||
ply:AddCount("triggers", prop_trigger)
|
||||
|
||||
DoPropSpawnedEffect(prop_trigger)
|
||||
|
||||
return prop_trigger
|
||||
end
|
||||
|
||||
duplicator.RegisterEntityClass("prop_trigger", MakeNpcCrate, "pos", "ang", "model", "keySolid", "settings")
|
||||
end
|
||||
|
||||
function TOOL:LeftClick(trace)
|
||||
if (trace.HitSky or !trace.HitPos or IsValid(trace.Entity) and (trace.Entity:IsPlayer() or trace.Entity:IsNPC())) then return false end
|
||||
if (CLIENT) then return true end
|
||||
|
||||
if (trace.Entity:GetClass() != "prop_physics") then return false end
|
||||
|
||||
local Tbl = { }
|
||||
Tbl["type"] = self:GetClientInfo("type")
|
||||
Tbl["toggle_type"] = self:GetClientInfo("toggle_type")
|
||||
Tbl["allow_players"] = self:GetClientInfo("allow_players")
|
||||
Tbl["allow_npcs"] = self:GetClientInfo("allow_npcs")
|
||||
Tbl["allow_props"] = self:GetClientInfo("allow_props")
|
||||
Tbl["output1"] = self:GetClientInfo("output1")
|
||||
Tbl["output2"] = self:GetClientInfo("output2")
|
||||
Tbl["tar_index"] = self:GetClientInfo("target_index")
|
||||
Tbl["tar_input"] = self:GetClientInfo("target_input")
|
||||
Tbl["tar_param"] = self:GetClientInfo("target_parameter")
|
||||
Tbl["tar_delay"] = self:GetClientInfo("target_delay")
|
||||
|
||||
local ply = self:GetOwner()
|
||||
local model = trace.Entity:GetModel()
|
||||
|
||||
// Update existing Prop Trigger
|
||||
if (trace.Entity:GetClass() == "prop_trigger") then
|
||||
trace.Entity:SetOwner(ply)
|
||||
table.Merge(trace.Entity:GetTable(), {
|
||||
ply = ply,
|
||||
model = model,
|
||||
settings = Tbl,
|
||||
})
|
||||
return true
|
||||
end
|
||||
|
||||
// Create a new Prop Trigger
|
||||
local ang = trace.HitNormal:Angle()
|
||||
ang.pitch = ang.pitch - 270
|
||||
|
||||
local prop_trigger = MakePropTrigger(ply, trace.Entity:GetPos(), trace.Entity:GetAngles(), model, self:GetClientNumber("solid"), Tbl)
|
||||
trace.Entity:Remove()
|
||||
|
||||
undo.Create("prop_trigger")
|
||||
undo.AddEntity(prop_trigger)
|
||||
undo.SetPlayer(ply)
|
||||
undo.Finish()
|
||||
|
||||
ply:AddCleanup("prop_trigger", prop_trigger)
|
||||
|
||||
return true
|
||||
end
|
||||
function TOOL:RightClick(trace)
|
||||
if (trace.HitSky or trace.HitWorld or !trace.HitPos or IsValid(trace.Entity) and (trace.Entity:IsPlayer() or trace.Entity:GetClass() == "prop_trigger")) then return false end
|
||||
if (CLIENT) then return true end
|
||||
|
||||
local ply = self:GetOwner()
|
||||
local index = trace.Entity:EntIndex()
|
||||
ply:ConCommand("trigger_target_index ".. tostring(index))
|
||||
ply:SendLua("GAMEMODE:AddNotify('Target index set to ".. tostring(index) .."!', NOTIFY_GENERIC, 5)")
|
||||
|
||||
return true
|
||||
end
|
||||
function TOOL.BuildCPanel(panel)
|
||||
panel:AddControl("Numpad", { Label = "#tool.trigger.solid",
|
||||
Command = "trigger_solid",
|
||||
ButtonSize = "22"})
|
||||
panel:ControlHelp( "Toggle the Trigger visible and disabled." )
|
||||
panel:AddControl("ComboBox", {Label = "#tool.trigger.type", MenuButton = "0", Options = list.Get("PropTriggerTypes")})
|
||||
panel:AddControl("Numpad", { Label = "#tool.trigger.output1",
|
||||
Label2 = "#tool.trigger.output2",
|
||||
Command = "trigger_output1",
|
||||
Command2 = "trigger_output2",
|
||||
ButtonSize = "22"})
|
||||
panel:ControlHelp("Keys To Simulate while triggered.")
|
||||
panel:AddControl("ComboBox", {Label = "#tool.trigger.toggle_type", MenuButton = "0", Options = list.Get("PropTriggerToggleTypes")})
|
||||
panel:AddControl("Checkbox", {Label = "#tool.trigger.allow_players", Command = "trigger_allow_players"})
|
||||
panel:AddControl("Checkbox", {Label = "#tool.trigger.allow_npcs", Command = "trigger_allow_npcs"})
|
||||
panel:AddControl("Checkbox", {Label = "#tool.trigger.allow_props", Command = "trigger_allow_props"})
|
||||
panel:Help("Advanced Settings (Output 3):")
|
||||
panel:AddControl( "TextBox", { Label = "#tool.trigger.target",
|
||||
MaxLenth = "5",
|
||||
Command = "trigger_target_index" } )
|
||||
panel:ControlHelp("Target's Entity Index ..")
|
||||
panel:AddControl( "TextBox", { Label = "#tool.trigger.target_input",
|
||||
MaxLenth = "20",
|
||||
Command = "trigger_target_input" } )
|
||||
panel:ControlHelp("Via this Input ..")
|
||||
panel:AddControl( "TextBox", { Label = "#tool.trigger.target_parameter",
|
||||
MaxLenth = "20",
|
||||
Command = "trigger_target_parameter" } )
|
||||
panel:ControlHelp("With a Parameter Override of ..")
|
||||
panel:AddControl("Slider", {Label = "#tool.trigger.target_delay", Type = "Integer", Min = 0.001, Max = 10, Command = "trigger_target_delay", Help = true})
|
||||
panel:AddControl("Button", {Label = "#tool.trigger.reset", Command = "trigger_reset"})
|
||||
panel:Help("What is a Trigger?")
|
||||
panel:ControlHelp( "A Trigger can be used to activate / to fire the Inputs of other Entities. For example: Thrusters, Dynamites or Motors." )
|
||||
panel:Help("Where are they used?")
|
||||
panel:ControlHelp( "Throughout the whole Campaign of the Half-Life 2 series and other source engine based Games." )
|
||||
panel:Help("What is their purpose?")
|
||||
panel:ControlHelp( "To make a Game look more fascinating and random. It's used to create a Chain of Events happening without the Player pressing anything." )
|
||||
panel:Help("Things I should consider?")
|
||||
panel:ControlHelp("- Always move your Prop to the desired Position, before you turn it into a non-solid Trigger!")
|
||||
panel:ControlHelp("- Disable all 'toggle' or similar Options of Entities from other STools. Otherwise they get in conflict with the 'toggle' Options from this STool!")
|
||||
end
|
||||
list.Set("PropTriggerTypes", "#tool.trigger.trigger_multiple", {trigger_type = "0"})
|
||||
list.Set("PropTriggerTypes", "#tool.trigger.trigger_once", {trigger_type = "1"})
|
||||
|
||||
list.Set("PropTriggerToggleTypes", "#tool.trigger.toggle_none", {trigger_toggle_type = "0"})
|
||||
list.Set("PropTriggerToggleTypes", "#tool.trigger.toggle_touch", {trigger_toggle_type = "1"})
|
||||
list.Set("PropTriggerToggleTypes", "#tool.trigger.toggle_always", {trigger_toggle_type = "2"})
|
||||
115
lua/weapons/gmod_tool/stools/vjstool_bullseye.lua
Normal file
115
lua/weapons/gmod_tool/stools/vjstool_bullseye.lua
Normal file
@@ -0,0 +1,115 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
TOOL.Name = "#tool.vjstool_bullseye.name"
|
||||
TOOL.Tab = "DrVrej"
|
||||
TOOL.Category = "Tools"
|
||||
TOOL.Command = nil -- The console command to execute upon being selected in the Q menu.
|
||||
|
||||
TOOL.Information = {
|
||||
{name = "left"},
|
||||
}
|
||||
|
||||
TOOL.ClientConVar["type"] = "Dynamic"
|
||||
TOOL.ClientConVar["modeldirectory"] = "models/hunter/plates/plate.mdl"
|
||||
TOOL.ClientConVar["usecolor"] = 1
|
||||
TOOL.ClientConVar["startactivate"] = 1
|
||||
|
||||
-- Just to make it easier to reset everything to default
|
||||
local DefaultConVars = {}
|
||||
for k,v in pairs(TOOL.ClientConVar) do
|
||||
DefaultConVars["vjstool_bullseye_"..k] = v
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
if CLIENT then
|
||||
local function DoBuildCPanel_VJ_BullseyeSpawner(Panel)
|
||||
local reset = vgui.Create("DButton")
|
||||
reset:SetFont("DermaDefaultBold")
|
||||
reset:SetText("#vjbase.menu.general.reset.everything")
|
||||
reset:SetSize(150,25)
|
||||
reset:SetColor(Color(0,0,0,255))
|
||||
reset.DoClick = function()
|
||||
for k,v in pairs(DefaultConVars) do
|
||||
if v == "" then
|
||||
LocalPlayer():ConCommand(k.." ".."None")
|
||||
else
|
||||
LocalPlayer():ConCommand(k.." "..v) end
|
||||
timer.Simple(0.05,function()
|
||||
GetPanel = controlpanel.Get("vjstool_bullseye")
|
||||
GetPanel:ClearControls()
|
||||
DoBuildCPanel_VJ_BullseyeSpawner(GetPanel)
|
||||
end)
|
||||
end
|
||||
end
|
||||
Panel:AddPanel(reset)
|
||||
|
||||
local tutorial = vgui.Create("DButton")
|
||||
tutorial:SetFont("DermaDefaultBold")
|
||||
tutorial:SetText("#tool.vjstool.menu.tutorialvideo")
|
||||
tutorial:SetSize(150, 20)
|
||||
tutorial:SetColor(Color(0,0,255,255))
|
||||
tutorial.DoClick = function()
|
||||
gui.OpenURL("http://www.youtube.com/watch?v=Qf-vrE-BAW4")
|
||||
end
|
||||
Panel:AddPanel(tutorial)
|
||||
|
||||
Panel:AddControl("Label", {Text = "#tool.vjstool.menu.label.recommendation"})
|
||||
Panel:ControlHelp("- "..language.GetPhrase("#tool.vjstool_bullseye.menu.help1"))
|
||||
Panel:ControlHelp("- "..language.GetPhrase("#tool.vjstool_bullseye.menu.help2"))
|
||||
Panel:AddControl("Label", {Text = language.GetPhrase("#tool.vjstool_bullseye.menu.label1")..":"})
|
||||
local typebox = vgui.Create("DComboBox")
|
||||
//typebox:SetConVar("vjstool_bullseye_type")
|
||||
typebox:SetValue(GetConVarString("vjstool_bullseye_type"))
|
||||
typebox:AddChoice("Dynamic")
|
||||
typebox:AddChoice("Static")
|
||||
typebox:AddChoice("Physics")
|
||||
function typebox:OnSelect(index,value,data)
|
||||
LocalPlayer():ConCommand("vjstool_bullseye_type "..value)
|
||||
end
|
||||
Panel:AddPanel(typebox)
|
||||
Panel:AddControl("Label", {Text = language.GetPhrase("#tool.vjstool_bullseye.menu.label2")..":"})
|
||||
local modeldir = vgui.Create("DTextEntry")
|
||||
modeldir:SetConVar("vjstool_bullseye_modeldirectory")
|
||||
modeldir:SetMultiline(false)
|
||||
Panel:AddPanel(modeldir)
|
||||
Panel:AddControl("Checkbox", {Label = "#tool.vjstool_bullseye.menu.toggleusestatus", Command = "vjstool_bullseye_usecolor"})
|
||||
Panel:AddControl("Checkbox", {Label = "#tool.vjstool_bullseye.menu.togglestartactivated", Command = "vjstool_bullseye_startactivate"})
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL.BuildCPanel(Panel)
|
||||
DoBuildCPanel_VJ_BullseyeSpawner(Panel)
|
||||
end
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:LeftClick(tr)
|
||||
if CLIENT then return true end
|
||||
local spawner = ents.Create("obj_vj_bullseye")
|
||||
spawner:SetPos(tr.HitPos)
|
||||
spawner:SetModel(GetConVarString("vjstool_bullseye_modeldirectory"))
|
||||
spawner.SolidMovementType = GetConVarString("vjstool_bullseye_type")
|
||||
spawner.UseActivationSystem = true
|
||||
spawner.UserStatusColors = GetConVar("vjstool_bullseye_usecolor"):GetBool()
|
||||
spawner.Activated = GetConVar("vjstool_bullseye_startactivate"):GetBool()
|
||||
spawner:Spawn()
|
||||
spawner:Activate()
|
||||
undo.Create("NPC Bullseye")
|
||||
undo.AddEntity(spawner)
|
||||
undo.SetPlayer(self:GetOwner())
|
||||
undo.Finish()
|
||||
return true
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:RightClick(tr)
|
||||
if CLIENT then return true end
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:Reload(tr)
|
||||
if CLIENT then return true end
|
||||
end
|
||||
66
lua/weapons/gmod_tool/stools/vjstool_entityscanner.lua
Normal file
66
lua/weapons/gmod_tool/stools/vjstool_entityscanner.lua
Normal file
@@ -0,0 +1,66 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
TOOL.Name = "#tool.vjstool_entityscanner.name"
|
||||
TOOL.Tab = "DrVrej"
|
||||
TOOL.Category = "Tools"
|
||||
TOOL.Command = nil -- The console command to execute upon being selected in the Q menu.
|
||||
|
||||
TOOL.Information = {
|
||||
{name = "left"},
|
||||
}
|
||||
|
||||
-- Just to make it easier to reset everything to default
|
||||
local DefaultConVars = {}
|
||||
for k,v in pairs(TOOL.ClientConVar) do
|
||||
DefaultConVars["vjstool_entityscanner_"..k] = v
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
if CLIENT then
|
||||
local function DoBuildCPanel_EntityScanner(Panel)
|
||||
Panel:AddControl("Label", {Text = "#tool.vjstool_entityscanner.label"})
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL.BuildCPanel(Panel)
|
||||
DoBuildCPanel_EntityScanner(Panel)
|
||||
end
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:LeftClick(tr)
|
||||
if CLIENT then return true end
|
||||
if !IsValid(tr.Entity) then return false end
|
||||
local Ent = tr.Entity
|
||||
local Phys = Ent:GetPhysicsObject()
|
||||
PrintMessage(HUD_PRINTCONSOLE,"------------------- Name = "..Ent:GetName().." ||| Class = "..Ent:GetClass().." ||| Index = "..Ent:EntIndex().." -------------------")
|
||||
PrintMessage(HUD_PRINTCONSOLE,"MODEL: File Path = "..Ent:GetModel().." ||| Skin = "..Ent:GetSkin())
|
||||
PrintMessage(HUD_PRINTCONSOLE,"POSITION: Vector("..Ent:GetPos().x..", "..Ent:GetPos().y..", "..Ent:GetPos().z..") ||| X = "..Ent:GetPos().x.." , Y = "..Ent:GetPos().y.." , Z = "..Ent:GetPos().z)
|
||||
PrintMessage(HUD_PRINTCONSOLE,"ANGLE: Angle("..Ent:GetAngles().p..", "..Ent:GetAngles().y..", "..Ent:GetAngles().r..") ||| Pitch = "..Ent:GetAngles().p.." , Yaw = "..Ent:GetAngles().y.." , Roll = "..Ent:GetAngles().r)
|
||||
PrintMessage(HUD_PRINTCONSOLE,"SEQUENCE: ID = "..Ent:GetSequence().." ||| Name = "..Ent:GetSequenceName(Ent:GetSequence()).." ||| Duration = "..VJ_GetSequenceDuration(Ent,Ent:GetSequenceName(Ent:GetSequence())))
|
||||
if IsValid(Phys) then
|
||||
PrintMessage(HUD_PRINTCONSOLE,"VELOCITY: Vector("..Phys:GetVelocity().x..", "..Phys:GetVelocity().y..", "..Phys:GetVelocity().z..") ||| X = "..Phys:GetVelocity().x.." , Y = "..Phys:GetVelocity().y.." , Z = "..Phys:GetVelocity().z.." ||| Length = "..Phys:GetVelocity():Length())
|
||||
PrintMessage(HUD_PRINTCONSOLE,"PHYSICS: Mass = "..Phys:GetMass().." ||| Surface Area = "..Phys:GetSurfaceArea().." ||| Volume = "..Phys:GetVolume())
|
||||
else
|
||||
PrintMessage(HUD_PRINTCONSOLE,"VELOCITY: Can't display this information! Reason: Model doesn't have proper physics!")
|
||||
PrintMessage(HUD_PRINTCONSOLE,"PHYSICS: Can't display this information! Reason: Model doesn't have proper physics!")
|
||||
end
|
||||
PrintMessage(HUD_PRINTCONSOLE,"COLOR: Color("..Ent:GetColor().r..", "..Ent:GetColor().g..", "..Ent:GetColor().b..", "..Ent:GetColor().a..") ||| Red = "..Ent:GetColor().r.." , Green = "..Ent:GetColor().g.." , Blue = "..Ent:GetColor().b.." , Alpha = "..Ent:GetColor().a)
|
||||
PrintMessage(HUD_PRINTCONSOLE,"-----------------------------------------------------------------------------------------------")
|
||||
return true
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:RightClick(tr)
|
||||
if CLIENT then return true end
|
||||
return false
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:Reload(tr)
|
||||
if CLIENT then return true end
|
||||
return false
|
||||
end
|
||||
152
lua/weapons/gmod_tool/stools/vjstool_healthmodifier.lua
Normal file
152
lua/weapons/gmod_tool/stools/vjstool_healthmodifier.lua
Normal file
@@ -0,0 +1,152 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
TOOL.Name = "#tool.vjstool_healthmodifier.name"
|
||||
TOOL.Tab = "DrVrej"
|
||||
TOOL.Category = "Tools"
|
||||
TOOL.Command = nil -- The console command to execute upon being selected in the Q menu.
|
||||
|
||||
TOOL.Information = {
|
||||
{name = "left"},
|
||||
{name = "right"},
|
||||
{name = "reload"},
|
||||
}
|
||||
|
||||
TOOL.ClientConVar["health"] = "100"
|
||||
TOOL.ClientConVar["godmode"] = 0
|
||||
TOOL.ClientConVar["healthregen"] = 0
|
||||
TOOL.ClientConVar["healthregen_amt"] = 4
|
||||
TOOL.ClientConVar["healthregen_delay"] = 5
|
||||
|
||||
-- Just to make it easier to reset everything to default
|
||||
local DefaultConVars = {}
|
||||
for k,v in pairs(TOOL.ClientConVar) do
|
||||
DefaultConVars["vjstool_healthmodifier_"..k] = v
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
if CLIENT then
|
||||
function DoBuildCPanel_VJ_HealthModifier(Panel)
|
||||
local reset = vgui.Create("DButton")
|
||||
reset:SetFont("DermaDefaultBold")
|
||||
reset:SetText("#vjbase.menu.general.reset.everything")
|
||||
reset:SetSize(150,25)
|
||||
reset:SetColor(Color(0,0,0,255))
|
||||
reset.DoClick = function()
|
||||
for k,v in pairs(DefaultConVars) do
|
||||
if v == "" then
|
||||
LocalPlayer():ConCommand(k.." ".."None")
|
||||
else
|
||||
LocalPlayer():ConCommand(k.." "..v) end
|
||||
timer.Simple(0.05,function()
|
||||
GetPanel = controlpanel.Get("vjstool_healthmodifier")
|
||||
GetPanel:ClearControls()
|
||||
DoBuildCPanel_VJ_HealthModifier(GetPanel)
|
||||
end)
|
||||
end
|
||||
end
|
||||
Panel:AddPanel(reset)
|
||||
|
||||
local tutorial = vgui.Create("DButton")
|
||||
tutorial:SetFont("DermaDefaultBold")
|
||||
tutorial:SetText("#tool.vjstool.menu.tutorialvideo")
|
||||
tutorial:SetSize(150, 20)
|
||||
tutorial:SetColor(Color(0,0,255,255))
|
||||
tutorial.DoClick = function()
|
||||
gui.OpenURL("http://www.youtube.com/watch?v=kLygPP-vbHY")
|
||||
end
|
||||
Panel:AddPanel(tutorial)
|
||||
|
||||
Panel:AddControl("Label", {Text = "#tool.vjstool_healthmodifier.adminonly"})
|
||||
Panel:AddControl("Slider", {Label = "#tool.vjstool_healthmodifier.sliderhealth", min = 0, max = 10000, Command = "vjstool_healthmodifier_health"})
|
||||
Panel:AddControl("Label", {Text = "#tool.vjstool_healthmodifier.label1"})
|
||||
Panel:AddControl("Checkbox", {Label = "#tool.vjstool_healthmodifier.togglegodmode", Command = "vjstool_healthmodifier_godmode"})
|
||||
Panel:AddControl("Checkbox", {Label = "#tool.vjstool_healthmodifier.togglehealthregen", Command = "vjstool_healthmodifier_healthregen"})
|
||||
Panel:AddControl("Slider", {Label = "#tool.vjstool_healthmodifier.sliderhealthregenamt", min = 0, max = 10000, Command = "vjstool_healthmodifier_healthregen_amt"})
|
||||
Panel:AddControl("Slider", {Label = "#tool.vjstool_healthmodifier.sliderhealthregendelay", min = 0, max = 10000, Command = "vjstool_healthmodifier_healthregen_delay"})
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL.BuildCPanel(Panel)
|
||||
DoBuildCPanel_VJ_HealthModifier(Panel)
|
||||
end
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:LeftClick(tr)
|
||||
if CLIENT then return true end
|
||||
if IsValid(tr.Entity) then
|
||||
local Ply = self:GetOwner()
|
||||
local trent = tr.Entity
|
||||
local canheal = true
|
||||
if (trent:Health() != 0 or (trent:IsNPC() or trent:IsPlayer())) then
|
||||
if trent:IsPlayer() && !Ply:IsAdmin() then
|
||||
canheal = false
|
||||
end
|
||||
if canheal == true then
|
||||
trent:SetHealth(self:GetClientNumber("health"))
|
||||
Ply:ChatPrint("Set "..trent:GetClass().."'s health to "..self:GetClientNumber("health"))
|
||||
if trent:IsNPC() then
|
||||
if self:GetClientNumber("godmode") == 1 then trent.GodMode = true else trent.GodMode = false end
|
||||
if trent.IsVJBaseSNPC == true && self:GetClientNumber("healthregen") == 1 then
|
||||
trent.HasHealthRegeneration = true
|
||||
trent.HealthRegenerationAmount = self:GetClientNumber("healthregen_amt")
|
||||
trent.HealthRegenerationDelay = VJ_Set(self:GetClientNumber("healthregen_delay"), self:GetClientNumber("healthregen_delay"))
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:RightClick(tr)
|
||||
if CLIENT then return true end
|
||||
if IsValid(tr.Entity) then
|
||||
local Ply = self:GetOwner()
|
||||
local trent = tr.Entity
|
||||
local canheal = true
|
||||
if (trent:Health() != 0 or (trent:IsNPC() or trent:IsPlayer())) then
|
||||
if trent:IsPlayer() && !Ply:IsAdmin() then
|
||||
canheal = false
|
||||
end
|
||||
if canheal == true then
|
||||
trent:SetHealth(self:GetClientNumber("health"))
|
||||
trent:SetMaxHealth(self:GetClientNumber("health"))
|
||||
Ply:ChatPrint("Set "..trent:GetClass().."'s health and max health to "..self:GetClientNumber("health"))
|
||||
if trent:IsNPC() then
|
||||
if self:GetClientNumber("godmode") == 1 then trent.GodMode = true else trent.GodMode = false end
|
||||
if trent.IsVJBaseSNPC == true && self:GetClientNumber("healthregen") == 1 then
|
||||
trent.HasHealthRegeneration = true
|
||||
trent.HealthRegenerationAmount = self:GetClientNumber("healthregen_amt")
|
||||
trent.HealthRegenerationDelay = VJ_Set(self:GetClientNumber("healthregen_delay"), self:GetClientNumber("healthregen_delay"))
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:Reload(tr)
|
||||
if CLIENT then return true end
|
||||
if IsValid(tr.Entity) then
|
||||
local Ply = self:GetOwner()
|
||||
local trent = tr.Entity
|
||||
local canheal = true
|
||||
if (trent:Health() != 0 or (trent:IsNPC() or trent:IsPlayer())) then
|
||||
if trent:IsPlayer() && !Ply:IsAdmin() then
|
||||
canheal = false
|
||||
end
|
||||
if canheal == true then
|
||||
trent:SetHealth(trent:GetMaxHealth())
|
||||
Ply:ChatPrint("Healed "..trent:GetClass().." to its max health ("..trent:GetMaxHealth()..")")
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
66
lua/weapons/gmod_tool/stools/vjstool_notarget.lua
Normal file
66
lua/weapons/gmod_tool/stools/vjstool_notarget.lua
Normal file
@@ -0,0 +1,66 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
TOOL.Name = "#tool.vjstool_notarget.name"
|
||||
TOOL.Tab = "DrVrej"
|
||||
TOOL.Category = "Tools"
|
||||
TOOL.Command = nil -- The console command to execute upon being selected in the Q menu.
|
||||
|
||||
TOOL.Information = {
|
||||
{name = "left"},
|
||||
{name = "right"},
|
||||
}
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
if CLIENT then
|
||||
local function DoBuildCPanel_NoTarget(Panel)
|
||||
Panel:AddControl("Label", {Text = "#tool.vjstool_notarget.label"})
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL.BuildCPanel(Panel)
|
||||
DoBuildCPanel_NoTarget(Panel)
|
||||
end
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:LeftClick(tr)
|
||||
if CLIENT then return true end
|
||||
local Ply = self:GetOwner()
|
||||
if Ply:IsFlagSet(FL_NOTARGET) != true then
|
||||
Ply:ChatPrint("#tool.vjstool_notarget.print.yourselfon")
|
||||
Ply:AddFlags(FL_NOTARGET)
|
||||
return true
|
||||
else
|
||||
Ply:ChatPrint("#tool.vjstool_notarget.print.yourselfoff")
|
||||
Ply:RemoveFlags(FL_NOTARGET)
|
||||
return true
|
||||
end
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:RightClick(tr)
|
||||
if CLIENT then return true end
|
||||
if !IsValid(tr.Entity) then return false end
|
||||
local Ply = self:GetOwner()
|
||||
local Ent = tr.Entity
|
||||
|
||||
local name = Ent:IsPlayer() and Ent:Nick() or Ent:GetClass()
|
||||
if Ent:IsFlagSet(FL_NOTARGET) != true then
|
||||
Ply:ChatPrint("Set no target to "..name..": ON")
|
||||
Ent:AddFlags(FL_NOTARGET)
|
||||
return true
|
||||
else
|
||||
Ply:ChatPrint("Set no target to "..name..": OFF")
|
||||
Ent:RemoveFlags(FL_NOTARGET)
|
||||
return true
|
||||
end
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:Reload(tr)
|
||||
if CLIENT then return true end
|
||||
return false
|
||||
end
|
||||
124
lua/weapons/gmod_tool/stools/vjstool_npcequipment.lua
Normal file
124
lua/weapons/gmod_tool/stools/vjstool_npcequipment.lua
Normal file
@@ -0,0 +1,124 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
TOOL.Name = "#tool.vjstool_npcequipment.name"
|
||||
TOOL.Tab = "DrVrej"
|
||||
TOOL.Category = "Tools"
|
||||
TOOL.Command = nil -- The console command to execute upon being selected in the Q menu.
|
||||
|
||||
TOOL.Information = {
|
||||
{name = "left"},
|
||||
{name = "right"},
|
||||
}
|
||||
|
||||
TOOL.ClientConVar["weaponclass"] = "None"
|
||||
TOOL.ClientConVar["weaponname"] = "Unknown"
|
||||
|
||||
-- Just to make it easier to reset everything to default
|
||||
local DefaultConVars = {}
|
||||
for k,v in pairs(TOOL.ClientConVar) do
|
||||
DefaultConVars["vjstool_npcequipment_"..k] = v
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
if CLIENT then
|
||||
local function DoBuildCPanel_VJ_NPCEquipment(Panel)
|
||||
local reset = vgui.Create("DButton")
|
||||
reset:SetFont("DermaDefaultBold")
|
||||
reset:SetText("#vjbase.menu.general.reset.everything")
|
||||
reset:SetSize(150,25)
|
||||
reset:SetColor(Color(0,0,0,255))
|
||||
reset.DoClick = function()
|
||||
for k,v in pairs(DefaultConVars) do
|
||||
if v == "" then
|
||||
LocalPlayer():ConCommand(k.." ".."None")
|
||||
else
|
||||
LocalPlayer():ConCommand(k.." "..v) end
|
||||
timer.Simple(0.05,function()
|
||||
GetPanel = controlpanel.Get("vjstool_npcequipment")
|
||||
GetPanel:ClearControls()
|
||||
DoBuildCPanel_VJ_NPCEquipment(GetPanel)
|
||||
end)
|
||||
end
|
||||
end
|
||||
Panel:AddPanel(reset)
|
||||
|
||||
Panel:AddControl("Label", {Text = "#tool.vjstool.menu.label.recommendation"})
|
||||
Panel:ControlHelp("#tool.vjstool_npcequipment.label")
|
||||
|
||||
local selectwep = vgui.Create("DTextEntry")
|
||||
selectwep:SetEditable(false)
|
||||
selectwep:SetText(language.GetPhrase("#tool.vjstool_npcequipment.selectedequipment")..": "..GetConVarString("vjstool_npcequipment_weaponname").." ["..GetConVarString("vjstool_npcequipment_weaponclass").."]")
|
||||
selectwep.OnGetFocus = function() LocalPlayer():ConCommand("vj_npcequipment_openwepselect") end
|
||||
Panel:AddItem(selectwep)
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL.BuildCPanel(Panel)
|
||||
DoBuildCPanel_VJ_NPCEquipment(Panel)
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
concommand.Add("vj_npcequipment_openwepselect",function(pl,cmd,args)
|
||||
local MenuFrame = vgui.Create('DFrame')
|
||||
MenuFrame:SetSize(420, 440)
|
||||
MenuFrame:SetPos(ScrW()*0.6, ScrH()*0.1)
|
||||
MenuFrame:SetTitle("#tool.vjstool_npcequipment.print.doubleclick")
|
||||
//MenuFrame:SetBackgroundBlur(true)
|
||||
MenuFrame:SetFocusTopLevel(true)
|
||||
MenuFrame:SetSizable(true)
|
||||
MenuFrame:ShowCloseButton(true)
|
||||
//MenuFrame:SetDeleteOnClose(false)
|
||||
MenuFrame:MakePopup()
|
||||
|
||||
local CheckList = vgui.Create("DListView")
|
||||
CheckList:SetTooltip(false)
|
||||
CheckList:SetParent(MenuFrame)
|
||||
CheckList:SetPos(10,30)
|
||||
CheckList:SetSize(400,400) -- Size
|
||||
CheckList:SetMultiSelect(false)
|
||||
CheckList:AddColumn("#tool.vjstool_npcequipment.header1")
|
||||
CheckList:AddColumn("#tool.vjstool_npcequipment.header2")
|
||||
CheckList.OnRowSelected = function() chat.AddText(Color(0,255,0), "#tool.vjstool_npcequipment.print.doubleclick") end
|
||||
function CheckList:DoDoubleClick(lineID,line)
|
||||
chat.AddText(Color(0,255,0), "#tool.vjstool_npcequipment.print.weaponselected1", Color(255,100,0), " "..line:GetValue(1).." ", Color(0,255,0), "#tool.vjstool_npcequipment.print.weaponselected2")
|
||||
LocalPlayer():ConCommand("vjstool_npcequipment_weaponname "..line:GetValue(1))
|
||||
LocalPlayer():ConCommand("vjstool_npcequipment_weaponclass "..line:GetValue(2))
|
||||
MenuFrame:Close()
|
||||
timer.Simple(0.05,function()
|
||||
GetPanel = controlpanel.Get("vjstool_npcequipment")
|
||||
GetPanel:ClearControls()
|
||||
DoBuildCPanel_VJ_NPCEquipment(GetPanel)
|
||||
end)
|
||||
end
|
||||
//MenuFrame:AddItem(CheckList)
|
||||
//CheckList:SizeToContents()
|
||||
for _,v in pairs(list.Get("NPCUsableWeapons")) do
|
||||
CheckList:AddLine(v.title,v.class)
|
||||
end
|
||||
CheckList:SortByColumn(1,false)
|
||||
end)
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:LeftClick(tr)
|
||||
if CLIENT then return true end
|
||||
if !tr.Entity:IsNPC() then return end
|
||||
if IsValid(tr.Entity:GetActiveWeapon()) then tr.Entity:GetActiveWeapon():Remove() end
|
||||
tr.Entity:Give(GetConVarString("vjstool_npcequipment_weaponclass"))
|
||||
return true
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:RightClick(tr)
|
||||
if CLIENT then return true end
|
||||
if !tr.Entity:IsNPC() then return end
|
||||
if IsValid(tr.Entity:GetActiveWeapon()) then tr.Entity:GetActiveWeapon():Remove() end
|
||||
return true
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:Reload(tr)
|
||||
if CLIENT then return true end
|
||||
end
|
||||
144
lua/weapons/gmod_tool/stools/vjstool_npcfollower.lua
Normal file
144
lua/weapons/gmod_tool/stools/vjstool_npcfollower.lua
Normal file
@@ -0,0 +1,144 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
TOOL.Name = "#tool.vjstool_npcfollower.name"
|
||||
TOOL.Tab = "DrVrej"
|
||||
TOOL.Category = "Tools"
|
||||
TOOL.Command = nil -- The console command to execute upon being selected in the Q menu.
|
||||
|
||||
TOOL.Information = {
|
||||
{name = "left"},
|
||||
{name = "right"},
|
||||
{name = "reload"},
|
||||
}
|
||||
|
||||
-- Just to make it easier to reset everything to default
|
||||
local DefaultConVars = {}
|
||||
for k,v in pairs(TOOL.ClientConVar) do
|
||||
DefaultConVars["vjstool_npcfollower_"..k] = v
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
if CLIENT then
|
||||
NPC_FOLLOWER_ENT_NAME = "None"
|
||||
local function DoBuildCPanel_NPCFollower(Panel)
|
||||
local reset = vgui.Create("DButton")
|
||||
reset:SetFont("DermaDefaultBold")
|
||||
reset:SetText("#vjbase.menu.general.reset.everything")
|
||||
reset:SetSize(150, 25)
|
||||
reset:SetColor(Color(0,0,0,255))
|
||||
reset.DoClick = function()
|
||||
for k, v in pairs(DefaultConVars) do
|
||||
if v == "" then
|
||||
LocalPlayer():ConCommand(k.." ".."None")
|
||||
else
|
||||
LocalPlayer():ConCommand(k.." "..v)
|
||||
end
|
||||
timer.Simple(0.05,function()
|
||||
GetPanel = controlpanel.Get("vjstool_npcfollower")
|
||||
GetPanel:ClearControls()
|
||||
DoBuildCPanel_NPCFollower(GetPanel)
|
||||
end)
|
||||
end
|
||||
end
|
||||
Panel:AddPanel(reset)
|
||||
|
||||
Panel:AddControl("Label", {Text = "#tool.vjstool.menu.label.recommendation"})
|
||||
Panel:AddControl("Label", {Text = "Selected NPC: " .. NPC_FOLLOWER_ENT_NAME})
|
||||
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
net.Receive("vj_npcfollower_cl_update", function(len, ply)
|
||||
local wep = LocalPlayer():GetActiveWeapon()
|
||||
if wep:IsValid() && wep:GetClass() == "gmod_tool" && wep:GetMode() == "vjstool_npcfollower" then
|
||||
local entName = net.ReadString()
|
||||
NPC_FOLLOWER_ENT_NAME = entName
|
||||
GetPanel = controlpanel.Get("vjstool_npcfollower")
|
||||
GetPanel:ClearControls()
|
||||
DoBuildCPanel_NPCFollower(GetPanel)
|
||||
end
|
||||
end)
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL.BuildCPanel(Panel)
|
||||
DoBuildCPanel_NPCFollower(Panel)
|
||||
end
|
||||
else -- If SERVER
|
||||
util.AddNetworkString("vj_npcfollower_cl_update")
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:LeftClick(tr)
|
||||
if CLIENT then return true end
|
||||
local ent = tr.Entity
|
||||
if (!IsValid(ent)) then return end
|
||||
if !ent:IsNPC() then return end
|
||||
if !ent.IsVJBaseSNPC then return end
|
||||
|
||||
local NPCname = list.Get("NPC")[ent:GetClass()].Name
|
||||
local ply = self:GetOwner()
|
||||
self:ClearObjects()
|
||||
self:SetObject(1, ent, tr.HitPos, Phys, tr.PhysicsBone, tr.HitNormal)
|
||||
//if CLIENT then return true end
|
||||
ply:ChatPrint(NPCname .. " Has been selected!")
|
||||
|
||||
net.Start("vj_npcfollower_cl_update")
|
||||
net.WriteString(NPCname)
|
||||
net.Send(ply)
|
||||
return true
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:RightClick(tr)
|
||||
if CLIENT then return true end
|
||||
local ent = tr.Entity
|
||||
if (!IsValid(ent)) then return end
|
||||
|
||||
local iNum = self:NumObjects()
|
||||
local ply = self:GetOwner()
|
||||
if iNum >= 1 then
|
||||
local selectedEnt = self:GetEnt(1)
|
||||
if IsValid(selectedEnt) then
|
||||
if selectedEnt:Follow(ent, false) then
|
||||
self:ClearObjects()
|
||||
ply:ChatPrint(list.Get("NPC")[selectedEnt:GetClass()].Name .. " is now following " .. ent:GetClass())
|
||||
else
|
||||
ply:ChatPrint(list.Get("NPC")[selectedEnt:GetClass()].Name .. " is currently unable to follow!")
|
||||
end
|
||||
else
|
||||
ply:ChatPrint("#tool.vjstool_npcfollower.print.noselection")
|
||||
end
|
||||
else
|
||||
ply:ChatPrint("#tool.vjstool_npcfollower.print.noselection")
|
||||
end
|
||||
//if CLIENT then return true end
|
||||
net.Start("vj_npcfollower_cl_update")
|
||||
net.WriteString("None")
|
||||
net.Send(ply)
|
||||
return true
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:Reload(tr)
|
||||
if CLIENT then return true end
|
||||
local ent = tr.Entity
|
||||
if (!IsValid(ent)) then return end
|
||||
if !ent:IsNPC() then return end
|
||||
if !ent.IsVJBaseSNPC then return end
|
||||
|
||||
ent:FollowReset()
|
||||
local ply = self:GetOwner()
|
||||
ply:ChatPrint("#tool.vjstool_npcfollower.print.reset")
|
||||
return true
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:Holster()
|
||||
if SERVER then
|
||||
net.Start("vj_npcfollower_cl_update")
|
||||
net.WriteString("None")
|
||||
net.Send(self:GetOwner())
|
||||
end
|
||||
self:ClearObjects()
|
||||
end
|
||||
294
lua/weapons/gmod_tool/stools/vjstool_npcmover.lua
Normal file
294
lua/weapons/gmod_tool/stools/vjstool_npcmover.lua
Normal file
@@ -0,0 +1,294 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
TOOL.Name = "#tool.vjstool_npcmover.name"
|
||||
TOOL.Tab = "DrVrej"
|
||||
TOOL.Category = "Tools"
|
||||
TOOL.Command = nil -- The console command to execute upon being selected in the Q menu.
|
||||
|
||||
TOOL.Information = {
|
||||
{name = "left"},
|
||||
{name = "right"},
|
||||
{name = "reload"},
|
||||
}
|
||||
|
||||
-- Just to make it easier to reset everything to default
|
||||
local DefaultConVars = {}
|
||||
for k,v in pairs(TOOL.ClientConVar) do
|
||||
DefaultConVars["vjstool_npcmover_"..k] = v
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
if CLIENT then
|
||||
local function DoBuildCPanel_Mover(Panel)
|
||||
VJ_MOVE_TblCurrentValues = VJ_MOVE_TblCurrentValues or {}
|
||||
VJ_MOVE_TblCurrentLines = VJ_MOVE_TblCurrentLines or {}
|
||||
|
||||
local reset = vgui.Create("DButton")
|
||||
reset:SetFont("DermaDefaultBold")
|
||||
reset:SetText("#vjbase.menu.general.reset.everything")
|
||||
reset:SetSize(150,25)
|
||||
reset:SetColor(Color(0,0,0,255))
|
||||
reset.DoClick = function()
|
||||
for k,v in pairs(DefaultConVars) do
|
||||
if v == "" then
|
||||
LocalPlayer():ConCommand(k.." ".."None")
|
||||
else
|
||||
LocalPlayer():ConCommand(k.." "..v) end
|
||||
timer.Simple(0.05,function()
|
||||
GetPanel = controlpanel.Get("vjstool_npcmover")
|
||||
GetPanel:ClearControls()
|
||||
DoBuildCPanel_Mover(GetPanel)
|
||||
end)
|
||||
end
|
||||
end
|
||||
Panel:AddPanel(reset)
|
||||
|
||||
Panel:AddControl("Label", {Text = "#tool.vjstool.menu.label.recommendation"})
|
||||
local CheckList = vgui.Create("DListView")
|
||||
CheckList:SetTooltip(false)
|
||||
//CheckList:Center() -- No need since Size does it already
|
||||
CheckList:SetSize(100, 300) -- Size
|
||||
CheckList:SetMultiSelect(false)
|
||||
//CheckList.Paint = function()
|
||||
//draw.RoundedBox(8, 0, 0, CheckList:GetWide(), CheckList:GetTall(), Color(0, 0, 100, 255))
|
||||
//end
|
||||
CheckList:AddColumn("#tool.vjstool_npcmover.header1")
|
||||
CheckList:AddColumn("#tool.vjstool_npcmover.header2")
|
||||
//CheckList:AddColumn("Index")
|
||||
CheckList:AddColumn("#tool.vjstool_npcmover.header3")
|
||||
//CheckList:AddColumn("Position")
|
||||
//CheckList:AddColumn("Equipment")
|
||||
for _,v in ipairs(VJ_MOVE_TblCurrentValues) do
|
||||
if IsValid(v) then
|
||||
local locname = "Unknown"
|
||||
for _,lv in pairs(list.Get("NPC")) do
|
||||
if v:GetClass() == lv.Class then locname = lv.Name end
|
||||
end
|
||||
CheckList:AddLine(locname,v:GetClass(),v) //v:EntIndex()
|
||||
//CheckList:AddLine(v)
|
||||
end
|
||||
end
|
||||
CheckList.OnRowSelected = function(rowIndex,row) chat.AddText(Color(0,255,0),"Double click to ",Color(255,100,0),"unselect ",Color(0,255,0),"a NPC") end
|
||||
function CheckList:DoDoubleClick(lineID,line)
|
||||
chat.AddText(Color(0,255,0),"NPC",Color(255,100,0)," "..line:GetValue(1).." ",Color(0,255,0),"unselected!")
|
||||
net.Start("vj_npcmover_remove")
|
||||
net.WriteTable({line:GetValue(3)})
|
||||
net.SendToServer()
|
||||
CheckList:RemoveLine(lineID)
|
||||
table.Empty(VJ_MOVE_TblCurrentValues)
|
||||
for _,vLine in pairs(CheckList:GetLines()) do
|
||||
table.insert(VJ_MOVE_TblCurrentValues,vLine:GetValue(3))
|
||||
end
|
||||
end
|
||||
Panel:AddItem(CheckList)
|
||||
//VJ_MOVE_TblCurrentLines = CheckList:GetLines()
|
||||
|
||||
local unselectall = vgui.Create("DButton")
|
||||
unselectall:SetFont("DermaDefaultBold")
|
||||
unselectall:SetText("#tool.vjstool_npcmover.buttonunselectall")
|
||||
unselectall:SetSize(150, 25)
|
||||
unselectall:SetColor(Color(0,0,0,255))
|
||||
unselectall.DoClick = function()
|
||||
local brah = VJ_MOVE_TblCurrentValues
|
||||
if table.Count(brah) > 0 then
|
||||
chat.AddText(Color(255,100,0), "#tool.vjstool_npcmover.print.unselectedall")
|
||||
else
|
||||
chat.AddText(Color(0,255,0), "#tool.vjstool_npcmover.print.unselectedall.error")
|
||||
end
|
||||
net.Start("vj_npcmover_remove")
|
||||
net.WriteTable(brah)
|
||||
net.SendToServer()
|
||||
table.Empty(brah)
|
||||
CheckList:Clear()
|
||||
end
|
||||
Panel:AddPanel(unselectall)
|
||||
//Panel:AddControl("Checkbox", {Label = "Kill The Enemy", Command = "vjstool_npccontroller_killenemy"})
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
net.Receive("vj_npcmover_cl_create", function(len, ply)
|
||||
local wep = LocalPlayer():GetActiveWeapon()
|
||||
if wep:IsValid() && wep:GetClass() == "gmod_tool" && wep:GetMode() == "vjstool_npcmover" then
|
||||
local sventity = net.ReadEntity()
|
||||
local sventname = net.ReadString()
|
||||
VJ_MOVE_TblCurrentValues = VJ_MOVE_TblCurrentValues or {}
|
||||
//if svchangetype == "AddNPC" then table.insert(VJ_MOVE_TblCurrentValues,sventity) end
|
||||
local changetype = 0 -- Check if we are removing or adding an NPC | 0 = Add, 1 = Remove
|
||||
for k,v in ipairs(VJ_MOVE_TblCurrentValues) do
|
||||
if !IsValid(v) then table.remove(VJ_MOVE_TblCurrentValues,k) continue end -- Remove any NPCs that no longer exist!
|
||||
if v == sventity then -- If the selected NPC already exists then unselect it!
|
||||
chat.AddText(Color(0,255,0),"NPC",Color(255,100,0)," "..sventname.." ",Color(0,255,0),"unselected!")
|
||||
changetype = 1
|
||||
table.remove(VJ_MOVE_TblCurrentValues, k)
|
||||
end
|
||||
end
|
||||
if changetype == 0 then -- Only if we are adding
|
||||
chat.AddText(Color(0,255,0),"NPC",Color(255,100,0)," "..sventname.." ",Color(0,255,0),"selected!")
|
||||
table.insert(VJ_MOVE_TblCurrentValues,sventity)
|
||||
end
|
||||
-- Refresh the tool menu
|
||||
GetPanel = controlpanel.Get("vjstool_npcmover")
|
||||
GetPanel:ClearControls()
|
||||
DoBuildCPanel_Mover(GetPanel)
|
||||
net.Start("vj_npcmover_sv_create")
|
||||
net.WriteEntity(sventity)
|
||||
net.WriteBit(changetype)
|
||||
net.SendToServer()
|
||||
//print("Current Entity: ",sventity)
|
||||
//print("--------------")
|
||||
//PrintTable(VJ_MOVE_TblCurrentValues)
|
||||
//print("--------------")
|
||||
end
|
||||
end)
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
net.Receive("vj_npcmover_cl_startmove", function(len, ply)
|
||||
local svwalktype = net.ReadBit()
|
||||
local svvector = net.ReadVector()
|
||||
local wep = LocalPlayer():GetActiveWeapon()
|
||||
if wep:IsValid() && wep:GetClass() == "gmod_tool" && wep:GetMode() == "vjstool_npcmover" then
|
||||
for k,v in ipairs(VJ_MOVE_TblCurrentValues) do
|
||||
if !IsValid(v) then -- Remove any NPCs that no longer exist!
|
||||
table.remove(VJ_MOVE_TblCurrentValues,k)
|
||||
GetPanel = controlpanel.Get("vjstool_npcmover")
|
||||
GetPanel:ClearControls()
|
||||
DoBuildCPanel_Mover(GetPanel)
|
||||
end
|
||||
end
|
||||
net.Start("vj_npcmover_sv_startmove")
|
||||
net.WriteTable(VJ_MOVE_TblCurrentValues)
|
||||
net.WriteBit(svwalktype)
|
||||
net.WriteVector(svvector)
|
||||
net.SendToServer()
|
||||
end
|
||||
end)
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL.BuildCPanel(Panel)
|
||||
DoBuildCPanel_Mover(Panel)
|
||||
end
|
||||
else -- If SERVER
|
||||
util.AddNetworkString("vj_npcmover_cl_create")
|
||||
util.AddNetworkString("vj_npcmover_sv_create")
|
||||
util.AddNetworkString("vj_npcmover_cl_startmove")
|
||||
util.AddNetworkString("vj_npcmover_sv_startmove")
|
||||
util.AddNetworkString("vj_npcmover_remove")
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
net.Receive("vj_npcmover_sv_create", function(len, ply)
|
||||
local wep = ply:GetActiveWeapon()
|
||||
if wep:IsValid() && wep:GetClass() == "gmod_tool" && wep:GetMode() == "vjstool_npcmover" then
|
||||
local sventity = net.ReadEntity()
|
||||
local svchangetype = net.ReadBit()
|
||||
if svchangetype == 0 then
|
||||
//print("fully added")
|
||||
sventity.VJ_IsBeingControlled_Tool = true
|
||||
sventity:StopMoving()
|
||||
if sventity.IsVJBaseSNPC == true then
|
||||
sventity.DisableWandering = true
|
||||
sventity.DisableChasingEnemy = true
|
||||
end
|
||||
elseif svchangetype == 1 then
|
||||
//print("fully removed")
|
||||
sventity.VJ_IsBeingControlled_Tool = false
|
||||
if sventity.IsVJBaseSNPC == true then
|
||||
sventity.DisableWandering = false
|
||||
sventity.DisableChasingEnemy = false
|
||||
sventity:SelectSchedule()
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
net.Receive("vj_npcmover_remove", function(len, ply)
|
||||
local wep = ply:GetActiveWeapon()
|
||||
if wep:IsValid() && wep:GetClass() == "gmod_tool" && wep:GetMode() == "vjstool_npcmover" then
|
||||
local brahtbl = net.ReadTable()
|
||||
for _,v in ipairs(brahtbl) do
|
||||
v.VJ_IsBeingControlled_Tool = false
|
||||
if v.IsVJBaseSNPC == true then
|
||||
v.DisableWandering = false
|
||||
v.DisableChasingEnemy = false
|
||||
v:SelectSchedule()
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
net.Receive("vj_npcmover_sv_startmove", function(len, ply)
|
||||
local wep = ply:GetActiveWeapon()
|
||||
if wep:IsValid() && wep:GetClass() == "gmod_tool" && wep:GetMode() == "vjstool_npcmover" then
|
||||
local sventtable = net.ReadTable()
|
||||
local svwalktype = net.ReadBit()
|
||||
local svvector = net.ReadVector()
|
||||
local type_task = "TASK_WALK_PATH"
|
||||
local type_sched = SCHED_FORCED_GO
|
||||
if svwalktype == 1 then
|
||||
type_task = "TASK_RUN_PATH"
|
||||
type_sched = SCHED_FORCED_GO_RUN
|
||||
end
|
||||
for k, v in ipairs(sventtable) do
|
||||
if IsValid(v) then -- Move the NPC if it's valid!
|
||||
v:StopMoving()
|
||||
v:SetLastPosition(svvector)
|
||||
if v.IsVJBaseSNPC == true then
|
||||
if k == 1 or math.random(1, 5) == 1 then v:PlaySoundSystem("OnReceiveOrder") end
|
||||
v:VJ_TASK_GOTO_LASTPOS(type_task, function(x)
|
||||
if IsValid(v:GetEnemy()) && v:Visible(v:GetEnemy()) then
|
||||
x:EngTask("TASK_FACE_ENEMY", 0)
|
||||
x.CanShootWhenMoving = true
|
||||
x.ConstantlyFaceEnemy = true
|
||||
end
|
||||
end)
|
||||
else -- For non-VJ NPCs
|
||||
v:SetSchedule(type_sched)
|
||||
end
|
||||
end
|
||||
end
|
||||
//self:MoveNPC(sventity,svvector,svwalktype)
|
||||
end
|
||||
end)
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:LeftClick(tr)
|
||||
if CLIENT then return true end
|
||||
if !tr.Entity:IsNPC() then return end
|
||||
net.Start("vj_npcmover_cl_create")
|
||||
net.WriteEntity(tr.Entity)
|
||||
if tr.Entity:GetName() == "" then
|
||||
net.WriteString(list.Get("NPC")[tr.Entity:GetClass()].Name)
|
||||
else
|
||||
net.WriteString(tr.Entity:GetName())
|
||||
end
|
||||
net.Send(self:GetOwner())
|
||||
return true
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:RightClick(tr)
|
||||
if CLIENT then return true end
|
||||
net.Start("vj_npcmover_cl_startmove")
|
||||
net.WriteBit(1)
|
||||
net.WriteVector(tr.HitPos)
|
||||
net.Send(self:GetOwner())
|
||||
return true
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:Reload(tr)
|
||||
if CLIENT then return true end
|
||||
net.Start("vj_npcmover_cl_startmove")
|
||||
net.WriteBit(0)
|
||||
net.WriteVector(tr.HitPos)
|
||||
net.Send(self:GetOwner())
|
||||
return true
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:Holster()
|
||||
/*if CLIENT then return end
|
||||
self.TblCurrentNPCs = self.TblCurrentNPCs or {}
|
||||
for k,v in pairs(self.TblCurrentNPCs) do
|
||||
self:RemoveNPC(v)
|
||||
end*/
|
||||
end
|
||||
290
lua/weapons/gmod_tool/stools/vjstool_npcrelationship.lua
Normal file
290
lua/weapons/gmod_tool/stools/vjstool_npcrelationship.lua
Normal file
@@ -0,0 +1,290 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
TOOL.Name = "#tool.vjstool_npcrelationship.name"
|
||||
TOOL.Tab = "DrVrej"
|
||||
TOOL.Category = "Tools"
|
||||
TOOL.Command = nil -- The console command to execute upon being selected in the Q menu.
|
||||
|
||||
TOOL.Information = {
|
||||
{name = "left"},
|
||||
{name = "right"},
|
||||
{name = "reload"},
|
||||
}
|
||||
|
||||
//TOOL.ClientConVar["playerinteract"] = 1
|
||||
TOOL.ClientConVar["allytoplyallies"] = 1
|
||||
|
||||
-- Just to make it easier to reset everything to default
|
||||
local DefaultConVars = {}
|
||||
for k,v in pairs(TOOL.ClientConVar) do
|
||||
DefaultConVars["vjstool_npcrelationship_"..k] = v
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
if CLIENT then
|
||||
local function DoBuildCPanel_Relationship(Panel)
|
||||
local reset = vgui.Create("DButton")
|
||||
reset:SetFont("DermaDefaultBold")
|
||||
reset:SetText("#vjbase.menu.general.reset.everything")
|
||||
reset:SetSize(150,25)
|
||||
reset:SetColor(Color(0,0,0,255))
|
||||
reset.DoClick = function()
|
||||
for k,v in pairs(DefaultConVars) do
|
||||
if v == "" then
|
||||
LocalPlayer():ConCommand(k.." ".."None")
|
||||
else
|
||||
LocalPlayer():ConCommand(k.." "..v) end
|
||||
timer.Simple(0.05,function()
|
||||
GetPanel = controlpanel.Get("vjstool_npcrelationship")
|
||||
GetPanel:ClearControls()
|
||||
DoBuildCPanel_Relationship(GetPanel)
|
||||
end)
|
||||
end
|
||||
end
|
||||
Panel:AddPanel(reset)
|
||||
|
||||
local tutorial = vgui.Create("DButton")
|
||||
tutorial:SetFont("DermaDefaultBold")
|
||||
tutorial:SetText("#tool.vjstool.menu.tutorialvideo")
|
||||
tutorial:SetSize(150, 20)
|
||||
tutorial:SetColor(Color(0,0,255,255))
|
||||
tutorial.DoClick = function()
|
||||
gui.OpenURL("http://www.youtube.com/watch?v=SnuQU8Sc4cg")
|
||||
end
|
||||
Panel:AddPanel(tutorial)
|
||||
|
||||
Panel:AddControl("Label", {Text = "#tool.vjstool.menu.label.recommendation"})
|
||||
Panel:ControlHelp("#tool.vjstool_npcrelationship.label1")
|
||||
|
||||
VJ_NPCRELATION_TblCurrentValues = VJ_NPCRELATION_TblCurrentValues or {}
|
||||
local CheckList = vgui.Create("DListView")
|
||||
CheckList:SetTooltip(false)
|
||||
//CheckList:Center() -- No need since Size does it already
|
||||
CheckList:SetSize( 100, 300 ) -- Size
|
||||
CheckList:SetMultiSelect(false)
|
||||
CheckList:AddColumn("#tool.vjstool_npcrelationship.header")
|
||||
CheckList.OnRowSelected = function(rowIndex,row) chat.AddText(Color(0,255,0),"Double click to ",Color(255,100,0),"remove ",Color(0,255,0),"a class") end
|
||||
function CheckList:DoDoubleClick(lineID,line)
|
||||
chat.AddText(Color(255,100,0)," "..line:GetValue(1).." ",Color(0,255,0),"removed!")
|
||||
CheckList:RemoveLine(lineID)
|
||||
table.Empty(VJ_NPCRELATION_TblCurrentValues)
|
||||
for _,vLine in pairs(CheckList:GetLines()) do
|
||||
table.insert(VJ_NPCRELATION_TblCurrentValues,vLine:GetValue(1))
|
||||
end
|
||||
end
|
||||
Panel:AddItem(CheckList)
|
||||
for _,v in pairs(VJ_NPCRELATION_TblCurrentValues) do
|
||||
CheckList:AddLine(v)
|
||||
end
|
||||
|
||||
local function InsertToTable(val)
|
||||
if string.len(val) > 0 then
|
||||
val = string.upper(val)
|
||||
if VJ_HasValue(VJ_NPCRELATION_TblCurrentValues,val) then
|
||||
chat.AddText(Color(220,20,60),"ERROR! ",Color(255,100,0),val.." ",Color(220,20,60),"already exists in the table!")
|
||||
else
|
||||
chat.AddText(Color(0,255,0),"Added",Color(255,100,0)," "..val.." ",Color(0,255,0),"to the class list!")
|
||||
table.insert(VJ_NPCRELATION_TblCurrentValues,val)
|
||||
timer.Simple(0.05,function()
|
||||
GetPanel = controlpanel.Get("vjstool_npcrelationship")
|
||||
GetPanel:ClearControls()
|
||||
DoBuildCPanel_Relationship(GetPanel)
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
local TextEntry = vgui.Create("DTextEntry")
|
||||
//TextEntry:SetText("Press enter to add class...")
|
||||
TextEntry.OnEnter = function()
|
||||
InsertToTable(TextEntry:GetValue())
|
||||
end
|
||||
Panel:AddItem(TextEntry)
|
||||
Panel:ControlHelp("#tool.vjstool_npcrelationship.label2")
|
||||
|
||||
local button = vgui.Create("DButton")
|
||||
button:SetFont("DermaDefaultBold")
|
||||
button:SetText("#tool.vjstool_npcrelationship.button.combine")
|
||||
button:SetSize(50,20)
|
||||
button:SetColor(Color(0,0,0,255))
|
||||
button.DoClick = function()
|
||||
InsertToTable("CLASS_COMBINE")
|
||||
end
|
||||
Panel:AddPanel(button)
|
||||
|
||||
button = vgui.Create("DButton")
|
||||
button:SetFont("DermaDefaultBold")
|
||||
button:SetText("#tool.vjstool_npcrelationship.button.antlion")
|
||||
button:SetSize(50,20)
|
||||
button:SetColor(Color(0,0,0,255))
|
||||
button.DoClick = function()
|
||||
InsertToTable("CLASS_ANTLION")
|
||||
end
|
||||
Panel:AddPanel(button)
|
||||
|
||||
button = vgui.Create("DButton")
|
||||
button:SetFont("DermaDefaultBold")
|
||||
button:SetText("#tool.vjstool_npcrelationship.button.zombie")
|
||||
button:SetSize(50,20)
|
||||
button:SetColor(Color(0,0,0,255))
|
||||
button.DoClick = function()
|
||||
InsertToTable("CLASS_ZOMBIE")
|
||||
end
|
||||
Panel:AddPanel(button)
|
||||
|
||||
button = vgui.Create("DButton")
|
||||
button:SetFont("DermaDefaultBold")
|
||||
button:SetText("#tool.vjstool_npcrelationship.button.player")
|
||||
button:SetSize(50,20)
|
||||
button:SetColor(Color(0,0,0,255))
|
||||
button.DoClick = function()
|
||||
InsertToTable("CLASS_PLAYER_ALLY")
|
||||
end
|
||||
Panel:AddPanel(button)
|
||||
Panel:AddControl("Checkbox", {Label = "#tool.vjstool_npcrelationship.togglealliedply", Command = "vjstool_npcrelationship_allytoplyallies"})
|
||||
Panel:ControlHelp(language.GetPhrase("#tool.vjstool_npcrelationship.label3").." CLASS_PLAYER_ALLY")
|
||||
|
||||
//Panel:AddControl("Label", {Text = "For PLAYER entities Only:"})
|
||||
//Panel:AddControl("Checkbox", {Label = "Make NPCs interact with friendly player", Command = "vjstool_npcspawner_playerinteract"})
|
||||
//Panel:ControlHelp("Make NPCs be able to interact with friendly player, such follow when pressed E or get out of their way")
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL.BuildCPanel(Panel)
|
||||
DoBuildCPanel_Relationship(Panel)
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
net.Receive("vj_npcrelationship_cl_select", function(len, ply)
|
||||
local wep = LocalPlayer():GetActiveWeapon()
|
||||
if wep:IsValid() && wep:GetClass() == "gmod_tool" && wep:GetMode() == "vjstool_npcrelationship" then
|
||||
//local ent = net.ReadEntity()
|
||||
local entname = net.ReadString()
|
||||
//local hasclasstbl = net.ReadBool()
|
||||
local classtbl = net.ReadTable()
|
||||
chat.AddText(Color(0,255,0),"Obtained",Color(255,100,0)," "..entname.."'s ",Color(0,255,0),"relationship class list!")
|
||||
//print(ent)
|
||||
//print(hasclasstbl)
|
||||
//PrintTable(classtbl)
|
||||
//print(#classtbl)
|
||||
VJ_NPCRELATION_TblCurrentValues = classtbl
|
||||
timer.Simple(0.05,function()
|
||||
GetPanel = controlpanel.Get("vjstool_npcrelationship")
|
||||
GetPanel:ClearControls()
|
||||
DoBuildCPanel_Relationship(GetPanel)
|
||||
end)
|
||||
end
|
||||
end)
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
net.Receive("vj_npcrelationship_cl_leftclick", function(len, ply)
|
||||
local wep = LocalPlayer():GetActiveWeapon()
|
||||
if wep:IsValid() && wep:GetClass() == "gmod_tool" && wep:GetMode() == "vjstool_npcrelationship" then
|
||||
local ent = net.ReadEntity()
|
||||
local entname = net.ReadString()
|
||||
local clicktype = net.ReadString()
|
||||
local allynum = net.ReadFloat()
|
||||
if clicktype == "ReloadClick" then entname = "Yourself" end
|
||||
chat.AddText(Color(0,255,0),"#tool.vjstool_npcrelationship.print.applied",Color(255,100,0)," "..entname)
|
||||
net.Start("vj_npcrelationship_sr_leftclick")
|
||||
net.WriteEntity(ent)
|
||||
//net.WriteTable(self)
|
||||
//net.WriteString(clicktype)
|
||||
net.WriteTable(VJ_NPCRELATION_TblCurrentValues)
|
||||
net.WriteFloat(allynum)
|
||||
net.SendToServer()
|
||||
end
|
||||
end)
|
||||
else
|
||||
util.AddNetworkString("vj_npcrelationship_cl_select")
|
||||
util.AddNetworkString("vj_npcrelationship_cl_leftclick")
|
||||
util.AddNetworkString("vj_npcrelationship_sr_leftclick")
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
net.Receive("vj_npcrelationship_sr_leftclick", function(len, ply)
|
||||
local wep = ply:GetActiveWeapon()
|
||||
if wep:IsValid() && wep:GetClass() == "gmod_tool" && wep:GetMode() == "vjstool_npcrelationship" then
|
||||
local ent = net.ReadEntity()
|
||||
//local clicktype = net.ReadString()
|
||||
local classtbl = net.ReadTable()
|
||||
local allynum = net.ReadFloat()
|
||||
if #classtbl > 0 then
|
||||
ent.VJ_NPC_Class = classtbl
|
||||
if ent.IsVJBaseSNPC == true then
|
||||
if table.HasValue(classtbl,"CLASS_PLAYER_ALLY") then
|
||||
if allynum == 1 then ent.FriendsWithAllPlayerAllies = true end
|
||||
ent.PlayerFriendly = true
|
||||
else
|
||||
ent.PlayerFriendly = false
|
||||
end
|
||||
end
|
||||
else
|
||||
ent.VJ_NPC_Class = {nil}
|
||||
ent.PlayerFriendly = false
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:LeftClick(tr)
|
||||
if CLIENT then return true end
|
||||
local ent = tr.Entity
|
||||
if IsValid(ent) && ent:IsPlayer() or ent:IsNPC() then
|
||||
local entname = ent:GetName()
|
||||
if entname == "" then entname = ent:GetClass() end
|
||||
net.Start("vj_npcrelationship_cl_leftclick")
|
||||
net.WriteEntity(ent)
|
||||
net.WriteString(entname)
|
||||
net.WriteString("LeftClick")
|
||||
net.WriteFloat(self:GetClientNumber("allytoplyallies"))
|
||||
net.Send(self:GetOwner())
|
||||
return true
|
||||
end
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:RightClick(tr)
|
||||
if CLIENT then return true end
|
||||
local ent = tr.Entity
|
||||
if IsValid(ent) && ent:IsPlayer() or ent:IsNPC() then
|
||||
//local hasclasstbl = false
|
||||
local classtbl = {nil}
|
||||
local entname = ent:GetName()
|
||||
if entname == "" then entname = ent:GetClass() end
|
||||
if (ent.VJ_NPC_Class) then
|
||||
//hasclasstbl = true
|
||||
//classtbl = ent.VJ_NPC_Class
|
||||
for _,v in ipairs(ent.VJ_NPC_Class) do
|
||||
table.insert(classtbl,v)
|
||||
end
|
||||
//if (classtbl.BaseClass) then table.remove(classtbl,BaseClass) end
|
||||
end
|
||||
//PrintTable(ent.VJ_NPC_Class)
|
||||
net.Start("vj_npcrelationship_cl_select")
|
||||
//net.WriteEntity(ent)
|
||||
net.WriteString(entname)
|
||||
//net.WriteBool(hasclasstbl)
|
||||
net.WriteTable(classtbl)
|
||||
net.Send(self:GetOwner())
|
||||
return true
|
||||
end
|
||||
/* local trent = tr.Entity
|
||||
trent:SetHealth(self:GetClientNumber("health"))
|
||||
if tr.Entity:IsNPC() then
|
||||
if self:GetClientNumber("godmode") == 1 then trent.GodMode = true else trent.GodMode = false end
|
||||
end
|
||||
return true
|
||||
end*/
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:Reload(tr)
|
||||
if CLIENT then return true end
|
||||
net.Start("vj_npcrelationship_cl_leftclick")
|
||||
net.WriteEntity(self:GetOwner())
|
||||
net.WriteString("Me")
|
||||
net.WriteString("ReloadClick")
|
||||
net.Send(self:GetOwner())
|
||||
return true
|
||||
end
|
||||
334
lua/weapons/gmod_tool/stools/vjstool_npcspawner.lua
Normal file
334
lua/weapons/gmod_tool/stools/vjstool_npcspawner.lua
Normal file
@@ -0,0 +1,334 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
TOOL.Name = "#tool.vjstool_npcspawner.name"
|
||||
TOOL.Tab = "DrVrej"
|
||||
TOOL.Category = "Tools"
|
||||
TOOL.Command = nil -- The console command to execute upon being selected in the Q menu.
|
||||
|
||||
TOOL.Information = {
|
||||
{name = "left"},
|
||||
{name = "right"},
|
||||
}
|
||||
|
||||
TOOL.ClientConVar["playsound"] = 1
|
||||
TOOL.ClientConVar["nextspawntime"] = 1
|
||||
TOOL.ClientConVar["spawnent"] = "None"
|
||||
TOOL.ClientConVar["spawnentname"] = "Unknown"
|
||||
TOOL.ClientConVar["spawnnpclass"] = ""
|
||||
TOOL.ClientConVar["fritoplyallies"] = 1
|
||||
TOOL.ClientConVar["spawnpos_forward"] = 0
|
||||
TOOL.ClientConVar["spawnpos_right"] = 0
|
||||
TOOL.ClientConVar["spawnpos_up"] = 0
|
||||
TOOL.ClientConVar["weaponequip"] = "None"
|
||||
TOOL.ClientConVar["weaponequipname"] = "None"
|
||||
TOOL.ClientConVar["nextspawntime"] = 3
|
||||
|
||||
-- Just to make it easier to reset everything to default
|
||||
local DefaultConVars = {}
|
||||
for k,v in pairs(TOOL.ClientConVar) do
|
||||
DefaultConVars["vjstool_npcspawner_"..k] = v
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
if CLIENT then
|
||||
local function DoBuildCPanel_Spawner(Panel)
|
||||
local reset = vgui.Create("DButton")
|
||||
reset:SetFont("DermaDefaultBold")
|
||||
reset:SetText("#vjbase.menu.general.reset.everything")
|
||||
reset:SetSize(150,25)
|
||||
reset:SetColor(Color(0,0,0,255))
|
||||
reset.DoClick = function()
|
||||
for k,v in pairs(DefaultConVars) do
|
||||
-- Ignore "vjstool_npcspawner_spawnnpclass" because we don't want it set to "None", we need it to stay ""
|
||||
if k == "vjstool_npcspawner_spawnnpclass" then
|
||||
LocalPlayer():ConCommand("vjstool_npcspawner_spawnnpclass \"\"")
|
||||
elseif v == "" then
|
||||
LocalPlayer():ConCommand(k.." ".."None")
|
||||
else
|
||||
LocalPlayer():ConCommand(k.." "..v)
|
||||
end
|
||||
timer.Simple(0.05,function()
|
||||
GetPanel = controlpanel.Get("vjstool_npcspawner")
|
||||
GetPanel:ClearControls()
|
||||
DoBuildCPanel_Spawner(GetPanel)
|
||||
end)
|
||||
end
|
||||
end
|
||||
Panel:AddPanel(reset)
|
||||
|
||||
local tutorial = vgui.Create("DButton")
|
||||
tutorial:SetFont("DermaDefaultBold")
|
||||
tutorial:SetText("#tool.vjstool.menu.tutorialvideo")
|
||||
tutorial:SetSize(150, 20)
|
||||
tutorial:SetColor(Color(0,0,255,255))
|
||||
tutorial.DoClick = function()
|
||||
gui.OpenURL("http://www.youtube.com/watch?v=5H_hIz35W90")
|
||||
end
|
||||
Panel:AddPanel(tutorial)
|
||||
|
||||
VJ_NPCSPAWNER_TblCurrentValues = VJ_NPCSPAWNER_TblCurrentValues or {}
|
||||
VJ_NPCSPAWNER_TblCurrentLines = VJ_NPCSPAWNER_TblCurrentLines or {}
|
||||
VJ_NPCSPAWNER_TblCurrentLinesUsable = VJ_NPCSPAWNER_TblCurrentLinesUsable or {}
|
||||
|
||||
Panel:AddControl("Label", {Text = "#tool.vjstool.menu.label.recommendation"})
|
||||
local selectnpc = vgui.Create("DTextEntry")
|
||||
selectnpc:SetEditable(false)
|
||||
selectnpc:SetText(language.GetPhrase("#tool.vjstool_npcspawner.selectednpc")..": "..GetConVarString("vjstool_npcspawner_spawnentname").." ["..GetConVarString("vjstool_npcspawner_spawnent").."]")
|
||||
selectnpc.OnGetFocus = function() LocalPlayer():ConCommand("vj_npcspawner_opennpcselect") end
|
||||
Panel:AddItem(selectnpc)
|
||||
Panel:AddControl("TextBox",{Label = "#tool.vjstool_npcspawner.spawnpos.forward",MaxLength = 10,Type = "Float",WaitForEnter = false,Command = "vjstool_npcspawner_spawnpos_forward"})
|
||||
Panel:AddControl("TextBox",{Label = "#tool.vjstool_npcspawner.spawnpos.right",MaxLength = 10,Type = "Float",WaitForEnter = false,Command = "vjstool_npcspawner_spawnpos_right"})
|
||||
Panel:AddControl("TextBox",{Label = "#tool.vjstool_npcspawner.spawnpos.up",MaxLength = 10,Type = "Float",WaitForEnter = false,Command = "vjstool_npcspawner_spawnpos_up"})
|
||||
local selectwep = vgui.Create("DTextEntry")
|
||||
selectwep:SetEditable(false)
|
||||
selectwep:SetText(language.GetPhrase("#tool.vjstool_npcspawner.selectweapon")..": "..GetConVarString("vjstool_npcspawner_weaponequipname").." ["..GetConVarString("vjstool_npcspawner_weaponequip").."]")
|
||||
selectwep.OnGetFocus = function() LocalPlayer():ConCommand("vj_npcspawner_openwepselect") end
|
||||
Panel:AddItem(selectwep)
|
||||
Panel:AddControl("TextBox",{Label = "#tool.vjstool_npcspawner.spawnnpclass",WaitForEnter = false,Command = "vjstool_npcspawner_spawnnpclass"})
|
||||
Panel:AddControl("CheckBox",{Label = "#tool.vjstool_npcspawner.fritoplyallies",Command = "vjstool_npcspawner_fritoplyallies"})
|
||||
Panel:ControlHelp("#tool.vjstool_npcspawner.label.fritoplyallies")
|
||||
Panel:AddControl("Button",{Label = "#tool.vjstool_npcspawner.button.updatelist",Command = "vj_npcspawner_updatelist"})
|
||||
Panel:ControlHelp("#tool.vjstool_npcspawner.label1")
|
||||
local CheckList = vgui.Create("DListView")
|
||||
CheckList:SetTooltip(false)
|
||||
CheckList:SetSize(100, 307) -- Size
|
||||
CheckList:SetMultiSelect(false)
|
||||
CheckList:AddColumn("#tool.vjstool_npcspawner.header1")
|
||||
CheckList:AddColumn("#tool.vjstool_npcspawner.header2")
|
||||
CheckList:AddColumn("#tool.vjstool_npcspawner.header3")
|
||||
CheckList.OnRowSelected = function(rowIndex,row) chat.AddText(Color(0,255,0),"Double click to ",Color(255,100,0),"remove ",Color(0,255,0),"a NPC") end
|
||||
function CheckList:DoDoubleClick(lineID,line)
|
||||
chat.AddText(Color(0,255,0),"NPC",Color(255,100,0)," "..line:GetValue(1).." ",Color(0,255,0),"removed!")
|
||||
CheckList:RemoveLine(lineID)
|
||||
table.Empty(VJ_NPCSPAWNER_TblCurrentLinesUsable)
|
||||
for _,vLine in pairs(VJ_NPCSPAWNER_TblCurrentLines) do
|
||||
table.insert(VJ_NPCSPAWNER_TblCurrentLinesUsable,{Entities=vLine:GetValue(4),SpawnPosition=vLine:GetValue(2),WeaponsList=vLine:GetValue(3),EntityName=vLine:GetValue(1),Relationship=vLine:GetValue(5)})
|
||||
end
|
||||
end
|
||||
Panel:AddItem(CheckList)
|
||||
for k,v in pairs(VJ_NPCSPAWNER_TblCurrentValues) do
|
||||
if v.Entities == "" or v.Entities == "none" or v.Entities == {} then table.remove(VJ_NPCSPAWNER_TblCurrentValues,k) continue end
|
||||
if v.Entities != "" && v.Entities != "none" && v.Entities != {} then
|
||||
CheckList:AddLine(v.EntityName,Vector(v.SpawnPosition.vForward,v.SpawnPosition.vRight,v.SpawnPosition.vUp),v.WeaponsList,v.Entities,v.Relationship)
|
||||
//CheckList:AddLine(v.Entities,"x:"..v.SpawnPosition.vForward.." y:"..v.SpawnPosition.vRight.." z:"..v.SpawnPosition.vUp)
|
||||
end
|
||||
end
|
||||
table.Empty(VJ_NPCSPAWNER_TblCurrentValues)
|
||||
for _,vLine in pairs(VJ_NPCSPAWNER_TblCurrentLines) do
|
||||
CheckList:AddLine(vLine:GetValue(1),vLine:GetValue(2),vLine:GetValue(3),vLine:GetValue(4),vLine:GetValue(5))
|
||||
end
|
||||
VJ_NPCSPAWNER_TblCurrentLines = CheckList:GetLines()
|
||||
table.Empty(VJ_NPCSPAWNER_TblCurrentLinesUsable)
|
||||
for _,vLine in pairs(VJ_NPCSPAWNER_TblCurrentLines) do
|
||||
table.insert(VJ_NPCSPAWNER_TblCurrentLinesUsable,{Entities=vLine:GetValue(4),SpawnPosition=vLine:GetValue(2),WeaponsList=vLine:GetValue(3),EntityName=vLine:GetValue(1),Relationship=vLine:GetValue(5)})
|
||||
end
|
||||
Panel:AddControl("Label", {Text = language.GetPhrase("#tool.vjstool_npcspawner.label2")..":"})
|
||||
Panel:AddControl("Checkbox", {Label = "#tool.vjstool_npcspawner.toggle.spawnsound", Command = "vjstool_npcspawner_playsound"})
|
||||
Panel:AddControl("Slider", {Label = "#tool.vjstool_npcspawner.nextspawntime",min = 0,max = 1000,Command = "vjstool_npcspawner_nextspawntime"})
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
concommand.Add("vj_npcspawner_opennpcselect",function(ply,cmd,args)
|
||||
local MenuFrame = vgui.Create('DFrame')
|
||||
MenuFrame:SetSize(420, 440)
|
||||
MenuFrame:SetPos(ScrW()*0.6, ScrH()*0.1)
|
||||
MenuFrame:SetTitle("#tool.vjstool_npcspawner.title1")
|
||||
//MenuFrame:SetBackgroundBlur(true)
|
||||
MenuFrame:SetFocusTopLevel(true)
|
||||
MenuFrame:SetSizable(true)
|
||||
MenuFrame:ShowCloseButton(true)
|
||||
//MenuFrame:SetDeleteOnClose(false)
|
||||
MenuFrame:MakePopup()
|
||||
|
||||
local CheckList = vgui.Create("DListView")
|
||||
CheckList:SetTooltip(false)
|
||||
//CheckList:Center() -- No need since Size does it already
|
||||
CheckList:SetParent(MenuFrame)
|
||||
CheckList:SetPos(10,30)
|
||||
CheckList:SetSize(400,400) -- Size
|
||||
CheckList:SetMultiSelect(false)
|
||||
CheckList:AddColumn("#tool.vjstool_npcspawner.popup.header1")
|
||||
CheckList:AddColumn("#tool.vjstool_npcspawner.popup.header2")
|
||||
CheckList:AddColumn("#tool.vjstool_npcspawner.popup.header3")
|
||||
CheckList.OnRowSelected = function() chat.AddText(Color(0,255,0),"#tool.vjstool_npcspawner.title1") end
|
||||
function CheckList:DoDoubleClick(lineID,line)
|
||||
chat.AddText(Color(0,255,0),"NPC",Color(255,100,0)," "..line:GetValue(1).." ",Color(0,255,0),"selected!")
|
||||
LocalPlayer():ConCommand("vjstool_npcspawner_spawnentname "..line:GetValue(1))
|
||||
LocalPlayer():ConCommand("vjstool_npcspawner_spawnent "..line:GetValue(2))
|
||||
MenuFrame:Close()
|
||||
timer.Simple(0.05,function()
|
||||
GetPanel = controlpanel.Get("vjstool_npcspawner")
|
||||
GetPanel:ClearControls()
|
||||
DoBuildCPanel_Spawner(GetPanel)
|
||||
end)
|
||||
end
|
||||
//MenuFrame:AddItem(CheckList)
|
||||
//CheckList:SizeToContents()
|
||||
for _,v in pairs(list.Get("NPC")) do
|
||||
getcat = v.Category
|
||||
if v.Category == "" then getcat = "Unknown" end
|
||||
CheckList:AddLine(v.Name,v.Class,getcat)
|
||||
end
|
||||
CheckList:SortByColumn(1,false)
|
||||
end)
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
concommand.Add("vj_npcspawner_openwepselect",function(ply,cmd,args)
|
||||
local MenuFrame = vgui.Create('DFrame')
|
||||
MenuFrame:SetSize(420, 440)
|
||||
MenuFrame:SetPos(ScrW()*0.6, ScrH()*0.1)
|
||||
MenuFrame:SetTitle("#tool.vjstool_npcspawner.title2")
|
||||
//MenuFrame:SetBackgroundBlur(true)
|
||||
MenuFrame:SetFocusTopLevel(true)
|
||||
MenuFrame:SetSizable(true)
|
||||
MenuFrame:ShowCloseButton(true)
|
||||
//MenuFrame:SetDeleteOnClose(false)
|
||||
MenuFrame:MakePopup()
|
||||
|
||||
local CheckList = vgui.Create("DListView")
|
||||
CheckList:SetTooltip(false)
|
||||
//CheckList:Center() -- No need since Size does it already
|
||||
CheckList:SetParent(MenuFrame)
|
||||
CheckList:SetPos(10,30)
|
||||
CheckList:SetSize(400,400) -- Size
|
||||
CheckList:SetMultiSelect(false)
|
||||
CheckList:AddColumn("#tool.vjstool_npcspawner.popup.header1")
|
||||
CheckList:AddColumn("#tool.vjstool_npcspawner.popup.header2")
|
||||
CheckList.OnRowSelected = function() chat.AddText(Color(0,255,0),"#tool.vjstool_npcspawner.title2") end
|
||||
function CheckList:DoDoubleClick(lineID,line)
|
||||
chat.AddText(Color(0,255,0),"Weapon",Color(255,100,0)," "..line:GetValue(1).." ",Color(0,255,0),"selected!")
|
||||
LocalPlayer():ConCommand("vjstool_npcspawner_weaponequipname "..line:GetValue(1))
|
||||
LocalPlayer():ConCommand("vjstool_npcspawner_weaponequip "..line:GetValue(2))
|
||||
MenuFrame:Close()
|
||||
timer.Simple(0.05,function()
|
||||
GetPanel = controlpanel.Get("vjstool_npcspawner")
|
||||
GetPanel:ClearControls()
|
||||
DoBuildCPanel_Spawner(GetPanel)
|
||||
end)
|
||||
end
|
||||
//MenuFrame:AddItem(CheckList)
|
||||
//CheckList:SizeToContents()
|
||||
for _,v in pairs(list.Get("NPCUsableWeapons")) do
|
||||
CheckList:AddLine(v.title,v.class)
|
||||
end
|
||||
CheckList:SortByColumn(1,false)
|
||||
CheckList:AddLine("None","None")
|
||||
CheckList:AddLine("Default","Default")
|
||||
end)
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
concommand.Add("vj_npcspawner_updatelist",function(ply,cmd,args)
|
||||
local spawnent = string.lower(GetConVarString("vjstool_npcspawner_spawnent"))
|
||||
local spawnentname = GetConVarString("vjstool_npcspawner_spawnentname")
|
||||
local spawnposfor = GetConVarString("vjstool_npcspawner_spawnpos_forward")
|
||||
local spawnposright = GetConVarString("vjstool_npcspawner_spawnpos_right")
|
||||
local spawnposup = GetConVarString("vjstool_npcspawner_spawnpos_up")
|
||||
local spawnnpclass = GetConVarString("vjstool_npcspawner_spawnnpclass")
|
||||
local spawnfritoplyallies = GetConVarString("vjstool_npcspawner_fritoplyallies")
|
||||
local spawnequip = string.lower(GetConVarString("vjstool_npcspawner_weaponequip"))
|
||||
table.insert(VJ_NPCSPAWNER_TblCurrentValues,{EntityName=spawnentname, Entities=spawnent, SpawnPosition={vForward=spawnposfor,vRight=spawnposright,vUp=spawnposup}, WeaponsList=spawnequip, Relationship={Class = spawnnpclass, FriToPlyAllies = spawnfritoplyallies}})
|
||||
GetPanel = controlpanel.Get("vjstool_npcspawner")
|
||||
GetPanel:ClearControls()
|
||||
DoBuildCPanel_Spawner(GetPanel)
|
||||
end)
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
net.Receive("vj_npcspawner_cl_create", function(len, ply)
|
||||
local wep = LocalPlayer():GetActiveWeapon()
|
||||
if wep:IsValid() && wep:GetClass() == "gmod_tool" && wep:GetMode() == "vjstool_npcspawner" then
|
||||
local svpos = net.ReadVector()
|
||||
local svclicktype = net.ReadString()
|
||||
local convartbl = {}
|
||||
for k,_ in pairs(DefaultConVars) do
|
||||
convartbl[k] = GetConVarNumber(k)
|
||||
end
|
||||
net.Start("vj_npcspawner_sv_create")
|
||||
net.WriteTable(convartbl)
|
||||
net.WriteVector(svpos)
|
||||
net.WriteType(VJ_NPCSPAWNER_TblCurrentLinesUsable)
|
||||
net.WriteString(svclicktype)
|
||||
net.SendToServer()
|
||||
end
|
||||
end)
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL.BuildCPanel(Panel)
|
||||
DoBuildCPanel_Spawner(Panel)
|
||||
end
|
||||
else -- If SERVER
|
||||
util.AddNetworkString("vj_npcspawner_cl_create")
|
||||
util.AddNetworkString("vj_npcspawner_sv_create")
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
local spawnSounds = {"garrysmod/save_load1.wav","garrysmod/save_load2.wav","garrysmod/save_load3.wav","garrysmod/save_load4.wav"}
|
||||
--
|
||||
net.Receive("vj_npcspawner_sv_create", function(len, ply)
|
||||
local wep = ply:GetActiveWeapon()
|
||||
if wep:IsValid() && wep:GetClass() == "gmod_tool" && wep:GetMode() == "vjstool_npcspawner" then
|
||||
local convartbl = net.ReadTable()
|
||||
local svpos = net.ReadVector()
|
||||
local svgetlines = net.ReadType()
|
||||
local svgettype = net.ReadString()
|
||||
if !IsValid(ply) then return false end
|
||||
if table.Count(svgetlines) <= 0 then ply:ChatPrint("#tool.vjstool_npcspawner.print.nothingspawn") return false end
|
||||
local spawner = ents.Create("obj_vj_spawner_base")
|
||||
spawner.EntitiesToSpawn = {}
|
||||
spawner:SetPos(svpos)
|
||||
local angs = Angle(0,0,0)
|
||||
if IsValid(ply) then
|
||||
angs = ply:GetAngles()
|
||||
angs.pitch = 0
|
||||
angs.roll = 0
|
||||
angs.yaw = angs.yaw + 180
|
||||
end
|
||||
spawner:SetAngles(angs)
|
||||
for _,v in pairs(svgetlines) do
|
||||
//if v.IsVJBaseSpawner == true then ply:ChatPrint("Can't be spawned because it's a spawner") end
|
||||
table.insert(spawner.EntitiesToSpawn,{SpawnPosition={vForward=v.SpawnPosition.x,vRight=v.SpawnPosition.y,vUp=v.SpawnPosition.z}, Entities={v.Entities}, WeaponsList={v.WeaponsList}, NPC_Class = v.Relationship.Class, FriToPlyAllies = tobool(v.Relationship.FriToPlyAllies)})
|
||||
end
|
||||
//spawner.EntitiesToSpawn = {entitiestospawntbl}
|
||||
if convartbl.vjstool_npcspawner_playsound == 1 then
|
||||
spawner.SoundTbl_SpawnEntity = spawnSounds
|
||||
end
|
||||
spawner.TimedSpawn_Time = convartbl.vjstool_npcspawner_nextspawntime //GetConVarNumber("vjstool_npcspawner_nextspawntime")
|
||||
if svgettype == "RightClick" then spawner.SingleSpawner = true end
|
||||
spawner:SetCreator(ply)
|
||||
spawner:Spawn()
|
||||
spawner:Activate()
|
||||
undo.Create("NPC Spawner")
|
||||
undo.AddEntity(spawner)
|
||||
undo.SetPlayer(ply)
|
||||
undo.Finish()
|
||||
for vpk,vpv in pairs(spawner.CurrentEntities) do
|
||||
if IsValid(vpv.TheEntity) && vpv.TheEntity.IsVJBaseSpawner == true && vpv.TheEntity.SingleSpawner == true then
|
||||
vpv.TheEntity:SetCreator(ply)
|
||||
table.remove(spawner.CurrentEntities,vpk)
|
||||
if table.Count(spawner.CurrentEntities) <= 0 then spawner:Remove() end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:LeftClick(tr)
|
||||
if CLIENT then return true end
|
||||
net.Start("vj_npcspawner_cl_create")
|
||||
net.WriteVector(tr.HitPos)
|
||||
net.WriteString("LeftClick")
|
||||
net.Send(self:GetOwner())
|
||||
return true
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:RightClick(tr)
|
||||
if CLIENT then return true end
|
||||
net.Start("vj_npcspawner_cl_create")
|
||||
net.WriteVector(tr.HitPos)
|
||||
net.WriteString("RightClick")
|
||||
net.Send(self:GetOwner())
|
||||
return true
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function TOOL:Reload(tr)
|
||||
if CLIENT then return true end
|
||||
end
|
||||
206
lua/weapons/lightning_gun.lua
Normal file
206
lua/weapons/lightning_gun.lua
Normal file
@@ -0,0 +1,206 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
--[[-------------------------------------------------------------------------
|
||||
Point and click
|
||||
---------------------------------------------------------------------------]]
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
SWEP.PrintName = "Mjölnir Gun"
|
||||
SWEP.Instructions = "The power of Thor!"
|
||||
SWEP.Spawnable = true
|
||||
SWEP.AdminOnly = true
|
||||
SWEP.UseHands = true
|
||||
|
||||
SWEP.ViewModel = Model( "models/weapons/c_pistol.mdl") --"models/weapons/w_eq_tablet.mdl") -- )
|
||||
SWEP.WorldModel = Model( "models/weapons/w_pistol.mdl" )
|
||||
|
||||
-- No ammo
|
||||
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 = true
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
|
||||
SWEP.Slot = 5
|
||||
SWEP.SlotPos = 1
|
||||
|
||||
SWEP.DrawAmmo = false
|
||||
SWEP.DrawCrosshair = false
|
||||
SWEP.Spawnable = true
|
||||
SWEP.UseHands = true
|
||||
|
||||
SWEP.Selected = 1
|
||||
|
||||
if ( SERVER ) then
|
||||
SWEP.AutoSwitchTo = true
|
||||
SWEP.AutoSwitchFrom = true
|
||||
end
|
||||
|
||||
function SWEP:Initialize()
|
||||
self:SetHoldType( "pistol" )
|
||||
self:SendWeaponAnim( 1 )
|
||||
self.power = 0
|
||||
self._bUsed = true
|
||||
self._bGlow = -1
|
||||
end
|
||||
function SWEP:HasPower()
|
||||
return self:GetPower() >= 1
|
||||
end
|
||||
function SWEP:GetPower()
|
||||
local a = (CurTime() - self.power) / 1.2
|
||||
if a >= 1 then return 1 end
|
||||
return math.max(0, a)
|
||||
end
|
||||
function SWEP:UsePower( t )
|
||||
self.power = CurTime() + t
|
||||
self._bUsed = true
|
||||
timer.Simple(0.5, function()
|
||||
if not IsValid( self ) then return end
|
||||
self._bGlow = -1
|
||||
self:SendWeaponAnim( ACT_VM_IDLE_LOWERED )
|
||||
end)
|
||||
end
|
||||
|
||||
-- SF commands
|
||||
local function Strike( self, bAlt )
|
||||
if CLIENT then return end
|
||||
local tr = util.TraceLine( util.GetPlayerTrace( self:GetOwner() ) )
|
||||
if not tr.HitPos then return end
|
||||
if bAlt then
|
||||
StormFox2.Thunder.CreateAt( tr.HitPos + vector_up * 4 )
|
||||
else
|
||||
StormFox2.Thunder.Strike( tr.HitPos, true )
|
||||
end
|
||||
end
|
||||
local function Rumble( self )
|
||||
if CLIENT then return end
|
||||
local tr = util.TraceLine( util.GetPlayerTrace( self:GetOwner() ) )
|
||||
if not tr.HitPos then return end
|
||||
StormFox2.Thunder.Rumble(tr.HitPos,true)
|
||||
end
|
||||
|
||||
function SWEP:CanPrimaryAttack()
|
||||
return self:HasPower()
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
if not IsFirstTimePredicted() then return end
|
||||
if not self:CanPrimaryAttack() then return end
|
||||
local Owner = self:GetOwner()
|
||||
Owner:MuzzleFlash()
|
||||
self.Weapon:SendWeaponAnim( 186 )
|
||||
Owner:SetAnimation( ACT_GLOCK_SHOOTEMPTY )
|
||||
self._bGlow = CurTime() + 0.1
|
||||
self:UsePower( ( 0.5 + CurTime()%0.5 ) )
|
||||
if SERVER then
|
||||
Strike(self, Owner:KeyDown(IN_SPEED))
|
||||
else
|
||||
--self:EmitSound("weapons/physcannon/energy_disintegrate4.wav", 75, 100, 0.2)
|
||||
local hitPos = Owner:GetEyeTrace().HitPos or Owner:GetShootPos()
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
if not IsFirstTimePredicted() then return end
|
||||
if not self:CanPrimaryAttack() then return end
|
||||
self:UsePower( 0.25 )
|
||||
self.Weapon:SendWeaponAnim( ACT_VM_IDLE_TO_LOWERED ) -- View model animation
|
||||
if SERVER then
|
||||
Rumble(self)
|
||||
else
|
||||
self:EmitSound("weapons/slam/mine_mode.wav")
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Think()
|
||||
if self._bUsed and self:HasPower() then
|
||||
self:SendWeaponAnim( ACT_VM_IDLE_TO_LOWERED )
|
||||
self._bUsed = false
|
||||
self:EmitSound("weapons/physcannon/superphys_small_zap1.wav", 75, 100, 0.2)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Deploy()
|
||||
self.Weapon:SendWeaponAnim( 172 )
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:ShouldDropOnDie() return false end
|
||||
|
||||
if ( SERVER ) then return end -- Only clientside lua after this line
|
||||
function SWEP:Holster()
|
||||
end
|
||||
|
||||
SWEP.WepSelectIcon = surface.GetTextureID( "vgui/gmod_camera" )
|
||||
|
||||
-- Don't draw the weapon info on the weapon selection thing
|
||||
function SWEP:DrawHUD() end
|
||||
function SWEP:PrintWeaponInfo( x, y, alpha ) end
|
||||
|
||||
--[[-------------------------------------------------------------------------
|
||||
function SWEP:CalcView(ply,pos,ang,fov)
|
||||
--pos = pos + ang:Forward() * -50
|
||||
return pos,ang,fov
|
||||
end
|
||||
---------------------------------------------------------------------------]]
|
||||
|
||||
-- CL swep rendering
|
||||
function SWEP:CalcViewModelView( vm, _,_,pos, ang)
|
||||
--pos = pos + ang:Forward() * 10 + ang:Right() * 30 + ang:Up()*5
|
||||
--ang:RotateAroundAxis(ang:Up(),80)
|
||||
return pos,ang
|
||||
end
|
||||
|
||||
|
||||
function SWEP:DrawWorldModel()
|
||||
self:DrawModel()
|
||||
cam.Start3D2D(self:LocalToWorld(Vector(1,-0.4,0.4)),self:LocalToWorldAngles(Angle(0,0,80)),0.1)
|
||||
local w,h,s = 20,4,1
|
||||
surface.SetDrawColor(0,0,0)
|
||||
surface.DrawRect(0,0,w,h)
|
||||
surface.SetDrawColor(0,255,0)
|
||||
surface.DrawRect(s,s,w - s*2,h - s*2)
|
||||
cam.End3D2D()
|
||||
end
|
||||
|
||||
local g_mat = Material("sprites/glow04_noz")
|
||||
function SWEP:PostDrawViewModel(vm,wep,ply)
|
||||
if not vm then return end
|
||||
local pos, ang = vm:GetBonePosition(39)
|
||||
if self._bGlow > -1 then
|
||||
local time = (self._bGlow - CurTime()) * 4
|
||||
if time > 0 then
|
||||
local t = (1 - time)
|
||||
render.SetMaterial(g_mat)
|
||||
render.DrawSprite(pos + ang:Up() * (3 + t * 2.1 ), 8 * t, 8 * t, color_white)
|
||||
end
|
||||
end
|
||||
local pow = wep:GetPower()
|
||||
ang:RotateAroundAxis(ang:Right(), 90)
|
||||
cam.Start3D2D(pos - ang:Up() + ang:Forward() * -3,ang,0.1)
|
||||
local w,h,s = 20,4,1
|
||||
local w2 = w * pow
|
||||
surface.SetDrawColor(0,0,0)
|
||||
surface.DrawRect(0,0,w,h)
|
||||
if pow < 1 then
|
||||
surface.SetDrawColor(255,255 * pow,0)
|
||||
else
|
||||
surface.SetDrawColor(55,55,255)
|
||||
end
|
||||
surface.DrawRect(s,s,(w2 - s * 2),h - s*2)
|
||||
cam.End3D2D()
|
||||
end
|
||||
132
lua/weapons/pill_wep_alyxgun.lua
Normal file
132
lua/weapons/pill_wep_alyxgun.lua
Normal file
@@ -0,0 +1,132 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
SWEP.ViewModel = "models/weapons/c_arms_citizen.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_alyx_gun.mdl"
|
||||
SWEP.Primary.ClipSize = 30
|
||||
SWEP.Primary.DefaultClip = 30
|
||||
SWEP.Primary.Automatic = true
|
||||
SWEP.Primary.Ammo = "smg1"
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = false
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
SWEP.Spawnable = true
|
||||
SWEP.AdminSpawnable = true
|
||||
SWEP.PrintName = "Alyx's Gun"
|
||||
SWEP.Category = "Pill Pack Weapons"
|
||||
SWEP.Slot = 1
|
||||
|
||||
function SWEP:SetupDataTables()
|
||||
self:NetworkVar("Int", 0, "Mode")
|
||||
end
|
||||
|
||||
function SWEP:Initialize()
|
||||
self:SetHoldType("pistol")
|
||||
self:SetMode(0)
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
if (not self:CanPrimaryAttack()) then return end
|
||||
local spread = .01
|
||||
|
||||
if self:GetMode() == 0 then
|
||||
spread = .02
|
||||
elseif self:GetMode() == 1 then
|
||||
spread = .06
|
||||
end
|
||||
|
||||
local bullet = {}
|
||||
bullet.Num = 1
|
||||
bullet.Src = self.Owner:GetShootPos()
|
||||
bullet.Dir = self.Owner:GetAimVector()
|
||||
bullet.Spread = Vector(spread, spread, 0)
|
||||
bullet.Tracer = 1
|
||||
bullet.TracerName = "Tracer"
|
||||
bullet.Force = 5
|
||||
|
||||
if self:GetMode() == 0 then
|
||||
bullet.Damage = 10
|
||||
elseif self:GetMode() == 1 then
|
||||
bullet.Damage = 5
|
||||
else
|
||||
bullet.Damage = 50
|
||||
end
|
||||
|
||||
self:ShootEffects()
|
||||
self.Owner:FireBullets(bullet)
|
||||
|
||||
if SERVER then
|
||||
sound.Play("npc/sniper/echo1.wav", self:GetPos(), 100, 100, 1)
|
||||
|
||||
if self:GetMode() == 0 then
|
||||
sound.Play("weapons/pistol/pistol_fire2.wav", self:GetPos(), 100, 100, 1)
|
||||
elseif self:GetMode() == 1 then
|
||||
sound.Play("weapons/smg1/smg1_fireburst1.wav", self:GetPos(), 100, 100, 1)
|
||||
else
|
||||
sound.Play("weapons/357/357_fire2.wav", self:GetPos(), 100, 100, 1)
|
||||
end
|
||||
end
|
||||
|
||||
self:TakePrimaryAmmo(1)
|
||||
local delay = 1
|
||||
|
||||
if self:GetMode() == 0 then
|
||||
delay = .3
|
||||
elseif self:GetMode() == 1 then
|
||||
delay = .1
|
||||
end
|
||||
|
||||
self:SetNextPrimaryFire(CurTime() + delay)
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
if CLIENT then return end
|
||||
|
||||
if self:GetMode() < 2 then
|
||||
self:SetMode(self:GetMode() + 1)
|
||||
else
|
||||
self:SetMode(0)
|
||||
end
|
||||
|
||||
if self:GetMode() == 0 then
|
||||
self.Owner:ChatPrint("Pistol Mode")
|
||||
self:SetHoldType("pistol")
|
||||
self:PillAnim("weapon_pistol")
|
||||
elseif self:GetMode() == 1 then
|
||||
self.Owner:ChatPrint("SMG Mode")
|
||||
self:SetHoldType("smg")
|
||||
self:PillAnim("weapon_smg")
|
||||
elseif self:GetMode() == 2 then
|
||||
self.Owner:ChatPrint("Rifle Mode")
|
||||
self:SetHoldType("ar2")
|
||||
self:PillAnim("weapon_rifle")
|
||||
end
|
||||
|
||||
self.Owner:EmitSound("weapons/smg1/switch_single.wav")
|
||||
end
|
||||
|
||||
function SWEP:Reload()
|
||||
if self.ReloadingTime and CurTime() <= self.ReloadingTime then return end
|
||||
|
||||
if (self:Clip1() < self.Primary.ClipSize and self.Owner:GetAmmoCount(self.Primary.Ammo) > 0) then
|
||||
self:EmitSound("weapons/pistol/pistol_reload1.wav")
|
||||
self:DefaultReload(ACT_VM_RELOAD)
|
||||
self.ReloadingTime = CurTime() + 1
|
||||
self:SetNextPrimaryFire(CurTime() + 1)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:PillAnim(anim)
|
||||
if IsValid(self.pill_proxy) then
|
||||
self.pill_proxy:ResetSequence(self.pill_proxy:LookupSequence(anim))
|
||||
end
|
||||
end
|
||||
59
lua/weapons/pill_wep_annabelle.lua
Normal file
59
lua/weapons/pill_wep_annabelle.lua
Normal file
@@ -0,0 +1,59 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
SWEP.ViewModel = "models/weapons/c_arms_citizen.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_annabelle.mdl"
|
||||
SWEP.Primary.ClipSize = 2
|
||||
SWEP.Primary.DefaultClip = 2
|
||||
SWEP.Primary.Automatic = false
|
||||
SWEP.Primary.Ammo = "357"
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = false
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
SWEP.Spawnable = true
|
||||
SWEP.AdminSpawnable = true
|
||||
SWEP.PrintName = "Annabelle"
|
||||
SWEP.Category = "Pill Pack Weapons"
|
||||
SWEP.Slot = 3
|
||||
|
||||
function SWEP:Initialize()
|
||||
self:SetHoldType("crossbow")
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
if (not self:CanPrimaryAttack()) then return end
|
||||
local bullet = {}
|
||||
bullet.Num = 1
|
||||
bullet.Src = self.Owner:GetShootPos()
|
||||
bullet.Dir = self.Owner:GetAimVector()
|
||||
bullet.Spread = Vector(.01, .01, 0)
|
||||
bullet.Tracer = 1
|
||||
bullet.TracerName = "Tracer"
|
||||
bullet.Force = 5
|
||||
bullet.Damage = 50
|
||||
self:ShootEffects()
|
||||
self.Owner:FireBullets(bullet)
|
||||
self:EmitSound("weapons/shotgun/shotgun_fire6.wav")
|
||||
self:TakePrimaryAmmo(1)
|
||||
self:SetNextPrimaryFire(CurTime() + .5)
|
||||
end
|
||||
|
||||
function SWEP:Reload()
|
||||
if self.ReloadingTime and CurTime() <= self.ReloadingTime then return end
|
||||
|
||||
if (self:Clip1() < self.Primary.ClipSize and self.Owner:GetAmmoCount(self.Primary.Ammo) > 0) then
|
||||
self:EmitSound("weapons/shotgun/shotgun_reload1.wav")
|
||||
self:DefaultReload(ACT_VM_RELOAD)
|
||||
self.ReloadingTime = CurTime() + 1
|
||||
self:SetNextPrimaryFire(CurTime() + 1)
|
||||
end
|
||||
end
|
||||
124
lua/weapons/pill_wep_csniper.lua
Normal file
124
lua/weapons/pill_wep_csniper.lua
Normal file
@@ -0,0 +1,124 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
//SWEP.base = "weapon_base"
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
SWEP.ViewModel = "models/weapons/c_arms_citizen.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_combine_sniper.mdl"
|
||||
|
||||
SWEP.Primary.ClipSize = 1
|
||||
SWEP.Primary.DefaultClip = 1
|
||||
SWEP.Primary.Automatic = false
|
||||
SWEP.Primary.Ammo = "AR2"
|
||||
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = false
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
|
||||
SWEP.Spawnable=true
|
||||
SWEP.AdminSpawnable=true
|
||||
|
||||
SWEP.PrintName="Pulse Sniper Rifle"
|
||||
SWEP.Category = "Pill Pack Weapons"
|
||||
SWEP.Slot=3
|
||||
|
||||
SWEP.pill_attachment = "anim_attachment_RH"
|
||||
SWEP.pill_offset = Vector(20,0,5)
|
||||
SWEP.pill_angle = Angle(0,180,0)
|
||||
|
||||
function SWEP:SetupDataTables()
|
||||
self:NetworkVar("Bool",0,"Scoped")
|
||||
end
|
||||
|
||||
function SWEP:Initialize()
|
||||
self:SetHoldType("ar2")
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
if ( !self:CanPrimaryAttack() ) then return end
|
||||
|
||||
local bullet = {}
|
||||
bullet.Num = 1
|
||||
bullet.Src = self.Owner:GetShootPos()
|
||||
bullet.Dir = self.Owner:GetAimVector()
|
||||
//bullet.Spread = Vector(.001 ,.001, 0)
|
||||
bullet.Tracer = 1
|
||||
bullet.TracerName = "AirboatGunHeavyTracer"
|
||||
bullet.Force = 5
|
||||
bullet.Damage = 50
|
||||
|
||||
self:ShootEffects()
|
||||
|
||||
self.Owner:FireBullets(bullet)
|
||||
self:EmitSound("npc/sniper/sniper1.wav")
|
||||
self:EmitSound("npc/sniper/echo1.wav")
|
||||
self:TakePrimaryAmmo(1)
|
||||
|
||||
//self:SetNextPrimaryFire( CurTime() + .5)
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
//if !IsFirstTimePredicted() then return end
|
||||
self:SetScoped(!self:GetScoped())
|
||||
|
||||
if self:GetScoped() then
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetEntity(self)
|
||||
util.Effect("sniper_lazer",effectdata,true,true)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Reload()
|
||||
if self.ReloadingTime and CurTime() <= self.ReloadingTime then return end
|
||||
|
||||
if ( self:Clip1() < self.Primary.ClipSize and self.Owner:GetAmmoCount( self.Primary.Ammo ) > 0 ) then
|
||||
self:EmitSound("npc/sniper/reload1.wav")
|
||||
self:DefaultReload(ACT_VM_RELOAD)
|
||||
self.ReloadingTime = CurTime() + 1.5
|
||||
self:SetNextPrimaryFire(CurTime() + 1.5)
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:TranslateFOV( fov )
|
||||
if self:GetScoped() then
|
||||
return 15
|
||||
end
|
||||
return fov
|
||||
end
|
||||
|
||||
function SWEP:AdjustMouseSensitivity()
|
||||
if self:GetScoped() then
|
||||
return .1
|
||||
end
|
||||
return 1
|
||||
end
|
||||
|
||||
function SWEP:Holster()
|
||||
self:SetScoped(false)
|
||||
return true
|
||||
end
|
||||
|
||||
/*local lazerMat = Material("cable/xbeam")
|
||||
function SWEP:PillDraw()
|
||||
//print("AHHH")
|
||||
print(self:GetScoped())
|
||||
//if self:GetScoped() then
|
||||
//print("NIG")
|
||||
local color = Color(90, 240, 255)
|
||||
|
||||
render.SetMaterial(lazerMat)
|
||||
|
||||
render.DrawBeam(self.Owner:EyePos(),self.Owner:GetEyeTrace().HitPos,2,0,0,color)
|
||||
//print("RWJ")
|
||||
//end
|
||||
end*/
|
||||
35
lua/weapons/pill_wep_holstered.lua
Normal file
35
lua/weapons/pill_wep_holstered.lua
Normal file
@@ -0,0 +1,35 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
--SWEP.base = "weapon_base"
|
||||
AddCSLuaFile()
|
||||
SWEP.ViewModel = "models/weapons/c_arms_citizen.mdl"
|
||||
SWEP.WorldModel = ""
|
||||
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.Spawnable=true
|
||||
SWEP.AdminSpawnable=true]]
|
||||
SWEP.PrintName = "Holstered"
|
||||
|
||||
function SWEP:Initialize()
|
||||
self:SetHoldType("normal")
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
end
|
||||
57
lua/weapons/pill_wep_magnade.lua
Normal file
57
lua/weapons/pill_wep_magnade.lua
Normal file
@@ -0,0 +1,57 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
//SWEP.base = "weapon_base"
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
SWEP.ViewModel = "models/weapons/v_magnade.mdl"
|
||||
SWEP.WorldModel = ""
|
||||
|
||||
SWEP.Primary.ClipSize = -1
|
||||
SWEP.Primary.DefaultClip = -1
|
||||
SWEP.Primary.Automatic = false
|
||||
SWEP.Primary.Ammo = "none"//"Grenade"
|
||||
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = false
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
|
||||
SWEP.Spawnable=true
|
||||
SWEP.AdminSpawnable=true
|
||||
|
||||
SWEP.PrintName="Magnades"
|
||||
SWEP.Category = "Pill Pack Weapons"
|
||||
SWEP.Slot=4
|
||||
|
||||
function SWEP:Initialize()
|
||||
self:SetHoldType("grenade")
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
//if self:Ammo1()==0 then return end
|
||||
if CLIENT then return end
|
||||
local g = ents.Create("pill_proj_magnade")
|
||||
g:SetPos(self.Owner:EyePos()+self.Owner:EyeAngles():Forward()*100)
|
||||
g:SetVelocity(self.Owner:EyeAngles():Forward()*100)
|
||||
g:Spawn()
|
||||
g.attacker=self.Owner
|
||||
g:GetPhysicsObject():SetVelocity(self.Owner:EyeAngles():Forward()*800)
|
||||
|
||||
self:SendWeaponAnim(ACT_VM_THROW)
|
||||
timer.Simple(.5,function() if !IsValid(self) then return end self:SendWeaponAnim(ACT_VM_DRAW) end)
|
||||
self.Owner:SetAnimation(PLAYER_ATTACK1)
|
||||
|
||||
self:SetNextPrimaryFire(CurTime() + 1.5)
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
end
|
||||
137
lua/weapons/pill_wep_morphgun.lua
Normal file
137
lua/weapons/pill_wep_morphgun.lua
Normal file
@@ -0,0 +1,137 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
SWEP.ViewModel = "models/weapons/c_toolgun.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_toolgun.mdl"
|
||||
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.PrintName = "Morph Gun"
|
||||
|
||||
function SWEP:SetupDataTables()
|
||||
self:NetworkVar("String", 1, "Form")
|
||||
self:NetworkVar("Int", 1, "Mode")
|
||||
end
|
||||
|
||||
function SWEP:Initialize()
|
||||
self:SetHoldType("pistol")
|
||||
self.nextreload = 0
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
if SERVER and self.Owner:IsAdmin() then
|
||||
local ply = self.Owner:GetEyeTrace().Entity
|
||||
|
||||
if ply:GetClass() == "pill_ent_phys" then
|
||||
ply:EmitSound("npc/manhack/bat_away.wav")
|
||||
ply = ply:GetPillUser()
|
||||
elseif not ply:IsPlayer() then
|
||||
return
|
||||
else
|
||||
ply:EmitSound("npc/manhack/bat_away.wav")
|
||||
end
|
||||
|
||||
local mode = self:GetMode()
|
||||
|
||||
if mode == 0 then
|
||||
mode = "force"
|
||||
elseif mode == 1 then
|
||||
mode = "lock-life"
|
||||
elseif mode == 2 then
|
||||
mode = "lock-map"
|
||||
elseif mode == 3 then
|
||||
mode = "lock-perma"
|
||||
end
|
||||
|
||||
pk_pills.apply(ply, self:GetForm(), mode)
|
||||
self.Owner:EmitSound("weapons/airboat/airboat_gun_energy2.wav")
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
if SERVER and self.Owner:IsAdmin() then
|
||||
local ply = self.Owner:GetEyeTrace().Entity
|
||||
|
||||
if ply:GetClass() == "pill_ent_phys" then
|
||||
ply:EmitSound("npc/manhack/bat_away.wav")
|
||||
ply = ply:GetPillUser()
|
||||
elseif not ply:IsPlayer() then
|
||||
return
|
||||
else
|
||||
ply:EmitSound("npc/manhack/bat_away.wav")
|
||||
end
|
||||
|
||||
pk_pills.restore(ply, true)
|
||||
self.Owner:EmitSound("weapons/airboat/airboat_gun_energy2.wav")
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Reload()
|
||||
if SERVER and self.Owner:IsAdmin() and CurTime() > self.nextreload then
|
||||
local n = self:GetMode()
|
||||
|
||||
if n < 3 then
|
||||
n = n + 1
|
||||
else
|
||||
n = 0
|
||||
end
|
||||
|
||||
if n == 0 then
|
||||
self.Owner:ChatPrint("FORCE MODE: Players will be forced to morph but can still change back.")
|
||||
elseif n == 1 then
|
||||
self.Owner:ChatPrint("LIFELOCK MODE: The player will be locked in the pill until they die.")
|
||||
elseif n == 2 then
|
||||
self.Owner:ChatPrint("MAPLOCK MODE: The player will be locked in the pill until the map changes.")
|
||||
elseif n == 3 then
|
||||
self.Owner:ChatPrint("PERMALOCK MODE: Players will be locked in the pill forever.")
|
||||
end
|
||||
|
||||
self:SetMode(n)
|
||||
self.nextreload = CurTime() + 1
|
||||
self.Owner:EmitSound("weapons/slam/mine_mode.wav")
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:OnDrop()
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
local matScreen = Material("models/weapons/v_toolgun/screen")
|
||||
|
||||
function SWEP:ViewModelDrawn(ent)
|
||||
local matBg = Material("pills/" .. self:GetForm() .. ".png")
|
||||
matScreen:SetTexture("$basetexture", matBg:GetTexture("$basetexture"))
|
||||
local n = self:GetMode()
|
||||
local color
|
||||
|
||||
if n == 0 then
|
||||
color = Color(0, 255, 0)
|
||||
elseif n == 1 then
|
||||
color = Color(255, 255, 0)
|
||||
elseif n == 2 then
|
||||
color = Color(255, 150, 0)
|
||||
elseif n == 3 then
|
||||
color = Color(255, 0, 0)
|
||||
end
|
||||
|
||||
local ap = ent:GetAttachment(ent:LookupAttachment("muzzle"))
|
||||
cam.Start3D(EyePos(), EyeAngles())
|
||||
render.SetMaterial(Material("sprites/light_glow02_add"))
|
||||
render.DrawSprite(ap.Pos, 20, 20, color)
|
||||
cam.End3D()
|
||||
end
|
||||
end
|
||||
61
lua/weapons/pill_wep_pro.lua
Normal file
61
lua/weapons/pill_wep_pro.lua
Normal file
@@ -0,0 +1,61 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
--Made by SkyLight http://steamcommunity.com/id/_I_I_I_I_I/, had to be indented manually because copy/pasta from github didn't. Copy pastad of Parakeet's code.
|
||||
--Formatted and edited by Parakeet
|
||||
SWEP.ViewModel = "models/weapons/c_arms_citizen.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_snip_awp.mdl"
|
||||
SWEP.Primary.ClipSize = 1
|
||||
SWEP.Primary.DefaultClip = 1
|
||||
SWEP.Primary.Automatic = false
|
||||
SWEP.Primary.Ammo = "357"
|
||||
SWEP.Secondary.ClipSize = -1
|
||||
SWEP.Secondary.DefaultClip = -1
|
||||
SWEP.Secondary.Automatic = false
|
||||
SWEP.Secondary.Ammo = "none"
|
||||
SWEP.Spawnable = true
|
||||
SWEP.AdminSpawnable = true
|
||||
SWEP.PrintName = "Professional Rifle"
|
||||
SWEP.Category = "Pill Pack Weapons"
|
||||
SWEP.Slot = 3
|
||||
|
||||
function SWEP:Initialize()
|
||||
self:SetHoldType("pistol")
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
if (not self:CanPrimaryAttack()) then return end
|
||||
local bullet = {}
|
||||
bullet.Num = 1
|
||||
bullet.Src = self.Owner:GetShootPos()
|
||||
bullet.Dir = self.Owner:GetAimVector()
|
||||
bullet.Spread = Vector(.001, .001, 0)
|
||||
bullet.Tracer = 1
|
||||
bullet.TracerName = "Tracer"
|
||||
bullet.Force = 9001
|
||||
bullet.Damage = 9001
|
||||
self:ShootEffects()
|
||||
self.Owner:FireBullets(bullet)
|
||||
self.Owner:EmitSound("birdbrainswagtrain/pro" .. math.random(11) .. ".wav")
|
||||
self.Owner:EmitSound("weapons/awp/awp1.wav")
|
||||
self:TakePrimaryAmmo(1)
|
||||
end
|
||||
|
||||
function SWEP:Reload()
|
||||
if self.ReloadingTime and CurTime() <= self.ReloadingTime then return end
|
||||
|
||||
if (self:Clip1() < self.Primary.ClipSize and self.Owner:GetAmmoCount(self.Primary.Ammo) > 0) then
|
||||
self:EmitSound("weapons/awp/awp_bolt.wav")
|
||||
self:DefaultReload(ACT_VM_RELOAD)
|
||||
self.ReloadingTime = CurTime() + 2
|
||||
self:SetNextPrimaryFire(CurTime() + 2)
|
||||
end
|
||||
end
|
||||
80
lua/weapons/pill_wep_translocator.lua
Normal file
80
lua/weapons/pill_wep_translocator.lua
Normal file
@@ -0,0 +1,80 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
SWEP.ViewModel = "models/weapons/c_irifle.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_irifle.mdl"
|
||||
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.Spawnable = true
|
||||
SWEP.AdminSpawnable = true
|
||||
SWEP.PrintName = "Translocator"
|
||||
SWEP.Category = "Pill Pack Weapons"
|
||||
SWEP.Slot = 3
|
||||
|
||||
function SWEP:SetupDataTables()
|
||||
self:NetworkVar("Entity", 1, "Target")
|
||||
end
|
||||
|
||||
function SWEP:Initialize()
|
||||
self:SetHoldType("ar2")
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
if CLIENT or not IsValid(self:GetTarget()) then return end
|
||||
local tr = self.Owner:GetEyeTrace()
|
||||
self:GetTarget():SetPos(tr.HitPos + tr.HitNormal * self:GetTarget():BoundingRadius())
|
||||
|
||||
if self:GetTarget():GetPhysicsObjectCount() > 0 then
|
||||
self:GetTarget():PhysWake()
|
||||
end
|
||||
|
||||
if self:GetTarget():IsPlayer() then
|
||||
self:GetTarget():SetMoveType(MOVETYPE_WALK)
|
||||
end
|
||||
|
||||
self:GetTarget():EmitSound("beams/beamstart5.wav")
|
||||
self.Owner:EmitSound("npc/roller/mine/rmine_taunt1.wav")
|
||||
self:SetNextPrimaryFire(CurTime() + 1)
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
if CLIENT then return end
|
||||
local tr = self.Owner:GetEyeTrace()
|
||||
|
||||
if not tr.Entity or tr.Entity:IsWorld() or not hook.Call("PhysgunPickup", GAMEMODE, self.Owner, tr.Entity) then
|
||||
self.Owner:EmitSound("buttons/button10.wav")
|
||||
self:SetTarget(nil)
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
self:EmitSound("buttons/blip1.wav")
|
||||
self:SetTarget(tr.Entity)
|
||||
end
|
||||
|
||||
function SWEP:DrawHUD()
|
||||
if not IsValid(self:GetTarget()) then return end
|
||||
|
||||
halo.Render{
|
||||
Ents = {self:GetTarget()},
|
||||
Color = Color(0, 255, 255),
|
||||
BlurX = 10,
|
||||
BlurY = 10,
|
||||
DrawPasses = 2,
|
||||
IgnoreZ = true
|
||||
}
|
||||
end
|
||||
231
lua/weapons/sf2_tool/cl_init.lua
Normal file
231
lua/weapons/sf2_tool/cl_init.lua
Normal file
@@ -0,0 +1,231 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
--[[-------------------------------------------------------------------------
|
||||
Point and click
|
||||
---------------------------------------------------------------------------]]
|
||||
|
||||
include("shared.lua")
|
||||
|
||||
|
||||
if ( SERVER ) then
|
||||
SWEP.AutoSwitchTo = false
|
||||
SWEP.AutoSwitchFrom = false
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
if not game.SinglePlayer() and not IsFirstTimePredicted() then return end
|
||||
local tool = self:GetTool()
|
||||
if not tool or not tool.LeftClick then return end
|
||||
tool.LeftClick(tool, self:GetOwner():GetEyeTrace())
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
if not game.SinglePlayer() and not IsFirstTimePredicted() then return end
|
||||
local tool = self:GetTool()
|
||||
if not tool or not tool.RightClick then return end
|
||||
tool.RightClick(tool, self:GetOwner():GetEyeTrace())
|
||||
end
|
||||
|
||||
function SWEP:Holster()
|
||||
self:RemoveGhost()
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:OnRemove()
|
||||
self:RemoveGhost()
|
||||
return true
|
||||
end
|
||||
|
||||
local oldTool = -1
|
||||
function SWEP:Think()
|
||||
local tool_id = self:GetToolID()
|
||||
if tool_id ~= oldTool then
|
||||
self:RemoveGhost()
|
||||
oldTool = tool_id
|
||||
self:SetTool(tool_id)
|
||||
end
|
||||
end
|
||||
|
||||
local ghostHalo
|
||||
function SWEP:SetGhost(mdl, pos, ang)
|
||||
-- Remove ghost if nil mdl
|
||||
if not mdl then
|
||||
if self._ghost and IsValid(self._ghost) then
|
||||
self._ghost:Remove()
|
||||
self._ghost = nil
|
||||
end
|
||||
return
|
||||
end
|
||||
-- Make ghost or set mdl
|
||||
if not self._ghost or not IsValid(self._ghost) then
|
||||
self._ghost = ClientsideModel(mdl, RENDERMODE_TRANSCOLOR )
|
||||
ghostHalo = nil
|
||||
elseif self._ghost:GetModel() ~= mdl then
|
||||
self._ghost:SetModel(mdl)
|
||||
end
|
||||
-- Move ghost
|
||||
if pos then
|
||||
self._ghost:SetPos(pos)
|
||||
end
|
||||
if ang then
|
||||
self._ghost:SetAngles(ang)
|
||||
end
|
||||
return self._ghost
|
||||
end
|
||||
|
||||
function SWEP:SetGhostHalo(col)
|
||||
ghostHalo = col
|
||||
end
|
||||
|
||||
function SWEP:RemoveGhost()
|
||||
self:SetGhost()
|
||||
end
|
||||
|
||||
-- Context menu
|
||||
do
|
||||
local v = false
|
||||
hook.Add("OnContextMenuOpen", "StormFox2.Tool.COpen", function()
|
||||
v = true
|
||||
end)
|
||||
hook.Add("OnContextMenuClose", "StormFox2.Tool.CClose", function()
|
||||
v = false
|
||||
end)
|
||||
|
||||
function SWEP:IsContextMenuOpen()
|
||||
return v
|
||||
end
|
||||
end
|
||||
|
||||
hook.Add("PreDrawHalos", "StormFox2.GhostHalo", function()
|
||||
local wep = LocalPlayer():GetActiveWeapon()
|
||||
if not wep or not IsValid(wep) then return end
|
||||
if wep:GetClass() ~= "sf2_tool" then return end
|
||||
if not IsValid(wep._ghost) then return end
|
||||
if not ghostHalo then return end
|
||||
halo.Add( {wep._ghost}, ghostHalo, 5, 5, 2 )
|
||||
end)
|
||||
|
||||
SWEP.WepSelectIcon = surface.GetTextureID( "vgui/gmod_camera" )
|
||||
|
||||
-- Don't draw the weapon info on the weapon selection thing
|
||||
function SWEP:DrawHUD() end
|
||||
function SWEP:PrintWeaponInfo( x, y, alpha ) end
|
||||
|
||||
--[[-------------------------------------------------------------------------
|
||||
function SWEP:CalcView(ply,pos,ang,fov)
|
||||
--pos = pos + ang:Forward() * -50
|
||||
return pos,ang,fov
|
||||
end
|
||||
---------------------------------------------------------------------------]]
|
||||
|
||||
-- Unstable screen
|
||||
function SWEP:_GetScreenUN()
|
||||
return self._unstable or 0.2
|
||||
end
|
||||
function SWEP:_SetScreenUN( n )
|
||||
self._unstable = n
|
||||
end
|
||||
|
||||
-- Render screen
|
||||
local matScreen = Material( "stormfox2/weapons/sf_tool_screen" )
|
||||
local bgMat = Material("stormfox2/logo.png")
|
||||
local sMat = Material("effects/tvscreen_noise002a")
|
||||
local rMat = Material("gui/r.png")
|
||||
do
|
||||
local ScreenSize = 256
|
||||
local RTTexture = GetRenderTarget( "SFToolgunScreen", ScreenSize, ScreenSize )
|
||||
function SWEP:RenderToolScreen()
|
||||
local TEX_SIZE = ScreenSize
|
||||
-- Set up our view for drawing to the texture
|
||||
--cam.IgnoreZ(true)
|
||||
render.PushRenderTarget( RTTexture )
|
||||
render.ClearDepth()
|
||||
render.Clear( 0, 0, 0, 0 )
|
||||
cam.Start2D()
|
||||
-- Draw Screen
|
||||
local tool = self:GetTool()
|
||||
if not tool then
|
||||
surface.SetDrawColor(color_white)
|
||||
surface.SetMaterial(bgMat)
|
||||
surface.DrawTexturedRect(TEX_SIZE * 0.1,TEX_SIZE * 0.1,TEX_SIZE * 0.8,TEX_SIZE * 0.8)
|
||||
surface.SetMaterial(rMat)
|
||||
if math.Round(CurTime()%2) ~= 0 then
|
||||
surface.DrawTexturedRect(20,TEX_SIZE - 60,40,40)
|
||||
end
|
||||
else
|
||||
if not tool.NoPrintName then
|
||||
draw.DrawText(tool.PrintName or "Unknown", "sf_tool_large", TEX_SIZE / 2, 10, color_white, TEXT_ALIGN_CENTER)
|
||||
end
|
||||
if tool.ScreenRender then
|
||||
tool:ScreenRender( TEX_SIZE, TEX_SIZE )
|
||||
end
|
||||
end
|
||||
-- surface.SetMaterial(sMat)
|
||||
-- surface.DrawTexturedRect(TEX_SIZE * 0.1,TEX_SIZE * 0.1,TEX_SIZE * 0.8,TEX_SIZE * 0.8)
|
||||
if self:_GetScreenUN() > 0.15 then
|
||||
surface.SetDrawColor(color_white)
|
||||
surface.SetMaterial(sMat)
|
||||
surface.DrawTexturedRect(0,0,TEX_SIZE * 2,TEX_SIZE * 2)
|
||||
end
|
||||
cam.End2D()
|
||||
render.PopRenderTarget()
|
||||
|
||||
matScreen:SetTexture( "$basetexture", RTTexture )
|
||||
matScreen:SetFloat("$shake", self:_GetScreenUN())
|
||||
--cam.IgnoreZ(false)
|
||||
end
|
||||
end
|
||||
|
||||
local mTool = Material("stormfox2/weapons/sf_tool")
|
||||
|
||||
function SWEP:PreDrawViewModel()
|
||||
if self:_GetScreenUN() > 0 then
|
||||
self:_SetScreenUN( math.max(0, self:_GetScreenUN() - FrameTime() * 0.6) )
|
||||
end
|
||||
self:RenderToolScreen()
|
||||
render.MaterialOverrideByIndex(1,matScreen)
|
||||
render.MaterialOverrideByIndex(2,mTool)
|
||||
|
||||
end
|
||||
function SWEP:PostDrawViewModel()
|
||||
render.MaterialOverrideByIndex()
|
||||
local tool = self:GetTool()
|
||||
if not tool then return end
|
||||
-- Render
|
||||
if tool.Render then
|
||||
cam.Start3D()
|
||||
tool:Render()
|
||||
cam.End3D()
|
||||
end
|
||||
end
|
||||
|
||||
-- CL swep rendering
|
||||
function SWEP:CalcViewModelView( vm, _,_,pos, ang)
|
||||
end
|
||||
|
||||
function SWEP:Deploy()
|
||||
self:_SetScreenUN( 0.2 )
|
||||
end
|
||||
|
||||
function SWEP:DrawWorldModel()
|
||||
local Owner = self:GetOwner()
|
||||
if IsValid(Owner) and Owner ~= LocalPlayer() then
|
||||
self:_SetScreenUN( 0 )
|
||||
elseif self:_GetScreenUN() < 0.4 then
|
||||
self:_SetScreenUN( math.min(0.4, self:_GetScreenUN() + FrameTime() * 0.2) )
|
||||
end
|
||||
self:RenderToolScreen()
|
||||
render.MaterialOverrideByIndex(1,matScreen)
|
||||
render.MaterialOverrideByIndex(2,mTool)
|
||||
self:DrawModel()
|
||||
render.MaterialOverrideByIndex()
|
||||
end
|
||||
103
lua/weapons/sf2_tool/init.lua
Normal file
103
lua/weapons/sf2_tool/init.lua
Normal file
@@ -0,0 +1,103 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
--[[-------------------------------------------------------------------------
|
||||
Point and click
|
||||
---------------------------------------------------------------------------]]
|
||||
|
||||
AddCSLuaFile( "cl_init.lua" )
|
||||
AddCSLuaFile( "shared.lua" )
|
||||
|
||||
include("shared.lua")
|
||||
|
||||
SWEP.AutoSwitchTo = true
|
||||
SWEP.AutoSwitchFrom = true
|
||||
|
||||
function SWEP:ShouldDropOnDie() return false end
|
||||
|
||||
-- Add tools
|
||||
local TOOLS = {}
|
||||
|
||||
function SWEP:SwitchTool()
|
||||
local n = self:GetToolID() + 1
|
||||
if n > #self.Tool then
|
||||
n = 1
|
||||
end
|
||||
self:SetTool( n )
|
||||
end
|
||||
|
||||
function SWEP:HasAccessToSettings( onSuccess, ... )
|
||||
local a = {...}
|
||||
local ply = self:GetOwner()
|
||||
if not IsValid(ply) then return end
|
||||
CAMI.PlayerHasAccess(ply,"StormFox Settings",function(b)
|
||||
if not b then
|
||||
if IsValid(ply) then
|
||||
ply:EmitSound("ambient/alarms/klaxon1.wav")
|
||||
end
|
||||
SafeRemoveEntity(self)
|
||||
end
|
||||
onSuccess( unpack( a ) )
|
||||
end)
|
||||
end
|
||||
|
||||
function SWEP:Equip( newOwner )
|
||||
if newOwner:GetClass() ~= "player" then
|
||||
SafeRemoveEntity(self)
|
||||
else
|
||||
self:HasAccessToSettings( function() end )
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
if not IsFirstTimePredicted() then return end
|
||||
if ( game.SinglePlayer() ) then self:CallOnClient( "PrimaryAttack" ) end
|
||||
local tool = self:GetTool()
|
||||
if not tool or not tool.LeftClick then return end
|
||||
local Owner = self:GetOwner()
|
||||
if tool.LeftClick(self, Owner:GetEyeTrace()) then
|
||||
self:DoShootEffect(Owner:GetEyeTrace(),IsFirstTimePredicted())
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
if not IsFirstTimePredicted() then return end
|
||||
if ( game.SinglePlayer() ) then self:CallOnClient( "SecondaryAttack" ) end
|
||||
local tool = self:GetTool()
|
||||
if not tool or not tool.RightClick then return end
|
||||
local Owner = self:GetOwner()
|
||||
if tool.RightClick(self, Owner:GetEyeTrace()) then
|
||||
self:DoShootEffect(Owner:GetEyeTrace(),IsFirstTimePredicted())
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Holster()
|
||||
if not IsFirstTimePredicted() then return end
|
||||
if ( game.SinglePlayer() ) then self:CallOnClient( "Holster" ) end
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:Reload()
|
||||
if not IsFirstTimePredicted() then return end
|
||||
local Owner = self:GetOwner()
|
||||
if ( !Owner:KeyPressed( IN_RELOAD ) ) then return end
|
||||
self:SwitchTool()
|
||||
Owner:EmitSound("buttons/button14.wav")
|
||||
end
|
||||
|
||||
function SWEP:Think()
|
||||
end
|
||||
|
||||
-- Stops players from picking up multiple tools
|
||||
hook.Add("PlayerCanPickupWeapon", "StormFox2.Tool.Pickup", function(ply, wep)
|
||||
if (wep:GetClass() ~= "sf2_tool") then return end -- Ignore other weapons
|
||||
if IsValid(ply:GetWeapon("sf2_tool")) then return false end -- If you already have a tool, don't pick this one up
|
||||
end)
|
||||
333
lua/weapons/sf2_tool/settings/light_editor.lua
Normal file
333
lua/weapons/sf2_tool/settings/light_editor.lua
Normal file
@@ -0,0 +1,333 @@
|
||||
--[[
|
||||
| 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 TOOL = {}
|
||||
TOOL.RealName = "Light Editor"
|
||||
TOOL.PrintName = "#sf_tool.light_editor"
|
||||
TOOL.ToolTip = "#sf_tool.light_editor.desc"
|
||||
TOOL.NoPrintName = false
|
||||
-- TOOL.ShootSound = Sound("weapons/irifle/irifle_fire2.wav")
|
||||
|
||||
local SPAWN = 0
|
||||
local DELETE = 1
|
||||
local SPAWN_ALL = 2
|
||||
local DELETE_ALL= 3
|
||||
|
||||
local INVALID = 0
|
||||
local POINTLIGHT= 1
|
||||
local SPOTLIGHT = 2
|
||||
local FAKESPOT = 3
|
||||
|
||||
local t_models = {}
|
||||
t_models['models/props_c17/lamppost03a_off.mdl'] = {Vector(0,94,440), Angle(0,0,0), SPOTLIGHT}
|
||||
t_models['models/sickness/evolight_01.mdl'] = {Vector(0,-80,314), Angle(0,0,0), SPOTLIGHT}
|
||||
t_models['models/props_lighting/lightfixture02.mdl'] = {Vector(50,0,-10), Angle(30,0,0), FAKESPOT}
|
||||
t_models['models/sickness/parkinglotlight.mdl'] = {Vector(0,30,284), Angle(0,0,0), FAKESPOT, Vector(0,-30,284)}
|
||||
t_models['models/props/de_inferno/light_streetlight.mdl'] = {Vector(0,0,150), Angle(0,0,0), POINTLIGHT}
|
||||
t_models['models/props/cs_office/light_inset.mdl'] = {Vector(0,0,-3), Angle(0,0,0), POINTLIGHT}
|
||||
t_models['models/unioncity2/props_street/streetlight.mdl'] = {Vector(0,-108,388), Angle(0,0,0), SPOTLIGHT}
|
||||
t_models['models/unioncity2/props_lighting/lightpost_double.mdl']={Vector(5,0,358),Angle(0,0,0), SPOTLIGHT, Vector(-75,0,358)}
|
||||
t_models['models/unioncity2/props_street/telepole01b.mdl'] = {Vector(0,-109,335), Angle(0,0,0), SPOTLIGHT}
|
||||
t_models['models/unioncity2/props_lighting/lightpost_single.mdl']={Vector(76,0,357),Angle(0,0,0), SPOTLIGHT}
|
||||
|
||||
t_models['models/props_badlands/siloroom_light2.mdl'] = {Vector(0,0,-18), Angle(0,0,0), POINTLIGHT}
|
||||
t_models['models/props_badlands/siloroom_light2_small.mdl'] = {Vector(0,0,-14), Angle(0,0,0), POINTLIGHT}
|
||||
t_models['models/props_c17/light_cagelight01_off.mdl'] = {Vector(4,0,-8), Angle(0,0,0), POINTLIGHT}
|
||||
t_models['models/props_c17/light_cagelight02_off.mdl'] = {Vector(4,0,-8), Angle(0,0,0), POINTLIGHT}
|
||||
t_models['models/props_c17/light_cagelight02_on.mdl'] = {Vector(4,0,-8), Angle(0,0,0), POINTLIGHT}
|
||||
t_models['models/props_c17/light_decklight01_off.mdl'] = {Vector(0,0,0), Angle(90,180,0),SPOTLIGHT}
|
||||
t_models['models/props_c17/light_decklight01_on.mdl'] = {Vector(0,0,0), Angle(90,180,0),SPOTLIGHT}
|
||||
t_models['models/props_c17/light_domelight01_off.mdl'] = {Vector(0,0,-8), Angle(0,0,0), POINTLIGHT}
|
||||
t_models['models/props_c17/light_floodlight02_off.mdl'] = {Vector(0,-15,78), Angle(0,275,68),FAKESPOT,Vector(0,15,78), Angle(0,265,68)}
|
||||
t_models['models/props_c17/light_industrialbell01_on.mdl'] = {Vector(0,0,-8), Angle(0,0,0), FAKESPOT}
|
||||
t_models['models/props_combine/combine_light001a.mdl'] = {Vector(-6,0,34), Angle(90,0,0), SPOTLIGHT}
|
||||
t_models['models/props_combine/combine_light001b.mdl'] = {Vector(-12,0,47), Angle(90,0,0), SPOTLIGHT}
|
||||
t_models['models/props_combine/combine_light002a.mdl'] = {Vector(-9,0,37), Angle(90,0,0), SPOTLIGHT}
|
||||
t_models['models/props_equipment/light_floodlight.mdl'] = {Vector(0,-12,80), Angle(0,275,68),FAKESPOT,Vector(0,12,80), Angle(0,265,68)}
|
||||
t_models['models/props_gameplay/security_fence_light01.mdl']= {Vector(0,-68,-11), Angle(0,0,0), SPOTLIGHT}
|
||||
t_models['models/props_wasteland/lights_industrialcluster01a.mdl']= {Vector(-20,0,374),Angle(52,0,0),SPOTLIGHT, Vector(20,0,374), Angle(-52,0,0)}
|
||||
t_models['models/props_mvm/construction_light02.mdl'] = {Vector(-30,-25,144), Angle(0,275,68),FAKESPOT,Vector(-30,25,144), Angle(0,265,68)}
|
||||
t_models['models/props_hydro/construction_light.mdl'] = {Vector(0,-3,-19), Angle(0,0,45), SPOTLIGHT}
|
||||
t_models['models/props/cs_assault/streetlight.mdl'] = {Vector(50,0,45), Angle(0,0,0), SPOTLIGHT}
|
||||
t_models['models/props/cs_italy/it_streetlampleg.mdl']={Vector(0,0,156),Angle(0,0,0), POINTLIGHT}
|
||||
|
||||
local function IsLightNear(pos)
|
||||
local t = {}
|
||||
for k,v in ipairs(ents.FindInSphere(pos, 20)) do
|
||||
if v:GetClass() == "stormfox_streetlight_invisible" then
|
||||
return v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function SpawnMissingLight(pos, ang, i_type)
|
||||
if IsLightNear(pos) then return end
|
||||
local ent = ents.Create("stormfox_streetlight_invisible")
|
||||
ent:SetPos(pos)
|
||||
ent:SetAngles(ang)
|
||||
ent:Spawn()
|
||||
ent:SetLightType(i_type)
|
||||
return ent
|
||||
end
|
||||
|
||||
local function StaticLocal(v, pos, ang)
|
||||
return LocalToWorld(pos * (v.UniformScale or v.Scale or 1), ang, v.Origin, v.Angles)
|
||||
end
|
||||
|
||||
local function StaticLightPos(v)
|
||||
local tab = t_models[v.PropType]
|
||||
if not tab then return end -- Unknown
|
||||
local pos, ang = StaticLocal(v, tab[1] * (v.UniformScale or v.Scale), tab[2])
|
||||
local spos, ang2
|
||||
if tab[4] then
|
||||
spos, ang2 = StaticLocal(v, tab[4] * (v.UniformScale or v.Scale), tab[5] or tab[2])
|
||||
end
|
||||
return pos, ang, spos, ang2
|
||||
end
|
||||
|
||||
local sorter = function(a,b)
|
||||
return a[5]<b[5]
|
||||
end
|
||||
|
||||
local function FindStaticProps(pos, dis)
|
||||
local ls = StormFox2.Map.FindStaticsInSphere(pos, dis)
|
||||
local t = {}
|
||||
for k, v in ipairs(ls) do
|
||||
if t_models[v.PropType] then
|
||||
table.insert(t, {v.PropType, v.Origin, v.Angles, v.UniformScale or v.Scale or 1, v.Origin:DistToSqr(pos)})
|
||||
else
|
||||
--print(v.PropType)
|
||||
end
|
||||
end
|
||||
if #t < 1 then return end
|
||||
if #t < 2 then return t[1][1],t[1][2],t[1][3],t[1][4] end
|
||||
table.sort(t, sorter)
|
||||
return t[1][1],t[1][2],t[1][3],t[1][4]
|
||||
end
|
||||
|
||||
-- Returns a mdl, pos, ang and scale if found
|
||||
local function FindTraceTarget(tr)
|
||||
local ent = tr.Entity
|
||||
if not ent then return end
|
||||
if ent:IsWorld() then -- Static-Prop?
|
||||
if tr.HitTexture ~= "**studio**" then return end -- Not a static prop
|
||||
return FindStaticProps(tr.HitPos, 200)
|
||||
elseif IsValid(ent) and t_models[ent:GetModel()] then-- Prop
|
||||
return ent:GetModel(), ent:GetPos(), ent:GetAngles(), ent:GetModelScale()
|
||||
end
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
-- Spawns all missing lights for said model
|
||||
local function SpawnMissingLights(mdl)
|
||||
if not t_models[mdl] then return end
|
||||
local all_static = StormFox2.Map.StaticProps()
|
||||
for k, v in pairs(all_static) do
|
||||
if v.PropType ~= mdl then continue end
|
||||
local pos, ang, pos2, ang2 = StaticLightPos(v)
|
||||
SpawnMissingLight(pos, ang, t_models[mdl][3])
|
||||
if pos2 then
|
||||
SpawnMissingLight(pos2, ang2, t_models[mdl][3])
|
||||
end
|
||||
end
|
||||
end
|
||||
-- Deletes all light for said model
|
||||
local function DeleteAllLights(mdl)
|
||||
if not t_models[mdl] then return end
|
||||
local all_static = StormFox2.Map.StaticProps()
|
||||
for k, v in pairs(all_static) do
|
||||
if v.PropType ~= mdl then continue end
|
||||
local pos, ang, pos2 = StaticLightPos(v)
|
||||
SafeRemoveEntity(IsLightNear(pos))
|
||||
if pos2 then
|
||||
SafeRemoveEntity(IsLightNear(pos2))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local popsnd = Sound("garrysmod/balloon_pop_cute.wav")
|
||||
function TOOL:SendFunc( a, b, c, d )
|
||||
if a == SPAWN and type(b) == "number" and c and d then -- Spawn, n_type, pos, ang
|
||||
if IsLightNear(c) then return end
|
||||
local ent = ents.Create("stormfox_streetlight_invisible")
|
||||
ent:SetPos(c)
|
||||
ent:SetAngles(d)
|
||||
ent:Spawn()
|
||||
ent:SetLightType(b)
|
||||
self:EmitSound("weapons/ar2/ar2_reload_rotate.wav")
|
||||
elseif a == DELETE and IsValid(b) and b.GetClass then -- Delete, entity
|
||||
if b:GetClass()~="stormfox_streetlight_invisible" then return end -- Can't delete things
|
||||
b:EmitSound(popsnd)
|
||||
SafeRemoveEntity(b)
|
||||
elseif a == SPAWN_ALL then
|
||||
SpawnMissingLights(b)
|
||||
self:EmitSound("weapons/ar2/ar2_reload_rotate.wav")
|
||||
elseif a == DELETE_ALL then
|
||||
DeleteAllLights(b)
|
||||
self:EmitSound("weapons/ar2/ar2_reload_rotate.wav")
|
||||
end
|
||||
end
|
||||
else
|
||||
function TOOL:SpawnLight(n_type, pos, ang, double, ang2)
|
||||
self.SendFunc( SPAWN, n_type, pos, ang )
|
||||
if double then self.SendFunc( SPAWN, n_type, double, ang2 or ang ) end
|
||||
end
|
||||
function TOOL:DeleteLight( ent )
|
||||
if not IsValid(ent) then return end
|
||||
self.SendFunc( DELETE, ent )
|
||||
end
|
||||
function TOOL:SpawnAllLights(mdl)
|
||||
if not t_models[mdl] then return end
|
||||
self.SendFunc( SPAWN_ALL, mdl )
|
||||
end
|
||||
function TOOL:DeleteAllLights(mdl)
|
||||
if not t_models[mdl] then return end
|
||||
self.SendFunc( DELETE_ALL, mdl )
|
||||
end
|
||||
|
||||
local selectedData = {
|
||||
}
|
||||
local ghost
|
||||
-- Render is called right after screenrender
|
||||
local v = Vector(440,40,40)
|
||||
local m_lamp = Material('stormfox2/effects/light_beam')
|
||||
local m_spot = Material('stormfox2/effects/spotlight')
|
||||
function TOOL:Render()
|
||||
if not selectedData.Pos then return end
|
||||
if selectedData.Type == SPOTLIGHT or selectedData.Type == FAKESPOT then
|
||||
render.SetMaterial(m_lamp)
|
||||
render.DrawBeam(selectedData.Pos, selectedData.Pos - selectedData.Ang:Up() * 300, 300, 0, 1, color_white)
|
||||
if selectedData.Pos2 then
|
||||
render.DrawBeam(selectedData.Pos2, selectedData.Pos2 - selectedData.Ang2:Up() * 300, 300, 0, 1, color_white)
|
||||
end
|
||||
elseif selectedData.Type == POINTLIGHT then
|
||||
render.SetMaterial(m_spot)
|
||||
render.DrawSprite(selectedData.Pos, 80, 80, color_white)
|
||||
if selectedData.Pos2 then
|
||||
render.DrawSprite(selectedData.Pos2, 80, 80, color_white)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local ghost
|
||||
local col = Color(0,255,0)
|
||||
local ssi_mdl = Model("models/hunter/blocks/cube025x025x025.mdl")
|
||||
local c_outline = "model_color"
|
||||
local a_outline = "models/effects/comball_tape"
|
||||
local default_lighttype = FAKESPOT
|
||||
local function ScanTrace(self,tr)
|
||||
selectedData = {}
|
||||
-- Delete lights if looking at them
|
||||
if IsValid(tr.Entity) and tr.Entity:GetClass() == "stormfox_streetlight_invisible" then
|
||||
ghost = self._swep:SetGhost(tr.Entity:GetModel(), tr.Entity:GetPos(), tr.Entity:GetAngles())
|
||||
self:SetGhostHalo(col)
|
||||
selectedData.deleteEnt = tr.Entity
|
||||
else -- Check for staticprops / props
|
||||
local mdl, pos, ang, scale = FindTraceTarget(tr)
|
||||
if mdl then -- If valid target
|
||||
selectedData.Model = mdl
|
||||
local tab = t_models[mdl]
|
||||
ghost = self._swep:SetGhost(mdl, pos, ang)
|
||||
ghost:SetMaterial(a_outline)
|
||||
if ghost then -- If ghost
|
||||
scale = scale or 1
|
||||
-- Check if ent is there
|
||||
ghost:SetModelScale(scale)
|
||||
ghost:SetColor(Color(255,255,255,255))
|
||||
selectedData.Pos = ghost:LocalToWorld(tab[1] * scale)
|
||||
selectedData.Ang = ghost:LocalToWorldAngles(tab[2])
|
||||
selectedData.Pos2 = tab[4] and ghost:LocalToWorld(tab[4] * scale)
|
||||
selectedData.Ang2 = tab[5] and ghost:LocalToWorldAngles(tab[5]) or selectedData.Ang
|
||||
selectedData.Type = tab[3]
|
||||
local b = IsLightNear(selectedData.Pos)
|
||||
local c = selectedData.Pos2 and IsLightNear(selectedData.Pos2)
|
||||
if b then
|
||||
self:SetGhostHalo(col)
|
||||
selectedData.deleteEnt = b
|
||||
selectedData.deleteEnt2 = c
|
||||
else
|
||||
self:SetGhostHalo(color_white)
|
||||
end
|
||||
end
|
||||
else -- Invalid target
|
||||
selectedData.Type = default_lighttype
|
||||
local ang = tr.HitNormal:Angle()
|
||||
ang:RotateAroundAxis(ang:Right(), 90)
|
||||
ghost = self._swep:SetGhost(ssi_mdl, tr.HitPos, ang)
|
||||
if ghost then
|
||||
ghost:SetMaterial(c_outline)
|
||||
selectedData.Pos = ghost:GetPos()
|
||||
selectedData.Ang = (input.IsKeyDown( KEY_LCONTROL ) or input.IsKeyDown( KEY_RCONTROL )) and Angle(0,0,0) or ghost:GetAngles()
|
||||
if default_lighttype == POINTLIGHT then
|
||||
selectedData.Pos = selectedData.Pos + tr.HitNormal
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local m1 = Material("effects/lamp_beam")
|
||||
local m2 = Material("sprites/glow04_noz")
|
||||
local m3 = Material("effects/flashlight001")
|
||||
function TOOL:ScreenRender( w, h )
|
||||
ScanTrace(self,LocalPlayer():GetEyeTrace())
|
||||
surface.SetDrawColor(color_white)
|
||||
surface.DrawOutlinedRect(w * 0.1,h * 0.2,w * 0.8,h * 0.7)
|
||||
local l_type = selectedData.Type or default_lighttype
|
||||
surface.SetDrawColor(255,255,255)
|
||||
if l_type == POINTLIGHT then
|
||||
surface.SetMaterial(m2)
|
||||
elseif l_type == FAKESPOT then
|
||||
surface.SetMaterial(m1)
|
||||
elseif l_type == SPOTLIGHT then
|
||||
surface.SetMaterial(m3)
|
||||
surface.DrawTexturedRect(w * 0.1, h * 0.4, w * 0.8, h * 0.7)
|
||||
surface.SetMaterial(m1)
|
||||
end
|
||||
|
||||
surface.DrawTexturedRect(w * 0.1, h * 0.2, w * 0.8, h * 0.7)
|
||||
end
|
||||
end
|
||||
function TOOL:LeftClick(tr)
|
||||
if not IsValid(ghost) then return end
|
||||
local select_all = input.IsKeyDown( KEY_LCONTROL ) or input.IsKeyDown( KEY_RCONTROL )
|
||||
-- If we hold control in. Spawn all lights for given model
|
||||
if select_all and selectedData.Model then
|
||||
if selectedData.Model then
|
||||
self:SpawnAllLights(selectedData.Model)
|
||||
return
|
||||
end
|
||||
elseif not selectedData.deleteEnt and selectedData.Pos then -- Only spawn light, if we aren't looking at an entity atm
|
||||
self:SpawnLight(selectedData.Type, selectedData.Pos, selectedData.Ang, selectedData.Pos2, selectedData.Ang2)
|
||||
-- selectedData.Pos = nil
|
||||
end
|
||||
end
|
||||
function TOOL:RightClick(tr)
|
||||
if self:IsContextMenuOpen() then return end -- Don't delete the entity if you rightclick it for properties.
|
||||
-- Delete all lights for the given model (If not valid, then do nothing)
|
||||
local select_all = input.IsKeyDown( KEY_LCONTROL ) or input.IsKeyDown( KEY_RCONTROL )
|
||||
if select_all then
|
||||
if selectedData.Model then
|
||||
self:DeleteAllLights(selectedData.Model)
|
||||
end
|
||||
return
|
||||
end
|
||||
-- Delete the entity we look at
|
||||
if selectedData.deleteEnt then
|
||||
self:DeleteLight(selectedData.deleteEnt)
|
||||
self:DeleteLight(selectedData.deleteEnt2)
|
||||
else -- If no entity, then swap the lighttype.
|
||||
default_lighttype = default_lighttype + 1
|
||||
if default_lighttype > 3 then default_lighttype = 1 end
|
||||
end
|
||||
end
|
||||
end
|
||||
return TOOL
|
||||
148
lua/weapons/sf2_tool/settings/surface_editor.lua
Normal file
148
lua/weapons/sf2_tool/settings/surface_editor.lua
Normal file
@@ -0,0 +1,148 @@
|
||||
--[[
|
||||
| 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 TOOL = {}
|
||||
TOOL.RealName = "Surface Editor"
|
||||
TOOL.PrintName = "#sf_tool.surface_editor"
|
||||
TOOL.ToolTip = "#sf_tool.surface_editor.desc"
|
||||
TOOL.NoPrintName = false
|
||||
TOOL.ShootSound = Sound("weapons/irifle/irifle_fire2.wav")
|
||||
|
||||
local mat = Material("stormfox2/weapons/sf_tool_mat")
|
||||
local function FindTexture( str )
|
||||
str = str:lower()
|
||||
if str == "**displacement**" then return end
|
||||
if str == "**studio**" then return end
|
||||
if str:sub(0,5) == "tools" then return end
|
||||
local mat = Material(str)
|
||||
--if str:sub(0,5) == "maps/" and false then -- This is a hammer thingy
|
||||
-- str = mat:GetString( "$basetexture" ) or mat:GetString( "$basetexture2" )
|
||||
-- mat = Material(str)
|
||||
-- if StormFox2.Terrain.HasMaterialChanged(mat) then -- We havve replaced this material. Lets get the basetexture
|
||||
-- return StormFox2.Terrain.GetOriginalTexture(mat)
|
||||
-- end
|
||||
--end
|
||||
return str
|
||||
end
|
||||
|
||||
local cross = Material("gui/cross.png")
|
||||
local c_red = Color(255,55,55)
|
||||
|
||||
local m_roof = Material("stormfox2/hud/tool/texture_roof.png")
|
||||
local m_ground = Material("stormfox2/hud/tool/texture_ground.png")
|
||||
|
||||
local snd_accept = Sound("buttons/button3.wav")
|
||||
local snd_deny = Sound("buttons/button2.wav")
|
||||
|
||||
if SERVER then
|
||||
function TOOL:SendFunc( tex, a )
|
||||
if not tex or not a then return end
|
||||
if type(tex) ~= "string" or type(a) ~= "number" then return end
|
||||
StormFox2.Map.ModifyMaterialType( tex, a )
|
||||
self:EmitSound(snd_accept)
|
||||
end
|
||||
else
|
||||
local function OpenOption( self, sTexture )
|
||||
local p = vgui.Create("DFrame")
|
||||
p:SetTitle(language.GetPhrase("spawnmenu.menu.edit"))
|
||||
p:SetSize( 50 * 3 + 10, 50 + 24)
|
||||
p:Center()
|
||||
p:MakePopup()
|
||||
-- Roof
|
||||
local roof = vgui.Create( "DImageButton", p )
|
||||
roof:SetSize( 50, 50)
|
||||
roof:SetImage("stormfox2/hud/tool/texture_roof.png")
|
||||
roof:Dock(LEFT)
|
||||
roof.DoClick = function()
|
||||
self.SendFunc( sTexture, 1 )
|
||||
p:Remove()
|
||||
end
|
||||
-- Roof
|
||||
local ground = vgui.Create( "DImageButton", p )
|
||||
ground:SetSize( 50, 50)
|
||||
ground:SetImage("stormfox2/hud/tool/texture_ground.png")
|
||||
ground:Dock(LEFT)
|
||||
ground.DoClick = function()
|
||||
self.SendFunc( sTexture, 0 )
|
||||
p:Remove()
|
||||
end
|
||||
-- Block
|
||||
local block = vgui.Create( "DImageButton", p )
|
||||
block:SetSize( 50, 50)
|
||||
block:SetImage("gui/cross.png")
|
||||
block:Dock(LEFT)
|
||||
block.DoClick = function()
|
||||
self.SendFunc( sTexture, -1 )
|
||||
p:Remove()
|
||||
end
|
||||
end
|
||||
function TOOL:LeftClick(tr)
|
||||
local tex = FindTexture(tr.HitTexture)
|
||||
if not tex then
|
||||
self:EmitSound(snd_deny)
|
||||
return
|
||||
end
|
||||
OpenOption( self, tex )
|
||||
end
|
||||
function TOOL:RightClick(tr)
|
||||
local tex = FindTexture(tr.HitTexture)
|
||||
if not tex then
|
||||
self:EmitSound(snd_deny)
|
||||
return
|
||||
end
|
||||
self.SendFunc( tex, -2, -2 )
|
||||
self:EmitSound(snd_accept)
|
||||
end
|
||||
end
|
||||
|
||||
function TOOL:ScreenRender( w, h )
|
||||
local tr = LocalPlayer():GetEyeTrace()
|
||||
local tex = FindTexture(tr.HitTexture)
|
||||
if tex then
|
||||
mat:SetTexture("$basetexture", tex)
|
||||
-- In case this material doesn't have a valid texture, it might be only a material.
|
||||
if not mat:GetTexture("$basetexture") then
|
||||
local m = Material(tex)
|
||||
local tryTex = StormFox2.Terrain.GetOriginalTexture(m) or m:GetTexture("$basetexture")
|
||||
if tryTex then
|
||||
mat:SetTexture("$basetexture", tryTex)
|
||||
end
|
||||
end
|
||||
local tData = SF_TEXTDATA[tex]
|
||||
surface.SetMaterial(mat)
|
||||
surface.SetDrawColor(color_white)
|
||||
surface.DrawTexturedRect(w * 0.1,h * 0.2,w * 0.8,h * 0.7)
|
||||
if tData and tData[1] then
|
||||
-- Roof type
|
||||
if tData[1] == -1 then
|
||||
surface.SetDrawColor(c_red)
|
||||
surface.SetMaterial(cross)
|
||||
surface.DrawTexturedRect(w * 0.15,h * 0.65,w * 0.2,h * 0.2)
|
||||
elseif tData[1] == 0 then
|
||||
surface.SetDrawColor(color_white)
|
||||
surface.SetMaterial(m_ground)
|
||||
surface.DrawTexturedRect(w * 0.15,h * 0.65,w * 0.2,h * 0.2)
|
||||
elseif tData[1] == 1 then
|
||||
surface.SetDrawColor(color_white)
|
||||
surface.SetMaterial(m_roof)
|
||||
surface.DrawTexturedRect(w * 0.15,h * 0.65,w * 0.2,h * 0.2)
|
||||
end
|
||||
end
|
||||
else
|
||||
surface.SetDrawColor(c_red)
|
||||
surface.SetMaterial(cross)
|
||||
surface.DrawTexturedRect(w * 0.1,h * 0.2,w * 0.8,h * 0.7)
|
||||
surface.SetDrawColor(color_white)
|
||||
end
|
||||
|
||||
surface.DrawOutlinedRect(w * 0.1,h * 0.2,w * 0.8,h * 0.7)
|
||||
end
|
||||
return TOOL
|
||||
171
lua/weapons/sf2_tool/shared.lua
Normal file
171
lua/weapons/sf2_tool/shared.lua
Normal file
@@ -0,0 +1,171 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
|
||||
SWEP.PrintName = "#sf_tool.name"
|
||||
SWEP.Author = "Nak"
|
||||
SWEP.Contact = ""
|
||||
SWEP.Purpose = "#sf_tool.desc"
|
||||
SWEP.Instructions = "#sf_tool.desc"
|
||||
|
||||
SWEP.ViewModel = "models/weapons/c_toolgun.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_toolgun.mdl"
|
||||
|
||||
SWEP.UseHands = true
|
||||
SWEP.Spawnable = true
|
||||
SWEP.AdminOnly = true
|
||||
|
||||
SWEP.Slot = 5
|
||||
SWEP.SlotPos = 5
|
||||
|
||||
util.PrecacheModel( SWEP.ViewModel )
|
||||
util.PrecacheModel( SWEP.WorldModel )
|
||||
|
||||
-- Tool meta
|
||||
local t_meta = {}
|
||||
-- Proxy allows to push entity functions within TOOL to SWEP. Its a hack, but I'm lazy.
|
||||
local proxy_key,proxy_self
|
||||
local function proxy(...)
|
||||
local self = proxy_self
|
||||
local func = self[proxy_key]
|
||||
local a = {...}
|
||||
-- In case first argument is "self", weplace it with SWEP
|
||||
if #a > 0 then
|
||||
if type(a[1]) == "table" and a[1].MetaName and a[1].MetaName == "sftool" then
|
||||
a[1] = self
|
||||
end
|
||||
end
|
||||
func(unpack(a))
|
||||
proxy_key = nil
|
||||
proxy_self = nil
|
||||
end
|
||||
t_meta.__index = function(self, key)
|
||||
if key == "_swep" then return end
|
||||
if IsValid(self._swep) and self._swep[key] then
|
||||
proxy_key = key
|
||||
proxy_self = self._swep
|
||||
return proxy
|
||||
end
|
||||
end
|
||||
function t_meta:GetSWEP()
|
||||
return self._swep
|
||||
end
|
||||
|
||||
-- Load tools
|
||||
SWEP.Tool = {}
|
||||
|
||||
for _,fil in ipairs(file.Find("weapons/sf2_tool/settings/*.lua","LUA")) do
|
||||
if SERVER then
|
||||
AddCSLuaFile("weapons/sf2_tool/settings/" .. fil)
|
||||
end
|
||||
local tool = (include("weapons/sf2_tool/settings/" .. fil))
|
||||
tool.MetaName = "sftool"
|
||||
setmetatable(tool, t_meta)
|
||||
table.insert(SWEP.Tool, tool)
|
||||
end
|
||||
|
||||
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.CanHolster = true
|
||||
SWEP.CanDeploy = true
|
||||
|
||||
function SWEP:SetupDataTables()
|
||||
self:NetworkVar( "Int", 0, "ToolID" )
|
||||
end
|
||||
|
||||
function SWEP:SetTool(num)
|
||||
self._toolobj = nil
|
||||
if not IsValid(self:GetOwner()) then return end
|
||||
if SERVER then
|
||||
self:SetToolID( num )
|
||||
end
|
||||
if num == 0 then return end -- Screen
|
||||
self._toolobj = table.Copy(self.Tool[num])
|
||||
self._toolobj._swep = self
|
||||
setmetatable(self._toolobj, t_meta)
|
||||
return self._toolobj
|
||||
end
|
||||
|
||||
function SWEP:GetTool()
|
||||
if not IsValid(self:GetOwner()) then return end -- No owner.
|
||||
if self._toolobj then
|
||||
return self._toolobj
|
||||
end
|
||||
local n = self:GetToolID()
|
||||
if n == 0 then return end
|
||||
self:SetTool(self:GetToolID())
|
||||
return self._toolobj
|
||||
end
|
||||
|
||||
function SWEP:DoShootEffect( tr, bFirstTimePredicted )
|
||||
self:SendWeaponAnim( ACT_VM_PRIMARYATTACK ) -- View model animation
|
||||
local Owner = self:GetOwner()
|
||||
Owner:SetAnimation( PLAYER_ATTACK1 )
|
||||
if ( not bFirstTimePredicted ) then return end
|
||||
local traceEffect = EffectData()
|
||||
traceEffect:SetOrigin( tr.HitPos + tr.HitNormal * 4 )
|
||||
traceEffect:SetStart( Owner:GetShootPos() )
|
||||
traceEffect:SetAttachment( 1 )
|
||||
traceEffect:SetEntity( self )
|
||||
traceEffect:SetScale(0.2)
|
||||
traceEffect:SetNormal( tr.HitNormal )
|
||||
util.Effect( "ToolTracer", traceEffect )
|
||||
util.Effect( "StunstickImpact", traceEffect )
|
||||
local tool = self:GetTool()
|
||||
if not tool or not tool.ShootSound then return end
|
||||
Owner:EmitSound(tool.ShootSound)
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
local function dofunction(ply, wep, tool, data)
|
||||
StormFox2.Msg(ply:GetName(),color_white," used",tool.RealName or "SF2 Tool.")
|
||||
tool.SendFunc( wep, unpack( data ) )
|
||||
wep:DoShootEffect(ply:GetEyeTrace(),IsFirstTimePredicted())
|
||||
end
|
||||
net.Receive(StormFox2.Net.Tool, function(len, ply)
|
||||
local wep = ply:GetActiveWeapon()
|
||||
if not IsValid(wep) then return end
|
||||
if wep:GetClass() ~= "sf2_tool" then return end
|
||||
local tool = wep:GetTool()
|
||||
if not tool or not tool.SendFunc then return end
|
||||
wep:HasAccessToSettings(dofunction, ply, wep, tool, net.ReadTable() )
|
||||
end)
|
||||
else
|
||||
function SWEP.SendFunc( ... )
|
||||
net.Start(StormFox2.Net.Tool)
|
||||
net.WriteTable({...})
|
||||
net.SendToServer()
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Initialize()
|
||||
self:SetHoldType( "revolver" )
|
||||
self.Primary = {
|
||||
ClipSize = -1,
|
||||
DefaultClip = -1,
|
||||
Automatic = false,
|
||||
Ammo = "none"
|
||||
}
|
||||
self.Secondary = {
|
||||
ClipSize = -1,
|
||||
DefaultClip = -1,
|
||||
Automatic = false,
|
||||
Ammo = "none"
|
||||
}
|
||||
end
|
||||
139
lua/weapons/swep_fiery_minigun.lua
Normal file
139
lua/weapons/swep_fiery_minigun.lua
Normal file
@@ -0,0 +1,139 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
SWEP.PrintName = "Fire Vulcan Minigu"
|
||||
SWEP.Category = "Jakub Baku"
|
||||
SWEP.Spawnable = false
|
||||
SWEP.AdminOnly = false
|
||||
|
||||
SWEP.ViewModel = "models/weapons/jakubbaku/v_mach_m249mini.mdl"
|
||||
SWEP.WorldModel = "models/weapons/w_shotgun.mdl"
|
||||
SWEP.UseHands = false
|
||||
|
||||
SWEP.Primary.Automatic = true
|
||||
|
||||
SWEP._IsFiring = false
|
||||
SWEP._FireSnd = nil
|
||||
|
||||
function SWEP:Initialize()
|
||||
self:SetWeaponHoldType("shotgun")
|
||||
end
|
||||
|
||||
function SWEP:OnStartFiring()
|
||||
self._FireSnd = CreateSound(self, "poopass/fireloop.wav")
|
||||
self._FireSnd:Play()
|
||||
end
|
||||
|
||||
function SWEP:OnStopFiring()
|
||||
if(!self._IsFiring) then return end
|
||||
self._FireSnd:Stop()
|
||||
self:EmitSound("poopass/winddown.wav")
|
||||
end
|
||||
|
||||
function SWEP:OnRemove()
|
||||
self:OnStopFiring()
|
||||
end
|
||||
|
||||
function SWEP:Holster()
|
||||
self:OnStopFiring()
|
||||
self._IsFiring = false
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:Think()
|
||||
local own = self:GetOwner()
|
||||
|
||||
if(!self._IsFiring && own:KeyDown(IN_ATTACK)) then
|
||||
self._IsFiring = true
|
||||
self:OnStartFiring()
|
||||
elseif(self._IsFiring && !own:KeyDown(IN_ATTACK)) then
|
||||
self:OnStopFiring()
|
||||
self._IsFiring = false
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
local own = self:GetOwner()
|
||||
local b = {
|
||||
Src = own:GetShootPos(),
|
||||
Dir = own:GetAimVector(),
|
||||
Damage = 8,
|
||||
Force = 6,
|
||||
Tracer = 1,
|
||||
TracerName = "eff_baku_burntcer",
|
||||
Attacker = own,
|
||||
Inflictor = self,
|
||||
Num = 1,
|
||||
Spread = Vector(1,1,0) * 0.02,
|
||||
}
|
||||
|
||||
if(SERVER) then
|
||||
b.Callback = function(_att, _tr, _dmg)
|
||||
local ent = _tr.Entity
|
||||
|
||||
if(!ent:IsPlayer()) then
|
||||
ent:Ignite(2)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
own:MuzzleFlash()
|
||||
own:SetAnimation( PLAYER_ATTACK1 )
|
||||
self:SendWeaponAnim( ACT_VM_PRIMARYATTACK )
|
||||
own:ViewPunch(AngleRand() * 0.002)
|
||||
|
||||
own:FireBullets(b)
|
||||
self:SetNextPrimaryFire(CurTime() + 0.05)
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:Reload()
|
||||
return false
|
||||
end
|
||||
|
||||
function SWEP:DoImpactEffect(tr, dmg)
|
||||
local ef = EffectData()
|
||||
ef:SetOrigin(tr.HitPos + tr.HitNormal * 2)
|
||||
ef:SetNormal(tr.HitNormal)
|
||||
ef:SetScale(1)
|
||||
|
||||
util.Effect("eff_baku_impactor", ef)
|
||||
return true
|
||||
end
|
||||
|
||||
function SWEP:FireAnimationEvent(pos, ang, event)
|
||||
if(event == 5001) then
|
||||
local eff = EffectData()
|
||||
eff:SetEntity(self.Owner:GetViewModel())
|
||||
eff:SetAttachment(1)
|
||||
eff:SetScale(0.5)
|
||||
|
||||
util.Effect("eff_baku_burnzzle", eff)
|
||||
return true
|
||||
elseif(event == 6001) then return true
|
||||
end
|
||||
end
|
||||
|
||||
if(SERVER)then
|
||||
|
||||
else
|
||||
function SWEP:CustomAmmoDisplay()
|
||||
self.AmmoDisplay = self.AmmoDisplay or {}
|
||||
self.AmmoDisplay.Draw = false
|
||||
|
||||
return self.AmmoDisplay
|
||||
end
|
||||
end
|
||||
1002
lua/weapons/tfa_base_template/shared.lua
Normal file
1002
lua/weapons/tfa_base_template/shared.lua
Normal file
File diff suppressed because it is too large
Load Diff
265
lua/weapons/tfa_bash_base.lua
Normal file
265
lua/weapons/tfa_bash_base.lua
Normal file
@@ -0,0 +1,265 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Copyright (c) 2018-2020 TFA Base Devs
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
if SERVER then
|
||||
AddCSLuaFile()
|
||||
end
|
||||
|
||||
DEFINE_BASECLASS("tfa_gun_base")
|
||||
SWEP.Secondary.BashDamage = 25
|
||||
SWEP.Secondary.BashSound = Sound("TFA.Bash")
|
||||
SWEP.Secondary.BashHitSound = Sound("TFA.BashWall")
|
||||
SWEP.Secondary.BashHitSound_Flesh = Sound("TFA.BashFlesh")
|
||||
SWEP.Secondary.BashLength = 54
|
||||
SWEP.Secondary.BashDelay = 0.2
|
||||
SWEP.Secondary.BashDamageType = DMG_SLASH
|
||||
SWEP.Secondary.BashEnd = nil --Override bash sequence length easier
|
||||
SWEP.Secondary.BashInterrupt = false --Do you need to be in a "ready" status to bash?
|
||||
SWEP.BashBase = true
|
||||
|
||||
function SWEP:BashForce(ent, force, pos, now)
|
||||
if not IsValid(ent) or not ent.GetPhysicsObjectNum then return end
|
||||
|
||||
if now then
|
||||
if ent.GetRagdollEntity then
|
||||
ent = ent:GetRagdollEntity() or ent
|
||||
end
|
||||
|
||||
local phys = ent:GetPhysicsObjectNum(0)
|
||||
|
||||
if IsValid(phys) then
|
||||
if ent:IsPlayer() or ent:IsNPC() then
|
||||
ent:SetVelocity( force * 0.1)
|
||||
phys:SetVelocity(phys:GetVelocity() + force * 0.1)
|
||||
else
|
||||
phys:ApplyForceOffset(force, pos)
|
||||
end
|
||||
end
|
||||
else
|
||||
timer.Simple(0, function()
|
||||
if IsValid(self) and self:OwnerIsValid() and IsValid(ent) then
|
||||
self:BashForce(ent, force, pos, true)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
local cv_doordestruction = GetConVar("sv_tfa_melee_doordestruction")
|
||||
|
||||
function SWEP:HandleDoor(slashtrace)
|
||||
if CLIENT or not IsValid(slashtrace.Entity) then return end
|
||||
|
||||
if not cv_doordestruction:GetBool() then return end
|
||||
|
||||
if slashtrace.Entity:GetClass() == "func_door_rotating" or slashtrace.Entity:GetClass() == "prop_door_rotating" then
|
||||
slashtrace.Entity:EmitSound("ambient/materials/door_hit1.wav", 100, math.random(80, 120))
|
||||
|
||||
local newname = "TFABash" .. self:EntIndex()
|
||||
self.PreBashName = self:GetName()
|
||||
self:SetName(newname)
|
||||
|
||||
slashtrace.Entity:SetKeyValue("Speed", "500")
|
||||
slashtrace.Entity:SetKeyValue("Open Direction", "Both directions")
|
||||
slashtrace.Entity:SetKeyValue("opendir", "0")
|
||||
slashtrace.Entity:Fire("unlock", "", .01)
|
||||
slashtrace.Entity:Fire("openawayfrom", newname, .01)
|
||||
|
||||
timer.Simple(0.02, function()
|
||||
if not IsValid(self) or self:GetName() ~= newname then return end
|
||||
|
||||
self:SetName(self.PreBashName)
|
||||
end)
|
||||
|
||||
timer.Simple(0.3, function()
|
||||
if IsValid(slashtrace.Entity) then
|
||||
slashtrace.Entity:SetKeyValue("Speed", "100")
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
local l_CT = CurTime
|
||||
local sp = game.SinglePlayer()
|
||||
|
||||
function SWEP:AltAttack()
|
||||
local time = l_CT()
|
||||
|
||||
if
|
||||
self:GetStatL("Secondary.CanBash") == false or
|
||||
not self:OwnerIsValid() or
|
||||
time < self:GetNextSecondaryFire()
|
||||
then return end
|
||||
|
||||
local stat = self:GetStatus()
|
||||
if not TFA.Enum.ReadyStatus[stat] and not self:GetStatL("Secondary.BashInterrupt") or
|
||||
stat == TFA.Enum.STATUS_BASHING and self:GetStatL("Secondary.BashInterrupt") then return end
|
||||
|
||||
if self:IsSafety() or self:GetHolding() then return end
|
||||
|
||||
local retVal = hook.Run("TFA_CanBash", self)
|
||||
if retVal == false then return end
|
||||
|
||||
local enabled, tanim, ttype = self:ChooseBashAnim()
|
||||
if not enabled then return end
|
||||
|
||||
hook.Run("TFA_Bash", self)
|
||||
|
||||
if self:GetOwner().Vox and IsFirstTimePredicted() then
|
||||
self:GetOwner():Vox("bash", 0)
|
||||
end
|
||||
|
||||
self:BashAnim()
|
||||
if sp and SERVER then self:CallOnClient("BashAnim", "") end
|
||||
|
||||
local bashend = self:GetStatL("Secondary.BashEnd")
|
||||
local nextTime = time + (bashend or self:GetActivityLength(tanim, false, ttype))
|
||||
|
||||
self:SetNextPrimaryFire(nextTime)
|
||||
self:SetNextSecondaryFire(nextTime)
|
||||
|
||||
self:EmitSoundNet(self:GetStatL("Secondary.BashSound"))
|
||||
|
||||
self:ScheduleStatus(TFA.Enum.STATUS_BASHING, self:GetStatL("Secondary.BashDelay"))
|
||||
|
||||
hook.Run("TFA_PostBash", self)
|
||||
end
|
||||
|
||||
function SWEP:BashAnim()
|
||||
if not IsFirstTimePredicted() then return end
|
||||
local ht = self.DefaultHoldType or self.HoldType
|
||||
local altanim = false
|
||||
|
||||
if ht == "ar2" or ht == "shotgun" or ht == "crossbow" or ht == "physgun" then
|
||||
altanim = true
|
||||
end
|
||||
|
||||
self:GetOwner():AnimRestartGesture(0, altanim and ACT_GMOD_GESTURE_MELEE_SHOVE_2HAND or ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE2, true)
|
||||
end
|
||||
|
||||
local ttime = -1
|
||||
|
||||
function SWEP:HandleBashAttack()
|
||||
local ply = self:GetOwner()
|
||||
local pos = ply:GetShootPos()
|
||||
local av = ply:GetAimVector()
|
||||
|
||||
local slash = {}
|
||||
slash.start = pos
|
||||
slash.endpos = pos + (av * self:GetStatL("Secondary.BashLength"))
|
||||
slash.filter = ply
|
||||
slash.mins = Vector(-10, -5, 0)
|
||||
slash.maxs = Vector(10, 5, 5)
|
||||
local slashtrace = util.TraceHull(slash)
|
||||
|
||||
local pain = self:GetStatL("Secondary.BashDamage")
|
||||
|
||||
if not slashtrace.Hit then return end
|
||||
self:HandleDoor(slashtrace)
|
||||
|
||||
if not (sp and CLIENT) then
|
||||
self:EmitSound(
|
||||
(slashtrace.MatType == MAT_FLESH or slashtrace.MatType == MAT_ALIENFLESH) and
|
||||
self:GetStatL("Secondary.BashHitSound_Flesh") or
|
||||
self:GetStatL("Secondary.BashHitSound"))
|
||||
end
|
||||
|
||||
if CLIENT then return end
|
||||
|
||||
local dmg = DamageInfo()
|
||||
dmg:SetAttacker(ply)
|
||||
dmg:SetInflictor(self)
|
||||
dmg:SetDamagePosition(pos)
|
||||
dmg:SetDamageForce(av * pain)
|
||||
dmg:SetDamage(pain)
|
||||
dmg:SetDamageType(self:GetStatL("Secondary.BashDamageType"))
|
||||
|
||||
if IsValid(slashtrace.Entity) and slashtrace.Entity.TakeDamageInfo then
|
||||
slashtrace.Entity:TakeDamageInfo(dmg)
|
||||
end
|
||||
|
||||
local ent = slashtrace.Entity
|
||||
if not IsValid(ent) or not ent.GetPhysicsObject then return end
|
||||
|
||||
local phys
|
||||
|
||||
if ent:IsRagdoll() then
|
||||
phys = ent:GetPhysicsObjectNum(slashtrace.PhysicsBone or 0)
|
||||
else
|
||||
phys = ent:GetPhysicsObject()
|
||||
end
|
||||
|
||||
if IsValid(phys) then
|
||||
if ent:IsPlayer() or ent:IsNPC() then
|
||||
ent:SetVelocity(av * self:GetStatL("Secondary.BashDamage") * 0.5)
|
||||
phys:SetVelocity(phys:GetVelocity() + av * self:GetStatL("Secondary.BashDamage") * 0.5)
|
||||
else
|
||||
phys:ApplyForceOffset(av * self:GetStatL("Secondary.BashDamage") * 0.5, slashtrace.HitPos)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:Think2(...)
|
||||
if self:GetStatus() == TFA.Enum.STATUS_BASHING and self:GetStatusEnd() < l_CT() then
|
||||
self:SetStatus(TFA.Enum.STATUS_BASHING_WAIT, self:GetNextSecondaryFire())
|
||||
|
||||
if IsFirstTimePredicted() then
|
||||
self:HandleBashAttack()
|
||||
end
|
||||
end
|
||||
|
||||
BaseClass.Think2(self, ...)
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
if not self:GetStatL("Secondary.IronSightsEnabled", false) then
|
||||
self:AltAttack()
|
||||
return
|
||||
end
|
||||
|
||||
BaseClass.SecondaryAttack(self)
|
||||
end
|
||||
|
||||
function SWEP:GetBashing()
|
||||
local stat = self:GetStatus()
|
||||
|
||||
if not self:VMIV() then
|
||||
return stat == TFA.Enum.STATUS_BASHING or stat == TFA.Enum.STATUS_BASHING_WAIT
|
||||
end
|
||||
|
||||
return (stat == TFA.Enum.STATUS_BASHING or stat == TFA.Enum.STATUS_BASHING_WAIT) and self.OwnerViewModel:GetCycle() > 0 and self.OwnerViewModel:GetCycle() < 0.65
|
||||
end
|
||||
|
||||
function SWEP:GetBashingStrict()
|
||||
local stat = self:GetStatus()
|
||||
return stat == TFA.Enum.STATUS_BASHING or stat == TFA.Enum.STATUS_BASHING_WAIT
|
||||
end
|
||||
|
||||
TFA.FillMissingMetaValues(SWEP)
|
||||
347
lua/weapons/tfa_bow_base.lua
Normal file
347
lua/weapons/tfa_bow_base.lua
Normal file
@@ -0,0 +1,347 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Copyright (c) 2018-2020 TFA Base Devs
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
if SERVER then
|
||||
AddCSLuaFile()
|
||||
end
|
||||
|
||||
DEFINE_BASECLASS("tfa_gun_base")
|
||||
--primary stats
|
||||
SWEP.Primary.Spread = 0.001
|
||||
SWEP.Primary.SpreadShake = 0.05 --when shaking
|
||||
SWEP.Primary.Velocity = 64 --velocity in m/s
|
||||
SWEP.Primary.Damage_Charge = {0.2, 1} --velocity/damage multiplier between min and max charge
|
||||
SWEP.Primary.Shake = true --enable shaking
|
||||
--options
|
||||
SWEP.Secondary.Cancel = true --enable cancelling
|
||||
--bow base shit
|
||||
SWEP.ChargeRate = 30 / 75 --1 is fully charged
|
||||
SWEP.ChargeThreshold = 0.75 --minimum charge percent to fire
|
||||
SWEP.ShakeTime = 5 --minimum time to start shaking
|
||||
SWEP.Secondary.IronSightsEnabled = false
|
||||
--tfa ballistics integration
|
||||
SWEP.UseBallistics = true
|
||||
SWEP.BulletModel = "models/weapons/w_tfa_arrow.mdl"
|
||||
SWEP.BulletTracer = ""
|
||||
|
||||
--animation
|
||||
SWEP.BowAnimations = {
|
||||
["shake"] = {
|
||||
["type"] = TFA.Enum.ANIMATION_SEQ, --Sequence or act
|
||||
["value"] = "tiredloop",
|
||||
["enabled"] = true --Manually force a sequence to be enabled
|
||||
},
|
||||
["shoot"] = {
|
||||
["type"] = TFA.Enum.ANIMATION_SEQ, --Sequence or act
|
||||
["value"] = "fire_1",
|
||||
["enabled"] = true --Manually force a sequence to be enabled
|
||||
},
|
||||
["cancel"] = {
|
||||
["type"] = TFA.Enum.ANIMATION_SEQ, --Sequence or act
|
||||
["value"] = "cancelarrow",
|
||||
["enabled"] = true --Manually force a sequence to be enabled
|
||||
},
|
||||
["draw"] = {
|
||||
["type"] = TFA.Enum.ANIMATION_SEQ, --Sequence or act
|
||||
["value"] = "drawarrow",
|
||||
["enabled"] = true --Manually force a sequence to be enabled
|
||||
}
|
||||
}
|
||||
|
||||
--["idle_charged"] = {["type"] = TFA.Enum.ANIMATION_SEQ, ["value"] = "idle_charged", ["enabled"] = true }
|
||||
function SWEP:SetupDataTables(...)
|
||||
BaseClass.SetupDataTables(self, ...)
|
||||
|
||||
self:NetworkVarTFA("Bool", "Shaking")
|
||||
self:NetworkVarTFA("Float", "Charge")
|
||||
end
|
||||
|
||||
function SWEP:GetChargeTime()
|
||||
return self:GetCharge() / self.ChargeRate
|
||||
end
|
||||
|
||||
function SWEP:ShouldShake()
|
||||
return self:GetChargeTime() >= self.ShakeTime
|
||||
end
|
||||
|
||||
function SWEP:Deploy(...)
|
||||
self:SetCharge(0)
|
||||
self:SetShaking(false)
|
||||
|
||||
return BaseClass.Deploy(self, ...)
|
||||
end
|
||||
|
||||
function SWEP:Charge(t)
|
||||
self:SetCharge(self:GetCharge() + self.ChargeRate * t)
|
||||
end
|
||||
|
||||
local sp = game.SinglePlayer()
|
||||
local ft
|
||||
|
||||
function SWEP:Think2(...)
|
||||
ft = FrameTime()
|
||||
|
||||
if self:GetStatus() == TFA.Enum.STATUS_BOW_CANCEL and self:GetStatusEnd() > CurTime() then
|
||||
self:SetCharge(0)
|
||||
self:SetShaking(false)
|
||||
end
|
||||
|
||||
if TFA.Enum.ReadyStatus[self:GetStatus()] and self:CanPrimaryAttack() then
|
||||
if self:GetOwner():KeyDown(IN_ATTACK2) and self:GetCharge() > self.ChargeThreshold then
|
||||
self:PlayAnimation(self.BowAnimations.cancel)
|
||||
self:ScheduleStatus(TFA.Enum.STATUS_BOW_CANCEL, self:GetActivityLength())
|
||||
elseif self:GetOwner():KeyDown(IN_ATTACK) then
|
||||
if self:GetCharge() <= 0 then
|
||||
self:PlayAnimation(self.BowAnimations.draw)
|
||||
self:SetCharge(0.01)
|
||||
self:SetShaking(false)
|
||||
end
|
||||
|
||||
self:Charge(ft)
|
||||
|
||||
if self:ShouldShake() and not self:GetShaking() then
|
||||
self:SetShaking(true)
|
||||
self:PlayAnimation(self.BowAnimations.shake)
|
||||
end
|
||||
else
|
||||
local c = self:GetCharge()
|
||||
|
||||
if c > self.ChargeThreshold then
|
||||
self:Shoot()
|
||||
elseif c > 0 then
|
||||
self:Charge(ft)
|
||||
end
|
||||
end
|
||||
elseif self:GetCharge() > 0 then
|
||||
if TFA.Enum.ReadyStatus[self:GetStatus()] then
|
||||
if self:GetCharge() > self.ChargeThreshold then
|
||||
self:PlayAnimation(self.BowAnimations.cancel)
|
||||
self:ScheduleStatus(TFA.Enum.STATUS_BOW_CANCEL, self:GetActivityLength())
|
||||
else
|
||||
self.Idle_ModeOld = self.Idle_Mode
|
||||
self:ClearStatCache("Idle_Mode")
|
||||
self.Idle_Mode = TFA.Enum.IDLE_BOTH
|
||||
self:ChooseIdleAnim()
|
||||
self.Idle_Mode = self.Idle_ModeOld
|
||||
end
|
||||
end
|
||||
|
||||
self:SetCharge(0)
|
||||
self:SetShaking(false)
|
||||
end
|
||||
|
||||
if IsFirstTimePredicted() or game.SinglePlayer() then
|
||||
self.Primary_TFA.SpreadBase = self.Primary_TFA.SpreadBase or self:GetStatL("Primary.Spread")
|
||||
local targ = self:GetShaking() and self.Primary_TFA.SpreadShake or self:GetStatL("Primary.SpreadBase")
|
||||
self.Primary_TFA.Spread = math.Approach(self.Primary_TFA.Spread, targ, (targ - self.Primary_TFA.Spread) * FrameTime() * 5)
|
||||
self:ClearStatCache("Primary.Spread")
|
||||
end
|
||||
|
||||
BaseClass.Think2(self, ...)
|
||||
end
|
||||
|
||||
function SWEP:Shoot()
|
||||
if self:GetStatL("Primary.Sound") and IsFirstTimePredicted() and not ( sp and CLIENT ) then
|
||||
if self:GetStatL("Primary.SilencedSound") and self:GetSilenced() then
|
||||
self:EmitSound(self:GetStatL("Primary.SilencedSound") )
|
||||
else
|
||||
self:EmitSound(self:GetStatL("Primary.Sound"))
|
||||
end
|
||||
end
|
||||
self:TakePrimaryAmmo(self:GetStatL("Primary.AmmoConsumption"))
|
||||
self:PlayAnimation(self.BowAnimations.shoot)
|
||||
self:ShootBulletInformation()
|
||||
self:SetCharge(0)
|
||||
self:SetShaking(false)
|
||||
self:ScheduleStatus(TFA.Enum.STATUS_BOW_SHOOT, 0.1)
|
||||
end
|
||||
|
||||
function SWEP:ChooseIdleAnim(...)
|
||||
if self:GetShaking() then
|
||||
return self:PlayAnimation(self.BowAnimations.shake)
|
||||
elseif self:GetCharge() > 0 and self.BowAnimations["idle_charged"] then
|
||||
return self:PlayAnimation(self.BowAnimations.idle_charged)
|
||||
end
|
||||
|
||||
return BaseClass.ChooseIdleAnim(self, ...)
|
||||
end
|
||||
|
||||
function SWEP:PrimaryAttack()
|
||||
end
|
||||
|
||||
function SWEP:SecondaryAttack()
|
||||
end
|
||||
|
||||
SWEP.MainBullet = {}
|
||||
SWEP.MainBullet.Spread = Vector()
|
||||
local ballistics_distcv = GetConVar("sv_tfa_ballistics_mindist")
|
||||
|
||||
local function BallisticFirebullet(ply, bul, ovr)
|
||||
local wep = ply:GetActiveWeapon()
|
||||
|
||||
if TFA.Ballistics and TFA.Ballistics:ShouldUse(wep) then
|
||||
if ballistics_distcv:GetInt() == -1 or ply:GetEyeTrace().HitPos:Distance(ply:GetShootPos()) > (ballistics_distcv:GetFloat() * TFA.Ballistics.UnitScale) then
|
||||
bul.SmokeParticle = bul.SmokeParticle or wep.BulletTracer or wep.TracerBallistic or wep.BallisticTracer or wep.BallisticsTracer
|
||||
|
||||
if ovr then
|
||||
TFA.Ballistics:FireBullets(wep, bul, angle_zero, true)
|
||||
else
|
||||
TFA.Ballistics:FireBullets(wep, bul)
|
||||
end
|
||||
else
|
||||
ply:FireBullets(bul)
|
||||
end
|
||||
else
|
||||
ply:FireBullets(bul)
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: ShootBulletInformation
|
||||
Syntax: self:ShootBulletInformation().
|
||||
Returns: Nothing.
|
||||
Notes: Used to generate a self.MainBullet table which is then sent to self:ShootBullet, and also to call shooteffects.
|
||||
Purpose: Bullet
|
||||
]]
|
||||
--
|
||||
local cv_dmg_mult = GetConVar("sv_tfa_damage_multiplier")
|
||||
local cv_dmg_mult_min = GetConVar("sv_tfa_damage_mult_min")
|
||||
local cv_dmg_mult_max = GetConVar("sv_tfa_damage_mult_max")
|
||||
local dmg, con, rec
|
||||
|
||||
function SWEP:ShootBulletInformation()
|
||||
self:UpdateConDamage()
|
||||
self.lastbul = nil
|
||||
self.lastbulnoric = false
|
||||
self.ConDamageMultiplier = cv_dmg_mult:GetFloat()
|
||||
if not IsFirstTimePredicted() then return end
|
||||
con, rec = self:CalculateConeRecoil()
|
||||
local tmpranddamage = math.Rand(cv_dmg_mult_min:GetFloat(), cv_dmg_mult_max:GetFloat())
|
||||
local basedamage = self.ConDamageMultiplier * self:GetStatL("Primary.Damage")
|
||||
dmg = basedamage * tmpranddamage
|
||||
local ns = self:GetStatL("Primary.NumShots")
|
||||
local clip = (self:GetStatL("Primary.ClipSize") == -1) and self:Ammo1() or self:Clip1()
|
||||
ns = math.Round(ns, math.min(clip / self:GetStatL("Primary.NumShots"), 1))
|
||||
self:ShootBullet(dmg, rec, ns, con)
|
||||
end
|
||||
|
||||
--[[
|
||||
Function Name: ShootBullet
|
||||
Syntax: self:ShootBullet(damage, recoil, number of bullets, spray cone, disable ricochet, override the generated self.MainBullet table with this value if you send it).
|
||||
Returns: Nothing.
|
||||
Notes: Used to shoot a self.MainBullet.
|
||||
Purpose: Bullet
|
||||
]]
|
||||
--
|
||||
local cv_forcemult = GetConVar("sv_tfa_force_multiplier")
|
||||
|
||||
local AttachArrowModel = function(a, b, c, wep)
|
||||
c:SetDamageType(bit.bor(DMG_NEVERGIB, DMG_CLUB))
|
||||
if CLIENT then return end
|
||||
if not IsValid(wep) then return end
|
||||
|
||||
if b.HitWorld and not (IsValid(b.Entity) and not b.Entity:IsWorld()) then
|
||||
local arrowstuck = ents.Create("tfbow_arrow_stuck")
|
||||
arrowstuck:SetModel(wep:GetStatL("BulletModel"))
|
||||
arrowstuck.gun = wep:GetClass()
|
||||
arrowstuck:SetPos(b.HitPos)
|
||||
arrowstuck:SetAngles(b.Normal:Angle())
|
||||
arrowstuck:Spawn()
|
||||
else
|
||||
local arrowstuck = ents.Create("tfbow_arrow_stuck_clientside")
|
||||
arrowstuck:SetModel(wep:GetStatL("BulletModel"))
|
||||
arrowstuck:SetModel(wep:GetStatL("BulletModel"))
|
||||
arrowstuck.gun = wep:GetClass()
|
||||
arrowstuck:SetPos(b.HitPos)
|
||||
arrowstuck:SetAngles(b.Normal:Angle())
|
||||
arrowstuck.targent = b.Entity
|
||||
arrowstuck.targphysbone = b.PhysicsBone or -1
|
||||
arrowstuck:Spawn()
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:AutoDetectForce()
|
||||
if self:GetStatRawL("Primary.Force") == -1 or not self:GetStatRawL("Primary.Force") then
|
||||
self:SetStatRawL("Primary.Force", self:GetStatRawL("Force") or self:GetStatRawL("Primary.Damage") / 6 * math.sqrt(self:GetStatRawL("Primary.KickUp") + self:GetStatRawL("Primary.KickDown") + self:GetStatRawL("Primary.KickHorizontal")))
|
||||
end
|
||||
end
|
||||
|
||||
function SWEP:ShootBullet(damage, recoil, num_bullets, aimcone, disablericochet, bulletoverride)
|
||||
if not IsFirstTimePredicted() and not game.SinglePlayer() then return end
|
||||
local chargeTable = self:GetStatL("Primary.Damage_Charge")
|
||||
local mult = Lerp(math.Clamp(self:GetCharge() - self.ChargeThreshold, 0, 1 - self.ChargeThreshold) / (1 - self.ChargeThreshold), chargeTable[1], chargeTable[2])
|
||||
local unitScale = TFA.Ballistics.UnitScale or TFA.UnitScale or 40
|
||||
num_bullets = num_bullets or 1
|
||||
aimcone = aimcone or 0
|
||||
self.MainBullet.Attacker = self:GetOwner()
|
||||
self.MainBullet.Inflictor = self
|
||||
self.MainBullet.Num = num_bullets
|
||||
self.MainBullet.Src = self:GetOwner():GetShootPos()
|
||||
self.MainBullet.Dir = self:GetOwner():EyeAngles():Forward()
|
||||
self.MainBullet.HullSize = 0
|
||||
self.MainBullet.Spread.x = aimcone
|
||||
self.MainBullet.Spread.y = aimcone
|
||||
|
||||
if self.TracerPCF then
|
||||
self.MainBullet.Tracer = 0
|
||||
else
|
||||
self.MainBullet.Tracer = self:GetStatL("TracerCount") or 3
|
||||
end
|
||||
|
||||
self.MainBullet.PenetrationCount = 0
|
||||
self.MainBullet.AmmoType = self:GetPrimaryAmmoType()
|
||||
self.MainBullet.Force = self:GetStatL("Primary.Force") * cv_forcemult:GetFloat() * self:GetAmmoForceMultiplier() * mult
|
||||
self.MainBullet.Damage = damage * mult
|
||||
self.MainBullet.HasAppliedRange = false
|
||||
self.MainBullet.Velocity = self:GetStatL("Primary.Velocity") * mult * unitScale
|
||||
|
||||
self.MainBullet.Callback = function(a, b, c)
|
||||
if IsValid(self) then
|
||||
c:SetInflictor(self)
|
||||
end
|
||||
|
||||
if self.MainBullet.Callback2 then
|
||||
self.MainBullet.Callback2(a, b, c)
|
||||
end
|
||||
|
||||
self:CallAttFunc("CustomBulletCallback", a, b, c)
|
||||
|
||||
if SERVER and IsValid(a) and a:IsPlayer() and IsValid(b.Entity) and (b.Entity:IsPlayer() or b.Entity:IsNPC() or type(b.Entity) == "NextBot") then
|
||||
self:SendHitMarker(a, b, c)
|
||||
end
|
||||
|
||||
AttachArrowModel(a, b, c, self)
|
||||
end
|
||||
|
||||
BallisticFirebullet(self:GetOwner(), self.MainBullet)
|
||||
end
|
||||
|
||||
TFA.FillMissingMetaValues(SWEP)
|
||||
60
lua/weapons/tfa_gun_base/cl_init.lua
Normal file
60
lua/weapons/tfa_gun_base/cl_init.lua
Normal file
@@ -0,0 +1,60 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Copyright (c) 2018-2020 TFA Base Devs
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
include("shared.lua")
|
||||
|
||||
include("common/ai_translations.lua")
|
||||
include("common/anims.lua")
|
||||
include("common/autodetection.lua")
|
||||
include("common/utils.lua")
|
||||
include("common/stat.lua")
|
||||
include("common/attachments.lua")
|
||||
include("common/bullet.lua")
|
||||
include("common/effects.lua")
|
||||
include("common/calc.lua")
|
||||
include("common/akimbo.lua")
|
||||
include("common/events.lua")
|
||||
include("common/nzombies.lua")
|
||||
include("common/ttt.lua")
|
||||
include("common/viewmodel.lua")
|
||||
include("common/skins.lua")
|
||||
|
||||
include("client/effects.lua")
|
||||
include("client/viewbob.lua")
|
||||
include("client/viewmodel.lua")
|
||||
include("client/bobcode.lua")
|
||||
include("client/hud.lua")
|
||||
include("client/mods.lua")
|
||||
include("client/laser.lua")
|
||||
include("client/fov.lua")
|
||||
include("client/flashlight.lua")
|
||||
|
||||
TFA.FillMissingMetaValues(SWEP)
|
||||
247
lua/weapons/tfa_gun_base/client/bobcode.lua
Normal file
247
lua/weapons/tfa_gun_base/client/bobcode.lua
Normal file
@@ -0,0 +1,247 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
-- Copyright (c) 2018-2020 TFA Base Devs
|
||||
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
-- of this software and associated documentation files (the "Software"), to deal
|
||||
-- in the Software without restriction, including without limitation the rights
|
||||
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
-- copies of the Software, and to permit persons to whom the Software is
|
||||
-- furnished to do so, subject to the following conditions:
|
||||
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
|
||||
local vector_origin = Vector()
|
||||
|
||||
SWEP.ti = 0
|
||||
SWEP.LastCalcBob = 0
|
||||
SWEP.tiView = 0
|
||||
SWEP.LastCalcViewBob = 0
|
||||
local TAU = math.pi * 2
|
||||
local rateScaleFac = 2
|
||||
local rate_up = 6 * rateScaleFac
|
||||
local scale_up = 0.5
|
||||
local rate_right = 3 * rateScaleFac
|
||||
local scale_right = -0.5
|
||||
local rate_forward_view = 3 * rateScaleFac
|
||||
local scale_forward_view = 0.35
|
||||
local rate_right_view = 3 * rateScaleFac
|
||||
local scale_right_view = -1
|
||||
local rate_p = 6 * rateScaleFac
|
||||
local scale_p = 3
|
||||
local rate_y = 3 * rateScaleFac
|
||||
local scale_y = 6
|
||||
local rate_r = 3 * rateScaleFac
|
||||
local scale_r = -6
|
||||
local pist_rate = 3 * rateScaleFac
|
||||
local pist_scale = 9
|
||||
local rate_clamp = 2 * rateScaleFac
|
||||
local walkIntensitySmooth, breathIntensitySmooth = 0, 0
|
||||
local walkRate = 160 / 60 * TAU / 1.085 / 2 * rateScaleFac --steps are at 160bpm at default velocity, then divide that by 60 for per-second, multiply by TAU for trig, divided by default walk rate
|
||||
local walkVec = Vector()
|
||||
local ownerVelocity, ownerVelocityMod = Vector(), Vector()
|
||||
local zVelocity, zVelocitySmooth = 0, 0
|
||||
local xVelocity, xVelocitySmooth, rightVec = 0, 0, Vector()
|
||||
local flatVec = Vector(1, 1, 0)
|
||||
local WalkPos = Vector()
|
||||
local WalkPosLagged = Vector()
|
||||
local gunbob_intensity_cvar = GetConVar("cl_tfa_gunbob_intensity")
|
||||
local gunbob_intensity = 0
|
||||
SWEP.VMOffsetWalk = Vector(0.5, -0.5, -0.5)
|
||||
SWEP.footstepTotal = 0
|
||||
SWEP.footstepTotalTarget = 0
|
||||
local upVec, riVec, fwVec = Vector(0, 0, 1), Vector(1, 0, 0), Vector(0, 1, 0)
|
||||
|
||||
local function l_Lerp(t, a, b)
|
||||
if t <= 0 then return a end
|
||||
if t >= 1 then return b end
|
||||
return a + (b - a) * t
|
||||
end
|
||||
|
||||
function SWEP:WalkBob(pos, ang, breathIntensity, walkIntensity, rate, ftv)
|
||||
local self2 = self:GetTable()
|
||||
if not self2.OwnerIsValid(self) then return end
|
||||
rate = math.min(rate or 0.5, rate_clamp)
|
||||
gunbob_intensity = gunbob_intensity_cvar:GetFloat()
|
||||
|
||||
local ea = self:GetOwner():EyeAngles()
|
||||
local up = ang:Up()
|
||||
local ri = ang:Right()
|
||||
local fw = ang:Forward()
|
||||
local upLocal = upVec
|
||||
local riLocal = riVec
|
||||
local fwLocal = fwVec
|
||||
local delta = ftv
|
||||
local flip_v = self2.ViewModelFlip and -1 or 1
|
||||
--delta = delta * game.GetTimeScale()
|
||||
--self2.LastCalcBob = SysTime()
|
||||
self2.bobRateCached = rate
|
||||
self2.ti = self2.ti + delta * rate
|
||||
|
||||
if self2.SprintStyle == nil then
|
||||
if self:GetStatL("SprintViewModelAngle") and self:GetStatL("SprintViewModelAngle").x > 5 then
|
||||
self2.SprintStyle = 1
|
||||
else
|
||||
self2.SprintStyle = 0
|
||||
end
|
||||
end
|
||||
|
||||
--preceding calcs
|
||||
walkIntensitySmooth = l_Lerp(delta * 10 * rateScaleFac, walkIntensitySmooth, walkIntensity)
|
||||
breathIntensitySmooth = l_Lerp(delta * 10 * rateScaleFac, breathIntensitySmooth, breathIntensity)
|
||||
walkVec = LerpVector(walkIntensitySmooth, vector_origin, self2.VMOffsetWalk)
|
||||
ownerVelocity = self:GetOwner():GetVelocity()
|
||||
zVelocity = ownerVelocity.z
|
||||
zVelocitySmooth = l_Lerp(delta * 7 * rateScaleFac, zVelocitySmooth, zVelocity)
|
||||
ownerVelocityMod = ownerVelocity * flatVec
|
||||
ownerVelocityMod:Normalize()
|
||||
rightVec = ea:Right() * flatVec
|
||||
rightVec:Normalize()
|
||||
xVelocity = ownerVelocity:Length2D() * ownerVelocityMod:Dot(rightVec)
|
||||
xVelocitySmooth = l_Lerp(delta * 5 * rateScaleFac, xVelocitySmooth, xVelocity)
|
||||
|
||||
--multipliers
|
||||
breathIntensity = breathIntensitySmooth * gunbob_intensity * 1.5
|
||||
walkIntensity = walkIntensitySmooth * gunbob_intensity * 1.5
|
||||
|
||||
--breathing / walking while ADS
|
||||
local breatheMult2 = math.Clamp((self2.IronSightsProgressUnpredicted2 or self:GetIronSightsProgress()), 0, 1)
|
||||
--local breatheMult2 = 0
|
||||
local breatheMult1 = 1 - breatheMult2
|
||||
--local breatheMult1 = 1
|
||||
|
||||
pos:Add(riLocal * (math.sin(self2.ti * walkRate) - math.cos(self2.ti * walkRate)) * flip_v * breathIntensity * 0.2 * breatheMult1)
|
||||
pos:Add(upLocal * math.sin(self2.ti * walkRate) * breathIntensity * 0.5 * breatheMult1)
|
||||
|
||||
pos:Add(riLocal * math.cos(self2.ti * walkRate / 2) * flip_v * breathIntensity * 0.6 * breatheMult2)
|
||||
pos:Add(upLocal * math.sin(self2.ti * walkRate) * breathIntensity * 0.3 * breatheMult2)
|
||||
|
||||
--walk anims, danny method because i just can't
|
||||
self2.walkTI = (self2.walkTI or 0) + delta * 160 / 60 * self:GetOwner():GetVelocity():Length2D() / self:GetOwner():GetWalkSpeed()
|
||||
WalkPos.x = l_Lerp(delta * 5 * rateScaleFac, WalkPos.x, -math.sin(self2.ti * walkRate * 0.5) * gunbob_intensity * walkIntensity)
|
||||
WalkPos.y = l_Lerp(delta * 5 * rateScaleFac, WalkPos.y, math.sin(self2.ti * walkRate) / 1.5 * gunbob_intensity * walkIntensity)
|
||||
WalkPosLagged.x = l_Lerp(delta * 5 * rateScaleFac, WalkPosLagged.x, -math.sin((self2.ti * walkRate * 0.5) + math.pi / 3) * gunbob_intensity * walkIntensity)
|
||||
WalkPosLagged.y = l_Lerp(delta * 5 * rateScaleFac, WalkPosLagged.y, math.sin(self2.ti * walkRate + math.pi / 3) / 1.5 * gunbob_intensity * walkIntensity)
|
||||
pos:Add(WalkPos.x * 0.33 * riLocal)
|
||||
pos:Add(WalkPos.y * 0.25 * upLocal)
|
||||
ang:RotateAroundAxis(ri, -WalkPosLagged.y)
|
||||
ang:RotateAroundAxis(up, WalkPosLagged.x)
|
||||
ang:RotateAroundAxis(fw, WalkPos.x)
|
||||
|
||||
--constant offset
|
||||
pos:Add(riLocal * walkVec.x * flip_v)
|
||||
pos:Add(fwLocal * walkVec.y)
|
||||
pos:Add(upLocal * walkVec.z)
|
||||
|
||||
--jumping
|
||||
local trigX = -math.Clamp(zVelocitySmooth / 200, -1, 1) * math.pi / 2
|
||||
local jumpIntensity = (3 + math.Clamp(math.abs(zVelocitySmooth) - 100, 0, 200) / 200 * 4) * (1 - (self2.IronSightsProgressUnpredicted or self:GetIronSightsProgress()) * 0.8)
|
||||
pos:Add(ri * math.sin(trigX) * scale_r * 0.1 * jumpIntensity * flip_v * 0.4)
|
||||
pos:Add(-up * math.sin(trigX) * scale_r * 0.1 * jumpIntensity * 0.4)
|
||||
ang:RotateAroundAxis(ang:Forward(), math.sin(trigX) * scale_r * jumpIntensity * flip_v * 0.4)
|
||||
|
||||
--rolling with horizontal motion
|
||||
local xVelocityClamped = xVelocitySmooth
|
||||
|
||||
if math.abs(xVelocityClamped) > 200 then
|
||||
local sign = (xVelocityClamped < 0) and -1 or 1
|
||||
xVelocityClamped = (math.sqrt((math.abs(xVelocityClamped) - 200) / 50) * 50 + 200) * sign
|
||||
end
|
||||
|
||||
ang:RotateAroundAxis(ang:Forward(), xVelocityClamped * 0.04 * flip_v)
|
||||
|
||||
return pos, ang
|
||||
end
|
||||
|
||||
function SWEP:SprintBob(pos, ang, intensity, origPos, origAng)
|
||||
local self2 = self:GetTable()
|
||||
if not IsValid(self:GetOwner()) or not gunbob_intensity then return pos, ang end
|
||||
local flip_v = self2.ViewModelFlip and -1 or 1
|
||||
|
||||
local eyeAngles = self:GetOwner():EyeAngles()
|
||||
local localUp = ang:Up()
|
||||
local localRight = ang:Right()
|
||||
local localForward = ang:Forward()
|
||||
|
||||
local playerUp = eyeAngles:Up()
|
||||
local playerRight = eyeAngles:Right()
|
||||
local playerForward = eyeAngles:Forward()
|
||||
|
||||
intensity = intensity * gunbob_intensity * 1.5
|
||||
gunbob_intensity = gunbob_intensity_cvar:GetFloat()
|
||||
|
||||
if intensity > 0.005 then
|
||||
if self2.SprintStyle == 1 then
|
||||
local intensity3 = math.max(intensity - 0.3, 0) / (1 - 0.3)
|
||||
ang:RotateAroundAxis(ang:Up(), math.sin(self2.ti * pist_rate) * pist_scale * intensity3 * 0.33 * 0.75)
|
||||
ang:RotateAroundAxis(ang:Forward(), math.sin(self2.ti * pist_rate) * pist_scale * intensity3 * 0.33 * -0.25)
|
||||
pos:Add(ang:Forward() * math.sin(self2.ti * pist_rate * 2 + math.pi) * pist_scale * -0.1 * intensity3 * 0.4)
|
||||
pos:Add(ang:Right() * math.sin(self2.ti * pist_rate) * pist_scale * 0.15 * intensity3 * 0.33 * 0.2)
|
||||
else
|
||||
pos:Add(localUp * math.sin(self2.ti * rate_up + math.pi) * scale_up * intensity * 0.33)
|
||||
pos:Add(localRight * math.sin(self2.ti * rate_right) * scale_right * intensity * flip_v * 0.33)
|
||||
pos:Add(eyeAngles:Forward() * math.max(math.sin(self2.ti * rate_forward_view), 0) * scale_forward_view * intensity * 0.33)
|
||||
pos:Add(eyeAngles:Right() * math.sin(self2.ti * rate_right_view) * scale_right_view * intensity * flip_v * 0.33)
|
||||
|
||||
ang:RotateAroundAxis(localRight, math.sin(self2.ti * rate_p + math.pi) * scale_p * intensity * 0.33)
|
||||
pos:Add(-localUp * math.sin(self2.ti * rate_p + math.pi) * scale_p * 0.1 * intensity * 0.33)
|
||||
|
||||
ang:RotateAroundAxis(localUp, math.sin(self2.ti * rate_y) * scale_y * intensity * flip_v * 0.33)
|
||||
pos:Add(localRight * math.sin(self2.ti * rate_y) * scale_y * 0.1 * intensity * flip_v * 0.33)
|
||||
|
||||
ang:RotateAroundAxis(localForward, math.sin(self2.ti * rate_r) * scale_r * intensity * flip_v * 0.33)
|
||||
pos:Add(localRight * math.sin(self2.ti * rate_r) * scale_r * 0.05 * intensity * flip_v * 0.33)
|
||||
pos:Add(localUp * math.sin(self2.ti * rate_r) * scale_r * 0.1 * intensity * 0.33)
|
||||
end
|
||||
end
|
||||
|
||||
return pos, ang
|
||||
end
|
||||
|
||||
local cv_customgunbob = GetConVar("cl_tfa_gunbob_custom")
|
||||
local fac, bscale
|
||||
|
||||
function SWEP:UpdateEngineBob()
|
||||
local self2 = self:GetTable()
|
||||
|
||||
if cv_customgunbob:GetBool() then
|
||||
self2.BobScale = 0
|
||||
self2.SwayScale = 0
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local isp = self2.IronSightsProgressUnpredicted or self:GetIronSightsProgress()
|
||||
local wpr = self2.WalkProgressUnpredicted or self:GetWalkProgress()
|
||||
local spr = self:GetSprintProgress()
|
||||
|
||||
fac = gunbob_intensity_cvar:GetFloat() * ((1 - isp) * 0.85 + 0.15)
|
||||
bscale = fac
|
||||
|
||||
if spr > 0.005 then
|
||||
bscale = bscale * l_Lerp(spr, 1, self2.SprintBobMult)
|
||||
elseif wpr > 0.005 then
|
||||
bscale = bscale * l_Lerp(wpr, 1, l_Lerp(isp, self2.WalkBobMult, self2.WalkBobMult_Iron or self2.WalkBobMult))
|
||||
end
|
||||
|
||||
self2.BobScale = bscale
|
||||
self2.SwayScale = fac
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user