add sborka

This commit is contained in:
2026-03-31 10:27:04 +03:00
commit f5e5f56c84
2345 changed files with 382127 additions and 0 deletions

View File

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

View File

@@ -0,0 +1,467 @@
AddCSLuaFile("shared.lua")
include("shared.lua")
util.AddNetworkString("MuR_DroneCam_Grenade")
util.AddNetworkString("MuR_DroneLost_Grenade")
util.AddNetworkString("MuR_GrenadeDropped")
util.AddNetworkString("MuR_ThermalState")
util.AddNetworkString("MuR_DroneEmergency")
local rotorSounds = {
"ambient/machines/spin_loop.wav",
"ambient/machines/machine1_hit1.wav"
}
local damageSounds = {
"physics/metal/metal_box_impact_bullet1.wav",
"physics/metal/metal_box_impact_bullet2.wav",
"physics/metal/metal_box_impact_bullet3.wav",
"physics/metal/metal_computer_impact_bullet1.wav",
"physics/metal/metal_computer_impact_bullet2.wav"
}
local startupSounds = {
"buttons/button9.wav",
"buttons/button17.wav"
}
function ENT:Initialize()
self:SetModel("models/murdered/weapons/drone_ex.mdl")
self:ResetSequence("idle")
self:SetHealth(self.HealthCount)
self:SetGravity(0)
self.Velo = {x = 0, y = 0, z = 0}
self:SetSolid(SOLID_VPHYSICS)
self:PhysicsInit(SOLID_VPHYSICS)
self.MultSpeed = 700
self.MaxSpeed = 800
self.BoostSpeed = 1250
self.MaxPitch = 18
self.MaxRoll = 22
self.LinearDrag = 0.04
self.GrenadeDropDelay = 0
self.GrenadesLeft = 3
self.TakeDamageWall = 0
self.DeltaTime = 0
self.LastBoostSound = 0
self.LastWindSound = 0
self:SetNW2Float('RemoveTime', CurTime() + self.BatteryCount)
self:SetNW2Int("Grenades", self.GrenadesLeft)
self:EmitSound(startupSounds[math.random(#startupSounds)], 60, 100, 0.5)
if CreateSound then
self.RotorSound = CreateSound(self, rotorSounds[1])
if self.RotorSound then
self.RotorSound:PlayEx(0.2, 80)
end
self.WindSound = CreateSound(self, "ambient/wind/wind_snippet2.wav")
if self.WindSound then
self.WindSound:PlayEx(0, 100)
end
end
local ply = self:GetCreator()
if IsValid(ply) then
local forward = ply:GetForward()
forward.z = 0
forward = forward:GetNormalized()
local spawnDist = 80
local spawnHeight = 40
local spawnPos = ply:GetPos() + forward * spawnDist + Vector(0, 0, spawnHeight)
local tr = util.TraceHull({
start = spawnPos,
endpos = spawnPos,
mins = Vector(-20, -20, -20),
maxs = Vector(20, 20, 20),
filter = {ply, self}
})
if tr.Hit then
spawnPos = spawnPos + forward * 60
end
local ground = util.TraceLine({
start = spawnPos,
endpos = spawnPos - Vector(0, 0, 5000),
filter = self
})
if spawnPos.z < ground.HitPos.z + 30 then
spawnPos.z = ground.HitPos.z + 30
end
self:SetPos(spawnPos)
self:SetAngles(Angle(0, ply:EyeAngles().y, 0))
end
timer.Simple(0.1, function()
if not IsValid(self) then return end
local ply = self:GetCreator()
if not IsValid(ply) then return end
ply.ControlDrone = self
net.Start("MuR_DroneCam_Grenade")
net.WriteEntity(self)
net.Send(ply)
end)
end
function ENT:OnRemove()
if self.RotorSound then
self.RotorSound:Stop()
end
if self.WindSound then
self.WindSound:Stop()
end
self:StopSound("ambient/machines/spin_loop.wav")
self:StopSound("ambient/wind/wind_snippet2.wav")
self:StopSound("vehicles/airboat/fan_blade_fullthrottle_loop1.wav")
end
function ENT:GetForwardAbs()
local ang = self:GetAngles()
ang.x = 0
ang.z = 0
return ang:Forward()
end
function ENT:GetRightAbs()
local ang = self:GetAngles()
ang.x = 0
ang.z = 0
return ang:Right()
end
function ENT:GetUpAbs()
local ang = self:GetAngles()
ang.x = 0
ang.z = 0
return ang:Up()
end
function ENT:Think()
if self.EmergencyKill then
local phys = self:GetPhysicsObject()
if IsValid(phys) then
phys:EnableMotion(false)
end
if CurTime() >= (self.EmergencyKillTime or 0) then
self:Explode()
return true
end
end
if self:GetNWBool("Jammed") then
if not self.JamKillTime then
self.JamKillTime = CurTime() + 5
end
if CurTime() >= self.JamKillTime then
local effect = EffectData()
effect:SetOrigin(self:GetPos())
util.Effect("Explosion", effect)
self:Remove()
return true
end
-- ВАЖНО: НЕ ДЕЛАТЬ return здесь!
-- Просто продолжаем Think(), чтобы таймер мог дойти до взрыва
else
-- вышел из зоны — сбрасываем таймер
self.JamKillTime = nil
end
local ply = self:GetCreator()
if not IsValid(ply) then
self:Remove()
else
local phys = self:GetPhysicsObject()
local mu = self.MultSpeed
local ms = self.MaxSpeed
local deltatime = self.DeltaTime
local vel = phys:GetVelocity()
local pos = self:GetPos()
local ang = ply:EyeAngles().y
local sang = Angle(0, ang, 0)
ply:SetActiveWeapon(nil)
local trace = {start = self:GetPos(), endpos = self:GetPos(), filter = self}
local tr = util.TraceEntity(trace, self)
-- Кнопка G — экстренный выход
if not self.EmergencyKill and ply:KeyDown(IN_GRENADE1) then
self.EmergencyKill = true
self.EmergencyKillTime = CurTime() + 3 -- 3 секунды до взрыва
-- отправляем время на клиент для HUD
self:SetNWFloat("EmergencyCountdown", self.EmergencyKillTime)
self:EmitSound("buttons/button17.wav", 75, 100, 0.6)
end
-- ускоренный расход батареи при включённом теплаке
if self:GetNW2Bool("ThermalActive") then
local drainMul = 2 -- во сколько раз быстрее жрёт
local newRemove = self:GetNW2Float("RemoveTime") - FrameTime() * (drainMul - 1)
self:SetNW2Float("RemoveTime", newRemove)
end
if self:GetNW2Bool('Boost') then
local fwd = self:GetForward()
phys:SetVelocityInstantaneous(fwd * self.Velo.x)
else
if tr.Hit then
phys:SetVelocityInstantaneous((self:GetForwardAbs() * self.Velo.x + self:GetRightAbs() * self.Velo.y + self:GetUpAbs() * self.Velo.z) / 2)
if self.TakeDamageWall < CurTime() then
self:TakeDamage(1)
self.TakeDamageWall = CurTime() + 0.2
end
else
phys:SetVelocityInstantaneous(self:GetForwardAbs() * self.Velo.x + self:GetRightAbs() * self.Velo.y + self:GetUpAbs() * self.Velo.z + Vector(0,0,15))
end
end
local ratioX = math.Clamp(self.Velo.x / ms, -1, 1)
local ratioY = math.Clamp(self.Velo.y / ms, -1, 1)
local targetPitch = ratioX * self.MaxPitch
local targetRoll = ratioY * self.MaxRoll
sang = Angle(targetPitch, ang, targetRoll)
local b = {}
b.secondstoarrive = 1
b.pos = self:GetPos()
b.angle = sang
b.maxangular = 120
b.maxangulardamp = 50
b.maxspeed = 1000
b.maxspeeddamp = 150
b.dampfactor = 0.4
b.teleportdistance = 0
b.deltatime = CurTime() - self.DeltaTime
phys:ComputeShadowControl(b)
local tick = FrameTime()
if ply:KeyDown(IN_FORWARD) then
self.Velo.x = math.Clamp(self.Velo.x + tick * mu, -ms, ms)
elseif ply:KeyDown(IN_BACK) then
self.Velo.x = math.Clamp(self.Velo.x - tick * mu, -ms, ms)
end
if ply:KeyDown(IN_MOVELEFT) then
self.Velo.y = math.Clamp(self.Velo.y - tick * mu, -ms, ms)
elseif ply:KeyDown(IN_MOVERIGHT) then
self.Velo.y = math.Clamp(self.Velo.y + tick * mu, -ms, ms)
end
if ply:KeyDown(IN_DUCK) then
self.Velo.z = math.Clamp(self.Velo.z - tick * mu, -ms, ms)
elseif ply:KeyDown(IN_SPEED) then
self.Velo.z = math.Clamp(self.Velo.z + tick * mu, -ms, ms)
end
local drag = 1 - math.Clamp(self.LinearDrag * tick, 0, 0.2)
self.Velo.x = self.Velo.x * drag
self.Velo.y = self.Velo.y * drag
self.Velo.z = self.Velo.z * (0.98 * drag)
if not ply:KeyDown(IN_FORWARD) and not ply:KeyDown(IN_BACK) and not self:GetNW2Bool('Boost') then
if self.Velo.x > 5 or self.Velo.x < -5 then
if self.Velo.x > 0 then
self.Velo.x = math.Clamp(self.Velo.x - tick * mu, -ms, ms)
elseif self.Velo.x < 0 then
self.Velo.x = math.Clamp(self.Velo.x + tick * mu, -ms, ms)
end
else
self.Velo.x = 0
end
end
if not ply:KeyDown(IN_SPEED) and not ply:KeyDown(IN_DUCK) then
if self.Velo.z > 5 or self.Velo.z < -5 then
if self.Velo.z > 0 then
self.Velo.z = math.Clamp(self.Velo.z - tick * mu, -ms, ms)
elseif self.Velo.z < 0 then
self.Velo.z = math.Clamp(self.Velo.z + tick * mu, -ms, ms)
end
else
self.Velo.z = 0
end
end
if not ply:KeyDown(IN_MOVELEFT) and not ply:KeyDown(IN_MOVERIGHT) then
if self.Velo.y > 5 or self.Velo.y < -5 then
if self.Velo.y > 0 then
self.Velo.y = math.Clamp(self.Velo.y - tick * mu, -ms, ms)
elseif self.Velo.y < 0 then
self.Velo.y = math.Clamp(self.Velo.y + tick * mu, -ms, ms)
end
else
self.Velo.y = 0
end
end
-- Removed Boost Logic for Bomber Drone
-- local wasBoost = self:GetNW2Bool('Boost')
-- self:SetNW2Bool('Boost', ply:KeyDown(IN_ATTACK))
-- Drop Grenade Logic
if ply:KeyDown(IN_ATTACK2) and self.GrenadesLeft > 0 and CurTime() > self.GrenadeDropDelay then
self:DropGrenade()
self.GrenadeDropDelay = CurTime() + 1.5
end
-- Removed boost sound logic
if self.RotorSound then
local spd = phys:GetVelocity():Length()
local load = math.Clamp((math.abs(self.Velo.x) + math.abs(self.Velo.y) + math.abs(self.Velo.z)) / (self.BoostSpeed * 0.6), 0, 1)
local timeLeft = math.max(self:GetNW2Float('RemoveTime') - CurTime(), 0)
local battFrac = math.Clamp(timeLeft / self.BatteryCount, 0, 1)
local basePitch = 80 + 45 * load + math.Clamp(spd * 0.025, 0, 35)
local baseVol = 0.15 + 0.35 * load
basePitch = basePitch * (0.85 + 0.15 * battFrac)
if battFrac < 0.15 then
basePitch = basePitch + math.sin(CurTime() * 15) * 5
end
self.RotorSound:ChangePitch(math.Clamp(basePitch, 55, 180), 0.08)
self.RotorSound:ChangeVolume(math.Clamp(baseVol, 0.05, 0.55), 0.08)
end
if self.WindSound then
local spd = phys:GetVelocity():Length()
local windVol = math.Clamp(spd / 800, 0, 0.4)
local windPitch = 80 + math.Clamp(spd * 0.05, 0, 40)
self.WindSound:ChangeVolume(windVol, 0.15)
self.WindSound:ChangePitch(windPitch, 0.15)
end
local maxDist = 13000 * 13000 -- дальность БИБА ТВОЮ МАТЬ ДАЛЬНОСТЬ!!!
local dist2 = ply:GetPos():DistToSqr(self:GetPos())
if dist2 > maxDist then
net.Start("MuR_DroneLost_Grenade")
net.Send(ply)
self:Explode()
return true
end
if self:Health() <= 0 then
net.Start("MuR_DroneLost_Grenade")
net.Send(ply)
self:Explode()
end
if self:GetNW2Float('RemoveTime') < CurTime() or not ply:Alive() or (ply.GetSVAnim and ply:GetSVAnim() ~= "") then
net.Start("MuR_DroneLost_Grenade")
net.Send(ply)
self:EmitSound("ambient/machines/machine1_hit2.wav", 70, 80, 0.6)
self:Remove()
elseif (ply:KeyDown(IN_RELOAD) and ply:GetPos():DistToSqr(self:GetPos()) < 50000) then
ply:Give("swep_drone_grenade")
ply:SelectWeapon("swep_drone_grenade")
self:EmitSound("buttons/button14.wav", 60, 100, 0.5)
self:Remove()
end
self.DeltaTime = CurTime()
self:NextThink(CurTime())
return true
end
end
function ENT:PhysicsCollide(col)
if self.Velo.x > self.MaxSpeed and self:GetNW2Bool('Boost') then
self:EmitSound("physics/metal/metal_solid_impact_hard"..math.random(1,5)..".wav", 80, 100, 0.8)
self:TakeDamage(self:Health())
end
end
function ENT:Explode()
local effect = EffectData()
effect:SetOrigin(self:GetPos())
util.Effect("Explosion", effect)
self:EmitSound("ambient/explosions/explode_4.wav", 100, 100, 1)
self:Remove()
end
function ENT:DropGrenade()
if self.GrenadesLeft <= 0 then return end
self.GrenadesLeft = self.GrenadesLeft - 1
self:SetNW2Int("Grenades", self.GrenadesLeft)
self:EmitSound("weapons/smg1/switch_single.wav", 80, 100)
local grenade = ents.Create("lvs_item_explosive")
grenade:SetPos(self:GetPos() - Vector(0,0,10))
grenade:SetAngles(self:GetAngles())
grenade:Spawn()
grenade:Activate()
grenade:Fire("SetTimer", "3")
local phys = grenade:GetPhysicsObject()
if IsValid(phys) then
phys:SetVelocity(self:GetVelocity() + Vector(0,0,-50))
phys:AddAngleVelocity(VectorRand() * 200)
end
local ply = self:GetCreator()
if IsValid(ply) then
net.Start("MuR_GrenadeDropped")
net.Send(ply)
end
local physDrone = self:GetPhysicsObject()
if IsValid(physDrone) then
physDrone:ApplyForceCenter(Vector(0,0,2000))
end
end
function ENT:OnTakeDamage(dmgt)
local dmg = dmgt:GetDamage()
local att = dmgt:GetAttacker()
self:SetHealth(self:Health() - dmg)
if IsValid(self:GetCreator()) then
self:GetCreator():ViewPunch(AngleRand(-1, 1))
local snd = damageSounds[math.random(#damageSounds)]
self:EmitSound(snd, 75, math.random(90, 110))
if self:Health() < self.HealthCount * 0.3 and math.random() < 0.3 then
self:EmitSound("ambient/machines/machine1_hit1.wav", 65, math.random(120, 140), 0.4)
end
end
end
net.Receive("MuR_DroneEmergency", function(len, ply)
local drone = ply.ControlDrone
if not IsValid(drone) then return end
if not drone.EmergencyKill then
drone.EmergencyKill = true
drone.EmergencyKillTime = CurTime() + 3
drone:SetNWFloat("EmergencyCountdown", drone.EmergencyKillTime)
drone:EmitSound("buttons/button17.wav", 75, 100, 0.6)
end
end)
net.Receive("MuR_ThermalState", function(len, ply)
local drone = ply.ControlDrone
if IsValid(drone) then
drone:SetNW2Bool("ThermalActive", net.ReadBool())
end
end)
hook.Add("SetupPlayerVisibility", "GpincDroneCam_Grenade", function(ply, viewEntity)
local drone = ply.ControlDrone
if IsValid(drone) and drone:GetClass() == "mur_drone_grenade" then
AddOriginToPVS(drone:GetPos())
end
end)

View File

@@ -0,0 +1,569 @@
ENT.Base = "base_gmodentity"
ENT.Type = "anim"
ENT.PrintName = "Grenade Drone"
ENT.Spawnable = true
ENT.AutomaticFrameAdvance = true
ENT.BatteryCount = 300
ENT.HealthCount = 10
ENT.GrenadeCount = 3
if CLIENT then
local droneRT = nil
local droneRTMat = nil
function GetDroneRT()
if not droneRT then
droneRT = GetRenderTarget("mur_drone_grenade_rt", ScrW(), ScrH(), false)
droneRTMat = CreateMaterial("mur_drone_grenade_rt_mat", "UnlitGeneric", {
["$basetexture"] = droneRT:GetName(),
["$ignorez"] = 1,
["$vertexcolor"] = 1,
["$vertexalpha"] = 1
})
end
return droneRT
end
local GrenadeNotifyEnd = 0
local GrenadeNotifyMat = Material("posvetka/nizhniya_posvedka.png")
net.Receive("MuR_GrenadeDropped", function()
GrenadeNotifyEnd = CurTime() + 1.5 -- показывать 1.5 секунды
end)
local function DrawSignalNoise(strength)
if strength > 1 then return end
local sw, sh = ScrW(), ScrH()
local noise = (1 - strength) * 200
local lines = (1 - strength) * 40
for i = 1, noise do
surface.SetDrawColor(255, 255, 255, math.random(10, 40))
surface.DrawRect(
math.random(0, sw),
math.random(0, sh),
math.random(1, 3),
math.random(1, 3)
)
end
for i = 1, lines do
local y = math.random(0, sh)
surface.SetDrawColor(255, 255, 255, math.random(10, 40))
surface.DrawRect(0, y, sw, math.random(1, 3))
end
if strength < 0.3 then
local shake = (0.3 - strength) * 4
surface.SetDrawColor(255, 255, 255, 20)
surface.DrawRect(
math.random(-shake, shake),
math.random(-shake, shake),
sw,
sh
)
end
end
hook.Add("HUDPaint", "MuR_GrenadeDropImage", function()
if GrenadeNotifyEnd <= CurTime() then return end
local sw, sh = ScrW(), ScrH()
local w, h = 282, 152 -- размер картинки
local timeLeft = GrenadeNotifyEnd - CurTime()
local alpha = math.Clamp(timeLeft * 255, 0, 255)
surface.SetMaterial(GrenadeNotifyMat)
surface.SetDrawColor(255, 255, 255, alpha)
surface.DrawTexturedRect(sw/2 - w/2, sh/2 - h/2, w, h)
end)
function DrawScanlines(sw, sh, spacing)
spacing = spacing or 3
surface.SetDrawColor(0, 0, 0, 40)
for y = 0, sh, spacing do
surface.DrawLine(0, y, sw, y)
end
end
function DrawGlitchNoise(sw, sh, strength)
strength = strength or 1
local count = math.floor(80 * strength)
for i = 1, count do
local x = math.random(0, sw)
local y = math.random(0, sh)
local w = math.random(1, 4)
local h = math.random(1, 4)
local c = math.random(80, 140)
surface.SetDrawColor(c, c, c, 80)
surface.DrawRect(x, y, w, h)
end
end
function DrawCornerBrackets(x, y, w, h, len, thick, col)
col = col or color_white
thick = thick or 2
len = len or 20
surface.SetDrawColor(col)
surface.DrawRect(x, y, len, thick)
surface.DrawRect(x, y, thick, len)
surface.DrawRect(x + w - len, y, len, thick)
surface.DrawRect(x + w - thick, y, thick, len)
surface.DrawRect(x, y + h - thick, len, thick)
surface.DrawRect(x, y + h - len, thick, len)
surface.DrawRect(x + w - len, y + h - thick, len, thick)
surface.DrawRect(x + w - thick, y + h - len, thick, len)
end
function DrawCrosshair(cx, cy, size, gap, thick, col)
col = col or color_white
size = size or 20
gap = gap or 4
thick = thick or 2
surface.SetDrawColor(col)
surface.DrawRect(cx - size, cy - thick / 2, size - gap, thick)
surface.DrawRect(cx + gap, cy - thick / 2, size - gap, thick)
surface.DrawRect(cx - thick / 2, cy - size, thick, size - gap)
surface.DrawRect(cx - thick / 2, cy + gap, thick, size - gap)
end
function DrawArcSegment(cx, cy, radius, startAng, endAng, thick, steps, col)
col = col or color_white
thick = thick or 2
steps = steps or 32
surface.SetDrawColor(col)
local step = (endAng - startAng) / steps
for i = 0, steps - 1 do
local a1 = math.rad(startAng + step * i)
local a2 = math.rad(startAng + step * (i + 1))
local x1, y1 = cx + math.cos(a1) * radius, cy + math.sin(a1) * radius
local x2, y2 = cx + math.cos(a2) * radius, cy + math.sin(a2) * radius
surface.DrawLine(x1, y1, x2, y2)
end
end
local DRONE = nil
local Thermal = false
local ThermalKeyHeld = false
local Zoom = 1
local DefMats = {}
local DefClrs = {}
local DoXRay = false
local FLIR = {
["$pp_colour_addr"] = -.3,
["$pp_colour_addg"] = -.4,
["$pp_colour_addb"] = -.4,
["$pp_colour_brightness"] = .1,
["$pp_colour_contrast"] = 1, -- да-да, мой флир, биба
["$pp_colour_colour"] = 0,
["$pp_colour_mulr"] = 0,
["$pp_colour_mulg"] = 0,
["$pp_colour_mulb"] = 0,
}
net.Receive("MuR_DroneCam_Grenade", function()
local ent = net.ReadEntity()
DRONE = ent
Thermal = false
Zoom = 1
local pulseAlpha = 0
local pulseDir = 1
local lastBattBeep = 0
local lastDmgBeep = 0
local startTime = CurTime()
local smoothBatt = 1
local smoothHP = 1
local ppTab = {
["$pp_colour_addr"] = 0.05,
["$pp_colour_addg"] = 0.02,
["$pp_colour_addb"] = 0,
["$pp_colour_brightness"] = -0.03,
["$pp_colour_contrast"] = 1.15,
["$pp_colour_colour"] = 0.5,
["$pp_colour_mulr"] = 0.05,
["$pp_colour_mulg"] = 0.05,
["$pp_colour_mulb"] = 0
}
hook.Add("RenderScreenspaceEffects", "DroneCam", function()
if not IsValid(ent) then return end
local rt = GetDroneRT()
render.CopyRenderTargetToTexture(rt)
local timeLeft = math.max(ent:GetNW2Float('RemoveTime') - CurTime(), 0)
local battFrac = math.Clamp(timeLeft / ent.BatteryCount, 0, 1)
if battFrac < 0.2 then
ppTab["$pp_colour_addr"] = 0.1 * (1 - battFrac / 0.2)
ppTab["$pp_colour_contrast"] = 1.15 + 0.2 * (1 - battFrac / 0.2)
else
ppTab["$pp_colour_addr"] = 0.05
ppTab["$pp_colour_contrast"] = 1.15
end
DrawColorModify(ppTab)
DrawSharpen(0.8, 0.8)
end)
hook.Add("HUDPaint", "DroneCam", function()
if not IsValid(ent) then return end
local sw, sh = ScrW(), ScrH()
local cx, cy = sw / 2, sh / 2
local time = CurTime()
local elapsed = time - startTime
pulseAlpha = pulseAlpha + pulseDir * FrameTime() * 400
if pulseAlpha >= 255 then pulseDir = -1 pulseAlpha = 255
elseif pulseAlpha <= 100 then pulseDir = 1 pulseAlpha = 100 end
local timeLeft = math.max(ent:GetNW2Float('RemoveTime') - CurTime(), 0)
local battFrac = math.Clamp(timeLeft / ent.BatteryCount, 0, 1)
local hpFrac = math.Clamp(ent:Health() / ent.HealthCount, 0, 1)
smoothBatt = Lerp(FrameTime() * 3, smoothBatt, battFrac)
smoothHP = Lerp(FrameTime() * 5, smoothHP, hpFrac)
local vel = ent:GetVelocity():Length()
local spd = math.Round(vel * 0.068)
local tr = util.TraceLine({start = ent:GetPos(), endpos = ent:GetPos() - Vector(0, 0, 10000), filter = ent})
local agl = math.Round(ent:GetPos().z - tr.HitPos.z)
local dist2 = LocalPlayer():GetPos():DistToSqr(ent:GetPos())
local signal = math.Clamp(1 - (dist2 / (10000 * 10000)), 0, 1)
local canDisarm = dist2 < 50000
local killTime = ent:GetNWFloat("EmergencyCountdown", 0)
DrawScanlines(sw, sh, 32)
DrawGlitchNoise(sw, sh, signal)
local frameCol = Color(255, 150, 40, 120)
DrawCornerBrackets(40, 40, sw - 80, sh - 80, 60, 3, frameCol)
local crossCol = Color(255, 150, 40, pulseAlpha)
DrawCrosshair(cx, cy, 25, 8, 2, crossCol)
surface.SetDrawColor(255, 50, 50, 100)
DrawArcSegment(cx, cy, 60, 0, 360, 2, 64, Color(255, 50, 50, 50))
if tr.Hit then
local screenData = tr.HitPos:ToScreen()
if screenData.visible then
surface.SetDrawColor(255, 0, 0, 200)
surface.DrawRect(screenData.x - 2, screenData.y - 2, 4, 4)
draw.SimpleText("МЕСТО ПАДЕНИЯ", "MuR_Font1", screenData.x, screenData.y - 15, Color(255, 50, 50, 200), TEXT_ALIGN_CENTER)
end
end
local targetDist = tr.HitPos:Distance(ent:GetPos())
if targetDist < 500 then
local lockCol = Color(255, 80, 60, pulseAlpha)
DrawCrosshair(cx, cy, 35, 5, 3, lockCol)
draw.SimpleText(string.format("%.1fm", targetDist * 0.0254), "MuR_Font2", cx, cy + 50, lockCol, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP)
end
draw.SimpleText("◈ ДРОН СО СБРОСОМ", "MuR_Font3", 80, 60, Color(255, 150, 40, 255), TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
draw.SimpleText(string.format("ВРЕМЯ РАБОТЫ %.1fs", elapsed), "MuR_Font1", 80, 95, Color(150, 150, 150, 200), TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
draw.SimpleText(os.date("%H:%M:%S"), "MuR_Font1", 80, 115, Color(150, 150, 150, 200), TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
local grenadesLeft = ent:GetNW2Int("Grenades", 3)
draw.SimpleText(string.format("БОЕКОМПЛЕКТ: %d/3", grenadesLeft), "MuR_Font3", 80, 140, grenadesLeft > 0 and Color(255, 50, 50) or Color(100, 100, 100), TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP)
local telemX = sw - 80
local spdCol = spd > 60 and Color(255, 200, 60) or Color(255, 150, 40)
draw.SimpleText(string.format("%03d km/h", spd), "MuR_Font3", telemX, 60, spdCol, TEXT_ALIGN_RIGHT, TEXT_ALIGN_TOP)
draw.SimpleText("СКОР", "MuR_Font1", telemX, 95, Color(100, 100, 100), TEXT_ALIGN_RIGHT, TEXT_ALIGN_TOP)
draw.SimpleText(string.format("%04d m", agl), "MuR_Font3", telemX, 120, Color(255, 150, 40), TEXT_ALIGN_RIGHT, TEXT_ALIGN_TOP)
draw.SimpleText("ВЫС", "MuR_Font1", telemX, 155, Color(100, 100, 100), TEXT_ALIGN_RIGHT, TEXT_ALIGN_TOP)
local sigCol = signal < 0.25 and Color(255, 60, 60) or (signal < 0.5 and Color(255, 200, 60) or Color(255, 150, 40))
local sigBars = math.floor(signal * 5)
local sigStr = string.rep("", sigBars) .. string.rep("", 5 - sigBars)
draw.SimpleText(sigStr, "MuR_Font2", telemX, 180, sigCol, TEXT_ALIGN_RIGHT, TEXT_ALIGN_TOP)
draw.SimpleText(string.format("%d%%", math.Round(signal * 100)), "MuR_Font1", telemX, 210, sigCol, TEXT_ALIGN_RIGHT, TEXT_ALIGN_TOP)
local barW, barH = 250, 12
local barX, barY = 80, sh - 180
local battCol = smoothBatt < 0.2 and Color(255, 60, 60) or (smoothBatt < 0.4 and Color(255, 200, 60) or Color(255, 150, 40))
surface.SetDrawColor(30, 30, 30, 200)
surface.DrawRect(barX, barY, barW, barH)
surface.SetDrawColor(battCol.r, battCol.g, battCol.b, 255)
surface.DrawRect(barX + 2, barY + 2, (barW - 4) * smoothBatt, barH - 4)
surface.SetDrawColor(battCol.r, battCol.g, battCol.b, 100)
surface.DrawOutlinedRect(barX, barY, barW, barH, 1)
draw.SimpleText(string.format("ЗАРЯД %d%%", math.Round(smoothBatt * 100)), "MuR_Font1", barX, barY - 20, battCol, TEXT_ALIGN_LEFT, TEXT_ALIGN_BOTTOM)
draw.SimpleText(string.format("%.0fs", timeLeft), "MuR_Font1", barX + barW, barY - 20, Color(150, 150, 150), TEXT_ALIGN_RIGHT, TEXT_ALIGN_BOTTOM)
barY = sh - 130
local hpCol = smoothHP < 0.3 and Color(255, 60, 60) or (smoothHP < 0.6 and Color(255, 200, 60) or Color(255, 150, 40))
surface.SetDrawColor(30, 30, 30, 200)
surface.DrawRect(barX, barY, barW, barH)
surface.SetDrawColor(hpCol.r, hpCol.g, hpCol.b, 255)
surface.DrawRect(barX + 2, barY + 2, (barW - 4) * smoothHP, barH - 4)
surface.SetDrawColor(hpCol.r, hpCol.g, hpCol.b, 100)
surface.DrawOutlinedRect(barX, barY, barW, barH, 1)
draw.SimpleText(string.format("ПРОЧНОСТЬ %d%%", math.Round(smoothHP * 100)), "MuR_Font1", barX, barY - 20, hpCol, TEXT_ALIGN_LEFT, TEXT_ALIGN_BOTTOM)
local ctrlX, ctrlY = sw - 80, sh - 200
local ctrlCol = Color(150, 150, 150, 200)
draw.SimpleText("▶ [J] САМОУНИЧТОЖЕНИЕ", "MuR_Font1", ctrlX, ctrlY, Color(255, 80, 80, 200), TEXT_ALIGN_RIGHT)
draw.SimpleText("▶ [ALT] ТЕПЛОВИЗОР", "MuR_Font1", ctrlX, ctrlY + 22, ctrlCol, TEXT_ALIGN_RIGHT)
draw.SimpleText("▼ [ПКМ] СБРОСИТЬ ГРАНАТУ", "MuR_Font1", ctrlX, ctrlY + 44, Color(255, 80, 60, 200), TEXT_ALIGN_RIGHT)
draw.SimpleText("▲ [SHIFT] ВВЕРХ", "MuR_Font1", ctrlX, ctrlY + 66, ctrlCol, TEXT_ALIGN_RIGHT)
draw.SimpleText("▼ [CTRL] ВНИЗ", "MuR_Font1", ctrlX, ctrlY + 88, ctrlCol, TEXT_ALIGN_RIGHT)
local rY = ctrlY + 110
if canDisarm then
draw.SimpleText("◉ [R] ВЕРНУТЬ ДРОН", "MuR_Font1", ctrlX, rY, Color(40, 255, 120, 200), TEXT_ALIGN_RIGHT)
else
draw.SimpleText("✖ СЛИШКОМ ДАЛЕКО", "MuR_Font1", ctrlX, rY, Color(255, 100, 60, 200), TEXT_ALIGN_RIGHT)
end
if ent:GetNW2Bool('Boost') then
local boostFlash = math.sin(time * 15) > 0 and 255 or 180
draw.SimpleText("◀◀ УСКОРЕНИЕ ▶▶", "MuR_Font2", cx, sh - 100, Color(255, 200, 60, boostFlash), TEXT_ALIGN_CENTER)
end
if smoothBatt < 0.15 then
local warnFlash = math.sin(time * 8) > 0 and 255 or 100
draw.SimpleText("⚠ НИЗКИЙ ЗАРЯД ⚠", "MuR_Font4", cx, 80, Color(255, 60, 60, warnFlash), TEXT_ALIGN_CENTER)
if time > lastBattBeep then
surface.PlaySound("buttons/button17.wav")
lastBattBeep = time + 0.8
end
end
if smoothHP < 0.25 then
local dmgFlash = math.sin(time * 6) > 0 and 255 or 100
draw.SimpleText("⚠ КРИТИЧЕСКИЕ ПОВРЕЖДЕНИЯ ⚠", "MuR_Font3", cx, 130, Color(255, 120, 60, dmgFlash), TEXT_ALIGN_CENTER)
if time > lastDmgBeep then
surface.PlaySound("buttons/button10.wav")
lastDmgBeep = time + 1.5
end
end
if signal < 0.2 then
local sigFlash = math.sin(time * 10) > 0 and 255 or 100
draw.SimpleText("◢◤ СЛАБЫЙ СИГНАЛ ◢◤", "MuR_Font3", cx, 180, Color(255, 80, 60, sigFlash), TEXT_ALIGN_CENTER)
end
DrawSignalNoise(signal)
if ent:GetNWBool("Jammed") then
local jamStrength = ent:GetNWFloat("JamStrength", 1)
DrawHeavySignalNoise(jamStrength)
local jamFlash = math.sin(time * 8) > 0 and 255 or 120
draw.SimpleText(
"◢◤ ОБНАРУЖЕНЫ ПОМЕХИ ◢◤",
"MuR_Font3",
cx,
220,
Color(255, 80, 60, jamFlash),
TEXT_ALIGN_CENTER
)
end
if killTime > CurTime() then
local left = math.max(0, killTime - CurTime())
local flash = math.sin(CurTime() * 10) > 0 and 255 or 120
draw.SimpleText(
string.format("САМОУНИЧТОЖЕНИЕ: %.1f", left),
"MuR_Font3",
cx,
260,
Color(255, 50, 50, flash),
TEXT_ALIGN_CENTER
)
end
end)
hook.Add("CreateMove", "DroneCam", function(cmd)
cmd:SetForwardMove(0)
cmd:SetSideMove(0)
cmd:RemoveKey(IN_JUMP)
cmd:RemoveKey(IN_USE)
end)
hook.Add("CalcView", "DroneCam", function(ply, pos, angles, fov)
if not IsValid(ent) then
hook.Remove("CalcView", "DroneCam")
hook.Remove("CreateMove", "DroneCam")
hook.Remove("RenderScreenspaceEffects", "DroneCam")
hook.Remove("HUDPaint", "DroneCam")
return
end
local dPos = ent:GetPos()
local dAng = ent:GetAngles()
local vel = ent:GetVelocity():Length()
local offset = Vector(-8 - math.Clamp(vel * 0.015, 0, 5), 0, -2)
local camPos = dPos + ent:GetForward() * offset.x + ent:GetUp() * offset.z
local camAng = Angle(dAng.p, dAng.y, dAng.r)
camAng.p = ply:EyeAngles().p
local dynFov = 40 + math.Clamp(vel * 0.025, 0, 15)
dynFov = Lerp(Zoom, 20, dynFov)
return {
origin = camPos,
angles = camAng,
fov = math.Clamp(dynFov, 20, 120),
drawviewer = true
}
end)
end)
hook.Add("Think", "mur_drone_ThermalToggle", function()
if not IsValid(DRONE) then return end
if DRONE:GetClass() ~= "mur_drone_grenade" then return end
if input.IsKeyDown(KEY_LALT) and not ThermalKeyHeld then
ThermalKeyHeld = true
Thermal = not Thermal
surface.PlaySound(Thermal and "sw/misc/nv_on.wav" or "sw/misc/nv_off.wav")
net.Start("MuR_ThermalState")
net.WriteBool(Thermal)
net.SendToServer()
end
if not input.IsKeyDown(KEY_LALT) then
ThermalKeyHeld = false
end
end)
local function ApplyXRay()
for _, v in ipairs(ents.GetAll()) do
if not v:GetModel() then continue end
if string.sub(v:GetModel(), -3) ~= "mdl" then continue end
if v:IsPlayer() then
elseif v:IsNPC() then
elseif v.LVS or v.LFS then
else
continue
end
local col = v:GetColor()
if col.a <= 0 then continue end
if not DefClrs[v] then
DefClrs[v] = Color(col.r, col.g, col.b, col.a)
end
local entmat = v:GetMaterial()
if not DefMats[v] then
DefMats[v] = entmat
end
v:SetColor(Color(255,255,255,255))
v:SetMaterial("xray/living")
end
end
hook.Add("RenderScene", "mur_drone_FLIR_Apply", function()
if not Thermal then return end
if not IsValid(DRONE) then return end
if DRONE:GetClass() ~= "mur_drone_grenade" then return end
if not DoXRay then
DoXRay = true
ApplyXRay()
end
end)
local function RenderFLIR()
DrawColorModify(FLIR)
DrawBloom(0,1,1,1,0,0,0,0,0)
DrawMotionBlur(FrameTime() * 50, 0.5, 0.05)
DrawBokehDOF(0.15, 1, 12)
end
hook.Add("HUDPaintBackground", "mur_drone_FLIR_Effects", function()
if not Thermal then return end
if not IsValid(DRONE) then return end
if DRONE:GetClass() ~= "mur_drone_grenade" then return end
RenderFLIR()
end)
hook.Add("Think", "mur_drone_FLIR_AutoOff", function()
if Thermal and not IsValid(DRONE) then
Thermal = false
end
if not Thermal and DoXRay then
DoXRay = false
for ent, mat in pairs(DefMats) do
if IsValid(ent) then ent:SetMaterial(mat) end
end
for ent, clr in pairs(DefClrs) do
if IsValid(ent) then
ent:SetRenderMode(RENDERMODE_TRANSALPHA)
ent:SetColor(Color(clr.r, clr.g, clr.b, clr.a))
end
end
DefMats = {}
DefClrs = {}
end
end)
hook.Add("Think", "mur_drone_Zoom", function()
if not IsValid(DRONE) then return end
if DRONE:GetClass() ~= "mur_drone_grenade" then return end
local delta = input.GetAnalogValue(ANALOG_MOUSE_WHEEL)
if delta ~= 0 then
Zoom = Zoom - delta * 0.05
Zoom = math.Clamp(Zoom, 0, 1)
end
end)
hook.Add("Think", "DroneEmergencyKey", function()
if not IsValid(DRONE) then return end
if DRONE:GetClass() ~= "mur_drone_grenade" then return end
if input.IsKeyDown(KEY_J) and not DRONE._KillKeyHeld then
DRONE._KillKeyHeld = true
net.Start("MuR_DroneEmergency")
net.SendToServer()
end
if not input.IsKeyDown(KEY_J) then
DRONE._KillKeyHeld = false
end
end)
hook.Add("PlayerBindPress", "mur_drone_ZoomBlock", function(ply, bind, pressed)
if not IsValid(DRONE) then return end
if DRONE:GetClass() ~= "mur_drone_grenade" then return end
if bind == "invprev" then
Zoom = math.Clamp(Zoom - 0.1, 0, 1)
return true
end
if bind == "invnext" then
Zoom = math.Clamp(Zoom + 0.1, 0, 1)
return true
end
end)
end