TOOL.Category = "Apply" TOOL.Name = "#Breakable Props Tool" TOOL.Command = nil TOOL.ConfigName = "" -- Tables local Breakable = {} -- ConVars TOOL.ClientConVar["Health"] = "100" TOOL.ClientConVar["Multiply"] = "3" TOOL.ClientConVar["Attached"] = "1" TOOL.ClientConVar["Use"] = "1" -- Client if (CLIENT) then language.Add("Tool_breakableprops_name", "Breakable Props Tool") language.Add("Tool_breakableprops_desc", "Make an entity breakable") language.Add("Tool_breakableprops_0", "Click on an entity to make it breakable and Right click to repair it!") language.Add("Undone_breakableprops", "Undone Breakable Prop") end -- Message function TOOL:Message(Text) if SERVER then self:GetOwner():SendLua("GAMEMODE:AddNotify('"..Text.."', NOTIFY_GENERIC, 10)") self:GetOwner():SendLua("surface.PlaySound('ambient/water/drip"..math.random(1, 4)..".wav')") end end -- Get entities local function ExtractEntities(Entity, Entities, Constraints) Constraints = Constraints or {} Entities = Entities or {} if (!Entity:IsValid()) then return Entities, Constraints end local Index = Entity:EntIndex() Entities[Index] = Entity if (!constraint.HasConstraints(Entity)) then return Entities, Constraints end local Cons = constraint.GetTable(Entity) for K, V in pairs(Cons) do local Index = V.Constraint if (!Constraints[Index]) then Constraints[Index] = V.Constraint for B, J in pairs(V.Entity) do local E, C = ExtractEntities(J.Entity, Entities, Constraints) table.Merge(Entities, E) table.Merge(Constraints, C) end end end return Entities, Constraints end -- Left click function TOOL:LeftClick(Trace) if (Trace.Entity) then if !Trace.Entity:IsValid() or Trace.Entity:IsPlayer() or Trace.HitWorld or Trace.Entity:IsNPC() then return false end end if(CLIENT) then return true end if(!SERVER) then return false end local HP = Trace.Entity:BoundingRadius() * self:GetClientNumber("Multiply") local Attached = self:GetClientNumber("Attached") HP = math.floor(HP) if self:GetClientNumber("Use") == 1 then HP = math.floor(self:GetClientNumber("Health")) end local r,g,b,a = Trace.Entity:GetColor() Trace.Entity.Breakable = {} Trace.Entity.Breakable.Cur = HP Trace.Entity.Breakable.Max = HP Trace.Entity.Breakable.FColR = r Trace.Entity.Breakable.FColG = g Trace.Entity.Breakable.FColB = b Trace.Entity.Breakable.FColA = a if Trace.Entity:GetTable().OnTakeDamage then local Prev = Trace.Entity:GetTable().OnTakeDamage function Trace.Entity:OnTakeDamage(Info) Breakable.DamagePhysicsEntity(self, Info:GetDamage()) Prev(self, Info) end end if (Wire_CreateOutputs) then Trace.Entity.Outputs = Wire_CreateOutputs(Trace.Entity, {"Health", "Max"}) end if (Wire_TriggerOutput) then Wire_TriggerOutput(Trace.Entity, "Health", HP) Wire_TriggerOutput(Trace.Entity, "Max", HP) end local Undos = {} table.insert(Undos, Trace.Entity) if (Attached == 1) then local Entities, Constraints = ExtractEntities(Trace.Entity) for K, V in pairs(Entities) do if V:IsValid() then if (V != Trace.Entity) then local HP = V:BoundingRadius() * 3 if self:GetClientNumber("Use") == 1 then HP = math.floor(self:GetClientNumber("Health")) end local r,g,b,a = V.Entity:GetColor() V.Breakable = {} V.Breakable.Cur = HP V.Breakable.Max = HP V.Breakable.FColR = r V.Breakable.FColG = g V.Breakable.FColB = b V.Breakable.FColA = a if (Wire_CreateOutputs) then V.Breakable.Outputs = Wire_CreateOutputs(V, {"Health", "Max"}) end if (Wire_TriggerOutput) then Wire_TriggerOutput(V, "Health", HP) Wire_TriggerOutput(V, "Max", HP) end if (V:GetTable().OnTakeDamage) then local Prev = V:GetTable().OnTakeDamage function V:OnTakeDamage(Info) Breakable.DamagePhysicsEntity(self, Info:GetDamage()) Prev(self, Info) end end table.insert(Undos, V) end end end end if self:GetClientNumber("Use") != 1 then self:Message("Entities health will be 3 times the objects bounding radius!") else local HP = math.floor(self:GetClientNumber("Health")) self:Message("Entities health are set to "..HP) end -- Undo local function Function(Undo, Table) for K, V in pairs(Table) do if (V:IsValid()) then Breakable.Extinguish(V) V.Breakable = nil end end end undo.Create("breakableprops") undo.SetPlayer(self:GetOwner()) undo.AddFunction(Function, Undos) undo.Finish() return true end -- Right cick function TOOL:RightClick(Trace) if (Trace.Entity) then if !Trace.Entity:IsValid() or Trace.Entity:IsPlayer() or Trace.HitWorld or Trace.Entity:IsNPC() then return false end end if(CLIENT) then if (Trace.Entity) then local Effect = EffectData() Effect:SetEntity(Trace.Entity) Effect:SetOrigin(Trace.Entity:GetPos()) Effect:SetStart(Trace.Entity:GetPos()) Effect:SetScale(999) Effect:SetMagnitude(250) util.Effect("WaterSplash", Effect) end return true end if(!SERVER) then return false end local Entities, Constraints = ExtractEntities(Trace.Entity) for K, V in pairs(Entities) do if (V.Breakable and V.Breakable.Max != 0) then Breakable.Extinguish(V) end end self:Message("This prop and connected props have been restored to full health!") return true end if SERVER then -- Extinguish function Breakable.Extinguish(Entity) local HP = Entity.Breakable.Max if Entity.Breakable.FColR != nil and Entity.Breakable.FColG != nil and Entity.Breakable.FColB != nil and Entity.Breakable.FColA != nil then Entity:SetColor( Entity.Breakable.FColR, Entity.Breakable.FColG, Entity.Breakable.FColB, Entity.Breakable.FColA ) end Entity.Breakable.Cur = HP timer.Remove("Destroy:"..Entity:EntIndex()) if (Entity:IsOnFire()) then Entity:Extinguish() end Breakable.DeleteEntityTrail(Entity) if (Wire_TriggerOutput) then Wire_TriggerOutput(Entity, "Health", HP) Wire_TriggerOutput(Entity, "Max", HP) end end -- Delete entity trail function Breakable.DeleteEntityTrail(Entity) if (Entity.Breakable.Smoke and Entity.Breakable.Smoke:IsValid()) then Entity.Breakable.Smoke:Remove() Entity.Breakable.Smoke = nil end end -- Set health based on color function Breakable.ColorHealthBased(Entity, HP, Col) if (Entity.Breakable.Cur <= (Entity.Breakable.Max / HP)) then Entity:SetColor(Col, Col, Col, 255) end end -- Damage a physics entity function Breakable.DamagePhysicsEntity(Entity, Amount) local smoke = Entity.Breakable.Smoke if smoke and smoke:IsValid() then local COLHP = 2.55*(Entity.Breakable.Cur / Entity.Breakable.Max *100) -- 255 to 0 based on HP smoke:Fire("addoutput","startcolor".." "..tostring(COLHP).." "..tostring(COLHP).." "..tostring(COLHP)) smoke:Fire("addoutput","endcolor".." "..tostring(COLHP).." "..tostring(COLHP).." "..tostring(COLHP)) end Amount = math.floor(Amount / 2) if (Entity.Breakable and Entity.Breakable.Cur > 0) then local HP = Entity.Breakable.Cur - Amount Entity.Breakable.Cur = HP if (Entity.Breakable.Cur <= Entity.Breakable.Max) then Breakable.CreateEntitySmokeTrail(Entity) end local r,g,b,a = Entity:GetColor() if Entity.Breakable.FColR != nil and Entity.Breakable.FColG != nil and Entity.Breakable.FColB != nil and Entity.Breakable.FColA != nil then Entity:SetColor( Entity.Breakable.FColR * (Entity.Breakable.Cur / Entity.Breakable.Max), Entity.Breakable.FColG * (Entity.Breakable.Cur / Entity.Breakable.Max), Entity.Breakable.FColB * (Entity.Breakable.Cur / Entity.Breakable.Max), Entity.Breakable.FColA ) end if (Entity.Breakable.Cur <= 0) then local function Func(Entity) if (Entity:IsValid()) then local OldVel = Entity:GetPhysicsObject():GetVelocity() local Wreckage = ents.Create( "wreckedstuff" ) Wreckage:SetModel( Entity:GetModel() ) Wreckage:SetAngles( Entity:GetAngles() ) Wreckage:SetPos( Entity:GetPos() ) Wreckage:Spawn() Wreckage:Activate() Wreckage:GetPhysicsObject():SetVelocity(OldVel) Entity:Remove() end end if Entity.Breakable.FColR != nil and Entity.Breakable.FColG != nil and Entity.Breakable.FColB != nil and Entity.Breakable.FColA != nil then Entity:SetColor( Entity.Breakable.FColR * (Entity.Breakable.Cur / Entity.Breakable.Max), Entity.Breakable.FColG * (Entity.Breakable.Cur / Entity.Breakable.Max), Entity.Breakable.FColB * (Entity.Breakable.Cur / Entity.Breakable.Max), Entity.Breakable.FColA ) end timer.Create("Destroy:"..Entity:EntIndex(), 0, 1, Func, Entity) end if (Wire_TriggerOutput) then Wire_TriggerOutput(Entity, "Health", Entity.Breakable.Cur) Wire_TriggerOutput(Entity, "Max", Entity.Breakable.Max) end end end -- Create smoke trail function Breakable.CreateEntitySmokeTrail(Entity) if not (Entity.Breakable.Smoke) then local Smoke = ents.Create("env_smoketrail") local INVHP = 100-(Entity.Breakable.Cur / Entity.Breakable.Max *100) local RAD = Entity:BoundingRadius() local COLHP = 2.55*(Entity.Breakable.Cur / Entity.Breakable.Max *100) -- 255 to 0 based on HP local INVCOLHP = 255-(2.55*(Entity.Breakable.Cur / Entity.Breakable.Max *100)) Smoke:SetKeyValue("opacity", 1) Smoke:SetKeyValue("spawnrate", (INVHP * 2) ) Smoke:SetKeyValue("lifetime", 4) Smoke:SetKeyValue("startcolor", tostring(COLHP).." "..tostring(COLHP).." "..tostring(COLHP)) Smoke:SetKeyValue("endcolor", tostring(COLHP).." "..tostring(COLHP).." "..tostring(COLHP)) Smoke:SetKeyValue("minspeed", 15) Smoke:SetKeyValue("maxspeed", 30) Smoke:SetKeyValue("startsize", ( RAD / 2)) Smoke:SetKeyValue("endsize", ( RAD * 5 )) Smoke:SetKeyValue("spawnradius", ( RAD / 2)) Smoke:SetKeyValue("emittime", 300) Smoke:SetKeyValue("firesprite", "particles/smokey") Smoke:SetKeyValue("smokesprite", "particles/smokey") Smoke:SetPos(Entity:GetPos()) Smoke:SetParent(Entity) Smoke:Spawn() Smoke:Activate() -- Delete on remove Entity:DeleteOnRemove(Smoke) -- Networked variables Entity.Breakable.Smoke = Smoke end end -- Entity take damage function TOOL.EntityTakeDamage(Entity, One, Two, Damage) Breakable.DamagePhysicsEntity(Entity, Damage) end hook.Add("EntityTakeDamage", "TOOL.EntityTakeDamage", TOOL.EntityTakeDamage) end -- Build CPanel function TOOL.BuildCPanel(Panel) Panel:AddControl("Header", {Text = "#Tool_breakableprops_name", Description = "#Tool_breakableprops_desc"}) Panel:AddControl("Checkbox", {Label = "#Make attached props breakable", Command = "breakableprops_Attached"}) Panel:AddControl("Checkbox", {Label = "#Use specified health", Command = "breakableprops_Use"}) Panel:AddControl("Slider", {Label = "#Health", Type = "Integer", Min = 0, Max = 100, Command = "breakableprops_Health"}) Panel:AddControl("Slider", {Label = "#Multiply", Type = "Integer", Min = 0, Max = 100, Command = "breakableprops_Multiply"}) end