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

[Levels Ranks] Lvl Show Info 2.5.2

Нет прав для скачивания
Сообщения
17
Реакции
14
Сообщения
417
Реакции
23
Всё работает, легко настраивается. Но является крайне унылой и не нужной хератой =)
 

Kruzya

Хам и грубиян
Супермодератор
Сообщения
7,683
Реакции
5,934
Кому как.
У меня подобное ещё более года назад заказывали для HLStatsX:CE. Но там просили только минимум информации: место в топе, кол-во киллов и смертей, и, что-то ещё было, но уже не вспомню.
 
Сообщения
540
Реакции
57
Всё работает, легко настраивается. Но является крайне унылой и не нужной хератой =)
Норм плагин) Давно искал такой, лично мне подобный нужен был с февраля)
--- Добавлено позже ---
Жаль нельзя настроить что именно будет отображаться, надеялся увидеть Опыт и номер в топе
 
Последнее редактирование:
Сообщения
168
Реакции
32
Сообщения
1,716
Реакции
1,325
Ждал пока @Faya™ опубликует свой плагин, чтобы потом его немного отредактировать под себя и использовать.
Итог: не дождался, написал сам. (Делаю под себя один сервер с системой lvl ranks)
upload_2019-4-17_3-5-3.png
Кстати, думал что он вроде как в привате от @RoadSide Romeo.
Давайте сначала пройдемся по коду @BaFeR .

PHP:
            iKill = LR_GetClientInfo(i, 2);
            iDeath = LR_GetClientInfo(i, 3);
            iAssists = LR_GetClientInfo(i, 7);
            iOnline = LR_GetClientInfo(i, 10);
 
            FormatEx(sHud, sizeof(sHud), "%N\nУБИЙСТВ: %i\nСМЕРТЕЙ: %i\nПОМОЩЬ: %i\nKDA: %0.1f\nОНЛАЙН: %i ч.",i , iKill, iDeath, iAssists, float(iKill)/float(iDeath), RoundToCeil(float(iOnline)/60.0/60.0));
 
 
            SetHudTextParams(g_fPostion[0], g_fPostion[1], g_fTimer + 0.1, g_iColors[0] , g_iColors[1], g_iColors[2], g_iColors[3], 2 , 0.0, 0.0, 0.0);
            ShowHudText(i, -1, sHud);
Это можно было вывести в отдельный паблик, у тебя один и тот же код используется два раза.

Пожалуйста войдите или зарегистрируйтесь чтобы видеть скрытый текст.

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

Зачем была подключена библиотека 'clientprefs'?

Получение KD игрока неправильное...
Что если у игрока n кол-во убийств и 0 смертей, делим, каков итог?

Для переменной 'g_bStatus' я бы создал отдельный цикл, а не использовал его в цикле.
Ну и забавный момент: if(iTarget != i) как можно наблюдать за собой?
Код идеальным никогда не будет :biggrin:

Теперь критикуем меня, с̶о̶б̶е̶н̶н̶о̶ ̶м̶н̶е̶ ̶Н̶Е̶ ̶н̶р̶а̶в̶и̶т̶с̶я̶ ̶'̶ф̶о̶р̶м̶а̶т̶и̶р̶о̶в̶а̶н̶и̶е̶'̶ ̶в̶р̶е̶м̶е̶н̶и̶ ̶и̶г̶р̶о̶к̶а̶. @Grey83

PHP:
#include <sourcemod>
#include <lvl_ranks>
#include <clientprefs>

public Plugin myinfo =
{
    name = "[LR] Players info",
    author = "Drumanid",
    version = "1.0.1",
    url = "Discord: Drumanid#9108"
};

Handle g_hCookie;
char g_sRanksInfo[19][32];
bool g_bUse[MAXPLAYERS +1];

#define SZF(%0) %0, sizeof(%0)
#define CyclePlayers(%0) for(int %0 = 1; %0 <= MaxClients; ++%0) if(IsClientInGame(%0))
public void OnPluginStart()
{
    // load translation file
    LoadTranslations("levels_ranks_playersinfo.phrases.txt");

    // Parser ranks info
    char sPath[64];
    BuildPath(Path_SM, SZF(sPath), "configs/levels_ranks/settings_ranks.ini");
    KeyValues hKeyValues = new KeyValues("LR_Settings");
    if(!hKeyValues.ImportFromFile(sPath))
        SetFailState("No found file: '%s'", sPath);

    hKeyValues.Rewind();
    if(!hKeyValues.JumpToKey("Ranks"))
        SetFailState("No found key: 'Ranks'", sPath);

    int iCount;
    hKeyValues.GotoFirstSubKey();
    do hKeyValues.GetString("name", g_sRanksInfo[iCount++], sizeof(g_sRanksInfo[]));
    while(hKeyValues.GotoNextKey());
    delete hKeyValues;

    // Update info
    CreateTimer(1.0, view_as<Timer>(TimerUpdate), _, TIMER_REPEAT);

    // Create cookie
    g_hCookie = RegClientCookie("levelranks_playerinfo", "On/off player information", CookieAccess_Private);

    // Load data players
    CyclePlayers(iClient)
        OnClientCookiesCached(iClient);
}

// Show info
#define KD(%0) float(%0 == 0 ? 1 : %0)
void TimerUpdate()
{
    int iTarget, iKills, iDeaths, iAssists, iSeconds;
    CyclePlayers(iClient)
    {
        if(g_bUse[iClient] && !IsFakeClient(iClient) && !IsPlayerAlive(iClient) && 3 < GetEntProp(iClient, Prop_Send, "m_iObserverMode") < 6 &&
        1 < (iTarget = GetEntPropEnt(iClient, Prop_Send, "m_hObserverTarget")) <= MaxClients && IsClientInGame(iTarget))
        {
            iKills = LR_GetClientInfo(iTarget, ST_KILLS);
            iDeaths = LR_GetClientInfo(iTarget, ST_DEATHS);
            iAssists = LR_GetClientInfo(iTarget, ST_ASSISTS);
            iSeconds = LR_GetClientInfo(iTarget, ST_PLAYTIME);

            PrintHintText(iClient, "%t", "Player information",  g_sRanksInfo[LR_GetClientInfo(iTarget, ST_RANK)],
                                                                LR_GetClientPos(iTarget),
                                                                LR_GetClientInfo(iTarget, ST_VALUE),
                                                                iKills,
                                                                iDeaths,
                                                                iAssists,
                                                                (KD(iKills) + float(iAssists / 2)) / KD(iDeaths),
                                                                LR_GetClientInfo(iTarget, ST_SHOOTS),
                                                                LR_GetClientInfo(iTarget, ST_HITS),
                                                                LR_GetClientInfo(iTarget, ST_HEADSHOTS),
                                                                iSeconds / 3600,
                                                                iSeconds / 60 %60,
                                                                iSeconds %60);
        }
    }
}

// Get info from cookie and record in variable
public void OnClientCookiesCached(int iClient)
{ 
    if(IsFakeClient(iClient))
        return;

    char sValue[4];
    GetClientCookie(iClient, g_hCookie, SZF(sValue));
    g_bUse[iClient] = sValue[0] && sValue[0] != '0';
}

// Add item in lvl menu
public void LR_OnMenuCreated(int iClient, Menu& hMenu)
{
    char sBuffer[64];
    FormatEx(SZF(sBuffer), "%T", g_bUse[iClient] ? "Item, on":"Item, off", iClient);
    hMenu.AddItem("playersinfo", sBuffer);
}

public void LR_OnMenuItemSelected(int iClient, const char[] sInfo)
{
    if(!StrEqual(sInfo, "playersinfo"))
        return;

    PrintToChat(iClient, "%t", (g_bUse[iClient] = !g_bUse[iClient]) ? "Message, on":"Message, off");
    LR_MenuInventory(iClient);
}

// Save data
public void OnClientDisconnect(int iClient)
{
    if(!IsFakeClient(iClient))
        SetClientCookie(iClient, g_hCookie, g_bUse[iClient] ? "1":"0");
}

public void OnPluginEnd()
{
    CyclePlayers(iClient)
        OnClientDisconnect(iClient);
}
Файл перевода:
Код:
"Phrases"
{
   "Player information"
   {
       // 1 - rank, 2 - top, 3 - score, 4 - kills, 5 - deaths, 6 - assists, 7 - kda, 8 - shoots, 9 - hits, 10 - headhshots, 11 - hours, 12 - minutes, 13 - seconds
       "#format"   "{1:s},{2:i},{3:i},{4:i},{5:i},{6:i},{7:.2f},{8:i},{9:i},{10:i},{11:i},{12:i},{13:i}"
 
       "en"       "Rank: {1} | Place in top: {2} | Score: {3}\nKills: {4} | Deaths: {5} | Assists: {6} | KDA: {7}\nPlayed: {11} hour(s) {12} minute(s) {13} second(s)"
       "ru"       "Ранг: {1} | Место в топе: {2} | Очки: {3}\nУбийств: {4} | Смертей: {5} | Содействий: {6} | KDA: {7}\nОтыграл: {11} час(а/ов) {12} минут(ы) {13} секунд(ы)"
   }
 
   "Item, on"
   {
       "en"       "Players information - [on]"
       "ru"       "Информация об игроках - [вкл]"
   }
 
   "Item, off"
   {
       "en"       "Players information - [off]"
       "ru"       "Информация об игроках - [выкл]"
   }
 
   "Message, on"
   {
       "en"       "Players information - on"
       "ru"       "Информация об игроках - включено"
   }
 
   "Message, off"
   {
       "en"       "Players information - off"
       "ru"       "Информация об игроках - выключено"
   }
}

/*
Rank: {1} | Place in top: {2} | Score: {3}\nKills: {4} | Deaths: {5} | Assists: {6} | KDA: {7}\nShoots: {8} | Hits: {9} | In the headshot: {10}\nPlayed: {11} hour(s) {12} minute(s) {13} second(s)
Ранг: {1} | Место в топе: {2} | Очки: {3}\nУбийств: {4} | Смертей: {5} | Содействий: {6} | KDA: {7}\nВыстрелов: {8} | Попаданий: {9} | В голову: {10}\nОтыграл: {11} час(а/ов) {12} минут(ы) {13} секунд(ы)
*/
Публиковать плагин как ресурс не буду, кто хочет сделает сам.
Поддержку плагина не оказываю, писал для себя.
Хотите убрать какую то информацию > редактируйте файл перевода.

Скриншот:
Counter-strike  Global Offensive Screenshot 2019.04.16 - 07.53.06.96.png
 

Вложения

Последнее редактирование:

Grey83

похухоль
Сообщения
2,973
Реакции
1,651
@Drumanid, чего вызывал?
PHP:
            while(iSeconds > 3600)
                ++iHours, iSeconds -= 3600;

            while(iSeconds > 60)
                ++iMinutes, iSeconds -= 60;
OMG :blink:я время разбивал вот так (где-то на форуме код уже выкладывал, но на винте найти быстрее):
PHP:
#pragma semicolon 1
#pragma newdecls required

static const char sName[][][] =
{
	{"день",	"дня",		"дней"},
	{"час",		"часа",		"часов"},
	{"минута",	"минуты",	"минут"},
	{"секунда",	"секунды",	"секунд"}
};

public void OnPluginStart()
{
	int time = GetTime() - 1471777116;
	PrintToServer("Время, которое прошло после написания поста:%s%s%s%s", NumToName(time/3600/24, 0), NumToName(time/3600%24, 1), NumToName(time/60%60, 2), NumToName(time%60, 3));
}

stock char NumToName(int num, const int type)
{
	static char buffer[PLATFORM_MAX_PATH];
	buffer[0] = 0;

	int form;
	switch(num)
	{
		case 0:		return buffer;
		case 1:		form = 0;
		case 2,3,4:	form = 1;
		default:
		{
			if(num < 21)	form = 2;
			else switch(num%10)
			{
				case 1:		form = 0;
				case 2,3,4:	form = 1;
				default:	form = 2;
			}
		}
	}
	FormatEx(buffer, sizeof(buffer), " %i %s", num, sName[type][form]);
	return buffer;
}
 
Сообщения
1,716
Реакции
1,325
@Drumanid, чего вызывал?
PHP:
            while(iSeconds > 3600)
                ++iHours, iSeconds -= 3600;

            while(iSeconds > 60)
                ++iMinutes, iSeconds -= 60;
OMG :blink:я время разбивал вот так (где-то на форуме код уже выкладывал, но на винте найти быстрее):
PHP:
#pragma semicolon 1
#pragma newdecls required

static const char sName[][][] =
{
    {"день",    "дня",        "дней"},
    {"час",        "часа",        "часов"},
    {"минута",    "минуты",    "минут"},
    {"секунда",    "секунды",    "секунд"}
};

public void OnPluginStart()
{
    int time = GetTime() - 1471777116;
    PrintToServer("Время, которое прошло после написания поста:%s%s%s%s", NumToName(time/3600/24, 0), NumToName(time/3600%24, 1), NumToName(time/60%60, 2), NumToName(time%60, 3));
}

stock char NumToName(int num, const int type)
{
    static char buffer[PLATFORM_MAX_PATH];
    buffer[0] = 0;

    int form;
    switch(num)
    {
        case 0:        return buffer;
        case 1:        form = 0;
        case 2,3,4:    form = 1;
        default:
        {
            if(num < 21)    form = 2;
            else switch(num%10)
            {
                case 1:        form = 0;
                case 2,3,4:    form = 1;
                default:    form = 2;
            }
        }
    }
    FormatEx(buffer, sizeof(buffer), " %i %s", num, sName[type][form]);
    return buffer;
}
Прекрасно. Обновил пост.
 

Grey83

похухоль
Сообщения
2,973
Реакции
1,651
%24 можно использовать, если выводишь дни (максимум, что у тебя может показать сейчас - 23 часа 59 минут 59 секунд, хоть наиграно сколько угодно больше времени)
--- Добавлено позже ---
кстати, дни - это iSeconds / 86400
--- Добавлено позже ---
по моему коду выдало только что
Время, которое прошло после написания поста: 968 дней 17 часов 9 минут 6 секунд
:ab:
--- Добавлено позже ---
KD(iKills) / KD(iDeaths) + float(iAssists / 2)
а разве ассист нужно не к убийствам прибавлять а уже потом всё делить на смерти?
Примерно так: (KD(iKills) + float(iAssists / 2)) / KD(iDeaths)
 
Последнее редактирование:
Сообщения
1,716
Реакции
1,325
%24 можно использовать, если выводишь дни (максимум, что у тебя может показать сейчас - 23 часа 59 минут 59 секунд, хоть наиграно сколько угодно больше времени)
--- Добавлено позже ---
кстати, дни - это iSeconds / 86400
--- Добавлено позже ---
по моему коду выдало только что:ab:
Судя по логике iSeconds / 31536000 - год.
а разве ассист нужно не к убийствам прибавлять а уже потом всё делить на смерти?
Примерно так: (KD(iKills) + float(iAssists / 2)) / KD(iDeaths)
Прозевал.
 

Grey83

похухоль
Сообщения
2,973
Реакции
1,651
FormatEx(SZF(sBuffer), "%t", g_bUse[iClient] ? "Item, on":"Item, off");
Наконец, существует вторая форма однострочного перевода, используя '%t'. Она допускается только в функциях, которые действуют непосредственно на одного или нескольких клиентов.
...
Таким образом, как правило, более удобны для использования ограниченные версии '%t' в функциях, таких как PrintToChat. Однако, в функциях, которые не "управляют игроком", таких, как Format или PrintToServer, может быть использован только '%T'.

Пожалуйста войдите или зарегистрируйтесь чтобы видеть скрытый текст.


%t используется если форматирование происходит после SetGlobalTransTarget.
Функция SetGlobalTransTarget устанавливает индекс игрока, для языка которого в данный момент будет выполняться форматирование. Если её аргумент равен 0 или LANG_SERVER то форматирование будет выполнено для языка сервера.
PHP:
SetGlobalTransTarget(iClient);
FormatEx(szBuffer, sizeof(szBuffer), "Перевод: %t", "MyPhrase", 123, "my_string", 22.4);
В функциях PrintToChat, PrintToChatAll, PrintCenterText, PrintCenterTextAll, PrintHintText, PrintHintTextToAll присутствует функция SetGlobalTransTarget, поэтому при форматировании текста в них нужно писать %t.
--- Добавлено позже ---
@Drumanid, если не високосный, то да
--- Добавлено позже ---
PHP:
    char sValue[4];
    IntToString(view_as<int>(g_bUse[iClient]), SZF(sValue));
    SetClientCookie(iClient, g_hCookie, sValue);
а не проще было бы просто вот так: SetClientCookie(iClient, g_hCookie, g_bUse[iClient] ? "1" : "0"); ?
--- Добавлено позже ---
Вот это: g_bUse[iClient] = sValue[0] ? view_as<bool>(StringToInt(sValue)):true;
я бы тоже упростил бы до g_bUse[iClient] = sValue[0] && sValue[0] != '0';
Получилось бы то же самое
 
Последнее редактирование:
Сообщения
1,716
Реакции
1,325
@Grey83 красиво, нанес косметику :biggrin:
Кстаааааааати, надо было добавить проверку на ботов...
--- Добавлено позже ---
Вот теперь огонь.
 
Последнее редактирование:

DeeperSpy

Гений, миллиардер, плейбой, филантроп, майнкрафтер
Сообщения
428
Реакции
187
А почему ядро, ядра ведь нету
upload_2019-4-29_14-5-25.png
 
Сообщения
200
Реакции
34
@Grey83 красиво, нанес косметику :biggrin:
Кстаааааааати, надо было добавить проверку на ботов...
--- Добавлено позже ---
Вот теперь огонь.
Пожалуйста , подскажите как сделать так, чтобы для впервые вошедшего игрока показ инфы был ВКЛЮЧЕН , и не нужно было сначала запустить его из меню . Пробовала сама найти, никак ...
 

KonveeR

Кон Чен Ый
Сообщения
1,235
Реакции
381
#include <sourcemod>
#include <lvl_ranks>
#include <clientprefs>

public Plugin myinfo =
{
name = "[LR] Players info",
author = "Drumanid",
version = "1.0.1",
url = "Discord: Drumanid#9108"
};

Handle g_hCookie;
char g_sRanksInfo[19][32];
bool g_bUse[MAXPLAYERS +1];

#define SZF(%0) %0, sizeof(%0)
#define CyclePlayers(%0) for(int %0 = 1; %0 <= MaxClients; ++%0) if(IsClientInGame(%0))

public void OnPluginStart()
{
// load translation file
LoadTranslations("levels_ranks_playersinfo.phrases.txt");

// Parser ranks info
char sPath[64];
BuildPath(Path_SM, SZF(sPath), "configs/levels_ranks/settings_ranks.ini");
KeyValues hKeyValues = new KeyValues("LR_Settings");
if(!
hKeyValues.ImportFromFile(sPath))
SetFailState("No found file: '%s'", sPath);

hKeyValues.Rewind();
if(!
hKeyValues.JumpToKey("Ranks"))
SetFailState("No found key: 'Ranks'", sPath);

int iCount;
hKeyValues.GotoFirstSubKey();
do
hKeyValues.GetString("name", g_sRanksInfo[iCount++], sizeof(g_sRanksInfo[]));
while(
hKeyValues.GotoNextKey());
delete hKeyValues;

// Update info
CreateTimer(1.0, view_as<Timer>(TimerUpdate), _, TIMER_REPEAT);

// Create cookie
g_hCookie = RegClientCookie("levelranks_playerinfo", "On/off player information", CookieAccess_Private);

// Load data players
CyclePlayers(iClient)
OnClientCookiesCached(iClient);
}

// Show info
#define KD(%0) float(%0 == 0 ? 1 : %0)

void TimerUpdate()
{
int iTarget, iKills, iDeaths, iAssists, iSeconds;
CyclePlayers(iClient)
{
if(
g_bUse[iClient] && !IsFakeClient(iClient) && !IsPlayerAlive(iClient) && 3 < GetEntProp(iClient, Prop_Send, "m_iObserverMode") < 6 &&
1 < (iTarget = GetEntPropEnt(iClient, Prop_Send, "m_hObserverTarget")) <= MaxClients && IsClientInGame(iTarget))
{
iKills = LR_GetClientInfo(iTarget, ST_KILLS);
iDeaths = LR_GetClientInfo(iTarget, ST_DEATHS);
iAssists = LR_GetClientInfo(iTarget, ST_ASSISTS);
iSeconds = LR_GetClientInfo(iTarget, ST_PLAYTIME);

PrintHintText(iClient, "%t", "Player information", g_sRanksInfo[LR_GetClientInfo(iTarget, ST_RANK)],
LR_GetClientPos(iTarget),
LR_GetClientInfo(iTarget, ST_VALUE),
iKills,
iDeaths,
iAssists,
(
KD(iKills) + float(iAssists / 2)) / KD(iDeaths),
LR_GetClientInfo(iTarget, ST_SHOOTS),
LR_GetClientInfo(iTarget, ST_HITS),
LR_GetClientInfo(iTarget, ST_HEADSHOTS),
iSeconds / 3600,
iSeconds / 60 %60,
iSeconds %60);
}
}
}

// Get info from cookie and record in variable
public void OnClientCookiesCached(int iClient)
{
if(
IsFakeClient(iClient))
return;

char sValue[4];
GetClientCookie(iClient, g_hCookie, SZF(sValue));
g_bUse[iClient] = sValue[0] && sValue[0] != '0';
}

// Add item in lvl menu
public void LR_OnMenuCreated(int iClient, Menu& hMenu)
{
char sBuffer[64];
FormatEx(SZF(sBuffer), "%T", g_bUse[iClient] ? "Item, on":"Item, off", iClient);
hMenu.AddItem("playersinfo", sBuffer);
}

public
void LR_OnMenuItemSelected(int iClient, const char[] sInfo)
{
if(!
StrEqual(sInfo, "playersinfo"))
return;

PrintToChat(iClient, "%t", (g_bUse[iClient] = !g_bUse[iClient]) ? "Message, on":"Message, off");
LR_MenuInventory(iClient);
}

// Save data
public void OnClientDisconnect(int iClient)
{
if(!
IsFakeClient(iClient))
SetClientCookie(iClient, g_hCookie, g_bUse[iClient] ? "1":"0");
}

public
void OnPluginEnd()
{
CyclePlayers(iClient)
OnClientDisconnect(iClient);
}
Можешь его под новое ядро переписать?
 

Kruzya

Хам и грубиян
Супермодератор
Сообщения
7,683
Реакции
5,934
@KonveeR, эти две строчки добавь:
C++:
#define LR_GetClientPos(%0) LR_GetClientInfo(%0, ST_PLACEINTOP)
#define ST_VALUE ST_EXP
Перед:
C++:
public void OnPluginStart()
 

KonveeR

Кон Чен Ый
Сообщения
1,235
Реакции
381
@Крузяра, Кстати еще проблемка есть:
Раньше название рангов бралось из ( addons/sourcemod/configs/levels_ranks/settings_ranks.ini )
В новом же ядре есть отдельный файл перевода , и плагин не может вывести название рангов (
 

Kruzya

Хам и грубиян
Супермодератор
Сообщения
7,683
Реакции
5,934
@KonveeR, вообще, дело поправимое.
В OnPluginStart() вписать где-нибудь:
C++:
LoadTranslations("имя_файла_с_именами_рангов_без_расширения"); // например lr_ranks.phrases
Смотрим далее, каким по счёту идёт в файле переводов самого модуля аргумент с номером ранга, и там же, в #format, меняем у этой цифры тип аргумента s на t.
Как-то так.

После всех изменений лучше перезагрузить сервер, поскольку он кеширует файлы переводов.
 
Сообщения
1,716
Реакции
1,325
Можешь его под новое ядро переписать?
PHP:
#include <sourcemod>
#include <lvl_ranks>
#include <clientprefs>

public Plugin myinfo =
{
    name = "[LR] Players info",
    author = "Drumanid",
    version = "1.0.2",
    url = "Discord: Drumanid#9108"
};

Handle g_hCookie;
char g_sRanksInfo[19][32];
bool g_bUse[MAXPLAYERS +1];

#define SZF(%0) %0, sizeof(%0)
#define CyclePlayers(%0) for(int %0 = 1; %0 <= MaxClients; ++%0) if(IsClientInGame(%0))
public void OnPluginStart()
{
    // load translation file
    LoadTranslations("lr_core_ranks.phrases");
    LoadTranslations("levels_ranks_playersinfo.phrases.txt");

    // Parser ranks info
    char sPath[64];
    BuildPath(Path_SM, SZF(sPath), "configs/levels_ranks/settings_ranks.ini");
    KeyValues hKeyValues = new KeyValues("LR_Settings");
    if(!hKeyValues.ImportFromFile(sPath))
        SetFailState("No found file: '%s'", sPath);

    hKeyValues.Rewind();
    if(!hKeyValues.JumpToKey("Ranks"))
        SetFailState("No found key: 'Ranks'", sPath);

    int iCount = 1;
    g_sRanksInfo[0] = "NONE";
    hKeyValues.GotoFirstSubKey();
    do hKeyValues.GetSectionName(g_sRanksInfo[iCount++], sizeof(g_sRanksInfo[]));
    while(hKeyValues.GotoNextKey());
    delete hKeyValues;

    // Update info
    CreateTimer(1.0, view_as<Timer>(TimerUpdate), _, TIMER_REPEAT);

    // Create cookie
    g_hCookie = RegClientCookie("levelranks_playerinfo", "On/off player information", CookieAccess_Private);

    // Load data players
    CyclePlayers(iClient)
        OnClientCookiesCached(iClient);
}

// Show info
#define KD(%0) float(%0 == 0 ? 1 : %0)
void TimerUpdate()
{
    char sRank[64];
    int iTarget, iKills, iDeaths, iAssists, iSeconds;
    CyclePlayers(iClient)
    {
        if(g_bUse[iClient] && !IsFakeClient(iClient) && !IsPlayerAlive(iClient) && 3 < GetEntProp(iClient, Prop_Send, "m_iObserverMode") < 6 &&
        1 < (iTarget = GetEntPropEnt(iClient, Prop_Send, "m_hObserverTarget")) <= MaxClients && IsClientInGame(iTarget))
        {
            FormatEx(SZF(sRank), "%T", g_sRanksInfo[LR_GetClientInfo(iTarget, ST_RANK)], iClient);

            iKills = LR_GetClientInfo(iTarget, ST_KILLS);
            iDeaths = LR_GetClientInfo(iTarget, ST_DEATHS);
            iAssists = LR_GetClientInfo(iTarget, ST_ASSISTS);
            iSeconds = LR_GetClientInfo(iTarget, ST_PLAYTIME);

            PrintHintText(iClient, "%t", "Player information", sRank,
                                                                LR_GetClientInfo(iTarget, ST_PLACEINTOP),
                                                                LR_GetClientInfo(iTarget, ST_EXP),
                                                                iKills,
                                                                iDeaths,
                                                                iAssists,
                                                                (KD(iKills) + float(iAssists / 2)) / KD(iDeaths),
                                                                LR_GetClientInfo(iTarget, ST_SHOOTS),
                                                                LR_GetClientInfo(iTarget, ST_HITS),
                                                                LR_GetClientInfo(iTarget, ST_HEADSHOTS),
                                                                iSeconds / 3600,
                                                                iSeconds / 60 %60,
                                                                iSeconds %60);
        }
    }
}

// Get info from cookie and record in variable
public void OnClientCookiesCached(int iClient)
{
    if(IsFakeClient(iClient))
        return;

    char sValue[4];
    GetClientCookie(iClient, g_hCookie, SZF(sValue));
    g_bUse[iClient] = sValue[0] ? view_as<bool>(StringToInt(sValue)):true;
}

// Add item in lvl menu
public void LR_OnMenuCreated(int iClient, Menu& hMenu)
{
    char sBuffer[64];
    FormatEx(SZF(sBuffer), "%T", g_bUse[iClient] ? "Item, on":"Item, off", iClient);
    hMenu.AddItem("playersinfo", sBuffer);
}

public void LR_OnMenuItemSelected(int iClient, const char[] sInfo)
{
    if(!StrEqual(sInfo, "playersinfo"))
        return;

    PrintToChat(iClient, "%t", (g_bUse[iClient] = !g_bUse[iClient]) ? "Message, on":"Message, off");
    LR_MenuInventory(iClient);
}

// Save data
public void OnClientDisconnect(int iClient)
{
    if(!IsFakeClient(iClient))
        SetClientCookie(iClient, g_hCookie, g_bUse[iClient] ? "1":"0");
}

public void OnPluginEnd()
{
    CyclePlayers(iClient)
        OnClientDisconnect(iClient);
}
 

Вложения

Последнее редактирование:
Сверху