/* * Author: Needles * https://steamcommunity.com/profiles/76561198026257137/ */ printl("*** HANDLER/SCRAP"); ::Scrap <- {}; ::Scrap.SCRAP_MODEL_PATH <- "models/player/gibs/gibs_can.mdl"; ::Scrap.SCRAP_MODEL_OFFSET <- Vector(0.0, -8.0, -16.0); ::Scrap.SCRAP_MODEL_SCALE <- 1.2; ::Scrap.SCRAP_SOUND_PATH <- "mvm/mvm_money_pickup.wav"; PrecacheModel(::Scrap.SCRAP_MODEL_PATH); PrecacheSound(::Scrap.SCRAP_SOUND_PATH); ::Scrap.standardHealAmount <- 15; ::Scrap.minHealAmount <- 5; ::Scrap.maxHealAmount <- 50; ::Scrap.overhealLimit <- 700; ::Scrap.collectionRadius <- 64.0; ::Scrap.overhealCollectionRadius <- ::Const.MVM_MONEY_COLLECT_RADIUS; ::Scrap.maxTestDistance <- 4096; ::Scrap.ent_lightingOrigin <- null; ::Scrap.spawnFilterList <- [ ::Filter.TFTeamFilter(Constants.ETFTeam.TF_TEAM_BLUE), ]; ::Scrap.collectFilterList <- [ ::Filter.TFTeamFilter(Constants.ETFTeam.TF_TEAM_RED), ]; ::Scrap.overhealFilterList <- [ ::Filter.TFClassFilter(Constants.ETFClass.TF_CLASS_SCOUT), ]; local ScrapHandler = class extends ::Handler.BaseHandler { self = null; ent_prop = null; despawnDelay = null; warningDelay = null; rotationSpeed = null; creationTime = null; doFlash = null; flashTimer = null; constructor() { base.constructor(); despawnDelay = 25; warningDelay = 5; rotationSpeed = 90.0; flashTimer = null; doFlash = false; } function OnAdd() { local particleAttachment = ::Particle.Validate(ent_prop); if (particleAttachment != null); particleAttachment.AddEffect("community_sparkle_rand"); } function OnRemove() { local particleAttachment = ::Particle.Validate(ent_prop); if (particleAttachment != null); particleAttachment.RemoveEffect("community_sparkle_rand"); } function Collect(player) { if (::Players.IsPlayerValid(player) == false || ::Players.IsPlayerAlive(player) == false) { return; } // @TODO - Make backscratcher increase the heal ammount if (::Filter.FilterAll(player, ::Scrap.overhealFilterList) == true) { // Overheal if (player.GetHealth() < ::Scrap.overhealLimit) { local healAmount = ::Scrap.maxHealAmount - (::Scrap.maxHealAmount - ::Scrap.minHealAmount) * player.GetHealth() / ::Scrap.overhealLimit; player.SetHealth(::MathN.Min(player.GetHealth() + healAmount, ::Scrap.overhealLimit)); } } else { // Standard heal if (player.GetHealth() < player.GetMaxHealth()) player.SetHealth(::MathN.Min(player.GetHealth() + ::Scrap.standardHealAmount, player.GetMaxHealth())); } ::Utils.TempAmbientGeneric(::Scrap.SCRAP_SOUND_PATH, player.GetOrigin(), 4096, 10, 100, 0.5); ::Handler.MarkForCleanup(self); self.Destroy(); } function Flash() { if (!self || !self.IsValid()) { return; } if (doFlash == true) { doFlash = false; NetProps.SetPropInt(ent_prop, "m_clrRender", ::Color.Color(255, 255, 255, 255).ToHex()); } else if (doFlash == false) { doFlash = true; NetProps.SetPropInt(ent_prop, "m_clrRender", ::Color.Color(255, 255, 255, 100).ToHex()); } } function OnEvent_Tick(params) { // Speeeeen local angles = self.GetAbsAngles(); angles.y += 45.0 * params.time; self.SetAbsAngles(angles); // Get collected by players for (local i = 1; i <= ::Players.Max(); i++) { local player = PlayerInstanceFromIndex(i); if (player == null) continue; if (::Filter.FilterAll(player, ::Scrap.collectFilterList) == false) { continue; } local radius = 0.0; if (::Filter.FilterAll(player, ::Scrap.overhealFilterList) == true) { // Big radius radius = ::Scrap.overhealCollectionRadius; } else { // Small radius radius = ::Scrap.collectionRadius; } if (((player.GetOrigin() - self.GetOrigin()).LengthSqr() > (radius * radius))) { continue; } Collect(player); break; } // Despawn warning if (flashTimer == null && Time() >= time + despawnDelay - warningDelay) { local _this = this; flashTimer = ::Timers.AddTimer(0.5, function(params) { if (_this.self == null || _this.self.IsValid() == false) { ::Debug.Print("*** SCRAP - Entity no longer exists, removing timer"); ::Timers.RemoveTimer(_this.flashTimer); return -1; } _this.Flash(); }, null, TIMER_REPEAT_INFINITE); } // Despawn if (Time() >= time + despawnDelay) { if (self.IsValid()) { ::Handler.MarkForCleanup(self); self.Destroy(); } } } } ::Handler.RegisterHandler("scrap", @() ScrapHandler()); function Scrap::BuildScrapItem(origin, angles) { // Don't appear in the air local trace = { start = origin, end = origin + Vector(0.0, 0.0, -::Scrap.maxTestDistance), mask = Constants.FContents.CONTENTS_SOLID | Constants.FContents.CONTENTS_GRATE | Constants.FContents.CONTENTS_WINDOW, ignore = null, }; TraceLineEx(trace); // @TODO - Try endpos local newOrigin = origin + Vector(0.0, 0.0, 8.0) + Vector(0.0, 0.0, -::Scrap.maxTestDistance) * trace.fraction; local ent_item = SpawnEntityFromTable("prop_dynamic", { origin = newOrigin, angles = angles, model = "models/empty.mdl", }); local ent_prop = SpawnEntityFromTable("prop_dynamic", { origin = newOrigin + ::Scrap.SCRAP_MODEL_OFFSET * ::Scrap.SCRAP_MODEL_SCALE, angles = angles, model = "models/empty.mdl", modelscale = ::Scrap.SCRAP_MODEL_SCALE, rendermode = 1, disablereceiveshadows = true, }); ent_prop.SetModel(::Scrap.SCRAP_MODEL_PATH); EntFireByHandle(ent_prop, "SetParent", "!activator", -1.0, ent_item, null); if (::Scrap.ent_lightingOrigin != null && ::Scrap.ent_lightingOrigin.IsValid()) { NetProps.SetPropEntity(ent_prop, "m_hLightingOrigin", ::Scrap.ent_lightingOrigin); } local scrapHandler = ::Handler.AddHandler(ent_item, "scrap", null, -1.0, {ent_prop = ent_prop,}); return scrapHandler; } ::Events.GetGlobalEvent(EVENT.PLAYER_DEATH).AddListener( function(params) { local player = GetPlayerFromUserID(params.userid); if (!::Players.IsPlayerValid(player)) { return; } foreach(filter in ::Scrap.spawnFilterList) { if (!filter.Filter(player)) { return; } } ::Scrap.BuildScrapItem(player.GetOrigin(), QAngle(0.0, 0.0, 0.0)); } );