local EMPTANK_VALUES_TABLE = { EMPTANK_MODEL_SHIELD = "models/props_tumb/mvm/tank_shield.mdl" EMPTANK_EMP_DAMAGE = 50 EMPTANK_EMP_RANGE = 450 EMPTANK_EMP_COOLDOWN = 12 EMPTANK_PULSE_DAMAGE = 35 EMPTANK_PULSE_RANGE = 300 EMPTANK_PULSE_COOLDOWN = 6 EMPTANK_DISABLE_DURATION = 8 EMPTANK_STUN_DURATION = 4 EMPTANK_SHIELD_RESISTANCE = 0.1 EMPTANK_SND_EMP_CHARGE = ")ambient/energy/electric_loop.wav" EMPTANK_SND_EMP_BLAST = ")ambient/energy/weld1.wav" EMPTANK_SND_PULSE = ")ambient/energy/zap9.wav" EMPTANK_SND_SHIELD_DEPLOY = "player/invuln_on_vaccinator.wav" EMPTANK_SND_SHIELD_RESIST = ")player/resistance_medium1.wav" EMPTANK_PARTICLE_EMP = "unusual_tesla_flash" //EMPTANK_PARTICLE_PULSE = "dxhr_sniper_rail_green" EMPTANK_PARTICLE_SHIELD = "vaccinator_red_buff2" } foreach(k,v in EMPTANK_VALUES_TABLE) if(!(k in TankExt.ValueOverrides)) ROOT[k] <- v // Define missing mathematical functions in ROOT scope if(!("min" in ROOT)) { ROOT.min <- function(a, b) { return a < b ? a : b } } if(!("max" in ROOT)) { ROOT.max <- function(a, b) { return a > b ? a : b } } // Precache only the working models and sounds PrecacheModel(EMPTANK_MODEL_SHIELD) TankExt.PrecacheSound(EMPTANK_SND_EMP_CHARGE) TankExt.PrecacheSound(EMPTANK_SND_EMP_BLAST) TankExt.PrecacheSound(EMPTANK_SND_PULSE) TankExt.PrecacheSound(EMPTANK_SND_SHIELD_DEPLOY) TankExt.PrecacheSound(EMPTANK_SND_SHIELD_RESIST) // EMP Tank damage resistance system ::EMPTankEvents <- { OnGameEvent_recalculate_holidays = function(_) { if(GetRoundState() == 3) delete ::EMPTankEvents } OnScriptHook_OnTakeDamage = function(params) { local hVictim = params.const_entity local hAttacker = params.attacker if(hVictim && hAttacker && hVictim.GetClassname() == "tank_boss" && hAttacker.GetTeam() != hVictim.GetTeam()) { local EMPScope = TankExt.GetMultiScopeTable(hVictim.GetScriptScope(), "emptank") if(EMPScope && EMPScope.bShieldActive) { // Reduce damage from blast sources (the green shield specialty) if(params.damage_type & (DMG_BLAST | DMG_BLAST_SURFACE)) { params.damage *= EMPTANK_SHIELD_RESISTANCE EMPScope.ShieldResist() EmitSoundEx({ sound_name = EMPTANK_SND_SHIELD_RESIST sound_level = 85 entity = hVictim filter_type = RECIPIENT_FILTER_GLOBAL }) } } } } } __CollectGameEventCallbacks(EMPTankEvents) // CRITICAL FIX: Safe building interaction function function SafeBuildingInteraction(hBuilding, action, param1 = null, param2 = null, param3 = null) { // Triple check for building validity if(!hBuilding) return false if(hBuilding == null) return false try { if(!hBuilding.IsValid()) return false // Additional check - make sure it has AcceptInput method if(!("AcceptInput" in hBuilding)) return false // Perform the action hBuilding.AcceptInput(action, param1, param2, param3) return true } catch(e) { // Silently handle any errors return false } } // FIXED: EMP Tank with comprehensive null safety TankExt.NewTankType("emptank", { function OnSpawn() { local arrayModels = [] local bIsBlueTeam = self.GetTeam() == TF_TEAM_BLUE // Deploy shield sound EmitSoundEx({ sound_name = EMPTANK_SND_SHIELD_DEPLOY pitch = 85 filter_type = RECIPIENT_FILTER_GLOBAL entity = self }) // Only spawn the vaccinator shield (the one that works) local hShield = TankExt.SpawnEntityFromTableFast("prop_dynamic", { model = EMPTANK_MODEL_SHIELD skin = 3 // Green blast shield skin disableshadows = 1 rendermode = 1 origin = "0 0 0" }) arrayModels.append(hShield) // Create green shield particle effect local hShieldParticle = SpawnEntityFromTable("info_particle_system", { origin = Vector(0, 0, 200) effect_name = format("vaccinator_%s_buff2", bIsBlueTeam ? "blue" : "red") start_active = 1 }) arrayModels.append(hShieldParticle) // Add green electrical glow to the shield hShield.AddEFlags(EFL_DONTBLOCKLOS) TankExt.DispatchParticleEffectOn(hShield, "unusual_tesla_flash", "") // Store references for EMP abilities hEMPShield <- hShield // Initialize EMP system variables flLastEMPBlast <- 0.0 flLastEMPPulse <- 0.0 iEMPCharge <- 0 bShieldActive <- true arrayDisabledBuildings <- [] // Start ambient EMP charging sound on the tank itself EmitSoundOn(EMPTANK_SND_EMP_CHARGE, self) // FIXED: Define functions with comprehensive null safety PerformMajorEMPBlast <- function() { EmitSoundEx({ sound_name = EMPTANK_SND_EMP_BLAST sound_level = 100 filter_type = RECIPIENT_FILTER_GLOBAL entity = self }) local vecOrigin = self.GetOrigin() // Massive green EMP visual effect from tank and shield TankExt.DispatchParticleEffectOn(self, EMPTANK_PARTICLE_EMP, "") TankExt.DispatchParticleEffectOn(hEMPShield, EMPTANK_PARTICLE_EMP, "") // Create additional visual effects around the tank for(local i = 0; i < 5; i++) { TankExt.DispatchParticleEffectOn(self, "unusual_tesla_flash", "") } // CRITICAL FIX: Safe building search and disable with null checks for(local hBuilding; hBuilding = FindByClassnameWithin(hBuilding, "obj_*", vecOrigin, EMPTANK_EMP_RANGE);) { // TRIPLE NULL CHECK for building safety if(hBuilding && hBuilding != null && hBuilding.IsValid()) { try { if(hBuilding.GetTeam() != self.GetTeam()) { DisableBuilding(hBuilding, EMPTANK_DISABLE_DURATION) // Green EMP effect on building TankExt.DispatchParticleEffectOn(hBuilding, EMPTANK_PARTICLE_EMP, "") } } catch(e) { // Silently handle any building interaction errors continue } } } // EMP effect on players - stun and drain ammo/metal for(local hPlayer; hPlayer = FindByClassnameWithin(hPlayer, "player", vecOrigin, EMPTANK_EMP_RANGE);) { if(hPlayer && hPlayer.IsValid() && hPlayer.IsAlive() && hPlayer.GetTeam() != self.GetTeam()) { // EMP damage hPlayer.TakeDamageCustom(self, self, null, Vector(), Vector(), EMPTANK_EMP_DAMAGE, DMG_SHOCK, TF_DMG_CUSTOM_NONE) // Stun effect hPlayer.AddCondEx(TF_COND_STUNNED, EMPTANK_STUN_DURATION, null) // Drain all ammo for(local i = 0; i < 3; i++) { local hWeapon = NetProps.GetPropEntityArray(hPlayer, "m_hMyWeapons", i) if(hWeapon != null) { NetProps.SetPropInt(hWeapon, "m_iClip1", 0) NetProps.SetPropInt(hWeapon, "m_iClip2", 0) } } // Drain engineer metal if(hPlayer.GetPlayerClass() == TF_CLASS_ENGINEER) { NetProps.SetPropIntArray(hPlayer, "m_iAmmo", 0, 3) } // Green EMP effect on player TankExt.DispatchParticleEffectOn(hPlayer, EMPTANK_PARTICLE_EMP, "") } } } PerformEMPPulse <- function() { EmitSoundEx({ sound_name = EMPTANK_SND_PULSE sound_level = 80 filter_type = RECIPIENT_FILTER_GLOBAL entity = self }) local vecOrigin = self.GetOrigin() // Green pulse effect from tank //TankExt.DispatchParticleEffectOn(self, EMPTANK_PARTICLE_PULSE, "") // Pulse damage to nearby players for(local hPlayer; hPlayer = FindByClassnameWithin(hPlayer, "player", vecOrigin, EMPTANK_PULSE_RANGE);) { if(hPlayer && hPlayer.IsValid() && hPlayer.IsAlive() && hPlayer.GetTeam() != self.GetTeam()) { // Pulse damage hPlayer.TakeDamageCustom(self, self, null, Vector(), Vector(), EMPTANK_PULSE_DAMAGE, DMG_SHOCK, TF_DMG_CUSTOM_NONE) // Brief interference effect hPlayer.AddCondEx(TF_COND_STUNNED, 1.0, null) // Green pulse effect on player //TankExt.DispatchParticleEffectOn(hPlayer, EMPTANK_PARTICLE_PULSE, "") } } // CRITICAL FIX: Safe building interference with comprehensive null checks for(local hBuilding; hBuilding = FindByClassnameWithin(hBuilding, "obj_*", vecOrigin, EMPTANK_PULSE_RANGE);) { // COMPREHENSIVE NULL AND VALIDITY CHECKS if(hBuilding && hBuilding != null && hBuilding.IsValid()) { try { if(hBuilding.GetTeam() != self.GetTeam()) { // Use safe building interaction if(SafeBuildingInteraction(hBuilding, "Disable", null, null, null)) { // Schedule re-enable using safe method TankExt.DelayFunction(self, this, 2.0, function() { SafeBuildingInteraction(hBuilding, "Enable", null, null, null) }) } // Green pulse effect on building //TankExt.DispatchParticleEffectOn(hBuilding, EMPTANK_PARTICLE_PULSE, "") } } catch(e) { // Silently handle any building interaction errors continue } } } } DisableBuilding <- function(hBuilding, flDuration) { // COMPREHENSIVE NULL SAFETY CHECK if(!hBuilding || hBuilding == null) return try { if(!hBuilding.IsValid()) return // Use safe building interaction if(SafeBuildingInteraction(hBuilding, "Disable", null, null, null)) { // Track disabled building local buildingData = { building = hBuilding, enableTime = Time() + flDuration } arrayDisabledBuildings.append(buildingData) } } catch(e) { // Silently handle any errors return } } MaintainDisabledBuildings <- function() { local flTime = Time() for(local i = arrayDisabledBuildings.len() - 1; i >= 0; i--) { local buildingData = arrayDisabledBuildings[i] // COMPREHENSIVE NULL SAFETY CHECK if(!buildingData.building || buildingData.building == null) { // Remove invalid building from tracking arrayDisabledBuildings.remove(i) continue } try { if(!buildingData.building.IsValid()) { // Building was destroyed, remove from tracking arrayDisabledBuildings.remove(i) } else if(flTime >= buildingData.enableTime) { // Time to re-enable building - use safe method if(SafeBuildingInteraction(buildingData.building, "Enable", null, null, null)) { arrayDisabledBuildings.remove(i) } } } catch(e) { // Remove problematic building from tracking arrayDisabledBuildings.remove(i) } } } ShieldResist <- function() { // Create shield flash effect local hShieldFlash = TankExt.SpawnEntityFromTableFast("prop_dynamic", { model = EMPTANK_MODEL_SHIELD skin = 3 // Green blast shield disableshadows = 1 renderfx = kRenderFxFadeFast }) SetPropBool(hShieldFlash, "m_bForcePurgeFixedupStrings", true) SetPropInt(hShieldFlash, "m_clrRender", GetPropInt(hEMPShield, "m_clrRender")) TankExt.SetParentArray([hShieldFlash], self) EntFireByHandle(hShieldFlash, "Kill", null, 1, null, null) } // FIXED: Main think function with safe mathematical operations Think <- function() { if(!self.IsValid()) return local flTime = Time() // EMP charge builds up over time - SAFE VERSION without min() if(iEMPCharge < 100) { iEMPCharge = iEMPCharge + 3 if(iEMPCharge > 100) iEMPCharge = 100 } // Visual charge indicator - more green effects as charge increases //if(iEMPCharge > 60) { //if(RandomInt(1, 100) <= (iEMPCharge - 60)) { // Create charging effect on the tank itself //TankExt.DispatchParticleEffectOn(self, EMPTANK_PARTICLE_PULSE, "") //} //} // Shield charging effects if(iEMPCharge > 80) { if(RandomInt(1, 100) <= 20) { TankExt.DispatchParticleEffectOn(hEMPShield, "unusual_tesla_flash", "") } } // Major EMP blast when fully charged if(iEMPCharge >= 100 && flTime - flLastEMPBlast >= EMPTANK_EMP_COOLDOWN) { PerformMajorEMPBlast() flLastEMPBlast = flTime iEMPCharge = 0 } // Regular EMP pulses if(flTime - flLastEMPPulse >= EMPTANK_PULSE_COOLDOWN) { PerformEMPPulse() flLastEMPPulse = flTime } // Maintain disabled buildings MaintainDisabledBuildings() } // Set up the tank models TankExt.SetParentArray(arrayModels, self) } }) // Storm variant with enhanced abilities TankExt.NewTankType("emptank_storm", { function OnSpawn() { // Call base emptank spawn - this will inherit all the EMP abilities TankExt.TankScripts.emptank.OnSpawn.call(this) // Add storm-specific abilities flLastEMPStorm <- 0.0 arrayEMPFields <- [] // Store the base think function local BaseThink = Think CreateEMPStorm <- function() { // Create multiple persistent EMP fields around the map for(local i = 0; i < 3; i++) { local vecFieldPos = self.GetOrigin() + Vector( RandomInt(-600, 600), RandomInt(-600, 600), 0 ) // Create EMP field data local empField = { position = vecFieldPos, creationTime = Time(), duration = 15.0, lastPulse = 0.0 } arrayEMPFields.append(empField) // Visual effect for field creation TankExt.DispatchParticleEffectOn(self, EMPTANK_PARTICLE_EMP, "") } } MaintainEMPFields <- function() { local flTime = Time() for(local i = arrayEMPFields.len() - 1; i >= 0; i--) { local field = arrayEMPFields[i] // Check if field has expired if(flTime - field.creationTime >= field.duration) { arrayEMPFields.remove(i) continue } // Pulse every 2 seconds if(flTime - field.lastPulse >= 2.0) { field.lastPulse = flTime // EMP field pulse effect for(local hPlayer; hPlayer = FindByClassnameWithin(hPlayer, "player", field.position, 200);) { if(hPlayer && hPlayer.IsValid() && hPlayer.IsAlive() && hPlayer.GetTeam() != self.GetTeam()) { hPlayer.TakeDamageCustom(self, self, null, Vector(), Vector(), 15, DMG_SHOCK, TF_DMG_CUSTOM_NONE) //TankExt.DispatchParticleEffectOn(hPlayer, EMPTANK_PARTICLE_PULSE, "") } } // CRITICAL FIX: Safe building disable in EMP fields for(local hBuilding; hBuilding = FindByClassnameWithin(hBuilding, "obj_*", field.position, 200);) { if(hBuilding && hBuilding != null && hBuilding.IsValid()) { try { if(hBuilding.GetTeam() != self.GetTeam()) { if(SafeBuildingInteraction(hBuilding, "Disable", null, null, null)) { TankExt.DelayFunction(self, this, 3.0, function() { SafeBuildingInteraction(hBuilding, "Enable", null, null, null) }) } } } catch(e) { // Silently handle any building interaction errors continue } } } } } } // FIXED: Override the Think function to include storm abilities Think <- function() { // Call base EMP tank think first BaseThink.call(this) local flTime = Time() // EMP storm ability - creates persistent EMP fields if(flTime - flLastEMPStorm >= 20.0) { if(RandomInt(1, 100) <= 40) { // 25% chance every 20 seconds CreateEMPStorm() flLastEMPStorm = flTime } } // Maintain EMP fields MaintainEMPFields() } } })