add sborka
This commit is contained in:
618
garrysmod/addons/tacrp/lua/entities/tacrp_proj_base.lua
Normal file
618
garrysmod/addons/tacrp/lua/entities/tacrp_proj_base.lua
Normal file
@@ -0,0 +1,618 @@
|
||||
AddCSLuaFile()
|
||||
|
||||
ENT.Type = "anim"
|
||||
ENT.Base = "base_entity"
|
||||
ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
|
||||
|
||||
ENT.PrintName = "Base Projectile"
|
||||
ENT.Category = ""
|
||||
|
||||
ENT.Spawnable = false
|
||||
ENT.Model = ""
|
||||
|
||||
local smokeimages = {"particle/smokesprites_0001", "particle/smokesprites_0002", "particle/smokesprites_0003", "particle/smokesprites_0004", "particle/smokesprites_0005", "particle/smokesprites_0006", "particle/smokesprites_0007", "particle/smokesprites_0008", "particle/smokesprites_0009", "particle/smokesprites_0010", "particle/smokesprites_0011", "particle/smokesprites_0012", "particle/smokesprites_0013", "particle/smokesprites_0014", "particle/smokesprites_0015", "particle/smokesprites_0016"}
|
||||
local function GetSmokeImage()
|
||||
return smokeimages[math.random(#smokeimages)]
|
||||
end
|
||||
|
||||
ENT.Material = false // custom material
|
||||
|
||||
ENT.IsRocket = false // projectile has a booster and will not drop.
|
||||
|
||||
ENT.Sticky = false // projectile sticks on impact
|
||||
|
||||
ENT.InstantFuse = true // projectile is armed immediately after firing.
|
||||
ENT.TimeFuse = false // projectile will arm after this amount of time
|
||||
ENT.RemoteFuse = false // allow this projectile to be triggered by remote detonator.
|
||||
ENT.ImpactFuse = false // projectile explodes on impact.
|
||||
ENT.StickyFuse = false // projectile becomes timed after sticking.
|
||||
|
||||
ENT.SafetyFuse = 0 // impact fuse hitting too early will not detonate
|
||||
|
||||
ENT.RemoveOnImpact = false
|
||||
ENT.ExplodeOnImpact = false
|
||||
ENT.ExplodeOnDamage = false // projectile explodes when it takes damage.
|
||||
ENT.ExplodeUnderwater = false // projectile explodes when it enters water
|
||||
|
||||
ENT.Defusable = false // press E on the projectile to defuse it
|
||||
ENT.DefuseOnDamage = false
|
||||
|
||||
ENT.ImpactDamage = 50
|
||||
ENT.ImpactDamageType = DMG_CRUSH + DMG_CLUB
|
||||
|
||||
ENT.Delay = 0 // after being triggered and this amount of time has passed, the projectile will explode.
|
||||
|
||||
ENT.SoundHint = false // Emit a sound hint so NPCs can react
|
||||
ENT.SoundHintDelay = 0 // Delay after spawn
|
||||
ENT.SoundHintRadius = 328
|
||||
ENT.SoundHintDuration = 1
|
||||
|
||||
ENT.Armed = false
|
||||
|
||||
ENT.SmokeTrail = false // leaves trail of smoke
|
||||
ENT.FlareColor = nil
|
||||
ENT.FlareSizeMin = 200
|
||||
ENT.FlareSizeMax = 250
|
||||
|
||||
|
||||
// Guided projectile related
|
||||
ENT.SteerDelay = 0 // Delay before steering logic kicks in
|
||||
ENT.SteerSpeed = 60 // Turn rate in degrees per second
|
||||
ENT.SteerBrake = 0 // Amount of speed to slow down by when turning
|
||||
ENT.SeekerAngle = 180 // Angle difference (degrees) above which projectile loses target
|
||||
ENT.SeekerExplodeRange = 256 // Distance to the target below which the missile will immediately explode
|
||||
ENT.SeekerExplodeSnapPosition = true // When exploding on a seeked target, teleport to the entity's position for more damage
|
||||
ENT.SeekerExplodeAngle = 180 // Angle tolerance (degrees) below which detonation can happen
|
||||
|
||||
ENT.TopAttack = false // This missile will attack from the top
|
||||
ENT.TopAttackHeight = 512 // Distance above target to top attack
|
||||
ENT.TopAttackDistance = 128 // Distance from target to stop top attacking
|
||||
|
||||
ENT.RocketLifetime = 30 // Rocket will cut after this time
|
||||
|
||||
ENT.MinSpeed = 0
|
||||
ENT.MaxSpeed = 0
|
||||
ENT.Acceleration = 0
|
||||
|
||||
ENT.LeadTarget = false // account for target's velocity and distance
|
||||
ENT.SuperSteerTime = 0 // Amount of time where turn rate is boosted
|
||||
ENT.SuperSteerSpeed = 100 // Boosted turn rate in degrees per seconds
|
||||
|
||||
ENT.NoReacquire = true // If target is lost, it cannot be tracked anymore
|
||||
ENT.FlareRedirectChance = 0
|
||||
|
||||
ENT.LockOnEntity = NULL
|
||||
ENT.TargetPos = nil
|
||||
|
||||
ENT.AudioLoop = nil
|
||||
ENT.BounceSounds = nil
|
||||
ENT.CollisionSphere = nil
|
||||
ENT.GunshipWorkaround = true
|
||||
|
||||
// Tell LVS to not ricochet us
|
||||
ENT.DisableBallistics = true
|
||||
|
||||
ENT.TopAttacking = false
|
||||
ENT.StartSuperSteerTime = 0
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
self:NetworkVar("Entity", 0, "Weapon")
|
||||
end
|
||||
|
||||
function ENT:Initialize()
|
||||
if SERVER then
|
||||
self:SetModel(self.Model)
|
||||
self:SetMaterial(self.Material or "")
|
||||
if self.CollisionSphere then
|
||||
self:PhysicsInitSphere(self.CollisionSphere)
|
||||
else
|
||||
self:PhysicsInit(SOLID_VPHYSICS)
|
||||
end
|
||||
self:SetMoveType(MOVETYPE_VPHYSICS)
|
||||
self:SetSolid(SOLID_VPHYSICS)
|
||||
|
||||
self:SetCollisionGroup(COLLISION_GROUP_PROJECTILE)
|
||||
if self.Defusable then
|
||||
self:SetUseType(SIMPLE_USE)
|
||||
end
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
if !phys:IsValid() then
|
||||
self:Remove()
|
||||
return
|
||||
end
|
||||
|
||||
phys:EnableDrag(false)
|
||||
phys:SetDragCoefficient(0)
|
||||
phys:SetBuoyancyRatio(0)
|
||||
phys:Wake()
|
||||
|
||||
if self.IsRocket then
|
||||
phys:EnableGravity(false)
|
||||
end
|
||||
|
||||
if self.TopAttack then
|
||||
self.TopAttacking = true
|
||||
end
|
||||
|
||||
self:SwitchTarget(self.LockOnEntity)
|
||||
end
|
||||
|
||||
self.StartSuperSteerTime = CurTime()
|
||||
self.SpawnTime = CurTime()
|
||||
self.NextFlareRedirectTime = 0
|
||||
|
||||
self.NPCDamage = IsValid(self:GetOwner()) and self:GetOwner():IsNPC() and !TacRP.ConVars["npc_equality"]:GetBool()
|
||||
|
||||
if self.AudioLoop then
|
||||
self.LoopSound = CreateSound(self, self.AudioLoop)
|
||||
self.LoopSound:Play()
|
||||
end
|
||||
|
||||
if self.InstantFuse then
|
||||
self.ArmTime = CurTime()
|
||||
self.Armed = true
|
||||
end
|
||||
|
||||
self:OnInitialize()
|
||||
end
|
||||
|
||||
function ENT:OnRemove()
|
||||
if self.LoopSound then
|
||||
self.LoopSound:Stop()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:OnTakeDamage(dmg)
|
||||
if self.Detonated then return end
|
||||
|
||||
// self:TakePhysicsDamage(dmg)
|
||||
|
||||
if self.ExplodeOnDamage then
|
||||
if IsValid(self:GetOwner()) and IsValid(dmg:GetAttacker()) then self:SetOwner(dmg:GetAttacker())
|
||||
else self.Attacker = dmg:GetAttacker() or self.Attacker end
|
||||
self:PreDetonate()
|
||||
elseif self.DefuseOnDamage and dmg:GetDamageType() != DMG_BLAST then
|
||||
self:EmitSound("physics/plastic/plastic_box_break" .. math.random(1, 2) .. ".wav", 70, math.Rand(95, 105))
|
||||
local fx = EffectData()
|
||||
fx:SetOrigin(self:GetPos())
|
||||
fx:SetNormal(self:GetAngles():Forward())
|
||||
fx:SetAngles(self:GetAngles())
|
||||
util.Effect("ManhackSparks", fx)
|
||||
self.Detonated = true
|
||||
self:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:PhysicsCollide(data, collider)
|
||||
if IsValid(data.HitEntity) and data.HitEntity:GetClass() == "func_breakable_surf" then
|
||||
self:FireBullets({
|
||||
Attacker = self:GetOwner(),
|
||||
Inflictor = self,
|
||||
Damage = 0,
|
||||
Distance = 32,
|
||||
Tracer = 0,
|
||||
Src = self:GetPos(),
|
||||
Dir = data.OurOldVelocity:GetNormalized(),
|
||||
})
|
||||
local pos, ang, vel = self:GetPos(), self:GetAngles(), data.OurOldVelocity
|
||||
self:SetAngles(ang)
|
||||
self:SetPos(pos)
|
||||
self:GetPhysicsObject():SetVelocityInstantaneous(vel * 0.5)
|
||||
return
|
||||
end
|
||||
|
||||
if (self.SafetyFuse or 0) > 0 and self.SpawnTime + self.SafetyFuse > CurTime() then
|
||||
self:SafetyImpact(data, collider)
|
||||
self:Remove()
|
||||
return
|
||||
elseif self.ImpactFuse then
|
||||
if !self.Armed then
|
||||
self.ArmTime = CurTime()
|
||||
self.Armed = true
|
||||
|
||||
if self:Impact(data, collider) then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if self.Delay == 0 or self.ExplodeOnImpact then
|
||||
self:PreDetonate(data.HitEntity)
|
||||
end
|
||||
elseif self.ImpactDamage > 0 and (self.NextImpactDamage or 0) < CurTime() and data.Speed >= 10 and IsValid(data.HitEntity) and (engine.ActiveGamemode() != "terrortown" or !data.HitEntity:IsPlayer()) then
|
||||
local dmg = DamageInfo()
|
||||
dmg:SetAttacker(IsValid(self:GetOwner()) and self:GetOwner() or self.Attacker)
|
||||
dmg:SetInflictor(self)
|
||||
dmg:SetDamage(self.ImpactDamage)
|
||||
dmg:SetDamageType(self.ImpactDamageType)
|
||||
dmg:SetDamageForce(data.OurOldVelocity)
|
||||
dmg:SetDamagePosition(data.HitPos)
|
||||
data.HitEntity:TakeDamageInfo(dmg)
|
||||
self.NextImpactDamage = CurTime() + 0.05
|
||||
elseif !self.ImpactFuse then
|
||||
self:Impact(data, collider)
|
||||
end
|
||||
|
||||
if self.Sticky then
|
||||
self:SetCollisionGroup(COLLISION_GROUP_DEBRIS)
|
||||
self:SetPos(data.HitPos)
|
||||
|
||||
self:SetAngles((-data.HitNormal):Angle())
|
||||
|
||||
if data.HitEntity:IsWorld() or data.HitEntity:GetSolid() == SOLID_BSP then
|
||||
self:SetMoveType(MOVETYPE_NONE)
|
||||
self:SetPos(data.HitPos)
|
||||
else
|
||||
self:SetPos(data.HitPos)
|
||||
self:SetParent(data.HitEntity)
|
||||
end
|
||||
|
||||
self:EmitSound("TacRP/weapons/plant_bomb.wav", 65)
|
||||
|
||||
self.Attacker = self:GetOwner()
|
||||
self:SetOwner(NULL)
|
||||
|
||||
if self.StickyFuse and !self.Armed then
|
||||
self.ArmTime = CurTime()
|
||||
self.Armed = true
|
||||
end
|
||||
|
||||
self:Stuck()
|
||||
else
|
||||
if !self.Bounced then
|
||||
self.Bounced = true
|
||||
local dot = data.HitNormal:Dot(Vector(0, 0, 1))
|
||||
if dot < 0 then
|
||||
self:GetPhysicsObject():SetVelocityInstantaneous(data.OurNewVelocity * (1 + dot * 0.5))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if data.DeltaTime < 0.1 then return end
|
||||
if !self.BounceSounds then return end
|
||||
|
||||
local s = table.Random(self.BounceSounds)
|
||||
|
||||
self:EmitSound(s)
|
||||
end
|
||||
|
||||
function ENT:OnThink()
|
||||
end
|
||||
|
||||
function ENT:OnInitialize()
|
||||
end
|
||||
|
||||
function ENT:DoSmokeTrail()
|
||||
if CLIENT and self.SmokeTrail then
|
||||
local emitter = ParticleEmitter(self:GetPos())
|
||||
|
||||
local smoke = emitter:Add(GetSmokeImage(), self:GetPos())
|
||||
|
||||
smoke:SetStartAlpha(50)
|
||||
smoke:SetEndAlpha(0)
|
||||
|
||||
smoke:SetStartSize(10)
|
||||
smoke:SetEndSize(math.Rand(50, 75))
|
||||
|
||||
smoke:SetRoll(math.Rand(-180, 180))
|
||||
smoke:SetRollDelta(math.Rand(-1, 1))
|
||||
|
||||
smoke:SetPos(self:GetPos())
|
||||
smoke:SetVelocity(-self:GetAngles():Forward() * 400 + (VectorRand() * 10))
|
||||
|
||||
smoke:SetColor(200, 200, 200)
|
||||
smoke:SetLighting(true)
|
||||
|
||||
smoke:SetDieTime(math.Rand(0.75, 1.25))
|
||||
|
||||
smoke:SetGravity(Vector(0, 0, 0))
|
||||
|
||||
emitter:Finish()
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:PhysicsUpdate(phys)
|
||||
if self.SpawnTime + self.RocketLifetime < CurTime() then return end
|
||||
|
||||
if self.TargetPos and (self.SteerDelay + self.SpawnTime) <= CurTime() then
|
||||
local v = phys:GetVelocity()
|
||||
|
||||
local steer_amount = self.SteerSpeed * FrameTime()
|
||||
if self.SuperSteerTime + self.StartSuperSteerTime > CurTime() then
|
||||
steer_amount = self.SuperSteerSpeed * FrameTime()
|
||||
end
|
||||
|
||||
local dir = (self.TargetPos - self:GetPos()):GetNormalized()
|
||||
local diff = math.deg(math.acos(dir:Dot(self:GetForward())))
|
||||
local turn_deg = math.min(diff, steer_amount)
|
||||
|
||||
local newang = self:GetAngles()
|
||||
newang:RotateAroundAxis(dir:Cross(self:GetForward()), -turn_deg)
|
||||
|
||||
local brake = turn_deg / steer_amount * self.SteerBrake
|
||||
|
||||
self:SetAngles(Angle(newang.p, newang.y, 0))
|
||||
phys:SetVelocityInstantaneous(self:GetForward() * math.Clamp(v:Length() + (self.Acceleration - brake) * FrameTime(), self.MinSpeed, self.MaxSpeed))
|
||||
elseif self.Acceleration > 0 then
|
||||
phys:SetVelocityInstantaneous(self:GetForward() * math.Clamp(phys:GetVelocity():Length() + self.Acceleration * FrameTime(), self.MinSpeed, self.MaxSpeed))
|
||||
end
|
||||
end
|
||||
|
||||
local gunship = {["npc_combinegunship"] = true, ["npc_combinedropship"] = true, ["npc_helicopter"] = true}
|
||||
|
||||
function ENT:DoTracking()
|
||||
local target = self.LockOnEntity
|
||||
if IsValid(target) then
|
||||
if self.TopAttack and self.TopAttacking then
|
||||
local xyvector = (target:WorldSpaceCenter() - self:GetPos())
|
||||
xyvector.z = 0
|
||||
local dist = xyvector:Length()
|
||||
|
||||
self.TargetPos = target:WorldSpaceCenter() + Vector(0, 0, self.TopAttackHeight)
|
||||
if self.LeadTarget then
|
||||
local dist2 = (self.TargetPos - self:GetPos()):Length()
|
||||
|
||||
local time = dist2 / self:GetVelocity():Length()
|
||||
self.TargetPos = self.TargetPos + (target:GetVelocity() * time)
|
||||
end
|
||||
|
||||
if dist <= self.TopAttackDistance then
|
||||
self.TopAttacking = false
|
||||
self.StartSuperSteerTime = CurTime()
|
||||
end
|
||||
else
|
||||
local dir = (target:WorldSpaceCenter() - self:GetPos()):GetNormalized()
|
||||
local diff = math.deg(math.acos(dir:Dot(self:GetForward())))
|
||||
if diff <= self.SeekerAngle or self.SuperSteerTime + self.StartSuperSteerTime > CurTime() then
|
||||
self.TargetPos = target:WorldSpaceCenter()
|
||||
local dist = (self.TargetPos - self:GetPos()):Length()
|
||||
if self.LeadTarget then
|
||||
local time = dist / self:GetVelocity():Length()
|
||||
self.TargetPos = self.TargetPos + (target:GetVelocity() * time)
|
||||
end
|
||||
|
||||
if self.FlareRedirectChance > 0 and self.NextFlareRedirectTime <= CurTime() and !TacRP.FlareEntities[target:GetClass()] then
|
||||
local flares = ents.FindInSphere(self:GetPos(), 2048)
|
||||
for k, v in pairs(flares) do
|
||||
if (TacRP.FlareEntities[v:GetClass()] or v.IsTacRPFlare) and math.Rand(0, 1) <= self.FlareRedirectChance then
|
||||
self:SwitchTarget(v)
|
||||
break
|
||||
end
|
||||
end
|
||||
self.NextFlareRedirectTime = CurTime() + 0.5
|
||||
end
|
||||
|
||||
if self.SeekerExplodeRange > 0 and diff <= self.SeekerExplodeAngle
|
||||
and self.SteerDelay + self.SpawnTime <= CurTime()
|
||||
and dist < self.SeekerExplodeRange then
|
||||
local tr = util.TraceLine({
|
||||
start = self:GetPos(),
|
||||
endpos = target:GetPos(),
|
||||
filter = self,
|
||||
mask = MASK_SOLID,
|
||||
})
|
||||
if self.SeekerExplodeSnapPosition then
|
||||
self:SetPos(tr.HitPos)
|
||||
end
|
||||
self:PreDetonate(target)
|
||||
end
|
||||
elseif self.NoReacquire then
|
||||
self.LockOnEntity = nil
|
||||
self.TargetPos = nil
|
||||
end
|
||||
end
|
||||
elseif (!IsValid(target) and self.NoReacquire) or target.UnTrackable then
|
||||
self.LockOnEntity = nil
|
||||
self.TargetPos = nil
|
||||
end
|
||||
|
||||
if self.GunshipWorkaround and (self.GunshipCheck or 0 < CurTime()) then
|
||||
self.GunshipCheck = CurTime() + 0.33
|
||||
local tr = util.TraceLine({
|
||||
start = self:GetPos(),
|
||||
endpos = self:GetPos() + (self:GetVelocity() * 6 * engine.TickInterval()),
|
||||
filter = self,
|
||||
mask = MASK_SHOT
|
||||
})
|
||||
if IsValid(tr.Entity) and gunship[tr.Entity:GetClass()] then
|
||||
self:SetPos(tr.HitPos)
|
||||
self:PreDetonate(tr.Entity)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:Think()
|
||||
if !IsValid(self) or self:GetNoDraw() then return end
|
||||
|
||||
if !self.SpawnTime then
|
||||
self.SpawnTime = CurTime()
|
||||
end
|
||||
|
||||
if SERVER and self.SoundHint and CurTime() >= self.SpawnTime + self.SoundHintDelay then
|
||||
self.SoundHint = false // only once
|
||||
sound.EmitHint(SOUND_DANGER, self:GetPos(), self.SoundHintRadius, self.SoundHintDuration, self)
|
||||
end
|
||||
|
||||
if !self.Armed and isnumber(self.TimeFuse) and self.SpawnTime + self.TimeFuse < CurTime() then
|
||||
self.ArmTime = CurTime()
|
||||
self.Armed = true
|
||||
end
|
||||
|
||||
if self.Armed and self.ArmTime + self.Delay < CurTime() then
|
||||
self:PreDetonate()
|
||||
end
|
||||
|
||||
if self.ExplodeUnderwater and self:WaterLevel() > 0 then
|
||||
self:PreDetonate()
|
||||
end
|
||||
|
||||
if SERVER and self.SpawnTime + self.RocketLifetime > CurTime() then
|
||||
self:DoTracking()
|
||||
end
|
||||
|
||||
self:DoSmokeTrail()
|
||||
|
||||
self:OnThink()
|
||||
|
||||
self:NextThink(CurTime())
|
||||
return true
|
||||
end
|
||||
|
||||
function ENT:Use(ply)
|
||||
if !self.Defusable then return end
|
||||
|
||||
self:EmitSound("TacRP/weapons/rifle_jingle-1.wav")
|
||||
|
||||
if self.PickupAmmo then
|
||||
ply:GiveAmmo(1, self.PickupAmmo, true)
|
||||
end
|
||||
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
function ENT:RemoteDetonate()
|
||||
self:EmitSound("TacRP/weapons/c4/relay_switch-1.wav")
|
||||
|
||||
self.ArmTime = CurTime()
|
||||
self.Armed = true
|
||||
end
|
||||
|
||||
function ENT:PreDetonate(ent)
|
||||
if CLIENT then return end
|
||||
|
||||
if !self.Detonated then
|
||||
self.Detonated = true
|
||||
|
||||
if !IsValid(self.Attacker) and !IsValid(self:GetOwner()) then self.Attacker = game.GetWorld() end
|
||||
|
||||
self:Detonate(ent)
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:Detonate(ent)
|
||||
// fill this in :)
|
||||
end
|
||||
|
||||
function ENT:Impact(data, collider)
|
||||
end
|
||||
|
||||
function ENT:SafetyImpact(data, collider)
|
||||
local attacker = self.Attacker or self:GetOwner()
|
||||
local ang = data.OurOldVelocity:Angle()
|
||||
local fx = EffectData()
|
||||
fx:SetOrigin(data.HitPos)
|
||||
fx:SetNormal(-ang:Forward())
|
||||
fx:SetAngles(-ang)
|
||||
util.Effect("ManhackSparks", fx)
|
||||
|
||||
if IsValid(data.HitEntity) then
|
||||
local dmginfo = DamageInfo()
|
||||
dmginfo:SetAttacker(attacker)
|
||||
dmginfo:SetInflictor(self)
|
||||
dmginfo:SetDamageType(self.ImpactDamageType)
|
||||
dmginfo:SetDamage(self.ImpactDamage * (self.NPCDamage and 0.25 or 1))
|
||||
dmginfo:SetDamageForce(data.OurOldVelocity * 20)
|
||||
dmginfo:SetDamagePosition(data.HitPos)
|
||||
data.HitEntity:TakeDamageInfo(dmginfo)
|
||||
end
|
||||
|
||||
self:EmitSound("weapons/rpg/shotdown.wav", 80)
|
||||
|
||||
if self:GetModel() == "models/weapons/tacint/rocket_deployed.mdl" then
|
||||
for i = 1, 4 do
|
||||
local prop = ents.Create("prop_physics")
|
||||
prop:SetPos(self:GetPos())
|
||||
prop:SetAngles(self:GetAngles())
|
||||
prop:SetModel("models/weapons/tacint/rpg7_shrapnel_p" .. i .. ".mdl")
|
||||
prop:Spawn()
|
||||
prop:GetPhysicsObject():SetVelocityInstantaneous(data.OurNewVelocity * 0.5 + VectorRand() * 75)
|
||||
prop:SetCollisionGroup(COLLISION_GROUP_DEBRIS)
|
||||
SafeRemoveEntityDelayed(prop, 3)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:ImpactTraceAttack(ent, damage, pen)
|
||||
if !IsValid(ent) then return end
|
||||
if ent.LVS then
|
||||
// LVS only does its penetration logic on FireBullets, so we must fire a bullet to trigger it
|
||||
self:SetCollisionGroup(COLLISION_GROUP_DEBRIS) // The projectile blocks the penetration decal?!
|
||||
self:FireBullets({
|
||||
Attacker = self.Attacker or self:GetOwner(),
|
||||
Damage = damage,
|
||||
Tracer = 0,
|
||||
Src = self:GetPos(),
|
||||
Dir = self:GetForward(),
|
||||
HullSize = 16,
|
||||
Distance = 128,
|
||||
IgnoreEntity = self,
|
||||
Callback = function(atk, btr, dmginfo)
|
||||
dmginfo:SetDamageType(DMG_AIRBOAT + DMG_SNIPER) // LVS wants this
|
||||
dmginfo:SetDamageForce(self:GetForward() * pen) // penetration strength
|
||||
end,
|
||||
})
|
||||
else
|
||||
// This is way more consistent because the damage always lands
|
||||
local tr = util.TraceHull({
|
||||
start = self:GetPos(),
|
||||
endpos = self:GetPos() + self:GetForward() * 256,
|
||||
filter = ent,
|
||||
whitelist = true,
|
||||
ignoreworld = true,
|
||||
mask = MASK_ALL,
|
||||
mins = Vector( -8, -8, -8 ),
|
||||
maxs = Vector( 8, 8, 8 ),
|
||||
})
|
||||
local dmginfo = DamageInfo()
|
||||
dmginfo:SetAttacker(self.Attacker or self:GetOwner())
|
||||
dmginfo:SetInflictor(self)
|
||||
dmginfo:SetDamagePosition(self:GetPos())
|
||||
dmginfo:SetDamageForce(self:GetForward() * pen)
|
||||
dmginfo:SetDamageType(DMG_AIRBOAT + DMG_SNIPER)
|
||||
dmginfo:SetDamage(damage)
|
||||
ent:DispatchTraceAttack(dmginfo, tr, self:GetForward())
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:Stuck()
|
||||
end
|
||||
|
||||
function ENT:DrawTranslucent()
|
||||
self:Draw()
|
||||
end
|
||||
|
||||
local mat = Material("effects/ar2_altfire1b")
|
||||
|
||||
function ENT:Draw()
|
||||
if self:GetOwner() == LocalPlayer() and (self.SpawnTime + 0.05) > CurTime() then return end
|
||||
|
||||
self:DrawModel()
|
||||
|
||||
if self.FlareColor then
|
||||
local mult = self.SafetyFuse and math.Clamp((CurTime() - (self.SpawnTime + self.SafetyFuse)) / self.SafetyFuse, 0.1, 1) or 1
|
||||
render.SetMaterial(mat)
|
||||
render.DrawSprite(self:GetPos() + (self:GetAngles():Forward() * -16), mult * math.Rand(self.FlareSizeMin, self.FlareSizeMax), mult * math.Rand(self.FlareSizeMin, self.FlareSizeMax), self.FlareColor)
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:SwitchTarget(target)
|
||||
if IsValid(self.LockOnEntity) then
|
||||
if isfunction(self.LockOnEntity.OnLaserLock) then
|
||||
self.LockOnEntity:OnLaserLock(false)
|
||||
end
|
||||
end
|
||||
|
||||
self.LockOnEntity = target
|
||||
|
||||
if IsValid(self.LockOnEntity) then
|
||||
if isfunction(self.LockOnEntity.OnLaserLock) then
|
||||
self.LockOnEntity:OnLaserLock(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
hook.Add("EntityTakeDamage", "tacrp_proj_collision", function(ent, dmginfo)
|
||||
if IsValid(dmginfo:GetInflictor())
|
||||
and scripted_ents.IsBasedOn(dmginfo:GetInflictor():GetClass(), "tacrp_proj_base")
|
||||
and dmginfo:GetDamageType() == DMG_CRUSH then dmginfo:SetDamage(0) return true end
|
||||
end)
|
||||
Reference in New Issue
Block a user