[Задание] Обработка оружия игрока при возрождении

Kailo

Участник
Сообщения
194
Реакции
896
Это задание предназначено для начинающих программистов на SourcePawn.
Главной его целью, я вижу развитие навыка самостоятельного изучения новых функций и осмысления путей их применения.
От вас требуется дописать 4 функции согласно ТЗ. Задания требуется выполнять в порядке: пункт 1, пункт 2, пункт 3. Подпункты можно выполнять в любом порядке.
Это так же поможет попрактиковаться в редактировании уже готового кода. Использовать вы можете только те функции, описание которых дано в задании,
или те что вы допишите сами. Они вымышленны мною специально для этого задания, и при этом некоторые подобны существующим в SP или даже копируют их.

Доступные функции:
PHP:
enum ClipType
{
    ClipPraimary, // Основные патроны
    ClipSecondary // Запасные патроны
};

// Индексы слотов оружия
#define CS_SLOT_PRIMARY        0    /**< Слот основного оружия. */
#define CS_SLOT_SECONDARY    1    /**< Слот вспомогательного оружия. */
#define CS_SLOT_KNIFE        2    /**< Слот с ножом. */
#define CS_SLOT_GRENADE        3    /**< Слот с гранатами. */

// Возвращает id оружия или -1 если слот пуст
int GetPlayerWeapon(int client, int slot);

// Максимальное кол-во патронов в обойме оружия
int GetAmmoClipMaxSize(int weapon, ClipType type);

// Кол-во патронов в обойме оружия
int GetAmmoClipSize(int weapon, ClipType type);

// Устанавливает игроку кол-во патронов в обойме
void SetAmmoClipSize(int weapon, ClipType type, int count);

// Выдает оружие игроку (к примеру, чтобы дать АК, надо указать "weapon_ak47")
// Возвращает id выданного оружия
// Оружие выдается с полными обоймами
int GivePlayerWeapon(int client, const char[] classname);

// Забирает оружие из слота если оно есть, иначе ничего не делает
void ClearWeaponSlot(int client, int slot);

// Возвращает индекс команды игрока:
#define CS_TEAM_T             2    /**< Terrorists. */
#define CS_TEAM_CT            3    /**< Counter-Terrorists. */
int GetClientTeam(int client);

// Cookie - функционал, позволяющий запоминать и воспроизводить информацию
// Функции для работы с cookie
// Доступны везде и в любой момент, после подключения игрока на сервер
// name - ключевое имя параметра для сохранения/записи

// Сохраняет значение
void SaveCookie(int client, const char[] name, any value);
void SaveCookie(int client, const char[] name, const char[] buffer);

// Получает значение
// Возвращает true, если значение было ранее сохранено и успешно получено
// false, если ни какое значение ранее не сохранялось, значение value/buffer при этом остается неизменным
bool LoadCookie(int client, const char[] name, any &value);
bool LoadCookie(int client, const char[] name, char[] buffer, int maxlength);

// Получает слот для которого предназначено оружие по имени класса, или -1 если имя оружие некорректное
int GetWeaponSlot(const char[] classname);

// Возвращает индекс клиента по его UserID
int GetClientOfUserID(int userid);

// Возвращает кол-во аргументов при вызове команды
int GetCmdArgs();

// Получает в буфер аргумент вызова команды, нумерация начинается с 1
void GetCmdArg(int num, char[] buffer, int maxlength);
Задание:
PHP:
// *** Задание ***
// 1) При возрождении игрока:
// 1.1) Если у него нет основного оружия, выдать ему AK , если он террорист, или M4, если он контр-террорист
// 1.2) Если у него нет вспомогательного оружия, выдать ему glock, если он террорист, или usp, если он контр-террорист (с одной не заряженной обоймой!)
// 1.3) Если у него есть основное оружие, то дополнить запас (только запасные патроны) патронов до максимума
// 1.4) Если у него есть вспомогательное оружие, то дополнить и основную и запасные обоймы до максимума
// 1.5) Забрать все гранаты

// 2) Добавить возможность отключения автоматической обработки оружия при возрождении, запоминая значение в cookie:
// 2.1) Реализовать обработчик команды Cmd_AutoWeapon, для команды "sm_autoweapon <1|0>"
// 2.2) При этом реализовать функцию IsAutoWeaponEnabled() и использовать в OnPlayerSpawn

// 3) Значение, полученное при использовании команды, запоминается в cookie (cookie для Т и КТ разные) и позже используется при выдаче нового основного оружия игрока
// 3.1) Реализовать обработчик команды Cmd_SetAutoWeapon, для команды "sm_setautoweapon <weaponclass> <t/ct>"
// 3.2) Дополнить обработку оружия игрока при возрождении, если нет сохранённого в cookie значение дает стандартное оружие - AK/M4

Шаблоны функций, которые надо написать.
PHP:
// Событие возрождения игрока
// При возрождении как мы привыкли автоматическая до закупка патронов не производится
// userid - UserID возродившегося игрока
public void OnPlayerSpawn(int userid)
{

}

// Обработчик команды sm_autoweapon
// sm_autoweapon <1|0>
// userid - UserID игрока вызвавшего команду
public void Cmd_AutoWeapon(int userid)
{
 
}

// Проверяет включена ли автоматическая обработка оружия при возрождении
// client - индекс клиента
// Возвращает true, если требуется обработка оружия при возрождении
// Возвращает false, если НЕ требуется обработка оружия при возрождении
bool IsAutoWeaponEnabled(int client)
{
 
}

// Обработчик команды sm_setautoweapon
// sm_setautoweapon <weaponclass> <t/ct>
// userid - UserID игрока вызвавшего команду
public void Cmd_SetAutoWeapon(int userid)
{
 
}

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

Для удобства всю информацию прикрепляю в файле.
 

Вложения

  • respawn-weapon.sp
    6.7 КБ · Просмотры: 36
Последнее редактирование:

bigboi300

Не удаляю копирайты
Сообщения
153
Реакции
28
PHP:
public void OnPlayerSpawn(int userid)
{
    int client = GetClientOfUserId(userid);
    int weapon = GetPlayerWeapon(client, CS_SLOT_PRIMARY);
    if(weapon == -1)
    {
        if(GetClientTeam(client) == CS_TEAM_T)
            GivePlayerWeapon(client, "weapon_ak47");
        else
            GivePlayerWeapon(client, "weapon_m4a1");
    }
    else
        SetAmmoClipSize(weapon, ClipSecondary, GetAmmoClipMaxSize(weapon, ClipSecondary));
    weapon = GetPlayerWeapon(client, CS_SLOT_SECONDARY);
    if(weapon == -1)
    {
        if(GetClientTeam(client) == CS_TEAM_T)
        {
            weapon = GivePlayerWeapon(client, "weapon_glock");
        }   
        else
        {
            weapon = GivePlayerWeapon(client, "weapon_usp");           
        }
        SetAmmoClipSize(weapon, ClipPriamory, 0);
        SetAmmoClipSize(weapon, ClipSecondary, GetAmmoClipMaxSize(weapon, ClipPriamory));
    }
    else
    {   
        SetAmmoClipSize(weapon, ClipSecondary, GetAmmoClipMaxSize(weapon, ClipSecondary));
        SetAmmoClipSize(weapon, ClipPriamory, GetAmmoClipMaxSize(weapon, ClipPriamory));
    }
    ClearWeaponSlot(client, CS_SLOT_GRENADE);
}
 

Someone

Участник
Сообщения
1,933
Реакции
1,653
PHP:
public void OnPlayerSpawn(int userid)
{
    int client = GetClientOfUserId(userid);
    int weapon = GetPlayerWeapon(client, CS_SLOT_PRIMARY);
    if(weapon == -1)
    {
        if(GetClientTeam(client) == CS_TEAM_T)
            GivePlayerWeapon(client, "weapon_ak47");
        else
            GivePlayerWeapon(client, "weapon_m4a1");
    }
    else
        SetAmmoClipSize(weapon, ClipSecondary, GetAmmoClipMaxSize(weapon, ClipSecondary));
    weapon = GetPlayerWeapon(client, CS_SLOT_SECONDARY);
    if(weapon == -1)
    {
        if(GetClientTeam(client) == CS_TEAM_T)
        {
            weapon = GivePlayerWeapon(client, "weapon_glock");
        }  
        else
        {
            weapon = GivePlayerWeapon(client, "weapon_usp");          
        }
        SetAmmoClipSize(weapon, ClipPriamory, 0);
        SetAmmoClipSize(weapon, ClipSecondary, GetAmmoClipMaxSize(weapon, ClipPriamory));
    }
    else
    {  
        SetAmmoClipSize(weapon, ClipSecondary, GetAmmoClipMaxSize(weapon, ClipSecondary));
        SetAmmoClipSize(weapon, ClipPriamory, GetAmmoClipMaxSize(weapon, ClipPriamory));
    }
    ClearWeaponSlot(client, CS_SLOT_GRENADE);
}
Я бы отдельную переменную выделил для хранения команды, а не 2 раза получал.
 

Danyas

Участник
Сообщения
2,173
Реакции
1,072
я бы вместо этого
PHP:
    if(GetClientTeam(client) == CS_TEAM_T)
    {
        weapon = GivePlayerWeapon(client, "weapon_glock");
    } 
    else
    {
        weapon = GivePlayerWeapon(client, "weapon_usp");         
    }
сделал бы так

PHP:
    char sWPNS[][] = {"",    "",    "weapon_glock",    "weapon_usp"}
    weapon = GivePlayerWeapon(client, sWPNS[GetClientTeam(client)]);
 

Kruzya

Участник
Сообщения
12,970
Реакции
10,914
  • Команда форума
  • #5
@Danyas, можно ещё проще.
Сохранять команду где-то, и сразу проверять: Т или КТ.
Если ни то, ни другое - обрываем выполнение.
Если всё Ок, то тупо -2 из индекса тимы и уже к массиву обращаемся, который, в свою очередь, выглядит как-то так:
PHP:
const char g_szWeapons[][][] = { {"weapon_ak47", "weapon_m4a1"}, {"weapon_glock", "weapon_usp"} };
 

Саша Шеин

Кому костылей?
Сообщения
1,697
Реакции
621
Мой вариант:
PHP:
char g_szWeapons[][][] =  {  { "weapon_ak47", "weapon_m4a1" }, { "weapon_glock", "weapon_usp" } };
char g_szCookie[][] =  { "sm_setautoweapon_t", "sm_setautoweapon_ct" };
public void OnPlayerSpawn(int userid)
{
    int client = GetClientOfUserId(userid);
    if (client) {
        if (!IsAutoWeaponEnabled(client)) { return; }
      
        int weapon = -1, team = GetClientTeam(client);
      
        if ((weapon = GetPlayerWeapon(client, CS_SLOT_PRIMARY)) == -1) {
            char weaponclass[28];
            GivePlayerWeapon(client, (LoadCookie(client, g_szCookie[team - 2], weaponclass, sizeof(weaponclass)) && weaponclass[0] != '\0') ? weaponclass : g_szWeapons[team - 2][0]); /*1.1) 3.2)*/
        } else {
            SetAmmoClipSize(weapon, ClipSecondary, GetAmmoClipMaxSize(weapon, ClipSecondary)); /*1.3)*/
        }
      
        if ((weapon = GetPlayerWeapon(client, CS_SLOT_SECONDARY)) == -1) {
            if ((weapon = GivePlayerWeapon(client, g_szWeapons[team - 2][1])) != -1) {
                SetAmmoClipSize(weapon, ClipSecondary, 0); /*1.2)*/
            }
        } else {
            SetAmmoClipSize(weapon, ClipPraimary, GetAmmoClipMaxSize(weapon, ClipPraimary)); /*1.4)*/
            SetAmmoClipSize(weapon, ClipSecondary, GetAmmoClipMaxSize(weapon, ClipSecondary)); /*1.4)*/
        }
      
        ClearWeaponSlot(client, CS_SLOT_GRENADE); /*1.5)*/
    }
}

// Обработчик команды sm_autoweapon
// sm_autoweapon <1|0>
// userid - UserID игрока вызвавшего команду
public void Cmd_AutoWeapon(int userid)/*2.1)*/
{
    int client = GetClientOfUserId(userid);
    if (client) {
        if (GetCmdArgs() >= 2) {
            char buffer[1];
            GetCmdArg(1, buffer, sizeof(buffer));
            SaveCookie(client, "sm_autoweapon", (buffer[0] == '1'));
        }
    }
}

// Проверяет включена ли автоматическая обработка оружия при возрождении
// client - индекс клиента
// Возвращает true, если требуется обработка оружия при возрождении
// Возвращает false, если НЕ требуется обработка оружия при возрождении
bool IsAutoWeaponEnabled(int client)
{
    bool bAutoWeapon = false;
    return (LoadCookie(client, "sm_autoweapon", bAutoWeapon) && bAutoWeapon);
}

// Обработчик команды sm_setautoweapon
// sm_setautoweapon <weaponclass> <t/ct>
// userid - UserID игрока вызвавшего команду
public void Cmd_SetAutoWeapon(int userid)
{
    int client = GetClientOfUserId(userid);
    if (client) {
        if (GetCmdArgs() >= 3) {
            char weaponclass[28], team[2];
            GetCmdArg(1, weaponclass, sizeof(weaponclass));
            GetCmdArg(2, team, sizeof(team));
          
            SaveCookie(client, g_szCookie[team[0] == 't'], weaponclass);
        }
    }
}
--- Добавлено позже ---
Можно добавить дополнительных проверок, но по условиям можно использовать только данные функции. (Хотя.. строку можно проверить посимвольно C[ index]=='.')
 
Последнее редактирование:

Kailo

Участник
Сообщения
194
Реакции
896
Мой вариант:
Можно добавить дополнительных проверок, но по условиям можно использовать только данные функции. (Хотя.. строку можно проверить посимвольно C[ index]=='.')
Ну тут наверно лучше добавить функции проверки строк в задание, т.к. извращаться с проверкой строк тут задачи не стоит, да и лучше уж иначе просто написать свою версию StrEqaul.
Так же я добавлял GetWeaponSlot с намеком, проверить корректность введенного игроком имени оружия в sm_setautoweapon.
Почему ты считаешь что GetCmdArgs возвращает кол-во аргументов при вызове команды плюс один? Даже стандартная SM команда возвращает именно кол-во аргументов (кроме HL2).
Ну и как мне казалось, фразой "Добавить возможность отключения" намекает что по дефолту она активна, т.е. если cookie нет, то true (но тут одно значение поменять).
 

Саша Шеин

Кому костылей?
Сообщения
1,697
Реакции
621
Так же я добавлял GetWeaponSlot с намеком, проверить корректность введенного игроком имени оружия в sm_setautoweapon.
Я просто не заметил этой функции.:dash2:
Почему ты считаешь что GetCmdArgs возвращает кол-во аргументов при вызове команды плюс один?
Ошибся, часто так ошибаюсь... Ведь стандартный GetCmdArg начинается с 0 аргумента, то есть с самой команды, но при этом функция GetCmdArgs возвращает нормальное количество аргументов.
Ну тут наверно лучше добавить функции проверки строк в задание, т.к. извращаться с проверкой строк тут задачи не стоит, да и лучше уж иначе просто написать свою версию StrEqaul.

Как-то так
PHP:
char g_szWeapons[][][] =  {  { "weapon_ak47", "weapon_m4a1" }, { "weapon_glock", "weapon_usp" } }; // Позаимствовал идею у @Kr1kuzya
char g_szCookie[][] =  { "sm_setautoweapon_t", "sm_setautoweapon_ct" };
public void OnPlayerSpawn(int userid)
{
    int client = GetClientOfUserId(userid);
    if (client) {
        if (!IsAutoWeaponEnabled(client)) { return; }
     
        int weapon = -1, team = GetClientTeam(client);
     
        if ((weapon = GetPlayerWeapon(client, CS_SLOT_PRIMARY)) == -1) {
            char weaponclass[28];
            GivePlayerWeapon(client, (LoadCookie(client, g_szCookie[team - 2], weaponclass, sizeof(weaponclass)) && weaponclass[0] != '\0') ? weaponclass : g_szWeapons[team - 2][0]); /*1.1) 3.2)*/
        } else {
            SetAmmoClipSize(weapon, ClipSecondary, GetAmmoClipMaxSize(weapon, ClipSecondary)); /*1.3)*/
        }
     
        if ((weapon = GetPlayerWeapon(client, CS_SLOT_SECONDARY)) == -1) {
            if ((weapon = GivePlayerWeapon(client, g_szWeapons[team - 2][1])) != -1) {
                SetAmmoClipSize(weapon, ClipSecondary, 0); /*1.2)*/
            }
        } else {
            SetAmmoClipSize(weapon, ClipPraimary, GetAmmoClipMaxSize(weapon, ClipPraimary)); /*1.4)*/
            SetAmmoClipSize(weapon, ClipSecondary, GetAmmoClipMaxSize(weapon, ClipSecondary)); /*1.4)*/
        }
     
        ClearWeaponSlot(client, CS_SLOT_GRENADE); /*1.5)*/
    }
}

// Обработчик команды sm_autoweapon
// sm_autoweapon <1|0>
// userid - UserID игрока вызвавшего команду
public void Cmd_AutoWeapon(int userid)/*2.1)*/
{
    int client = GetClientOfUserId(userid);
    if (client) {
        if (GetCmdArgs() >= 1) {
            char buffer[1];
            GetCmdArg(1, buffer, sizeof(buffer));
         
            SaveCookie(client, "sm_autoweapon", (buffer[0] == '1'));
         
            return;
        }
        //ReplyToCommand(client, "sm_autoweapon <1|0>");    
    }
}

// Проверяет включена ли автоматическая обработка оружия при возрождении
// client - индекс клиента
// Возвращает true, если требуется обработка оружия при возрождении
// Возвращает false, если НЕ требуется обработка оружия при возрождении
bool IsAutoWeaponEnabled(int client)
{
    bool bAutoWeapon = false;
    return (!LoadCookie(client, "sm_autoweapon", bAutoWeapon) || bAutoWeapon);
}

// Обработчик команды sm_setautoweapon
// sm_setautoweapon <weaponclass> <t/ct>
// userid - UserID игрока вызвавшего команду
public void Cmd_SetAutoWeapon(int userid)
{
    int client = GetClientOfUserId(userid);
    if (client) {
        if (GetCmdArgs() >= 2) {
            char weaponclass[28], team[2];
            GetCmdArg(1, weaponclass, sizeof(weaponclass));
            GetCmdArg(2, team, sizeof(team));
         
            if (GetWeaponSlot(weaponclass) == -1) {
                //ReplyToCommand(client, "Некорректное имя оружия.");
                return;
            }
         
            if (StrEqual(team, "t") || StrEqual(team, "ct")) {
                SaveCookie(client, g_szCookie[team[0] == 't'], weaponclass);
                return;
            }
            //ReplyToCommand(client, "Некорректное имя команды, доступно t или ct.");        
            return;
        }
        //ReplyToCommand(client, "sm_setautoweapon <weaponclass> <t/ct>");
    }
}
 
Сверху Снизу