210 lines
5.8 KiB
Lua
210 lines
5.8 KiB
Lua
SitAnywhere = SitAnywhere or {}
|
|
SitAnywhere.NET = {
|
|
["SitWantedAng"] = 0,
|
|
["SitRequestExit"] = 1,
|
|
}
|
|
|
|
SitAnywhere.ClassBlacklist = {
|
|
["gmod_wire_keyboard"] = true,
|
|
["prop_combine_ball"] = true
|
|
}
|
|
|
|
SitAnywhere.DoNotParent = {
|
|
["yava_chunk"] = true
|
|
}
|
|
|
|
SitAnywhere.ModelBlacklist = {}
|
|
|
|
local EMETA = FindMetaTable("Entity")
|
|
|
|
function SitAnywhere.GetAreaProfile(pos, resolution, simple)
|
|
local filter = player.GetAll()
|
|
local dists = {}
|
|
local distsang = {}
|
|
local ang_smallest_hori = nil
|
|
local smallest_hori = 90000
|
|
local angPerIt = (360 / resolution)
|
|
|
|
for I = 0, 360, angPerIt do
|
|
local rad = math.rad(I)
|
|
local dir = Vector(math.cos(rad), math.sin(rad), 0)
|
|
local trace = util.QuickTrace(pos + dir * 20 + Vector(0,0,5), Vector(0,0,-15000), filter)
|
|
trace.HorizontalTrace = util.QuickTrace(pos + Vector(0,0,5), dir * 1000, filter)
|
|
trace.Distance = trace.StartPos:Distance(trace.HitPos)
|
|
trace.Distance2 = trace.HorizontalTrace.StartPos:Distance(trace.HorizontalTrace.HitPos)
|
|
trace.ang = I
|
|
|
|
if (not trace.Hit or trace.Distance > 14) and (not trace.HorizontalTrace.Hit or trace.Distance2 > 20) then
|
|
if simple then return true end
|
|
table.insert(dists, trace)
|
|
end
|
|
|
|
if trace.Distance2 < smallest_hori and (not trace.HorizontalTrace.Hit or trace.Distance2 > 3) then
|
|
smallest_hori = trace.Distance2
|
|
ang_smallest_hori = I
|
|
end
|
|
distsang[I] = trace
|
|
end
|
|
|
|
if simple then return false end
|
|
return dists, distsang, ang_smallest_hori, smallest_hori
|
|
end
|
|
|
|
function SitAnywhere.CheckValidAngForSit(pos, surfaceAng, ang)
|
|
local rad = math.rad(ang)
|
|
local dir = Vector(math.cos(rad), math.sin(rad), 0)
|
|
local trace2 = util.TraceLine({
|
|
start = pos - dir * (20 - .5) + surfaceAng:Forward() * 5,
|
|
endpos = pos - dir * (20 - .5) + surfaceAng:Forward() * -160,
|
|
filter = player.GetAll()
|
|
})
|
|
|
|
local hor_trace = util.TraceLine({
|
|
start = pos + Vector(0, 0, 5),
|
|
endpos = pos + Vector(0, 0, 5) - dir * 1600,
|
|
filter = player.GetAll()
|
|
})
|
|
|
|
return hor_trace.StartPos:Distance(hor_trace.HitPos) > 20 and trace2.StartPos:Distance(trace2.HitPos) > 14
|
|
end
|
|
|
|
-- Настройки через ix.config
|
|
if SERVER then
|
|
ix.config.Add("sitEntMode", 3, "Режим сидения на объектах: 0=нет, 1=только мировые, 2=свои+мировые, 3=любые", nil, {
|
|
data = {min = 0, max = 3},
|
|
category = "Sit Anywhere"
|
|
})
|
|
end
|
|
|
|
local function GetSitOnEntsMode()
|
|
if SERVER then
|
|
return ix.config.Get("sitEntMode", 3)
|
|
end
|
|
return 3
|
|
end
|
|
|
|
local blacklist = SitAnywhere.ClassBlacklist
|
|
local model_blacklist = SitAnywhere.ModelBlacklist
|
|
|
|
function SitAnywhere.ValidSitTrace(ply, EyeTrace)
|
|
if not EyeTrace.Hit then return false end
|
|
if EyeTrace.HitPos:Distance(EyeTrace.StartPos) > 100 then return false end
|
|
|
|
local t = hook.Run("CheckValidSit", ply, EyeTrace)
|
|
if t == false or t == true then
|
|
return t
|
|
end
|
|
|
|
local mode = GetSitOnEntsMode()
|
|
|
|
if not EyeTrace.HitWorld and mode == 0 then return false end
|
|
if not EyeTrace.HitWorld and blacklist[string.lower(EyeTrace.Entity:GetClass())] then return false end
|
|
if not EyeTrace.HitWorld and EyeTrace.Entity:GetModel() and model_blacklist[string.lower(EyeTrace.Entity:GetModel())] then return false end
|
|
|
|
if EMETA.CPPIGetOwner and mode >= 1 then
|
|
if mode == 1 then
|
|
if not EyeTrace.HitWorld then
|
|
local owner = EyeTrace.Entity:CPPIGetOwner()
|
|
if type(owner) == "Player" and owner ~= nil and owner:IsValid() and owner:IsPlayer() then
|
|
return false
|
|
end
|
|
end
|
|
elseif mode == 2 then
|
|
if not EyeTrace.HitWorld then
|
|
local owner = EyeTrace.Entity:CPPIGetOwner()
|
|
if type(owner) == "Player" and owner ~= nil and owner:IsValid() and owner:IsPlayer() and owner ~= ply then
|
|
return false
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
local seatClass = "prop_vehicle_prisoner_pod"
|
|
local PMETA = FindMetaTable("Player")
|
|
|
|
function PMETA:GetSitters()
|
|
local seats, holders = {}, {}
|
|
|
|
local function processSeat(seat, depth)
|
|
depth = (depth or 0) + 1
|
|
if IsValid(seat:GetDriver()) and seat:GetDriver() ~= self then
|
|
table.insert(seats, seat)
|
|
end
|
|
for _, v in pairs(seat:GetChildren()) do
|
|
if IsValid(v) and v:GetClass() == seatClass and IsValid(v:GetDriver()) and #v:GetChildren() > 0 and depth <= 128 then
|
|
processSeat(v, depth)
|
|
end
|
|
end
|
|
end
|
|
|
|
local plyVehicle = self:GetVehicle()
|
|
if IsValid(plyVehicle) and plyVehicle:GetClass() == seatClass then
|
|
processSeat(plyVehicle)
|
|
end
|
|
|
|
for _, v in pairs(self:GetChildren()) do
|
|
if IsValid(v) and v:GetClass() == seatClass then
|
|
processSeat(v)
|
|
end
|
|
end
|
|
|
|
for _, v in pairs(ents.FindByClass("sit_holder")) do
|
|
if v.GetTargetPlayer and v:GetTargetPlayer() == self then
|
|
table.insert(holders, v)
|
|
if v.GetSeat and IsValid(v:GetSeat()) then
|
|
processSeat(v:GetSeat())
|
|
end
|
|
end
|
|
end
|
|
|
|
return seats, holders
|
|
end
|
|
|
|
function PMETA:IsPlayerSittingOn(ply)
|
|
local seats = ply:GetSitters()
|
|
for _,v in pairs(seats) do
|
|
if IsValid(v:GetDriver()) and v:GetDriver() == self then return true end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function PMETA:GetSitting()
|
|
if not IsValid(self:GetVehicle()) then return false end
|
|
local veh = self:GetVehicle()
|
|
if veh:GetNWBool("playerdynseat", false) then
|
|
local parent = veh:GetParent()
|
|
if IsValid(parent) and parent:GetClass() == "sit_holder" then
|
|
return veh, parent
|
|
else
|
|
return veh
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function PMETA:ExitSit()
|
|
if CLIENT then
|
|
if self ~= LocalPlayer() then return end
|
|
net.Start("SitAnywhere")
|
|
net.WriteInt(SitAnywhere.NET.SitRequestExit, 4)
|
|
net.SendToServer()
|
|
else
|
|
local seat, holder = self:GetSitting()
|
|
SafeRemoveEntity(seat)
|
|
SafeRemoveEntity(holder)
|
|
|
|
if SitAnywhere.GroundSit and self:GetNWBool("SitGroundSitting", false) then
|
|
self:SetNWBool("SitGroundSitting", false)
|
|
end
|
|
end
|
|
end
|
|
|
|
function EMETA:IsSitAnywhereSeat()
|
|
if self:GetClass() ~= "prop_vehicle_prisoner_pod" then return false end
|
|
if SERVER and self.playerdynseat then return true end
|
|
return self:GetNWBool("playerdynseat", false)
|
|
end
|