@@ -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