Promoveaza serverul
csb-bad-spawn-preventer / addons / amxmodx / scripting / csb_bad_spawn_preventer.sma
108 lines 2.8 KiB Pawn Raw Permalink History
/*
 * CSB Bad Spawn Fixer
 * Copyright (C) 2026 counter-strike-boost.com
 *
 * Prevents spawning inside another player. On spawn the plugin runs a human-hull
 * trace at the spawn origin; if it is solid (a body is already there) it nudges
 * the player up and then outward in a ring of directions until a free spot is
 * found, avoiding the classic deathmatch spawn-stuck and telefrag problem.
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version. It is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See <https://www.gnu.org/licenses/> for details.
 */

#include <amxmodx>
#include <fakemeta>
#include <hamsandwich>

new const PLUGIN[] = "CSB Bad Spawn Fixer"
new const VERSION[] = "1.0.0"
new const AUTHOR[]  = "counter-strike-boost.com"

#define HULL_HUMAN 1

new g_pEnabled

public plugin_init()
{
    register_plugin(PLUGIN, VERSION, AUTHOR)

    g_pEnabled = register_cvar("csb_badspawn_enabled", "1")

    RegisterHam(Ham_Spawn, "player", "fwSpawnPost", 1)
}

public fwSpawnPost(id)
{
    if (!get_pcvar_num(g_pEnabled) || !is_user_alive(id))
        return

    static Float:origin[3]
    pev(id, pev_origin, origin)

    if (!isStuck(id, origin))
        return

    static Float:test[3]

    /* first try lifting straight up in small steps */
    for (new z = 8; z <= 40; z += 8)
    {
        test[0] = origin[0]
        test[1] = origin[1]
        test[2] = origin[2] + float(z)

        if (!isStuck(id, test))
        {
            moveTo(id, test)
            return
        }
    }

    /* then a ring of directions at growing radius */
    new const dirs = 8

    for (new r = 32; r <= 96; r += 32)
    {
        for (new d = 0; d < dirs; d++)
        {
            new Float:ang = float(d) * (360.0 / float(dirs))
            new Float:rad = ang * 3.14159265 / 180.0

            test[0] = origin[0] + floatcos(rad, radian) * float(r)
            test[1] = origin[1] + floatsin(rad, radian) * float(r)
            test[2] = origin[2] + 16.0

            if (!isStuck(id, test))
            {
                moveTo(id, test)
                return
            }
        }
    }
}

bool:isStuck(id, const Float:pos[3])
{
    engfunc(EngFunc_TraceHull, pos, pos, 0, HULL_HUMAN, id, 0)

    new startsolid = get_tr2(0, TR_StartSolid)
    new allsolid = get_tr2(0, TR_AllSolid)

    return (startsolid != 0 || allsolid != 0)
}

moveTo(id, const Float:pos[3])
{
    engfunc(EngFunc_SetOrigin, id, pos)

    static Float:zero[3]
    zero[0] = 0.0
    zero[1] = 0.0
    zero[2] = 0.0
    set_pev(id, pev_velocity, zero)
}