add sborka

This commit is contained in:
2026-03-31 10:27:04 +03:00
commit f5e5f56c84
2345 changed files with 382127 additions and 0 deletions

View File

@@ -0,0 +1,605 @@
local TAG = "SitAny_"
local PLUGIN = PLUGIN
SitAnywhere = SitAnywhere or {}
local NextUse = setmetatable({}, {__mode = 'k', __index = function() return 0 end})
-- Конфигурация через ix.config
ix.config.Add("sitOnPlayers", true, "Разрешить сидеть на игроках в SitAnywhere", nil, {
category = "Sit Anywhere"
})
ix.config.Add("sitOnPlayerEntities", true, "Разрешить сидеть на сущностях игроков", nil, {
category = "Sit Anywhere"
})
ix.config.Add("sitPlayerDamage", false, "Разрешить урон сидящим игрокам", nil, {
category = "Sit Anywhere"
})
ix.config.Add("sitAllowWeapons", false, "Разрешить использование оружия при сидении", nil, {
category = "Sit Anywhere"
})
ix.config.Add("sitAdminOnly", false, "Только админы могут сидеть", nil, {
category = "Sit Anywhere"
})
ix.config.Add("sitAntiPropSurf", true, "Запретить физган на объектах с сидящими игроками", nil, {
category = "Sit Anywhere"
})
ix.config.Add("sitAntiToolAbuse", true, "Запретить тулган на объектах с сидящими игроками", nil, {
category = "Sit Anywhere"
})
ix.config.Add("sitAllowTightPlaces", false, "Разрешить сидеть в тесных местах", nil, {
category = "Sit Anywhere"
})
ix.config.Add("sitForceNoWalk", false, "Отключить необходимость шага для сидения", nil, {
category = "Sit Anywhere"
})
local META = FindMetaTable("Player")
util.AddNetworkString("SitAnywhere")
net.Receive("SitAnywhere", function(len, ply)
local netID = net.ReadInt(4)
if netID == SitAnywhere.NET.SitWantedAng then
local wantedAng, traceStart, traceNormal = net.ReadFloat(), net.ReadVector(), net.ReadVector()
if traceStart:Distance(ply:EyePos()) > 10 then return end
local trace = util.TraceLine({
start = traceStart,
endpos = traceStart + traceNormal * 12000,
filter = player.GetAll()
})
ply:Sit(trace, nil, nil, nil, nil, nil, wantedAng)
elseif netID == SitAnywhere.NET.SitRequestExit then
ply:ExitSit()
end
end)
local function Sit(ply, pos, ang, parent, parentbone, func, exit)
if IsValid(ply:GetVehicle()) then
local veh = ply:GetVehicle()
if veh:GetClass() == "prop_vehicle_prisoner_pod" and IsValid(veh.holder) then
SafeRemoveEntity(veh.holder)
end
ply:ExitVehicle()
end
local vehicle = ents.Create("prop_vehicle_prisoner_pod")
local t = hook.Run("OnPlayerSit", ply, pos, ang, parent or NULL, parentbone, vehicle)
if t == false then
SafeRemoveEntity(vehicle)
return false
end
vehicle:SetAngles(ang)
pos = pos + vehicle:GetUp() * 18
vehicle:SetPos(pos)
vehicle.playerdynseat = true
vehicle:SetNWBool("playerdynseat", true)
vehicle.sittingPly = ply
vehicle.oldpos = vehicle:WorldToLocal(ply:GetPos())
vehicle.wasCrouching = ply:Crouching()
vehicle:SetModel("models/nova/airboat_seat.mdl")
vehicle:SetKeyValue("vehiclescript", "scripts/vehicles/prisoner_pod.txt")
vehicle:SetKeyValue("limitview", "0")
vehicle:Spawn()
vehicle:Activate()
if not IsValid(vehicle) or not IsValid(vehicle:GetPhysicsObject()) then
SafeRemoveEntity(vehicle)
return false
end
local phys = vehicle:GetPhysicsObject()
vehicle:SetMoveType(MOVETYPE_PUSH)
phys:Sleep()
vehicle:SetCollisionGroup(COLLISION_GROUP_WORLD)
vehicle:SetNotSolid(true)
phys:Sleep()
phys:EnableGravity(false)
phys:EnableMotion(false)
phys:EnableCollisions(false)
phys:SetMass(1)
vehicle:CollisionRulesChanged()
vehicle:DrawShadow(false)
vehicle:SetColor(Color(0,0,0,0))
vehicle:SetRenderMode(RENDERMODE_TRANSALPHA)
vehicle:SetNoDraw(true)
vehicle.VehicleName = "Airboat Seat"
vehicle.ClassOverride = "prop_vehicle_prisoner_pod"
vehicle.PhysgunDisabled = true
vehicle.m_tblToolsAllowed = {}
vehicle.customCheck = function() return false end
if IsValid(parent) then
local r = math.rad(ang.yaw + 90)
vehicle.plyposhack = vehicle:WorldToLocal(pos + Vector(math.cos(r) * 2, math.sin(r) * 2, 2))
vehicle:SetParent(parent)
vehicle.parent = parent
else
vehicle.OnWorld = true
end
local prev = ply:GetAllowWeaponsInVehicle()
if prev then
ply.sitting_allowswep = nil
elseif ix.config.Get("sitAllowWeapons", false) then
ply.sitting_allowswep = prev
ply:SetAllowWeaponsInVehicle(true)
end
ply:EnterVehicle(vehicle)
if ix.config.Get("sitPlayerDamage", false) then
ply:SetCollisionGroup(COLLISION_GROUP_WEAPON)
ply:CollisionRulesChanged()
end
if func then
func(ply)
end
ply.seatExit = exit
ply:SetEyeAngles(Angle(0,90,0))
return vehicle
end
local d = function(a,b) return math.abs(a-b) end
local SittingOnPlayerPoses = {
{
Pos = Vector(-33, 13, 7),
Ang = Angle(0, 90, 90),
FindAng = 90,
},
{
Pos = Vector(33, 13, 7),
Ang = Angle(0, 270, 90),
Func = function(ply)
if not ply:LookupBone("ValveBiped.Bip01_R_Thigh") then return end
ply:ManipulateBoneAngles(ply:LookupBone("ValveBiped.Bip01_R_Thigh"), Angle(0,90,0))
ply:ManipulateBoneAngles(ply:LookupBone("ValveBiped.Bip01_L_Thigh"), Angle(0,90,0))
end,
OnExitFunc = function(ply)
if not ply:LookupBone("ValveBiped.Bip01_R_Thigh") then return end
ply:ManipulateBoneAngles(ply:LookupBone("ValveBiped.Bip01_R_Thigh"), Angle(0,0,0))
ply:ManipulateBoneAngles(ply:LookupBone("ValveBiped.Bip01_L_Thigh"), Angle(0,0,0))
end,
FindAng = 270,
},
{
Pos = Vector(0, 16, -15),
Ang = Angle(0, 180, 0),
Func = function(ply)
if not ply:LookupBone("ValveBiped.Bip01_R_Thigh") then return end
ply:ManipulateBoneAngles(ply:LookupBone("ValveBiped.Bip01_R_Thigh"), Angle(45,0,0))
ply:ManipulateBoneAngles(ply:LookupBone("ValveBiped.Bip01_L_Thigh"), Angle(-45,0,0))
end,
OnExitFunc = function(ply)
if not ply:LookupBone("ValveBiped.Bip01_R_Thigh") then return end
ply:ManipulateBoneAngles(ply:LookupBone("ValveBiped.Bip01_R_Thigh"), Angle(0,0,0))
ply:ManipulateBoneAngles(ply:LookupBone("ValveBiped.Bip01_L_Thigh"), Angle(0,0,0))
end,
FindAng = 0,
},
{
Pos = Vector(0, 8, -18),
Ang = Angle(0, 0, 0),
FindAng = 180,
},
}
local lookup = {}
for k,v in pairs(SittingOnPlayerPoses) do
table.insert(lookup, {v.FindAng, v})
table.insert(lookup, {v.FindAng + 360, v})
table.insert(lookup, {v.FindAng - 360, v})
end
local function FindPose(this,me)
local avec = me:GetAimVector()
avec.z = 0
avec:Normalize()
local evec = this:GetRight()
evec.z = 0
evec:Normalize()
local derp = avec:Dot(evec)
local avec2 = me:GetAimVector()
avec2.z = 0
avec2:Normalize()
local evec2 = this:GetForward()
evec2.z = 0
evec2:Normalize()
local herp = avec2:Dot(evec2)
local v = Vector(derp,herp,0)
local a = v:Angle()
local ang = a.y
ang = ang + 90 + 180
ang = ang % 360
table.sort(lookup,function(aa,bb)
return d(ang,aa[1]) < d(ang,bb[1])
end)
return lookup[1][2]
end
function META.Sit(ply, EyeTrace, ang, parent, parentbone, func, exit, wantedAng)
if EyeTrace == nil then
EyeTrace = ply:GetEyeTrace()
elseif type(EyeTrace) == "Vector" then
return Sit(ply, EyeTrace, ang or Angle(0,0,0), parent, parentbone or 0, func, exit)
end
local valid, ent = SitAnywhere.ValidSitTrace(ply, EyeTrace)
if not valid then return end
local surfaceAng = EyeTrace.HitNormal:Angle() + Angle(-270, 0, 0)
ang = surfaceAng
if wantedAng and math.abs(surfaceAng.pitch) <= 15 then
ent = EyeTrace.Entity
if EyeTrace.HitWorld or not ent:IsPlayer() then
if SitAnywhere.CheckValidAngForSit(EyeTrace.HitPos, EyeTrace.HitNormal:Angle(), wantedAng) then
ang.yaw = wantedAng + 90
else
return
end
end
return Sit(ply, EyeTrace.HitPos - Vector(0, 0, 23), ang, ent, EyeTrace.PhysicsBone or 0)
end
if ix.config.Get("sitOnPlayers", true) then
local veh
if not EyeTrace.HitWorld and IsValid(EyeTrace.Entity) and EyeTrace.Entity:IsPlayer() and IsValid(EyeTrace.Entity:GetVehicle()) and EyeTrace.Entity:GetVehicle().playerdynseat then
local safe = 256
veh = EyeTrace.Entity:GetVehicle()
while IsValid(veh.SittingOnMe) and IsValid(veh.SittingOnMe:GetDriver()) and safe > 0 do
safe = safe - 1
veh = veh.SittingOnMe
end
else
for k, v in pairs(ents.FindInSphere(EyeTrace.HitPos, 12)) do
local safe = 256
veh = v
while IsValid(veh.SittingOnMe) and IsValid(veh.SittingOnMe:GetDriver()) and safe > 0 do
safe = safe - 1
veh = veh.SittingOnMe
end
end
end
if IsValid(veh) and veh:GetClass() == "prop_vehicle_prisoner_pod" and veh:GetModel() ~= "models/vehicles/prisoner_pod_inner.mdl" and veh:GetDriver() and veh:GetDriver():IsValid() and not veh.PlayerSitOnPlayer then
if IsValid(veh.holder) and veh.holder.GetTargetPlayer and veh.holder:GetTargetPlayer() == ply then return end
if veh:GetDriver():GetInfoNum("sitting_allow_on_me", 1) == 0 then
ply:ChatPrint(("%s отключил возможность сидеть на нём!"):format(veh:GetDriver():Name()))
return false
end
local pose = FindPose(veh, ply)
local pos = veh:GetDriver():GetPos()
if veh.plyposhack then
pos = veh:LocalToWorld(veh.plyposhack)
end
local vec, ang2 = LocalToWorld(pose.Pos, pose.Ang, pos, veh:GetAngles())
if veh:GetParent() == ply then return false end
ent = Sit(ply, vec, ang2, veh, 0, pose.Func, pose.OnExitFunc)
if ent and IsValid(ent) then
ent.PlayerOnPlayer = true
veh.SittingOnMe = ent
end
return true, ent
end
else
for k, v in pairs(ents.FindInSphere(EyeTrace.HitPos, 5)) do
if v.playerdynseat then
return false
end
end
end
local shouldSitOnPlayer = (ply.IsFlying and ply:IsFlying()) or EyeTrace.Entity == ply:GetGroundEntity() or ply:GetMoveType() == MOVETYPE_NOCLIP
if IsValid(EyeTrace.Entity) and EyeTrace.Entity:IsPlayer() and ix.config.Get("sitOnPlayerEntities", true) and shouldSitOnPlayer then
ent = EyeTrace.Entity
if IsValid(ent:GetVehicle()) then return end
local min, max = ent:GetCollisionBounds()
local zadjust = math.abs(min.z) + math.abs(max.z)
local seatPos = ent:GetPos() + Vector(0, 0, 10 + zadjust / 2)
local vehicle = Sit(ply, seatPos, ply:GetAngles(), ent, EyeTrace.PhysicsBone or 0)
return vehicle
end
if math.abs(surfaceAng.pitch) <= 15 then
ang = Angle()
local sampleResolution = 24
local dists, distsang, ang_smallest_hori, smallest_hori = SitAnywhere.GetAreaProfile(EyeTrace.HitPos, sampleResolution, false)
local infront = ((ang_smallest_hori or 0) + 180) % 360
local cancelSit, seat = hook.Run("HandleSit", ply, dists, EyeTrace)
if cancelSit then
return seat
end
if ang_smallest_hori and distsang[infront].Hit and distsang[infront].Distance > 14 and smallest_hori <= 16 then
local hori = distsang[ang_smallest_hori].HorizontalTrace
ang.yaw = (hori.HitNormal:Angle().yaw - 90)
return Sit(ply, EyeTrace.HitPos - Vector(0, 0, 23), ang, (not EyeTrace.HitWorld) and EyeTrace.Entity, EyeTrace.PhysicsBone or 0)
else
table.sort(dists, function(a,b) return b.Distance < a.Distance end)
local wants = {}
local eyeang = ply:EyeAngles() + Angle(0, 180, 0)
for I = 1, #dists do
local trace = dists[I]
local behind = distsang[(trace.ang + 180) % 360]
if behind.Distance2 > 3 then
table.insert(wants, {
cost = math.abs(eyeang.yaw - trace.ang),
ang = trace.ang,
})
end
end
table.sort(wants,function(a,b) return b.cost > a.cost end)
if #wants == 0 then return end
ang.yaw = (wants[1].ang - 90)
return Sit(ply, EyeTrace.HitPos - Vector(0, 0, 23), ang, (not EyeTrace.HitWorld) and EyeTrace.Entity, EyeTrace.PhysicsBone or 0)
end
end
end
local function checkAllowSit(ply)
local allowSit = hook.Run("ShouldAllowSit", ply)
local bottom, top = ply:GetHull()
local diff = top.Z - bottom.Z
local trace = util.QuickTrace(ply:GetPos(), Vector(0, 0, diff), player.GetAll())
if not ix.config.Get("sitAllowTightPlaces", false) and trace.HitWorld then return false end
if allowSit == false or allowSit == true then
return allowSit
end
if ix.config.Get("sitAdminOnly", false) and not ply:IsAdmin() then
return false
end
return true
end
local function sitcmd(ply)
if not IsValid(ply) then return end
if ply:InVehicle() then return end
if not checkAllowSit(ply) then return end
local now = CurTime()
if NextUse[ply] > now then return end
if ply:Sit() then
NextUse[ply] = now + 1
else
NextUse[ply] = now + 0.1
end
end
concommand.Add("sit", function(ply, cmd, args)
sitcmd(ply)
end)
local function UndoSitting(ply)
if not IsValid(ply) then return end
local prev = ply.sitting_allowswep
if prev ~= nil then
ply.sitting_allowswep = nil
ply:SetAllowWeaponsInVehicle(prev)
end
if ix.config.Get("sitPlayerDamage", false) then
ply:SetCollisionGroup(COLLISION_GROUP_PLAYER)
ply:CollisionRulesChanged()
end
if ply.seatExit then
ply.seatExit(ply)
ply.seatExit = nil
end
end
-- Хуки
function PLUGIN:CanExitVehicle(seat, ply)
if not IsValid(seat) or not IsValid(ply) then return end
if not seat.playerdynseat then return end
if CurTime() < NextUse[ply] then return false end
end
function PLUGIN:PlayerLeaveVehicle(ply, seat)
if not IsValid(seat) or not IsValid(ply) then return end
if not seat.playerdynseat then return end
local oldpos = seat:LocalToWorld(seat.oldpos)
ply:SetPos(oldpos)
if ply.UnStuck then
ply:UnStuck()
end
for _, v in next, seat:GetChildren() do
if IsValid(v) and v.playerdynseat and IsValid(v.sittingPly) then
v.sittingPly:ExitVehicle()
end
end
SafeRemoveEntityDelayed(seat, 1)
UndoSitting(ply)
end
function PLUGIN:AllowPlayerPickup(ply)
if ply:KeyDown(IN_WALK) then
return false
end
end
function PLUGIN:PlayerDeath(pl)
local veh = pl:GetVehicle()
if IsValid(veh) and veh.playerdynseat then
SafeRemoveEntity(veh)
end
for k, v in next, pl:GetChildren() do
if IsValid(v) and v.playerdynseat and IsValid(v.sittingPly) then
v.sittingPly:ExitVehicle()
end
end
end
function PLUGIN:PlayerEnteredVehicle(pl, veh)
for k,v in next, pl:GetChildren() do
if IsValid(v) and v.playerdynseat and IsValid(v.sittingPly) then
v.sittingPly:ExitVehicle()
end
end
DropEntityIfHeld(veh)
local parent = veh:GetParent()
if IsValid(parent) then
DropEntityIfHeld(parent)
end
end
function PLUGIN:OnPlayerSit(ply, pos, ang, parent, parentbone, vehicle)
if IsValid(parent) and parent ~= game.GetWorld() then
if parent:GetModel():sub(1, 6) ~= "models" then return false end
if parent:IsPlayer() then
if not ix.config.Get("sitOnPlayerEntities", true) then return false end
if parent:GetInfoNum("sitting_allow_on_me", 1) == 0 then
ply:ChatPrint(("%s отключил возможность сидеть на нём!"):format(parent:Name()))
return false
end
if IsValid(parent:GetVehicle()) then return false end
end
end
end
function PLUGIN:EntityRemoved(ent)
if ent.playerdynseat and IsValid(ent.sittingPly) then
UndoSitting(ent.sittingPly)
end
for _, v in next, ent:GetChildren() do
if IsValid(v) and v.playerdynseat and IsValid(v.sittingPly) then
v.sittingPly:ExitVehicle()
end
end
end
function PLUGIN:PhysgunPickup(ply, ent)
if ix.config.Get("sitAntiPropSurf", true) then
local function CheckSeat(checkPly, checkEnt, tbl)
if not checkPly:InVehicle() then return true end
local vehicle = checkPly:GetVehicle()
local parent = vehicle.parent
if parent == checkEnt then return false end
for _,v in next, checkEnt:GetChildren() do
if IsValid(v) and not tbl[v] then
tbl[v] = true
if v ~= checkEnt and CheckSeat(checkPly, v, tbl) == false then
return false
end
end
end
local cEnts = constraint.GetAllConstrainedEntities(checkEnt)
if cEnts then
for _,v in next, cEnts do
if IsValid(v) and not tbl[v] then
tbl[v] = true
if v ~= checkEnt and CheckSeat(checkPly, v, tbl) == false then
return false
end
end
end
end
end
if IsValid(ply:GetVehicle()) and ply:GetVehicle().playerdynseat then
if CheckSeat(ply, ent, {}) == false then
return false
end
end
end
end
function PLUGIN:CanTool(ply, tr)
if ix.config.Get("sitAntiToolAbuse", true) and IsValid(tr.Entity) then
local function CheckSeat(checkPly, checkEnt, tbl)
if not checkPly:InVehicle() then return true end
local vehicle = checkPly:GetVehicle()
local parent = vehicle.parent
if parent == checkEnt then return false end
for _,v in next, checkEnt:GetChildren() do
if IsValid(v) and not tbl[v] then
tbl[v] = true
if v ~= checkEnt and CheckSeat(checkPly, v, tbl) == false then
return false
end
end
end
local cEnts = constraint.GetAllConstrainedEntities(checkEnt)
if cEnts then
for _,v in next, cEnts do
if IsValid(v) and not tbl[v] then
tbl[v] = true
if v ~= checkEnt and CheckSeat(checkPly, v, tbl) == false then
return false
end
end
end
end
end
if IsValid(ply:GetVehicle()) and ply:GetVehicle().playerdynseat then
if CheckSeat(ply, tr.Entity, {}) == false then
return false
end
end
end
end
timer.Create("SitAnywhere_RemoveSeats", 15, 0, function()
for k,v in pairs(ents.FindByClass("prop_vehicle_prisoner_pod")) do
if v.playerdynseat and (not IsValid(v.sittingPly) or v:GetDriver() == nil or not v:GetDriver():IsValid() or v:GetDriver():GetVehicle() ~= v) then
v:Remove()
end
end
end)