--[[ | 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/ --]] TOOL.Category = "Construction" TOOL.Name = "#tool.balloon.name" TOOL.ClientConVar[ "ropelength" ] = "64" TOOL.ClientConVar[ "force" ] = "500" TOOL.ClientConVar[ "r" ] = "255" TOOL.ClientConVar[ "g" ] = "255" TOOL.ClientConVar[ "b" ] = "0" TOOL.ClientConVar[ "model" ] = "normal_skin1" TOOL.Information = { { name = "left" }, { name = "right" } } cleanup.Register( "balloons" ) function TOOL:LeftClick( trace, attach ) if ( IsValid( trace.Entity ) && trace.Entity:IsPlayer() ) then return false end if ( CLIENT ) then return true end -- -- Right click calls this with attach = false -- if ( attach == nil ) then attach = true end -- If there's no physics object then we can't constraint it! if ( SERVER && attach && !util.IsValidPhysicsObject( trace.Entity, trace.PhysicsBone ) ) then return false end local ply = self:GetOwner() local material = "cable/rope" local r = self:GetClientNumber( "r", 255 ) local g = self:GetClientNumber( "g", 0 ) local b = self:GetClientNumber( "b", 0 ) local model = self:GetClientInfo( "model" ) local force = math.Clamp( self:GetClientNumber( "force", 500 ), -1E34, 1E34 ) local length = self:GetClientNumber( "ropelength", 64 ) local modeltable = list.Get( "BalloonModels" )[ model ] -- -- Model is a table index on BalloonModels -- If the model isn't defined then it can't be spawned. -- if ( !modeltable ) then return false end -- -- The model table can disable colouring for its model -- if ( modeltable.nocolor ) then r = 255 g = 255 b = 255 end -- -- Clicked on a balloon - modify the force/color/whatever -- if ( IsValid( trace.Entity ) && trace.Entity:GetClass() == "gmod_balloon" && trace.Entity.Player == ply ) then if ( IsValid( trace.Entity:GetPhysicsObject() ) ) then trace.Entity:GetPhysicsObject():Wake() end trace.Entity:SetColor( Color( r, g, b, 255 ) ) trace.Entity:SetForce( force ) trace.Entity.force = force return true end -- -- Hit the balloon limit, bail -- if ( !self:GetWeapon():CheckLimit( "balloons" ) ) then return false end local balloon = MakeBalloon( ply, r, g, b, force, { Pos = trace.HitPos, Model = modeltable.model, Skin = modeltable.skin } ) if ( !IsValid( balloon ) ) then return false end local CurPos = balloon:GetPos() local NearestPoint = balloon:NearestPoint( CurPos - ( trace.HitNormal * 512 ) ) local Offset = CurPos - NearestPoint local Pos = trace.HitPos + Offset balloon:SetPos( Pos ) undo.Create( "Balloon" ) undo.AddEntity( balloon ) if ( attach ) then -- The real model should have an attachment! local LPos1 = balloon:WorldToLocal( Pos ) local LPos2 = trace.Entity:WorldToLocal( trace.HitPos ) if ( IsValid( trace.Entity ) ) then local phys = trace.Entity:GetPhysicsObjectNum( trace.PhysicsBone ) if ( IsValid( phys ) ) then LPos2 = phys:WorldToLocal( trace.HitPos ) end end local constr, rope = constraint.Rope( balloon, trace.Entity, 0, trace.PhysicsBone, LPos1, LPos2, 0, length, 0, 0.5, material ) if ( IsValid( constr ) ) then undo.AddEntity( constr ) ply:AddCleanup( "balloons", constr ) end if ( IsValid( rope ) ) then undo.AddEntity( rope ) ply:AddCleanup( "balloons", rope ) end end undo.SetPlayer( ply ) undo.Finish() return true end function TOOL:RightClick( trace ) return self:LeftClick( trace, false ) end if ( SERVER ) then function MakeBalloon( ply, r, g, b, force, Data ) if ( IsValid( ply ) && !ply:CheckLimit( "balloons" ) ) then return end local balloon = ents.Create( "gmod_balloon" ) if ( !IsValid( balloon ) ) then return end duplicator.DoGeneric( balloon, Data ) balloon:Spawn() DoPropSpawnedEffect( balloon ) duplicator.DoGenericPhysics( balloon, ply, Data ) force = math.Clamp( force, -1E34, 1E34 ) balloon:SetColor( Color( r, g, b, 255 ) ) balloon:SetForce( force ) balloon:SetPlayer( ply ) balloon.Player = ply balloon.r = r balloon.g = g balloon.b = b balloon.force = force if ( IsValid( ply ) ) then ply:AddCount( "balloons", balloon ) ply:AddCleanup( "balloons", balloon ) end return balloon end duplicator.RegisterEntityClass( "gmod_balloon", MakeBalloon, "r", "g", "b", "force", "Data" ) end function TOOL:UpdateGhostBalloon( ent, ply ) if ( !IsValid( ent ) ) then return end local trace = ply:GetEyeTrace() if ( !trace.Hit || IsValid( trace.Entity ) && ( trace.Entity:IsPlayer() || trace.Entity:GetClass() == "gmod_balloon" ) ) then ent:SetNoDraw( true ) return end local CurPos = ent:GetPos() local NearestPoint = ent:NearestPoint( CurPos - ( trace.HitNormal * 512 ) ) local Offset = CurPos - NearestPoint local pos = trace.HitPos + Offset local modeltable = list.Get( "BalloonModels" )[ self:GetClientInfo( "model" ) ] if ( modeltable.skin ) then ent:SetSkin( modeltable.skin ) end ent:SetPos( pos ) ent:SetAngles( angle_zero ) ent:SetNoDraw( false ) end function TOOL:Think() if ( !IsValid( self.GhostEntity ) || self.GhostEntity.model != self:GetClientInfo( "model" ) ) then local modeltable = list.Get( "BalloonModels" )[ self:GetClientInfo( "model" ) ] if ( !modeltable ) then self:ReleaseGhostEntity() return end self:MakeGhostEntity( modeltable.model, vector_origin, angle_zero ) if ( IsValid( self.GhostEntity ) ) then self.GhostEntity.model = self:GetClientInfo( "model" ) end end self:UpdateGhostBalloon( self.GhostEntity, self:GetOwner() ) end local ConVarsDefault = TOOL:BuildConVarList() function TOOL.BuildCPanel( CPanel ) CPanel:AddControl( "Header", { Description = "#tool.balloon.help" } ) CPanel:AddControl( "ComboBox", { MenuButton = 1, Folder = "balloon", Options = { [ "#preset.default" ] = ConVarsDefault }, CVars = table.GetKeys( ConVarsDefault ) } ) CPanel:AddControl( "Slider", { Label = "#tool.balloon.ropelength", Type = "Float", Command = "balloon_ropelength", Min = 5, Max = 1000 } ) CPanel:AddControl( "Slider", { Label = "#tool.balloon.force", Type = "Float", Command = "balloon_force", Min = -1000, Max = 2000, Help = true } ) CPanel:AddControl( "Color", { Label = "#tool.balloon.color", Red = "balloon_r", Green = "balloon_g", Blue = "balloon_b" } ) CPanel:AddControl( "PropSelect", { Label = "#tool.balloon.model", ConVar = "balloon_model", Height = 0, ModelsTable = list.Get( "BalloonModels" ) } ) end list.Set( "BalloonModels", "normal", { model = "models/maxofs2d/balloon_classic.mdl", skin = 0 } ) list.Set( "BalloonModels", "normal_skin1", { model = "models/maxofs2d/balloon_classic.mdl", skin = 1 } ) list.Set( "BalloonModels", "normal_skin2", { model = "models/maxofs2d/balloon_classic.mdl", skin = 2 } ) list.Set( "BalloonModels", "normal_skin3", { model = "models/maxofs2d/balloon_classic.mdl", skin = 3 } ) list.Set( "BalloonModels", "gman", { model = "models/maxofs2d/balloon_gman.mdl", nocolor = true } ) list.Set( "BalloonModels", "mossman", { model = "models/maxofs2d/balloon_mossman.mdl", nocolor = true } ) list.Set( "BalloonModels", "dog", { model = "models/balloons/balloon_dog.mdl" } ) list.Set( "BalloonModels", "heart", { model = "models/balloons/balloon_classicheart.mdl" } ) list.Set( "BalloonModels", "star", { model = "models/balloons/balloon_star.mdl" } )