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,876 @@
-- lua/autorun/mrp_handcuffs_ext.lua
-- Realistic Handcuffs Extension for Military RP
if SERVER then
util.AddNetworkString("MRP_Handcuffs_PerformJail")
util.AddNetworkString("RHC_Jailer_Menu")
util.AddNetworkString("MRP_Handcuffs_PerformUnjail")
util.AddNetworkString("MRP_Handcuffs_OpenInteract")
util.AddNetworkString("MRP_Handcuffs_DoInteract")
util.AddNetworkString("MRP_UpdateJailInfo")
-- Data persistence for cells
local cellFilePath = "mrp_jailcells.txt"
MRP_JailCells = {RF = {}, UK = {}}
if file.Exists(cellFilePath, "DATA") then
local data = util.JSONToTable(file.Read(cellFilePath, "DATA") or "{}") or {}
MRP_JailCells.RF = data.RF or {}
MRP_JailCells.UK = data.UK or {}
end
local function SaveCells()
file.Write(cellFilePath, util.TableToJSON(MRP_JailCells))
end
-- Helper to get player being looked at
local function GetTarget(ply)
local tr = ply:GetEyeTrace()
if IsValid(tr.Entity) and tr.Entity:IsPlayer() and tr.Entity:GetPos():DistToSqr(ply:GetPos()) < 100000 then
return tr.Entity
end
return nil
end
-- Console commands as fallback for setting cells
concommand.Add("mrp_setcellrf", function(ply, cmd, args)
if IsValid(ply) and not ply:IsSuperAdmin() then return end
local cellNum = tonumber(args[1])
if cellNum and cellNum >= 1 and cellNum <= 3 then
MRP_JailCells.RF[cellNum] = ply:GetPos()
SaveCells()
if IsValid(ply) then ply:ChatPrint("Позиция камеры РФ " .. cellNum .. " установлена на ваше местоположение.") else print("Set.") end
else
if IsValid(ply) then ply:ChatPrint("Использование: mrp_setcellrf [1-3] в консоли") end
end
end)
concommand.Add("mrp_setcelluk", function(ply, cmd, args)
if IsValid(ply) and not ply:IsSuperAdmin() then return end
local cellNum = tonumber(args[1])
if cellNum and cellNum >= 1 and cellNum <= 3 then
MRP_JailCells.UK[cellNum] = ply:GetPos()
SaveCells()
if IsValid(ply) then ply:ChatPrint("Позиция камеры УК " .. cellNum .. " установлена на ваше местоположение.") else print("Set.") end
else
if IsValid(ply) then ply:ChatPrint("Использование: mrp_setcelluk [1-3] в консоли") end
end
end)
-- Chat commands
hook.Add("PlayerSay", "MRP_Handcuffs_ChatCommands", function(ply, text)
local args = string.Explode(" ", string.lower(text))
local cmd = args[1]
if cmd == "/setcellrf" then
if not ply:IsSuperAdmin() then return "" end
local cellNum = tonumber(args[2])
if cellNum and cellNum >= 1 and cellNum <= 3 then
MRP_JailCells.RF[cellNum] = ply:GetPos()
SaveCells()
ply:ChatPrint("Позиция камеры РФ " .. cellNum .. " установлена на ваше местоположение.")
else
ply:ChatPrint("Использование: /setcellrf [1-3] (Смотрите на место или стойте там)")
end
return "" -- suppress chat
end
if cmd == "/setcelluk" then
if not ply:IsSuperAdmin() then return "" end
local cellNum = tonumber(args[2])
if cellNum and cellNum >= 1 and cellNum <= 3 then
MRP_JailCells.UK[cellNum] = ply:GetPos()
SaveCells()
ply:ChatPrint("Позиция камеры УК " .. cellNum .. " установлена на ваше местоположение.")
else
ply:ChatPrint("Использование: /setcelluk [1-3] (Смотрите на место или стойте там)")
end
return "" -- suppress chat
end
local function HasPoliceAccess(p)
return true
end
if cmd == "/gag" then
if not HasPoliceAccess(ply) then return "" end
local target = GetTarget(ply)
if target and target:GetNWBool("rhc_cuffed", false) then
local isGagged = target:GetNWBool("MRP_Gagged", false)
target:SetNWBool("MRP_Gagged", not isGagged)
ply:ChatPrint(target:Nick() .. " теперь " .. (not isGagged and "с кляпом" or "без кляпа") .. ".")
else
ply:ChatPrint("Вы должны смотреть на закованного игрока.")
end
return ""
elseif cmd == "/blind" then
if not HasPoliceAccess(ply) then return "" end
local target = GetTarget(ply)
if target and target:GetNWBool("rhc_cuffed", false) then
local isBlind = target:GetNWBool("MRP_Blindfolded", false)
target:SetNWBool("MRP_Blindfolded", not isBlind)
if not isBlind then
target:PrintMessage(HUD_PRINTCENTER, "Вам завязали глаза.")
end
ply:ChatPrint(target:Nick() .. " теперь " .. (not isBlind and "с завязанными глазами" or "без повязки на глазах") .. ".")
else
ply:ChatPrint("Вы должны смотреть на закованного игрока.")
end
return ""
end
end)
-- Mute gagged players in voice
hook.Add("PlayerCanHearPlayersVoice", "MRP_Handcuffs_GagVoice", function(listener, talker)
if IsValid(talker) and talker:GetNWBool("MRP_Gagged", false) then
return false, false
end
end)
-- Mute gagged players in text chat (Helix override)
hook.Add("PlayerSay", "MRP_Handcuffs_GagChat", function(ply, text)
if ply:GetNWBool("MRP_Gagged", false) then
ply:ChatPrint("Вы не можете говорить с кляпом во рту.")
return ""
end
end)
-- Sync drag state for visuals
timer.Create("MRP_Handcuffs_SyncDrag", 0.5, 0, function()
for _, ply in ipairs(player.GetAll()) do
if ply.Dragging and IsValid(ply.Dragging) then
ply:SetNWEntity("MRP_DraggingTarget", ply.Dragging)
else
ply:SetNWEntity("MRP_DraggingTarget", NULL)
end
end
end)
-- Interaction Menu and Move/Freeze logic
net.Receive("MRP_Handcuffs_DoInteract", function(len, ply)
-- Removing privilege check to allow anyone with weapon to interact
-- if ply.IsRHCWhitelisted and not ply:IsRHCWhitelisted() and not ply:IsAdmin() then return end
local target = net.ReadEntity()
local action = net.ReadString()
if not IsValid(target) or not target:IsPlayer() or not target:GetNWBool("rhc_cuffed", false) then return end
if target:GetPos():DistToSqr(ply:GetPos()) > 100000 then return end
if action == "gag" then
local isGagged = target:GetNWBool("MRP_Gagged", false)
target:SetNWBool("MRP_Gagged", not isGagged)
ply:ChatPrint(target:Nick() .. " теперь " .. (not isGagged and "с кляпом" or "без кляпа") .. ".")
elseif action == "blind" then
local isBlind = target:GetNWBool("MRP_Blindfolded", false)
target:SetNWBool("MRP_Blindfolded", not isBlind)
if not isBlind then target:PrintMessage(HUD_PRINTCENTER, "Вам завязали глаза.") end
ply:ChatPrint(target:Nick() .. " теперь " .. (not isBlind and "с завязанными глазами" or "без повязки на глазах") .. ".")
end
end)
hook.Add("KeyPress", "MRP_Handcuffs_MoveBind", function(ply, key)
if key == IN_USE then
-- Removing privilege check to allow anyone with weapon to interact
-- if ply.IsRHCWhitelisted and not ply:IsRHCWhitelisted() and not ply:IsAdmin() then return end
local target = GetTarget(ply)
if IsValid(target) and target:GetNWBool("rhc_cuffed", false) then
if ply:KeyDown(IN_WALK) then -- ALT + E
if target:GetMoveType() == MOVETYPE_NONE then
target:SetMoveType(MOVETYPE_WALK)
ply:ChatPrint("Разморожен " .. target:Nick())
else
target:SetMoveType(MOVETYPE_NONE)
local trace = util.QuickTrace(ply:EyePos(), ply:GetAimVector() * 80, {ply, target})
target:SetPos(trace.HitPos)
ply:ChatPrint("Заморожен и перемещен " .. target:Nick())
end
else -- Just E
net.Start("MRP_Handcuffs_OpenInteract")
net.WriteEntity(target)
net.WriteBool(target:GetNWBool("MRP_Gagged", false))
net.WriteBool(target:GetNWBool("MRP_Blindfolded", false))
net.Send(ply)
end
end
end
end)
-- Custom Jailer network receiver
net.Receive("MRP_Handcuffs_PerformJail", function(len, ply)
local dragged = net.ReadEntity()
local time = net.ReadUInt(32) -- up to 3600
local reason = net.ReadString()
local cellIndex = net.ReadUInt(8) -- 1, 2, or 3
-- validate
if not ply.LastJailerNPC or not IsValid(ply.LastJailerNPC) then return end
if ply:GetPos():DistToSqr(ply.LastJailerNPC:GetPos()) > 60000 then return end
local faction = ply.LastJailerFaction or "RF"
if not IsValid(dragged) or not dragged:IsPlayer() then return end
-- Validate distance
if dragged:GetPos():DistToSqr(ply:GetPos()) > 60000 then
ply:ChatPrint("Заключенный слишком далеко!")
return
end
time = math.Clamp(time, 1, 3600)
-- Force teleport to custom cell
if cellIndex >= 1 and cellIndex <= 3 and MRP_JailCells[faction] and MRP_JailCells[faction][cellIndex] then
ply:ChatPrint("Игрок " .. dragged:Nick() .. " (" .. dragged:SteamID() .. ") посажен в камеру " .. faction .. " на " .. time .. " сек. Причина: " .. reason)
-- Log the jailing
hook.Run("RHC_jailed", dragged, ply, time, reason)
-- Keep them cuffed in jail (weapon limits already applied by standalone logic)
timer.Simple(0.2, function()
if IsValid(dragged) then
dragged:SetPos(MRP_JailCells[faction][cellIndex])
if dragged.getChar and dragged:getChar() then
dragged:getChar():setData("mrp_jail_time", os.time() + time)
dragged:getChar():setData("mrp_jail_faction", faction)
dragged:getChar():setData("mrp_jail_cell", cellIndex)
dragged:getChar():setData("mrp_jail_reason", reason)
dragged:getChar():setData("mrp_jailer_name", ply:Nick())
dragged:getChar():setData("mrp_jailer_steam", ply:SteamID())
-- Sync to client
dragged:SetNWInt("MRP_JailTime", os.time() + time)
dragged:SetNWString("MRP_JailReason", reason)
dragged:SetNWString("MRP_JailerName", ply:Nick())
dragged:SetNWString("MRP_JailerSteam", ply:SteamID())
net.Start("MRP_UpdateJailInfo")
net.WriteEntity(dragged)
net.WriteInt(os.time() + time)
net.WriteString(reason)
net.WriteString(ply:Nick())
net.WriteString(ply:SteamID())
net.Broadcast()
end
-- Simple arrest unjail timer
local timerName = "MRP_Jail_" .. dragged:SteamID64()
timer.Create(timerName, time, 1, function()
if IsValid(dragged) then
dragged:Spawn()
-- Trigger uncuff manually
dragged:SetNWBool("rhc_cuffed", false)
dragged:SetNWBool("MRP_Gagged", false)
dragged:SetNWBool("MRP_Blindfolded", false)
dragged:StripWeapon("weapon_r_cuffed")
-- Explicitly reset bone angles
local CuffedBones = {
["ValveBiped.Bip01_R_UpperArm"] = true,
["ValveBiped.Bip01_L_UpperArm"] = true,
["ValveBiped.Bip01_R_Forearm"] = true,
["ValveBiped.Bip01_L_Forearm"] = true,
["ValveBiped.Bip01_R_Hand"] = true,
["ValveBiped.Bip01_L_Hand"] = true,
}
for boneName, _ in pairs(CuffedBones) do
local boneId = dragged:LookupBone(boneName)
if boneId then
dragged:ManipulateBoneAngles(boneId, Angle(0,0,0))
end
end
if dragged.RHC_SavedWeapons then
for _, class in ipairs(dragged.RHC_SavedWeapons) do
dragged:Give(class)
end
dragged.RHC_SavedWeapons = nil
end
if dragged.RHC_OldWalk then
dragged:SetWalkSpeed(dragged.RHC_OldWalk)
dragged:SetRunSpeed(dragged.RHC_OldRun)
dragged.RHC_OldWalk = nil
dragged.RHC_OldRun = nil
end
if dragged.getChar and dragged:getChar() then
dragged:getChar():setData("mrp_jail_time", nil)
dragged:getChar():setData("mrp_jail_faction", nil)
dragged:getChar():setData("mrp_jail_cell", nil)
dragged:getChar():setData("mrp_jail_reason", nil)
dragged:getChar():setData("mrp_jailer_name", nil)
dragged:getChar():setData("mrp_jailer_steam", nil)
dragged:SetNWInt("MRP_JailTime", 0)
dragged:SetNWString("MRP_JailReason", "")
dragged:SetNWString("MRP_JailerName", "")
dragged:SetNWString("MRP_JailerSteam", "")
net.Start("MRP_UpdateJailInfo")
net.WriteEntity(dragged)
net.WriteInt(0)
net.WriteString("")
net.WriteString("")
net.WriteString("")
net.Broadcast()
end
if dragged.RHC_SavedWeapons then
for _, class in ipairs(dragged.RHC_SavedWeapons) do dragged:Give(class) end
dragged.RHC_SavedWeapons = nil
end
if dragged.RHC_OldWalk then
dragged:SetWalkSpeed(dragged.RHC_OldWalk)
dragged:SetRunSpeed(dragged.RHC_OldRun)
end
dragged:ChatPrint("Ваш срок заключения подошел к концу.")
end
end)
end
end)
-- Drop drag
ply.Dragging = nil
dragged.DraggedBy = nil
ply:SetNWEntity("MRP_DraggingTarget", NULL)
else
ply:ChatPrint("Внимание: Позиция выбранной камеры не настроена! Администратор должен использовать /setcell" .. string.lower(faction) .. " " .. cellIndex)
end
end)
net.Receive("MRP_Handcuffs_PerformUnjail", function(len, ply)
local target = net.ReadEntity()
if not IsValid(target) or not target:IsPlayer() then return end
-- validate
if not ply.LastJailerNPC or not IsValid(ply.LastJailerNPC) then return end
if ply:GetPos():DistToSqr(ply.LastJailerNPC:GetPos()) > 60000 then return end
local timerName = "MRP_Jail_" .. target:SteamID64()
if timer.Exists(timerName) then
timer.Remove(timerName)
target:SetNWBool("rhc_cuffed", false)
target:SetNWBool("MRP_Gagged", false)
target:SetNWBool("MRP_Blindfolded", false)
target:StripWeapon("weapon_r_cuffed")
-- Explicitly reset bone angles
local CuffedBones = {
["ValveBiped.Bip01_R_UpperArm"] = true,
["ValveBiped.Bip01_L_UpperArm"] = true,
["ValveBiped.Bip01_R_Forearm"] = true,
["ValveBiped.Bip01_L_Forearm"] = true,
["ValveBiped.Bip01_R_Hand"] = true,
["ValveBiped.Bip01_L_Hand"] = true,
}
for boneName, _ in pairs(CuffedBones) do
local boneId = target:LookupBone(boneName)
if boneId then
target:ManipulateBoneAngles(boneId, Angle(0,0,0))
end
end
if target.RHC_SavedWeapons then
for _, class in ipairs(target.RHC_SavedWeapons) do
target:Give(class)
end
target.RHC_SavedWeapons = nil
end
if target.RHC_OldWalk then
target:SetWalkSpeed(target.RHC_OldWalk)
target:SetRunSpeed(target.RHC_OldRun)
target.RHC_OldWalk = nil
target.RHC_OldRun = nil
end
if target.getChar and target:getChar() then
target:getChar():setData("mrp_jail_time", nil)
target:getChar():setData("mrp_jail_faction", nil)
target:getChar():setData("mrp_jail_cell", nil)
end
-- Spawn the player naturally, just like after natural timeout
target:Spawn()
target:ChatPrint("Вас досрочно освободил " .. ply:Nick())
ply:ChatPrint("Вы освободили " .. target:Nick())
else
ply:ChatPrint("Похоже, этот игрок не в тюрьме.")
end
end)
-- Reconnect persistence
hook.Add("PlayerLoadedCharacter", "MRP_Handcuffs_LoadJail", function(ply, character, oldCharacter)
timer.Simple(1, function()
if not IsValid(ply) then return end
if not character or not character.getData then return end -- FIX
local jailTime = character:getData("mrp_jail_time", 0)
local faction = character:getData("mrp_jail_faction", "RF")
local cellIndex = character:getData("mrp_jail_cell", 1)
if jailTime > os.time() then
local remaining = jailTime - os.time()
-- Ensure they're cuffed
ply:SetNWBool("rhc_cuffed", true)
ply:Give("weapon_r_cuffed")
if MRP_JailCells[faction] and MRP_JailCells[faction][cellIndex] then
ply:SetPos(MRP_JailCells[faction][cellIndex])
end
ply:ChatPrint("Вы вернулись, чтобы отсидеть оставшиеся " .. remaining .. " секунд вашего срока.")
-- Sync jail info to client
ply:SetNWInt("MRP_JailTime", jailTime)
ply:SetNWString("MRP_JailReason", character:getData("mrp_jail_reason", "Не указана"))
ply:SetNWString("MRP_JailerName", character:getData("mrp_jailer_name", "Неизвестен"))
ply:SetNWString("MRP_JailerSteam", character:getData("mrp_jailer_steam", "Неизвестен"))
net.Start("MRP_UpdateJailInfo")
net.WriteEntity(ply)
net.WriteInt(jailTime)
net.WriteString(character:getData("mrp_jail_reason", "Не указана"))
net.WriteString(character:getData("mrp_jailer_name", "Неизвестен"))
net.WriteString(character:getData("mrp_jailer_steam", "Неизвестен"))
net.Broadcast()
-- Re-apply timer
local timerName = "MRP_Jail_" .. ply:SteamID64()
timer.Create(timerName, remaining, 1, function()
if IsValid(ply) then
ply:SetNWBool("rhc_cuffed", false)
ply:SetNWBool("MRP_Gagged", false)
ply:SetNWBool("MRP_Blindfolded", false)
ply:StripWeapon("weapon_r_cuffed")
if ply.getChar and ply:getChar() then
ply:getChar():setData("mrp_jail_time", nil)
ply:getChar():setData("mrp_jail_faction", nil)
ply:getChar():setData("mrp_jail_cell", nil)
end
-- Look for nearest appropriate jailer for un-jailing position
local classStr = (faction == "RF") and "rhc_jailer_rf" or "rhc_jailer_uk"
local npc = ents.FindByClass(classStr)[1]
if IsValid(npc) then
ply:Spawn()
end
ply:ChatPrint("Ваш срок заключения подошел к концу.")
end
end)
else
-- Timed out while offline or was free
if character:getData("mrp_jail_time") then
character:setData("mrp_jail_time", nil)
character:setData("mrp_jail_faction", nil)
character:setData("mrp_jail_cell", nil)
character:setData("mrp_jail_reason", nil)
character:setData("mrp_jailer_name", nil)
character:setData("mrp_jailer_steam", nil)
ply:SetNWInt("MRP_JailTime", 0)
ply:SetNWString("MRP_JailReason", "")
ply:SetNWString("MRP_JailerName", "")
ply:SetNWString("MRP_JailerSteam", "")
net.Start("MRP_UpdateJailInfo")
net.WriteEntity(ply)
net.WriteInt(0)
net.WriteString("")
net.WriteString("")
net.WriteString("")
net.Broadcast()
end
end
end)
end)
-- Reset cuff state on spawn if not jailed
hook.Add("PlayerSpawn", "MRP_Handcuffs_ResetOnSpawn", function(ply)
if ply:GetNWBool("rhc_cuffed", false) then
local character = ply.getChar and ply:getChar()
if not character or not character.getData or character:getData("mrp_jail_time", 0) <= os.time() then
-- Not jailed, reset cuff state
ply:SetNWBool("rhc_cuffed", false)
ply:SetNWBool("MRP_Gagged", false)
ply:SetNWBool("MRP_Blindfolded", false)
ply:StripWeapon("weapon_r_cuffed")
-- Reset bones
for boneName, _ in pairs({
["ValveBiped.Bip01_R_UpperArm"] = true,
["ValveBiped.Bip01_L_UpperArm"] = true,
["ValveBiped.Bip01_R_Forearm"] = true,
["ValveBiped.Bip01_L_Forearm"] = true,
["ValveBiped.Bip01_R_Hand"] = true,
["ValveBiped.Bip01_L_Hand"] = true,
}) do
local boneId = ply:LookupBone(boneName)
if boneId then
ply:ManipulateBoneAngles(boneId, Angle(0,0,0))
end
end
-- Restore weapons and speed if saved
if ply.RHC_SavedWeapons then
for _, class in ipairs(ply.RHC_SavedWeapons) do
ply:Give(class)
end
ply.RHC_SavedWeapons = nil
end
if ply.RHC_OldWalk then
ply:SetWalkSpeed(ply.RHC_OldWalk)
ply:SetRunSpeed(ply.RHC_OldRun)
ply.RHC_OldWalk = nil
ply.RHC_OldRun = nil
end
end
end
end)
end
if CLIENT then
local clientJailTime = 0
local clientJailReason = ""
local clientJailerName = ""
local clientJailerSteam = ""
net.Receive("MRP_UpdateJailInfo", function()
local ent = net.ReadEntity()
if ent == LocalPlayer() then
clientJailTime = net.ReadInt()
clientJailReason = net.ReadString()
clientJailerName = net.ReadString()
clientJailerSteam = net.ReadString()
end
end)
-- Blindfold Overlay
hook.Add("HUDPaint", "MRP_Handcuffs_BlindfoldHUD", function()
local ply = LocalPlayer()
if not IsValid(ply) then return end
if ply:GetNWBool("MRP_Blindfolded", false) then
surface.SetDrawColor(0, 0, 0, 255)
surface.DrawRect(0, 0, ScrW(), ScrH())
draw.SimpleText("У вас завязаны глаза", "Trebuchet24", ScrW()/2, ScrH()/2, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
end
end)
-- Jail Time HUD
hook.Add("HUDPaint", "MRP_Handcuffs_JailHUD", function()
if clientJailTime > os.time() then
local remaining = clientJailTime - os.time()
local minutes = math.floor(remaining / 60)
local seconds = remaining % 60
local timeStr = string.format("%02d:%02d", minutes, seconds)
draw.SimpleTextOutlined("Осталось сидеть: " .. timeStr, "Trebuchet24", ScrW()/2, ScrH() - 150, Color(255, 255, 100, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM, 2, Color(0, 0, 0, 255))
draw.SimpleTextOutlined("Причина: " .. clientJailReason, "Trebuchet18", ScrW()/2, ScrH() - 120, Color(255, 255, 100, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM, 2, Color(0, 0, 0, 255))
draw.SimpleTextOutlined("Посадил: " .. clientJailerName .. " (" .. clientJailerSteam .. ")", "Trebuchet18", ScrW()/2, ScrH() - 90, Color(255, 255, 100, 255), TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM, 2, Color(0, 0, 0, 255))
end
end)
-- Beam dragging visual
local matBeam = Material("cable/rope")
hook.Add("PostDrawTranslucentRenderables", "MRP_Handcuffs_DrawDrag", function()
for _, ply in ipairs(player.GetAll()) do
local target = ply:GetNWEntity("MRP_DraggingTarget")
if IsValid(target) then
local startPos = ply:GetPos() + Vector(0,0,40)
local endPos = target:GetPos() + Vector(0,0,40)
local wep = ply:GetActiveWeapon()
if IsValid(wep) then
local vm = ply:GetViewModel()
if ply == LocalPlayer() and not ply:ShouldDrawLocalPlayer() and IsValid(vm) then
local attach = vm:GetAttachment(1)
if attach then startPos = attach.Pos end
else
local attach = wep:GetAttachment(1)
if attach then
startPos = attach.Pos
else
local bone = ply:LookupBone("ValveBiped.Bip01_R_Hand")
if bone then
local bPos = ply:GetBonePosition(bone)
if bPos then startPos = bPos end
end
end
end
else
local bone = ply:LookupBone("ValveBiped.Bip01_R_Hand")
if bone then
local bPos = ply:GetBonePosition(bone)
if bPos then startPos = bPos end
end
end
local tBone = target:LookupBone("ValveBiped.Bip01_R_Hand")
if tBone then
local bPos = target:GetBonePosition(tBone)
if bPos then endPos = bPos end
end
render.SetMaterial(matBeam)
render.DrawBeam(startPos, endPos, 2, 0, startPos:Distance(endPos) / 10, color_white)
end
end
end)
-- Models
hook.Add("PostPlayerDraw", "MRP_Handcuffs_DrawModels", function(ply)
if not IsValid(ply) or not ply:Alive() then return end
local isGagged = ply:GetNWBool("MRP_Gagged", false)
local isBlind = ply:GetNWBool("MRP_Blindfolded", false)
if not isGagged and not isBlind then return end
local bone = ply:LookupBone("ValveBiped.Bip01_Head1")
if not bone then return end
local pos, ang = ply:GetBonePosition(bone)
if not pos or not ang then return end
if isGagged then
if not IsValid(gagModel) then
gagModel = ClientsideModel("models/kidnappers_kit/tape gag cross/tapegagcross.mdl")
if IsValid(gagModel) then gagModel:SetNoDraw(true) end
end
if IsValid(gagModel) then
local gagAng = ang * 1
gagAng:RotateAroundAxis(gagAng:Right(), -92.67)
gagAng:RotateAroundAxis(gagAng:Up(), -85.54)
gagAng:RotateAroundAxis(gagAng:Forward(), 0)
local offset = ang:Forward() * -59.4 + ang:Right() * 6.53 + ang:Up() * 2.77
gagModel:SetRenderOrigin(pos + offset)
gagModel:SetRenderAngles(gagAng)
gagModel:SetModelScale(1)
gagModel:DrawModel()
end
end
if isBlind then
if not IsValid(blindModel) then
blindModel = ClientsideModel("models/kidnappers_kit/tape blindfold/tapeblindfold.mdl")
if IsValid(blindModel) then blindModel:SetNoDraw(true) end
end
if IsValid(blindModel) then
local blindAng = ang * 1
blindAng:RotateAroundAxis(blindAng:Right(), -90)
blindAng:RotateAroundAxis(blindAng:Up(), -89.11)
blindAng:RotateAroundAxis(blindAng:Forward(), 0)
local offset = ang:Forward() * -49 + ang:Right() * 3.17 + ang:Up() * 0.4
blindModel:SetRenderOrigin(pos + offset)
blindModel:SetRenderAngles(blindAng)
blindModel:SetModelScale(0.92)
blindModel:DrawModel()
end
end
end)
timer.Simple(2, function()
net.Receive("RHC_Jailer_Menu", function()
local dragged = net.ReadEntity()
local faction = net.ReadString() -- "RF" or "UK"
if not IsValid(dragged) then
chat.AddText(Color(255,0,0), "Рядом нет закованных игроков!")
return
end
local factionTitle = (faction == "RF" or faction == "UK") and (" (" .. faction .. ")") or ""
local frame = vgui.Create("DFrame")
frame:SetSize(400, 320)
frame:Center()
frame:SetTitle("Посадить игрока: " .. dragged:Nick() .. factionTitle)
frame:MakePopup()
frame.Paint = function(self, w, h)
draw.RoundedBox(4, 0, 0, w, h, Color(40, 40, 40, 240))
draw.RoundedBox(4, 0, 0, w, 24, Color(30, 30, 30, 255))
end
local timeLabel = vgui.Create("DLabel", frame)
timeLabel:SetPos(20, 40)
timeLabel:SetText("Время (1-3600 сек):")
timeLabel:SizeToContents()
timeLabel:SetTextColor(color_white)
local timeText = vgui.Create("DTextEntry", frame)
timeText:SetPos(20, 60)
timeText:SetSize(360, 25)
timeText:SetText("300")
timeText:SetNumeric(true)
local reasonLabel = vgui.Create("DLabel", frame)
reasonLabel:SetPos(20, 100)
reasonLabel:SetText("Причина:")
reasonLabel:SizeToContents()
reasonLabel:SetTextColor(color_white)
local reasonText = vgui.Create("DTextEntry", frame)
reasonText:SetPos(20, 120)
reasonText:SetSize(360, 25)
reasonText:SetText("Причина не указана")
local cellLabel = vgui.Create("DLabel", frame)
cellLabel:SetPos(20, 160)
cellLabel:SetText("Выберите камеру:")
cellLabel:SizeToContents()
cellLabel:SetTextColor(color_white)
local cellCombo = vgui.Create("DComboBox", frame)
cellCombo:SetPos(20, 180)
cellCombo:SetSize(360, 25)
cellCombo:SetValue("Камера 1")
cellCombo:AddChoice("Камера 1", 1)
cellCombo:AddChoice("Камера 2", 2)
cellCombo:AddChoice("Камера 3", 3)
local submitBtn = vgui.Create("DButton", frame)
submitBtn:SetPos(20, 230)
submitBtn:SetSize(360, 40)
submitBtn:SetText("Посадить")
submitBtn:SetTextColor(color_white)
submitBtn.Paint = function(self, w, h)
local col = self:IsHovered() and Color(60, 120, 200) or Color(50, 100, 180)
draw.RoundedBox(4, 0, 0, w, h, col)
end
submitBtn.DoClick = function()
local time = tonumber(timeText:GetValue()) or 300
local reason = reasonText:GetValue()
local _, cellIndex = cellCombo:GetSelected()
cellIndex = cellIndex or 1
net.Start("MRP_Handcuffs_PerformJail")
net.WriteEntity(dragged)
net.WriteUInt(time, 32)
net.WriteString(reason)
net.WriteUInt(cellIndex, 8)
net.SendToServer()
frame:Close()
end
-- Unjail functionality
local unjailBtn = vgui.Create("DButton", frame)
unjailBtn:SetPos(20, 275)
unjailBtn:SetSize(360, 25)
unjailBtn:SetText("Показать список заключенных для освобождения")
unjailBtn:SetTextColor(Color(255,100,100))
unjailBtn.Paint = function(self, w, h)
draw.RoundedBox(4, 0, 0, w, h, Color(50, 20, 20))
end
unjailBtn.DoClick = function()
frame:Close()
local uFrame = vgui.Create("DFrame")
uFrame:SetSize(300, 400)
uFrame:Center()
uFrame:SetTitle("Досрочное освобождение")
uFrame:MakePopup()
uFrame.Paint = function(self, w, h)
draw.RoundedBox(4, 0, 0, w, h, Color(40, 40, 40, 240))
end
local list = vgui.Create("DListView", uFrame)
list:Dock(FILL)
list:AddColumn("Заключенные игроки")
for _, p in ipairs(player.GetAll()) do
if p:GetNWBool("rhc_cuffed", false) and not IsValid(p.DraggedBy) then
local line = list:AddLine(p:Nick())
line.PlayerObj = p
end
end
local relBtn = vgui.Create("DButton", uFrame)
relBtn:Dock(BOTTOM)
relBtn:SetTall(30)
relBtn:SetText("Освободить выбранного")
relBtn.DoClick = function()
local selected = list:GetSelectedLine()
if selected then
local plyObj = list:GetLine(selected).PlayerObj
if IsValid(plyObj) then
net.Start("MRP_Handcuffs_PerformUnjail")
net.WriteEntity(plyObj)
net.SendToServer()
end
uFrame:Close()
end
end
end
end)
end)
net.Receive("MRP_Handcuffs_OpenInteract", function()
local target = net.ReadEntity()
local isGagged = net.ReadBool()
local isBlind = net.ReadBool()
if not IsValid(target) then return end
local frame = vgui.Create("DFrame")
frame:SetSize(250, 140)
frame:Center()
frame:SetTitle("Взаимодействие: " .. target:Nick())
frame:MakePopup()
frame.Paint = function(self, w, h)
draw.RoundedBox(4, 0, 0, w, h, Color(40, 40, 40, 240))
draw.RoundedBox(4, 0, 0, w, 24, Color(30, 30, 30, 255))
end
local gagBtn = vgui.Create("DButton", frame)
gagBtn:Dock(TOP)
gagBtn:DockMargin(10, 10, 10, 0)
gagBtn:SetTall(35)
gagBtn:SetText(isGagged and "Снять кляп" or "Вставить кляп")
gagBtn:SetTextColor(color_white)
gagBtn.Paint = function(self, w, h)
draw.RoundedBox(4, 0, 0, w, h, self:IsHovered() and Color(60, 60, 60) or Color(80, 80, 80))
end
gagBtn.DoClick = function()
net.Start("MRP_Handcuffs_DoInteract")
net.WriteEntity(target)
net.WriteString("gag")
net.SendToServer()
frame:Close()
end
local blindBtn = vgui.Create("DButton", frame)
blindBtn:Dock(TOP)
blindBtn:DockMargin(10, 10, 10, 0)
blindBtn:SetTall(35)
blindBtn:SetText(isBlind and "Снять повязку" or "Надеть повязку")
blindBtn:SetTextColor(color_white)
blindBtn.Paint = function(self, w, h)
draw.RoundedBox(4, 0, 0, w, h, self:IsHovered() and Color(60, 60, 60) or Color(80, 80, 80))
end
blindBtn.DoClick = function()
net.Start("MRP_Handcuffs_DoInteract")
net.WriteEntity(target)
net.WriteString("blind")
net.SendToServer()
frame:Close()
end
end)
end

View File

@@ -0,0 +1,50 @@
-- lua/autorun/server/mrp_jailer_spawns.lua
if not SERVER then return end
local function SpawnJailers()
-- Remove existing jailers to prevent duplicates on lua refresh
for _, ent in ipairs(ents.FindByClass("rhc_jailer_rf")) do ent:Remove() end
for _, ent in ipairs(ents.FindByClass("rhc_jailer_uk")) do ent:Remove() end
-- Spawn RF Jailer
local rf_jailer = ents.Create("rhc_jailer_rf")
if IsValid(rf_jailer) then
rf_jailer:SetPos(Vector(10651.541992, 10210.736328, 193.868973))
rf_jailer:SetAngles(Angle(0, 90, 0))
rf_jailer:Spawn()
-- Drop to floor to be safe
local tr = util.TraceLine({
start = rf_jailer:GetPos() + Vector(0,0,10),
endpos = rf_jailer:GetPos() - Vector(0,0,100),
filter = rf_jailer
})
if tr.Hit then rf_jailer:SetPos(tr.HitPos) end
end
-- Spawn UK Jailer
local uk_jailer = ents.Create("rhc_jailer_uk")
if IsValid(uk_jailer) then
uk_jailer:SetPos(Vector(-12438.240234, -9908.939453, 181.868973))
uk_jailer:SetAngles(Angle(0, 180, 0))
uk_jailer:Spawn()
local tr = util.TraceLine({
start = uk_jailer:GetPos() + Vector(0,0,10),
endpos = uk_jailer:GetPos() - Vector(0,0,100),
filter = uk_jailer
})
if tr.Hit then uk_jailer:SetPos(tr.HitPos) end
end
end
hook.Add("InitPostEntity", "MRP_SpawnHandcuffsJailers", function()
timer.Simple(5, SpawnJailers) -- Wait a bit to ensure map is fully loaded
end)
-- Make it easy to respawn via command if accidentally deleted
concommand.Add("mrp_respawn_jailers", function(ply)
if IsValid(ply) and not ply:IsSuperAdmin() then return end
SpawnJailers()
if IsValid(ply) then ply:ChatPrint("NPC-тюремщики возрождены.") end
end)

View File

@@ -0,0 +1 @@
-- Cleared to fix "attempt to index global ENT" error

View File

@@ -0,0 +1,7 @@
if SERVER then
-- Suppress missing file errors
end
if CLIENT then
-- Suppress missing file errors
end

View File

@@ -0,0 +1,34 @@
include('shared.lua')
function ENT:Initialize()
end
function ENT:Think ()
end
local AttMat = Material("cable/cable")
function ENT:Draw()
local Player = self:GetOwningPlayer()
local AEnt = self:GetAttatchedEntity()
local APos = self:GetAttatchPosition()
if IsValid(AEnt) then
APos = AEnt:GetPos()
end
if IsValid(Player) then
local Bone = Player:LookupBone("ValveBiped.Bip01_R_Hand")
if Bone then
local Pos, Ang = Player:GetBonePosition(Bone)
local FPos = Pos + Ang:Forward() * 3.2 + Ang:Right() * 2 + Ang:Up() * -5
self:SetPos(FPos)
self:SetAngles(Ang)
render.SetMaterial(AttMat)
render.DrawBeam(self:GetPos(), APos, 1, 0, 0, Color(255, 255, 255, 255))
end
end
end
function ENT:OnRemove( )
end

View File

@@ -0,0 +1,23 @@
AddCSLuaFile( "cl_init.lua" )
AddCSLuaFile( "shared.lua" )
include('shared.lua')
function ENT:Initialize()
self.Entity:SetModel("models/tobadforyou/handcuffs.mdl")
self.Entity:PhysicsInit(SOLID_NONE)
self.Entity:SetMoveType(MOVETYPE_VPHYSICS)
self.Entity:SetSolid(SOLID_NONE)
self.Entity:SetUseType(SIMPLE_USE)
end
function ENT:Use( activator, caller )
end
function ENT:Think()
end
function ENT:Touch(TouchEnt)
if self.Entity.Touched and self.Entity.Touched > CurTime() then return ; end
self.Entity.Touched = CurTime() + 1;
end

View File

@@ -0,0 +1,16 @@
ENT.Type = "anim"
ENT.Base = "base_anim"
ENT.Category = "ToBadForYou"
ENT.Spawnable = false
ENT.PrintName = "Attatch Entity"
ENT.Author = "ToBadForYou"
ENT.Contact = ""
ENT.Purpose = ""
ENT.Instructions = ""
function ENT:SetupDataTables()
self:NetworkVar("Entity", 0, "OwningPlayer")
self:NetworkVar("Entity", 1, "AttatchedEntity")
self:NetworkVar("Vector", 0, "AttatchPosition")
end

View File

@@ -0,0 +1,42 @@
include('shared.lua')
function ENT:Initialize ()
local Data = RHandcuffsConfig.NPCData[self:GetClass()]
self.aps = Data.TextRotationSpeed
self.lastRot = CurTime()
self.curRot = 0
self.Font = Data.TextFont
self.Text = Data.Text
self.TextColor = Data.TextColor
self.TextBGColor = Data.TextBackgroundColor
end
function ENT:Draw()
self.curRot = self.curRot + (self.aps * (CurTime() - self.lastRot))
if (self.curRot > 360) then self.curRot = self.curRot - 360 end
self.lastRot = CurTime()
local Maxs = self:LocalToWorld(self:OBBMaxs())
local EntPos = self:GetPos()
local TextPos = Vector(EntPos.x,EntPos.y,Maxs.z+8)
local Text = self.Text
local Font = self.Font
surface.SetFont(Font)
local W,H = surface.GetTextSize(Text)
surface.SetDrawColor(self.TextBGColor)
cam.Start3D2D(TextPos, Angle(180, self.curRot, -90), .1)
surface.DrawRect(-W/2,-H/2,W,H)
draw.SimpleText(Text, Font, 0, 0, self.TextColor, TEXT_ALIGN_CENTER,TEXT_ALIGN_CENTER)
cam.End3D2D()
cam.Start3D2D(TextPos, Angle(180, self.curRot + 180, -90), .1)
draw.SimpleText(Text, Font, 0, 0, self.TextColor, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
cam.End3D2D()
self:DrawModel()
end
function ENT:OnRemove( )
end

View File

@@ -0,0 +1,31 @@
AddCSLuaFile("cl_init.lua")
AddCSLuaFile("shared.lua")
include('shared.lua')
function ENT:Initialize()
local Data = RHandcuffsConfig.NPCData[self:GetClass()]
self:SetModel(Data.Model)
self:SetSolid(SOLID_BBOX);
self:PhysicsInit(SOLID_BBOX);
self:SetMoveType(MOVETYPE_NONE);
self:DrawShadow(true);
self:SetUseType(SIMPLE_USE);
self:SetFlexWeight( 10, 0 )
self:ResetSequence(3)
end
function ENT:Use(activator, caller)
if self.Touched and self.Touched > CurTime() then return ; end
self.Touched = CurTime() + 2;
if (RHC_GetConf("BAIL_RestrictBailing") and activator:CanRHCBail()) or !RHC_GetConf("BAIL_RestrictBailing") then
net.Start("RHC_Bailer_Menu")
net.Send(activator)
else
TBFY_Notify(activator, 1, 4, RHC_GetLang("NotAllowedToUseBailer"))
end
end
function ENT:Think()
end

View File

@@ -0,0 +1,11 @@
ENT.Type = "anim"
ENT.Base = "base_anim"
ENT.Category = "ToBadForYou"
ENT.Spawnable = false
ENT.PrintName = "Bailer NPC"
ENT.Author = "ToBadForYou"
ENT.Contact = ""
ENT.Purpose = ""
ENT.Instructions = ""
ENT.TBFYEnt = true

View File

@@ -0,0 +1,40 @@
include('shared.lua')
function ENT:Initialize ()
self.aps = 50
self.lastRot = CurTime()
self.curRot = 0
self.Font = "DermaDefault"
self.Text = "Jailer"
self.TextColor = Color(255,255,255,255)
self.TextBGColor = Color(0,0,0,200)
end
function ENT:Draw()
self.curRot = self.curRot + (self.aps * (CurTime() - self.lastRot))
if (self.curRot > 360) then self.curRot = self.curRot - 360 end
self.lastRot = CurTime()
local Maxs = self:LocalToWorld(self:OBBMaxs())
local EntPos = self:GetPos()
local TextPos = Vector(EntPos.x,EntPos.y,Maxs.z+8)
local Text = self.Text
local Font = self.Font
surface.SetFont(Font)
local W,H = surface.GetTextSize(Text)
surface.SetDrawColor(self.TextBGColor)
cam.Start3D2D(TextPos, Angle(180, self.curRot, -90), .1)
surface.DrawRect(-W/2,-H/2,W+8,H+8)
draw.SimpleText(Text, Font, 0, 0, self.TextColor, TEXT_ALIGN_CENTER,TEXT_ALIGN_CENTER)
cam.End3D2D()
cam.Start3D2D(TextPos, Angle(180, self.curRot + 180, -90), .1)
draw.SimpleText(Text, Font, 0, 0, self.TextColor, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
cam.End3D2D()
self:DrawModel()
end
function ENT:OnRemove( )
end

View File

@@ -0,0 +1,38 @@
AddCSLuaFile("cl_init.lua")
AddCSLuaFile("shared.lua")
include('shared.lua')
function ENT:Initialize()
self:SetModel("models/Barney.mdl") -- Standalone default model
self:SetSolid(SOLID_BBOX)
self:PhysicsInit(SOLID_BBOX)
self:SetMoveType(MOVETYPE_NONE)
self:DrawShadow(true)
self:SetUseType(SIMPLE_USE)
self:SetFlexWeight(10, 0)
self:ResetSequence(3)
end
local function IsPolice(ply)
return true
end
function ENT:Use(activator, caller)
if self.Touched and self.Touched > CurTime() then return end
self.Touched = CurTime() + 2
-- Removing specific job check to allow anyone to use the jailer
activator.LastJailerNPC = self
net.Start("RHC_Jailer_Menu")
net.WriteEntity(activator.Dragging)
net.WriteString("RF")
net.Send(activator)
-- The else block and restriction message are removed.
-- if not isAllowed then
-- activator:ChatPrint("Только сотрудники исполнительной власти могут использовать этого NPC.")
-- return
-- end
end
function ENT:Think()
end

View File

@@ -0,0 +1,12 @@
ENT.Type = "anim"
ENT.Base = "base_anim"
ENT.Category = "ToBadForYou"
ENT.Spawnable = true
ENT.AdminSpawnable = true
ENT.PrintName = "Jailer NPC"
ENT.Author = "Military RP"
ENT.Contact = ""
ENT.Purpose = ""
ENT.Instructions = ""
ENT.TBFYEnt = true

View File

@@ -0,0 +1,5 @@
include('shared.lua')
function ENT:Draw()
self:DrawModel()
end

View File

@@ -0,0 +1,55 @@
AddCSLuaFile("cl_init.lua")
AddCSLuaFile("shared.lua")
include("shared.lua")
util.AddNetworkString("RHC_Jailer_Menu")
local RUSSIAN_FACTION = FACTION_RUSSIAN
local SPECIAL_PODR = 6
function ENT:Initialize()
self:SetModel("models/Barney.mdl")
self:SetSolid(SOLID_BBOX)
self:PhysicsInit(SOLID_BBOX)
self:SetMoveType(MOVETYPE_NONE)
self:DrawShadow(true)
self:SetUseType(SIMPLE_USE)
self:SetFlexWeight(10, 0)
self:ResetSequence(3)
end
function ENT:Use(activator)
if self.Touched and self.Touched > CurTime() then return end
self.Touched = CurTime() + 1.5
local char = activator:GetCharacter()
if not char then return end
-- Removing specific job check to allow anyone to use the jailer
-- if not isAllowed then
-- activator:ChatPrint("Только сотрудники исполнительной власти могут использовать этого NPC.")
-- return
-- end
local targetPly = activator.Dragging
if not IsValid(targetPly) then
local closestDist = 40000 -- 200 units
for _, p in ipairs(player.GetAll()) do
if p ~= activator and p:GetNWBool("rhc_cuffed", false) then
local dist = p:GetPos():DistToSqr(activator:GetPos())
if dist < closestDist then
closestDist = dist
targetPly = p
end
end
end
end
activator.LastJailerNPC = self
activator.LastJailerFaction = "RF"
net.Start("RHC_Jailer_Menu")
net.WriteEntity(targetPly)
net.WriteString("RF")
net.Send(activator)
end

View File

@@ -0,0 +1,12 @@
ENT.Type = "anim"
ENT.Base = "base_anim"
ENT.Category = "ToBadForYou"
ENT.Spawnable = true
ENT.AdminSpawnable = true
ENT.PrintName = "Jailer NPC (RF)"
ENT.Author = "Military RP"
ENT.Contact = ""
ENT.Purpose = ""
ENT.Instructions = ""
ENT.TBFYEnt = true

View File

@@ -0,0 +1,5 @@
include('shared.lua')
function ENT:Draw()
self:DrawModel()
end

View File

@@ -0,0 +1,55 @@
AddCSLuaFile("cl_init.lua")
AddCSLuaFile("shared.lua")
include("shared.lua")
util.AddNetworkString("RHC_Jailer_Menu")
local UKRAINE_FACTION = FACTION_UKRAINE
local SPECIAL_PODR = 6
function ENT:Initialize()
self:SetModel("models/Barney.mdl")
self:SetSolid(SOLID_BBOX)
self:PhysicsInit(SOLID_BBOX)
self:SetMoveType(MOVETYPE_NONE)
self:DrawShadow(true)
self:SetUseType(SIMPLE_USE)
self:SetFlexWeight(10, 0)
self:ResetSequence(3)
end
function ENT:Use(activator)
if self.Touched and self.Touched > CurTime() then return end
self.Touched = CurTime() + 1.5
local char = activator:GetCharacter()
if not char then return end
-- Removing specific job check to allow anyone to use the jailer
-- if not isAllowed then
-- activator:ChatPrint("Только сотрудники исполнительной власти могут использовать этого NPC.")
-- return
-- end
local targetPly = activator.Dragging
if not IsValid(targetPly) then
local closestDist = 40000 -- 200 units
for _, p in ipairs(player.GetAll()) do
if p ~= activator and p:GetNWBool("rhc_cuffed", false) then
local dist = p:GetPos():DistToSqr(activator:GetPos())
if dist < closestDist then
closestDist = dist
targetPly = p
end
end
end
end
activator.LastJailerNPC = self
activator.LastJailerFaction = "UK"
net.Start("RHC_Jailer_Menu")
net.WriteEntity(targetPly)
net.WriteString("UK")
net.Send(activator)
end

View File

@@ -0,0 +1,12 @@
ENT.Type = "anim"
ENT.Base = "base_anim"
ENT.Category = "ToBadForYou"
ENT.Spawnable = true
ENT.AdminSpawnable = true
ENT.PrintName = "Jailer NPC (UK)"
ENT.Author = "Military RP"
ENT.Contact = ""
ENT.Purpose = ""
ENT.Instructions = ""
ENT.TBFYEnt = true

View File

@@ -0,0 +1,27 @@
local MODULE = GAS.Logging:MODULE()
MODULE.Category = "ToBadForYou"
MODULE.Name = "Realistic Handcuffs"
MODULE.Colour = Color(0,0,255)
MODULE:Hook("RHC_restrain","rhc_toggle_restrain",function(vic, handcuffer)
local LogText = "cuffed"
if !vic.Restrained then
LogText = "uncuffed"
end
MODULE:Log(GAS.Logging:FormatPlayer(handcuffer) .. " " .. LogText .. " " .. GAS.Logging:FormatPlayer(vic))
end)
MODULE:Hook("RHC_jailed","rhc_jailed_player",function(vic, jailer, time, reason)
MODULE:Log(GAS.Logging:FormatPlayer(jailer) .. " jailed " .. GAS.Logging:FormatPlayer(vic) .. " for " .. time .. " seconds, reason: " .. reason)
end)
MODULE:Hook("RHC_confis_weapon","rhc_confis_w",function(vic, confis, wep)
MODULE:Log(GAS.Logging:FormatPlayer(confis) .. " confiscated a " .. wep .. " from " .. GAS.Logging:FormatPlayer(vic) .. ".")
end)
MODULE:Hook("RHC_confis_item","rhc_confis_i",function(vic, confis, item)
MODULE:Log(GAS.Logging:FormatPlayer(confis) .. " confiscated a " .. item .. " from " .. GAS.Logging:FormatPlayer(vic) .. ".")
end)
GAS.Logging:AddModule(MODULE)

View File

@@ -0,0 +1,23 @@
--[[
mLogs 2 (M4D Logs 2)
Created by M4D | http://m4d.one/ | http://steamcommunity.com/id/m4dhead |
Copyright © 2018 M4D.one All Rights Reserved
All 3rd party content is public domain or used with permission
M4D.one is the copyright holder of all code below. Do not distribute in any circumstances.
--]]
mLogs.addCategory(
"Realistic Handcuff System", -- Name
"rhandcuff",
Color(0,0,255), -- Color
function() -- Check
return true
end,
true
)
mLogs.addCategoryDefinitions("rhandcuff", {
cuffing = function(data) return mLogs.doLogReplace({"^player1", "^action", "^player2"},data) end,
jailing = function(data) return mLogs.doLogReplace({"^player1", "jailed", "^player2", "for", "^time", "seconds, reason:", "^reason"},data) end,
confiscation = function(data) return mLogs.doLogReplace({"^player1", "confiscated a", "^item", "from", "^player2"},data) end,
})

View File

@@ -0,0 +1,19 @@
--[[
mLogs 2 (M4D Logs 2)
Created by M4D | http://m4d.one/ | http://steamcommunity.com/id/m4dhead |
Copyright © 2018 M4D.one All Rights Reserved
All 3rd party content is public domain or used with permission
M4D.one is the copyright holder of all code below. Do not distribute in any circumstances.
--]]
local category = "rhandcuff"
mLogs.addLogger("Confiscation","confiscation",category)
mLogs.addHook("RHC_confis_weapon", category, function(vic,confis, wep)
if(not IsValid(vic) or not IsValid(confis))then return end
mLogs.log("confiscation", category, {player1=mLogs.logger.getPlayerData(confis),item=wep,player2=mLogs.logger.getPlayerData(vic),a=true})
end)
mLogs.addHook("RHC_confis_item", category, function(vic,confis, item)
if(not IsValid(vic) or not IsValid(confis))then return end
mLogs.log("confiscation", category, {player1=mLogs.logger.getPlayerData(confis),item=item,player2=mLogs.logger.getPlayerData(vic),a=true})
end)

View File

@@ -0,0 +1,20 @@
--[[
mLogs 2 (M4D Logs 2)
Created by M4D | http://m4d.one/ | http://steamcommunity.com/id/m4dhead |
Copyright © 2018 M4D.one All Rights Reserved
All 3rd party content is public domain or used with permission
M4D.one is the copyright holder of all code below. Do not distribute in any circumstances.
--]]
local category = "rhandcuff"
mLogs.addLogger("Cuffing","cuffing",category)
mLogs.addHook("RHC_restrain", category, function(vic,handcuffer)
if(not IsValid(vic) or not IsValid(handcuffer))then return end
local LogText = "cuffed"
if !vic.Restrained then
LogText = "uncuffed"
end
mLogs.log("cuffing", category, {player1=mLogs.logger.getPlayerData(handcuffer),action=LogText,player2=mLogs.logger.getPlayerData(vic),a=true})
end)

View File

@@ -0,0 +1,15 @@
--[[
mLogs 2 (M4D Logs 2)
Created by M4D | http://m4d.one/ | http://steamcommunity.com/id/m4dhead |
Copyright © 2018 M4D.one All Rights Reserved
All 3rd party content is public domain or used with permission
M4D.one is the copyright holder of all code below. Do not distribute in any circumstances.
--]]
local category = "rhandcuff"
mLogs.addLogger("Jailing","jailing",category)
mLogs.addHook("RHC_jailed", category, function(vic, jailer, time, reason)
if(not IsValid(vic) or not IsValid(jailer))then return end
mLogs.log("jailing", category, {player1=mLogs.logger.getPlayerData(jailer),player2=mLogs.logger.getPlayerData(vic),time=time, reason=reason,a=true})
end)

View File

@@ -0,0 +1 @@
-- Cleared to fix syntax error "expected near end"

View File

@@ -0,0 +1,51 @@
if SERVER then
AddCSLuaFile("shared.lua")
end
if CLIENT then
SWEP.PrintName = "Surrender"
SWEP.Slot = 2
SWEP.SlotPos = 1
SWEP.DrawAmmo = false
SWEP.DrawCrosshair = false
end
SWEP.Author = "ToBadForYou"
SWEP.Instructions = ""
SWEP.Contact = ""
SWEP.Purpose = ""
SWEP.HoldType = "passive";
SWEP.ViewModelFlip = false
SWEP.AnimPrefix = "passive"
SWEP.Category = "ToBadForYou"
SWEP.UID = 76561198187122039
SWEP.Spawnable = false
SWEP.AdminSpawnable = false
SWEP.Primary.ClipSize = -1
SWEP.Primary.DefaultClip = 0
SWEP.Primary.Automatic = false
SWEP.Primary.Ammo = ""
SWEP.Secondary.ClipSize = -1
SWEP.Secondary.DefaultClip = 0
SWEP.Secondary.Automatic = false
SWEP.Secondary.Ammo = ""
function SWEP:Initialize() self:SetHoldType("passive") end
function SWEP:CanPrimaryAttack() return false; end
function SWEP:SecondaryAttack() return false; end
function SWEP:PreDrawViewModel(vm)
return true
end
function SWEP:DrawWorldModel()
end
if CLIENT then
function SWEP:DrawHUD()
draw.SimpleTextOutlined(RHC_GetLang("SurrenderedText"),"Trebuchet24",ScrW()/2,ScrH()/12,Color(255,255,255,255), TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM,2,Color(0,0,0,255))
end
end

View File

@@ -0,0 +1,138 @@
if SERVER then
AddCSLuaFile("shared.lua")
end
if CLIENT then
SWEP.PrintName = "Cuffed"
SWEP.Slot = 2
SWEP.SlotPos = 1
SWEP.DrawAmmo = false
SWEP.DrawCrosshair = false
end
SWEP.Author = "Military RP"
SWEP.Instructions = ""
SWEP.Contact = ""
SWEP.Purpose = ""
SWEP.HoldType = "passive"
SWEP.ViewModelFlip = false
SWEP.AnimPrefix = "passive"
SWEP.Category = "Military RP"
SWEP.Spawnable = false
SWEP.AdminSpawnable = false
SWEP.ViewModel = "models/tobadforyou/c_hand_cuffs.mdl"
SWEP.WorldModel = "models/tobadforyou/handcuffs.mdl"
SWEP.Primary.ClipSize = -1
SWEP.Primary.DefaultClip = 0
SWEP.Primary.Automatic = false
SWEP.Primary.Ammo = ""
SWEP.Secondary.ClipSize = -1
SWEP.Secondary.DefaultClip = 0
SWEP.Secondary.Automatic = false
SWEP.Secondary.Ammo = ""
local CuffedBones = {
["ValveBiped.Bip01_R_UpperArm"] = Angle(-21.4, 21.4, 3.6),
["ValveBiped.Bip01_L_UpperArm"] = Angle(30, 8.2, 27.8),
["ValveBiped.Bip01_R_Forearm"] = Angle(0, 25, -10.7),
["ValveBiped.Bip01_L_Forearm"] = Angle(-11.5, 31.1, -18),
["ValveBiped.Bip01_R_Hand"] = Angle(14.3, -14.3, 60),
["ValveBiped.Bip01_L_Hand"] = Angle(-11, 14.7, 70.4),
}
function SWEP:Initialize()
self:SetHoldType("normal")
end
function SWEP:CanPrimaryAttack() return false end
function SWEP:SecondaryAttack() return false end
function SWEP:Reload() return false end
function SWEP:Deploy()
self:SetHoldType("normal")
if SERVER then
local ply = self:GetOwner()
if IsValid(ply) then
for boneName, ang in pairs(CuffedBones) do
local boneId = ply:LookupBone(boneName)
if boneId then
ply:ManipulateBoneAngles(boneId, ang)
end
end
end
end
return true
end
function SWEP:Holster()
if SERVER then
local ply = self:GetOwner()
if IsValid(ply) then
for boneName, _ in pairs(CuffedBones) do
local boneId = ply:LookupBone(boneName)
if boneId then
ply:ManipulateBoneAngles(boneId, Angle(0,0,0))
end
end
end
end
return true
end
function SWEP:OnRemove()
if SERVER then
local ply = self:GetOwner()
if IsValid(ply) then
for boneName, _ in pairs(CuffedBones) do
local boneId = ply:LookupBone(boneName)
if boneId then
ply:ManipulateBoneAngles(boneId, Angle(0,0,0))
end
end
end
end
end
if CLIENT then
function SWEP:PreDrawViewModel(vm) return true end
function SWEP:DrawWorldModel()
local ply = self:GetOwner()
if not IsValid(ply) then return end
local boneindex = ply:LookupBone("ValveBiped.Bip01_L_Hand")
if boneindex then
local pos, ang = ply:GetBonePosition(boneindex)
if pos and ang then
-- Hardcoded tuned values
local cx, cy, cz = 0.9, 0.8, 4.8
local cp, cyaw, cr = 7.1, -14.3, 96.2
local offset = ang:Forward() * cx + ang:Right() * cy + ang:Up() * cz
ang:RotateAroundAxis(ang:Right(), cp)
ang:RotateAroundAxis(ang:Up(), cyaw)
ang:RotateAroundAxis(ang:Forward(), cr)
self:SetRenderOrigin(pos + offset)
self:SetRenderAngles(ang)
self:DrawModel()
end
end
end
end
if SERVER then
hook.Add("PlayerSwitchWeapon", "MRP_Handcuffs_PreventSwitch", function(ply, oldWep, newWep)
if ply:GetNWBool("rhc_cuffed", false) and newWep:GetClass() ~= "weapon_r_cuffed" then
return true -- Block switching weapons when cuffed
end
end)
end
if CLIENT then
function SWEP:DrawHUD()
draw.SimpleTextOutlined("Вы закованы в наручники","Trebuchet24",ScrW()/2,ScrH() - 100,Color(255,100,100,255), TEXT_ALIGN_CENTER, TEXT_ALIGN_BOTTOM,2,Color(0,0,0,255))
end
end

View File

@@ -0,0 +1,379 @@
if SERVER then
AddCSLuaFile("shared.lua")
end
if CLIENT then
SWEP.PrintName = "Handcuffs"
SWEP.Slot = 2
SWEP.SlotPos = 1
SWEP.DrawAmmo = false
SWEP.DrawCrosshair = false
end
SWEP.Author = "ToBadForYou"
SWEP.Instructions = "Left Click: Restrain/Release.\nRight Click: Force Players out of vehicle.\nReload: Drag Cuffed Player."
SWEP.Contact = ""
SWEP.Purpose = ""
SWEP.HoldType = "melee"
SWEP.UseHands = true
SWEP.ViewModelFOV = 62
SWEP.ViewModelFlip = false
SWEP.AnimPrefix = "melee"
SWEP.Category = "Military RP"
SWEP.Spawnable = true
SWEP.AdminSpawnable = true
SWEP.Primary.ClipSize = -1
SWEP.Primary.DefaultClip = 0
SWEP.Primary.Automatic = false
SWEP.Primary.Ammo = ""
SWEP.Secondary.ClipSize = -1
SWEP.Secondary.DefaultClip = 0
SWEP.Secondary.Automatic = false
SWEP.Secondary.Ammo = ""
SWEP.PlayBackRate = 2
function SWEP:Initialize()
self:SetHoldType("melee")
self.ViewModel = "models/tobadforyou/c_hand_cuffs.mdl"
self.WorldModel = "models/tobadforyou/handcuffs.mdl"
end
function SWEP:CanPrimaryAttack() return true end
function SWEP:CanSecondaryAttack() return true end
function SWEP:PlayCuffSound(Time)
timer.Simple(Time, function() if IsValid(self) then self:EmitSound("npc/metro-police/gear2.wav") end end)
timer.Simple(Time+1, function() if IsValid(self) then self:EmitSound("npc/metro-police/gear2.wav") end end)
end
local function IsPolice(ply)
return true
end
local function RestrainPlayer(target, cop)
if not IsValid(target) or not target:IsPlayer() then return end
target:SetNWBool("rhc_cuffed", true)
if SERVER then
target:EmitSound("npc/metro-police/gear2.wav")
local serverlogsPlugin = ix.plugin.list["serverlogs"]
if serverlogsPlugin then
serverlogsPlugin:AddLog("HANDCUFF_RESTRAIN", cop:Nick() .. " restrained " .. target:Nick(), cop, {target = target})
end
-- Save weapons
target.RHC_SavedWeapons = {}
for _, w in ipairs(target:GetWeapons()) do
table.insert(target.RHC_SavedWeapons, w:GetClass())
end
target:StripWeapons()
target:Give("weapon_r_cuffed")
target:SelectWeapon("weapon_r_cuffed")
target.RHC_OldWalk = target:GetWalkSpeed()
target.RHC_OldRun = target:GetRunSpeed()
target:SetWalkSpeed(100)
target:SetRunSpeed(100)
end
end
local CuffedBones = {
["ValveBiped.Bip01_R_UpperArm"] = true,
["ValveBiped.Bip01_L_UpperArm"] = true,
["ValveBiped.Bip01_R_Forearm"] = true,
["ValveBiped.Bip01_L_Forearm"] = true,
["ValveBiped.Bip01_R_Hand"] = true,
["ValveBiped.Bip01_L_Hand"] = true,
}
local function UnrestrainPlayer(target, cop)
if not IsValid(target) or not target:IsPlayer() then return end
target:SetNWBool("rhc_cuffed", false)
target:SetNWBool("MRP_Gagged", false)
target:SetNWBool("MRP_Blindfolded", false)
if SERVER then
target:EmitSound("npc/metro-police/gear2.wav")
local serverlogsPlugin = ix.plugin.list["serverlogs"]
if serverlogsPlugin then
serverlogsPlugin:AddLog("HANDCUFF_UNRESTRAIN", cop:Nick() .. " unrestrained " .. target:Nick(), cop, {target = target})
end
target:StripWeapon("weapon_r_cuffed")
for boneName, _ in pairs(CuffedBones) do
local boneId = target:LookupBone(boneName)
if boneId then
target:ManipulateBoneAngles(boneId, Angle(0,0,0))
end
end
if target.RHC_SavedWeapons then
for _, class in ipairs(target.RHC_SavedWeapons) do
target:Give(class)
end
target.RHC_SavedWeapons = nil
end
if target.RHC_OldWalk then
target:SetWalkSpeed(target.RHC_OldWalk)
target:SetRunSpeed(target.RHC_OldRun)
end
if IsValid(target.DraggedBy) then
target.DraggedBy.Dragging = nil
target.DraggedBy = nil
end
end
end
function SWEP:Think()
local target = self.AttemptToCuff
if IsValid(target) then
local vm = self.Owner:GetViewModel()
local ResetSeq = vm:LookupSequence("Reset")
local TraceEnt = self.Owner:GetEyeTrace().Entity
local distance = target:GetPos():Distance(self.Owner:GetPos())
if not IsValid(TraceEnt) or TraceEnt ~= target or distance > 150 then
self.AttemptToCuff = nil
target.RHC_BeingCuffed = false
vm:SendViewModelMatchingSequence(ResetSeq)
target:Freeze(false)
elseif CurTime() >= self.AttemptCuffFinish then
if SERVER then
RestrainPlayer(target, self.Owner)
end
target.RHC_BeingCuffed = false
self.AttemptToCuff = nil
vm:SendViewModelMatchingSequence(ResetSeq)
target:Freeze(false)
end
end
end
function SWEP:PrimaryAttack()
self.Weapon:SetNextPrimaryFire(CurTime() + 1.5)
if not IsPolice(self.Owner) then
if SERVER then self.Owner:ChatPrint("Вам не разрешено использовать наручники.") end
return
end
self.Weapon:EmitSound("npc/vort/claw_swing" .. math.random(1, 2) .. ".wav")
self.Owner:SetAnimation(PLAYER_ATTACK1)
local target = self.Owner:GetEyeTrace().Entity
if not IsValid(target) or not target:IsPlayer() then return end
if self.Owner:EyePos():Distance(target:GetPos()) > 150 then return end
-- Uncuff
if target:GetNWBool("rhc_cuffed", false) then
if SERVER then UnrestrainPlayer(target, self.Owner) end
return
end
-- Begin Cuffing
self.AttemptToCuff = target
self.AttemptCuffStart = CurTime()
self.AttemptCuffFinish = CurTime() + 2
target.RHC_BeingCuffed = true
local vm = self.Owner:GetViewModel()
local DeploySeq = vm:LookupSequence("Deploy")
vm:SendViewModelMatchingSequence(DeploySeq)
vm:SetPlaybackRate(self.PlayBackRate)
self:PlayCuffSound(0.3)
if SERVER then target:Freeze(true) end
end
-- Dragging logic mapped to Reload
function SWEP:Reload()
if not IsFirstTimePredicted() then return end
if self.NextRPress and self.NextRPress > CurTime() then return end
self.NextRPress = CurTime() + 1
if CLIENT then return end
local target = self.Owner:GetEyeTrace().Entity
-- Stop dragging
if IsValid(self.Owner.Dragging) then
self.Owner.Dragging.DraggedBy = nil
self.Owner.Dragging = nil
self.Owner:ChatPrint("Вы перестали тащить игрока.")
return
end
-- Start dragging
if IsValid(target) and target:IsPlayer() and target:GetNWBool("rhc_cuffed", false) then
if self.Owner:EyePos():Distance(target:GetPos()) <= 150 then
self.Owner.Dragging = target
target.DraggedBy = self.Owner
self.Owner:ChatPrint("Вы теперь тащите " .. target:Nick())
end
end
end
function SWEP:SecondaryAttack()
-- Force out of vehicle
self.Weapon:SetNextSecondaryFire(CurTime() + 1)
if CLIENT then return end
if not IsPolice(self.Owner) then return end
-- Helper function to find an empty seat
local function GetEmptySeat(veh)
if veh.IsDriveable and veh:IsDriveable() then
-- LVS Specific
if veh.GetDriver and not IsValid(veh:GetDriver()) then
local dSeat = veh:GetDriverSeat()
if IsValid(dSeat) then return dSeat end
end
if veh.GetPassengerSeats then
for _, seat in pairs(veh:GetPassengerSeats()) do
if IsValid(seat) and not IsValid(seat:GetDriver()) then
return seat
end
end
end
return nil
end
-- Standard/Simfphys
if veh.GetDriver and not IsValid(veh:GetDriver()) then return veh end
if veh.pSeats then
for _, seat in pairs(veh.pSeats) do
if IsValid(seat) and not IsValid(seat:GetDriver()) then
return seat
end
end
end
return nil
end
local target = self.Owner:GetEyeTrace().Entity
if not IsValid(target) then return end
if self.Owner:GetPos():Distance(target:GetPos()) > 300 then return end
local isVeh = target:IsVehicle() or (target.GetClass and string.find(string.lower(target:GetClass()), "lvs"))
if IsValid(self.Owner.Dragging) then
local dragged = self.Owner.Dragging
if isVeh then
local seat = GetEmptySeat(target)
if IsValid(seat) then
dragged:EnterVehicle(seat)
self.Owner.Dragging = nil
dragged.DraggedBy = nil
self.Owner:ChatPrint("Игрок посажен в транспорт.")
else
self.Owner:ChatPrint("Нет свободных мест.")
end
end
else
if isVeh then
local found = false
-- LVS Specific
if target.IsDriveable and target:IsDriveable() then
local drv = target:GetDriver()
if IsValid(drv) and drv:GetNWBool("rhc_cuffed", false) then
drv:ExitVehicle()
found = true
end
if target.GetPassengerSeats then
for _, seat in pairs(target:GetPassengerSeats()) do
local sDrv = IsValid(seat) and seat:GetDriver()
if IsValid(sDrv) and sDrv:GetNWBool("rhc_cuffed", false) then
sDrv:ExitVehicle()
found = true
end
end
end
else
-- Standard/Simfphys
local drv = target:GetDriver()
if IsValid(drv) and drv:GetNWBool("rhc_cuffed", false) then
drv:ExitVehicle()
found = true
end
if target.pSeats then
for _, seat in pairs(target.pSeats) do
local sDrv = IsValid(seat) and seat:GetDriver()
if IsValid(sDrv) and sDrv:GetNWBool("rhc_cuffed", false) then
sDrv:ExitVehicle()
found = true
end
end
end
end
if found then
self.Owner:ChatPrint("Игрок(и) вытащен(ы) из транспорта.")
end
end
end
end
if SERVER then
hook.Add("PlayerTick", "MRP_Handcuffs_DragLogic", function(ply)
local dragged = ply.Dragging
if IsValid(dragged) and dragged:IsPlayer() and dragged:GetNWBool("rhc_cuffed", false) then
local dist = ply:GetPos():Distance(dragged:GetPos())
if dist > 300 then
ply.Dragging = nil
dragged.DraggedBy = nil
ply:ChatPrint("Таскание прекращено: слишком далеко.")
elseif dist > 100 then
local dir = (ply:GetPos() - dragged:GetPos()):GetNormalized()
dragged:SetVelocity(dir * (dist * 2))
end
elseif dragged then
ply.Dragging = nil
if IsValid(dragged) then dragged.DraggedBy = nil end
end
end)
hook.Add("PlayerDisconnected", "MRP_Handcuffs_DragCleanup", function(ply)
if IsValid(ply.DraggedBy) then ply.DraggedBy.Dragging = nil end
if IsValid(ply.Dragging) then ply.Dragging.DraggedBy = nil end
end)
end
if CLIENT then
function SWEP:DrawWorldModel()
if not IsValid(self.Owner) then return end
local boneindex = self.Owner:LookupBone("ValveBiped.Bip01_R_Hand")
if boneindex then
local HPos, HAng = self.Owner:GetBonePosition(boneindex)
local offset = HAng:Right() * 0.5 + HAng:Forward() * 3.3
HAng:RotateAroundAxis(HAng:Right(), 0)
HAng:RotateAroundAxis(HAng:Forward(), -90)
self:SetRenderOrigin(HPos + offset)
self:SetRenderAngles(HAng)
self:DrawModel()
end
end
function SWEP:DrawHUD()
draw.SimpleText("ЛКМ: Надеть/Снять наручники", "default", ScrW()/2, 5, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP, 2, color_black)
draw.SimpleText("ПКМ: Посадить/Вытащить из транспорта", "default", ScrW()/2, 15, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP, 2, color_black)
draw.SimpleText("Перезарядка (R): Тащить закованного", "default", ScrW()/2, 25, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_TOP, 2, color_black)
local target = self.AttemptToCuff
if not IsValid(target) then return end
local percent = math.Clamp((CurTime() - self.AttemptCuffStart) / (self.AttemptCuffFinish - self.AttemptCuffStart), 0, 1)
draw.SimpleText("Заковываем " .. target:Nick() .. " (" .. math.Round(percent * 100) .. "%)", "DermaLarge", ScrW()/2, ScrH()/2, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
end
end