add sborka
This commit is contained in:
@@ -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
|
||||
@@ -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)
|
||||
@@ -0,0 +1 @@
|
||||
-- Cleared to fix "attempt to index global ENT" error
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
if SERVER then
|
||||
-- Suppress missing file errors
|
||||
end
|
||||
if CLIENT then
|
||||
-- Suppress missing file errors
|
||||
end
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,5 @@
|
||||
include('shared.lua')
|
||||
|
||||
function ENT:Draw()
|
||||
self:DrawModel()
|
||||
end
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,5 @@
|
||||
include('shared.lua')
|
||||
|
||||
function ENT:Draw()
|
||||
self:DrawModel()
|
||||
end
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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,
|
||||
})
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -0,0 +1 @@
|
||||
-- Cleared to fix syntax error "expected near end"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user