dobrograd-13-06-2022/garrysmod/addons/util-dlib/lua/dlib/util/combathelper.lua
Jonny_Bro (Nikita) e4d5311906 first commit
2023-11-16 15:01:19 +05:00

241 lines
5.8 KiB
Lua

-- Copyright (C) 2017-2020 DBotThePony
-- 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 IsValid = FindMetaTable('Entity').IsValid
local type = type
local NULL = NULL
local table = table
DLib.combat = DLib.combat or {}
local combat = DLib.combat
--[[
@doc
@fname DLib.combat.findWeapon
@args CTakeDamageInfo dmginfo
@returns
Weapon
Entity: attacker
Entity: inflictor
]]
function combat.findWeapon(dmginfo)
local attacker, inflictor = dmginfo:GetAttacker(), dmginfo:GetInflictor()
if not IsValid(attacker) or not IsValid(inflictor) then return NULL, attacker, inflictor end
if type(attacker) ~= 'Player' or not (type(inflictor) == 'Weapon' or attacker == inflictor) then return end
local weapon = type(inflictor) == 'Weapon' and inflictor or attacker:GetActiveWeapon()
return weapon, attacker, inflictor
end
local function interval(val, min, max)
return val > min and val <= max
end
--[[
@doc
@fname DLib.combat.inPVS
@args Entity pointFrom, Entity pointTo, Angle eyes = pointFrom:EyeAnglesFixed(), number yawLimit = 60, number pitchLimit = 60
@desc
Despite function's name, this only checks whenever pointFrom can see on screen pointTo
using eye angles check assuming they have direct line of sight to each other
@enddesc
@returns
boolean
]]
function combat.inPVS(point1, point2, eyes, yawLimit, pitchLimit)
if type(point1) ~= 'Vector' then
if point1.EyeAnglesFixed then
eyes = eyes or point1:EyeAnglesFixed()
elseif point1.EyeAngles then
eyes = eyes or point1:EyeAngles()
end
point1 = point1:EyePos()
end
if type(point2) ~= 'Vector' then
point2 = point2:EyePos()
end
yawLimit = yawLimit or 60
pitchLimit = pitchLimit or 60
local ang = (point2 - point1):Angle()
local diffPith = ang.p:AngleDifference(eyes.p)
local diffYaw = ang.y:AngleDifference(eyes.y)
return interval(diffYaw, -yawLimit, yawLimit) and interval(diffPith, -pitchLimit, pitchLimit)
end
--[[
@doc
@fname DLib.combat.turnAngle
@args Entity pointFrom, Entity pointTo, Angle eyes = pointFrom:EyeAnglesFixed()
@returns
number: pitch delta
number: yaw delta
]]
function combat.turnAngle(point1, point2, eyes)
if type(point1) ~= 'Vector' then
if point1.EyeAnglesFixed then
eyes = eyes or point1:EyeAnglesFixed()
elseif point1.EyeAngles then
eyes = eyes or point1:EyeAngles()
end
point1 = point1:EyePos()
end
if type(point2) ~= 'Vector' then
point2 = point2:EyePos()
end
local ang = (point2 - point1):Angle()
return ang.p:AngleDifference(eyes.p), ang.y:AngleDifference(eyes.y)
end
--[[
@doc
@fname DLib.combat.findWeaponAlt
@args CTakeDamageInfo dmginfo
@returns
Weapon
Entity: attacker
Entity: inflictor
]]
function combat.findWeaponAlt(dmginfo)
local attacker, inflictor = dmginfo:GetAttacker(), dmginfo:GetInflictor()
local weapon = inflictor
if not IsValid(inflictor) and IsValid(attacker) then
inflictor = attacker
weapon = attacker
end
if not IsValid(attacker) or not IsValid(inflictor) then
return inflictor, attacker, inflictor
end
if type(inflictor) ~= 'Weapon' and attacker.GetActiveWeapon then
inflictor = attacker:GetActiveWeapon()
weapon = inflictor
end
return weapon, attacker, inflictor
end
--[[
@doc
@fname DLib.combat.detect
@args CTakeDamageInfo dmginfo
@returns
Entity: attacker
Entity: weapon or inflictor
Entity: inflictor
]]
function combat.detect(dmginfo)
local weapon, attacker, inflictor = combat.findWeapon(dmginfo)
if not IsValid(weapon) then
weapon = inflictor
end
return attacker, weapon, inflictor
end
--[[
@doc
@fname DLib.combat.findPlayers
@args Entity self
@desc
Attempts to find all players involved within certain entity. This can be a vehicle from another mod for example
(SCars or Simfphys or even Neurotec)
**This also include players who are spectating this entity**
@enddesc
@returns
table: of players found or false, if self is NULL
]]
function combat.findPlayers(self)
if not IsValid(self) then
return false
end
local specs = {}
for i, ply in ipairs(player.GetAll()) do
if ply ~= self and ply:GetObserverTarget() == self then
table.insert(specs, ply)
end
end
if type(self) == 'Player' then
table.insert(specs, self)
return specs
end
if type(self) == 'Vehicle' then
local driver = self:GetDriver()
if not IsValid(driver) then
return #specs ~= 0 and specs
end
table.insert(specs, driver)
return specs
end
local MEM = {}
local iterate = {self}
while #iterate > 0 do
local ent = table.remove(iterate)
if MEM[ent] then
goto CONTINUE
end
MEM[ent] = true
for i, ent2 in ipairs(self:GetChildren()) do
if type(ent2) == 'Player' then
table.insert(specs, ent2)
elseif type(ent2) == 'Vehicle' then
local driver = ent2:GetDriver()
if IsValid(driver) then
table.insert(specs, driver)
end
else
table.insert(iterate, ent2)
end
end
::CONTINUE::
end
return #specs ~= 0 and table.deduplicate(specs) or false
end