This commit is contained in:
lifestorm
2024-08-04 22:55:00 +03:00
parent 0e770b2b49
commit 94063e4369
7342 changed files with 1718932 additions and 14 deletions

View 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

View 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

File diff suppressed because it is too large Load Diff

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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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", {})

View 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

View 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

View 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

View 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

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

View 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

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

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

View 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

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

View 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

View 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

View 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

View 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

View 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

View 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

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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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

View 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

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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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*/

View 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

View 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

View 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

View 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

View 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

View 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

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

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

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

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

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

View 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