mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 21:53:46 +03:00
Upload
This commit is contained in:
411
lua/entities/lvs_base/sv_damagesystem.lua
Normal file
411
lua/entities/lvs_base/sv_damagesystem.lua
Normal file
@@ -0,0 +1,411 @@
|
||||
--[[
|
||||
| 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/
|
||||
--]]
|
||||
|
||||
|
||||
ENT._armorParts = {}
|
||||
ENT._dmgParts = {}
|
||||
|
||||
ENT.DSArmorDamageReduction = 0.1
|
||||
ENT.DSArmorDamageReductionType = DMG_BULLET + DMG_CLUB
|
||||
|
||||
ENT.DSArmorIgnoreDamageType = DMG_SONIC
|
||||
ENT.DSArmorIgnoreForce = 0
|
||||
|
||||
ENT.DSArmorBulletPenetrationAdd = 250
|
||||
|
||||
function ENT:AddDS( data )
|
||||
if not data then return end
|
||||
|
||||
data.pos = data.pos or Vector(0,0,0)
|
||||
data.ang = data.ang or Angle(0,0,0)
|
||||
data.mins = data.mins or Vector(-1,-1,-1)
|
||||
data.maxs = data.maxs or Vector(1,1,1)
|
||||
data.Callback = data.Callback or function( tbl, ent, dmginfo ) end
|
||||
|
||||
debugoverlay.BoxAngles( self:LocalToWorld( data.pos ), data.mins, data.maxs, self:LocalToWorldAngles( data.ang ), 5, Color( 50, 0, 50, 150 ) )
|
||||
|
||||
table.insert( self._dmgParts, data )
|
||||
end
|
||||
|
||||
function ENT:AddDSArmor( data )
|
||||
if not data then return end
|
||||
|
||||
data.pos = data.pos or Vector(0,0,0)
|
||||
data.ang = data.ang or Angle(0,0,0)
|
||||
data.mins = data.mins or Vector(-1,-1,-1)
|
||||
data.maxs = data.maxs or Vector(1,1,1)
|
||||
data.Callback = data.Callback or function( tbl, ent, dmginfo ) end
|
||||
|
||||
debugoverlay.BoxAngles( self:LocalToWorld( data.pos ), data.mins, data.maxs, self:LocalToWorldAngles( data.ang ), 5, Color( 0, 50, 50, 150 ) )
|
||||
|
||||
table.insert( self._armorParts, data )
|
||||
end
|
||||
|
||||
function ENT:CalcComponentDamage( dmginfo )
|
||||
local Len = self:BoundingRadius()
|
||||
local dmgPos = dmginfo:GetDamagePosition()
|
||||
local dmgDir = dmginfo:GetDamageForce():GetNormalized()
|
||||
local dmgPenetration = dmgDir * self.DSArmorBulletPenetrationAdd
|
||||
|
||||
debugoverlay.Line( dmgPos - dmgDir * self.DSArmorBulletPenetrationAdd, dmgPos + dmgPenetration, 4, Color( 0, 0, 255 ) )
|
||||
|
||||
local closestPart
|
||||
local closestDist = Len * 2
|
||||
local HitDistance
|
||||
|
||||
for index, part in ipairs( self._armorParts ) do
|
||||
local mins = part.mins
|
||||
local maxs = part.maxs
|
||||
local pos = self:LocalToWorld( part.pos )
|
||||
local ang = self:LocalToWorldAngles( part.ang )
|
||||
|
||||
local HitPos, HitNormal, Fraction = util.IntersectRayWithOBB( dmgPos, dmgPenetration, pos, ang, mins, maxs )
|
||||
|
||||
if HitPos then
|
||||
debugoverlay.Cross( HitPos, 50, 4, Color( 255, 0, 255 ) )
|
||||
|
||||
local dist = (HitPos - dmgPos):Length()
|
||||
|
||||
if closestDist > dist then
|
||||
closestPart = part
|
||||
closestDist = dist
|
||||
HitDistance = (HitPos - dmgPos):Length()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local lastPartDS
|
||||
local closestPartDS
|
||||
local closestDistDS = Len * 2
|
||||
for index, part in ipairs( self._dmgParts ) do
|
||||
local mins = part.mins
|
||||
local maxs = part.maxs
|
||||
local pos = self:LocalToWorld( part.pos )
|
||||
local ang = self:LocalToWorldAngles( part.ang )
|
||||
|
||||
local HitPos, HitNormal, Fraction = util.IntersectRayWithOBB( dmgPos, dmgPenetration, pos, ang, mins, maxs )
|
||||
|
||||
if HitPos and HitDistance then
|
||||
lastPartDS = part
|
||||
|
||||
if HitDistance < (HitPos - dmgPos):Length() then continue end
|
||||
|
||||
closestPart = nil
|
||||
closestDist = Len * 2
|
||||
end
|
||||
|
||||
if not HitPos then continue end
|
||||
|
||||
debugoverlay.Cross( HitPos, 50, 4, Color( 255, 0, 255 ) )
|
||||
|
||||
local dist = (HitPos - pos):Length()
|
||||
|
||||
if closestDistDS > dist then
|
||||
closestPartDS = part
|
||||
closestDistDS = dist
|
||||
end
|
||||
end
|
||||
|
||||
local Hit = false
|
||||
for index, part in pairs( self._dmgParts ) do
|
||||
local mins = part.mins
|
||||
local maxs = part.maxs
|
||||
local pos = self:LocalToWorld( part.pos )
|
||||
local ang = self:LocalToWorldAngles( part.ang )
|
||||
|
||||
if part == closestPartDS then
|
||||
Hit = true
|
||||
part:Callback( self, dmginfo )
|
||||
debugoverlay.BoxAngles( pos, mins, maxs, ang, 1, Color( 255, 0, 0, 150 ) )
|
||||
end
|
||||
end
|
||||
|
||||
for index, part in pairs( self._armorParts ) do
|
||||
local mins = part.mins
|
||||
local maxs = part.maxs
|
||||
local pos = self:LocalToWorld( part.pos )
|
||||
local ang = self:LocalToWorldAngles( part.ang )
|
||||
|
||||
if part == closestPart then
|
||||
if not part:Callback( self, dmginfo ) then
|
||||
lastPartDS = nil
|
||||
end
|
||||
|
||||
debugoverlay.BoxAngles( pos, mins, maxs, ang, 1, Color( 0, 150, 0, 150 ) )
|
||||
end
|
||||
end
|
||||
|
||||
if lastPartDS then
|
||||
lastPartDS:Callback( self, dmginfo )
|
||||
|
||||
local mins = lastPartDS.mins
|
||||
local maxs = lastPartDS.maxs
|
||||
local pos = self:LocalToWorld( lastPartDS.pos )
|
||||
local ang = self:LocalToWorldAngles( lastPartDS.ang )
|
||||
|
||||
debugoverlay.BoxAngles( pos, mins, maxs, ang, 1, Color( 255, 0, 0, 150 ) )
|
||||
|
||||
Hit = false
|
||||
end
|
||||
|
||||
return Hit
|
||||
end
|
||||
|
||||
function ENT:CalcDamage( dmginfo )
|
||||
if dmginfo:IsDamageType( self.DSArmorIgnoreDamageType ) then return end
|
||||
|
||||
if dmginfo:IsDamageType( self.DSArmorDamageReductionType ) then
|
||||
if dmginfo:GetDamage() ~= 0 then
|
||||
dmginfo:ScaleDamage( self.DSArmorDamageReduction )
|
||||
|
||||
dmginfo:SetDamage( math.max(dmginfo:GetDamage(),1) )
|
||||
end
|
||||
end
|
||||
|
||||
if dmginfo:IsDamageType( DMG_BLAST ) then
|
||||
local Inflictor = dmginfo:GetInflictor()
|
||||
|
||||
if IsValid( Inflictor ) and isfunction( Inflictor.GetEntityFilter ) then
|
||||
for ents, _ in pairs( Inflictor:GetEntityFilter() ) do
|
||||
if ents == self then return end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local IsFireDamage = dmginfo:IsDamageType( DMG_BURN )
|
||||
local IsCollisionDamage = dmginfo:GetDamageType() == (DMG_CRUSH + DMG_VEHICLE)
|
||||
local CriticalHit = false
|
||||
|
||||
if dmginfo:GetDamageForce():Length() < self.DSArmorIgnoreForce and not IsFireDamage then return end
|
||||
|
||||
if not IsCollisionDamage then
|
||||
CriticalHit = self:CalcComponentDamage( dmginfo )
|
||||
end
|
||||
|
||||
local Damage = dmginfo:GetDamage()
|
||||
|
||||
if Damage <= 0 then return end
|
||||
|
||||
local CurHealth = self:GetHP()
|
||||
|
||||
local NewHealth = math.Clamp( CurHealth - Damage, -self:GetMaxHP(), self:GetMaxHP() )
|
||||
|
||||
self:SetHP( NewHealth )
|
||||
|
||||
if self:IsDestroyed() then return end
|
||||
|
||||
local Attacker = dmginfo:GetAttacker()
|
||||
|
||||
if IsValid( Attacker ) and Attacker:IsPlayer() and not IsFireDamage then
|
||||
net.Start( "lvs_hitmarker" )
|
||||
net.WriteBool( CriticalHit )
|
||||
net.Send( Attacker )
|
||||
end
|
||||
|
||||
if Damage > 1 and not IsCollisionDamage and not IsFireDamage then
|
||||
net.Start( "lvs_hurtmarker" )
|
||||
net.WriteFloat( math.min( Damage / 50, 1 ) )
|
||||
net.Send( self:GetEveryone() )
|
||||
end
|
||||
|
||||
if NewHealth <= 0 then
|
||||
self:SetDestroyed( IsCollisionDamage )
|
||||
|
||||
self:ClearPDS()
|
||||
|
||||
self.FinalAttacker = dmginfo:GetAttacker()
|
||||
self.FinalInflictor = dmginfo:GetInflictor()
|
||||
|
||||
local Attacker = self.FinalAttacker
|
||||
if IsValid( Attacker ) and Attacker:IsPlayer() then
|
||||
net.Start( "lvs_killmarker" )
|
||||
net.Send( Attacker )
|
||||
end
|
||||
|
||||
local ExplodeTime = self:PreExplode( math.Clamp((self:GetVelocity():Length() - 200) / 200,1.5,16) )
|
||||
|
||||
timer.Simple( ExplodeTime, function()
|
||||
if not IsValid( self ) then return end
|
||||
self:Explode()
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:PreExplode( ExplodeTime )
|
||||
self:OnStartExplosion()
|
||||
|
||||
local PhysObj = self:GetPhysicsObject()
|
||||
|
||||
if not IsValid( PhysObj ) then return 0 end
|
||||
|
||||
self:OnStartFireTrail( PhysObj, ExplodeTime )
|
||||
|
||||
return ExplodeTime
|
||||
end
|
||||
|
||||
function ENT:FindDS( PosToCheck, RadiusAdd )
|
||||
|
||||
if not isnumber( RadiusAdd ) then
|
||||
RadiusAdd = 1
|
||||
end
|
||||
|
||||
local closestPart
|
||||
local closestDist = 50000
|
||||
|
||||
local ToCenter = (self:LocalToWorld( self:OBBCenter() ) - PosToCheck):GetNormalized()
|
||||
|
||||
debugoverlay.Cross( PosToCheck, 50, 4, Color( 255, 255, 0 ) )
|
||||
|
||||
for _, tbl in ipairs( { self._armorParts, self._dmgParts } ) do
|
||||
for index, part in ipairs( tbl ) do
|
||||
local mins = part.mins
|
||||
local maxs = part.maxs
|
||||
local pos = self:LocalToWorld( part.pos )
|
||||
local ang = self:LocalToWorldAngles( part.ang )
|
||||
|
||||
local HitPos, HitNormal, Fraction = util.IntersectRayWithOBB( PosToCheck, ToCenter * RadiusAdd, pos, ang, mins, maxs )
|
||||
|
||||
if HitPos then
|
||||
local dist = (HitPos - PosToCheck):Length()
|
||||
|
||||
if closestDist > dist then
|
||||
closestPart = part
|
||||
closestDist = dist
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if closestPart then
|
||||
local mins = closestPart.mins
|
||||
local maxs = closestPart.maxs
|
||||
local pos = self:LocalToWorld( closestPart.pos )
|
||||
local ang = self:LocalToWorldAngles( closestPart.ang )
|
||||
debugoverlay.BoxAngles( pos, mins, maxs, ang, 1, Color( 255, 255, 0, 150 ) )
|
||||
end
|
||||
|
||||
return closestPart
|
||||
end
|
||||
|
||||
function ENT:DamageThink()
|
||||
if self.MarkForDestruction then
|
||||
self:Explode()
|
||||
end
|
||||
|
||||
if self:IsDestroyed() then
|
||||
if self:GetVelocity():Length() < 800 then
|
||||
self:Explode()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:HurtPlayer( ply, dmg, attacker, inflictor )
|
||||
if not IsValid( ply ) then return end
|
||||
|
||||
if not IsValid( attacker ) then
|
||||
attacker = game.GetWorld()
|
||||
end
|
||||
|
||||
if not IsValid( inflictor ) then
|
||||
inflictor = game.GetWorld()
|
||||
end
|
||||
|
||||
local dmginfo = DamageInfo()
|
||||
dmginfo:SetDamage( dmg )
|
||||
dmginfo:SetAttacker( attacker )
|
||||
dmginfo:SetInflictor( inflictor )
|
||||
dmginfo:SetDamageType( DMG_DIRECT )
|
||||
|
||||
ply:TakeDamageInfo( dmginfo )
|
||||
end
|
||||
|
||||
function ENT:Explode()
|
||||
if self.ExplodedAlready then return end
|
||||
|
||||
self.ExplodedAlready = true
|
||||
|
||||
local Driver = self:GetDriver()
|
||||
|
||||
if IsValid( Driver ) then
|
||||
self:HurtPlayer( Driver, Driver:Health() + Driver:Armor(), self.FinalAttacker, self.FinalInflictor )
|
||||
end
|
||||
|
||||
if istable( self.pSeats ) then
|
||||
for _, pSeat in pairs( self.pSeats ) do
|
||||
if not IsValid( pSeat ) then continue end
|
||||
|
||||
local psgr = pSeat:GetDriver()
|
||||
if not IsValid( psgr ) then continue end
|
||||
|
||||
self:HurtPlayer( psgr, psgr:Health() + psgr:Armor(), self.FinalAttacker, self.FinalInflictor )
|
||||
end
|
||||
end
|
||||
|
||||
self:OnFinishExplosion()
|
||||
|
||||
self:Remove()
|
||||
end
|
||||
|
||||
function ENT:OnStartExplosion()
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( self:GetPos() )
|
||||
util.Effect( "lvs_explosion_nodebris", effectdata )
|
||||
end
|
||||
|
||||
function ENT:OnFinishExplosion()
|
||||
local ent = ents.Create( "lvs_destruction" )
|
||||
|
||||
if not IsValid( ent ) then return end
|
||||
|
||||
ent:SetModel( self:GetModel() )
|
||||
ent:SetPos( self:GetPos() )
|
||||
ent:SetAngles( self:GetAngles() )
|
||||
ent.GibModels = self.GibModels
|
||||
ent.Vel = self:GetVelocity()
|
||||
ent:Spawn()
|
||||
ent:Activate()
|
||||
end
|
||||
|
||||
function ENT:OnStartFireTrail( PhysObj, ExplodeTime )
|
||||
local effectdata = EffectData()
|
||||
effectdata:SetOrigin( self:GetPos() )
|
||||
effectdata:SetStart( PhysObj:GetMassCenter() )
|
||||
effectdata:SetEntity( self )
|
||||
effectdata:SetScale( (self.FireTrailScale or 1) )
|
||||
effectdata:SetMagnitude( ExplodeTime )
|
||||
util.Effect( "lvs_firetrail", effectdata )
|
||||
end
|
||||
|
||||
function ENT:IsDestroyed()
|
||||
return self.Destroyed == true
|
||||
end
|
||||
|
||||
function ENT:OnDestroyed()
|
||||
end
|
||||
|
||||
util.AddNetworkString( "lvs_vehicle_destroy" )
|
||||
|
||||
function ENT:SetDestroyed( SuppressOnDestroy )
|
||||
if self.Destroyed then return end
|
||||
|
||||
self.Destroyed = true
|
||||
|
||||
hook.Run( "LVS.UpdateRelationship", self )
|
||||
|
||||
if SuppressOnDestroy then return end
|
||||
|
||||
self:OnDestroyed()
|
||||
|
||||
net.Start("lvs_vehicle_destroy")
|
||||
net.WriteEntity( self )
|
||||
net.SendPAS( self:GetPos() )
|
||||
end
|
||||
|
||||
include("sv_damagesystem_armor.lua")
|
||||
Reference in New Issue
Block a user