This commit is contained in:
lifestorm
2024-08-04 23:54:45 +03:00
parent 8064ba84d8
commit 6a58f406b1
7522 changed files with 4011896 additions and 15 deletions

View File

@@ -0,0 +1,138 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
properties.Add( "bodygroups", {
MenuLabel = "#bodygroups",
Order = 600,
MenuIcon = "icon16/link_edit.png",
Filter = function( self, ent, ply )
if ( !IsValid( ent ) ) then return false end
if ( ent:IsPlayer() ) then return false end
if ( !gamemode.Call( "CanProperty", ply, "bodygroups", ent ) ) then return false end
if ( IsValid( ent.AttachedEntity ) ) then ent = ent.AttachedEntity end -- If our ent has an attached entity, we want to use and modify its bodygroups instead
--
-- Get a list of bodygroups
--
local options = ent:GetBodyGroups()
if ( !options ) then return false end
--
-- If a bodygroup has more than one state - then we can configure it
--
for k, v in pairs( options ) do
if ( v.num > 1 ) then return true end
end
return false
end,
MenuOpen = function( self, option, ent, tr )
local target = IsValid( ent.AttachedEntity ) and ent.AttachedEntity or ent
--
-- Get a list of bodygroups
--
local options = target:GetBodyGroups()
--
-- Add a submenu to our automatically created menu option
--
local submenu = option:AddSubMenu()
--
-- For each body group - add a menu or checkbox
--
for k, v in pairs( options ) do
if ( v.num <= 1 ) then continue end
--
-- If there's only 2 options, add it as a checkbox instead of a submenu
--
if ( v.num == 2 ) then
local current = target:GetBodygroup( v.id )
local opposite = 1
if ( current == opposite ) then opposite = 0 end
local opt = submenu:AddOption( string.NiceName( v.name ) )
opt:SetChecked( current == 1 )
opt:SetIsCheckable( true )
opt.OnChecked = function( s, checked ) self:SetBodyGroup( ent, v.id, checked and 1 or 0 ) end
--
-- More than 2 options we add our own submenu
--
else
local groups = submenu:AddSubMenu( string.NiceName( v.name ) )
for i = 1, v.num do
local modelname = "Model #" .. i
if ( v.submodels and v.submodels[ i - 1 ] != "" ) then modelname = v.submodels[ i - 1 ] end
modelname = string.Trim( modelname, "." )
modelname = string.Trim( modelname, "/" )
modelname = string.Trim( modelname, "\\" )
modelname = string.StripExtension( modelname )
modelname = string.GetFileFromFilename( modelname )
local opt = groups:AddOption( string.NiceName( modelname ) )
opt:SetRadio( true )
opt:SetChecked( target:GetBodygroup( v.id ) == i - 1 )
opt:SetIsCheckable( true )
opt.OnChecked = function( s, checked ) if ( checked ) then self:SetBodyGroup( ent, v.id, i - 1 ) end end
end
end
end
end,
Action = function( self, ent )
-- Nothing - we use SetBodyGroup below
end,
SetBodyGroup = function( self, ent, body, id )
self:MsgStart()
net.WriteEntity( ent )
net.WriteUInt( body, 8 )
net.WriteUInt( id, 8 )
self:MsgEnd()
end,
Receive = function( self, length, ply )
local ent = net.ReadEntity()
local body = net.ReadUInt( 8 )
local id = net.ReadUInt( 8 )
if ( !properties.CanBeTargeted( ent, ply ) ) then return end
if ( !self:Filter( ent, ply ) ) then return end
ent = IsValid( ent.AttachedEntity ) and ent.AttachedEntity or ent
ent:SetBodygroup( body, id )
end
} )

View File

@@ -0,0 +1,236 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
properties.Add( "bone_manipulate", {
MenuLabel = "#edit_bones",
Order = 500,
MenuIcon = "icon16/vector.png",
Filter = function( self, ent, ply )
if ( !gamemode.Call( "CanProperty", ply, "bonemanipulate", ent ) ) then return false end
if ( IsValid( ent.AttachedEntity ) ) then ent = ent.AttachedEntity end -- If our ent has an attached entity, we want to use and modify its bones instead
local bonecount = ent:GetBoneCount()
if ( bonecount <= 1 ) then return false end
return ents.FindByClassAndParent( "widget_bones", ent ) == nil
end,
Action = function( self, ent )
if ( IsValid( ent.AttachedEntity ) ) then ent = ent.AttachedEntity end
self:MsgStart()
net.WriteEntity( ent )
self:MsgEnd()
end,
Receive = function( self, length, ply )
local ent = net.ReadEntity()
if ( !IsValid( ent ) ) then return end
if ( !properties.CanBeTargeted( ent, ply ) ) then return end
if ( !self:Filter( ent, ply ) ) then return end
ent.widget = ents.Create( "widget_bones" )
ent.widget:Setup( ent )
ent.widget:Spawn()
ent.widget.LastBonePress = 0
ent.widget.BonePressCount = 0
-- What happens when we click on a bone?
ent.widget.OnBoneClick = function( w, boneid, pl )
-- If we have an old axis, remove it
if ( IsValid( w.axis ) ) then w.axis:Remove() end
-- We clicked on the same bone
if ( w.LastBonePress == boneid ) then
w.BonePressCount = w.BonePressCount + 1
if ( w.BonePressCount >= 3 ) then w.BonePressCount = 0 end
-- We clicked on a new bone!
else
w.BonePressCount = 0
w.LastBonePress = boneid
end
local EntityCycle = { "widget_bonemanip_move", "widget_bonemanip_rotate", "widget_bonemanip_scale" }
w.axis = ents.Create( EntityCycle[ w.BonePressCount + 1 ] )
w.axis:Setup( ent, boneid, w.BonePressCount == 1 )
w.axis:Spawn()
w.axis:SetPriority( 0.5 )
w:DeleteOnRemove( w.axis )
end
end
} )
properties.Add( "bone_manipulate_end", {
MenuLabel = "#stop_editing_bones",
Order = 500,
MenuIcon = "icon16/vector_delete.png",
Filter = function( self, ent )
if ( IsValid( ent.AttachedEntity ) ) then ent = ent.AttachedEntity end -- If our ent has an attached entity, we want to use and modify its bones instead
return ents.FindByClassAndParent( "widget_bones", ent ) != nil
end,
Action = function( self, ent )
if ( IsValid( ent.AttachedEntity ) ) then ent = ent.AttachedEntity end
self:MsgStart()
net.WriteEntity( ent )
self:MsgEnd()
end,
Receive = function( self, length, ply )
local ent = net.ReadEntity()
if ( !IsValid( ent ) ) then return end
if ( !IsValid( ent.widget ) ) then return end
ent.widget:Remove()
end
} )
local widget_bonemanip_move = {
Base = "widget_axis",
OnArrowDragged = function( self, num, dist, pl, mv )
-- Prediction doesn't work properly yet.. because of the confusion with the bone moving, and the parenting, Agh.
if ( CLIENT ) then return end
local ent = self:GetParent()
if ( !IsValid( ent ) ) then return end
local bone = self:GetParentAttachment()
if ( bone <= 0 ) then return end
local v = Vector( 0, 0, 0 )
if ( num == 1 ) then v.x = dist end
if ( num == 2 ) then v.y = dist end
if ( num == 3 ) then v.z = dist end
ent:ManipulateBonePosition( bone, ent:GetManipulateBonePosition( bone ) + v )
end,
--
-- Although we use the position from our bone, we want to use the angles from the
-- parent bone - because that's the direction our bone goes
--
CalcAbsolutePosition = function( self, v, a )
local ent = self:GetParent()
if ( !IsValid( ent ) ) then return end
local bone = ent:GetBoneParent( self:GetParentAttachment() )
if ( bone <= 0 ) then return end
local _, ang = ent:GetBonePosition( bone )
local pos, _ = ent:GetBonePosition( self:GetParentAttachment() )
return pos, ang
end
}
scripted_ents.Register( widget_bonemanip_move, "widget_bonemanip_move" )
local widget_bonemanip_rotate = {
Base = "widget_axis",
OnArrowDragged = function( self, num, dist, pl, mv )
-- Prediction doesn't work properly yet.. because of the confusion with the bone moving, and the parenting, Agh.
if ( CLIENT ) then return end
local ent = self:GetParent()
if ( !IsValid( ent ) ) then return end
local bone = self:GetParentAttachment()
if ( bone <= 0 ) then return end
local v = Angle( 0, 0, 0 )
if ( num == 2 ) then v.x = dist end
if ( num == 3 ) then v.y = dist end
if ( num == 1 ) then v.z = dist end
ent:ManipulateBoneAngles( bone, ent:GetManipulateBoneAngles( bone ) + v )
end
}
scripted_ents.Register( widget_bonemanip_rotate, "widget_bonemanip_rotate" )
local widget_bonemanip_scale = {
Base = "widget_axis",
IsScaleArrow = true,
OnArrowDragged = function( self, num, dist, pl, mv )
-- Prediction doesn't work properly yet.. because of the confusion with the bone moving, and the parenting, Agh.
if ( CLIENT ) then return end
local ent = self:GetParent()
if ( !IsValid( ent ) ) then return end
local bone = self:GetParentAttachment()
if ( bone <= 0 ) then return end
local v = Vector( 0, 0, 0 )
if ( num == 1 ) then v.x = dist end
if ( num == 2 ) then v.y = dist end
if ( num == 3 ) then v.z = dist end
ent:ManipulateBoneScale( bone, ent:GetManipulateBoneScale( bone ) + v * 0.1 )
ent:ManipulateBoneScale( ent:GetBoneParent( bone ), ent:GetManipulateBoneScale( ent:GetBoneParent( bone ) ) + v )
end,
--
-- Although we use the position from our bone, we want to use the angles from the
-- parent bone - because that's the direction our bone goes
--
CalcAbsolutePosition = function( self, v, a )
local ent = self:GetParent()
if ( !IsValid( ent ) ) then return end
local bone = self:GetParentAttachment()
if ( bone <= 0 ) then return end
local pbone = ent:GetBoneParent( bone )
if ( pbone <= 0 ) then return end
local pos, ang = ent:GetBonePosition( bone )
local pos2, _ = ent:GetBonePosition( pbone )
return pos + ( pos2 - pos ) * 0.5, ang
end
}
scripted_ents.Register( widget_bonemanip_scale, "widget_bonemanip_scale" )

View File

@@ -0,0 +1,83 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
properties.Add( "collision_off", {
MenuLabel = "#collision_off",
Order = 1500,
MenuIcon = "icon16/collision_off.png",
Filter = function( self, ent, ply )
if ( !IsValid( ent ) ) then return false end
if ( ent:IsPlayer() ) then return false end
if ( !gamemode.Call( "CanProperty", ply, "collision", ent ) ) then return false end
if ( ent:GetCollisionGroup() == COLLISION_GROUP_WORLD ) then return false end
return true
end,
Action = function( self, ent )
self:MsgStart()
net.WriteEntity( ent )
self:MsgEnd()
end,
Receive = function( self, length, ply )
local ent = net.ReadEntity()
if ( !properties.CanBeTargeted( ent, ply ) ) then return end
if ( !self:Filter( ent, ply ) ) then return end
ent:SetCollisionGroup( COLLISION_GROUP_WORLD )
end
} )
properties.Add( "collision_on", {
MenuLabel = "#collision_on",
Order = 1500,
MenuIcon = "icon16/collision_on.png",
Filter = function( self, ent, ply )
if ( !IsValid( ent ) ) then return false end
if ( ent:IsPlayer() ) then return false end
if ( !gamemode.Call( "CanProperty", ply, "collision", ent ) ) then return false end
return ent:GetCollisionGroup() == COLLISION_GROUP_WORLD
end,
Action = function( self, ent )
self:MsgStart()
net.WriteEntity( ent )
self:MsgEnd()
end,
Receive = function( self, length, ply )
local ent = net.ReadEntity()
if ( !properties.CanBeTargeted( ent, ply ) ) then return end
if ( !self:Filter( ent, ply ) ) then return end
ent:SetCollisionGroup( COLLISION_GROUP_NONE )
end
} )

View File

@@ -0,0 +1,62 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
properties.Add( "drive", {
MenuLabel = "#drive",
Order = 1100,
MenuIcon = "icon16/joystick.png",
Filter = function( self, ent, ply )
if ( !IsValid( ent ) || !IsValid( ply ) ) then return false end
if ( ent:IsPlayer() || IsValid( ply:GetVehicle() ) ) then return false end
if ( !gamemode.Call( "CanProperty", ply, "drive", ent ) ) then return false end
if ( !gamemode.Call( "CanDrive", ply, ent ) ) then return false end
-- We cannot drive these, maybe this should have a custom GetEntityDriveMode?
if ( ent:GetClass() == "prop_vehicle_jeep" || ent:GetClass() == "prop_vehicle_jeep_old" ) then return false end
-- Make sure nobody else is driving this or we can get into really invalid states
for id, pl in ipairs( player.GetAll() ) do
if ( pl:GetDrivingEntity() == ent ) then return false end
end
return true
end,
Action = function( self, ent )
self:MsgStart()
net.WriteEntity( ent )
self:MsgEnd()
end,
Receive = function( self, length, ply )
local ent = net.ReadEntity()
if ( !properties.CanBeTargeted( ent, ply ) ) then return end
if ( !self:Filter( ent, ply ) ) then return end
local drivemode = "drive_sandbox"
if ( ent.GetEntityDriveMode ) then
drivemode = ent:GetEntityDriveMode( ply )
end
drive.PlayerStartDriving( ply, ent, drivemode )
end
} )

View File

@@ -0,0 +1,48 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
properties.Add( "editentity", {
MenuLabel = "#entedit",
Order = 90001,
PrependSpacer = true,
MenuIcon = "icon16/pencil.png",
Filter = function( self, ent, ply )
if ( !IsValid( ent ) ) then return false end
if ( !ent.Editable ) then return false end
if ( !gamemode.Call( "CanProperty", ply, "editentity", ent ) ) then return false end
return true
end,
Action = function( self, ent )
local window = g_ContextMenu:Add( "DFrame" )
window:SetSize( 320, 400 )
window:SetTitle( tostring( ent ) )
window:Center()
window:SetSizable( true )
local control = window:Add( "DEntityProperties" )
control:SetEntity( ent )
control:Dock( FILL )
control.OnEntityLost = function()
window:Remove()
end
end
} )

View File

@@ -0,0 +1,92 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
-- The following is for the server's eyes only
local GravityDuplicator
if ( SERVER ) then
function GravityDuplicator( ply, ent, data )
if ( !data || !data.enabled ) then
duplicator.ClearEntityModifier( ent, "gravity_property" )
return
end
-- Simply restore the value whenever we are duplicated
-- We don't need to reapply EnableGravity because duplicator already does it for us
ent:SetNWBool( "gravity_disabled", data.enabled )
duplicator.StoreEntityModifier( ent, "gravity_property", data )
end
duplicator.RegisterEntityModifier( "gravity_property", GravityDuplicator )
end
properties.Add( "gravity", {
MenuLabel = "#gravity",
Type = "toggle",
Order = 1001,
Filter = function( self, ent, ply )
if ( !IsValid( ent ) ) then return false end
if ( !gamemode.Call( "CanProperty", ply, "gravity", ent ) ) then return false end
if ( ent:GetClass() == "prop_physics" ) then return true end
if ( ent:GetClass() == "prop_ragdoll" ) then return true end
return false
end,
Checked = function( self, ent, ply )
return ent:GetNWBool( "gravity_disabled" ) == false
end,
Action = function( self, ent )
self:MsgStart()
net.WriteEntity( ent )
self:MsgEnd()
end,
Receive = function( self, length, ply )
local ent = net.ReadEntity()
if ( !properties.CanBeTargeted( ent, ply ) ) then return end
if ( !self:Filter( ent, ply ) ) then return end
local bones = ent:GetPhysicsObjectCount()
local b = ent:GetNWBool( "gravity_disabled" )
for i = 0, bones - 1 do
local phys = ent:GetPhysicsObjectNum( i )
if ( IsValid( phys ) ) then
phys:EnableGravity( b )
phys:Wake()
end
end
ent:SetNWBool( "gravity_disabled", b == false )
GravityDuplicator( ply, ent, { enabled = ent:GetNWBool( "gravity_disabled" ) } )
end
} )

View File

@@ -0,0 +1,96 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
local function CanEntityBeSetOnFire( ent )
-- func_pushable, func_breakable & func_physbox cannot be ignited
if ( ent:GetClass() == "item_item_crate" ) then return true end
if ( ent:GetClass() == "simple_physics_prop" ) then return true end
if ( ent:GetClass():match( "prop_physics*" ) ) then return true end
if ( ent:GetClass():match( "prop_ragdoll*" ) ) then return true end
if ( ent:IsNPC() ) then return true end
return false
end
properties.Add( "ignite", {
MenuLabel = "#ignite",
Order = 999,
MenuIcon = "icon16/fire.png",
Filter = function( self, ent, ply )
if ( !IsValid( ent ) ) then return false end
if ( ent:IsPlayer() ) then return false end
if ( !CanEntityBeSetOnFire( ent ) ) then return false end
if ( !gamemode.Call( "CanProperty", ply, "ignite", ent ) ) then return false end
return !ent:IsOnFire()
end,
Action = function( self, ent )
self:MsgStart()
net.WriteEntity( ent )
self:MsgEnd()
end,
Receive = function( self, length, ply )
local ent = net.ReadEntity()
if ( !properties.CanBeTargeted( ent, ply ) ) then return end
if ( !self:Filter( ent, ply ) ) then return end
ent:Ignite( 360 )
end
} )
properties.Add( "extinguish", {
MenuLabel = "#extinguish",
Order = 999,
MenuIcon = "icon16/water.png",
Filter = function( self, ent, ply )
if ( !IsValid( ent ) ) then return false end
if ( ent:IsPlayer() ) then return false end
if ( !gamemode.Call( "CanProperty", ply, "extinguish", ent ) ) then return false end
return ent:IsOnFire()
end,
Action = function( self, ent )
self:MsgStart()
net.WriteEntity( ent )
self:MsgEnd()
end,
Receive = function( self, length, ply )
local ent = net.ReadEntity()
if ( !properties.CanBeTargeted( ent, ply ) ) then return end
if ( !self:Filter( ent, ply ) ) then return end
ent:Extinguish()
end
} )

View File

@@ -0,0 +1,107 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
properties.Add( "keepupright", {
MenuLabel = "#keepupright",
Order = 900,
MenuIcon = "icon16/arrow_up.png",
Filter = function( self, ent, ply )
if ( !IsValid( ent ) ) then return false end
if ( ent:GetClass() != "prop_physics" ) then return false end
if ( ent:GetNWBool( "IsUpright" ) ) then return false end
if ( !gamemode.Call( "CanProperty", ply, "keepupright", ent ) ) then return false end
return true
end,
Action = function( self, ent )
self:MsgStart()
net.WriteEntity( ent )
self:MsgEnd()
end,
Receive = function( self, length, ply )
local ent = net.ReadEntity()
if ( !IsValid( ent ) ) then return end
if ( !IsValid( ply ) ) then return end
if ( !properties.CanBeTargeted( ent, ply ) ) then return end
if ( ent:GetClass() != "prop_physics" ) then return end
if ( ent:GetNWBool( "IsUpright" ) ) then return end
if ( !self:Filter( ent, ply ) ) then return end
local Phys = ent:GetPhysicsObjectNum( 0 )
if ( !IsValid( Phys ) ) then return end
local constraint = constraint.Keepupright( ent, Phys:GetAngles(), 0, 999999 )
-- I feel like this is not stable enough
-- This cannot be implemented without a custom constraint.Keepupright function or modification for proper duplicator support.
--print( constraint:GetSaveTable().m_worldGoalAxis )
--constraint:SetSaveValue( "m_localTestAxis", constraint:GetSaveTable().m_worldGoalAxis ) --ent:GetAngles():Up() )
--constraint:SetSaveValue( "m_worldGoalAxis", Vector( 0, 0, 1 ) )
--constraint:SetSaveValue( "m_bDampAllRotation", true )
if ( constraint ) then
ply:AddCleanup( "constraints", constraint )
ent:SetNWBool( "IsUpright", true )
end
end
} )
properties.Add( "keepupright_stop", {
MenuLabel = "#keepupright_stop",
Order = 900,
MenuIcon = "icon16/arrow_rotate_clockwise.png",
Filter = function( self, ent )
if ( !IsValid( ent ) ) then return false end
if ( ent:GetClass() != "prop_physics" ) then return false end
if ( !ent:GetNWBool( "IsUpright" ) ) then return false end
return true
end,
Action = function( self, ent )
self:MsgStart()
net.WriteEntity( ent )
self:MsgEnd()
end,
Receive = function( self, length, ply )
local ent = net.ReadEntity()
if ( !IsValid( ent ) ) then return end
if ( !IsValid( ply ) ) then return end
if ( !properties.CanBeTargeted( ent, ply ) ) then return end
if ( ent:GetClass() != "prop_physics" ) then return end
if ( !ent:GetNWBool( "IsUpright" ) ) then return end
constraint.RemoveConstraints( ent, "Keepupright" )
ent:SetNWBool( "IsUpright", false )
end
} )

View File

@@ -0,0 +1,91 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
if ( SERVER ) then
CreateConVar( "sensor_debugragdoll", "0", FCVAR_NOTIFY )
CreateConVar( "sensor_stretchragdoll", "0", FCVAR_NOTIFY )
end
local playerTimeouts = {}
properties.Add( "motioncontrol_ragdoll", {
MenuLabel = "#control_with_motion_sensor",
Order = 2500,
MenuIcon = "icon16/controller.png",
Filter = function( self, ent, ply )
if ( CLIENT && !motionsensor ) then return false end
if ( CLIENT && !motionsensor.IsAvailable() ) then return false end
if ( !ent:IsRagdoll() ) then return false end
if ( !gamemode.Call( "CanProperty", ply, "motioncontrol_ragdoll", ent ) ) then return false end
return true
end,
Action = function( self, ent )
self:MsgStart()
net.WriteEntity( ent )
self:MsgEnd()
--
-- Start up the kinect controller. This will freeze the game for a second.
--
if ( !motionsensor.IsActive() ) then
motionsensor.Start()
end
end,
Receive = function( self, length, player )
local ent = net.ReadEntity()
if ( !self:Filter( ent, player ) ) then return end
-- Do not spam please!
local timeout = playerTimeouts[ player ]
if ( timeout && timeout.time > CurTime() ) then
if ( !timeout.sentMessage ) then
ServerLog( "Player " .. tostring( player ) .. " tried to use 'motioncontrol_ragdoll' property too rapidly!\n" )
player:PrintMessage( HUD_PRINTTALK, "Please wait at least 0.2 seconds before trying to control another ragdoll." )
timeout.sentMessage = true
end
return
end
-- Only 1 controller per ragdoll please!
if ( IsValid( ent.MotionSensorController ) ) then
ent.MotionSensorController:Remove()
end
local ragdoll_motion = ents.Create( "ragdoll_motion" )
ragdoll_motion:SetPos( player:EyePos() + player:EyeAngles():Forward() * 10 )
ragdoll_motion:SetAngles( Angle( 0, player:EyeAngles().yaw, 0 ) )
ragdoll_motion:SetRagdoll( ent )
ragdoll_motion:SetController( player )
ragdoll_motion:Spawn()
undo.Create( "MotionController" )
undo.AddEntity( ragdoll_motion )
undo.SetPlayer( player )
undo.Finish()
playerTimeouts[ player ] = { time = CurTime() + 0.2, sentMessage = false }
end
} )

View File

@@ -0,0 +1,82 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
properties.Add( "npc_bigger", {
MenuLabel = "#biggify",
Order = 1799,
MenuIcon = "icon16/magnifier_zoom_in.png",
Filter = function( self, ent, ply )
if ( !gamemode.Call( "CanProperty", ply, "npc_bigger", ent ) ) then return false end
if ( !IsValid( ent ) ) then return false end
if ( !ent:IsNPC() ) then return false end
return true
end,
Action = function( self, ent )
self:MsgStart()
net.WriteEntity( ent )
self:MsgEnd()
end,
Receive = function( self, length, ply )
local ent = net.ReadEntity()
if ( !properties.CanBeTargeted( ent, ply ) ) then return end
if ( !self:Filter( ent, ply ) ) then return end
ent:SetModelScale( ent:GetModelScale() * 1.25, 1 )
end
} )
properties.Add( "npc_smaller", {
MenuLabel = "#smallify",
Order = 1800,
MenuIcon = "icon16/magifier_zoom_out.png",
Filter = function( self, ent, ply )
if ( !gamemode.Call( "CanProperty", ply, "npc_smaller", ent ) ) then return false end
if ( !IsValid( ent ) ) then return false end
if ( !ent:IsNPC() ) then return false end
return true
end,
Action = function( self, ent )
self:MsgStart()
net.WriteEntity( ent )
self:MsgEnd()
end,
Receive = function( self, length, ply )
local ent = net.ReadEntity()
if ( !properties.CanBeTargeted( ent, ply ) ) then return end
if ( !self:Filter( ent, ply ) ) then return end
ent:SetModelScale( ent:GetModelScale() * 0.8, 1 )
end
} )

View File

@@ -0,0 +1,89 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
properties.Add( "persist", {
MenuLabel = "#makepersistent",
Order = 400,
MenuIcon = "icon16/link.png",
Filter = function( self, ent, ply )
if ( ent:IsPlayer() ) then return false end
if ( GetConVarString( "sbox_persist" ):Trim() == "" ) then return false end
if ( !gamemode.Call( "CanProperty", ply, "persist", ent ) ) then return false end
return !ent:GetPersistent()
end,
Action = function( self, ent )
self:MsgStart()
net.WriteEntity( ent )
self:MsgEnd()
end,
Receive = function( self, length, ply )
local ent = net.ReadEntity()
if ( !IsValid( ent ) ) then return end
if ( !properties.CanBeTargeted( ent, ply ) ) then return end
if ( !self:Filter( ent, ply ) ) then return end
-- TODO: Start some kind of animation, take 5 seconds to make something persistent
ent:SetPersistent( true )
--ent:EnableMotion( false )
end
} )
properties.Add( "persist_end", {
MenuLabel = "#stoppersisting",
Order = 400,
MenuIcon = "icon16/link_break.png",
Filter = function( self, ent, ply )
if ( ent:IsPlayer() ) then return false end
if ( GetConVarString( "sbox_persist" ):Trim() == "" ) then return false end
if ( !gamemode.Call( "CanProperty", ply, "persist", ent ) ) then return false end
return ent:GetPersistent()
end,
Action = function( self, ent )
self:MsgStart()
net.WriteEntity( ent )
self:MsgEnd()
end,
Receive = function( self, length, ply )
local ent = net.ReadEntity()
if ( !IsValid( ent ) ) then return end
if ( !properties.CanBeTargeted( ent, ply ) ) then return end
if ( !self:Filter( ent, ply ) ) then return end
-- TODO: Start some kind of animation, take 5 seconds to make something persistent
ent:SetPersistent( false )
end
} )

View File

@@ -0,0 +1,67 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
properties.Add( "remove", {
MenuLabel = "#remove",
Order = 1000,
MenuIcon = "icon16/delete.png",
Filter = function( self, ent, ply )
if ( !gamemode.Call( "CanProperty", ply, "remover", ent ) ) then return false end
if ( !IsValid( ent ) ) then return false end
if ( ent:IsPlayer() ) then return false end
return true
end,
Action = function( self, ent )
self:MsgStart()
net.WriteEntity( ent )
self:MsgEnd()
end,
Receive = function( self, length, ply )
if ( !IsValid( ply ) ) then return end
local ent = net.ReadEntity()
if ( !IsValid( ent ) ) then return end
-- Don't allow removal of players or objects that cannot be physically targeted by properties
if ( !properties.CanBeTargeted( ent, ply ) ) then return end
if ( !self:Filter( ent, ply ) ) then return end
-- Remove all constraints (this stops ropes from hanging around)
constraint.RemoveAll( ent )
-- Remove it properly in 1 second
timer.Simple( 1, function() if ( IsValid( ent ) ) then ent:Remove() end end )
-- Make it non solid
ent:SetNotSolid( true )
ent:SetMoveType( MOVETYPE_NONE )
ent:SetNoDraw( true )
-- Send Effect
local ed = EffectData()
ed:SetEntity( ent )
util.Effect( "entity_remove", ed, true, true )
ply:SendLua( "achievements.Remover()" )
end
} )

View File

@@ -0,0 +1,85 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
properties.Add( "skin", {
MenuLabel = "#skin",
Order = 601,
MenuIcon = "icon16/picture_edit.png",
Filter = function( self, ent, ply )
if ( !IsValid( ent ) ) then return false end
if ( ent:IsPlayer() ) then return false end
if ( !gamemode.Call( "CanProperty", ply, "skin", ent ) ) then return false end
if ( IsValid( ent.AttachedEntity ) ) then ent = ent.AttachedEntity end -- If our ent has an attached entity, we want to modify its skin instead
if ( !ent:SkinCount() ) then return false end
return ent:SkinCount() > 1
end,
MenuOpen = function( self, option, ent, tr )
--
-- Add a submenu to our automatically created menu option
--
local submenu = option:AddSubMenu()
--
-- Create a check item for each skin
--
local target = IsValid( ent.AttachedEntity ) and ent.AttachedEntity or ent
local num = target:SkinCount()
for i = 0, num - 1 do
local opt = submenu:AddOption( "Skin " .. i )
opt:SetRadio( true )
opt:SetChecked( target:GetSkin() == i )
opt:SetIsCheckable( true )
opt.OnChecked = function( s, checked ) if ( checked ) then self:SetSkin( ent, i ) end end
end
end,
Action = function( self, ent )
-- Nothing - we use SetSkin below
end,
SetSkin = function( self, ent, id )
self:MsgStart()
net.WriteEntity( ent )
net.WriteUInt( id, 8 )
self:MsgEnd()
end,
Receive = function( self, length, ply )
local ent = net.ReadEntity()
local skinid = net.ReadUInt( 8 )
if ( !properties.CanBeTargeted( ent, ply ) ) then return end
if ( !self:Filter( ent, ply ) ) then return end
ent = IsValid( ent.AttachedEntity ) and ent.AttachedEntity or ent
ent:SetSkin( skinid )
end
} )

View File

@@ -0,0 +1,202 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile()
-- The following is for the server's eyes only
local StatueDuplicator
if ( SERVER ) then
function StatueDuplicator( ply, ent, data )
if ( !data ) then
duplicator.ClearEntityModifier( ent, "statue_property" )
return
end
-- We have been pasted from duplicator, restore the necessary variables for the unstatue to work
if ( ent.StatueInfo == nil ) then
-- Ew. Have to wait a frame for the constraints to get pasted
timer.Simple( 0, function()
if ( !IsValid( ent ) ) then return end
local bones = ent:GetPhysicsObjectCount()
if ( bones < 2 ) then return end
ent:SetNWBool( "IsStatue", true )
ent.StatueInfo = {}
local con = constraint.FindConstraints( ent, "Weld" )
for id, t in pairs( con ) do
if ( t.Ent1 != t.Ent2 || t.Ent1 != ent || t.Bone1 != 0 ) then continue end
ent.StatueInfo[ t.Bone2 ] = t.Constraint
end
local numC = table.Count( ent.StatueInfo )
if ( numC < 1 --[[or numC != bones - 1]] ) then duplicator.ClearEntityModifier( ent, "statue_property" ) end
end )
end
duplicator.StoreEntityModifier( ent, "statue_property", data )
end
duplicator.RegisterEntityModifier( "statue_property", StatueDuplicator )
end
local playerTimeouts = {}
properties.Add( "statue", {
MenuLabel = "#makestatue",
Order = 1501,
MenuIcon = "icon16/lock.png",
Filter = function( self, ent, ply )
if ( !IsValid( ent ) ) then return false end
if ( ent:GetClass() != "prop_ragdoll" ) then return false end
if ( ent:GetNWBool( "IsStatue" ) ) then return false end
if ( !gamemode.Call( "CanProperty", ply, "statue", ent ) ) then return false end
return true
end,
Action = function( self, ent )
self:MsgStart()
net.WriteEntity( ent )
self:MsgEnd()
end,
Receive = function( self, length, ply )
local ent = net.ReadEntity()
if ( !IsValid( ent ) ) then return end
if ( !IsValid( ply ) ) then return end
if ( !properties.CanBeTargeted( ent, ply ) ) then return end
if ( ent:GetClass() != "prop_ragdoll" ) then return end
if ( !self:Filter( ent, ply ) ) then return end
-- Do not spam please!
local timeout = playerTimeouts[ ply ]
if ( timeout && timeout.time > CurTime() ) then
if ( !timeout.sentMessage ) then
ServerLog( "Player " .. tostring( ply ) .. " tried to use 'statue' property too rapidly!\n" )
ply:PrintMessage( HUD_PRINTTALK, "Please wait at least 0.2 seconds before trying to make another ragdoll a statue." )
timeout.sentMessage = true
end
return
end
local bones = ent:GetPhysicsObjectCount()
if ( bones < 2 ) then return end
if ( ent.StatueInfo ) then return end
ent.StatueInfo = {}
undo.Create( "Statue" )
for bone = 1, bones - 1 do
local constr = constraint.Weld( ent, ent, 0, bone, 0 )
if ( constr ) then
ent.StatueInfo[ bone ] = constr
ply:AddCleanup( "constraints", constr )
undo.AddEntity( constr )
end
local effectdata = EffectData()
effectdata:SetOrigin( ent:GetPhysicsObjectNum( bone ):GetPos() )
effectdata:SetScale( 1 )
effectdata:SetMagnitude( 1 )
util.Effect( "GlassImpact", effectdata, true, true )
end
ent:SetNWBool( "IsStatue", true )
undo.AddFunction( function()
if ( !IsValid( ent ) ) then return false end
ent:SetNWBool( "IsStatue", false )
ent.StatueInfo = nil
StatueDuplicator( ply, ent, nil )
end )
undo.SetPlayer( ply )
undo.Finish()
StatueDuplicator( ply, ent, {} )
playerTimeouts[ ply ] = { time = CurTime() + 0.2, sentMessage = false }
end
} )
properties.Add( "statue_stop", {
MenuLabel = "#unstatue",
Order = 1501,
MenuIcon = "icon16/lock_open.png",
Filter = function( self, ent, ply )
if ( !IsValid( ent ) ) then return false end
if ( ent:GetClass() != "prop_ragdoll" ) then return false end
if ( !ent:GetNWBool( "IsStatue" ) ) then return false end
if ( !gamemode.Call( "CanProperty", ply, "unstatue", ent ) ) then return false end
return true
end,
Action = function( self, ent )
self:MsgStart()
net.WriteEntity( ent )
self:MsgEnd()
end,
Receive = function( self, length, ply )
local ent = net.ReadEntity()
if ( !IsValid( ent ) ) then return end
if ( !IsValid( ply ) ) then return end
if ( !properties.CanBeTargeted( ent, ply ) ) then return end
if ( ent:GetClass() != "prop_ragdoll" ) then return end
local bones = ent:GetPhysicsObjectCount()
if ( bones < 2 ) then return end
if ( !ent.StatueInfo ) then return end
for k, v in pairs( ent.StatueInfo ) do
if ( IsValid( v ) ) then
v:Remove()
end
end
ent:SetNWBool( "IsStatue", false )
ent.StatueInfo = nil
StatueDuplicator( ply, ent, nil )
end
} )