Разобраться с функцией rg_set_user_team

Сообщения
14
Реакции
1
Баллы
3
Плагин меняет команды игроков местами каждые N раундов. И вроде он работает очень хорошо, но бывает, что у игрока не меняется скин.
Подскажите, как правильно реализовать подобный плагин, чтобы исключить такую ошибку. При маленьком онлайне на сервере есть боты.
Убивать оставшихся в живых игроков не хочется, но если это единственный путь, как лучше это сделать и чтобы им не засчитали смерть?

C++:
#include <amxmodx>
#include <reapi>

#define PLUGIN_NAME    "Auto Team Swap"
#define PLUGIN_VERSION "1.1"
#define PLUGIN_AUTHOR  "kakavanAI"

// Глобальные переменные
new g_iCurrentRound = 0;      // Счетчик прошедших раундов
new g_pCvarRounds;            // Указатель на cvar количества раундов до смены

/**
 * Инициализация плагина. Регистрирует cvar'ы и хук на окончание раунда.
 */
public plugin_init()
{
    register_plugin(PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_AUTHOR);

    // Cvar: количество раундов, после которых произойдет смена (0 = отключено)
    g_pCvarRounds = register_cvar("ats_rounds", "5");

    // Хук на окончание раунда. post=true означает, что код выполнится ПОСЛЕ оригинальной логики игры
    RegisterHookChain(RG_RoundEnd, "OnRoundEnd", .post = true);
}

public plugin_precache()
{
    precache_sound("darkstar_meat/gong2.wav");
}



/**
 * Хук RG_RoundEnd. Вызывается каждый раз, когда раунд завершается.
 * Увеличивает счетчик и при достижении заданного порога вызывает смену команд.
 */
public OnRoundEnd(const WinStatus:status, const ScenarioEventEndRound:event, const Float:tmDelay)
{
    g_iCurrentRound++;

    new swapRounds = get_pcvar_num(g_pCvarRounds);
    // Проверяем, делится ли текущий раунд на заданное число без остатка
    if (swapRounds > 0 && g_iCurrentRound % swapRounds == 0)
    {
        SwapTeams();
    }

    return HC_CONTINUE;
}

/**
 * Основная функция смены команд.
 * Проходит по всем подключенным игрокам, меняет TERRORIST <-> CT,
 * игнорирует спектаторов и корректно обрабатывает мертвых игроков.
 */
stock SwapTeams()
{
    new players[MAX_PLAYERS], pnum;
    // Получаем список всех подключенных игроков
    get_players(players, pnum, "h");

    new szName[MAX_NAME_LENGTH];

    for (new i = 0; i < pnum; i++)
    {
        new id = players[i];
        
        // Получаем текущую команду игрока через ReAPI member
        new TeamName:currentTeam = get_member(id, m_iTeam);
        
        // Пропускаем спектаторов и игроков без команды
        if (currentTeam != TEAM_TERRORIST && currentTeam != TEAM_CT)
            continue;

        get_user_name(id, szName, charsmax(szName));

        // Определяем новую команду: если был T -> станет CT, и наоборот
        new TeamName:newTeam = (currentTeam == TEAM_TERRORIST) ? TEAM_CT : TEAM_TERRORIST;

        // rg_set_user_team меняет команду БЕЗ убийства игрока.
        // Параметры:
        // id           - индекс игрока
        // newTeam      - новая команда
        // MODEL_AUTO   - автоматически подобрать модель новой команды
        // true         - отправить TeamInfo сообщение клиенту (обновить табличку)
        // false        - НЕ запускать перепроверку условий победы (чтобы не сбросить раунд)
        rg_set_user_team(id, newTeam, MODEL_AUTO, true, false);
        client_cmd(id, "spk darkstar_meat/gong2");

        client_print(id, print_chat, "[ATS] Команды поменялись местами!");

    }

}
 

Вложения

Исправлено это:

  • В autoteamswitch.sma (line 10) добавлен флаг g_bFixModelOnSpawn[] для игроков, которым после swap нужно принудительно обновить модель.
  • В plugin_init (line 12) добавлен RG_CBasePlayer_Spawn, чтобы чинить скин именно на следующем спавне.
  • В SwapTeams (line 40) убран ручной перевод каждого игрока через rg_set_user_team().
  • Вместо этого теперь используется rg_swap_all_players() (line 62) — это надежнее, потому что swap делает сам gamedll.
  • Перед swap для игроков T/CT вызывается rg_reset_user_model(id, true) (line 58), чтобы снять возможный model lock.
  • После спавна в OnPlayerSpawn_Post (line 79) еще раз вызывается rg_reset_user_model(id, true) (line 87), чтобы модель точно соответствовала новой команде.
  • Игроков не убивает, смерти/фраги не трогает.
 

Вложения

За 0
C-подобный:
#include <amxmodx>
#include <reapi>

#define PLUGIN_NAME    "Auto Team Swap"
#define PLUGIN_VERSION "1.2"
#define PLUGIN_AUTHOR  "kakavanAI + Joker Fix"

new g_iCurrentRound = 0;
new g_pCvarRounds;
new bool:g_bSwapPending = false;

public plugin_init()
{
    register_plugin(PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_AUTHOR);

    // Колко рунда да минат до размяна. 0 = изключено
    g_pCvarRounds = register_cvar("ats_rounds", "5");

    // Само отбелязваме, че трябва да има swap
    RegisterHookChain(RG_RoundEnd, "OnRoundEnd_Post", true);

    // Реалната смяна я правим при рестарт на новия рунд
    RegisterHookChain(RG_CSGameRules_RestartRound, "OnRestartRound_Pre", false);
}

public plugin_precache()
{
    precache_sound("darkstar_meat/gong2.wav");
}

public OnRoundEnd_Post(const WinStatus:status, const ScenarioEventEndRound:event, const Float:tmDelay)
{
    new swapRounds = get_pcvar_num(g_pCvarRounds);

    if (swapRounds <= 0)
        return HC_CONTINUE;

    g_iCurrentRound++;

    if (g_iCurrentRound % swapRounds == 0)
    {
        g_bSwapPending = true;
    }

    return HC_CONTINUE;
}

public OnRestartRound_Pre()
{
    if (!g_bSwapPending)
        return HC_CONTINUE;

    g_bSwapPending = false;
    SwapTeamsSafe();

    return HC_CONTINUE;
}

stock SwapTeamsSafe()
{
    new players[MAX_PLAYERS], pnum;
    get_players(players, pnum, "h");

    new id;
    new TeamName:currentTeam;
    new TeamName:newTeam;

    for (new i = 0; i < pnum; i++)
    {
        id = players[i];

        if (!is_user_connected(id))
            continue;

        currentTeam = get_member(id, m_iTeam);

        if (currentTeam != TEAM_TERRORIST && currentTeam != TEAM_CT)
            continue;

        newTeam = (currentTeam == TEAM_TERRORIST) ? TEAM_CT : TEAM_TERRORIST;

        // Смяна на отбора без kill и без излишна проверка за край на рунда
        rg_set_user_team(id, newTeam, MODEL_AUTO, true, false);

        // Личен звук
        client_cmd(id, "spk ^"darkstar_meat/gong2^"");

        client_print(id, print_chat, "[ATS] Командите се смениха.");
    }

    SwapTeamScores();
}

stock SwapTeamScores()
{
    new tWins = get_member_game(m_iNumTerroristWins);
    new ctWins = get_member_game(m_iNumCTWins);

    set_member_game(m_iNumTerroristWins, ctWins);
    set_member_game(m_iNumCTWins, tWins);

    message_begin(MSG_ALL, get_user_msgid("TeamScore"));
    write_string("TERRORIST");
    write_short(ctWins);
    message_end();

    message_begin(MSG_ALL, get_user_msgid("TeamScore"));
    write_string("CT");
    write_short(tWins);
    message_end();
}
 
За 0
За 0
Действительно, не знал что есть функция rg_swap_all_players(); , а если так сделать, могут быть ошибки в скине игрока?

C++:
#include <amxmodx>
#include <reapi>

#define PLUGIN_NAME    "Auto Team Swap"
#define PLUGIN_VERSION "1.2"
#define PLUGIN_AUTHOR  "kakavanAI + Joker Fix"

new g_iCurrentRound = 0;
new g_pCvarRounds;
new bool:g_bSwapPending = false;

public plugin_init()
{
    register_plugin(PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_AUTHOR);

    // Колко рунда да минат до размяна. 0 = изключено
    g_pCvarRounds = register_cvar("ats_rounds", "5");

    // Само отбелязваме, че трябва да има swap
    RegisterHookChain(RG_RoundEnd, "OnRoundEnd_Post", true);

    // Реалната смяна я правим при рестарт на новия рунд
    RegisterHookChain(RG_CSGameRules_RestartRound, "OnRestartRound_Pre", false);
}

public plugin_precache()
{
    precache_sound("darkstar_meat/gong2.wav");
}

public OnRoundEnd_Post(const WinStatus:status, const ScenarioEventEndRound:event, const Float:tmDelay)
{
    new swapRounds = get_pcvar_num(g_pCvarRounds);

    if (swapRounds <= 0)
        return HC_CONTINUE;

    g_iCurrentRound++;

    if (g_iCurrentRound % swapRounds == 0)
    {
        g_bSwapPending = true;
    }

    return HC_CONTINUE;
}

public OnRestartRound_Pre()
{
    if (!g_bSwapPending)
        return HC_CONTINUE;

    g_bSwapPending = false;

    rg_swap_all_players();

    SwapTeamScores();

    client_cmd(0, "spk ^"darkstar_meat/gong2^"");
    client_print(0, print_chat, "[ATS] Командите се смениха.");

    return HC_CONTINUE;
}


stock SwapTeamScores()
{
    new tWins = get_member_game(m_iNumTerroristWins);
    new ctWins = get_member_game(m_iNumCTWins);

    set_member_game(m_iNumTerroristWins, ctWins);
    set_member_game(m_iNumCTWins, tWins);

    message_begin(MSG_ALL, get_user_msgid("TeamScore"));
    write_string("TERRORIST");
    write_short(ctWins);
    message_end();

    message_begin(MSG_ALL, get_user_msgid("TeamScore"));
    write_string("CT");
    write_short(tWins);
    message_end();
}
 
За 0
счет команд уже в этом нативе меняется автоматически

остальное как будто бы ОК
смена скинов тоже должна быть ОК

в общем потести
 
За 0
счет команд уже в этом нативе меняется автоматически

остальное как будто бы ОК
смена скинов тоже должна быть ОК

в общем потести


Я проверил, действительно счет меняется, сегодня проведу тесты этой версии на игроках.


C++:
#include <amxmodx>
#include <reapi>

#define PLUGIN_NAME    "Auto Team Swap"
#define PLUGIN_VERSION "1.3"
#define PLUGIN_AUTHOR  "kakavanAI + Joker Fix"

new g_iCurrentRound = 0;
new g_pCvarRounds;
new bool:g_bSwapPending = false;

public plugin_init()
{
    register_plugin(PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_AUTHOR);

    // Колко рунда да минат до размяна. 0 = изключено
    g_pCvarRounds = register_cvar("ats_rounds", "5");

    // Само отбелязваме, че трябва да има swap
    RegisterHookChain(RG_RoundEnd, "OnRoundEnd_Post", true);

    // Реалната смяна я правим при рестарт на новия рунд
    RegisterHookChain(RG_CSGameRules_RestartRound, "OnRestartRound_Pre", false);
}

public plugin_precache()
{
    precache_sound("darkstar_meat/gong2.wav");
}

public OnRoundEnd_Post(const WinStatus:status, const ScenarioEventEndRound:event, const Float:tmDelay)
{
    new swapRounds = get_pcvar_num(g_pCvarRounds);

    if (swapRounds <= 0)
        return HC_CONTINUE;

    g_iCurrentRound++;

    if (g_iCurrentRound % swapRounds == 0)
    {
        g_bSwapPending = true;
    }

    return HC_CONTINUE;
}

public OnRestartRound_Pre()
{
    if (!g_bSwapPending)
        return HC_CONTINUE;

    g_bSwapPending = false;

    rg_swap_all_players();

    client_cmd(0, "spk ^"darkstar_meat/gong2^"");
    client_print(0, print_chat, "[ATS] Командите се смениха.");

    return HC_CONTINUE;
}
 
За 0
Я проверил, действительно счет меняется, сегодня проведу тесты этой версии на игроках.


C++:
#include <amxmodx>
#include <reapi>

#define PLUGIN_NAME    "Auto Team Swap"
#define PLUGIN_VERSION "1.3"
#define PLUGIN_AUTHOR  "kakavanAI + Joker Fix"

new g_iCurrentRound = 0;
new g_pCvarRounds;
new bool:g_bSwapPending = false;

public plugin_init()
{
    register_plugin(PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_AUTHOR);

    // Колко рунда да минат до размяна. 0 = изключено
    g_pCvarRounds = register_cvar("ats_rounds", "5");

    // Само отбелязваме, че трябва да има swap
    RegisterHookChain(RG_RoundEnd, "OnRoundEnd_Post", true);

    // Реалната смяна я правим при рестарт на новия рунд
    RegisterHookChain(RG_CSGameRules_RestartRound, "OnRestartRound_Pre", false);
}

public plugin_precache()
{
    precache_sound("darkstar_meat/gong2.wav");
}

public OnRoundEnd_Post(const WinStatus:status, const ScenarioEventEndRound:event, const Float:tmDelay)
{
    new swapRounds = get_pcvar_num(g_pCvarRounds);

    if (swapRounds <= 0)
        return HC_CONTINUE;

    g_iCurrentRound++;

    if (g_iCurrentRound % swapRounds == 0)
    {
        g_bSwapPending = true;
    }

    return HC_CONTINUE;
}

public OnRestartRound_Pre()
{
    if (!g_bSwapPending)
        return HC_CONTINUE;

    g_bSwapPending = false;

    rg_swap_all_players();

    client_cmd(0, "spk ^"darkstar_meat/gong2^"");
    client_print(0, print_chat, "[ATS] Командите се смениха.");

    return HC_CONTINUE;
}
Так что ещё нужно сделать?
 
За 0
Тщательно протестируйте предоставленный мной код, и если что-то не так, напишите мне точно, что вы хотите, чтобы произошло, и я это сделаю.
 
За 0

Кто просматривает тему

Назад
Верх