Skip to content

Commit

Permalink
Seat alias entity, bullet mask change
Browse files Browse the repository at this point in the history
New seat alias entity, only present when sitting in a vehicle
- An entity that will attempt to match the player's animation when they sit in a seat, and when present will take over damage to the player as opposed to the seat itself, leaving the seat to protect the player instead
- It is only possible to be hit by ACF bullets (due to mask changes), and nothing else

Bullet mask was changed, brought back the ability for bullets 30mm and below to ignore fences (but done right this time so as to not ignore armor), also added CONTENTS_AUX to the mask used so it'll be easier to find out if a trace is for an ACF bullet when all you have is a mask to identify it (which was unfortunately needed for the new seat alias)

This new alias entity is also able to be seen on a seat when you hover over it with the ACF menu tool

There may be some teething issues with this, so by all means raise issues as they come up
  • Loading branch information
LiddulBOFH committed May 28, 2024
1 parent 24420fe commit 2d0b360
Show file tree
Hide file tree
Showing 8 changed files with 611 additions and 14 deletions.
8 changes: 7 additions & 1 deletion lua/acf/ballistics/ballistics_sv.lua
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,17 @@ function Ballistics.CreateBullet(BulletData)
Bullet.Index = Index
Bullet.LastThink = Clock.CurTime
Bullet.Fuze = Bullet.Fuze and Bullet.Fuze + Clock.CurTime or nil -- Convert Fuze from fuze length to time of detonation
Bullet.Mask = MASK_SOLID -- Note: MASK_SHOT removed for smaller projectiles as it ignores armor
Bullet.Mask = (Bullet.Caliber < 3 and bit.band(MASK_SOLID,MASK_SHOT) or MASK_SOLID) + CONTENTS_AUX -- I hope CONTENTS_AUX isn't used for anything important? I can't find any references outside of the wiki to it so hopefully I can use this
Bullet.Ricochets = 0
Bullet.GroundRicos = 0
Bullet.Color = ColorRand(100, 255)

-- Purely to allow someone to shoot out of a seat without hitting themselves and dying
if IsValid(Bullet.Owner) and Bullet.Owner:InVehicle() and IsValid(Bullet.Owner:GetVehicle().Alias) then
Bullet.Filter[#Bullet.Filter + 1] = Bullet.Owner:GetVehicle()
Bullet.Filter[#Bullet.Filter + 1] = Bullet.Owner:GetVehicle().Alias
end

-- TODO: Make bullets use a metatable instead
function Bullet:GetPenetration()
local Ammo = AmmoTypes.Get(Bullet.Type)
Expand Down
325 changes: 318 additions & 7 deletions lua/acf/core/utilities/util_sv.lua
Original file line number Diff line number Diff line change
Expand Up @@ -624,11 +624,284 @@ do -- Extra overlay text
end
end

do -- Seat alias system
local SeatModel = {
[1] = {
model = "models/chairs_playerstart/sitpose.mdl",
pos = Vector(0,-19.6,20),
ang = Angle(0,90,0)
},
[2] = {
model = "models/chairs_playerstart/jeeppose.mdl",
pos = Vector(0,-39.5,5),
ang = Angle(0,90,0)
},
[3] = {
model = "models/chairs_playerstart/airboatpose.mdl",
pos = Vector(0,-35.4,9.3),
ang = Angle(0,90,0)
},
[4] = {
model = "models/chairs_playerstart/podpose.mdl",
pos = Vector(0,5,6),
ang = Angle(0,90,0)
},
}

-- Because garry's mod wouldn't even be a game without annoying fucking workarounds
-- HL2 vehicles MOVE the fucking normally static "vehicle_feet_passenger0" so we have to do something totally different
local PosOverride = {
["models/airboat.mdl"] = function(Vic)
local SeatPos, SeatAng = Vic:GetPassengerSeatPoint(0)

return Vic:WorldToLocal(SeatPos) - Vector(0.1,-24,-25.5), Vic:WorldToLocalAngles(SeatAng), true
end,
["models/vehicle.mdl"] = function(Vic)
local SeatPos, SeatAng = Vic:GetPassengerSeatPoint(0)

return Vic:WorldToLocal(SeatPos), Vic:WorldToLocalAngles(SeatAng), false
end,
["models/buggy.mdl"] = function(Vic)
local SeatPos, SeatAng = Vic:GetPassengerSeatPoint(0)

return Vic:WorldToLocal(SeatPos), Vic:WorldToLocalAngles(SeatAng), false
end,
["models/vehicles/prisoner_pod_inner.mdl"] = function(Vic)
local SeatPos, SeatAng = Vic:GetPassengerSeatPoint(0)

return Vic:WorldToLocal(SeatPos) - Vector(5,0,6), Vic:WorldToLocalAngles(SeatAng) + Angle(0,-90,0), true
end,
["models/vehicles/driver_pod.mdl"] = function(Vic)
local SeatPos, SeatAng = Vic:GetPassengerSeatPoint(0)

return Vic:WorldToLocal(SeatPos) - Vector(5,0,6), Vic:WorldToLocalAngles(SeatAng) + Angle(0,-90,0), true
end,
["models/chairs_playerstart/pronepose.mdl"] = function(Vic)
local SeatPos, SeatAng = Vic:GetPassengerSeatPoint(0)

return Vic:WorldToLocal(SeatPos) - Vector(0,42,-5), Vic:WorldToLocalAngles(SeatAng) + Angle(0,0,-85), true
end,
["models/lubprops/seat/raceseat2.mdl"] = function(Vic)
local SeatPos, SeatAng = Vic:GetPassengerSeatPoint(0)

-- Close enough, I hate this seat in particular because of the weird offset everything *just has to have*
return Vic:WorldToLocal(SeatPos) + Vector(0,24,-6), Vic:WorldToLocalAngles(SeatAng) + Angle(20,-90,22.5), true
end,
}

local ClassList = {
["prop_vehicle_jeep"] = function(Ply) return Ply:LookupSequence("drive_jeep") end,
["prop_vehicle_airboat"] = function(Ply) return Ply:LookupSequence("drive_airboat") end,
["prop_vehicle_prisoner_pod"] = function(Ply,Vic)
-- Using the same shitty hack that whoever wrote however long ago in garrysmod/gamemodes/base/gamemode/animations.lua #171

if Vic:GetModel() == "models/vehicles/prisoner_pod_inner.mdl" then
return Ply:LookupSequence("drive_pd")
else
return Ply:LookupSequence("sit_rollercoaster")
end
end,
}

local Hitboxes = {
[1] = {
["head"] = {
pos = Vector(0,-18,46),
ang = Angle(0,0,-10),
min = Vector(-4,-6,-6),
max = Vector(4,6,6)
},
["chest"] = {
pos = Vector(0,-22,30),
ang = Angle(0,0,0),
min = Vector(-8,-5.5,-12),
max = Vector(8,6,12)
},
},
[2] = {
["head"] = {
pos = Vector(0,-34,38),
ang = Angle(0,0,0),
min = Vector(-4,-6,-6),
max = Vector(4,6,6)
},
["chest"] = {
pos = Vector(0,-32,20),
ang = Angle(0,0,15),
min = Vector(-8,-5.5,-12),
max = Vector(8,6,12)
},
},
[3] = {
["head"] = {
pos = Vector(0,-31,39),
ang = Angle(0,0,0),
min = Vector(-4,-6,-6),
max = Vector(4,6,6)
},
["chest"] = {
pos = Vector(0,-33,22),
ang = Angle(0,0,10),
min = Vector(-8,-5.5,-12),
max = Vector(8,6,12)
},
},
[4] = {
["head"] = {
pos = Vector(0,-3,73),
ang = Angle(0,0,20),
min = Vector(-4,-6,-6),
max = Vector(4,6,6)
},
["chest"] = {
pos = Vector(0,-0.5,54),
ang = Angle(0,0,0),
min = Vector(-8,-5.5,-12),
max = Vector(8,6,12)
},
}
}

local ArmorHitboxes = {
[1] = {
["helmet"] = {
parent = "head",
min = Vector(-4.5,-6.5,3),
max = Vector(4.5,6.5,6.5)
},
["vest"] = {
parent = "chest",
min = Vector(-7.5,-6,-11),
max = Vector(7.5,6.5,11)
},
},
[2] = {
["helmet"] = {
parent = "head",
min = Vector(-4.5,-6.5,3),
max = Vector(4.5,6.5,6.5)
},
["vest"] = {
parent = "chest",
min = Vector(-7.5,-6,-11),
max = Vector(7.5,6.5,11)
},
},
[3] = {
["helmet"] = {
parent = "head",
min = Vector(-4.5,-6.5,3),
max = Vector(4.5,6.5,6.5)
},
["vest"] = {
parent = "chest",
min = Vector(-7.5,-6,-11),
max = Vector(7.5,6.5,11)
},
},
[4] = {
["helmet"] = {
parent = "head",
min = Vector(-4.5,-6.5,3),
max = Vector(4.5,6.5,6.5)
},
["vest"] = {
parent = "chest",
min = Vector(-7.5,-6,-11),
max = Vector(7.5,6.5,11)
},
}
}

local function RoundVector(Vec,Dec)
return Vector(math.Round(Vec.x,Dec),math.Round(Vec.y,Dec),math.Round(Vec.z,Dec))
end

local function RoundAngle(Ang,Dec)
return Angle(math.Round(Ang.p,Dec),math.Round(Ang.y,Dec),math.Round(Ang.r,Dec))
end

function ACF.PrepareAlias(Vehicle,Ply)
if not IsValid(Vehicle) then return end
if not IsValid(Ply) then return end
if Vehicle._Alias ~= nil then return end
local Alias = {}

-- Every playermodel is a little different, so this has to be done on a per-player basis
local SeqList = {
[Ply:LookupSequence("sit_rollercoaster")] = 1,
[Ply:LookupSequence("sit")] = 1, -- basically the same as sit_rollercoaster? Seems to only be used for PHX Car Seat 1
[Ply:LookupSequence("drive_jeep")] = 2,
[Ply:LookupSequence("drive_airboat")] = 3,
[Ply:LookupSequence("drive_pd")] = 4,
}

local Seq = -1
if Vehicle.HandleAnimation and isfunction(Vehicle.HandleAnimation) then
Seq = Vehicle:HandleAnimation(Ply)

if not SeqList[Seq] then
print("Unhandled sequence, defaulting to sit_rollercoaster")
Seq = -1
end
else
local Class = Vehicle:GetClass()

if ClassList[Class] then
Seq = ClassList[Class](Ply,Vehicle)
end
end

local Pose = (Seq ~= -1) and SeqList[Seq] or 1
Alias.Pose = Pose
local AliasInfo = SeatModel[Pose]
Alias.Model = AliasInfo.model
local Pos = AliasInfo.pos
local Ang = AliasInfo.ang

local AttachmentPos = Vector()
local AttachmentAng = Angle()
local Override = false

if PosOverride[Vehicle:GetModel()] then
AttachmentPos, AttachmentAng, Override = PosOverride[Vehicle:GetModel()](Vehicle)
else
local Attachment = Vehicle:LookupAttachment("vehicle_feet_passenger0")
if Attachment > 0 then
local AttachmentInfo = Vehicle:GetAttachment(Attachment)

AttachmentPos = Vehicle:WorldToLocal(AttachmentInfo.Pos)
AttachmentAng = Vehicle:WorldToLocalAngles(AttachmentInfo.Ang)
end
end

if Override then
Alias.Pos = RoundVector(AttachmentPos,2)
Alias.Ang = RoundAngle(AttachmentAng,2)
else
Alias.Pos = RoundVector(AttachmentPos - Pos,2)
Alias.Ang = RoundAngle(AttachmentAng - Ang,2)
end

Alias.Hitboxes = Hitboxes[Pose]
Alias.ArmorHitboxes = ArmorHitboxes[Pose]
Alias.SeatModel = Vehicle:GetModel()

Vehicle._Alias = Alias
end

function ACF.ApplyAlias(Vehicle,Ply)
ACF.PrepareAlias(Vehicle,Ply)

MakeACF_SeatAlias(Vehicle)
end
end

do -- Special squishy functions
local BoneList = {
head = {boneName = "ValveBiped.Bip01_Head1",group = "head",min = Vector(-6,-6,-4),max = Vector(8,4,4)},

spine = {boneName = "ValveBiped.Bip01_Spine",group = "chest",min = Vector(-6,-4,-9),max = Vector(18,10,9)},
chest = {boneName = "ValveBiped.Bip01_Spine",group = "chest",min = Vector(-6,-4,-9),max = Vector(18,10,9)},

lthigh = {boneName = "ValveBiped.Bip01_L_Thigh",group = "limb",min = Vector(0,-4,-4),max = Vector(18,4,4)},
lcalf = {boneName = "ValveBiped.Bip01_L_Calf",group = "limb",min = Vector(0,-4,-4),max = Vector(18,4,4)},
Expand Down Expand Up @@ -669,13 +942,51 @@ do -- Special squishy functions

local HitBones = {}

for k,v in pairs(Bones) do
local BoneData = CheckList[k]
local BonePos,BoneAng = Entity:GetBonePosition(v)
if Entity:IsPlayer() and Entity:InVehicle() and IsValid(Entity:GetVehicle().Alias) then
local Vehicle = Entity:GetVehicle()
local Alias = Vehicle.Alias
local AliasInfo = Vehicle._Alias
local LocalRay = Alias:WorldToLocal(RayStart)
local LocalRayDir = Alias:WorldToLocal(RayDir + Alias:GetPos())

for k,v in pairs(AliasInfo.Hitboxes) do
local HitPos = util.IntersectRayWithOBB(LocalRay,LocalRayDir * 64, v.pos, v.ang, v.min, v.max)

--debugoverlay.Text(Alias:LocalToWorld(v.pos),k,10,false)
--debugoverlay.BoxAngles(Alias:LocalToWorld(v.pos),v.min,v.max,Alias:LocalToWorldAngles(v.ang),10,Color(255,0,0,50))

if HitPos ~= nil then
HitBones[k] = HitPos
end
end

if Entity:Armor() > 0 then
for k,v in pairs(AliasInfo.ArmorHitboxes) do
local parentBox = AliasInfo.Hitboxes[v.parent]

local HitPos = util.IntersectRayWithOBB(RayStart, RayDir * 64, BonePos, BoneAng, BoneData.min, BoneData.max)
if HitPos ~= nil then
HitBones[k] = HitPos
local HitPos = util.IntersectRayWithOBB(LocalRay,LocalRayDir * 64, parentBox.pos, parentBox.ang, v.min, v.max)

--debugoverlay.Text(Alias:LocalToWorld(parentBox.pos),k,10,false)
--debugoverlay.BoxAngles(Alias:LocalToWorld(parentBox.pos),v.min,v.max,Alias:LocalToWorldAngles(parentBox.ang),10,Color(0,0,255,50))

if HitPos ~= nil then
HitBones[k] = HitPos
end
end
end
else
for k,v in pairs(Bones) do
local BoneData = CheckList[k]
local BonePos,BoneAng = Entity:GetBonePosition(v)

local HitPos = util.IntersectRayWithOBB(RayStart, RayDir * 64, BonePos, BoneAng, BoneData.min, BoneData.max)

--debugoverlay.Text(BonePos,k,5,false)
--debugoverlay.BoxAngles(BonePos,BoneData.min,BoneData.max,BoneAng,5,Color(255,0,0,50))

if HitPos ~= nil then
HitBones[k] = HitPos
end
end
end

Expand Down
11 changes: 7 additions & 4 deletions lua/acf/damage/damage_sv.lua
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,15 @@ end
-- @param DmgInfo A DamageInfo object.
-- @return The output of the DamageResult object.
function Damage.doVehicleDamage(Entity, DmgResult, DmgInfo)
local Driver = Entity:GetDriver()

if IsValid(Driver) then
DmgInfo:SetHitGroup(math.random(0, 7)) -- Hit a random part of the driver
if not IsValid(Entity.Alias) then
local Driver = Entity:GetDriver()

Damage.dealDamage(Driver, DmgResult, DmgInfo) -- Deal direct damage to the driver
if IsValid(Driver) then
DmgInfo:SetHitGroup(math.random(0, 7)) -- Hit a random part of the driver

Damage.dealDamage(Driver, DmgResult, DmgInfo) -- Deal direct damage to the driver
end
end

return Damage.doPropDamage(Entity, DmgResult, DmgInfo) -- We'll just damage it like a regular prop
Expand Down
Loading

0 comments on commit 2d0b360

Please sign in to comment.