Переделываем плагин на ReAPI

Сообщения
2,491
Реакции
2,790
Помог
61 раз(а)
Итак, на старте мы имеем плагин https://dev-cs.ru/threads/2953/
Как же нам переделать его на ReAPI + AmxModX 1.8.3, а также исправить множество баг и косяков?
Код:
#include <amxmodx>
#include <amxmisc>
#include <cstrike>
#include <hamsandwich>
#include <fakemeta>
#include <ColorChat>
#include <aes_main>

enum _:score
{
    frags,
    Float:dmg,
    hs
}

new niceP[33][score]

new Aesopt
new g_iMaxPlayers

public plugin_init()
{
    register_plugin("BestAes", "1.0", "") //Исходник [*J*]

    RegisterHam(Ham_TakeDamage, "player", "hook_TakeDamage")
    register_event("DeathMsg", "Event_DeathMessage", "a")
    register_logevent("event_round_end", 2, "1=Round_End")
    register_event("HLTV", "event_round_start", "a", "1=0", "2=0")
    Aesopt    = register_cvar("nkiller_aes", "10")
    g_iMaxPlayers = get_maxplayers()
    return 0;

}

public event_round_end ()
{
    new Players[32], num, tmpf, Float:tmpd, tmpid
    get_players( Players, num )

    for( new i; i < 32; i++)
    {
        if ( niceP[i][frags] > tmpf )
        {
            tmpid = i
            tmpf = niceP[i][frags]
            tmpd = niceP[i][dmg]
        }
        else if ( niceP[i][frags] == tmpf && niceP[i][dmg] > tmpd)
        {
            tmpid = i
            tmpf = niceP[i][frags]
            tmpd = niceP[i][dmg]
        }
    }

    if ( tmpf > 0 )
    {
        new name[32]
        get_user_name(tmpid, name, 31);
  
        aes_add_player_exp(tmpid, tmpf*get_pcvar_num(Aesopt) )
        for(new ids = 1; ids <= g_iMaxPlayers; ids++)
        {
        ColorChat( ids, NORMAL, "[^x4Сервер^x1] Самый лучший игрок раунда ^x3%s^x1 получил^x4 %d^x1 опыта, убив ^x4%d^x1 игроков!", name, tmpf * get_pcvar_num(Aesopt), tmpf)
        }
  
    }
}

public hook_TakeDamage(Victim, inflictor, Attacker, Float:damage, damagebits)
{
    if( inflictor == Attacker )
        niceP[Attacker][dmg] += damage
    else
    {
        static classname[32]
        pev (inflictor, pev_classname, classname, 31)
        if( equal (classname, "grenade") )
            niceP[Attacker][dmg] += damage
    }

    if ( get_pdata_int(Victim, 75, 5) == HIT_HEAD )
        niceP[Attacker][hs]++

    return HAM_IGNORED
}

public Event_DeathMessage()
    niceP[read_data(1)][frags]++

public event_round_start ( )
    for (new i; i < 32; i++)
        for ( new j; j < 3; j++)
            niceP[i][j] = 0

public client_disconnected(id)
    for ( new j; j < 3; j++)
        niceP[id][j] = 0
Для начала давайте отформатируем код и переименуем все переменные на более красивые и понятные
Diff:
- #include < amxmodx >
- #include < amxmisc >
- #include < cstrike >
- #include < hamsandwich >
- #include < fakemeta >
- #include < ColorChat >
- #include < aes_main >
+ #include <amxmodx>
+ #include <amxmisc>
+ #include <cstrike>
+ #include <hamsandwich>
+ #include <fakemeta>
+ #include <ColorChat>
+ #include <aes_main>
 
- enum _:score
- {
+ enum _:score {
    frags,
    Float:dmg,
    hs
  }
 
- new niceP[33][score]
+ new g_PlayersData[33][score];
 
- new Aesopt
- new g_iMaxPlayers
+ new pcv_Aesopt;
+ new g_iMaxPlayers;
 
- public plugin_init()
- {
-   register_plugin("BestAes", "1.0", "") //Исходник [*J*]
+ public plugin_init(){
+   register_plugin("BestAes", "1.0", "");
 
-   RegisterHam(Ham_TakeDamage, "player", "hook_TakeDamage")
-   register_event("DeathMsg", "Event_DeathMessage", "a")
-   register_logevent("event_round_end", 2, "1=Round_End")
-   register_event("HLTV", "event_round_start", "a", "1=0", "2=0")
-   Aesopt  = register_cvar("nkiller_aes", "10")
-   g_iMaxPlayers = get_maxplayers()
+   RegisterHam(Ham_TakeDamage, "player", "hook_TakeDamage");
+   register_event("DeathMsg", "Event_DeathMessage", "a");
+   register_logevent("event_round_end", 2, "1=Round_End");
+   register_event("HLTV", "event_round_start", "a", "1=0", "2=0");
+   pcv_Aesopt    = register_cvar("nkiller_aes", "10");
+   g_iMaxPlayers = get_maxplayers();
    return 0;
-  
  }
 
- public event_round_end ()
- {
-   new Players[32], num, tmpf, Float:tmpd, tmpid
-   get_players( Players, num )
+ public event_round_end () {
+   new players[32], num, tmpf, Float:tmpd, tmpid;
+   get_players(players, num);
 
-   for( new i; i < 32; i++)
-   {
-     if ( niceP[i][frags] > tmpf )
-     {
-       tmpid = i
-       tmpf = niceP[i][frags]
-       tmpd = niceP[i][dmg]
-     }
-     else if ( niceP[i][frags] == tmpf && niceP[i][dmg] > tmpd)
-     {
+   for (new i; i < 32; i++) {
+     if (g_PlayersData[i][frags] > tmpf) {
+       tmpid = i;
+       tmpf = g_PlayersData[i][frags];
+       tmpd = g_PlayersData[i][dmg];
+     } else if (g_PlayersData[i][frags] == tmpf && g_PlayersData[i][dmg] > tmpd) {
        tmpid = i;
-       tmpf = niceP[i][frags];
-       tmpd = niceP[i][dmg];
+       tmpf = g_PlayersData[i][frags];
+       tmpd = g_PlayersData[i][dmg];
      }
    }
 
-   if ( tmpf > 0 )
-   {
-     new name[32]
+   if (tmpf > 0) {
+     new name[32];
      get_user_name(tmpid, name, 31);
-    
-     aes_add_player_exp(tmpid, tmpf*get_pcvar_num(Aesopt) )
-     for(new ids = 1; ids <= g_iMaxPlayers; ids++)
-     {
-     ColorChat( ids, NORMAL, "[^x4Сервер^x1] Самый лучший игрок раунда ^x3%s^x1 получил^x4 %d^x1 опыта, убив ^x4%d^x1 игроков!", name, tmpf * get_pcvar_num(Aesopt), tmpf)
+   
+     aes_add_player_exp(tmpid, tmpf * get_pcvar_num(pcv_Aesopt));
+     for (new id = 1; id <= g_iMaxPlayers; id++) {
+       ColorChat(id, NORMAL, "[^x4Сервер^x1] Самый лучший игрок раунда ^x3%s^x1 получил^x4 %d^x1 опыта, убив ^x4%d^x1 игроков!", name, tmpf * get_pcvar_num(pcv_Aesopt), tmpf);
      }
-    
+   
    }
  }
 
- public hook_TakeDamage(Victim, inflictor, Attacker, Float:damage, damagebits)
- {
-   if( inflictor == Attacker )
-     niceP[Attacker][dmg] += damage
-   else
-   {
-     static classname[32]
-     pev (inflictor, pev_classname, classname, 31)
-     if( equal (classname, "grenade") )
-       niceP[Attacker][dmg] += damage
+ public hook_TakeDamage(victim, inflictor, attacker, Float:damage, damagebits) {
+   if (inflictor == attacker ) {
+     g_PlayersData[attacker][dmg] += damage;
+   } else {
+     static classname[32];
+     pev (inflictor, pev_classname, classname, 31);
+     if (equal (classname, "grenade")) {
+       g_PlayersData[attacker][dmg] += damage;
+     }
    }
 
-   if ( get_pdata_int(Victim, 75, 5) == HIT_HEAD )
-     niceP[Attacker][hs]++
+   if (get_pdata_int(victim, 75, 5) == HIT_HEAD) {
+     g_PlayersData[attacker][hs]++;
+   }
 
-   return HAM_IGNORED
+   return HAM_IGNORED;
  }
 
- public Event_DeathMessage()
-   niceP[read_data(1)][frags]++
+ public Event_DeathMessage() {
+   g_PlayersData[read_data(1)][frags]++;
+ }
 
- public event_round_start ( )
-   for (new i; i < 32; i++)
-     for ( new j; j < 3; j++)
-       niceP[i][j] = 0
+ public event_round_start() {
+   for (new i; i < 32; i++) {
+     for (new j; j < 3; j++) {
+       g_PlayersData[i][j] = 0;
+     }
+   }
+ }
 
- public client_disconnected(id)
-   for ( new j; j < 3; j++)
-     niceP[id][j] = 0
+ public client_disconnected(id) {
+   for (new j; j < 3; j++) {
+     g_PlayersData[id][j] = 0;
+   }
+ }
Можно заметить, что модуль cstrike и инклуд amxmisc нигде по коду не используются. Проверить это легко: закомментируем две строчки и пробуем откомпилить. Если компилятор не выдал ошибки, значит их можно убрать.
Diff:
- #include <amxmisc>
- #include <cstrike>
Далее уберем include колорчата, так как он уже есть в AmxModX 1.8.3. Для этого достаточно ColorChat(id, color, message[]) заменить на client_print_color(id, color, message[]). Стоит учесть, что цвет задается через enum или указывается id игрока
Diff:
- #include <ColorChat>
- ColorChat(id, NORMAL, "[^x4Сервер^x1] Самый лучший игрок раунда ^x3%s^x1 получил^x4 %d^x1 опыта, убив ^x4%d^x1 игроков!", name, tmpf * get_pcvar_num(pcv_Aesopt), tmpf);
+ client_print_color(id, print_team_default, "[^4Сервер^1] Самый лучший игрок раунда ^3%s^1 получил^x4 %d^1 опыта, убив ^4%d^1 игроков!", name, tmpf * get_pcvar_num(pcv_Aesopt), tmpf);
В AES 0.5 версии новый include aes_v вместо aes_main. Заменяем. Также в новой версии убрали натив aes_add_player_exp. Для этого используем связку aes_set_player_exp(id, aes_get_player_exp(id) + amount)
Diff:
- #include <aes_main>
+ #include <aes_v>
- aes_add_player_exp(tmpid, tmpf * get_pcvar_num(pcv_Aesopt));
+ aes_set_player_exp(tmpid, aes_get_player_exp(tmpid) + tmpf * get_pcvar_num(pcv_Aesopt));
Посмотрим на цикл
Код:
for (new i; i < 32; i++) {
  for (new j; j < 3; j++) {
    g_PlayersData[i][j] = 0;
  }
}
Стоит отметить что тут присутствует бага. Слотов на сервере максимально 32. Но в данном примере мы никогда не обнулим последний 32-ой слот. А значит со временем игрок под этим индексом всегда будет в топе. Потому стоит заменить i < 32 на i <= 32
Избавляемся от захардкодженного числа 32. В 1.8.3 присутствует глобальная переменная MaxClients которая равна максимальному числу слотов на сервере и идентична результату get_maxplayers. Еще один момент это начальный индекс, игроки начинаются с 1 вместо 0. Теперь мы можем проходить не все 33 элемента, а только те, которые реально нужны.
Diff:
- for (new i; i < 32; i++) {
+ for (new i = 1; i <= MaxClients; i++) {
    for (new j; j < 3; j++) {
      g_PlayersData[i][j] = 0;
    }
  }
Далее нам не нужен внутренний цикл. Ведь у нас есть замечательный натив arrayset
Diff:
  for (new i = 1; i <= MaxClients; i++) {
-   for (new j; j < 3; j++) {
-     g_PlayersData[i][j] = 0;
-   }
+   arrayset(g_PlayersData[i], 0, score);
  }
То же самое проделываем и с хуком дисконнекта игрока
Diff:
  public client_disconnected(id) {
-   for (new j; j < 3; j++) {
-     g_PlayersData[id][j] = 0;
-   }
+   arrayset(g_PlayersData[id], 0, score);
  }
Движемся дальше. Для отправки всем игрокам сообщения в чат. Достаточно указать вместо id игрока 0. Убираем цикл.
Diff:
- for (new id = 1; id <= g_iMaxPlayers; id++) {
-   client_print_color(id, print_team_default, "[^4Сервер^x1] Самый лучший игрок раунда ^3%s^1 получил^4 %d^1 опыта, убив ^4%d^1 игроков!", name, tmpf * get_pcvar_num(pcv_Aesopt), tmpf);
- }
+ client_print_color(0, print_team_default, "[^4Сервер^x1] Самый лучший игрок раунда ^3%s^1 получил^4 %d^1 опыта, убив ^4%d^1 игроков!", name, tmpf * get_pcvar_num(pcv_Aesopt), tmpf);
Компилятор подсказывает, что мы больше нигде не используем переменную g_iMaxPlayers. Убираем.
Diff:
- new g_iMaxPlayers;
- g_iMaxPlayers = get_maxplayers();
Переходим к коду расчета топа по урону. Тут есть множество багов.
Код:
new players[32], num, tmpf, Float:tmpd, tmpid;
get_players(players, num);

for (new i; i < 32; i++) {
  if (g_PlayersData[i][frags] > tmpf) {
    tmpid = i;
    tmpf = g_PlayersData[i][frags];
    tmpd = g_PlayersData[i][dmg];
  } else if (g_PlayersData[i][frags] == tmpf && g_PlayersData[i][dmg] > tmpd) {
    tmpid = i;
    tmpf = g_PlayersData[i][frags];
    tmpd = g_PlayersData[i][dmg];
  }
}
Во-первых, используя get_players в переменной num, мы получаем количество игроков в массиве players, которое нам возвращает натив. И, оно, как правило ниже числа 32, значит мы всегда обходим много невалидных игроков. Во вторых, массив players содержит индексы игроков и использовать переменную итерации i - грубая ошибка. Дополнительно для get_players укажем флаг h, который пропустит HLTV (ведь он не может нанести урон). Исправляем
Diff:
  new players[32], num, tmpf, Float:tmpd, tmpid;
- get_players(players, num);
+ get_players(players, num, "h");
 
- for (new i; i < 32; i++) {
-   if (g_PlayersData[i][frags] > tmpf) {
-     tmpid = i;
-     tmpf = g_PlayersData[i][frags];
-     tmpd = g_PlayersData[i][dmg];
-   } else if (g_PlayersData[i][frags] == tmpf && g_PlayersData[i][dmg] > tmpd) {
-     tmpid = i;
-     tmpf = g_PlayersData[i][frags];
-     tmpd = g_PlayersData[i][dmg];
+ for (new i, player; i < num; i++) {
+   player = players[i];
+   if (g_PlayersData[player][frags] > tmpf) {
+     tmpid = player;
+     tmpf = g_PlayersData[player][frags];
+     tmpd = g_PlayersData[player][dmg];
+   } else if (g_PlayersData[player][frags] == tmpf && g_PlayersData[player][dmg] > tmpd) {
+     tmpid = player;
+     tmpf = g_PlayersData[player][frags];
+     tmpd = g_PlayersData[player][dmg];
    }
  }
Заодно видим что в plugin_init присутствует return 0;. Он там не нужен, Убираем
Diff:
- return 0;
Теперь переходим к самому ReAPI. Малой кровью нам удастся заменить хук TakeDamage.
Достаточно RegisterHam заменить на RegisterHookChain и Ham_TakeDamage на RG_CBasePlayer_TakeDamage. Не стоит забывать, что у HAM модуля в хуке вторым аргументом указывается classname, а в ReAPI указывать класс player не нужно.
Также стоит исправить недочет автора плагина, который делает PRE хук. Так как нанесение урона может быть заблокировано другим плагином, то нам обязательно нужен POST хук. Для этого последним аргументом указываем true. Также заменяем return HAM_IGNORED на return HC_CONTINUE. Сразу переименуем callback хука с hook_TakeDamage на CBasePlayer_TakeDamage.
Diff:
- RegisterHam(Ham_TakeDamage, "player", "hook_TakeDamage");
+ RegisterHookChain(RG_CBasePlayer_TakeDamage, "CBasePlayer_TakeDamage", true);
 
- public hook_TakeDamage(victim, inflictor, attacker, Float:damage, damagebits) {
+ public CBasePlayer_TakeDamage(victim, inflictor, attacker, Float:damage, damagebits) {
    if (inflictor == attacker ) {
      g_PlayersData[attacker][dmg] += damage;
    } else {
      static classname[32];
      pev (inflictor, pev_classname, classname, 31);
      if (equal (classname, "grenade")) {
        g_PlayersData[attacker][dmg] += damage;
      }
    }
 
    if (get_pdata_int(victim, 75, 5) == HIT_HEAD) {
      g_PlayersData[attacker][hs]++;
    }
 
-   return HAM_IGNORED;
+   return HC_CONTINUE;
  }
Также сразу исправим баг с невалидным атакующим. Для этого достаточно добавить проверку is_user_conencted, и, если он не валиден, завершаем функцию через return.
Еще одна бага получится у нас, если игрок сам себе нанесет урон (например падение с высоты). Такой урон не должен учитываться. Чтобы исключить такое, достаточно проверить совпадает ли ID игрока с ID атакующего.
Diff:
  public CBasePlayer_TakeDamage(victim, inflictor, attacker, Float:damage, damagebits) {
+   if (!is_user_connected(attacker) || victim == attacker) {
+         return HC_CONTINUE;
+     }
+
    if (inflictor == attacker ) {
      g_PlayersData[attacker][dmg] += damage;
    } else {
      static classname[32];
      pev (inflictor, pev_classname, classname, 31);
      if (equal (classname, "grenade")) {
        g_PlayersData[attacker][dmg] += damage;
      }
    }
 
    if (get_pdata_int(victim, 75, 5) == HIT_HEAD) {
      g_PlayersData[attacker][hs]++;
    }
 
    return HC_CONTINUE;
  }
Давайте сразу же избавимся от модуля fakemeta, который используется только в одном месте. В ReAPI есть уже отличный натив для проверки класснейма FClassnameIs. Тем самым мы упрощаем наш код до следующего:
Diff:
  public CBasePlayer_TakeDamage(victim, inflictor, attacker, Float:damage, damagebits) {
    if (!is_user_connected(attacker) || victim == attacker) {
          return HC_CONTINUE;
      }
 
    if (inflictor == attacker ) {
      g_PlayersData[attacker][dmg] += damage;
-   } else {
-     static classname[32];
-     pev (inflictor, pev_classname, classname, 31);
-     if (equal (classname, "grenade")) {
-       g_PlayersData[attacker][dmg] += damage;
-     }
+   } else if (FClassnameIs(inflictor, "grenade")) {
+     g_PlayersData[attacker][dmg] += damage;
    }
 
    if (get_pdata_int(victim, 75, 5) == HIT_HEAD) {
      g_PlayersData[attacker][hs]++;
    }
 
    return HC_CONTINUE;
  }
Но мы пойдем еще дальше, и вместо сравнения класснеймов мы воспользуемся проверкой битсумы damagebits на присутствие бита DMG_GRENADE.
Diff:
  public CBasePlayer_TakeDamage(victim, inflictor, attacker, Float:damage, damagebits) {
    if (!is_user_connected(attacker) || victim == attacker) {
          return HC_CONTINUE;
      }
 
-   if (inflictor == attacker ) {
-     g_PlayersData[attacker][dmg] += damage;
-   } else if (FClassnameIs(inflictor, "grenade")) {
-     g_PlayersData[attacker][dmg] += damage;
-   }
+   if (inflictor == attacker || damagebits & DMG_GRENADE) {
+         g_PlayersData[attacker][dmg] += damage;
+     }
 
    if (get_pdata_int(victim, 75, 5) == HIT_HEAD) {
      g_PlayersData[attacker][hs]++;
    }
 
    return HC_CONTINUE;
  }
Дело осталось за малым. Проверка на попадание в голову. Для этого есть мембер m_LastHitGroup.
Diff:
  public CBasePlayer_TakeDamage(victim, inflictor, attacker, Float:damage, damagebits) {
    if (!is_user_connected(attacker) || victim == attacker) {
          return HC_CONTINUE;
      }
 
    if (inflictor == attacker || damagebits & DMG_GRENADE) {
          g_PlayersData[attacker][dmg] += damage;
      }
 
-   if (get_pdata_int(victim, 75, 5) == HIT_HEAD) {
+   if (get_member(victim, m_LastHitGroup) == HIT_HEAD) {
      g_PlayersData[attacker][hs]++;
    }
 
    return HC_CONTINUE;
  }
Убираем модули fakemeta и hamsandwich, так как больше они нигде не используются, а также добавляем ReAPI.
Diff:
- #include <hamsandwich>
- #include <fakemeta>
+ #include <reapi>
Теперь давайте заменим хук конца раунда на хук из ReAPI.
Diff:
- register_logevent("event_round_end", 2, "1=Round_End");
+ RegisterHookChain(RG_RoundEnd, "RoundEnd", true);
 
- public event_round_end () {
+ public RoundEnd () {
    // ...
  }
Тут сразу возможна оптимизация: вместо обнуления в новом раунде всех игроков, мы можем в хуке конца раунда добавить обнуление.
Diff:
- register_event("HLTV", "event_round_start", "a", "1=0", "2=0");
-
  public RoundEnd () {
    new players[32], num, tmpf, Float:tmpd, tmpid;
    get_players(players, num, "h");
 
    for (new i, player; i < num; i++) {
      player = players[i];
      if (g_PlayersData[player][frags] > tmpf) {
        tmpid = player;
        tmpf = g_PlayersData[player][frags];
        tmpd = g_PlayersData[player][dmg];
      } else if (g_PlayersData[player][frags] == tmpf && g_PlayersData[player][dmg] > tmpd) {
        tmpid = palyer;
        tmpf = g_PlayersData[player][frags];
        tmpd = g_PlayersData[player][dmg];
      }
    }
 
    if (tmpf > 0) {
      new name[32];
      get_user_name(tmpid, name, 31);
    
      aes_set_player_exp(tmpid, aes_get_player_exp(tmpid) + tmpf * get_pcvar_num(pcv_Aesopt));
      client_print_color(0, print_team_default, "[^4Сервер^1] Самый лучший игрок раунда ^3%s^1 получил^x4 %d^1 опыта, убив ^4%d^1 игроков!", name, tmpf * get_pcvar_num(pcv_Aesopt), tmpf);
    }

+   for (new i = 1; i <= MaxClients; i++) {
+     arrayset(g_PlayersData[i], 0, score);
+   }
  }
 
- public event_round_start() {
-   for (new i = 1; i <= MaxClients; i++) {
-     arrayset(g_PlayersData[i], 0, score);
-   }
-  }
Осталось отловить событие смерти игрока. Нам достаточно использовать хук RG_CBasePlayer_Killed. Заодно добавляем проверки на валидного атакующего, чтобы избежать такую же багу, как и в случае TakeDamage.
Diff:
- register_event("DeathMsg", "Event_DeathMessage", "a");
+ RegisterHookChain(RG_CBasePlayer_Killed, "CBasePlayer_Killed", true);
 
- public Event_DeathMessage() {
-   g_PlayersData[read_data(1)][frags]++;
+ public CBasePlayer_Killed(id, attacker) {
+   if (id != attacker && is_user_connected(attacker)) {
+     g_PlayersData[attacker][frags]++;
+   }
  }
Ну и последние штрихи.
Diff:
- new g_PlayersData[33][score];
+ new g_PlayersData[MAX_PLAYERS + 1][score];
Diff:
- new name[32];
+ new name[MAX_NAME_LENGTH];
- get_user_name(tmpid, name, 31);
+ get_user_name(tmpid, name, charsmax(name));
Diff:
+ new bonus = tmpf * get_pcvar_num(pcv_Aesopt);
- aes_set_player_exp(tmpid, aes_get_player_exp(tmpid) + tmpf * get_pcvar_num(pcv_Aesopt));
+ aes_set_player_exp(tmpid, aes_get_player_exp(tmpid) + bonus);
- client_print_color(0, print_team_default, "[^4Сервер^1] Самый лучший игрок раунда ^3%s^1 получил^x4 %d^1 опыта, убив ^4%d^1 игроков!", name, tmpf * get_pcvar_num(pcv_Aesopt), tmpf);
+ client_print_color(0, print_team_default, "[^4Сервер^1] Самый лучший игрок раунда ^3%s^1 получил^x4 %d^1 опыта, убив ^4%d^1 игроков!", name, bonus, tmpf);
Оптимизируем
Diff:
  for (new i, player; i < num; i++) {
    player = players[i];
-   if (g_PlayersData[player][frags] > tmpf) {
+   if (g_PlayersData[player][frags] > tmpf || (g_PlayersData[player][frags] == tmpf && g_PlayersData[player][dmg] > tmpd)) {
      tmpid = player;
      tmpf = g_PlayersData[player][frags];
      tmpd = g_PlayersData[player][dmg];
-   } else if (g_PlayersData[player][frags] == tmpf && g_PlayersData[player][dmg] > tmpd) {
-     tmpid = player;
-     tmpf = g_PlayersData[player][frags];
-     tmpd = g_PlayersData[player][dmg];
    }
  }
В итоге конечный код выглядит так:
Код:
#include <amxmodx>
#include <reapi>
#include <aes_v>

enum _:score {
  frags,
  Float:dmg,
  hs
}

new g_PlayersData[MAX_PLAYERS + 1][score];

new pcv_Aesopt;

public plugin_init(){
  register_plugin("BestAes", "1.0", "");

  RegisterHookChain(RG_CBasePlayer_TakeDamage, "CBasePlayer_TakeDamage", true);
  RegisterHookChain(RG_CBasePlayer_Killed, "CBasePlayer_Killed", true);
  RegisterHookChain(RG_RoundEnd, "RoundEnd", true);
  pcv_Aesopt    = register_cvar("nkiller_aes", "10");
}

public RoundEnd () {
  new players[32], num, tmpf, Float:tmpd, tmpid;
  get_players(players, num, "h");

  for (new i, player; i < num; i++) {
    player = players[i];
    if (g_PlayersData[player][frags] > tmpf || (g_PlayersData[player][frags] == tmpf && g_PlayersData[player][dmg] > tmpd)) {
      tmpid = player;
      tmpf = g_PlayersData[player][frags];
      tmpd = g_PlayersData[player][dmg];
    }
  }

  if (tmpf > 0) {
    new name[MAX_NAME_LENGTH];
    get_user_name(tmpid, name, charsmax(name));
   
    new bonus = tmpf * get_pcvar_num(pcv_Aesopt);
    aes_set_player_exp(tmpid, aes_get_player_exp(tmpid) + bonus);
    client_print_color(0, print_team_default, "[^4Сервер^1] Самый лучший игрок раунда ^3%s^1 получил^x4 %d^1 опыта, убив ^4%d^1 игроков!", name, bonus, tmpf);
  }
 
  for (new i = 1; i <= MaxClients; i++) {
    arrayset(g_PlayersData[i], 0, score);
  }
}

public CBasePlayer_TakeDamage(victim, inflictor, attacker, Float:damage, damagebits) {
  if (!is_user_connected(attacker) || victim == attacker) {
    return HC_CONTINUE;
  }

  if (inflictor == attacker || damagebits & DMG_GRENADE) {
    g_PlayersData[attacker][dmg] += damage;
  }

  if (get_member(victim, m_LastHitGroup) == HIT_HEAD) {
    g_PlayersData[attacker][hs]++;
  }

  return HC_CONTINUE;
}

public CBasePlayer_Killed(id, attacker) {
  if (id != attacker && is_user_connected(attacker)) {
    g_PlayersData[attacker][frags]++;
  }
}

public client_disconnected(id) {
  arrayset(g_PlayersData[id], 0, score);
}

Подитожим:
  1. Мы научились переводить плагины на ReAPI.
  2. На практике поняли, почему ReAPI + AmxModx 1.8.3 - отличный выбор.
  3. Исправили множество багов.
  4. Увидели типичные ошибки в плагинах.
12 Июн 2018
Спасибо d3m37r4 за исправление ошибок
 
Последнее редактирование:
Сообщения
1,668
Реакции
1,495
Помог
24 раз(а)
Где же это раньше было?? Спасибо, пойдем сборку переделывать.
 

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

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