/* * Author: Needles * https://steamcommunity.com/profiles/76561198026257137/ */ printl("*** HANDLER/SPAWN_POINT"); ::SpawnPoint <- {}; ::SpawnPoint.MODEL_PATH <- "models/props_mvm/robot_spawnpoint.mdl" ::SpawnPoint.SPRITE_TIMER_PATH <- "needles/sprites/spawn_timer_radial.vmt"; ::SpawnPoint.SOUND_PATH <- ""; //"weapons/teleporter_receive.wav"; ::SpawnPoint.PARTICLE_BLUE <- "teleportedin_blue"; ::SpawnPoint.PARTICLE_RED <- "teleportedin_red"; PrecacheModel(::SpawnPoint.MODEL_PATH); PrecacheModel(::SpawnPoint.SPRITE_TIMER_PATH); PrecacheSound(::SpawnPoint.SOUND_PATH); ::Particle.PrecacheEffect(::SpawnPoint.PARTICLE_BLUE); ::Particle.PrecacheEffect(::SpawnPoint.PARTICLE_RED); ::SpawnPoint.SPAWN_POINT_PROTECTION_TIME <- 1.5; ::SpawnPoint.classIconPathMap <- { "scout" : "hud/leaderboard_class_scout.vmt", "soldier" : "hud/leaderboard_class_soldier.vmt", "soldier_crit" : "hud/leaderboard_class_soldier_crit.vmt", "soldier_spammer" : "hud/leaderboard_class_soldier_spammer.vmt", "soldier_burstfire" : "hud/leaderboard_class_soldier_burstfire.vmt", "soldier_barrage" : "hud/leaderboard_class_soldier_barrage.vmt", "pyro" : "hud/leaderboard_class_pyro.vmt", "pyro_dragonfury" : "hud/leaderboard_class_pyro_dragonfury.vmt", "demo" : "hud/leaderboard_class_demo.vmt", "demoknight" : "hud/leaderboard_class_demoknight.vmt", "heavy" : "hud/leaderboard_class_heavy.vmt", "heavy_champ" : "hud/leaderboard_class_heavy_champ.vmt", "engineer" : "hud/leaderboard_class_engineer.vmt", "medic" : "hud/leaderboard_class_medic.vmt", "sniper" : "hud/leaderboard_class_sniper.vmt", "sniper_bow" : "hud/leaderboard_class_sniper_bow.vmt", "spy" : "hud/leaderboard_class_spy.vmt", }; foreach (key, path in ::SpawnPoint.classIconPathMap) { PrecacheModel(path); } function SpawnPoint::GetClassIconPath(key) { return ::SpawnPoint.classIconPathMap[key]; } local SpawnPointHandler = class extends ::Handler.BaseHandler { gui_timerProgressBar = null; gui_classIcon = null; spawnGroup = null; prevSpawnGroup = null; doWaitForAllDead = null; soundPath = null; readyTime = null; isReady = null; spawnOffset = null; initialSpawn = null; event_onSpawn = null; constructor() { base.constructor(); spawnGroup = null; prevSpawnGroup = null; doWaitForAllDead = false; soundPath = ""; readyTime = -1.0; isReady = false; spawnOffset = Vector(0.0, 0.0, 0.0); initialSpawn = true; event_onSpawn = ::Events.Event(); } function OnEvent_Tick(params) { if (doWaitForAllDead == true) { if (prevSpawnGroup.ActiveCount() > 0) { ::Debug.Print("*** SPAWN_POINT - waiting for all dead..."); return; } else { ::Debug.Print("*** SPAWN_POINT - All robots from the previous spawngroup are dead"); doWaitForAllDead = false; } } if (isReady == true) { gui_timerProgressBar.SetPercentage((Time() - readyTime) / spawnGroup.spawnDelay); if (Time() >= readyTime + spawnGroup.spawnDelay) { Spawn(); } } else { if (spawnGroup.IsReadyToSpawn() == true) { SpawnGroupReady(); } } } function SpawnGroupReady() { if (initialSpawn == true) { readyTime = Time() - (spawnGroup.spawnDelay - spawnGroup.initialDelay); initialSpawn = false; } else if (initialSpawn == false) { readyTime = Time(); } isReady = true; gui_classIcon.SetColor(::Color.GetQuickColor(COLOR.WHITE)); } function Spawn() { local spawnedPlayerList = spawnGroup.SpawnPlayers(self.GetOrigin() + spawnOffset, self.GetAbsAngles()); foreach(player in spawnedPlayerList) { player.RemoveCond(Constants.ETFCond.TF_COND_INVULNERABLE_HIDE_UNLESS_DAMAGED) player.AddCondEx(Constants.ETFCond.TF_COND_INVULNERABLE, ::SpawnPoint.SPAWN_POINT_PROTECTION_TIME, null); } EmitSoundEx({ sound_name = soundPath, channel = CHANNEL.CHAN_AUTO, volume = 1.0, }); DispatchParticleEffect(::SpawnPoint.PARTICLE_BLUE, self.GetOrigin(), Vector(90.0, 0.0, 0.0)); // Only deactivate the timer if no more subsequent spawns are possible if (spawnGroup.IsReadyToSpawn() == true) { SpawnGroupReady(); return; } isReady = false; readyTime = -1.0; gui_timerProgressBar.SetPercentage(0.0); gui_classIcon.SetColor(::Color.GetQuickColor(COLOR.GREY)); event_onSpawn.FireListeners({ spawnpoint = this, playerList = spawnedPlayerList }); } function SetSpawnGroup(newSpawnGroup, waitForAllDead = false) { isReady = false; readyTime = -1.0; // @TODO - Make icons dependant on spawngroups rather than spawnpoints? // If we change the spawngroup, it could automatically assign the correct icon? prevSpawnGroup = spawnGroup; spawnGroup = newSpawnGroup; doWaitForAllDead = waitForAllDead; gui_classIcon.SetColor(::Color.GetQuickColor(COLOR.GREY)); } function SetIcon(path) { gui_classIcon.SetSprite(path); } } ::Handler.RegisterHandler("spawnpoint", @() SpawnPointHandler()); function SpawnPoint::BuildSpawnPoint(origin, angles, spawnGroup, classIconPath, soundPath = ::SpawnPoint.SOUND_PATH) { local spriteOffset = Vector(0.0, 0.0, 96.0); // Timer local ent_spriteTimer = SpawnEntityFromTable("env_glow", { scale = 0.4, origin = origin + spriteOffset, angles = angles, model = ::SpawnPoint.SPRITE_TIMER_PATH, framerate = 0, frame = 0, rendermode = 1, spawnflags = 1, }); ::Gui.GuiSprite(ent_spriteTimer); local gui_timerProgressBar = ::Gui.GuiProgressBar(ent_spriteTimer, ::AnimatedSprite.GetAnimationData(::SpawnPoint.SPRITE_TIMER_PATH), 0.0); // Class Icon local ent_spriteClassIcon = SpawnEntityFromTable("env_glow", { scale = 0.5, origin = origin + spriteOffset, angles = angles, model = classIconPath, framerate = 0, frame = 0, rendermode = 1, spawnflags = 1, }); local gui_classIcon = ::Gui.GuiSprite(ent_spriteClassIcon); // Dynamic Prop local ent_prop = SpawnEntityFromTable("prop_dynamic", { origin = origin, angles = angles, model = ::SpawnPoint.MODEL_PATH, skin = 1, disableshadows = true, }); ent_prop.ResetSequence(ent_prop.LookupSequence("idle")); EntFireByHandle(ent_spriteClassIcon, "SetParent", "!activator", -1.0, ent_prop, null); EntFireByHandle(ent_spriteTimer, "SetParent", "!activator", -1.0, ent_prop, null); local handler_spawnPoint = ::Handler.AddHandler(ent_prop, "spawnpoint", null, -1.0, {gui_timerProgressBar = gui_timerProgressBar, gui_classIcon = gui_classIcon, spawnGroup = spawnGroup, soundPath = soundPath}); return handler_spawnPoint; } function SpawnPoint::ClearSpawnPoints() { local handlerList = ::Handler.GetAllById("spawnpoint"); foreach(handler in handlerList) { if (handler.self == null || handler.self.IsValid() == false) continue; ::Handler.MarkForCleanup(handler.self); handler.self.Destroy(); } }