4ªU>nutscripts/vscriptsdirector_base_addon*…©[ÿÈ,ÿÿ::ShockStationSettings <- { trigger_radius = 150.0, damage = 50.0, survivor_damage = 50.0, trap_duration = 30.0, shock_delay = 2.0, shock_interval = 1.0, survivor_shock = true }; ::ShockStationModel <- "models/w_models/weapons/w_eq_defibrillator.mdl"; ::ShockStationSound <- "weapons/defibrillator/defibrillator_use.wav"; ::ShockStationElectricSound <- "ReallyLoudSpark"; ::ShockStationParticle <- "electrical_arc_01_parent"; ::ShockStation_IN_ATTACK2 <- 2048; ::ShockStation_IN_DUCK <- 4; ::ShockStationTraps <- {}; ::ShockStationPreviousCombo <- {}; function LoadShockStationSettings() { local path = "shockstation/settings.cfg", file = FileToString(path); if (!file) { StringToFile(path, "trigger_radius = 150.0\ndamage = 50.0\nsurvivor_damage = 50.0\ntrap_duration = 30.0\nshock_delay = 2.0\nshock_interval = 1.0\nsurvivor_shock = true\n"); return; } foreach (line in split(file, "\n")) { line = strip(line); if (line == "" || line.slice(0, 1) == "#" || (line.len() >= 2 && line.slice(0, 2) == "//")) continue; local eq = line.find("="); if (eq == null) continue; local key = strip(line.slice(0, eq)), val = strip(line.slice(eq + 1)); if (!(key in ::ShockStationSettings)) continue; if (key == "survivor_shock") { local v = val.tolower(); ::ShockStationSettings[key] = (v == "true" || v == "1" || v == "yes"); } else ::ShockStationSettings[key] = val.tofloat(); } } ::ShockStationCreateProp <- function(pos) { local defib = SpawnEntityFromTable("prop_dynamic_override", { targetname = "shock_station_prop_" + UniqueString("defib_"), model = ::ShockStationModel, origin = format("%f %f %f", pos.x, pos.y, pos.z), angles = "0 0 0", solid = 0, glowstate = 3, glowcolor = "50 150 255" }); if (!defib || !defib.IsValid()) return null; defib.SetOrigin(pos); defib.SetAngles(QAngle(0, 0, 0)); DoEntFire("!self", "DisableCollision", "", 0.0, null, defib); DoEntFire("!self", "StartGlowing", "", 0.0, null, defib); DoEntFire("!self", "SetGlowColor", "50 150 255", 0.0, null, defib); return defib; }; ::ShockStationCreateElectricEffect <- function(pos) { local particle = SpawnEntityFromTable("info_particle_system", { targetname = "shock_station_electric_" + UniqueString("electric_"), effect_name = ::ShockStationParticle, origin = format("%f %f %f", pos.x, pos.y, pos.z) }); if (!particle || !particle.IsValid()) return null; DoEntFire("!self", "Start", "", 0.0, null, particle); DoEntFire("!self", "Kill", "", 0.30, null, particle); return particle; }; ::ShockStationPlayElectricSound <- function(prop) { if (prop && prop.IsValid()) EmitSoundOn(::ShockStationElectricSound, prop); }; ::ShockStationDamage <- function(ent, owner) { if (!ent || !ent.IsValid()) return false; try { ent.TakeDamage(::ShockStationSettings.damage, 0, owner); } catch(e) { try { ent.TakeDamage(::ShockStationSettings.damage, 0, null); } catch(e2) { return false; } } return true; }; ::ShockStationDamageSurvivor <- function(ent) { if (!ent || !ent.IsValid()) return false; try { ent.TakeDamage(::ShockStationSettings.survivor_damage, 0, null); return true; } catch(e) { return false; } }; ::ShockStationShockCommon <- function(pos, owner, radius) { local found = false, ent = null; while ((ent = Entities.FindByClassnameWithin(ent, "infected", pos, radius)) != null) { if (!ent || !ent.IsValid() || ent.GetHealth() <= 0) continue; try { ent.TakeDamage(999999, 0, owner); found = true; } catch(e) { try { ent.TakeDamage(999999, 0, null); found = true; } catch(e2) {} } } return found; }; ::ShockStationShockWitch <- function(pos, owner, radius) { local found = false, ent = null; while ((ent = Entities.FindByClassnameWithin(ent, "witch", pos, radius)) != null) { if (!ent || !ent.IsValid() || ent.GetHealth() <= 0) continue; try { ent.TakeDamage(1, 64, owner); } catch(e) {} if (::ShockStationDamage(ent, owner)) found = true; } return found; }; ::ShockStationShockSpecials <- function(pos, owner, radius) { local found = false, ent = null; while ((ent = Entities.FindByClassnameWithin(ent, "player", pos, radius)) != null) { if (!ent || !ent.IsValid() || ent.IsSurvivor() || ent.GetHealth() <= 0) continue; if ("Stagger" in ent) try { ent.Stagger(pos); found = true; } catch(e) {} if (::ShockStationDamage(ent, owner)) found = true; } return found; }; ::ShockStationShockSurvivors <- function(pos, radius) { if (!::ShockStationSettings.survivor_shock) return false; local found = false, ent = null; while ((ent = Entities.FindByClassnameWithin(ent, "player", pos, radius)) != null) { if (!ent || !ent.IsValid() || !ent.IsSurvivor() || ent.IsDead()) continue; if (::ShockStationDamageSurvivor(ent)) found = true; if ("Stagger" in ent) try { ent.Stagger(pos); } catch(e) {} } return found; }; ::ShockStationShock <- function(data) { if (!data || !data.prop || !data.prop.IsValid()) return false; local pos = data.pos, owner = data.owner, rad = ::ShockStationSettings.trigger_radius, found = false; if (::ShockStationShockCommon(pos, owner, rad)) found = true; if (::ShockStationShockWitch(pos, owner, rad)) found = true; if (::ShockStationShockSpecials(pos, owner, rad)) found = true; if (::ShockStationShockSurvivors(pos, rad)) found = true; if (found) try { EmitSoundOn(::ShockStationSound, data.prop); } catch(e) {} return found; }; ::ShockStationGetGroundPosition <- function(player) { if (!player || !player.IsValid()) return null; local playerPos = player.GetOrigin(), forward = player.GetForwardVector(); local startPos = playerPos + (forward * 30.0) + Vector(0, 0, 20.0); local trace = { start = startPos, end = startPos - Vector(0, 0, 200.0), ignore = player }; try { TraceLine(trace); } catch(e) { return null; } return trace.hit ? trace.pos : playerPos + (forward * 30.0) - Vector(0, 0, 35.0); }; ::ShockStationCreate <- function(pos, owner) { local now = Time(), prop = ::ShockStationCreateProp(pos); if (!prop || !prop.IsValid()) return false; local trap = SpawnEntityFromTable("info_target", { targetname = "shock_station_" + UniqueString("trap_"), origin = format("%f %f %f", pos.x, pos.y, pos.z) }); ::ShockStationTraps[prop.GetEntityIndex()] <- { trap = trap, prop = prop, pos = pos, owner = owner, expireTime = now + ::ShockStationSettings.trap_duration, shockStart = now + ::ShockStationSettings.shock_delay, nextShock = now + ::ShockStationSettings.shock_delay, nextParticle = now + ::ShockStationSettings.shock_delay, nextElectricSound = now + ::ShockStationSettings.shock_delay }; return true; }; ::ShockStationPlace <- function(player) { if (!player || !player.IsValid()) return false; local weapon = player.GetActiveWeapon(); if (!weapon || !weapon.IsValid() || weapon.GetClassname() != "weapon_defibrillator") return false; local spawnPos = ::ShockStationGetGroundPosition(player); if (!spawnPos) return false; try { weapon.Kill(); } catch(e) { return false; } if (!::ShockStationCreate(spawnPos, player)) { try { player.GiveItem("weapon_defibrillator"); } catch(e) {} return false; } return true; }; ::ShockStationUpdate <- function() { local player = null; while ((player = Entities.FindByClassname(player, "player")) != null) { if (!player.IsValid() || !player.IsSurvivor() || player.IsDead() || player.IsGhost()) continue; local id = player.GetEntityIndex(), buttons = player.GetButtonMask(), weapon = player.GetActiveWeapon(); if (!weapon || !weapon.IsValid() || weapon.GetClassname() != "weapon_defibrillator") { ::ShockStationPreviousCombo[id] <- false; continue; } local combo = ((buttons & ::ShockStation_IN_DUCK) != 0) && ((buttons & ::ShockStation_IN_ATTACK2) != 0); local previous = (id in ::ShockStationPreviousCombo) ? ::ShockStationPreviousCombo[id] : false; if (combo && !previous) ::ShockStationPlace(player); ::ShockStationPreviousCombo[id] <- combo; } }; ::ShockStationThink <- function() { local now = Time(), remove = []; foreach (idx, data in ::ShockStationTraps) { if (!data.prop || !data.prop.IsValid() || now >= data.expireTime) { if (data.trap && data.trap.IsValid()) try { data.trap.Kill(); } catch(e) {} if (data.prop && data.prop.IsValid()) try { data.prop.Kill(); } catch(e) {} remove.append(idx); continue; } if (now >= data.shockStart) { if (now >= data.nextParticle) { ::ShockStationCreateElectricEffect(data.pos); data.nextParticle = now + 0.20; } if (now >= data.nextElectricSound) { ::ShockStationPlayElectricSound(data.prop); data.nextElectricSound = now + 0.60; } if (now >= data.nextShock) { ::ShockStationShock(data); data.nextShock = now + ::ShockStationSettings.shock_interval; } } } foreach (idx in remove) { if (idx in ::ShockStationTraps) delete ::ShockStationTraps[idx]; } }; ::ShockStationCleanupPlayer <- function(id) { if (id in ::ShockStationPreviousCombo) delete ::ShockStationPreviousCombo[id]; }; ::ShockStationCleanupAll <- function() { foreach (idx, data in ::ShockStationTraps) { if (data.trap && data.trap.IsValid()) try { data.trap.Kill(); } catch(e) {} if (data.prop && data.prop.IsValid()) try { data.prop.Kill(); } catch(e) {} } ::ShockStationTraps.clear(); ::ShockStationPreviousCombo.clear(); }; function OnGameEvent_player_death(params) { if (params && ("userid" in params)) { local player = GetPlayerFromUserID(params.userid); if (player && player.IsValid()) ::ShockStationCleanupPlayer(player.GetEntityIndex()); } } function OnGameEvent_player_disconnect(params) { OnGameEvent_player_death(params); } function OnGameEvent_round_start(params) { ::ShockStationCleanupAll(); } function OnGameEvent_round_end(params) { ::ShockStationCleanupAll(); } ::ShockStationThinker <- function() { local old = Entities.FindByName(null, "shock_station_thinker"); if (old && old.IsValid()) old.Kill(); local thinker = SpawnEntityFromTable("info_target", { targetname = "shock_station_thinker" }); if (!thinker || !thinker.IsValid()) return; thinker.ValidateScriptScope(); thinker.GetScriptScope().Think <- function() { ::ShockStationUpdate(); ::ShockStationThink(); return 0.05; }; AddThinkToEnt(thinker, "Think"); }; try { PrecacheModel(::ShockStationModel); } catch(e) {} try { PrecacheSound(::ShockStationSound); } catch(e) {} LoadShockStationSettings(); ::ShockStationThinker(); __CollectGameEventCallbacks(this);