Перевод: DJ_WEST
Описание
Данная статья расскажет Вам о том, как сменить спрайт HUD оружия. Данный метод обладает следующими преимуществами:
- Можно менять некоторые типы спрайтов: weapon, weapon_s (select), ammo, crosshair, zoom
- Можно изменить слот для оружия
- Динамическое обновление: не нужно перезапускать клиент, сервер или делать что-то еще
- Вы можете делать все изменения для одного конкретного игрока
У метода также есть и свои недостатки:
- Можно заменить только какое-то оригинальное оружие, нельзя добавить свое
- Вы можете иметь только 29 новых оружий одновременно
- Перенаправление слотов оружий не всегда работает корректно
Такая функциональность должна быть интегрирована в отдельный плагин или модуль, который будет управлять нестандартным оружием, к примеру, как WeaponMod.
Как это работает?
Первым ключом является игровое событие: Вы должны зарегистрироваться, чтобы видеть ссылки.
Данное событие непосредственно настраивает список HUD оружия. Поэтому для корректной работы необходимо отправлять сообщение с правильными значениями. Правильные значения можно найти Вы должны зарегистрироваться, чтобы видеть ссылки..
Структура сообщения имеет следующий вид:
string WeaponName
byte PrimaryAmmoID
byte PrimaryAmmoMaxAmount
byte SecondaryAmmoID
byte SecondaryAmmoMaxAmount
byte SlotID
byte NumberInSlot
byte WeaponID
byte Flags
Второй ключ - это WeaponName и SlotID.
Первый аргумент используется, к примеру, когда игрок выбирает оружие, что равносильно тому, когда клиент набирает название оружия в консоли.
Необходимо изменить его на название вашего нового оружия, к примеру, weapon_flare.
Чтобы выбрать оружие, необходимо хукнуть новое название оружия и затем перенаправить на оригинальное оружие.
Второй аргумент позволяет изменить слот оружия.
Третий ключ - это опять же первый аргумент (WeaponName), который связан также с файлом weapon_*.txt (* = название оружия) в директории sprites на клиенте.
Данный файл содержит спрайты для каждого типа. Полный список типов: weapon, weapon_s, ammo, ammo2, autoaim, crosshair, zoom, zoom_aim (автор не уверен, что ammo2, autoaim или zoom_aim можно использовать).
Формат файла:
количество_спрайтов
<тип> <разрешение> <спрайт> <смещение_по_X> <смещение_по_Y> <ширина> <высота>
В данном файле вы можете прописать ваши новые спрайты. К примеру, файл weapon_knife.txt:
- Код: Выделить всё
10
weapon 320 320hud1 0 0 80 20
weapon_s 320 320hud1 0 20 80 20
ammo 320 320hud2 0 16 18 18
crosshair 320 crosshairs 24 0 24 24
autoaim 320 crosshairs 0 72 24 24
weapon 640 640hud10 0 135 170 45
weapon_s 640 640hud11 0 135 170 45
ammo 640 640hud7 0 72 24 24
crosshair 640 crosshairs 24 0 24 24
autoaim 640 crosshairs 0 72 24 24
Четвертый ключ - это предварительное кеширование нужных файлов.
Оба файла .txt и.spr/.tga необходимы клиенту. Они могут быть кешированы без проблем с использованием функции precache_generic().
Лучше всего делать для оружия уникальные названия, потому что если другой плагин будет использовать точно такое же название, то файлы на клиенте не буду перезаписаны. Также для спрайтов можно создавать свои директории.
Примеры в деталях
1. Создаем свой файл настроек.
Допустим вы хотите заменить оружие knife на flare, а также изменить его слот.
Вы должны создать файл weapon_ArkFlare.txt:
- Код: Выделить всё
2
weapon 640 640hud19 0 0 170 45
weapon_s 640 640hud20 0 0 170 45
Будем использовать следующие спрайты: sprites/640hud19.spr и sprites/640hud20.spr.
2. Предварительное кеширование файлов.
Для этого нам необходимо прописать в нашем плагине:
- Код: Выделить всё
public plugin_precache()
{
precache_generic( "sprites/weapon_ArkFlare.txt" );
precache_generic( "sprites/640hud19.spr" );
precache_generic( "sprites/640hud20.spr" );
}
3. Хук события, когда игрок получает оружие.
Нам необходимо хукнуть событие, когда игрок получает нож. Затем мы сможем послать сообщение WeaponList , где сообщим клиенту о том, что хотим использовать "weapon_ArkFlare".
Мы можем использовать Ham_Item_AddToPlayer для этого:
- Код: Выделить всё
RegisterHam( Ham_Item_AddToPlayer, "weapon_knife", "OnAddToPlayerKnife", .Post = true );
Затем мы можем послать наше сообщение:
- Код: Выделить всё
new MsgIndexWeaponList;
public plugin_init()
{
RegisterHam( Ham_Item_AddToPlayer, "weapon_knife", "OnAddToPlayerKnife", .Post = true );
MsgIndexWeaponList = get_user_msgid( "WeaponList" );
}
public OnAddToPlayerKnife( const item, const player )
{
if( pev_valid( item ) && is_user_alive( player ) ) // для безопасности
{
message_begin( MSG_ONE, MsgIndexWeaponList, .player = player );
{
write_string("weapon_ArkFlare"); // WeaponName
write_byte( -1 ); // PrimaryAmmoID
write_byte( -1 ); // PrimaryAmmoMaxAmount
write_byte( -1 ); // SecondaryAmmoID
write_byte( -1 ); // SecondaryAmmoMaxAmount
write_byte( 2 ); // SlotID (0...N)
write_byte( 1 ); // NumberInSlot (1...N)
write_byte( CSW_KNIFE ); // WeaponID
write_byte( 0 ); // Flags
}
message_end();
}
}
В результате получим:
4. Хукаем событие, когда игрок получает оружие и меняем ему слот.
Почти тоже самое, что в 3 пункту, но только теперь нам надо будет поменять номер слота. Также необходимо хукнуть Ham_Item_ItemSlot, потому что значения, которые хранятся в CKnife::GetItemInfo() не изменяются и когда ItemSlot() будет вызван, то он вернет оригинальное значение.
- Код: Выделить всё
RegisterHam( Ham_Item_ItemSlot, "weapon_knife", "OnItemSlotKnife" );
Допустим мы хотим изменить слот оружия на 5. Будьте внимательны, потому что нумерация слотов в сообщение начинается с 0, когда же в ItemSlot идет с 1.
- Код: Выделить всё
new MsgIndexWeaponList;
public plugin_init()
{
RegisterHam( Ham_Item_AddToPlayer, "weapon_knife", "OnAddToPlayerKnife", .Post = true );
RegisterHam( Ham_Item_ItemSlot, "weapon_knife", "OnItemSlotKnife" );
MsgIndexWeaponList = get_user_msgid( "WeaponList" );
}
public OnAddToPlayerKnife( const item, const player )
{
if( pev_valid( item ) && is_user_alive( player ) ) // для безопасности
{
message_begin( MSG_ONE, MsgIndexWeaponList, .player = player );
{
write_string("weapon_ArkFlare"); // WeaponName
write_byte( -1 ); // PrimaryAmmoID
write_byte( -1 ); // PrimaryAmmoMaxAmount
write_byte( -1 ); // SecondaryAmmoID
write_byte( -1 ); // SecondaryAmmoMaxAmount
write_byte(4); // SlotID (0...N) <== Changed here (was 2)
write_byte( 1 ); // NumberInSlot (1...N)
write_byte( CSW_KNIFE ); // WeaponID
write_byte( 0 ); // Flags
}
message_end();
}
}
public OnItemSlotKnife( const item )
{
SetHamReturnInteger(5);
return HAM_SUPERCEDE;
}
В результате получим:
5. Хук выбора оружия.
После того, как вы изменили имя оружия, необходимо хукнуть его вызов. Потому что когда игрок выбирает ваше новое оружие, будет использовано weapon_ArkFlare, но такого оружия не существует фактически, поэтому нам нужно в хуке заставить использовать оригинальное.
- Код: Выделить всё
public plugin_init()
{
register_clcmd( "weapon_ArkFlare", "ClientCommand_SelectFlare" );
}
public ClientCommand_SelectFlare( const client )
{
engclient_cmd( client, "weapon_knife" );
}
6. Полностью рабочий код.
- Код: Выделить всё
#include <amxmodx>
#include <hamsandwich>
#include <fakemeta>
new MsgIndexWeaponList;
public plugin_precache()
{
precache_generic( "sprites/weapon_ArkFlare.txt" );
precache_generic( "sprites/640hud19.spr" );
precache_generic( "sprites/640hud20.spr" );
}
public plugin_init()
{
RegisterHam( Ham_Item_AddToPlayer, "weapon_knife", "OnAddToPlayerKnife", .Post = true );
RegisterHam( Ham_Item_ItemSlot, "weapon_knife", "OnItemSlotKnife" );
register_clcmd( "weapon_ArkFlare", "ClientCommand_SelectFlare" );
MsgIndexWeaponList = get_user_msgid( "WeaponList" );
}
public ClientCommand_SelectFlare( const client )
{
engclient_cmd( client, "weapon_knife" );
}
public OnAddToPlayerKnife( const item, const player )
{
if( pev_valid( item ) && is_user_alive( player ) ) // just for safety.
{
message_begin( MSG_ONE, MsgIndexWeaponList, .player = player );
{
write_string( "weapon_ArkFlare" ); // WeaponName
write_byte( -1 ); // PrimaryAmmoID
write_byte( -1 ); // PrimaryAmmoMaxAmount
write_byte( -1 ); // SecondaryAmmoID
write_byte( -1 ); // SecondaryAmmoMaxAmount
write_byte( 4 ); // SlotID (0...N)
write_byte( 1 ); // NumberInSlot (1...N)
write_byte( CSW_KNIFE ); // WeaponID
write_byte( 0 ); // Flags
}
message_end();
}
}
public OnItemSlotKnife( const item )
{
SetHamReturnInteger( 5 );
return HAM_SUPERCEDE;
}