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

DeathMatch Spawn Manager

Vaqtincha

aggressive
Разработчик
Скриптер
Регистрация
28 Янв 2018
Сообщения
963
Симпатии
685
Пол
Мужской
Vaqtincha добавил(а) новый ресурс:

DeathMatch Spawn Manager - Редактор спаунов для дезматч или других модов.

Входит в комплект моего ксдм мода но работает независимо от него (будет использован и для других модов, плагинов)

Полностью совместим со спаун файлами "CSDM Spawn Editor" от BAILOPAN'а (или KWo). Является более функциональном аналогом вышеуказанного плагина и работает без ксдм мода.

Поддерживает командный спаун (для Team Deathmatch). Плагин должен быт запущен всегда (включается когда нужно через...
Узнать больше об этом ресурсе...
 

Vaqtincha

aggressive
Разработчик
Скриптер
Регистрация
28 Янв 2018
Сообщения
963
Симпатии
685
Пол
Мужской

Nelpsen

Пользователь
Регистрация
9 Июл 2017
Сообщения
59
Симпатии
27
Пол
Мужской
Плохо знаю английский, нету возможности двигать там спавны влево вправо, вокруг себя?
 

Vaqtincha

aggressive
Разработчик
Скриптер
Регистрация
28 Янв 2018
Сообщения
963
Симпатии
685
Пол
Мужской
Nelpsen, Выбираешь спаун, смотришь туда куда надо и нажимаешь "Update position"
 

Nelpsen

Пользователь
Регистрация
9 Июл 2017
Сообщения
59
Симпатии
27
Пол
Мужской
Vaqtincha, ну это понятно, со стороны просто удобнее двигать все, особенно когда ты в душе немного с тараканми, и хочется все ровно =D
 

Vaqtincha

aggressive
Разработчик
Скриптер
Регистрация
28 Янв 2018
Сообщения
963
Симпатии
685
Пол
Мужской
Nelpsen, так нельзя. игроки застрянут
 

Izmayl7

Пользователь
Регистрация
9 Июн 2017
Сообщения
527
Симпатии
103
Пол
Мужской
Плохо знаю английский, нету возможности двигать там спавны влево вправо, вокруг себя?
C-like:
// Copyright © 2016/2020 Vaqtincha

const MAX_SPAWNS = 64
const Float:MIN_SPAWN_RADIUS = 500.0
new const CSDM_SPAWN_DIR[] = "csdm/spawns" // default: addons/amxmodx/configs/csdm/spawns


#define PL_VERSION     "0.1.4"

#include <amxmodx>
#include <fakemeta>
#include <reapi>


#if AMXX_VERSION_NUM < 183
    #include <colorchat>
#endif

#define IsVectorZero(%1)                 (%1[X] == 0.0 && %1[Y] == 0.0 && %1[Z] == 0.0)
#define IsPlayer(%1)                    (1 <= %1 <= g_iMaxPlayers)

#define Vector(%1,%2,%3)                (Float:{%1.0, %2.0, %3.0})
#define VECTOR_ZERO                     Vector(0, 0, 0)

#define FIND_ENT_IN_SPHERE(%1,%2,%3)     engfunc(EngFunc_FindEntityInSphere, %1, %2, %3)
#define REMOVE_ENTITY(%1)                 engfunc(EngFunc_RemoveEntity, %1)
#define SET_ORIGIN(%1,%2)                 engfunc(EngFunc_SetOrigin, %1, %2)
#define SET_SIZE(%1,%2,%3)                 engfunc(EngFunc_SetSize, %1, %2, %3)
#define SET_MODEL(%1,%2)                engfunc(EngFunc_SetModel, %1, %2)


const MENU_KEY_BITS = (MENU_KEY_1|MENU_KEY_2|MENU_KEY_3|MENU_KEY_4|MENU_KEY_5|MENU_KEY_6|MENU_KEY_7|MENU_KEY_9)

enum coord_e { Float:X, Float:Y, Float:Z }
enum { FAILED_CREATE, FILE_SAVED, FILE_DELETED }
enum { MODE_TEAMPLAY, MODE_DEATHMATCH }

enum spawn_s
{
    Float:Origin[coord_e],
    Float:VAngle[coord_e],
    Float:Angles[coord_e],
    TeamName:Team
}

enum player_s
{
    Float:LastOrigin[coord_e],
    Float:LastVAngle[coord_e],
    Float:LastAngles[coord_e],
    LastSpawn,
    AimedEntity,
    bool:FirstSpawn,
    TeamName:LastTeam,
    TeamName:CurTeam
}

// ======================= spawn editor settings =======================
const MAX_SEARCH_DISTANCE = 2500
const Float:ADD_Z_POSITION = 15.0
new const Float:g_flGravityValues[] = { 1.0, 0.5, 0.25, 0.15, 0.05 }

new const Float:g_vecColorTeam[any:TEAM_CT + 1][coord_e] =
{
    { 0.0, 250.0, 0.0 },    // TEAM_UNASSIGNED
    { 250.0, 0.0, 0.0 },    // TEAM_TERRORIST
    { 0.0, 0.0, 250.0 }        // TEAM_CT
}

new const SOUND_SELECT[] = "common/menu2.wav"
new const SOUND_ERROR[] = "buttons/button2.wav"
new const SOUND_SUCCESS[] = "buttons/blip2.wav"


new const g_szModels[any:TEAM_CT + 1][] =
{
    "models/player/vip/vip.mdl",    // TEAM_UNASSIGNED
    "models/player/leet/leet.mdl",    // TEAM_TERRORIST
    "models/player/gign/gign.mdl"    // TEAM_CT
}

//======================================================================

new const g_szClassName[] = "view_spawn"
new const g_szMenuTitle[] = "SpawnEditor"

new any:g_aSpot[MAX_SPAWNS][spawn_s], any:g_aPlayerData[MAX_CLIENTS + 1][player_s]
new g_szSpawnDirectory[256], g_szSpawnFile[256], g_szMapName[32]
new g_iMenuID, bool:g_bEditSpawns, bool:g_bNotSaved
new g_iGravity, g_iMaxPlayers, HookChain:g_hGetPlayerSpawnSpot, HookChain:g_hUseEmpty
new g_iTotalPoints, g_iNum[any:TEAM_CT + 1], g_iSpawnMode = MODE_TEAMPLAY


public SetSpawnerStateApi(bool:bEnabled, const iNewMode)
{
    SetSpawnerState(bEnabled, clamp(iNewMode, MODE_TEAMPLAY, MODE_DEATHMATCH))
    return g_iTotalPoints
}

public plugin_precache()
{
    for (new i = 0; i < sizeof(g_szModels); i++) {
        precache_model(g_szModels[i])    // for custom models
    }
    
    precache_sound(SOUND_SELECT)
    precache_sound(SOUND_ERROR)
    precache_sound(SOUND_SUCCESS)
}

public plugin_init()
{
    register_plugin("DeathMatch Spawn Manager", PL_VERSION, "Vaqtincha")

    register_concmd("csdm_edit_spawns", "ConCmd_EditSpawns", ADMIN_MAP, "Edits spawn configuration")
    register_clcmd("nightvision", "ClCmd_Nightvision")
    register_menucmd((g_iMenuID = register_menuid(g_szMenuTitle)), MENU_KEY_BITS, "EditorMenuHandler")

    DisableHookChain(g_hGetPlayerSpawnSpot = RegisterHookChain(RG_CSGameRules_GetPlayerSpawnSpot, "CSGameRules_GetPlayerSpawnSpot", .post = false))
    DisableHookChain(g_hUseEmpty = RegisterHookChain(RG_CBasePlayer_UseEmpty, "CBasePlayer_UseEmpty", .post = false))

    g_iMaxPlayers = get_maxplayers()
}

public plugin_cfg()
{
    new iLen = get_localinfo("amxx_configsdir", g_szSpawnDirectory, charsmax(g_szSpawnDirectory))
    formatex(g_szSpawnDirectory[iLen], charsmax(g_szSpawnDirectory) - iLen, "%s/%s", g_szSpawnDirectory[iLen], CSDM_SPAWN_DIR)
    MakeDir(g_szSpawnDirectory)

    get_mapname(g_szMapName, charsmax(g_szMapName))
    formatex(g_szSpawnFile, charsmax(g_szSpawnFile), "%s/%s.spawns.cfg", g_szSpawnDirectory, g_szMapName)
    LoadPoints()
}

public plugin_end()
{
    if (g_bEditSpawns && g_bNotSaved) // autosave
    {
        MakeDir(g_szSpawnDirectory)
        SavePoints()
    }
}

public client_connect(pPlayer)
{
    g_aPlayerData[pPlayer][FirstSpawn] = true
}

public client_putinserver(pPlayer)
{
    g_aPlayerData[pPlayer][AimedEntity] = NULLENT
    g_aPlayerData[pPlayer][LastTeam] = TEAM_UNASSIGNED
    g_aPlayerData[pPlayer][LastSpawn] = 0
    g_aPlayerData[pPlayer][FirstSpawn] = false
    g_aPlayerData[pPlayer][LastOrigin][X] = g_aPlayerData[pPlayer][LastOrigin][Y] = g_aPlayerData[pPlayer][LastOrigin][Z] = 0.0
}

public ClCmd_Nightvision(const pPlayer, const level) {
    return (!g_bEditSpawns || !is_user_alive(pPlayer) || !(get_user_flags(pPlayer) & level)) ? PLUGIN_CONTINUE : ShowEditorMenu(pPlayer)
}

public ConCmd_EditSpawns(const pPlayer, const level)
{
    if (!is_user_alive(pPlayer) || !(get_user_flags(pPlayer) & level))
        return PLUGIN_HANDLED
    
    if (g_bEditSpawns)
    {
        if (g_bNotSaved && SavePoints() == FAILED_CREATE)
        {
            console_print(pPlayer, "[CSDM] Autosave is failed! Please try again...")
            return ShowEditorMenu(pPlayer)
        }

        console_print(pPlayer, "[CSDM] Spawn editor disabled.")
        IsViewingMenu(pPlayer, true)
        RemoveAllSpotEntitys()
        g_bEditSpawns = false
        
        set_cvar_num("mp_round_infinite", 0)
        set_cvar_num("mp_forcerespawn", 0)
        set_entvar(pPlayer, var_gravity, 1.0)
        // SetSpawnerState(false)
        DisableHookChain(g_hUseEmpty)
        
        return PLUGIN_HANDLED
    }

    console_print(pPlayer, "[CSDM] Spawn editor enabled.")
    MakeAllSpotEntitys()
    g_bEditSpawns = true
    
    set_cvar_num("mp_round_infinite", 1)
    set_cvar_num("mp_forcerespawn", 1)
    set_entvar(pPlayer, var_gravity, g_flGravityValues[g_iGravity])
    SetSpawnerState(true)
    EnableHookChain(g_hUseEmpty)
    
    return ShowEditorMenu(pPlayer)
}


public CBasePlayer_UseEmpty(const pPlayer)
{
    if (IsViewingMenu(pPlayer))
    {
        EditorMenuHandler(pPlayer, 1)

        return HC_SUPERCEDE
    }
    
    return HC_CONTINUE
}

public CSGameRules_GetPlayerSpawnSpot(const pPlayer)
{
    if (g_iTotalPoints > 0 && !g_aPlayerData[pPlayer][FirstSpawn] && RandomSpawn(pPlayer))
    {
        SetHookChainReturn(ATYPE_INTEGER, pPlayer)
        return HC_SUPERCEDE
    }

    return HC_CONTINUE
}

public ShowEditorMenu(const pPlayer)
{
    new szMenu[512], bitKeys = (MENU_KEY_2|MENU_KEY_3|MENU_KEY_6|MENU_KEY_7)
    new iLen = formatex(szMenu, charsmax(szMenu), "\yРедактор точек возрожд.^n^n")
    new bool:bAddCancel = bool:(!IsVectorZero(g_aPlayerData[pPlayer][LastOrigin])), bool:bReached = bool:(g_iTotalPoints >= MAX_SPAWNS)
    static const szTeamName[any:TEAM_CT + 1][] = { "ALL", "TT", "CT" }

    if (bAddCancel)
    {
        bitKeys |= MENU_KEY_5
    }

    if (g_aPlayerData[pPlayer][AimedEntity] == NULLENT)
    {
        iLen += formatex(szMenu[iLen], charsmax(szMenu) - iLen,
            "%s^n^n\
            \y2. \wВыделить точку возрожд.^n\
            \y3. \wВыбрать команду\r: \w[\y%s\w]^n\
            \d4. Проверка точки возрожд.^n\
            %s^n^n",
            bReached ? "\d1. Добавить точку для возрожд.\w(\rМаксим. лимит точек\w)" : "\y1. \wДобавить новую точку для возрожд.",
            szTeamName[g_aPlayerData[pPlayer][CurTeam]], bAddCancel ? "\y5. \wОтменить удаление" : "\d5. Удалить точку возрожд."
        )

        if (!bReached) {
            bitKeys |= MENU_KEY_1
        }
    }
    else
    {
        iLen += formatex(szMenu[iLen], charsmax(szMenu) - iLen,
            "\y1. \wОбновить точку возрожд.^n^n\
            \y2. \wСнять выделение с точки возрожд.^n\
            \y3. \wВыбрать точку возрожд. для команд\r:    \w[\y%s\w]^n\
            \y4. \wПроверка точки возрожд.^n\
            \y5. %s^n^n", szTeamName[get_entvar(g_aPlayerData[pPlayer][AimedEntity], var_team)],
            bAddCancel ? "\wОтменить удаление" : "\rУдалить точку возрожд."
        )

        bitKeys |= (MENU_KEY_1|MENU_KEY_4|MENU_KEY_5)
    }

    iLen += formatex(szMenu[iLen], charsmax(szMenu) - iLen,
        "\y6. \wПоказать статистику^n\
        \y7. \wГравитация\r: \w[\y%0.2f\w]^n^n\
        %s^n^n\
        \wВсего точек\r: \w[\y%d\r/\y%d\w] \r(\wALL \y%d \r| \wTT \y%d \r| \wCT \y%d\r)", g_flGravityValues[g_iGravity],
        g_bNotSaved ? "\y9. \wСохранить" : "\d9. Сохранить", g_iTotalPoints, MAX_SPAWNS, g_iNum[TEAM_UNASSIGNED], g_iNum[TEAM_TERRORIST], g_iNum[TEAM_CT]
    )

    show_menu(pPlayer, bitKeys |= g_bNotSaved ? MENU_KEY_9 : bitKeys, szMenu, .title = g_szMenuTitle)
    return PLUGIN_HANDLED
}

public EditorMenuHandler(const pPlayer, iKey)
{
    if (!g_bEditSpawns)
        return PLUGIN_HANDLED

    iKey++
    switch (iKey)
    {
        case 1:
        {
            g_bNotSaved = bool:(g_aPlayerData[pPlayer][AimedEntity] == NULLENT ? AddSpawn(pPlayer) : MoveSpawn(pPlayer, g_aPlayerData[pPlayer][AimedEntity]))
            g_aPlayerData[pPlayer][LastOrigin][X] = g_aPlayerData[pPlayer][LastOrigin][Y] = g_aPlayerData[pPlayer][LastOrigin][Z] = 0.0
        }
        case 2:
        {
            if (g_aPlayerData[pPlayer][AimedEntity] == NULLENT)
            {
                if (!SetAimedEntity(pPlayer)) {
                    client_print(pPlayer, print_center, "Spawn entity not found!")
                }
                else {
                    rg_send_audio(pPlayer, SOUND_SELECT)
                }
            }
            else
            {
                ClearAimedEntity(pPlayer)
            }
        }
        case 3:
        {
            if (g_aPlayerData[pPlayer][AimedEntity] == NULLENT)
            {
                if (++g_aPlayerData[pPlayer][CurTeam] > TEAM_CT) {
                    g_aPlayerData[pPlayer][CurTeam] = TEAM_UNASSIGNED
                }
            }
            else
            {
                SetSpotTeam(g_aPlayerData[pPlayer][AimedEntity])
                g_bNotSaved = true
            }
        }
        case 4: TeleportToAimed(pPlayer, g_aPlayerData[pPlayer][AimedEntity])
        case 5: g_bNotSaved = bool:(IsVectorZero(g_aPlayerData[pPlayer][LastOrigin]) ? DeleteSpawn(pPlayer, g_aPlayerData[pPlayer][AimedEntity]) : AddSpawn(pPlayer, true))
        case 6:
        {
            new Float:vecOrigin[coord_e]
            get_entvar(pPlayer, var_origin, vecOrigin)

            client_print_color(pPlayer, print_team_grey, "Всего точек: ^4%d ^1(^3ALL ^4%d ^3TT ^4%d ^3CT ^4%d^1) Текущ. положение: ^3X ^4%0.f ^3Y ^4%0.f ^3Z ^4%0.f",
                g_iTotalPoints, g_iNum[TEAM_UNASSIGNED], g_iNum[TEAM_TERRORIST], g_iNum[TEAM_CT], vecOrigin[X], vecOrigin[Y], vecOrigin[Z])
        }
        case 7:
        {
            if (++g_iGravity >= sizeof(g_flGravityValues)) {
                g_iGravity = 0
            }

            set_entvar(pPlayer, var_gravity, g_flGravityValues[g_iGravity])
        }
        case 9:
        {
            static const szResultPrint[][] = {"Failed to create file!^rPlease try again", "Saved successfully", "File deleted"}
            client_print(pPlayer, print_center, "%s", szResultPrint[SavePoints()])
        }
    }

    return ShowEditorMenu(pPlayer)
}


bool:AddSpawn(const pPlayer, bool:bUndo = false)
{
    new Float:vecOrigin[coord_e], Float:vecAngles[coord_e], Float:vecVAngles[coord_e], pEntity = NULLENT
    
    if ((pEntity = CreateEntity()) == NULLENT)
        return false

    if (bUndo)
    {
        SetPosition(pEntity, g_aPlayerData[pPlayer][LastOrigin], g_aPlayerData[pPlayer][LastAngles], g_aPlayerData[pPlayer][LastVAngle])
        set_entvar(pEntity, var_team, g_aPlayerData[pPlayer][LastTeam])
        SET_MODEL(pEntity, g_szModels[g_aPlayerData[pPlayer][LastTeam]])
        g_iNum[g_aPlayerData[pPlayer][LastTeam]]++
        SetAimedEntity(pPlayer, pEntity, false)
    }
    else
    {
        GetPosition(pPlayer, vecOrigin, vecAngles, vecVAngles)
        vecOrigin[Z] += ADD_Z_POSITION

        if (!CheckFreeSpace(pPlayer, vecOrigin))
        {
            REMOVE_ENTITY(pEntity)
            return false
        }

        g_iNum[g_aPlayerData[pPlayer][CurTeam]]++
        SetPosition(pEntity, vecOrigin, vecAngles, vecVAngles)
        set_entvar(pEntity, var_team, g_aPlayerData[pPlayer][CurTeam])
        SET_MODEL(pEntity, g_szModels[g_aPlayerData[pPlayer][CurTeam]])
        rg_send_audio(pPlayer, SOUND_SUCCESS)
    }

    g_iTotalPoints++
    return true
}

bool:MoveSpawn(const pPlayer, const pEntity)
{
    new Float:vecOrigin[coord_e], Float:vecAngles[coord_e], Float:vecVAngles[coord_e]
    GetPosition(pPlayer, vecOrigin, vecAngles, vecVAngles)
    vecOrigin[Z] += ADD_Z_POSITION

    if (CheckFreeSpace(pPlayer, vecOrigin))
    {
        SetPosition(pEntity, vecOrigin, vecAngles, vecVAngles)
        return true
    }
    return false
}

bool:DeleteSpawn(const pPlayer, const pEntity)
{
    if (is_nullent(pEntity))
        return false

    GetPosition(pEntity, g_aPlayerData[pPlayer][LastOrigin], g_aPlayerData[pPlayer][LastAngles], g_aPlayerData[pPlayer][LastVAngle])
    g_aPlayerData[pPlayer][LastTeam] = get_entvar(pEntity, var_team)
    g_aPlayerData[pPlayer][AimedEntity] = NULLENT

    REMOVE_ENTITY(pEntity)
    g_iNum[g_aPlayerData[pPlayer][LastTeam]]--
    g_iTotalPoints--
    return true
}

TeleportToAimed(const pPlayer, const pEntity = NULLENT)
{
    if (is_nullent(pEntity))
        return

    new Float:vecOrigin[coord_e], Float:vecAngles[coord_e], Float:vecVAngles[coord_e]
    GetPosition(pEntity, vecOrigin, vecAngles, vecVAngles)

    if (CheckFreeSpace(pPlayer, vecOrigin)) {
        SetPlayerPosition(pPlayer, vecOrigin, vecVAngles)
    }
}

LoadPoints()
{
    new pFile
    if (!(pFile = fopen(g_szSpawnFile, "rt")))
    {
        server_print("[CSDM] No spawn points file found ^"%s^"", g_szMapName)
        return
    }

    new szDatas[128], szOrigin[coord_e][6], szTeam[3], szAngles[coord_e][6], szVAngles[coord_e][6]

    while (!feof(pFile))
    {
        fgets(pFile, szDatas, charsmax(szDatas))
        trim(szDatas)

        if (!szDatas[0] || (szDatas[0] == '/' && szDatas[1] == '/'))
            continue

        if (parse(szDatas, szOrigin[X], 5, szOrigin[Y], 5, szOrigin[Z], 5, szAngles[X], 5, szAngles[Y], 5, szAngles[Z], 5,
                szTeam, charsmax(szTeam), szVAngles[X], 5, szVAngles[Y], 5, szVAngles[Z], 5
            ) != 10)
        {
            continue // ignore invalid lines
        }

        if (g_iTotalPoints >= MAX_SPAWNS)
        {
            server_print("[CSDM] Max limit %d reached!", MAX_SPAWNS)
            break
        }

        g_aSpot[g_iTotalPoints][Origin][X] = str_to_float(szOrigin[X])
        g_aSpot[g_iTotalPoints][Origin][Y] = str_to_float(szOrigin[Y])
        g_aSpot[g_iTotalPoints][Origin][Z] = str_to_float(szOrigin[Z])

        // if (!IsHullVacant(g_aSpot[g_iTotalPoints][Origin], HULL_HUMAN))
        // {
            // server_print("[CSDM] Warning bad spawn detected at: [X: %0.f | Y: %0.f | Z: %0.f]", g_aSpot[g_iTotalPoints][Origin][X], g_aSpot[g_iTotalPoints][Origin][Y], g_aSpot[g_iTotalPoints][Origin][Z])
            // continue
        // }

        g_aSpot[g_iTotalPoints][Angles][X] = str_to_float(szAngles[X])
        g_aSpot[g_iTotalPoints][Angles][Y] = str_to_float(szAngles[Y])
        // g_aSpot[g_iTotalPoints][Angles][Z] = str_to_float(szAngles[Z]) // not used

        g_aSpot[g_iTotalPoints][VAngle][X] = str_to_float(szVAngles[X])
        g_aSpot[g_iTotalPoints][VAngle][Y] = str_to_float(szVAngles[Y])
        // g_aSpot[g_iTotalPoints][VAngle][Z] = str_to_float(szVAngles[Z]) // not used
        g_aSpot[g_iTotalPoints][Team] = clamp(str_to_num(szTeam), any:TEAM_UNASSIGNED, any:TEAM_CT)

        g_iNum[g_aSpot[g_iTotalPoints][Team]]++
        g_iTotalPoints++
    }

    if (g_iTotalPoints > 0)
    {
        server_print("[CSDM] Map ^"%s^" total spawns: %d [ANY: %d | TT: %d | CT: %d]", g_szMapName,
            g_iTotalPoints, g_iNum[TEAM_UNASSIGNED], g_iNum[TEAM_TERRORIST], g_iNum[TEAM_CT])

        // SetSpawnerState(true, (!g_iNum[TEAM_TERRORIST] && !g_iNum[TEAM_CT]) ? MODE_DEATHMATCH : MODE_TEAMPLAY)
    }

    fclose(pFile)
}

SavePoints()
{
    if (g_iTotalPoints <= 0)
    {
        delete_file(g_szSpawnFile)
        SetSpawnerState(false)
        return FILE_DELETED
    }

    new pFile, pEntity = NULLENT
    if (!(pFile = fopen(g_szSpawnFile, "wt")))
    {
        MakeDir(g_szSpawnDirectory, false)
        return FAILED_CREATE
    }

    fprintf(pFile, "// File generated by ^"CSDM Spawn Manager^" Version: %s^n// Total spawns: %d (ANY = %d, TT = %d, CT = %d)^n^n// Origin X:Y:Z, Angles X:Y:Z, Team, View Angles X:Y:Z^n^n",
        PL_VERSION, g_iTotalPoints, g_iNum[TEAM_UNASSIGNED], g_iNum[TEAM_TERRORIST], g_iNum[TEAM_CT])
    ClearAllArrays()

    while ((pEntity = rg_find_ent_by_class(pEntity, g_szClassName)))
    {
        if (g_iTotalPoints >= MAX_SPAWNS)
        {
            server_print("[CSDM] Max limit %d reached!", MAX_SPAWNS)
            break
        }

        GetPosition(pEntity, g_aSpot[g_iTotalPoints][Origin], g_aSpot[g_iTotalPoints][Angles], g_aSpot[g_iTotalPoints][VAngle])
        if (IsVectorZero(g_aSpot[g_iTotalPoints][Origin]))
            continue

        g_aSpot[g_iTotalPoints][Team] = get_entvar(pEntity, var_team)
        g_iNum[g_aSpot[g_iTotalPoints][Team]]++

        fprintf(pFile, "%-6.f %-6.f %-6.f %-4.f %-5.f %-2.f %-2.1d %-4.f %-5.f %-1.f^n",
            g_aSpot[g_iTotalPoints][Origin][X], g_aSpot[g_iTotalPoints][Origin][Y], g_aSpot[g_iTotalPoints][Origin][Z],
            g_aSpot[g_iTotalPoints][Angles][X], g_aSpot[g_iTotalPoints][Angles][Y], g_aSpot[g_iTotalPoints][Angles][Z],
            g_aSpot[g_iTotalPoints][Team],
            g_aSpot[g_iTotalPoints][VAngle][X], g_aSpot[g_iTotalPoints][VAngle][Y], g_aSpot[g_iTotalPoints][VAngle][Z]
        )

        g_iTotalPoints++
    }

    // SetSpawnerState(true)
    g_bNotSaved = false
    fclose(pFile)
    return FILE_SAVED
}

MakeAllSpotEntitys()
{
    for (new i = 0, pEntity = NULLENT; i < g_iTotalPoints; i++)
    {
        if (!IsVectorZero(g_aSpot[i][Origin]) && (pEntity = CreateEntity()) != NULLENT)
        {
            SetPosition(pEntity, g_aSpot[i][Origin], g_aSpot[i][Angles], g_aSpot[i][VAngle])
            set_entvar(pEntity, var_team, g_aSpot[i][Team])
            SET_MODEL(pEntity, g_szModels[g_aSpot[i][Team]])
        }
    }
}

RemoveAllSpotEntitys()
{
    new pEntity = NULLENT, pPlayer
    for (pPlayer = 1; pPlayer < g_iMaxPlayers; pPlayer++)
    {
        g_aPlayerData[pPlayer][LastOrigin][X] = g_aPlayerData[pPlayer][LastOrigin][Y] = g_aPlayerData[pPlayer][LastOrigin][Z] = 0.0
        g_aPlayerData[pPlayer][AimedEntity] = NULLENT
        g_aPlayerData[pPlayer][LastTeam] = TEAM_UNASSIGNED
    }

    while ((pEntity = rg_find_ent_by_class(pEntity, g_szClassName))) {
        REMOVE_ENTITY(pEntity)
    }
}

CreateEntity()
{
    new pEntity = rg_create_entity("info_target")

    if (is_nullent(pEntity))
    {
        abort(AMX_ERR_GENERAL, "Failed to create entity!")
        return NULLENT
    }

    set_entvar(pEntity, var_classname, g_szClassName)
    set_entvar(pEntity, var_solid, SOLID_BBOX)
    rg_animate_entity(pEntity, ACT_IDLE)

    return pEntity
}

SetPlayerPosition(const pPlayer, const Float:vecOrigin[], const Float:vecAngles[])
{
    const FORCE_VIEW_ANGLES = 1
    SET_ORIGIN(pPlayer, vecOrigin)
    set_entvar(pPlayer, var_velocity, VECTOR_ZERO)
    // set_entvar(pPlayer, var_avelocity, VECTOR_ZERO)
    set_entvar(pPlayer, var_v_angle, VECTOR_ZERO)
    set_entvar(pPlayer, var_angles, vecAngles)
    set_entvar(pPlayer, var_punchangle, VECTOR_ZERO)
    set_entvar(pPlayer, var_fixangle, FORCE_VIEW_ANGLES)
}

SetPosition(const pEntity, const Float:vecOrigin[], const Float:vecAngles[], const Float:vecVAngles[])
{
    SET_ORIGIN(pEntity, vecOrigin)
    set_entvar(pEntity, var_angles, vecAngles)
    set_entvar(pEntity, var_v_angle, vecVAngles) // temporary save
}

GetPosition(const pEntity, Float:vecOrigin[], Float:vecAngles[], Float:vecVAngles[])
{
    get_entvar(pEntity, var_origin, vecOrigin)
    get_entvar(pEntity, var_angles, vecAngles)
    get_entvar(pEntity, var_v_angle, vecVAngles)
}

SetSpotTeam(const pEntity)
{
    new TeamName:iOldTeam, TeamName:iNewTeam = iOldTeam = get_entvar(pEntity, var_team)

    if (++iNewTeam > TEAM_CT) {
        iNewTeam = TEAM_UNASSIGNED
    }

    g_iNum[iNewTeam]++
    g_iNum[iOldTeam]--
    set_entvar(pEntity, var_team, iNewTeam)
    SET_MODEL(pEntity, g_szModels[iNewTeam])
    rg_set_rendering(pEntity, kRenderFxGlowShell, g_vecColorTeam[iNewTeam], 10.0)
}

bool:SetAimedEntity(const pPlayer, pEntity = NULLENT, bool:bPrint = true)
{
    if (pEntity > 0 || (pEntity = FindEntityByAim(pPlayer)) != NULLENT)
    {
        rg_animate_entity(pEntity, ACT_RUN, 1.0)
        rg_set_rendering(pEntity, kRenderFxGlowShell, g_vecColorTeam[get_entvar(pEntity, var_team)], 10.0)

        g_aPlayerData[pPlayer][AimedEntity] = pEntity
        g_aPlayerData[pPlayer][LastOrigin][X] = g_aPlayerData[pPlayer][LastOrigin][Y] = g_aPlayerData[pPlayer][LastOrigin][Z] = 0.0

        if (bPrint) {
            client_print(pPlayer, print_center, "Aimed entity index %d", g_aPlayerData[pPlayer][AimedEntity])
        }
    
        return true
    }
    return false
}

ClearAimedEntity(const pPlayer)
{
    rg_animate_entity(g_aPlayerData[pPlayer][AimedEntity], ACT_IDLE)
    rg_set_rendering(g_aPlayerData[pPlayer][AimedEntity])
    g_aPlayerData[pPlayer][AimedEntity] = NULLENT
}

ClearAllArrays()
{
    for (new i = 0; i < MAX_SPAWNS; i++)
    {
        g_aSpot[i][Origin][X] = g_aSpot[i][Origin][Y] = g_aSpot[i][Origin][Z] = 0.0
        g_aSpot[i][VAngle][X] = g_aSpot[i][VAngle][Y] = g_aSpot[i][VAngle][Z] = 0.0
        g_aSpot[i][Angles][X] = g_aSpot[i][Angles][Y] = g_aSpot[i][Angles][Z] = 0.0
    }

    g_iNum[TEAM_UNASSIGNED] = g_iNum[TEAM_TERRORIST] = g_iNum[TEAM_CT] = 0
    g_iTotalPoints = 0
}

bool:IsViewingMenu(const pPlayer, bool:Close = false)
{
    new iMenuID, iKeys
    get_user_menu(pPlayer, iMenuID, iKeys)
    if (iMenuID == g_iMenuID)
    {
        if (Close)
        {
            // menu_cancel(pPlayer)
            show_menu(pPlayer, 0, "^n", 0)
        }
        
        return true
    }
    
    return false
}

FindEntityByAim(const pPlayer)
{
    new pEntity = NULLENT, iBody

    SetEntitysSolid(true)
    get_user_aiming(pPlayer, pEntity, iBody, MAX_SEARCH_DISTANCE)
    SetEntitysSolid(false)

    return (FClassnameIs(pEntity, g_szClassName)) ? pEntity : NULLENT
}

SetEntitysSolid(const bool:bSolid)
{
    new pEntity = NULLENT
    while ((pEntity = rg_find_ent_by_class(pEntity, g_szClassName)))
    {
        if (!bSolid)
            SET_SIZE(pEntity, VECTOR_ZERO, VECTOR_ZERO)
        else
            SET_SIZE(pEntity, Vector(-16, -16, -36), Vector(16, 16, 36))
    }
}

bool:RandomSpawn(const pPlayer)
{
    new iRand, iAttempts, iLast = g_aPlayerData[pPlayer][LastSpawn], TeamName:iTeam = get_member(pPlayer, m_iTeam)

    do
    {
        iAttempts++
        iRand = random(g_iTotalPoints)

        if (iRand != iLast && !IsVectorZero(g_aSpot[iRand][Origin]) && get_distance_fix(g_aSpot[iRand][Origin], g_aSpot[iLast][Origin]) > MIN_SPAWN_RADIUS)
        {
            if ((g_iSpawnMode == MODE_DEATHMATCH || g_aSpot[iRand][Team] == iTeam || g_aSpot[iRand][Team] == TEAM_UNASSIGNED)
                && !CheckDistance(pPlayer, g_aSpot[iRand][Origin])/* && IsHullVacant(g_aSpot[iRand][Origin], HULL_HUMAN, pPlayer) */)
            {
                SetPlayerPosition(pPlayer, g_aSpot[iRand][Origin], g_aSpot[iRand][VAngle])
                g_aPlayerData[pPlayer][LastSpawn] = iRand
                return true
            }
        }

    } while (iAttempts <= g_iTotalPoints)

    return false
}

bool:CheckDistance(const pPlayer, const Float:vecOrigin[])
{
    new pEntity = NULLENT
    while ((pEntity = FIND_ENT_IN_SPHERE(pEntity, vecOrigin, MIN_SPAWN_RADIUS)))
    {
        if (IsPlayer(pEntity) && pEntity != pPlayer && get_entvar(pEntity, var_deadflag) == DEAD_NO) {
            return true
        }
    }

    return false
}

bool:CheckFreeSpace(const pPlayer, const Float:vecOrigin[coord_e])
{
    if (!IsHullVacant(vecOrigin, HULL_HUMAN, pPlayer))
    {
        client_print(pPlayer, print_center, "No free space!")
        rg_send_audio(pPlayer, SOUND_ERROR)

        return false
    }

    return true
}

SetSpawnerState(bool:bEnabled, const iNewMode = MODE_TEAMPLAY)
{
    if (bEnabled && g_iTotalPoints > 0)
    {
        EnableHookChain(g_hGetPlayerSpawnSpot)
        g_iSpawnMode = iNewMode
    }
    else
    {
        DisableHookChain(g_hGetPlayerSpawnSpot)
    }
}

MakeDir(const szDirName[], bool:bPrint = true)
{
    if (dir_exists(szDirName))
        return

    if (bPrint) {
        server_print("[CSDM] Directory ^"%s^" not exist, will be created automatically.", szDirName)
    }
    if (mkdir(szDirName)) {
        abort(AMX_ERR_GENERAL, "[CSDM] Failed to create directory ^"%s^"", szDirName)
    }
}

// checks if a space is vacant, by VEN
stock bool:IsHullVacant(const Float:vecOrigin[], const iHullNumber, const pSkipEnt = 0)
{
    const pTr = 0 // pGlobalTrace
    engfunc(EngFunc_TraceHull, vecOrigin, vecOrigin, DONT_IGNORE_MONSTERS, iHullNumber, pSkipEnt, pTr)

    return bool:(!get_tr2(pTr, TR_StartSolid) && !get_tr2(pTr, TR_AllSolid) && get_tr2(pTr, TR_InOpen))
}

stock rg_animate_entity(const pEntity, const Activity:iSequence, const Float:flFramerate = 0.0)
{
    set_entvar(pEntity, var_sequence, iSequence)
    set_entvar(pEntity, var_framerate, flFramerate)
}

stock rg_set_rendering(const pEntity, const fx = kRenderFxNone, const Float:flColor[] = {0.0, 0.0, 0.0}, const Float:iAmount = 0.0)
{
    set_entvar(pEntity, var_renderfx, fx)
    set_entvar(pEntity, var_rendercolor, flColor)
    set_entvar(pEntity, var_renderamt, iAmount)
}

// FIX: "error 047: array sizes do not match, or destination array is too small"
stock Float:get_distance_fix(const Float:Origin1[], const Float:Origin2[])
{
    new Float:fOrigin1[coord_e], Float:fOrigin2[coord_e]
    fOrigin1[X] = Origin1[X]; fOrigin1[Y] = Origin1[Y]; fOrigin1[Z] = Origin1[Z]
    fOrigin2[X] = Origin2[X]; fOrigin2[Y] = Origin2[Y]; fOrigin2[Z] = Origin2[Z]

    return get_distance_f(fOrigin1, fOrigin2)
}
 

Hisary

Пользователь
Регистрация
7 Июн 2019
Сообщения
4
Симпатии
0
Почему расставленные спавны начинают работать после того как откроешь и закроешь меню редактирования спавнов?
 

Vaqtincha

aggressive
Разработчик
Скриптер
Регистрация
28 Янв 2018
Сообщения
963
Симпатии
685
Пол
Мужской
Hisary, Потому что его должен вызвать другой плагин мод нужное время.
Тут показано как Inline Warm-Up
Хотя могу добавить квар force_enable который включает его сразу при запуске карты.
 

Hisary

Пользователь
Регистрация
7 Июн 2019
Сообщения
4
Симпатии
0
А как этот плагин соединить с твоим ксдм? Что бы сразу начинал работать.
 

Hisary

Пользователь
Регистрация
7 Июн 2019
Сообщения
4
Симпатии
0
Хотя могу добавить квар force_enable который включает его сразу при запуске карты.
Если можешь, то сделать пожалуйста.
 
Сверху Снизу