4ªUZnutscripts/vscriptsdirector_base_addon:£—Fÿ5/ÿÿbus_trollg$¥”ÿ5/ÿÿPrecacheModel("models/props_waterfront/tour_bus.mdl"); PrecacheSound("vehicles/bus_horn.wav"); PrecacheSound("player/charger/hit/charger_punch1.wav"); if (!("BusTroll_EndPos" in getroottable())) ::BusTroll_EndPos <- null; if (!("BusTroll_EndPosCached" in getroottable())) ::BusTroll_EndPosCached <- false; ::Bus_IsAlive <- function(p) { return p && p.IsValid() && NetProps.GetPropInt(p, "m_lifeState") == 0; } ::BusTroll_FindEndPos <- function() { if (::BusTroll_EndPosCached) return ::BusTroll_EndPos; ::BusTroll_EndPosCached = true; local startPos = null; local p = null; while (p = Entities.FindByClassname(p, "player")) { if (p.IsValid() && NetProps.GetPropInt(p, "m_iTeamNum") == 2) { startPos = p.GetOrigin(); break; } } if (startPos == null) { local s = Entities.FindByClassname(null, "info_player_start"); if (s != null) startPos = s.GetOrigin(); } local allAreas = {}; try { NavMesh.GetAllAreas(allAreas); } catch(e) {} local bestPos = null; local bestDist = -1.0; foreach (id, area in allAreas) { if (!area.HasSpawnAttributes(2048)) continue; if (area.HasSpawnAttributes(64)) continue; if (area.IsDegenerate()) continue; local c = area.GetCenter(); if (startPos != null) { local d = (c - startPos).Length(); if (d > bestDist) { bestDist = d; bestPos = c; } } else if (bestPos == null) { bestPos = c; } } if (bestPos == null) { local door = null, endDoor = null, maxDist = 0.0; while ((door = Entities.FindByClassname(door, "prop_door_rotating_checkpoint")) != null) { if (startPos != null) { local d = (door.GetOrigin() - startPos).Length(); if (d > maxDist) { maxDist = d; endDoor = door; } } else { endDoor = door; } } if (endDoor != null) bestPos = endDoor.GetOrigin(); } ::BusTroll_EndPos = bestPos; return bestPos; } ::BusTroll_FindRusher <- function() { local survivors = []; local p = null; while (p = Entities.FindByClassname(p, "player")) { if (!::Bus_IsAlive(p)) continue; if (NetProps.GetPropInt(p, "m_iTeamNum") != 2) continue; // --- THE FIX: Ignore downed or hanging teammates --- if (NetProps.GetPropInt(p, "m_isIncapacitated") == 1) continue; if (NetProps.GetPropInt(p, "m_isHangingFromLedge") == 1) continue; local flow = GetCurrentFlowDistanceForPlayer(p); if (flow < 0) flow = 0; survivors.append({ ent = p, flow = flow, pos = p.GetOrigin() }); } // If everyone is dead or downed except 1 person, this safely aborts the bus if (survivors.len() < 2) { return { rusher = null, reason = "insufficient survivors" }; } survivors.sort(function(a, b) { if (a.flow > b.flow) return -1; if (a.flow < b.flow) return 1; return 0; }); local leader = survivors[0]; local runnerUp = survivors[1]; local endPos = ::BusTroll_FindEndPos(); if (endPos != null) { local distToEnd = (leader.pos - endPos).Length(); if (distToEnd < 800.0) { return { rusher = null, reason = "at saferoom" }; } } local lead = leader.flow - runnerUp.flow; if (lead < 1500.0) { return { rusher = null, reason = "lead too small" }; } local nearestDist = 999999.0; for (local i = 1; i < survivors.len(); i++) { local d = (survivors[i].pos - leader.pos).Length(); if (d < nearestDist) nearestDist = d; } if (nearestDist < 1000.0) { return { rusher = null, reason = "teammate too close" }; } return { rusher = leader.ent, reason = "rushing" }; } ::Bus_FindRunway <- function(origin, dir) { local start = Vector(origin.x, origin.y, origin.z + 40); local tr = { start = start, end = Vector(start.x + dir.x * 5000.0, start.y + dir.y * 5000.0, start.z), mask = 1 }; TraceLine(tr); return 5000.0 * tr.fraction; } ::Bus_PointToSegment <- function(p, a, b) { local ab = b - a; local len2 = ab.x*ab.x + ab.y*ab.y + ab.z*ab.z; if (len2 < 0.01) return (p - a).Length(); local ap = p - a; local t = (ap.x*ab.x + ap.y*ab.y + ap.z*ab.z) / len2; if (t < 0.0) t = 0.0; else if (t > 1.0) t = 1.0; return (p - Vector(a.x + ab.x*t, a.y + ab.y*t, a.z + ab.z*t)).Length(); } ::BusKill <- function(victim, velX, velY) { if (!::Bus_IsAlive(victim)) return; local punchName = UniqueString("bus_punch"); SpawnEntityFromTable("ambient_generic", { targetname = punchName, message = "player/charger/hit/charger_punch1.wav", health = 6, spawnflags = 17, radius = 0, origin = victim.GetOrigin() }); EntFire(punchName, "PlaySound", "", 0.0); EntFire(punchName, "Kill", "", 3.0); EmitSoundOn("Player.FallDamage", victim); victim.ApplyAbsVelocityImpulse(Vector(velX * 0.8, velY * 0.8, 1200)); DoEntFire("!self", "RunScriptCode", "if (self.IsValid()) { " + "NetProps.SetPropInt(self, \"m_currentReviveCount\", 2); " + "NetProps.SetPropInt(self, \"m_bIsOnThirdStrike\", 1); " + "NetProps.SetPropInt(self, \"m_isHangingFromLedge\", 0); " + "self.TakeDamage(9999, 131073, null); }", 0.05, null, victim); local shakeName = UniqueString("bus_shake"); SpawnEntityFromTable("env_shake", { targetname = shakeName, amplitude = 16, radius = 1500, duration = 1.2, frequency = 60, spawnflags = 4, origin = victim.GetOrigin() }); EntFire(shakeName, "StartShake", "", 0.0); EntFire(shakeName, "Kill", "", 1.5); } ::BusThink <- function() { if (!self.IsValid()) return; local scope = self.GetScriptScope(); local pos = self.GetOrigin(); local newPos = pos + (scope.vel * 0.015); self.SetOrigin(newPos); scope.elapsed += 0.015; if (scope.elapsed >= scope.lifetime) { if (!scope.hit && ::Bus_IsAlive(scope.victim)) { if (scope.retries < 2) { local retries = scope.retries + 1; local victim = scope.victim; EntFire("worldspawn", "RunScriptCode", "::PunishRusher(EntIndexToHScript(" + victim.GetEntityIndex() + "), " + retries + ")", 0.1); } else { ::BusKill(scope.victim, scope.vel.x, scope.vel.y); } } if (scope.hornName) { EntFire(scope.hornName, "ClearParent", "", 0.0); EntFire(scope.hornName, "Kill", "", 2.0); } self.Kill(); return; } if (!scope.hit && ::Bus_IsAlive(scope.victim)) { local v = scope.victim.GetOrigin(); local d = ::Bus_PointToSegment(Vector(v.x, v.y, v.z + 30), pos, newPos); if (d <= 130.0) { scope.hit = true; ::BusKill(scope.victim, scope.vel.x, scope.vel.y); } } return 0.015; } ::PunishRusher <- function(victim, retries = 0) { if (!::Bus_IsAlive(victim)) return; local victimPos = victim.GetOrigin(); local fwd = victim.GetForwardVector(); local rx = fwd.y, ry = -fwd.x; local rLen = sqrt(rx*rx + ry*ry); if (rLen < 0.01) { rx = 1; ry = 0; } else { rx /= rLen; ry /= rLen; } local sideA = Vector(rx, ry, 0); local sideB = Vector(-rx, -ry, 0); local distA = ::Bus_FindRunway(victimPos, sideA); local distB = ::Bus_FindRunway(victimPos, sideB); local sideDir = (distA >= distB) ? sideA : sideB; local runway = (distA >= distB) ? distA : distB; local spawnPos, velocity, yaw, lifetime; local divebomb = false; if (runway >= 200.0) { local spawnDist = runway - 60.0; spawnPos = Vector(victimPos.x + sideDir.x * spawnDist, victimPos.y + sideDir.y * spawnDist, victimPos.z + 30); velocity = Vector(-sideDir.x * 6000.0, -sideDir.y * 6000.0, 0); yaw = (atan2(-sideDir.y, -sideDir.x) * 180.0) / PI; lifetime = (runway / 6000.0) + 2.0; } else { local ceilCheck = { start = Vector(victimPos.x, victimPos.y, victimPos.z + 60), end = Vector(victimPos.x, victimPos.y, victimPos.z + 3000), mask = 1 }; TraceLine(ceilCheck); local ceilDist = 3000.0 * ceilCheck.fraction; if (ceilDist < 200.0) { return; } local arcOffset = (distA >= distB) ? sideDir : Vector(-sideDir.x, -sideDir.y, 0); local arcDist = (runway > 100.0) ? runway : 200.0; spawnPos = Vector(victimPos.x + arcOffset.x * arcDist, victimPos.y + arcOffset.y * arcDist, victimPos.z + ceilDist - 60); local toVictim = victimPos - spawnPos; local toLen = toVictim.Length(); if (toLen < 1.0) toLen = 1.0; velocity = Vector((toVictim.x / toLen) * 6000.0, (toVictim.y / toLen) * 6000.0, (toVictim.z / toLen) * 6000.0); yaw = (atan2(velocity.y, velocity.x) * 180.0) / PI; lifetime = (toLen / 6000.0) + 2.0; divebomb = true; } local busName = UniqueString("midnight_bus"); local busAngles = divebomb ? Vector(20, yaw, 0) : Vector(0, yaw, 0); local bus = SpawnEntityFromTable("prop_dynamic_override", { targetname = busName, model = "models/props_waterfront/tour_bus.mdl", origin = spawnPos, angles = busAngles, solid = 0, rendermode = 1, renderamt = 255 }); if (!bus) return; NetProps.SetPropFloat(bus, "m_flModelScale", 0.32); local hornName = UniqueString("bus_horn"); SpawnEntityFromTable("ambient_generic", { targetname = hornName, message = "vehicles/bus_horn.wav", health = 10, spawnflags = 17, radius = 0, origin = spawnPos }); EntFire(hornName, "SetParent", busName, 0.0); EntFire(hornName, "PlaySound", "", 0.01); local rumbleName = UniqueString("bus_rumble"); SpawnEntityFromTable("env_shake", { targetname = rumbleName, amplitude = 4, radius = 800, duration = lifetime, frequency = 20, spawnflags = 4, origin = victimPos }); EntFire(rumbleName, "StartShake", "", 0.0); EntFire(rumbleName, "Kill", "", lifetime + 0.1); bus.ValidateScriptScope(); local scope = bus.GetScriptScope(); scope.vel <- velocity; scope.victim <- victim; scope.elapsed <- 0.0; scope.hit <- false; scope.lifetime <- lifetime; scope.retries <- retries; scope.hornName <- hornName; scope.BusThink <- ::BusThink; AddThinkToEnt(bus, "BusThink"); } if (!("BusTroll_LastAutoBus" in getroottable())) ::BusTroll_LastAutoBus <- 0.0; ::BusTroll_AutoTick <- function() { if (Time() - ::BusTroll_LastAutoBus < 10.0) return 2.0; local result = ::BusTroll_FindRusher(); if (result.rusher != null) { ::BusTroll_LastAutoBus = Time(); ::PunishRusher(result.rusher); } return 2.0; } ::BusTroll_StartAutoDetect <- function() { ::BusTroll_LastAutoBus = 0.0; ::BusTroll_EndPosCached = false; ::BusTroll_EndPos = null; local world = Entities.First(); world.ValidateScriptScope(); local scope = world.GetScriptScope(); scope["BusTroll_AutoTick"] <- ::BusTroll_AutoTick; AddThinkToEnt(world, "BusTroll_AutoTick"); } function OnGameEvent_round_start_post_nav(params) { ::BusTroll_StartAutoDetect(); } ::BusTroll_StartAutoDetect(); __CollectEventCallbacks(this, "OnGameEvent_", "GameEventCallbacks", RegisterScriptGameEventListener);IncludeScript("bus_troll")