4U   b   nut scripts/vscripts director_base_addon ρw        txt   addoninfo s           "AddonInfo"
{

	addonSteamAppID		550
    addontitle			"Hulk Tank"
    addonversion	    1
    addontagline		"Tank Smash"
	addonauthor 		"karn"
	addonauthorSteamID "karn"

	addonContent_Campaign		0

	addonDescription "TANK SMASH!"
	addonContent_Script 1
	addonContent_Music 0
	addonContent_Sound 0
	addonContent_prop 0 //This Add-on provides new props,
	addonContent_Prefab 0 //Provides new prefabs

	addonContent_BackgroundMovie 0 //Provides a replacement for the background movie.
	addonContent_Survivor 0 //Provides a new survivor model. 0=false, 1=true, String in quotes if replaces specific single character, i.e. "Francis"
	addonContent_BossInfected 0 //Provides a new boss infected model. Break these out?
	addonContent_CommonInfected 0 //Provides a new common infected model
	addonContent_WeaponModel 0 //Provides a new appearance to existing weapons, but does not change their function
	addonContent_weapon 0 //provides new weapons or new zombie killing functionality, i.e. guns, explosives, booby traps, hot tar,
	addonContent_Skin 0 //0 if no new skin textures for existing models. 1 if multiple skin pack. String in quotes if specific single skin
	addonContent_Spray 0 //Provides new sprays.
	addonContent_Map 0 //Add-on provides a standalone map

}
// === TANK SLAM MECHANICS (NORMAL, SUPER CONE & FALL SLAM) ===
// Support for Bot Tanks (Automatic) and Player Tanks ('R' or 'E' Key)
// V5.14 - (Configurable Super Slam Fillers + Anti-Overflow & Micro-Delay Edition - 1.0s Particles Edit)

printl("[TankSlams] Initializing AI & Player Tank Slam Mechanics V5.14 (1.0s Visual Kill Edit)...");

// === GLOBAL DEFAULTS (PREVENTS CRASHES WITH OLD CONFIG FILES) ===
::TS_COOLDOWN <- 20.0; // Cooldown time for the Tank (Bot or Player) to attempt another Slam
::TS_SUPER_SLAM_CHANCE <- 50; // Chance (0 to 100) of choosing Super Slam vs Normal
::TS_PREPARE_DELAY_ENABLE <- true; // Gives a warning yell before locking the Tank in the animation
::TS_PREPARE_DELAY_TIME <- 0.2;
::TS_SUPER_SLAM_360_ENABLE <- false; // If true, Super Slam fires 8 shockwave cones in all directions
::TS_SUPER_SLAM_FILLERS_ENABLE <- false; // If true, adds extra visual filler rocks in Super Slam for a denser wave
::TS_ALLOW_CUSTOM_MODELS <- false; // Allow custom models (e.g., Meatwall) to use Slam
::TS_PLAY_EXPLOSION_SOUNDS <- false; // Plays the grenade explosion sound along with rock impacts
::TS_BLOCK_SLAM_DURING_ROCK_THROW <- true; // Prevent Slam while throwing a rock
::TS_DODGE_BY_JUMPING_ENABLE <- true; // Jumping evades the earthquake damage
::TS_PLAYER_SLAM_ENABLE <- true; // Allows human players to press the designated key to slam
::TS_THIRD_PERSON_ENABLE <- true; // Forces the player's camera to third-person while slamming
::TS_BOT_SLAM_ENABLE <- true; // Allows AI Bot Tanks to use the slam mechanics
::TS_SHOW_INVALID_TERRAIN_MSG <- false; // Shows a message when trying to slam on invalid terrain
::TS_REDUCE_ROCK_COOLDOWN_ENABLE <- false; // Reduces rock cooldown after slamming
::TS_REDUCE_ROCK_COOLDOWN_PCT <- 50; // Percentage of cooldown to reduce
::TS_NORMAL_SLAM_RANGE <- 250; // Max distance for Normal Slam target
::TS_SUPER_SLAM_MIN_RANGE <- 350; // Min distance for Super Slam target
::TS_SUPER_SLAM_MAX_RANGE <- 1000; // Max distance for Super Slam target
::TS_FALL_SLAM_ENABLE <- true; // Enables Earthquake upon falling from heights
::TS_FALL_SPEED_THRESHOLD <- 400.0; // Fall speed required to trigger Fall Slam
::TS_SMART_SLAM_SWITCH_ENABLE <- true; // Switches to Normal Slam if survivors get too close while waiting for Super Slam
::TS_DISTANCE_DAMAGE_ENABLE <- true; // Damage falloff based on distance from center
::TS_DISTANCE_DAMAGE_MIN_PCT <- 50; // Minimum % of damage applied at the very edge
::TS_DMG_SURVIVORS <- 15;
::TS_DMG_SI <- 50;
::TS_DMG_COMMONS <- 45;
::TS_SUPER_WAVES_COUNT <- 4;
::TS_SUPER_WAVES_DISTANCE <- 140;
::TS_SUPER_WAVE_DELAY <- 0.5;
::TS_RADIUS_PER_IMPACT <- 200;
::TS_SUPER_DMG_SURVIVORS <- 5;
::TS_SUPER_DMG_SI <- 20;
::TS_SUPER_DMG_COMMONS <- 100;

// --- NEW CONTROLS ---
::TS_PLAYER_SLAM_KEY <- "R"; // Default input ('R' or 'E')
::TS_ALLOW_SLAM_WHILE_STAGGERED <- false; // Allow casting while staggered?
::TS_PLAYER_MANUAL_SUPER_SLAM <- false; // If true, hold Crouch + Slam Key to Super Slam manually

// --- ANTI-GLITCH TIMERS (60/100 Tickrate Fixes) ---
::TS_LastGlobalShake <- 0.0; // Prevents screen shake overlap (fixes viewmodel gun glitch)

// === CONFIG FILE SYSTEM ===
::TS_LoadConfig <- function() {
    local configFileName = "tank_slams_v5_config.txt"; // Keeping v5 name for backward compatibility
    local configData = FileToString(configFileName);

    if (!configData) {
        local def = "";
        def += "// === TANK SLAM SETTINGS V5.14 ===\n";
        def += "// Cooldown time for the Tank (Bot or Player) to attempt another Slam\n";
        def += "TS_COOLDOWN = 20.0\n\n";

        def += "// --- CONTROLS ---\n";
        def += "// Player Slam Key ('R' for Reload, 'E' for Use)\n";
        def += "TS_PLAYER_SLAM_KEY = R\n\n";
        def += "// Allow Tank to Slam while staggered/stunned?\n";
        def += "TS_ALLOW_SLAM_WHILE_STAGGERED = false\n\n";
        def += "// Allow players to manually choose the Slam type? (Hold CROUCH + Slam Key = Super Slam)\n";
        def += "TS_PLAYER_MANUAL_SUPER_SLAM = false\n\n";
        def += "// ----------------\n\n";

        def += "// Chance (0 to 100) of choosing Super Slam vs Normal\n";
        def += "TS_SUPER_SLAM_CHANCE = 50\n\n";
        def += "// Preparation Delay (Gives a warning yell before locking the Tank in the animation)\n";
        def += "TS_PREPARE_DELAY_ENABLE = true\n";
        def += "TS_PREPARE_DELAY_TIME = 0.2\n\n";
        def += "// Super Slam 8-Way: If true, Super Slam fires 8 shockwave cones in all directions\n";
        def += "TS_SUPER_SLAM_360_ENABLE = false\n\n";
        def += "// Super Slam Fillers: If true, creates denser visual rock waves (Set to false for lighter visuals)\n";
        def += "TS_SUPER_SLAM_FILLERS_ENABLE = false\n\n";
        def += "// Allow custom models (e.g., custom boss mods like Meatwall) to use Slam. Set to false to disable.\n";
        def += "TS_ALLOW_CUSTOM_MODELS = false\n\n";
        def += "// Audio Settings\n";
        def += "TS_PLAY_EXPLOSION_SOUNDS = false\n\n";
        def += "// Safety Lock: Prevent Slam while throwing a rock (Postpones the Slam until the animation finishes)\n";
        def += "TS_BLOCK_SLAM_DURING_ROCK_THROW = true\n\n";
        def += "// Dodge Mechanic: If true, jumping evades the earthquake and damage from all waves!\n";
        def += "TS_DODGE_BY_JUMPING_ENABLE = true\n\n";
        def += "// Player Specific Settings: Allows human players to press the designated key to slam\n";
        def += "TS_PLAYER_SLAM_ENABLE = true\n\n";
        def += "// Third-Person Camera: If true, forces the player's camera to third-person while slamming\n";
        def += "TS_THIRD_PERSON_ENABLE = true\n\n";
        def += "// Bot Specific Settings: Allows AI Bot Tanks to use the slam mechanics\n";
        def += "TS_BOT_SLAM_ENABLE = true\n\n";
        def += "// Messages\n";
        def += "TS_SHOW_INVALID_TERRAIN_MSG = false\n\n";
        def += "// Rock Cooldown Reduction\n";
        def += "TS_REDUCE_ROCK_COOLDOWN_ENABLE = false\n";
        def += "TS_REDUCE_ROCK_COOLDOWN_PCT = 50\n\n";
        def += "// Ranges (For Bot targeting)\n";
        def += "TS_NORMAL_SLAM_RANGE = 250\n";
        def += "TS_SUPER_SLAM_MIN_RANGE = 350\n";
        def += "TS_SUPER_SLAM_MAX_RANGE = 1000\n\n";
        def += "// Free Fall (Fall Earthquake)\n";
        def += "TS_FALL_SLAM_ENABLE = true\n";
        def += "TS_FALL_SPEED_THRESHOLD = 400.0\n\n";
        def += "// AI Smart Slam Switch: If Tank waits 10s for a Super Slam but 2+ survivors are near, switches to Normal Slam\n";
        def += "TS_SMART_SLAM_SWITCH_ENABLE = true\n\n";
        def += "// Distance Based Damage (Normal Slams Only)\n";
        def += "TS_DISTANCE_DAMAGE_ENABLE = true\n";
        def += "TS_DISTANCE_DAMAGE_MIN_PCT = 50\n\n";
        def += "// Damage and Mechanics\n";
        def += "TS_DMG_SURVIVORS = 15\n";
        def += "TS_DMG_SI = 50\n";
        def += "TS_DMG_COMMONS = 45\n\n";
        def += "TS_SUPER_WAVES_COUNT = 4\n";
        def += "TS_SUPER_WAVES_DISTANCE = 140\n";
        def += "TS_SUPER_WAVE_DELAY = 0.5\n";
        def += "TS_RADIUS_PER_IMPACT = 200\n\n";
        def += "TS_SUPER_DMG_SURVIVORS = 5\n";
        def += "TS_SUPER_DMG_SI = 20\n";
        def += "TS_SUPER_DMG_COMMONS = 100\n";

        StringToFile(configFileName, def);
        printl("[TankSlams] Created default config file at ems/" + configFileName);
        configData = def;
    } else {
        printl("[TankSlams] Loaded configuration from ems/" + configFileName);
    }

    local lines = split(configData, "\n");
    foreach (line in lines) {
        local cIdx = line.find("//");
        if (cIdx != null) line = line.slice(0, cIdx);
        local eqIdx = line.find("=");
        if (eqIdx != null) {
            local key = line.slice(0, eqIdx);
            local val = line.slice(eqIdx + 1);
            local function trim(s) {
                local l = 0, r = s.len() - 1;
                while (l <= r && (s[l] == ' ' || s[l] == '\t' || s[l] == '\r')) l++;
                while (r >= l && (s[r] == ' ' || s[r] == '\t' || s[r] == '\r')) r--;
                return (l <= r) ? s.slice(l, r + 1) : "";
            }
            key = trim(key);
            val = trim(val);
            if (key != "" && (key in getroottable())) {
                if (val.tolower() == "true") getroottable()[key] = true;
                else if (val.tolower() == "false") getroottable()[key] = false;
                else if (key == "TS_PLAYER_SLAM_KEY") getroottable()[key] = val.toupper();
                else if (val.find(".") != null) { try { getroottable()[key] = val.tofloat(); } catch(e){} }
                else { try { getroottable()[key] = val.tointeger(); } catch(e){} }
            }
        }
    }
}
::TS_LoadConfig();

// === PRECACHE ===
PrecacheEntityFromTable({ classname = "info_particle_system", effect_name = "tank_ground_pound" });
PrecacheEntityFromTable({ classname = "info_particle_system", effect_name = "tank_rock_throw_impact" });
PrecacheSound("physics/concrete/concrete_break2.wav");
PrecacheSound("physics/concrete/concrete_break3.wav");
PrecacheSound("weapons/hegrenade/explode3.wav");
PrecacheSound("player/tank/voice/yell/tank_yell_12.wav");
PrecacheSound("player/tank/voice/yell/tank_yell_03.wav");
PrecacheSound("player/tank/voice/yell/tank_yell_04.wav");
PrecacheSound("player/tank/hit/pound_victim_1.wav");
PrecacheSound("player/tank/hit/pound_victim_2.wav");
PrecacheSound("physics/concrete/boulder_impact_hard1.wav");
PrecacheSound("physics/concrete/boulder_impact_hard2.wav");

if (!("TS_TankStates" in getroottable())) {
    ::TS_TankStates <- {};
}

// === INTEGRATED THIRD PERSON LOGIC ===
if (!("TS_IsInThirdPerson" in getroottable())) {
    ::TS_IsInThirdPerson <- false;
    ::TS_ThirdPersonEndTime <- 0.0;
}

::TS_ForceThirdPerson <- function(tank, duration) {
    if (!tank || !tank.IsValid() || IsPlayerABot(tank)) return;
    local tankIdx = tank.GetEntityIndex();
    ::TS_ThirdPersonEndTime = Time() + duration;

    if (!::TS_IsInThirdPerson) {
        ::TS_IsInThirdPerson = true;
        local cmd = Entities.FindByName(null, "ts_global_cmd");
        local isNew = false;
        if (!cmd) {
            cmd = SpawnEntityFromTable("point_clientcommand", { targetname = "ts_global_cmd" });
            isNew = true;
        }
        if (cmd) {
            local delay = isNew ? 0.15 : 0.05;
            DoEntFire("ts_global_cmd", "Command", "thirdpersonshoulder", delay, tank, tank);
        }
    }
    DoEntFire("worldspawn", "RunScriptCode", "::TS_CheckTurnOffThirdPerson(" + tankIdx + ")", duration + 0.1, null, null);
}

::TS_CheckTurnOffThirdPerson <- function(tankIdx) {
    if (!::TS_IsInThirdPerson) return;
    if (Time() < ::TS_ThirdPersonEndTime - 0.05) return;
    ::TS_IsInThirdPerson = false;
    local tank = EntIndexToHScript(tankIdx);
    if (!tank || !tank.IsValid() || IsPlayerABot(tank)) return;
    local cmd = Entities.FindByName(null, "ts_global_cmd");
    if (cmd) {
        DoEntFire("ts_global_cmd", "Command", "thirdpersonshoulder", 0.0, tank, tank);
    }
}

// Protection to unlock the camera if the player dies with it active
::TS_DisableCameraDead <- function(tank) {
    if (!::TS_IsInThirdPerson) return;
    ::TS_IsInThirdPerson = false;
    local cmd = Entities.FindByName(null, "ts_global_cmd");
    if (!cmd) cmd = SpawnEntityFromTable("point_clientcommand", { targetname = "ts_global_cmd" });
    if (tank && tank.IsValid() && !IsPlayerABot(tank)) {
        DoEntFire("ts_global_cmd", "Command", "thirdpersonshoulder", 0.15, tank, tank);
    }
}

function OnGameEvent_player_death(params) {
    if ("userid" in params) {
        local killed = GetPlayerFromUserID(params.userid);
        if (killed && killed.IsValid() && killed.GetZombieType() == 8 && !IsPlayerABot(killed)) {
            ::TS_DisableCameraDead(killed);
        }
    }
}
function OnGameEvent_tank_killed(params) {
    if ("userid" in params) {
        local killed = GetPlayerFromUserID(params.userid);
        if (killed && killed.IsValid() && !IsPlayerABot(killed)) {
            ::TS_DisableCameraDead(killed);
        }
    }
}
function OnGameEvent_round_start(params) { ::TS_IsInThirdPerson = false; ::TS_ThirdPersonEndTime = 0.0; }
function OnGameEvent_map_transition(params) { ::TS_IsInThirdPerson = false; ::TS_ThirdPersonEndTime = 0.0; }
__CollectEventCallbacks(this, "OnGameEvent_", "GameEventCallbacks", RegisterScriptGameEventListener);

// === SUPPORT FUNCTIONS ===
::TS_GetValidGroundPos <- function(basePos, ignoreEnt) {
    local tr = { start = Vector(basePos.x, basePos.y, basePos.z + 100.0), end = Vector(basePos.x, basePos.y, basePos.z - 300.0), ignore = ignoreEnt };
    TraceLine(tr);
    if (tr.hit) return tr.pos;
    return null;
}

::TS_CheckSlamValidity <- function(tank, slamType, targetDir) {
    local flags = NetProps.GetPropInt(tank, "m_fFlags");
    if (!(flags & 1)) return false;
    local pos = tank.GetOrigin();
    local checkPos = pos + (targetDir * 100.0); checkPos.z = pos.z;
    local ground = ::TS_GetValidGroundPos(checkPos, tank);
    if (ground == null) return false;
    local zDiff = fabs(ground.z - pos.z);
    if (zDiff > 120.0) return false;
    return true;
}

::TS_IsTankThrowingRock <- function(tank) {
    try {
        local seq = NetProps.GetPropInt(tank, "m_nSequence");
        if (seq >= 48 && seq <= 51) return true;
        local seqName = tank.GetSequenceName(seq);
        if (seqName && seqName.tolower().find("throw") != null) return true;
    } catch(e) {}
    return false;
}

::TS_ApplyRockCooldownReduction <- function(tank) {
    if (!::TS_REDUCE_ROCK_COOLDOWN_ENABLE) return;
    try {
        local ability = NetProps.GetPropEntity(tank, "m_customAbility");
        if (ability && ability.IsValid() && ability.GetClassname() == "ability_throw") {
            local timestamp = NetProps.GetPropFloat(ability, "m_timestamp");
            local timeNow = Time();
            if (timestamp > timeNow) {
                local remaining = timestamp - timeNow;
                local newRemaining = remaining * (1.0 - (::TS_REDUCE_ROCK_COOLDOWN_PCT / 100.0));
                NetProps.SetPropFloat(ability, "m_timestamp", timeNow + newRemaining);
            }
        }
    } catch(e) {}
}

::TS_GetClosestSurvivor <- function(tank) {
    local closest = null; local minDist = 999999.0; local pos = tank.GetOrigin(); local p = null;
    while (p = Entities.FindByClassname(p, "player")) {
        if (p.IsValid() && p.IsSurvivor() && p.GetHealth() > 0 && NetProps.GetPropInt(p, "m_lifeState") == 0 && NetProps.GetPropInt(p, "m_isIncapacitated") == 0) {
            local dist = (p.GetOrigin() - pos).Length();
            if (dist < minDist) {
                local trace = { start = pos + Vector(0,0,60), end = p.GetOrigin() + Vector(0,0,60), ignore = tank };
                TraceLine(trace);
                if (trace.fraction > 0.85 || trace.enthit == p) { minDist = dist; closest = p; }
            }
        }
    }
    return { ent = closest, dist = minDist };
}

// ANTI-OVERFLOW FIX: Kills the invisible physics entity in 0.1s instead of 2.0s
::TS_CreateImpactExplosion <- function(pos, mag = "200", tickDelay = 0.0) {
    local surface_exp = SpawnEntityFromTable("env_explosion", { iMagnitude = mag, iRadiusOverride = "350", spawnflags = "6013", origin = pos + Vector(0, 0, 5) });
    if (surface_exp) {
        DoEntFire("!self", "Explode", "", tickDelay, surface_exp, surface_exp);
        DoEntFire("!self", "Kill", "", tickDelay + 0.1, surface_exp, surface_exp); // Fixed to prevent Overflow
    }
}

// === BASE IMPACT (DAMAGE AND EFFECTS) ===
::TS_ApplyImpact <- function(tank, pos, isSuperWave = false, microDelay = 0.0) {
    local rad = ::TS_RADIUS_PER_IMPACT;
    local z_tolerance = 45.0;
    local m_fabs = fabs;
    local timeNow = Time();

    local dmgSurv = isSuperWave ? ::TS_SUPER_DMG_SURVIVORS : ::TS_DMG_SURVIVORS;
    local dmgSI = isSuperWave ? ::TS_SUPER_DMG_SI : ::TS_DMG_SI;
    local dmgCommons = isSuperWave ? ::TS_SUPER_DMG_COMMONS : ::TS_DMG_COMMONS;

    local ground_pound = SpawnEntityFromTable("info_particle_system", { effect_name = "tank_ground_pound", start_active = "1", origin = pos });
    if (ground_pound) {
        EmitSoundOn("physics/concrete/boulder_impact_hard1.wav", ground_pound);
        EmitSoundOn("physics/concrete/boulder_impact_hard2.wav", ground_pound);
        local pSnd = (RandomInt(0, 1) == 0) ? "player/tank/hit/pound_victim_1.wav" : "player/tank/hit/pound_victim_2.wav";
        EmitSoundOn(pSnd, ground_pound);
        DoEntFire("!self", "Kill", "", 1.0, ground_pound, ground_pound); // Changed to 1.0s
    }

    local impact = SpawnEntityFromTable("info_particle_system", { effect_name = "tank_rock_throw_impact", start_active = "1", origin = pos });
    if (impact) DoEntFire("!self", "Kill", "", 1.0, impact, impact); // Changed to 1.0s

    local mainExpMag = isSuperWave ? "150" : "600";
    ::TS_CreateImpactExplosion(pos, mainExpMag, microDelay);

    EmitSoundOn("physics/concrete/concrete_break2.wav", tank);
    EmitSoundOn("physics/concrete/concrete_break3.wav", tank);
    if (::TS_PLAY_EXPLOSION_SOUNDS) EmitSoundOn("weapons/hegrenade/explode3.wav", tank);

    // ANTI-GUN-GLITCH FIX: ScreenShake cooldown. Prevents client prediction break on 60/100 tick servers.
    if (timeNow - ::TS_LastGlobalShake > 0.3) {
        ScreenShake(pos, 15.0, 50.0, 1.5, rad * 2, 0, false);
        ::TS_LastGlobalShake = timeNow;
    }

    // ANTI-OVERFLOW FIX: env_physexplosion kills itself in 0.1s to free up memory instantly.
    local physexp = SpawnEntityFromTable("env_physexplosion", { magnitude = "1500", radius = rad.tostring(), spawnflags = "1", origin = pos });
    if (physexp) {
        DoEntFire("!self", "Explode", "", microDelay, physexp, physexp);
        DoEntFire("!self", "Kill", "", microDelay + 0.1, physexp, physexp);
    }

    // --- PLAYERS ---
    local p = null;
    while (p = Entities.FindByClassnameWithin(p, "player", pos, rad)) {
        if (p.IsValid() && p.GetHealth() > 0 && p != tank) {
            local zDiff = m_fabs(p.GetOrigin().z - pos.z);
            if (zDiff > z_tolerance) continue;

            if (::TS_DODGE_BY_JUMPING_ENABLE && !(NetProps.GetPropInt(p, "m_fFlags") & 1)) continue;

            local mult = 1.0;
            if (::TS_DISTANCE_DAMAGE_ENABLE && !isSuperWave) {
                local dist = (p.GetOrigin() - pos).Length(); if (dist > rad) dist = rad;
                mult = (::TS_DISTANCE_DAMAGE_MIN_PCT / 100.0) + ((1.0 - (::TS_DISTANCE_DAMAGE_MIN_PCT / 100.0)) * (1.0 - (dist / rad)));
            }

            // ANTI-GUN-GLITCH FIX: Only Stagger the player once every 1.2 seconds.
            p.ValidateScriptScope();
            local scope = p.GetScriptScope();
            if (!("TS_LastStagger" in scope)) scope.TS_LastStagger <- 0.0;
            if (timeNow - scope.TS_LastStagger > 1.2) {
                try { p.Stagger(pos); } catch(e) {}
                scope.TS_LastStagger = timeNow;
            }

            local team = NetProps.GetPropInt(p, "m_iTeamNum");
            if (team == 3) p.TakeDamage((dmgSI * mult).tointeger(), 128, tank);
            else if (team == 2) p.TakeDamage((dmgSurv * mult).tointeger(), 128, tank);
        }
    }

    // --- WITCHES & COMMONS ---
    local ent = null;
    while (ent = Entities.FindByClassnameWithin(ent, "witch", pos, rad)) {
        if (ent.IsValid() && ent.GetHealth() > 0) {
            if (m_fabs(ent.GetOrigin().z - pos.z) > z_tolerance) continue;
            if (::TS_DODGE_BY_JUMPING_ENABLE && !(NetProps.GetPropInt(ent, "m_fFlags") & 1)) continue;

            ent.ValidateScriptScope();
            local scope = ent.GetScriptScope();
            if (!("TS_LastStagger" in scope)) scope.TS_LastStagger <- 0.0;
            if (timeNow - scope.TS_LastStagger > 1.2) {
                try { ent.Stagger(pos); } catch(e) {}
                scope.TS_LastStagger = timeNow;
            }

            local mult = 1.0;
            if (::TS_DISTANCE_DAMAGE_ENABLE && !isSuperWave) {
                local dist = (ent.GetOrigin() - pos).Length(); if (dist > rad) dist = rad;
                mult = (::TS_DISTANCE_DAMAGE_MIN_PCT / 100.0) + ((1.0 - (::TS_DISTANCE_DAMAGE_MIN_PCT / 100.0)) * (1.0 - (dist / rad)));
            }
            ent.TakeDamage((dmgSI * mult).tointeger(), 128, tank);
        }
    }

    ent = null;
    while (ent = Entities.FindByClassnameWithin(ent, "infected", pos, rad)) {
        if (ent.IsValid() && ent.GetHealth() > 0) {
            if (m_fabs(ent.GetOrigin().z - pos.z) > z_tolerance) continue;
            if (::TS_DODGE_BY_JUMPING_ENABLE && !(NetProps.GetPropInt(ent, "m_fFlags") & 1)) continue;
            local mult = 1.0;
            if (::TS_DISTANCE_DAMAGE_ENABLE && !isSuperWave) {
                local dist = (ent.GetOrigin() - pos).Length(); if (dist > rad) dist = rad;
                mult = (::TS_DISTANCE_DAMAGE_MIN_PCT / 100.0) + ((1.0 - (::TS_DISTANCE_DAMAGE_MIN_PCT / 100.0)) * (1.0 - (dist / rad)));
            }
            local finalDmg = (dmgCommons * mult).tointeger();
            if (finalDmg >= ent.GetHealth()) {
                local dir = ent.GetOrigin() - pos; dir.Norm();
                ent.ApplyAbsVelocityImpulse(dir * 300 + Vector(0,0,350));
                ent.TakeDamage(finalDmg, 128, tank);
            } else {
                ent.TakeDamage(finalDmg, 33554432, tank);
            }
        }
    }
}

// === SUPER SLAM CONE ===
::TS_TriggerSuperSlamWave <- function(tankIdx, waveLevel, dirX, dirY, prevZ, useFillers = false) {
    local tank = EntIndexToHScript(tankIdx);
    if (!tank || !tank.IsValid() || tank.GetHealth() <= 0 || NetProps.GetPropInt(tank, "m_lifeState") != 0) return;
    if (waveLevel > ::TS_SUPER_WAVES_COUNT) return;

    local pos = tank.GetOrigin();
    local fwd = Vector(dirX, dirY, 0); fwd.Norm();
    local rightVec = Vector(fwd.y, -fwd.x, 0);

    local currentDist = 120.0 + (waveLevel * ::TS_SUPER_WAVES_DISTANCE);
    local basePos = pos + (fwd * currentDist);

    local impactsThisWave = 1 + waveLevel;
    local lateralSpacing = ::TS_SUPER_WAVES_DISTANCE * 0.85;
    local startOffset = -((impactsThisWave - 1) * lateralSpacing) / 2.0;

    // --- Fillers Logic (Controlled by TS_SUPER_SLAM_FILLERS_ENABLE) ---
    if (useFillers) {
        local midDist = currentDist - (::TS_SUPER_WAVES_DISTANCE * 0.5);
        local midBasePos = pos + (fwd * midDist);

        for (local j = 0; j < impactsThisWave; j++) {
            local offset = startOffset + (j * lateralSpacing);
            local midPos = midBasePos + (rightVec * offset); midPos.z = prevZ;
            local groundMid = ::TS_GetValidGroundPos(midPos, tank);
            if (groundMid) {
                groundMid.z -= 40.0;
                local filler = SpawnEntityFromTable("info_particle_system", { effect_name = "tank_rock_throw_impact", start_active = "1", origin = groundMid });
                if (filler) DoEntFire("!self", "Kill", "", 1.0, filler, filler); // Changed to 1.0s
            }
        }

        if (impactsThisWave > 1) {
            for (local k = 0; k < impactsThisWave - 1; k++) {
                local offset1 = startOffset + (k * lateralSpacing);
                local offset2 = startOffset + ((k + 1) * lateralSpacing);
                local midOffset = (offset1 + offset2) / 2.0;
                local latPos = basePos + (rightVec * midOffset); latPos.z = prevZ;
                local groundLat = ::TS_GetValidGroundPos(latPos, tank);
                if (groundLat) {
                    groundLat.z -= 40.0;
                    local latFiller = SpawnEntityFromTable("info_particle_system", { effect_name = "tank_rock_throw_impact", start_active = "1", origin = groundLat });
                    if (latFiller) DoEntFire("!self", "Kill", "", 1.0, latFiller, latFiller); // Changed to 1.0s
                }
            }
        }
    }

    local nextZ = prevZ; local validHits = 0; local sumZ = 0.0;

    // MAIN SUPER SLAM IMPACTS (Micro-Delayed to prevent Physics Stutter/Crash)
    for (local i = 0; i < impactsThisWave; i++) {
        local offset = startOffset + (i * lateralSpacing);
        local impactPos = basePos + (rightVec * offset); impactPos.z = prevZ;
        local groundImpact = ::TS_GetValidGroundPos(impactPos, tank);

        if (groundImpact) {
            local horizontalMicroDelay = i * 0.03;
            ::TS_ApplyImpact(tank, groundImpact, true, horizontalMicroDelay);
            sumZ += groundImpact.z; validHits++;
        }
    }
    if (validHits > 0) nextZ = sumZ / validHits;

    if (waveLevel < ::TS_SUPER_WAVES_COUNT) {
        if (::TS_SUPER_WAVE_DELAY <= 0.0) {
            ::TS_TriggerSuperSlamWave(tankIdx, waveLevel + 1, dirX, dirY, nextZ, useFillers);
        } else {
            local strFillers = useFillers ? "true" : "false";
            DoEntFire("worldspawn", "RunScriptCode", "::TS_TriggerSuperSlamWave(" + tankIdx + ", " + (waveLevel + 1) + ", " + dirX + ", " + dirY + ", " + nextZ + ", " + strFillers + ")", ::TS_SUPER_WAVE_DELAY, null, null);
        }
    }
}

// === FALL EARTHQUAKE (FALL SLAM) ===
::TS_ApplyFallEarthquake <- function(tankIdx) {
    local tank = EntIndexToHScript(tankIdx);
    if (!tank || !tank.IsValid() || tank.GetHealth() <= 0 || NetProps.GetPropInt(tank, "m_lifeState") != 0) return;
    local pos = tank.GetOrigin();
    local baseGround = ::TS_GetValidGroundPos(pos, tank);
    if (baseGround) pos = baseGround;

    ::TS_ApplyImpact(tank, pos, false, 0.0);
    ::TS_ApplyRockCooldownReduction(tank);

    local end_dis = 180; local start_dis = 60; local d_dist = (end_dis - start_dis) / 3.0;
    local PI2 = 6.28318;
    local ang_del = PI2 / 6.0;
    local ang_rotate = 0.0;

    local m_cos = cos;
    local m_sin = sin;

    // Visual rocks bursting out during the Fall Slam
    for (local dist = start_dis; dist <= end_dis; dist += d_dist) {
        for (local dir = 0.0; dir < PI2; dir += ang_del) {
            local dirVec = Vector(m_cos(dir + ang_rotate), m_sin(dir + ang_rotate), 0);
            local originMod = pos + (dirVec * dist); originMod.z = pos.z;
            local groundPos = ::TS_GetValidGroundPos(originMod, tank);
            if (groundPos) {
                groundPos.z -= 20.0;
                local impact = SpawnEntityFromTable("info_particle_system", { effect_name = "tank_rock_throw_impact", start_active = "1", origin = groundPos });
                if (impact) {
                    local rSnd = (RandomInt(0, 1) == 0) ? "physics/concrete/boulder_impact_hard1.wav" : "physics/concrete/boulder_impact_hard2.wav";
                    local pSnd = (RandomInt(0, 1) == 0) ? "player/tank/hit/pound_victim_1.wav" : "player/tank/hit/pound_victim_2.wav";
                    EmitSoundOn(rSnd, impact); EmitSoundOn(pSnd, impact);
                    if (::TS_PLAY_EXPLOSION_SOUNDS) EmitSoundOn("weapons/hegrenade/explode3.wav", impact);
                    EmitSoundOn("physics/concrete/concrete_break3.wav", impact);
                    DoEntFire("!self", "Kill", "", 1.0, impact, impact); // Changed to 1.0s
                }
            }
        }
        ang_rotate += 0.2;
    }

    // 6-Way Explosion Ring (Micro-Delayed and Optimized to kill in 0.1s to prevent Overflow)
    local ringStep = 0;
    for (local dir = 0.0; dir < PI2; dir += ang_del) {
        local dirVec = Vector(m_cos(dir), m_sin(dir), 0);
        local pushPos = pos + (dirVec * 100.0);
        pushPos.z = pos.z;
        local pushGround = ::TS_GetValidGroundPos(pushPos, tank);

        local finalPos = pushGround ? pushGround : pushPos;
        ::TS_CreateImpactExplosion(finalPos, "250", ringStep * 0.02);
        ringStep++;
    }
}

// === SLAM EXECUTION (PREPARE & ANIMATION) ===
::TS_PrepareSlam <- function(tankIdx, slamType, dirX, dirY) {
    local tank = EntIndexToHScript(tankIdx);
    if (!tank || !tank.IsValid() || tank.GetHealth() <= 0 || NetProps.GetPropInt(tank, "m_lifeState") != 0) return;

    if (::TS_ALLOW_SLAM_WHILE_STAGGERED) {
        try { NetProps.SetPropFloat(tank, "m_staggerTimer.m_timestamp", -1.0); } catch(e){}
    }

    if (slamType == "SUPER") {
        local rng_yell = (RandomInt(0, 1) == 0) ? "player/tank/voice/yell/tank_yell_03.wav" : "player/tank/voice/yell/tank_yell_04.wav";
        EmitSoundOn(rng_yell, tank);
    } else {
        EmitSoundOn("player/tank/voice/yell/tank_yell_12.wav", tank);
    }

    local delay = ::TS_PREPARE_DELAY_ENABLE ? ::TS_PREPARE_DELAY_TIME : 0.0;

    if (!IsPlayerABot(tank)) {
        if (::TS_THIRD_PERSON_ENABLE) {
            local camDuration = (slamType == "SUPER") ? 3.0 : 2.0;
            ::TS_ForceThirdPerson(tank, camDuration + delay);
        }
    }

    if (delay > 0.0) {
        DoEntFire("worldspawn", "RunScriptCode", "::TS_ExecuteSlam(" + tankIdx + ", \"" + slamType + "\", " + dirX + ", " + dirY + ")", delay, null, null);
    } else {
        ::TS_ExecuteSlam(tankIdx, slamType, dirX, dirY);
    }
}

::TS_ExecuteSlam <- function(tankIdx, slamType, dirX, dirY) {
    local tank = EntIndexToHScript(tankIdx);
    if (!tank || !tank.IsValid() || tank.GetHealth() <= 0 || NetProps.GetPropInt(tank, "m_lifeState") != 0) {
        if (tankIdx in ::TS_TankStates) ::TS_TankStates[tankIdx].isCasting = false;
        return;
    }

    if (::TS_ALLOW_SLAM_WHILE_STAGGERED) {
        try { NetProps.SetPropFloat(tank, "m_staggerTimer.m_timestamp", -1.0); } catch(e){}
    }

    NetProps.SetPropInt(tank, "m_MoveType", 0);
    tank.SetVelocity(Vector(0,0,0));

    local hitDelay = 0.72;
    local unfreezeDelay = 1.2;

    if (slamType == "SUPER") {
        local seqUp = tank.LookupSequence("Attack_Incap_03");
        if (seqUp == -1) seqUp = 45;
        NetProps.SetPropFloatArray(tank, "m_NetGestureStartTime", Time(), 5);
        NetProps.SetPropIntArray(tank, "m_NetGestureSequence", seqUp, 5);
        NetProps.SetPropIntArray(tank, "m_NetGestureActivity", 1, 5);
        hitDelay = 0.59; unfreezeDelay = 1.6;
    } else {
        local sequenceID = tank.LookupSequence("ACT_HULK_ATTACK_LOW");
        if (sequenceID == -1) sequenceID = 18;
        NetProps.SetPropFloatArray(tank, "m_NetGestureStartTime", Time(), 5);
        NetProps.SetPropIntArray(tank, "m_NetGestureSequence", sequenceID, 5);
        NetProps.SetPropIntArray(tank, "m_NetGestureActivity", 1, 5);
    }

    DoEntFire("worldspawn", "RunScriptCode", "::TS_ProcessSlamHit(" + tankIdx + ", \"" + slamType + "\", " + dirX + ", " + dirY + ")", hitDelay, null, null);
    DoEntFire("worldspawn", "RunScriptCode", "try { local t = EntIndexToHScript(" + tankIdx + "); if(t && t.IsValid() && NetProps.GetPropInt(t, \"m_lifeState\") == 0) NetProps.SetPropInt(t, \"m_MoveType\", 2); } catch(e){}", unfreezeDelay, null, null);
}

::TS_ProcessSlamHit <- function(tankIdx, slamType, dirX, dirY) {
    local tank = EntIndexToHScript(tankIdx);
    if (!tank || !tank.IsValid() || tank.GetHealth() <= 0 || NetProps.GetPropInt(tank, "m_lifeState") != 0) return;
    local pos = tank.GetOrigin();

    local PI2 = 6.28318;
    local m_cos = cos;
    local m_sin = sin;

    if (tankIdx in ::TS_TankStates) {
        ::TS_TankStates[tankIdx].isCasting = false;
        ::TS_TankStates[tankIdx].chosenType = null;
        ::TS_TankStates[tankIdx].chosenTime = 0.0;
    }

    if (slamType == "NORMAL") {
        local fwd = tank.EyeAngles().Forward(); fwd.z = 0; fwd.Norm();
        local sismicOrigin = pos + (fwd * 50.0); sismicOrigin.z = pos.z;
        local sGround = ::TS_GetValidGroundPos(sismicOrigin, tank);
        if (sGround) sismicOrigin = sGround;

        ::TS_ApplyImpact(tank, sismicOrigin, false, 0.0);

        local end_dis = 180; local start_dis = 60; local d_dist = (end_dis - start_dis) / 3.0;
        local ang_del = PI2 / 6.0;
        local ang_rotate = 0.0;

        for (local dist = start_dis; dist <= end_dis; dist += d_dist) {
            for (local dir = 0.0; dir < PI2; dir += ang_del) {
                local dirVec = Vector(m_cos(dir + ang_rotate), m_sin(dir + ang_rotate), 0);
                local originMod = sismicOrigin + (dirVec * dist); originMod.z = sismicOrigin.z;
                local groundPos = ::TS_GetValidGroundPos(originMod, tank);
                if (groundPos) {
                    groundPos.z -= 20.0;
                    local impact = SpawnEntityFromTable("info_particle_system", { effect_name = "tank_rock_throw_impact", start_active = "1", origin = groundPos });
                    if (impact) {
                        local rSnd = (RandomInt(0, 1) == 0) ? "physics/concrete/boulder_impact_hard1.wav" : "physics/concrete/boulder_impact_hard2.wav";
                        local pSnd = (RandomInt(0, 1) == 0) ? "player/tank/hit/pound_victim_1.wav" : "player/tank/hit/pound_victim_2.wav";
                        EmitSoundOn(rSnd, impact); EmitSoundOn(pSnd, impact);
                        if (::TS_PLAY_EXPLOSION_SOUNDS) EmitSoundOn("weapons/hegrenade/explode3.wav", impact);
                        EmitSoundOn("physics/concrete/concrete_break3.wav", impact);
                        DoEntFire("!self", "Kill", "", 1.0, impact, impact); // Changed to 1.0s
                    }
                }
            }
            ang_rotate += 0.2;
        }

        // 6-Way Explosion Ring Restored - Optimized to kill in 0.1s
        local ringStep = 0;
        for (local dir = 0.0; dir < PI2; dir += ang_del) {
            local dirVec = Vector(m_cos(dir), m_sin(dir), 0);
            local pushPos = sismicOrigin + (dirVec * 100.0);
            pushPos.z = sismicOrigin.z;
            local pushGround = ::TS_GetValidGroundPos(pushPos, tank);

            local finalPos = pushGround ? pushGround : pushPos;
            ::TS_CreateImpactExplosion(finalPos, "250", ringStep * 0.02);
            ringStep++;
        }

    } else if (slamType == "SUPER") {
        if (::TS_SUPER_SLAM_360_ENABLE) {
            local fGround = ::TS_GetValidGroundPos(pos, tank);
            if (fGround) pos = fGround;

            ::TS_ApplyImpact(tank, pos, false, 0.0);

            local ang_del = PI2 / 8.0;
            for (local i = 0; i < 8; i++) {
                local dir = i * ang_del;
                local dX = m_cos(dir);
                local dY = m_sin(dir);

                local waveMicroDelay = i * 0.02;
                local delay = (::TS_SUPER_WAVE_DELAY <= 0.0) ? waveMicroDelay : (0.2 + waveMicroDelay);

                // Always disable fillers in 360 mode to prevent instant entity overflow
                DoEntFire("worldspawn", "RunScriptCode", "::TS_TriggerSuperSlamWave(" + tankIdx + ", 1, " + dX + ", " + dY + ", " + pos.z + ", false)", delay, null, null);
            }
        } else {
            local baseDir = Vector(dirX, dirY, 0); baseDir.Norm();
            local firstPos = pos + (baseDir * 50.0); firstPos.z = pos.z;

            local fGround = ::TS_GetValidGroundPos(firstPos, tank);
            if (fGround) firstPos = fGround;

            ::TS_ApplyImpact(tank, firstPos, false, 0.0);

            // Pass the user setting TS_SUPER_SLAM_FILLERS_ENABLE to control filler rocks
            local useFillers = ::TS_SUPER_SLAM_FILLERS_ENABLE;
            local strFillers = useFillers ? "true" : "false";

            if (::TS_SUPER_WAVE_DELAY <= 0.0) ::TS_TriggerSuperSlamWave(tankIdx, 1, dirX, dirY, firstPos.z, useFillers);
            else DoEntFire("worldspawn", "RunScriptCode", "::TS_TriggerSuperSlamWave(" + tankIdx + ", 1, " + dirX + ", " + dirY + ", " + firstPos.z + ", " + strFillers + ")", 0.2, null, null);
        }
    }
}

// === AI BRAIN & PLAYER KEY READER ===
::TS_MonitorAllTanks <- function() {
    local timeNow = Time();
    local p = null;

    while (p = Entities.FindByClassname(p, "player")) {

        if (p.IsValid() && NetProps.GetPropInt(p, "m_zombieClass") == 8 && p.GetHealth() > 0 && NetProps.GetPropInt(p, "m_lifeState") == 0) {
            if (("tank_boss" in getroottable()) && p == ::tank_boss) continue;

            if (!::TS_ALLOW_CUSTOM_MODELS) {
                local mdl = p.GetModelName();
                if (mdl) {
                    mdl = mdl.tolower();
                    if (mdl != "models/infected/hulk.mdl" && mdl != "models/infected/hulk_dlc3.mdl" && mdl != "models/infected/hulk_l4d1.mdl") continue;
                }
            }

            local idx = p.GetEntityIndex();
            local isBot = IsPlayerABot(p);

            if (!(idx in ::TS_TankStates)) {
                ::TS_TankStates[idx] <- { lastTime = Time() - ::TS_COOLDOWN + 3.0, isCasting = false, chosenType = null, chosenTime = 0.0, wasFalling = false, maxFallSpeed = 0.0 };
            }

            local state = ::TS_TankStates[idx];
            local flags = NetProps.GetPropInt(p, "m_fFlags");
            local velZ = p.GetVelocity().z;

            if (!(flags & 1)) {
                state.wasFalling = true;
                if (velZ < state.maxFallSpeed) state.maxFallSpeed = velZ;
            } else {
                if (state.wasFalling) {
                    if (state.maxFallSpeed <= -::TS_FALL_SPEED_THRESHOLD && ::TS_FALL_SLAM_ENABLE) ::TS_ApplyFallEarthquake(idx);
                    state.wasFalling = false; state.maxFallSpeed = 0.0;
                }
            }

            if (state.isCasting || NetProps.GetPropInt(p, "m_isIncapacitated") == 1) continue;

            local isStaggered = false;
            try { if (NetProps.GetPropFloat(p, "m_staggerTimer.m_timestamp") > timeNow) isStaggered = true; } catch(e){}

            // Block if staggered and config doesn't allow it
            if (isStaggered && !::TS_ALLOW_SLAM_WHILE_STAGGERED) continue;

            // PLAYERS
            if (!isBot && ::TS_PLAYER_SLAM_ENABLE) {
                local reqBtn = 8192; // Default to R (Reload)
                if (::TS_PLAYER_SLAM_KEY == "E") reqBtn = 32; // IN_USE

                local buttons = NetProps.GetPropInt(p, "m_nButtons");
                if (buttons & reqBtn) {
                    if (timeNow - state.lastTime >= ::TS_COOLDOWN) {
                        if (!(::TS_BLOCK_SLAM_DURING_ROCK_THROW && ::TS_IsTankThrowingRock(p))) {

                            local slamType = "NORMAL";
                            if (::TS_PLAYER_MANUAL_SUPER_SLAM) {
                                // Checking if player is crouching (IN_DUCK = 4) to execute Super Slam
                                slamType = (buttons & 4) ? "SUPER" : "NORMAL";
                            } else {
                                // Classic random chance
                                slamType = (RandomInt(1, 100) <= ::TS_SUPER_SLAM_CHANCE) ? "SUPER" : "NORMAL";
                            }

                            local targetDir = p.EyeAngles().Forward(); targetDir.z = 0; targetDir.Norm();

                            if (::TS_CheckSlamValidity(p, slamType, targetDir)) {
                                state.lastTime = timeNow; state.isCasting = true;
                                ::TS_PrepareSlam(idx, slamType, targetDir.x, targetDir.y);
                                ::TS_ApplyRockCooldownReduction(p);
                            } else {
                                if (::TS_SHOW_INVALID_TERRAIN_MSG) {
                                    try { ClientPrint(p, 3, "\x04[Tank Slam]\x01 Invalid Terrain!"); } catch(e) {}
                                }
                            }
                        }
                    }
                }
            }

            // BOT AI
            if (isBot && ::TS_BOT_SLAM_ENABLE) {
                if (timeNow - state.lastTime >= ::TS_COOLDOWN) {
                    if (!(::TS_BLOCK_SLAM_DURING_ROCK_THROW && ::TS_IsTankThrowingRock(p))) {
                        local targetInfo = ::TS_GetClosestSurvivor(p);

                        if (targetInfo.ent != null) {
                            local targetDir = targetInfo.ent.GetOrigin() - p.GetOrigin(); targetDir.z = 0; targetDir.Norm();

                            if (state.chosenType == null) {
                                if (RandomInt(1, 100) <= ::TS_SUPER_SLAM_CHANCE) state.chosenType = "SUPER"; else state.chosenType = "NORMAL";
                                state.chosenTime = timeNow;
                            }

                            if (::TS_SMART_SLAM_SWITCH_ENABLE && state.chosenType == "SUPER" && (timeNow - state.chosenTime >= 10.0)) {
                                local survsNear = 0; local pNear = null; local pos = p.GetOrigin();
                                while (pNear = Entities.FindByClassnameWithin(pNear, "player", pos, ::TS_NORMAL_SLAM_RANGE)) {
                                    if (pNear.IsValid() && pNear.IsSurvivor() && pNear.GetHealth() > 0 && NetProps.GetPropInt(pNear, "m_lifeState") == 0 && NetProps.GetPropInt(pNear, "m_isIncapacitated") == 0) {
                                        local tr = { start = pos + Vector(0,0,60), end = pNear.GetOrigin() + Vector(0,0,60), ignore = p };
                                        TraceLine(tr);
                                        if (tr.fraction > 0.85 || tr.enthit == pNear) survsNear++;
                                    }
                                }
                                if (survsNear >= 2) state.chosenType = "NORMAL";
                            }

                            local canCast = false;
                            if (state.chosenType == "NORMAL") { if (targetInfo.dist <= ::TS_NORMAL_SLAM_RANGE) canCast = true; }
                            else if (state.chosenType == "SUPER") { if (targetInfo.dist >= ::TS_SUPER_SLAM_MIN_RANGE && targetInfo.dist <= ::TS_SUPER_SLAM_MAX_RANGE) canCast = true; }

                            if (canCast) {
                                if (::TS_CheckSlamValidity(p, state.chosenType, targetDir)) {
                                    state.isCasting = true; state.lastTime = timeNow;
                                    ::TS_PrepareSlam(idx, state.chosenType, targetDir.x, targetDir.y);
                                    ::TS_ApplyRockCooldownReduction(p);
                                } else {
                                    if (timeNow - state.chosenTime > 3.0) state.chosenType = null;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    DoEntFire("worldspawn", "RunScriptCode", "::TS_MonitorAllTanks()", 0.1, null, null);
}

DoEntFire("worldspawn", "RunScriptCode", "::TS_MonitorAllTanks()", 2.0, null, null);
