AddCSLuaFile() local SligWolf_Addons = SligWolf_Addons local SLIGWOLF_BASECHECK = include("sligwolf_addons/basecheck.lua") if not SLIGWOLF_BASECHECK then return end SLIGWOLF_BASECHECK.Addonname = "Garbage Truck" SLIGWOLF_BASECHECK.RequiredBaseApiVersion = "1.5.0" if not SLIGWOLF_BASECHECK.CheckBaseAddonExist() then return end if not SLIGWOLF_ADDON then if not SligWolf_Addons.AutoLoadAddon then SLIGWOLF_BASECHECK.CheckBaseAddonVersion() return SligWolf_Addons.ERROR_BAD_VERSION end SligWolf_Addons.AutoLoadAddon(function() end) return end local SLIGWOLF_ERROR = SLIGWOLF_BASECHECK.DoRuntimeChecks() if SLIGWOLF_ERROR then return SLIGWOLF_ERROR end local CONSTANTS = SligWolf_Addons.Constants local LIBConstraints = SligWolf_Addons.Constraints local LIBEntities = SligWolf_Addons.Entities local LIBPosition = SligWolf_Addons.Position local LIBVelocity = SligWolf_Addons.Velocity local LIBCoupling = SligWolf_Addons.Coupling local LIBPhysics = SligWolf_Addons.Physics local LIBBones = SligWolf_Addons.Bones SLIGWOLF_ADDON.Author = "SligWolf" SLIGWOLF_ADDON.NiceName = "Garbage Truck" SLIGWOLF_ADDON.Version = "1.1.6" local headerProps = {header = "Props"} local headerVmodels = {header = "View Models"} local headerWmodels = {header = "World Models"} local dumpsterMdl = "models/sligwolf/garbagetruck/dumpster.mdl" SLIGWOLF_ADDON:AddProp(dumpsterMdl, headerProps) SLIGWOLF_ADDON:AddProp("models/sligwolf/garbagetruck/trashbag_1.mdl", headerProps) SLIGWOLF_ADDON:AddProp("models/sligwolf/garbagetruck/trashbag_2.mdl", headerProps) SLIGWOLF_ADDON:AddProp("models/sligwolf/garbagetruck/trashbag_3.mdl", headerProps) SLIGWOLF_ADDON:AddProp("models/sligwolf/garbagetruck/c_dumpsterswep.mdl", headerVmodels) SLIGWOLF_ADDON:AddProp("models/sligwolf/garbagetruck/w_dumpsterswep.mdl", headerWmodels) SLIGWOLF_ADDON:AddProp("models/sligwolf/garbagetruck/c_trashbagswep.mdl", headerVmodels) SLIGWOLF_ADDON:AddProp("models/sligwolf/garbagetruck/w_trashbagswep.mdl", headerWmodels) SLIGWOLF_ADDON:AddWeapon("sligwolf_weapon_dumpster", { title = "Dumpster", }) SLIGWOLF_ADDON:AddWeapon("sligwolf_weapon_trashbag", { title = "Trashbag", }) SLIGWOLF_ADDON:LuaInclude("vehiclespawnlist.lua") local components = SLIGWOLF_ADDON:LuaIncludeSimple("vehicleparts.lua") local cvarFlags = bit.bor(FCVAR_ARCHIVE, FCVAR_GAMEDLL, FCVAR_NOTIFY, FCVAR_REPLICATED) CreateConVar("sv_sligwolf_garbagetruck_trashbag_capacity", "3", cvarFlags, "Change the trashbag capacity for the Trashbag SWEP.\nTechnical speaking: The physical volume capacity that can be wraped up with the trashbag SWEP.\nA higher number means bigger items can be wraped up.\nValue can not be set higher than 99999 or lower than 3.", 3, 99999) local smokeOffThreshold = LIBVelocity.GetUPSSpeed(40) local smokeOnThreshold = LIBVelocity.GetUPSSpeed(39) local mechanicSnd = SLIGWOLF_ADDON:GetSoundScriptName("mechanic") local maxOpenCloseDumpsterDist = 100 * 100 local maxGrabDumpsterDist = 10 * 10 local maxDestroyTrashDist = 50 * 50 local lightTable = { lights = { "^Light_L", "^Glow_G", }, indicators = { R = { "^Glow_IR", }, L = { "^Glow_IL", }, }, allowMidLights = true, } function SLIGWOLF_ADDON:SetupVehicle(vehicle, vat, customProperties) local skins = customProperties.skins or {} local skinPrimary = skins.primary or CONSTANTS.skinError local colors = customProperties.colors or {} local colorPrimary = colors.primary or CONSTANTS.colorError1 local colorSecondary = colors.secondary or CONSTANTS.colorError2 LIBCoupling.MarkAsTrailerMain(vehicle) local vehicleTable = vehicle:SligWolf_GetTable() vehicleTable.vehicleLights = lightTable vat.sndFork = self:SoundCreate(vehicle, "moveFork") self:SoundEdit(vat.sndFork, 4, 0, 0, 0.25, 0) LIBEntities.CallOnRemove(vehicle, "Stop_GarbageTruck_ForkMove", function() self:SoundEdit(vat.sndFork, 0) vat.sndFork = nil end) vehicle:SetSkin(skinPrimary) vehicle:SetColor(colorPrimary) self:RegisterEntityDuplicatorModifier(vehicle, { copy = function(f_ent, data) data.Skin = f_ent:GetSkin() data.Color = f_ent:GetColor() data.LightData = LIBCoupling.GetTrailerDataForDupe(f_ent) data.Parts = {} local parts = data.Parts local ent = LIBEntities.GetChildFromPath(f_ent, "Prop_Fork") if IsValid(ent) then parts["Prop_Fork"] = { Color = ent:GetColor(), } end end, paste = function(f_ent, data) f_ent:SetSkin(data.Skin or skinPrimary) f_ent:SetColor(data.Color or colorPrimary) LIBCoupling.SetTrailerDataFromDupe(f_ent, data.LightData) self:LightsUpdateGlows(f_ent) local parts = data.Parts or {} local ent = LIBEntities.GetChild(f_ent, "Prop_Fork") if IsValid(ent) then local part = parts["Prop_Fork"] or {} ent:SetColor(part.Color or colorSecondary) end end }) end function SLIGWOLF_ADDON:SpawnVehicle(ply, vehicle, vat, customProperties) if CLIENT then return end local denyToolReload = vehicle.sligwolf_denyToolReload self:SetupVehicle(vehicle, vat, customProperties) self:SetUpVehicleParts( vehicle, components, denyToolReload, ply ) end function SLIGWOLF_ADDON:OnPostDisconnectTrailer(VehicleA, VehicleB, Dir) local trailerMainA = LIBCoupling.GetTrailerMainVehicle(VehicleA, true) local trailerMainB = LIBCoupling.GetTrailerMainVehicle(VehicleB, true) self:LightsUpdateGlows(trailerMainA) self:LightsUpdateGlows(trailerMainB) end function SLIGWOLF_ADDON:OnConnectTrailer(VehicleA, VehicleB, Dir) local trailerMainA = LIBCoupling.GetTrailerMainVehicle(VehicleA) if not IsValid(trailerMainA) then return end self:LightsUpdateGlows(trailerMainA) end local function openCloseDumpster(ply) if CLIENT then return end if not IsValid(ply) then return end local trace = util.TraceLine(util.GetPlayerTrace(ply)) local ent = trace.Entity if not IsValid(ent) then return end if ent:GetModel() ~= dumpsterMdl then return end if ent.sligwolf_isOnFork then return end local delay = ent.sligwolf_openCloseDelay or 0 if (CurTime() - delay) < 0.25 then return end ent.sligwolf_openCloseDelay = CurTime() local entPos = ent:GetPos() local plyPos = ply:GetPos() if entPos:DistToSqr(plyPos) > maxOpenCloseDumpsterDist then return end ent.sligwolf_changeState = not ent.sligwolf_changeState ent:EmitSound(mechanicSnd) if not ent.sligwolf_changeState then LIBBones.SetAnim(ent, "open") return else LIBBones.SetAnim(ent, "close") return end end local function temPropOwner(ent, ply, state) if not IsValid(ent) then return end if not IsValid(ply) then return end local oldOwner = ent.SLIGWOLF_oldOwner if not IsValid(oldOwner) then oldOwner = nil end if state then ent.SLIGWOLF_oldOwner = LIBEntities.GetOwner(ent) LIBEntities.SetOwner(ent, ply) else LIBEntities.SetOwner(ent, oldOwner) end return end local function hasWorldConstraint(ent) if not IsValid(ent) then return false end local IsConstrainted = LIBConstraints.HasConstraints(ent) if not IsConstrainted then return false end local world = Entity(0) local Constraints = LIBConstraints.GetTable(ent) or {} for k, data in pairs(Constraints) do local ent1 = data.Ent1 local ent2 = data.Ent2 if ent1 == world then return true end if ent2 == world then return true end end return false end local function hasIllegalConstraints(ent, whitelist_ents, allowworld) if not IsValid(ent) then return false end local IsConstrainted = LIBConstraints.HasConstraints(ent) if not IsConstrainted then return false end local whitelist_ents = whitelist_ents or {} local ConEnts = LIBConstraints.GetAllConstrainedEntities(ent) or {} for k, constrainted_ent in pairs(ConEnts) do if constrainted_ent == ent then continue end local invalid = true for k, whitelist_ent in pairs(whitelist_ents) do if constrainted_ent ~= whitelist_ent then continue end invalid = false break end if invalid then return true end end if not allowworld and hasWorldConstraint(ent) then return true end return false end function SLIGWOLF_ADDON:GrabDumpster(fork, veh, vat, ply, dumpster, d_phys) if not IsValid(fork) then return end if not IsValid(veh) then return end if not IsValid(ply) then return end if not IsValid(dumpster) then return end if not IsValid(d_phys) then return end local attD = dumpster:GetAttachment(1) local attV = veh:GetAttachment(2) if not attD then return end if not attV then return end local posA = attD.Pos local posB = attV.Pos if not posA then return end if not posB then return end if posA:DistToSqr(posB) > maxGrabDumpsterDist then return end local localang = veh:GetAngles() local vec = LIBPosition.VectorToLocalToWorld(veh, Vector(0, 65, 60)) if not IsValid(vat.dumpsterOnFork) then if hasIllegalConstraints(dumpster, {fork, veh}) then fork:EmitSound(CONSTANTS.sndVehicleDenyAction2) return end LIBConstraints.RemoveAll(dumpster) temPropOwner(dumpster, ply, true) fork:EmitSound(mechanicSnd) LIBBones.SetAnim(fork, "close") LIBBones.SetAnim(dumpster, "close") dumpster.sligwolf_changeState = true dumpster.sligwolf_isOnFork = true d_phys:SetMaterial("gmod_ice") d_phys:EnableMotion(true) local weld = LIBConstraints.Weld(fork, dumpster, {nocollide = true}) if not IsValid(weld) then veh:Remove() return end vat.dumpsterOnFork = weld if not IsValid(vat.forkWeld) then return end vat.forkWeld:Remove() vat.forkWeld = nil return else LIBConstraints.RemoveAll(dumpster) temPropOwner(dumpster, ply, false) fork:EmitSound(mechanicSnd) LIBBones.SetAnim(fork, "open") LIBBones.SetAnim(dumpster, "open") dumpster.sligwolf_changeState = false dumpster.sligwolf_isOnFork = false fork:SetPos(vec) fork:SetAngles(localang) d_phys:SetMaterial("metalvehicle") d_phys:EnableMotion(true) local weld = LIBConstraints.Weld( fork, veh, { nocollide = true, deleteEntOnBreak = true, } ) if not IsValid(weld) then veh:Remove() return end vat.forkWeld = weld vat.dumpsterOnFork = nil return end end function SLIGWOLF_ADDON:ForkCheck(ent, vat) if not IsValid(ent) then return end if IsValid(vat.dumpsterOnFork) then return end if IsValid(vat.forkWeld) then return end local localang = ent:GetAngles() local vec = LIBPosition.VectorToLocalToWorld(ent, Vector(0, 65, 60)) local fork = LIBEntities.GetChild(ent, "Prop_Fork") if not IsValid(fork) then return end fork:SetPos(vec) fork:SetAngles(localang) LIBBones.SetAnim(fork, "open") local weld = LIBConstraints.Weld( fork, ent, { nocollide = true, deleteEntOnBreak = true, } ) if not IsValid(weld) then ent:Remove() return end vat.forkWeld = weld vat.dumpsterOnFork = false return end local function isTrashBag(target) if not IsValid(target) then return false end if target:GetClass() ~= "prop_physics" then return false end for i = 1, 3 do local model = "models/sligwolf/garbagetruck/trashbag_" .. i .. ".mdl" if target:GetModel() == model then return true end end return false end local function attToPos(ent, num) if not IsValid(ent) then return nil end local att = ent:GetAttachment(num) if not att then return nil end local pos = att.Pos if not pos then return nil end return pos end local function destroyTrash(ent, nums) if not IsValid(ent) then return end nums = nums or {} local vecs = {} for k, v in pairs(nums) do vecs[#vecs + 1] = attToPos(ent, v) end for i = 1, 3 do local TB = ents.FindByModel("models/sligwolf/garbagetruck/trashbag_" .. i .. ".mdl") for k, trashbag in pairs(TB) do if not isTrashBag(trashbag) then continue end local pos = trashbag:GetPos() local near = false for k, vec in pairs(vecs) do if pos:DistToSqr(vec) > maxDestroyTrashDist then continue end near = true break end if not near then continue end local trash = trashbag.content if IsValid(trash) then trash:Remove() end trashbag:EmitSound(CONSTANTS.sndBreakItem) trashbag:Remove() end end end function SLIGWOLF_ADDON:VehicleDelayedThink(ent, vat) local delay = vat.thinkDelay or 0 local now = CurTime() if delay > now then return end vat.thinkDelay = now + CONSTANTS.numBlinkInterval1 destroyTrash(ent, {3, 4}) self:ForkCheck(ent, vat) end local rightForce = 100000 local function Boosting(ent, ply) if not ply:KeyDown(IN_SPEED) then return end local phys = ent:GetPhysicsObject() if not LIBPhysics.IsValidPhysObject(phys) then return end local dir_rgt = LIBPosition.DirToLocalToWorld(ent, CONSTANTS.angZero, "Right") phys:ApplyForceCenter(dir_rgt * -rightForce) LIBCoupling.ForEachTrailerVehicles(ent, function(k, trailer_veh) if trailer_veh == ent then return end local phys = trailer_veh:GetPhysicsObject() if not LIBPhysics.IsValidPhysObject(phys) then return end local dir_rgt_trailer = LIBPosition.DirToLocalToWorld(trailer_veh, Angle(), "Right") phys:ApplyForceCenter(dir_rgt_trailer * - (rightForce / 2)) end) end local function Handbrake(ent, vat, ply) local handbrake = ply:KeyDown(IN_JUMP) if handbrake ~= vat.handbrake then vat.handbrake = handbrake LIBCoupling.ForEachTrailerVehicles(ent, function(k, trailer_veh) if trailer_veh == veh then return end if not trailer_veh:IsVehicle() then return end trailer_veh:SetHandbrake(handbrake) end) end end local function ExhaustSmoke(ent, vat) local smokeOff = LIBVelocity.IsMoving(ent, smokeOffThreshold) local smokeOn = not LIBVelocity.IsMoving(ent, smokeOnThreshold) local smokeActive = vat.smokeActive if smokeOff and smokeActive then smokeActive = false end if smokeOn and not smokeActive then smokeActive = true end local change = vat.smokeActive ~= smokeActive vat.smokeActive = smokeActive if not change then return end LIBEntities.ForEachFilteredChild(ent, "^Smoke_", function(f_ent, index, k, v) v:TurnOn(smokeActive) end) end local function VehicleBehavior(ent, vat) local ply = ent:GetDriver() if not IsValid(ply) then return end if not ply:InVehicle() then return end Boosting(ent, ply) Handbrake(ent, vat, ply) ExhaustSmoke(ent, vat) end if SERVER then function SLIGWOLF_ADDON:Think() self:ForEachInEntList("vehicles", function(addon, index, ent) local vat = self:GetEntityTable(ent) self:LightsUpdateIndicators(ent) self:VehicleDelayedThink(ent, vat) VehicleBehavior(ent, vat) end) end end local function ToggleExhaustSmoke(vehicle, toggle) toggle = tobool(toggle or false) LIBEntities.ForEachFilteredChild(vehicle, "^Smoke_", function(f_ent, index, k, v) v:TurnOn(toggle) end) end function SLIGWOLF_ADDON:EnterVehicle(ply, vehicle, vat) if CLIENT then return end if not vehicle.sligwolf_is_garbagetruck then return end self:SoundEdit(vat.sndFork, 5, 0, 0, 0, 0) ToggleExhaustSmoke(vehicle, true) end function SLIGWOLF_ADDON:LeaveVehicle(ply, vehicle, vat) if CLIENT then return end if not vehicle.sligwolf_is_garbagetruck then return end self:SoundEdit(vat.sndFork, 5, 0, 0, 0, 0) ToggleExhaustSmoke(vehicle, false) end function SLIGWOLF_ADDON:KeyPress(ply, key) if not IsValid(ply) then return end local vehicle = ply:GetVehicle() if not IsValid(vehicle) then if key == IN_USE then self:PressButton(ply) openCloseDumpster(ply) end end end SLIGWOLF_ADDON:LuaInclude("vehicleorder.lua") SLIGWOLF_ADDON:LuaInclude("sound.lua") return true