zombiesurvival-evolved/gamemodes/zombiesurvival/gamemode/obj_entity_extend.lua
2015-10-22 04:01:26 -04:00

392 lines
10 KiB
Lua

local meta = FindMetaTable("Entity")
if not meta then return end
local LASTHITCLIPHULL = false
local ClipHullBulletsResult
local ClipHullBulletsReturn = {effects = false, damage = false}
local ClipHullBullets = {
Damage = 0,
Force = 0,
Tracer = 0,
Callback = function(from, tr, dmginfo)
ClipHullBulletsResult = tr
return ClipHullBulletsReturn
end
}
function meta:ClipHullTraceHull(distance, size, start, dir)
start = start or self:GetShootPos()
dir = dir or self:GetAimVector()
ClipHullBullets.Src = start
ClipHullBullets.Dir = dir
ClipHullBullets.HullSize = size
ClipHullBulletsResult = nil
self:FireBullets(ClipHullBullets)
LASTHITCLIPHULL = false
if ClipHullBulletsResult and ClipHullBulletsResult.HitNonWorld and ClipHullBulletsResult.Entity:IsValid() and ClipHullBulletsResult.Entity:IsPlayer() and ClipHullBulletsResult.HitPos:Distance(start) <= distance then
LASTHITCLIPHULL = true
return ClipHullBulletsResult
end
return self:TraceHull(distance, mask, size, filter, start)
end
function meta:ClipHullMeleeTrace(distance, size, filter, start)
local cliphullpretrace = self:ClipHullTraceHull(distance, size, start)
if cliphullpretrace and LASTHITCLIPHULL then
return cliphullpretrace
end
self:LagCompensation(true)
local t = self:MeleeTrace(distance, size, filter, start)
self:LagCompensation(false)
return t
end
-- Extremely shitty workaround for util trace functions not using clip hulls
function meta:PenetratingClipHullMeleeTrace(distance, size, prehit, start, dir)
local t
local cliphullpretrace = self:ClipHullTraceHull(distance, size, start, dir)
self:LagCompensation(true)
t = self:PenetratingMeleeTrace(distance, size, prehit, start, dir)
if cliphullpretrace and LASTHITCLIPHULL and cliphullpretrace.Entity ~= prehit then
table.insert(t, 1, cliphullpretrace)
end
self:LagCompensation(false)
return t
end
function meta:ApplyPlayerProperties(ply)
self.GetPlayerColor = function() return ply:GetPlayerColor() end
self:SetBodygroup( ply:GetBodygroup(1), 1 )
self:SetMaterial( ply:GetMaterial() )
self:SetSkin( ply:GetSkin() or 1 )
end
function meta:GetVolume()
local mins, maxs = self:OBBMins(), self:OBBMaxs()
return (maxs.x - mins.x) + (maxs.y - mins.y) + (maxs.z - mins.z)
end
function meta:TakeSpecialDamage(damage, damagetype, attacker, inflictor, hitpos, damageforce)
attacker = attacker or self
if not attacker:IsValid() then attacker = self end
inflictor = inflictor or attacker
if not inflictor:IsValid() then inflictor = attacker end
local nearest = self:NearestPoint(inflictor:NearestPoint(self:LocalToWorld(self:OBBCenter())))
local dmginfo = DamageInfo()
dmginfo:SetDamage(damage)
dmginfo:SetAttacker(attacker)
dmginfo:SetInflictor(inflictor)
dmginfo:SetDamagePosition(hitpos or nearest)
dmginfo:SetDamageType(damagetype)
if damageforce then
dmginfo:SetDamageForce(damageforce)
end
self:TakeDamageInfo(dmginfo)
return dmginfo
end
function meta:NearestBone(pos)
local count = self:GetBoneCount()
if count == 0 then return end
local nearest
local nearestdist
for boneid = 1, count - 1 do
local bonepos, boneang = self:GetBonePositionMatrixed(boneid)
local dist = bonepos:Distance(pos)
if not nearest or dist < nearestdist then
nearest = boneid
nearestdist = dist
end
end
return nearest
end
function meta:IsProjectile()
return self:GetCollisionGroup() == COLLISION_GROUP_PROJECTILE or self.m_IsProjectile
end
function meta:ResetBones(onlyscale)
local v = Vector(1, 1, 1)
if onlyscale then
for i=0, self:GetBoneCount() - 1 do
self:ManipulateBoneScale(i, v)
end
else
local a = Angle(0, 0, 0)
for i=0, self:GetBoneCount() - 1 do
self:ManipulateBoneScale(i, v)
self:ManipulateBoneAngles(i, a)
self:ManipulateBonePosition(i, vector_origin)
end
end
end
function meta:SetBarricadeHealth(m)
self:SetDTFloat(1, m)
end
function meta:GetBarricadeHealth()
return self:GetDTFloat(1)
end
function meta:SetMaxBarricadeHealth(m)
self:SetDTFloat(2, m)
end
function meta:GetMaxBarricadeHealth()
return self:GetDTFloat(2)
end
function meta:SetBarricadeRepairs(m)
self:SetDTFloat(3, m)
end
function meta:GetBarricadeRepairs()
return self:GetDTFloat(3)
end
function meta:GetMaxBarricadeRepairs()
return self:GetMaxBarricadeHealth() * 1.5
end
function meta:GetBonePositionMatrixed(index)
local matrix = self:GetBoneMatrix(index)
if matrix then
return matrix:GetTranslation(), matrix:GetAngles()
end
return self:GetPos(), self:GetAngles()
end
-- This needs to be done otherwise the physics might crash.
function meta:CollisionRulesChanged()
if not self.m_OldCollisionGroup then self.m_OldCollisionGroup = self:GetCollisionGroup() end
self:SetCollisionGroup(self.m_OldCollisionGroup == COLLISION_GROUP_DEBRIS and COLLISION_GROUP_WORLD or COLLISION_GROUP_DEBRIS)
self:SetCollisionGroup(self.m_OldCollisionGroup)
self.m_OldCollisionGroup = nil
end
function meta:IsNailed()
if self:IsValid() then -- In case we're the world.
for _, nail in pairs(ents.FindByClass("prop_nail")) do
if nail:IsValid() and (nail.GetAttachEntity and nail:GetAttachEntity() == self or nail.GetBaseEntity and nail:GetBaseEntity() == self) then
return true
end
end
end
return false
end
function meta:GetAlpha()
return self:GetColor().a
end
function meta:SetAlpha(a)
local col = self:GetColor()
col.a = a
self:SetColor(col)
end
local function barricadetimer(self, timername)
if self:IsValid() then
for _, e in pairs(ents.FindInBox(self:WorldSpaceAABB())) do
if e and e:IsValid() and e:IsPlayer() and e:Alive() then
return
end
end
self.IsBarricadeObject = nil
self:CollisionRulesChanged()
end
timer.Destroy(timername)
end
function meta:TemporaryBarricadeObject()
if self.IsBarricadeObject then return end
for _, e in pairs(ents.FindInBox(self:WorldSpaceAABB())) do
if e and e:IsValid() and e:IsPlayer() and e:Alive() then
self.IsBarricadeObject = true
self:CollisionRulesChanged()
local timername = "TemporaryBarricadeObject"..self:GetCreationID()
timer.CreateEx(timername, 0, 0, barricadetimer, self, timername)
return
end
end
end
function meta:IsBarricadeProp()
return self.IsBarricadeObject or self:IsNailed()
end
function meta:GetHolder()
for _, ent in pairs(ents.FindByClass("status_human_holding")) do
if ent:GetObject() == self then
local owner = ent:GetOwner()
if owner:IsPlayer() and owner:Alive() then return owner, ent end
end
end
end
function meta:RemoveNextFrame(time)
self.Removing = true
self:Fire("kill", "", time or 0.01)
end
function meta:ThrowFromPosition(pos, force, noknockdown)
if force == 0 or self:IsProjectile() or self.NoThrowFromPosition then return false end
if self:IsPlayer() and self:ActiveBarricadeGhosting() then return false end
if self:GetMoveType() == MOVETYPE_VPHYSICS then
local phys = self:GetPhysicsObject()
if phys:IsValid() and phys:IsMoveable() then
local nearest = self:NearestPoint(pos)
phys:ApplyForceOffset(force * 50 * (nearest - pos):GetNormalized(), nearest)
end
return true
elseif self:GetMoveType() >= MOVETYPE_WALK and self:GetMoveType() < MOVETYPE_PUSH then
self:SetGroundEntity(NULL)
if SERVER and not noknockdown and self:IsPlayer() then
local absforce = math.abs(force)
if absforce >= 512 or self.Clumsy and self:Team() == TEAM_HUMAN and absforce >= 32 then
self:KnockDown()
end
end
self:SetVelocity(force * (self:LocalToWorld(self:OBBCenter()) - pos):GetNormalized())
return true
end
end
function meta:ThrowFromPositionSetZ(pos, force, zmul, noknockdown)
if force == 0 or self:IsProjectile() or self.NoThrowFromPosition then return false end
zmul = zmul or 0.7
if self:IsPlayer() and self:ActiveBarricadeGhosting() then return false end
if self:GetMoveType() == MOVETYPE_VPHYSICS then
local phys = self:GetPhysicsObject()
if phys:IsValid() and phys:IsMoveable() then
local nearest = self:NearestPoint(pos)
local dir = nearest - pos
dir.z = 0
dir:Normalize()
dir.z = zmul
phys:ApplyForceOffset(force * 50 * dir, nearest)
end
return true
elseif self:GetMoveType() >= MOVETYPE_WALK and self:GetMoveType() < MOVETYPE_PUSH then
self:SetGroundEntity(NULL)
if SERVER and not noknockdown and self:IsPlayer() then
local absforce = math.max(math.abs(force) * math.abs(zmul), math.abs(force))
if absforce >= 512 or self.Clumsy and self:Team() == TEAM_HUMAN and absforce >= 32 then
self:KnockDown()
end
end
local dir = self:LocalToWorld(self:OBBCenter()) - pos
dir.z = 0
dir:Normalize()
dir.z = zmul
self:SetVelocity(force * dir)
return true
end
end
util.PrecacheSound("player/pl_pain5.wav")
util.PrecacheSound("player/pl_pain6.wav")
util.PrecacheSound("player/pl_pain7.wav")
function meta:PoisonDamage(damage, attacker, inflictor, hitpos, noreduction)
damage = damage or 1
local dmginfo = DamageInfo()
if self:IsPlayer() then
if self:Team() ~= TEAM_HUMAN then return end
if self.BuffResistant then
damage = damage / 2
end
self:ViewPunch(Angle(math.random(-10, 10), math.random(-10, 10), math.random(-20, 20)))
self:EmitSound("player/pl_pain"..math.random(5, 7)..".wav")
if SERVER then
self:GiveStatus("poisonrecovery"):AddDamage(math.floor(damage * 0.75))
end
dmginfo:SetDamageType(DMG_ACID)
else
if not noreduction then
damage = damage / 3
end
dmginfo:SetDamageType(DMG_SLASH) -- Fixes not doing damage to props.
end
attacker = attacker or self
inflictor = inflictor or attacker
dmginfo:SetDamagePosition(hitpos or self:NearestPoint(inflictor:NearestPoint(self:LocalToWorld(self:OBBCenter()))))
dmginfo:SetDamage(damage)
dmginfo:SetAttacker(attacker)
dmginfo:SetInflictor(inflictor)
self:TakeDamageInfo(dmginfo)
end
if CLIENT then
function meta:SetModelScaleVector(vec)
local bonecount = self:GetBoneCount()
if bonecount and bonecount > 1 then
local scale
if type(vec) == "number" then
scale = vec
else
scale = math.min(vec.x, vec.y, vec.z)
end
self._ModelScale = Vector(scale, scale, scale)
self:SetModelScale(scale, 0)
else
if type(vec) == "number" then
vec = Vector(vec, vec, vec)
end
self._ModelScale = vec
local m = Matrix()
m:Scale(vec)
self:EnableMatrix("RenderMultiply", m)
end
end
if not meta.TakeDamageInfo then
meta.TakeDamageInfo = function() end
end
if not meta.SetPhysicsAttacker then
meta.SetPhysicsAttacker = function() end
end
end
local OldSequenceDuration = meta.SequenceDuration
function meta:SequenceDuration(seqid)
return OldSequenceDuration(self, seqid) or 0
end