Игрок с наименьшим кол-вом очков CS:GO

denj

Участник
Сообщения
23
Реакции
0
Подскажите как правильно получить индекс игрока с наименьшим количеством очков:dntknw:
 

denj

Участник
Сообщения
23
Реакции
0
PHP:
new g_iPoints[MAXPLAYERS+1]; //кол-во очков у игрока
new index_client; //индекс игрока с наименьшим кол-вом очков

for(new i=0; i<=MaxClients; i++)
{
    if(i = 0)
    {
        index_client = i;
    }
    else if(g_iPoints[i] < g_iPoints[i-1])
    {
        index_client = i;
    }
}
Вроде все так должно быть.

Спасибо за ответ, но что-то не получается.
Попробую объяснить задачу подробнее: нужно в конце каждого раунда получать в переменную worstplayer индекс игрока у которого меньше всех очков и говорить что-то вроде PrintToChatAll("Худший игрок на сервере %N", worstplayer)
 

denj

Участник
Сообщения
23
Реакции
0
PHP:
new g_iPoints[MAXPLAYERS+1]; //кол-во очков у игрока

public OnPluginStart()
{
    HookEvent("round_end", RoundEnd);
}

public RoundEnd(Handle:event, const String:name[], bool:dontBroadcast) 
{
    new worstplayer; //индекс игрока с наименьшим кол-вом очков

    for(new i = 1; i <= MaxClients; i++) 
    {
        if(IsClientInGame(i) && !IsFakeClient(i))
        {
            if(i == 1)
            { 
                worstplayer = i;
            }
            else if(g_iPoints[i] < g_iPoints[i-1]) 
            { 
                worstplayer = i;
            }            
        }
    }
    
    PrintToChatAll("Худший игрок на сервере %N", worstplayer)
}

Пишел "Худший игрок на сервере Console":-D
 

denj

Участник
Сообщения
23
Реакции
0
Сам делал так (язык изучаю только второй день, так что не бейте)
PHP:
        new score[MaxClients];
        new cur_players;
        for (new i = 1; i <= MaxClients; i++) // цикл будет заносит в массив список очков
        {
            if (IsClientInGame(i))
            {
                score[i] = CS_GetClientContributionScore(i); //получаем список очков в масив score[]
                cur_players++;
            }
        }
        SortIntegers(score[1], cur_players, Sort_Ascending); //сортируем
        for (new i = 1; i <= MaxClients; i++)
        {
            if (IsClientInGame(i))
            {
                if (CS_GetClientContributionScore(i) == score[1]) //ищем игрока с наименьшим кол-вом очков
                {
                    PrintToChatAll("Худший игрок на сервере %N", i) 
                }
            }
        }
Так вроде работало, но в какой-то момент, происходил баг и массив score[] сдвигался на 1 шаг, т.е. score[1] становилось 0 всегда, а score[2] показывало то, что раньше показывало score[1] как-то так
 

AlmazON

Не путать с самим yand3xmail
Сообщения
5,099
Реакции
2,755
PHP:
score[i] = CS_GetClientContributionScore(i); //получаем список очков в масив score[]                cur_players++;
Индекс игрока может записываться в сам массив, но не является верным показателем размерности его заполнения (если только сервер не полон):
PHP:
score[cur_players++] = CS_GetClientContributionScore(i);
Ну и дальше массив должен быть вписан верно.
По твоей схеме где-то так:
PHP:
		decl score[MaxClients];
        new cur_players;
        for (new i = 1; i <= MaxClients; i++) // цикл будет заносит в массив список очков
        {
            if (IsClientInGame(i))
            {
                score[cur_players++] = CS_GetClientContributionScore(i); //получаем список очков в масив score[]
            }
        }
        SortIntegers(score, cur_players, Sort_Ascending); //сортируем
        for (new i = 1; i <= MaxClients; i++)
        {
            if (IsClientInGame(i))
            {
                if (CS_GetClientContributionScore(i) == score[0]) //ищем игрока с наименьшим кол-вом очков
                {
                    PrintToChatAll("Худший игрок на сервере %N", i);
					break;
                }
            }
        }
 
  • Мне нравится
Реакции: denj

denj

Участник
Сообщения
23
Реакции
0
Индекс игрока может записываться в сам массив, но не является верным показателем размерности его заполнения (если только сервер не полон):
PHP:
score[cur_players++] = CS_GetClientContributionScore(i);
Ну и дальше массив должен быть вписан верно.
По твоей схеме где-то так:
PHP:
        decl score[MaxClients];
        new cur_players;
        for (new i = 1; i <= MaxClients; i++) // цикл будет заносит в массив список очков
        {
            if (IsClientInGame(i))
            {
                score[cur_players++] = CS_GetClientContributionScore(i); //получаем список очков в масив score[]
            }
        }
        SortIntegers(score, cur_players, Sort_Ascending); //сортируем
        for (new i = 1; i <= MaxClients; i++)
        {
            if (IsClientInGame(i))
            {
                if (CS_GetClientContributionScore(i) == score[0]) //ищем игрока с наименьшим кол-вом очков
                {
                    PrintToChatAll("Худший игрок на сервере %N", i);
                    break;
                }
            }
        }


Спасибо большое! Пока что работает, но опять же я так и не понял, почему при старом коде массив иногда сбивался на 1 шаг?:blush2:
 

AlmazON

Не путать с самим yand3xmail
Сообщения
5,099
Реакции
2,755
почему при старом коде массив иногда сбивался на 1 шаг?
Поскольку у тебя new score[MaxClients];, то весь массив по умолчанию наполнен (инициализирован) нулями. Так вот один из этих нулей и уходит почти постоянно в score[1]:
score[1] становилось 0 всегда
Так как ты неправильно засчитал его валидным игроком.
 
  • Мне нравится
Реакции: denj

denj

Участник
Сообщения
23
Реакции
0
Поскольку у тебя new score[MaxClients];, то весь массив по умолчанию наполнен (инициализирован) нулями. Так вот один из этих нулей и уходит почти постоянно в score[1]:Так как ты неправильно засчитал его валидным игроком.
А не подскажешь теперь как сделать так, чтобы раунд не заканчивался, пока у нескольких игроков минимальный счет? Т.е. раундтайм закончился, но раунд должен продолжаться до момента, когда только один из игроков будет иметь минимальный счет?
 

AlmazON

Не путать с самим yand3xmail
Сообщения
5,099
Реакции
2,755
чтобы раунд не заканчивался, пока у нескольких игроков минимальный счет?
Для блокировки при наступлении конца раунда:
PHP:
#include <cstrike>

public Action:CS_OnTerminateRound(&Float:delay, &CSRoundEndReason:reason)
{
   if(g_bBlock) return Plugin_Handled;
   return Plugin_Continue;
}
Где g_bBlock - "сигнальная" bool переменная. Должна содержать true, когда худших игроков несколько.
Далее отлавливаешь событие смерти и проверяешь счёт игроков. Так до тех пор, пока неудачливый игрок не останется один, после чего сам вызываешь конец раунда через натив CS_TerminateRound(Float:delay, CSRoundEndReason:reason, bool:blockhook = false);.
Возможно, вызывать и не понадобится - зависит от настроек игры (с CS:GO не знаком).
 
  • Мне нравится
Реакции: denj

denj

Участник
Сообщения
23
Реакции
0
Для блокировки при наступлении конца раунда:
PHP:
#include <cstrike>

public Action:CS_OnTerminateRound(&Float:delay, &CSRoundEndReason:reason)
{
   if(g_bBlock) return Plugin_Handled;
   return Plugin_Continue;
}
Где g_bBlock - "сигнальная" bool переменная. Должна содержать true, когда худших игроков несколько.
Далее отлавливаешь событие смерти и проверяешь счёт игроков. Так до тех пор, пока неудачливый игрок не останется один, после чего сам вызываешь конец раунда через натив CS_TerminateRound(Float:delay, CSRoundEndReason:reason, bool:blockhook = false);.
Возможно, вызывать и не понадобится - зависит от настроек игры (с CS:GO не знаком).
Можно подробнее про натив, что это?)
 

Reiko1231

AlexTheRegent
Сообщения
508
Реакции
1,335
Лучший способ для поиска худшего игрока - один цикл. Решение с сортировкой хуже, т.к. всё равно требуется один цикл по всем игрокам с целью получения их счета.
C-подобный:
#include <cstrike>

new bool:	g_bBlockRoundEnd;

public OnPluginStart() 
{
	HookEvent("player_death", 	Ev_PlayerDeath);
	HookEvent("round_start", 	Ev_RoundStart);
}

GetWorstPlayer()
{
	new iWorstScore = 9999, iWorstPlayer;
	for ( new i = 1; i <= MaxClients; ++i ) {
		if ( IsClientInGame(i) && GetClientTeam() > 1 ) {
			new iScore = CS_GetClientContributionScore(i);
			if ( iWorstScore > iScore ) {
				iWorstScore = iScore;
				iWorstPlayer = i;
			}
			else if ( iWorstScore == iScore ) {
				iWorstPlayer = 0;
			}
		}
	}
	return iWorstPlayer;
}

public Ev_RoundStart(Handle:hEvent, const String:sEvName[], bool:bSilent)
{
	g_bBlockRoundEnd = true;
}

public Ev_PlayerDeath(Handle:hEvent, const String:sEvName[], bool:bSilent)
{
	new iWorstPlayer = GetWorstPlayer();
	if ( iWorstPlayer ) {
		PrintToChatAll("Худший игрок: %N", iWorstPlayer);
		g_bBlockRoundEnd = false;
	}
}

public Action:CS_OnTerminateRound(&Float:delay, &CSRoundEndReason:reason)
{
	return g_bBlockRoundEnd?Plugin_Handled:Plugin_Continue;
}
CS_OnTerminateRound - вызывается во время завершения раунда. Plugin_Continue - разрешить завершение, используя задержку и причину из входных аргументов, Plugin_Handled и выше - заблокировать завершение раунда. Будет вызываться до тех пор, пока в конце концов все плагины, использующие его, не вернут через него Plugin_Continue;
 
  • Мне нравится
Реакции: denj

AlmazON

Не путать с самим yand3xmail
Сообщения
5,099
Реакции
2,755
Натив (native) - прямая внутренняя функция, уже предусмотренная в приложениях SourcePawn.
В нашем случае, это принудительный вызов конца раунда в играх cstrike (CS_TerminateRound).
 
  • Мне нравится
Реакции: denj

denj

Участник
Сообщения
23
Реакции
0
Лучший способ для поиска худшего игрока - один цикл. Решение с сортировкой хуже, т.к. всё равно требуется один цикл по всем игрокам с целью получения их счета.
C-подобный:
#include <cstrike>

new bool:    g_bBlockRoundEnd;

public OnPluginStart() 
{
    HookEvent("player_death",     Ev_PlayerDeath);
    HookEvent("round_start",     Ev_RoundStart);
}

GetWorstPlayer()
{
    new iWorstScore = 9999, iWorstPlayer;
    for ( new i = 1; i <= MaxClients; ++i ) {
        if ( IsClientInGame(i) && GetClientTeam() > 1 ) {
            new iScore = CS_GetClientContributionScore(i);
            if ( iWorstScore > iScore ) {
                iWorstScore = iScore;
                iWorstPlayer = i;
            }
            else if ( iWorstScore == iScore ) {
                iWorstPlayer = 0;
            }
        }
    }
    return iWorstPlayer;
}

public Ev_RoundStart(Handle:hEvent, const String:sEvName[], bool:bSilent)
{
    g_bBlockRoundEnd = true;
}

public Ev_PlayerDeath(Handle:hEvent, const String:sEvName[], bool:bSilent)
{
    new iWorstPlayer = GetWorstPlayer();
    if ( iWorstPlayer ) {
        PrintToChatAll("Худший игрок: %N", iWorstPlayer);
        g_bBlockRoundEnd = false;
    }
}

public Action:CS_OnTerminateRound(&Float:delay, &CSRoundEndReason:reason)
{
    return g_bBlockRoundEnd?Plugin_Handled:Plugin_Continue;
}
CS_OnTerminateRound - вызывается во время завершения раунда. Plugin_Continue - разрешить завершение, используя задержку и причину из входных аргументов, Plugin_Handled и выше - заблокировать завершение раунда. Будет вызываться до тех пор, пока в конце концов все плагины, использующие его, не вернут через него Plugin_Continue;

Большое спасибо за разъяснение. Но если использую твой код, то он просто спамит в чат во время раунда:dntknw:
 

Reiko1231

AlexTheRegent
Сообщения
508
Реакции
1,335
Большое спасибо за разъяснение. Но если использую твой код, то он просто спамит в чат во время раунда:dntknw:

Это набросок кода, так как я не понимаю, зачем нужно останавливать раунд до тех пор, пока один из игроков не станет худшим. Ведь все игроки будут мертвы, а значит как кто-то станет хуже? В коде я набросал скелет, который содержит в себе функцию поиска худшего игрока и механизм остановки раунда, дальше его нужно модифицировать, как тебе нужно. Сейчас то там идет поиск худшего игрока сразу, т.к. нет проверки на то, сколько игроков осталось в живых, поэтому при каждой смерти ищется худший игрок, если такой есть. Кстати, я допустил небольшую опечатку - GetClientTeam() > 1 нужно заменить на GetClientTeam(i) > 1.

P.S. И да, возможно придется вручную вызывать CS_TerminateRound(). Данная функция аналогична форварду, только является функцией.
 
Последнее редактирование:
  • Мне нравится
Реакции: denj

denj

Участник
Сообщения
23
Реакции
0
Теперь встал вопрос как искать худшего игрока и среди отключившихся, т.к. когда матч запущен, то после отключения клиента его статистика где-то сохраняется.
 

denj

Участник
Сообщения
23
Реакции
0
Просто убрать IsClientInGame в счётчиках. Однако, учти, что получить имя отключившегося игрока через индекс уже не получится. Придётся сохранять их заранее, при отключении, например.В твоём массиве тоже должна сохраняться, раз ты не обнуляешь его при отключении игрока.
массив обновляется при любой смерти на сервере.
А если убрать IsClientInGame, то в консоле пишет ошибку связанную с CS_GetClientContributionScore и все перестает работать)

Добавлено через 1 час 18 минут
Кто-нибудь знает где хранится статистика отключившегося игрока?
 
Последнее редактирование:

AlmazON

Не путать с самим yand3xmail
Сообщения
5,099
Реакции
2,755
где хранится статистика отключившегося игрока?
Лучше сохраняй всё в глобальный массив перед отключением игрока, а то и после каждой смерти, если итак задействуешь там подсчёт.
 
Сверху Снизу