Иконка ресурса

Autospawnpoints 1.0.2

Нет прав для скачивания

iPlague

♿️
Сообщения
230
Реакции
130
Помог
2 раз(а)
iPlague добавил(а) новый ресурс:

Autospawnpoints - Плагин позволяет автоматически расставлять спавны.

Данный плагин позволяет в автоматическом режиме добавлять на карту новые спавны, если текущего количества спавнов недостаточно. По умолчанию создаётся по 24 спавна за каждую команду (#define MAX_SPAWNS 24)
Проверить созданные спавны можно командой asp_status в консоль сервера:
Посмотреть вложение 29679
Выводится информация о количестве энтити info_player_start, info_player_deathmatch, а так же переменные...
Узнать больше об этом ресурсе...
 
Сообщения
673
Реакции
242
Помог
11 раз(а)
Предложение:
1) ручная команда (менюшка) для удаление ненужных спавнов
2) сохранение спавнов после смены карты, думаю нет необходимости каждый раз проходит по циклам и создавать спавны
 

iPlague

♿️
Сообщения
230
Реакции
130
Помог
2 раз(а)
PaTrIoT, я сам себе поставил. хотя у меня на сервере онлайн и небольшой сейчас, но в спектрах наблюдал как люди спавнятся на созданных спавнах.
 
Сообщения
147
Реакции
29
Seems to work okay (but i need more players for 100% test)

Thank for the plugin, but is there a specific reason to put register_srvcmd( "asp_check" ) than to do as admins only register_clcmd ?
Im not sure how opening server console is more convinient than writing as you are playing on the server :D
 

iPlague

♿️
Сообщения
230
Реакции
130
Помог
2 раз(а)
jocasrb,
but is there a specific reason to put register_srvcmd( "asp_check" ) than to do as admins only register_clcmd ?
Im not sure how opening server console is more convinient than writing as you are playing on the server :D
cuz of i check plugin without entering the game :) u may delete this cmd or make it client_cmd
or i will do it in few days, when'll take some free time.
18 Ноя 2021
but i need more players for 100% test
i tested it with 30 bots (yapb)
 
Сообщения
102
Реакции
16
Limbooc,
Предложение:
1) ручная команда (менюшка) для удаление ненужных спавнов
2) сохранение спавнов после смены карты, думаю нет необходимости каждый раз проходит по циклам и создавать спавны
Согласен, лишний раз гонять плагин на тех картах, где спавны уже были сделаны, такое себе. Лишняя нагрузка, вот если бы плагин ставить на паузу
 
Последнее редактирование:

iPlague

♿️
Сообщения
230
Реакции
130
Помог
2 раз(а)
загружать координаты с файла, удалять и пересоздавать заново энтити будет такая же "нагрузка".
 
Сообщения
31
Реакции
6
Добрый день! На карте de_santorini за теров создает спавны за забором.
 

iPlague

♿️
Сообщения
230
Реакции
130
Помог
2 раз(а)
geJIa, спасибо.
до этого использовал проверку на видимость от точки к точке, потом отключил её, так как не нашёл карт, где создавались бы спавны вне игровой зоны.

Добавлю эту проверку обратно и квар на ее включение.

Если что, она есть этой теме
Код:
// 6th check if start entity isn't in sight
    engfunc(EngFunc_TraceLine, foldorigin, forigin, 0, iEnt, 0);
    new Float:fraction;    get_tr2(0, TR_flFraction, fraction);
    if(fraction != 1.0)
        return false;
 

iPlague

♿️
Сообщения
230
Реакции
130
Помог
2 раз(а)
geJIa,

С включённой проверкой на видимость за забором курочек не оказалось.
1637582822492.png
С отключённой проверкой на видимость за забором обнаружил 2 курочки.
1637583883982.png
Переделал плагин:
добавил квар "проверка видимости" asp_check_visibility "1"
добавил команду "check" и "uncheck" для проверки созданных спавнов.

Чуть позже обновлю ресурс, пока что сюда выложу.
Код:
#include <amxmodx>
#include <reapi>
#include <engine>
#include <fakemeta>

#define TT_MDL        "models/player/leet/leet.mdl"
#define CT_MDL        "models/player/gign/gign.mdl"
new g_iModeltt, g_iModelct;

public plugin_precache(){
    g_iModeltt = precache_model(TT_MDL);
    g_iModelct = precache_model(CT_MDL);
}

enum Cvars{
    CVAR_ASP_TT_SPAWNS,                    // необходимое количество спавнов ТТ
    CVAR_ASP_CT_SPAWNS,                    // необходимое количество спавнов ТТ
    Float:CVAR_ASP_CHECK_HEIGHT,        // максимальная высота спавна над поверхностью
    Float:CVAR_ASP_CHECK_RADIUS,        // радиус проверки
    Float:CVAR_ASP_SEARCH_RADIUS,        // радиус поиска
    CVAR_ASP_REPAIR,                    // удалять плохие спавны?
    CVAR_ASP_DEBUG_INFO,                // включить доп инфо?
    CVAR_ASP_CHECK_VISIBILITY            // проверять точки на видимость
}

new g_eCvar[Cvars];                     // Квары
new Array:g_TTSpawn;                    // info_player_deathmatch entities ID
new Array:g_CTSpawn;                    // info_player_start entities ID
new g_iLastSpawnId[3];                    // ID последнего занятого спавна (спасибо fl0wer)

new const Float:pointXY[8][2] = {{0.0, -1.0},     
                                {1.0, -1.0},     
                                {1.0, 0.0},       
                                {1.0, 1.0},     
                                {0.0, 1.0},
                                {-1.0, 1.0},
                                {0.0, -1.0},
                                {-1.0, -1.0}};
new const Float:pointZ[] = {0.0, -48.0, -36.0, -18.0, 18.0, 36.0, 48.0};                           

public plugin_init(){
    register_plugin("ASP", "1.0.3", "iPlague");

    CreateCvars();
    AutoExecConfig(true, "asp");

    g_TTSpawn = ArrayCreate(1, 0);
    g_CTSpawn = ArrayCreate(1, 0);

    register_clcmd("asp_status", "show_asp_status");
    RegisterHookChain(RG_CSGameRules_GetPlayerSpawnSpot, "@CSGameRules_GetPlayerSpawnSpot_Pre", false); // prevent spawning if place isn't vacant
    RegisterHookChain(RG_CSGameRules_RestartRound, "@CSGameRules_RestartRound_Post", true); // reset iSpawnPointCount

    register_clcmd("check", "set_points");
    register_clcmd("uncheck", "clear_points");
    
    get_spawns_num();
}

public clear_points(id){
    new SpawnEnt = NULLENT;
    while ((SpawnEnt = rg_find_ent_by_class(SpawnEnt, "sexy_chick")) != 0)
        set_entvar(SpawnEnt, var_flags, FL_KILLME);
    return PLUGIN_HANDLED;
}

public set_points(id){
    for(new i = 0; i < ArraySize(g_TTSpawn); i++){
        new chick = rg_create_entity("info_target", false);
        
        new iSpawn = ArrayGetCell(g_TTSpawn, i);
        new Float:fOrigin[3]; get_entvar(iSpawn, var_origin, fOrigin);

        set_entvar(chick, var_model, TT_MDL);
        set_entvar(chick, var_modelindex, g_iModeltt);
        engfunc(EngFunc_SetOrigin, chick, fOrigin);
        set_entvar(chick, var_classname, "sexy_chick");
    }
    for(new i = 0; i < ArraySize(g_CTSpawn); i++){
        new chick = rg_create_entity("info_target", false);
        
        new iSpawn = ArrayGetCell(g_CTSpawn, i);
        new Float:fOrigin[3]; get_entvar(iSpawn, var_origin, fOrigin);

        set_entvar(chick, var_model, CT_MDL);
        set_entvar(chick, var_modelindex, g_iModelct);
        engfunc(EngFunc_SetOrigin, chick, fOrigin);
        set_entvar(chick, var_classname, "sexy_chick");
    }
    return PLUGIN_HANDLED;
}

public show_asp_status(id){
server_print("===============================================^n^nAUTO SPAWN POINTS^nENT NUM: %d | SPAWN POINTS NUM: %d^nENT NUM: %d | SPAWN POINTS NUM: %d^n===============================================^n^n",
ArraySize(g_TTSpawn),get_member_game(m_iSpawnPointCount_Terrorist), ArraySize(g_CTSpawn),get_member_game(m_iSpawnPointCount_CT));
client_print(id, print_console,"===============================================^n^nAUTO SPAWN POINTS^nENT NUM: %d | SPAWN POINTS NUM: %d^nENT NUM: %d | SPAWN POINTS NUM: %d^n===============================================^n^n", 
ArraySize(g_TTSpawn),get_member_game(m_iSpawnPointCount_Terrorist), ArraySize(g_CTSpawn),get_member_game(m_iSpawnPointCount_CT));
}

public get_spawns_num(){
    new SpawnEnt = NULLENT, Float:fOrigin[3];
    while ((SpawnEnt = rg_find_ent_by_class(SpawnEnt, "info_player_deathmatch")) != 0){
        if(g_eCvar[CVAR_ASP_REPAIR] == 1){
            get_entvar(SpawnEnt, var_origin, fOrigin);
            engfunc(EngFunc_TraceHull, fOrigin, fOrigin, 0, HULL_HUMAN, 0, 0);
            if(get_tr2(0, TR_StartSolid) || get_tr2(0, TR_AllSolid) || !get_tr2(0, TR_InOpen)){
                set_entvar(SpawnEnt, var_flags, FL_KILLME);
                continue;
            }
        }
        
        if(g_eCvar[CVAR_ASP_DEBUG_INFO] == 1)
            server_print("%d. TT ENTITY %d", ArraySize(g_TTSpawn), SpawnEnt);
        
        ArrayPushCell(g_TTSpawn, SpawnEnt);
    }

    SpawnEnt = NULLENT;
    while ((SpawnEnt = rg_find_ent_by_class(SpawnEnt, "info_player_start"))!= 0){
        if(g_eCvar[CVAR_ASP_REPAIR] == 1){
            get_entvar(SpawnEnt, var_origin, fOrigin);
            engfunc(EngFunc_TraceHull, fOrigin, fOrigin, 0, HULL_HUMAN, 0, 0);
            if(get_tr2(0, TR_StartSolid) || get_tr2(0, TR_AllSolid) || !get_tr2(0, TR_InOpen)){
                set_entvar(SpawnEnt, var_flags, FL_KILLME);
                continue;
            }
        }
        
        if(g_eCvar[CVAR_ASP_DEBUG_INFO] == 1)
            server_print("%d. TT ENTITY %d", ArraySize(g_CTSpawn), SpawnEnt);
        
        ArrayPushCell(g_CTSpawn, SpawnEnt);
    }

    if(g_eCvar[CVAR_ASP_DEBUG_INFO] == 1)
        server_print("= = = = = = = = = = =^nOLD RESULT: %d TTs AND %d CTs SPAWNS", ArraySize(g_TTSpawn), ArraySize(g_CTSpawn));

    make_new_spawns();
}

public make_new_spawns(){
    new iTTSpawnsNum = ArraySize(g_TTSpawn);
    new iCTSpawnsNum = ArraySize(g_CTSpawn);

    new iNeedTTSpawns = max(g_eCvar[CVAR_ASP_TT_SPAWNS] - iTTSpawnsNum, 0);
    new iNeedCTSpawns = max(g_eCvar[CVAR_ASP_CT_SPAWNS] - iCTSpawnsNum, 0);

    new iSpawn, Float:fOrigin[3], Float:fNewOrigin[3];
    
    if(g_eCvar[CVAR_ASP_DEBUG_INFO] == 1)
        server_print("NEED: %d TT^n= = = = = = = = =^nSTART SEARCH TT SPAWNS^n", iNeedTTSpawns);

    if(iNeedTTSpawns > 0){
        for(new i = 0; i < iTTSpawnsNum; i++){
            if(iNeedTTSpawns <= 0)
                break;
                
            iSpawn = ArrayGetCell(g_TTSpawn, i);
            get_entvar(iSpawn , var_origin, fOrigin);

            for(new j = 0; j < sizeof pointXY; j++){
                if(iNeedTTSpawns <= 0)
                    break;
                fNewOrigin[0] = (fOrigin[0] + g_eCvar[CVAR_ASP_SEARCH_RADIUS] * pointXY[j][0]);
                fNewOrigin[1] = (fOrigin[1] + g_eCvar[CVAR_ASP_SEARCH_RADIUS] * pointXY[j][1]);
                
                for( new z = 0; z < sizeof pointZ; z++){
                    if(iNeedTTSpawns <= 0)
                        break;
                    fNewOrigin[2] = (fOrigin[2] + pointZ[z]);
                    if(is_place_ok(iSpawn, fOrigin, fNewOrigin, g_eCvar[CVAR_ASP_CHECK_RADIUS])){
                        new iNewSpawn = rg_create_entity("info_player_deathmatch", true);
                        if(!is_nullent(iNewSpawn)){
                            engfunc(EngFunc_SetOrigin, iNewSpawn, fNewOrigin);
                            ArrayPushCell(g_TTSpawn, iNewSpawn);
                            if(g_eCvar[CVAR_ASP_DEBUG_INFO] == 1)
                                server_print("+++++++++++ADD SPAWN ENTITY %d (j %d)", iNewSpawn, j);
                            
                            iNeedTTSpawns--;
                            iTTSpawnsNum++;
                            if(z == 0)
                                break;
                        }
                    }
                }
            }
        }
    }
    if(g_eCvar[CVAR_ASP_DEBUG_INFO] == 1)
        server_print("NEED: %d CT^n= = = = = = = = =^nSTART SEARCH CT SPAWNS^n", iNeedCTSpawns);
    
    if(iNeedCTSpawns > 0){
        for(new i = 0; i < iCTSpawnsNum; i++){
            if(iNeedCTSpawns  <= 0)
                break;

            iSpawn = ArrayGetCell(g_CTSpawn, i);
            get_entvar(iSpawn , var_origin, fOrigin);

            for(new j = 0; j < sizeof pointXY; j++){
                if(iNeedCTSpawns <= 0)
                    break;
                fNewOrigin[0] = (fOrigin[0] + g_eCvar[CVAR_ASP_SEARCH_RADIUS] * pointXY[j][0]);
                fNewOrigin[1] = (fOrigin[1] + g_eCvar[CVAR_ASP_SEARCH_RADIUS] * pointXY[j][1]);
                
                for(new z = 0; z < sizeof pointZ; z++){
                    if(iNeedCTSpawns <= 0)
                        break;
                    fNewOrigin[2] = (fOrigin[2] + pointZ[z]);
                    
                    if(is_place_ok(iSpawn, fOrigin, fNewOrigin, g_eCvar[CVAR_ASP_CHECK_RADIUS])){
                        new iNewSpawn = rg_create_entity("info_player_start", true);
                        if(!is_nullent(iNewSpawn)){
                            engfunc(EngFunc_SetOrigin, iNewSpawn, fNewOrigin);
                            ArrayPushCell(g_CTSpawn, iNewSpawn);
                            if(g_eCvar[CVAR_ASP_DEBUG_INFO] == 1)
                                server_print("+++++++++++ADD SPAWN ENTITY %d (j %d)", iNewSpawn, j);
                            
                            iNeedCTSpawns--;
                            iCTSpawnsNum++;
                            if(z == 0)
                                break;
                        }
                    }
                }
            }
        }
    }
    if(g_eCvar[CVAR_ASP_DEBUG_INFO] == 1)
        server_print("NEW RESULT: %d TTs AND %d CTs SPAWNS", ArraySize(g_TTSpawn), ArraySize(g_CTSpawn));

    reset_spawns_num();
}

public reset_spawns_num(){
    if(ArraySize(g_TTSpawn))
        set_member_game(m_iSpawnPointCount_Terrorist, ArraySize(g_TTSpawn));
    
    if(ArraySize(g_CTSpawn))
        set_member_game(m_iSpawnPointCount_CT, ArraySize(g_CTSpawn));

    set_member_game(m_bLevelInitialized, true);
}


@CSGameRules_RestartRound_Post()
    reset_spawns_num();

@CSGameRules_GetPlayerSpawnSpot_Pre(id){
    new TeamName:team = get_member(id, m_iTeam);
    if (team != TEAM_TERRORIST && team != TEAM_CT)
        return HC_CONTINUE;

    new spot = EntSelectSpawnPoint(id, team);

    if (is_nullent(spot))
        return HC_CONTINUE;

    new Float:vecOrigin[3];    get_entvar(spot, var_origin, vecOrigin);
    new Float:vecAngles[3];    get_entvar(spot, var_angles, vecAngles);

    vecOrigin[2] += 1.0;

    set_entvar(id, var_origin, vecOrigin);
    set_entvar(id, var_v_angle, NULL_VECTOR);
    set_entvar(id, var_velocity, NULL_VECTOR);
    set_entvar(id, var_angles, vecAngles);
    set_entvar(id, var_punchangle, NULL_VECTOR);
    set_entvar(id, var_fixangle, 1);

    SetHookChainReturn(ATYPE_INTEGER, spot);
    return HC_SUPERCEDE;
}

EntSelectSpawnPoint(id, TeamName:team){
    new spotId = g_iLastSpawnId[_:team],spot,Float:vecOrigin[3];
    do{
        if (++spotId >= ArraySize(_:team == 1 ? g_TTSpawn : g_CTSpawn))
            spotId = 0;

        switch(team){
            case TEAM_TERRORIST: spot = ArrayGetCell(g_TTSpawn, spotId);
            case TEAM_CT: spot = ArrayGetCell(g_CTSpawn, spotId);
        }
        if (is_nullent(spot))
            continue;
        get_entvar(spot, var_origin, vecOrigin);
        if (!IsHullVacant(id, vecOrigin, HULL_HUMAN))
            continue;
        break;
    }
    while (spotId != g_iLastSpawnId[_:team]);
    if (is_nullent(spot))
        return 0;
    g_iLastSpawnId[_:team] = spotId;
    return spot;
}

CreateCvars(){
    bind_pcvar_num(create_cvar(
        "asp_tt_spawns", "24", FCVAR_SERVER,
        .description = "Необходимое количество спавнов ТТ.",
        .has_min = true, .min_val = 1.0,
        .has_max = true, .max_val = 128.0
    ),g_eCvar[CVAR_ASP_TT_SPAWNS]);

    bind_pcvar_num(create_cvar(
        "asp_ct_spawns", "24", FCVAR_SERVER,
        .description = "Необходимое количество спавнов СТ.",
        .has_min = true, .min_val = 1.0,
        .has_max = true, .max_val = 128.0
    ),g_eCvar[CVAR_ASP_CT_SPAWNS]);

    bind_pcvar_float(create_cvar(
        "asp_check_height", "64.0", FCVAR_SERVER,
        .description = "Максимальная высота над землёй, на которой может быть создан спавн.",
        .has_min = true, .min_val = 10.0,
        .has_max = true, .max_val = 128.0
    ),g_eCvar[CVAR_ASP_CHECK_HEIGHT]);

    bind_pcvar_float(create_cvar(
        "asp_check_radius", "72.0", FCVAR_SERVER,
        .description = "Радиус проверки на наличие существующих спавнов вокруг точки.",
        .has_min = true, .min_val = 48.0,
        .has_max = true, .max_val = 256.0
    ),g_eCvar[CVAR_ASP_CHECK_RADIUS]);

    bind_pcvar_float(create_cvar(
        "asp_search_radius", "96.0", FCVAR_SERVER,
        .description = "Рекомендованное расстояние между двумя спавнами.",
        .has_min = true, .min_val = 48.0,
        .has_max = true, .max_val = 256.0
    ),g_eCvar[CVAR_ASP_SEARCH_RADIUS]);

    bind_pcvar_num(create_cvar(
        "asp_repair", "1", FCVAR_SERVER,
        .description = "Удалить плохие спавны (игроки могут застрять) [0 - off / 1 - on]."
    ),g_eCvar[CVAR_ASP_REPAIR]);

    bind_pcvar_num(create_cvar(
        "asp_debug_info", "0", FCVAR_SERVER,
        .description = "Включить вывод информации в консоль сервера    [0 - off / 1 - on]."
    ),g_eCvar[CVAR_ASP_DEBUG_INFO]);
    
    bind_pcvar_num(create_cvar(
        "asp_check_visibility", "1", FCVAR_SERVER,
        .description = "Проверять точки на видимость [0 - off / 1 - on]."
    ),g_eCvar[CVAR_ASP_CHECK_VISIBILITY]);
}

//                        iSpawn        fOldOrigin        fNewOrigin        fSearchRadius
stock bool:is_place_ok(iEnt ,Float:foldorigin[3], Float:forigin[3],   Float:radius){
    // First check
    engfunc(EngFunc_TraceHull, forigin,  forigin, 0, HULL_HUMAN, 0, 0);
    if(get_tr2(0, TR_StartSolid) || get_tr2(0, TR_AllSolid) || !get_tr2(0, TR_InOpen)){
        return false;
    }
    // Second check    if any info_player_* or func_wall or other entities..
     new Ent = NULLENT;
    while((Ent = find_ent_in_sphere(Ent, forigin, radius)) != 0){
        new szClassname[32]; get_entvar(Ent, var_classname, szClassname, 31);
        if(    equal(szClassname, "func_buyzone") || equal(szClassname, "func_hostage_rescue") ||
            equal(szClassname, "env_sprite") || equal(szClassname, "armoury_entity") ||
            equal(szClassname, "func_water"))
            continue;
        return false;
    }
    // Third check    if this point is too high over ground (f.e. tt spawns on cs_assault)
    if(distance_to_ground(forigin) > g_eCvar[CVAR_ASP_CHECK_HEIGHT])
        return false;
    
    // 4th check if spawn out of map
    if(engfunc(EngFunc_PointContents , forigin) == CONTENTS_SOLID)
        return false;
    
    // 5th check if spawn out of map
    if(engfunc(EngFunc_PointContents , forigin) == CONTENTS_SKY)
        return false;

    // 6th check visibility
    if(g_eCvar[CVAR_ASP_CHECK_VISIBILITY] == 1){
        engfunc(EngFunc_TraceLine, foldorigin, forigin, 0, iEnt, 0);
        new Float:fraction;    get_tr2(0, TR_flFraction, fraction);
        if(fraction != 1.0)
            return false;
    }
    return true;   
}

stock Float:distance_to_ground(Float:start[3]){
    new Float:end[3];
 
    end[0] = start[0];
    end[1] = start[1];
    end[2] = start[2] - 9999.0;
    
    new ptr = create_tr2();
    engfunc(EngFunc_TraceHull, start, end, IGNORE_MONSTERS, HULL_HUMAN, 0, ptr);
    new Float:distance;
    get_tr2(ptr, TR_flFraction, distance);
    free_tr2(ptr);
    distance *= 9999.0;
    return distance;
}

bool:IsHullVacant(id, Float:vecOrigin[3], hull){
    engfunc(EngFunc_TraceHull, vecOrigin, vecOrigin, 0, hull, id, 0);
    if (get_tr2(0, TR_StartSolid) || get_tr2(0, TR_AllSolid) || !get_tr2(0, TR_InOpen))
        return false;
    return true;
}
 
  • Нравится
Реакции: ifx

Пользователи, просматривающие эту тему

Сейчас на форуме нет ни одного пользователя.
Сверху Снизу