local NUKETANK_VALUES_TABLE = { NUKETANK_NUKE_MODEL = "models/weapons/w_models/w_rocket_airstrike/w_rocket_airstrike.mdl" NUKETANK_INDICATOR_MODEL = "models/props_mvm/indicator/indicator_circle_long.mdl" NUKETANK_NUKE_DAMAGE = 350 NUKETANK_NUKE_SPLASH_RADIUS = 450 NUKETANK_NUKE_SPEED = 800 NUKETANK_NUKE_DELAY = 15.0 NUKETANK_NUKE_COUNT = 6 NUKETANK_SND_SIREN = "mvm/ambient_mp3/mvm_siren.mp3" NUKETANK_SND_LAUNCH = "MVM.GiantSoldierRocketShoot" NUKETANK_INDICATOR_DURATION = 3.0 NUKETANK_LAUNCH_INTERVAL = 0.5 } foreach(k,v in NUKETANK_VALUES_TABLE) if(!(k in TankExt.ValueOverrides)) ROOT[k] <- v PrecacheModel(NUKETANK_NUKE_MODEL) PrecacheModel(NUKETANK_INDICATOR_MODEL) TankExt.PrecacheSound(NUKETANK_SND_SIREN) TankExt.PrecacheSound(NUKETANK_SND_LAUNCH) TankExt.NewTankScript("nuketank", { function OnSpawn(hTank, sTankName, hPath) { // Create weapon mimic for launching nukes local hNukeLauncher = SpawnEntityFromTable("tf_point_weapon_mimic", { origin = "0 0 150" damage = NUKETANK_NUKE_DAMAGE modeloverride = NUKETANK_NUKE_MODEL modelscale = 1.5 speedmax = NUKETANK_NUKE_SPEED speedmin = NUKETANK_NUKE_SPEED splashradius = NUKETANK_NUKE_SPLASH_RADIUS weapontype = 0 spreadangle = 0 }) TankExt.SetParentArray([hNukeLauncher], hTank) // Initialize nuke system variables local hTank_scope = hTank.GetScriptScope() hTank_scope.flLastNukeStrike <- 0.0 hTank_scope.arrayNukeIndicators <- [] hTank_scope.arrayTargetPositions <- [] hTank_scope.bNukeSequenceActive <- false hTank_scope.iNukesLaunched <- 0 hTank_scope.hNukeLauncher <- hNukeLauncher // Generate example target coordinates (you can modify these) hTank_scope.GenerateTargetPositions <- function() { arrayTargetPositions.clear() local vecTankPos = self.GetOrigin() // Example coordinates - modify these for your map local examplePositions = [ Vector(vecTankPos.x + 400, vecTankPos.y + 200, vecTankPos.z), Vector(vecTankPos.x - 300, vecTankPos.y + 350, vecTankPos.z), Vector(vecTankPos.x + 500, vecTankPos.y - 400, vecTankPos.z), Vector(vecTankPos.x - 200, vecTankPos.y - 300, vecTankPos.z), Vector(vecTankPos.x + 100, vecTankPos.y + 450, vecTankPos.z), Vector(vecTankPos.x - 450, vecTankPos.y + 100, vecTankPos.z) ] // Add randomization to positions foreach(pos in examplePositions) { local randomizedPos = Vector( pos.x + RandomInt(-100, 100), pos.y + RandomInt(-100, 100), pos.z ) arrayTargetPositions.append(randomizedPos) } } hTank_scope.PlaceNukeIndicators <- function() { // Clear existing indicators foreach(indicator in arrayNukeIndicators) if(indicator && indicator.IsValid()) indicator.Destroy() arrayNukeIndicators.clear() // Place new indicators at target positions foreach(pos in arrayTargetPositions) { // Trace to ground local startPos = pos + Vector(0, 0, 100) local endPos = pos + Vector(0, 0, -500) local groundHeight = TraceLine(startPos, endPos, null) local groundPos = Vector(pos.x, pos.y, pos.z - groundHeight) local hIndicator = TankExt.SpawnEntityFromTableFast("prop_dynamic", { origin = groundPos + Vector(0, 0, 5) model = NUKETANK_INDICATOR_MODEL disableshadows = 1 rendercolor = "255 0 0" }) // Add glowing effect local hGlow = SpawnEntityFromTable("tf_glow", { glowcolor = "255 0 0 255" target = hIndicator.GetName() }) SetPropEntity(hGlow, "m_hTarget", hIndicator) arrayNukeIndicators.append(hIndicator) } } hTank_scope.LaunchNuke <- function(vecTarget) { if(!(hNukeLauncher && hNukeLauncher.IsValid())) return // Aim launcher at target local vecDirection = vecTarget - hNukeLauncher.GetOrigin() vecDirection.Norm() local angLaunch = TankExt.VectorToQAngle(vecDirection) hNukeLauncher.SetAbsAngles(angLaunch) // Fire the nuke hNukeLauncher.AcceptInput("FireOnce", null, null, null) // Play launch sound EmitSoundEx({ sound_name = NUKETANK_SND_LAUNCH sound_level = 95 entity = self filter_type = RECIPIENT_FILTER_GLOBAL }) } hTank_scope.StartNukeSequence <- function() { if(bNukeSequenceActive) return bNukeSequenceActive = true iNukesLaunched = 0 // Play siren sound EmitSoundEx({ sound_name = NUKETANK_SND_SIREN sound_level = 100 entity = self filter_type = RECIPIENT_FILTER_GLOBAL }) // Generate target positions GenerateTargetPositions() // Place indicators PlaceNukeIndicators() // Start launching nukes after indicator delay TankExt.DelayFunction(self, this, NUKETANK_INDICATOR_DURATION, function() { LaunchNextNuke() }) } hTank_scope.LaunchNextNuke <- function() { if(iNukesLaunched < NUKETANK_NUKE_COUNT && iNukesLaunched < arrayTargetPositions.len()) { LaunchNuke(arrayTargetPositions[iNukesLaunched]) iNukesLaunched++ if(iNukesLaunched < NUKETANK_NUKE_COUNT) { TankExt.DelayFunction(self, this, NUKETANK_LAUNCH_INTERVAL, function() { LaunchNextNuke() }) } else { // All nukes launched, clean up indicators after a delay TankExt.DelayFunction(self, this, 2.0, function() { foreach(indicator in arrayNukeIndicators) if(indicator && indicator.IsValid()) indicator.Destroy() arrayNukeIndicators.clear() bNukeSequenceActive = false }) } } } // Enhanced nuke projectiles hTank_scope.ProcessNukeProjectiles <- function() { if(!(hNukeLauncher && hNukeLauncher.IsValid())) return for(local hNuke; hNuke = FindByClassnameWithin(hNuke, "tf_projectile_rocket", hNukeLauncher.GetOrigin(), 128);) { if(hNuke.GetOwner() != hNukeLauncher || hNuke.GetEFlags() & EFL_NO_MEGAPHYSCANNON_RAGDOLL) continue hNuke.AddEFlags(EFL_NO_MEGAPHYSCANNON_RAGDOLL) hNuke.SetTeam(self.GetTeam()) hNuke.SetOwner(self) // Enhanced visual effects hNuke.AcceptInput("DispatchEffect", "ParticleEffectStop", null, null) local hTrail = CreateByClassname("trigger_particle") SetPropBool(hTrail, "m_bForcePurgeFixedupStrings", true) hTrail.KeyValueFromString("particle_name", "critical_rocket_red") hTrail.KeyValueFromInt("attachment_type", 1) hTrail.KeyValueFromInt("spawnflags", 64) DispatchSpawn(hTrail) hTrail.AcceptInput("StartTouch", null, hNuke, hNuke) hTrail.Kill() // Scale up the nuke hNuke.SetModelScale(1.5, 0) } } // Main think function hTank_scope.Think <- function() { local flTime = Time() // Process nuke projectiles ProcessNukeProjectiles() // Check for nuke strike timing if(flTime - flLastNukeStrike >= NUKETANK_NUKE_DELAY && !bNukeSequenceActive) { flLastNukeStrike = flTime StartNukeSequence() } } // Add the think function to the tank TankExt.AddThinkToEnt(hTank, "Think") } function OnDeath() { // Clean up indicators on death if("arrayNukeIndicators" in this) { foreach(indicator in arrayNukeIndicators) if(indicator && indicator.IsValid()) indicator.Destroy() } } })