#include <amxmodx>
#include <reapi>
#include <hamsandwich>
new const g_szPluginVersion[] = "0.1";
new const g_szConfigPath[] = "addons/amxmodx/configs/weapons_skins.ini";
#define MAX_WS_NAME_LEN 128
#define WEAPON_NULL -1
enum enumWeaponData {
WeaponIdType:WEAPON_DATA_ID,
WEAPON_UNIQUE_IMPULSE,
WEAPON_DATA_KEY[MAX_AUTHID_LENGTH],
WEAPON_DATA_NAME[MAX_WS_NAME_LEN],
WEAPON_DATA_MODEL_VIEW[MAX_RESOURCE_PATH_LENGTH],
WEAPON_DATA_MODEL_WEAPON[MAX_RESOURCE_PATH_LENGTH],
WEAPON_DATA_MODEL_WORLD[MAX_RESOURCE_PATH_LENGTH]
};
new Array:g_aWeaponData;
new g_iCurrentWeaponIndex[MAX_PLAYERS+1][any:WEAPON_P90+1], WeaponIdType:g_iMenuTargetWeapon[MAX_PLAYERS+1];
new g_iImpulseCounter;
public plugin_precache() {
register_plugin("Weapons skins", g_szPluginVersion, "Kurtis");
_read_config();
}
public plugin_init() {
if(g_aWeaponData == Invalid_Array || ArraySize(g_aWeaponData) == 0) {
if(g_aWeaponData != Invalid_Array) {
ArrayDestroy(g_aWeaponData);
}
set_fail_state("Не загружено ни одного скина, плагин остановлен");
return;
}
RegisterHookChain(RG_CBasePlayer_AddPlayerItem, "CBasePlayer_AddPlayerItem_Post", 1);
RegisterHookChain(RG_CBasePlayerWeapon_DefaultDeploy, "CBasePlayerWeapon_DefaultDeploy_Pre");
RegisterHookChain(RG_CWeaponBox_SetModel, "CWeaponBox_SetModel_Pre");
register_clcmd("say /skins", "cmdSkinsMenu");
register_clcmd("say_team /skins", "cmdSkinsMenu");
}
public plugin_end() {
if(g_aWeaponData != Invalid_Array) {
ArrayDestroy(g_aWeaponData);
}
}
public client_putinserver(pPlayer) {
for(new any:i = WEAPON_P228; i <= any:WEAPON_P90; i++) {
g_iCurrentWeaponIndex[pPlayer][i] = WEAPON_NULL;
}
new szAuthID[MAX_AUTHID_LENGTH];
get_user_authid(pPlayer, szAuthID, charsmax(szAuthID));
new eWeaponData[enumWeaponData];
for(new i, iSize = ArraySize(g_aWeaponData); i < iSize; i++) {
ArrayGetArray(g_aWeaponData, i, eWeaponData);
new iWeaponId = any:eWeaponData[WEAPON_DATA_ID];
if(g_iCurrentWeaponIndex[pPlayer][iWeaponId] == WEAPON_NULL && equal(szAuthID, eWeaponData[WEAPON_DATA_KEY])) {
g_iCurrentWeaponIndex[pPlayer][iWeaponId] = i;
}
}
}
public cmdSkinsMenu(pPlayer) {
if(!is_user_connected(pPlayer)) {
return PLUGIN_HANDLED;
}
new szAuthID[MAX_AUTHID_LENGTH];
get_user_authid(pPlayer, szAuthID, charsmax(szAuthID));
new iMenu = menu_create("\yВыбор оружия для скина:", "_handlerSkinsMenu");
new eWeaponData[enumWeaponData], szItemName[32];
for(new any:i = WEAPON_P228; i <= any:WEAPON_P90; i++) {
if(i == any:WEAPON_SHIELDGUN) {
continue;
}
new bool:bHasSkins = false;
for(new j = 0, iSize = ArraySize(g_aWeaponData); j < iSize; j++) {
ArrayGetArray(g_aWeaponData, j, eWeaponData);
if(any:eWeaponData[WEAPON_DATA_ID] == i && equal(szAuthID, eWeaponData[WEAPON_DATA_KEY])) {
bHasSkins = true;
break;
}
}
if(bHasSkins) {
_format_weapon_name(WeaponIdType:i, szItemName, charsmax(szItemName));
new iCurrentIndex = g_iCurrentWeaponIndex[pPlayer][i];
if(iCurrentIndex != WEAPON_NULL) {
ArrayGetArray(g_aWeaponData, iCurrentIndex, eWeaponData);
menu_additem(iMenu, fmt("%s \d[%s]", szItemName, eWeaponData[WEAPON_DATA_NAME]), fmt("%i", i));
}
else {
menu_additem(iMenu, fmt("%s \d[Стандартный]", szItemName), fmt("%i", i));
}
}
}
if(menu_items(iMenu) == 0) {
menu_destroy(iMenu);
client_print_color(pPlayer, print_team_default, "^3[Skins] ^1У вас нет доступных скинов.");
return PLUGIN_HANDLED;
}
menu_setprop(iMenu, MPROP_BACKNAME, "Назад");
menu_setprop(iMenu, MPROP_NEXTNAME, "Далее");
menu_setprop(iMenu, MPROP_EXITNAME, "Выход");
menu_display(pPlayer, iMenu, 0);
return PLUGIN_HANDLED;
}
public _handlerSkinsMenu(pPlayer, iMenu, iItem) {
if(iItem == MENU_EXIT) {
menu_destroy(iMenu);
return;
}
new szItemNum[8];
menu_item_getinfo(iMenu, iItem, .info = szItemNum, .infolen = charsmax(szItemNum));
menu_destroy(iMenu);
new WeaponIdType:iWeaponId = WeaponIdType:str_to_num(szItemNum);
g_iMenuTargetWeapon[pPlayer] = iWeaponId;
_SubSkinsMenu(pPlayer);
}
public _SubSkinsMenu(pPlayer) {
new szAuthID[MAX_AUTHID_LENGTH];
get_user_authid(pPlayer, szAuthID, charsmax(szAuthID));
new WeaponIdType:iWeaponId = g_iMenuTargetWeapon[pPlayer];
new szWpName[32];
_format_weapon_name(iWeaponId, szWpName, charsmax(szWpName));
new iMenu = menu_create(fmt("\yВыбор скина для \r%s:", szWpName), "_handlerSubMenu");
new eWeaponData[enumWeaponData];
menu_additem(iMenu, fmt("Стандартная модель %s %s", szWpName, (g_iCurrentWeaponIndex[pPlayer][any:iWeaponId] == WEAPON_NULL) ? "\r*" : ""), fmt("%i", WEAPON_NULL));
for(new j, iSize = ArraySize(g_aWeaponData); j < iSize; j++) {
ArrayGetArray(g_aWeaponData, j, eWeaponData);
if(eWeaponData[WEAPON_DATA_ID] == iWeaponId && equal(szAuthID, eWeaponData[WEAPON_DATA_KEY])) {
if(g_iCurrentWeaponIndex[pPlayer][any:iWeaponId] == j) {
menu_additem(iMenu, fmt("%s \r*", eWeaponData[WEAPON_DATA_NAME]), fmt("%i", j));
}
else {
menu_additem(iMenu, fmt("%s", eWeaponData[WEAPON_DATA_NAME]), fmt("%i", j));
}
}
}
menu_setprop(iMenu, MPROP_BACKNAME, "Назад");
menu_setprop(iMenu, MPROP_NEXTNAME, "Далее");
menu_setprop(iMenu, MPROP_EXITNAME, "Выход");
menu_display(pPlayer, iMenu, 0);
}
public _handlerSubMenu(pPlayer, iMenu, iItem) {
if(iItem == MENU_EXIT) {
menu_destroy(iMenu);
return;
}
new szItemNum[8];
menu_item_getinfo(iMenu, iItem, .info = szItemNum, .infolen = charsmax(szItemNum));
menu_destroy(iMenu);
new iSelectedIndex = str_to_num(szItemNum);
new WeaponIdType:iWeaponId = g_iMenuTargetWeapon[pPlayer];
g_iCurrentWeaponIndex[pPlayer][any:iWeaponId] = iSelectedIndex;
new szWpName[32];
_format_weapon_name(iWeaponId, szWpName, charsmax(szWpName));
if(iSelectedIndex == WEAPON_NULL) {
client_print_color(pPlayer, print_team_default, "^3[Skins] ^1Вы вернули стандартный вид для ^4%s^1.", szWpName);
}
else {
new eWeaponData[enumWeaponData];
ArrayGetArray(g_aWeaponData, iSelectedIndex, eWeaponData);
client_print_color(pPlayer, print_team_default, "^3[Skins] ^1Вы выбрали скин ^4%s ^1для ^4%s^1.", eWeaponData[WEAPON_DATA_NAME], szWpName);
}
cmdSkinsMenu(pPlayer);
}
public _format_weapon_name(WeaponIdType:iWeaponId, szOutput[], iMaxLen) {
new szRawName[32];
rg_get_weapon_info(iWeaponId, WI_NAME, szRawName, charsmax(szRawName));
replace(szRawName, charsmax(szRawName), "weapon_", "");
ucfirst(szRawName);
copy(szOutput, iMaxLen, szRawName);
}
public CBasePlayer_AddPlayerItem_Post(pPlayer, iItem) {
if(!is_user_alive(pPlayer) || is_nullent(iItem)) {
return;
}
if(get_entvar(iItem, var_impulse) > 0) {
RequestFrame("_delay_model_ver", pPlayer);
return;
}
new WeaponIdType:iWeaponId = get_member(iItem, m_iId);
if(iWeaponId == WEAPON_SHIELDGUN) {
return;
}
if(g_iCurrentWeaponIndex[pPlayer][any:iWeaponId] == WEAPON_NULL) {
return;
}
new eWeaponData[enumWeaponData];
ArrayGetArray(g_aWeaponData, g_iCurrentWeaponIndex[pPlayer][any:iWeaponId], eWeaponData);
set_entvar(iItem, var_impulse, eWeaponData[WEAPON_UNIQUE_IMPULSE]);
RequestFrame("_delay_model_ver", pPlayer);
}
public CBasePlayerWeapon_DefaultDeploy_Pre(iItem, const szViewModel[], const szWeaponModel[], iAnim, const szAnimExt[], skiplocal) {
if(is_nullent(iItem)) {
return;
}
new iUniqueImpulse = get_entvar(iItem, var_impulse);
if(iUniqueImpulse == 0) {
return;
}
new WeaponIdType:iWeaponId = get_member(iItem, m_iId);
if(iWeaponId == WEAPON_SHIELDGUN) {
return;
}
new pPlayer = get_member(iItem, m_pPlayer);
if(!is_user_alive(pPlayer)) {
return;
}
new iArrayItem = _find_skin_by_impulse(iUniqueImpulse);
if(iArrayItem != -1) {
new eWeaponData[enumWeaponData];
ArrayGetArray(g_aWeaponData, iArrayItem, eWeaponData);
SetHookChainArg(2, ATYPE_STRING, eWeaponData[WEAPON_DATA_MODEL_VIEW]);
SetHookChainArg(3, ATYPE_STRING, eWeaponData[WEAPON_DATA_MODEL_WEAPON]);
}
}
public CWeaponBox_SetModel_Pre(eEnt, const szModel[]) {
if(is_nullent(eEnt)) {
return;
}
new iSlotItem, iUniqueImpulse;
for(new iSlot; iSlot < MAX_ITEM_TYPES; iSlot++) {
iSlotItem = get_member(eEnt, m_WeaponBox_rgpPlayerItems, iSlot);
if(is_nullent(iSlotItem)) {
continue;
}
iUniqueImpulse = get_entvar(iSlotItem, var_impulse);
if(iUniqueImpulse == 0) {
continue;
}
new iArrayItem = _find_skin_by_impulse(iUniqueImpulse);
if(iArrayItem != -1) {
new eWeaponData[enumWeaponData];
ArrayGetArray(g_aWeaponData, iArrayItem, eWeaponData);
SetHookChainArg(2, ATYPE_STRING, eWeaponData[WEAPON_DATA_MODEL_WORLD]);
set_entvar(eEnt, var_impulse, iUniqueImpulse);
break;
}
}
}
public _find_skin_by_impulse(iImpulse) {
new eWeaponData[enumWeaponData];
for(new i = 0, iSize = ArraySize(g_aWeaponData); i < iSize; i++) {
ArrayGetArray(g_aWeaponData, i, eWeaponData);
if(eWeaponData[WEAPON_UNIQUE_IMPULSE] == iImpulse) {
return i;
}
}
return -1;
}
public _delay_model_ver(pPlayer) {
if(!is_user_alive(pPlayer)) {
return;
}
new iActiveItem = get_member(pPlayer, m_pActiveItem);
if(is_nullent(iActiveItem)) {
return;
}
ExecuteHamB(Ham_Item_Deploy, iActiveItem);
}
public _read_config() {
if(!file_exists(g_szConfigPath)) {
set_fail_state("Отсутствует конфиг `%s`: плагин остановлен", g_szConfigPath);
return;
}
g_aWeaponData = ArrayCreate(enumWeaponData);
g_iImpulseCounter = 10423; // magic
new INIParser:iParserHandle = INI_CreateParser();
INI_SetReaders(iParserHandle, "OnKeyValue");
INI_ParseFile(iParserHandle, g_szConfigPath);
INI_DestroyParser(iParserHandle);
}
public bool: OnKeyValue(INIParser:handle, const key[], const value[], bool:invalid_tokens, bool:equal_token, bool:quotes, curtok, any:data) {
new szData[512];
copy(szData, charsmax(szData), key);
trim(szData);
if(szData[0] == EOS || szData[0] == '/') {
return true;
}
new eWeaponData[enumWeaponData], szWeaponClassName[32];
parse(szData,
eWeaponData[WEAPON_DATA_KEY], MAX_AUTHID_LENGTH-1,
szWeaponClassName, charsmax(szWeaponClassName),
eWeaponData[WEAPON_DATA_NAME], MAX_WS_NAME_LEN-1,
eWeaponData[WEAPON_DATA_MODEL_VIEW], MAX_RESOURCE_PATH_LENGTH-1,
eWeaponData[WEAPON_DATA_MODEL_WEAPON], MAX_RESOURCE_PATH_LENGTH-1,
eWeaponData[WEAPON_DATA_MODEL_WORLD], MAX_RESOURCE_PATH_LENGTH-1
);
if(eWeaponData[WEAPON_DATA_KEY][0] == EOS) {
log_amx("Ошибка чтения конфига: не указан ключ (%s)", szData);
return true;
}
if(containi(szWeaponClassName, "weapon_") == -1) {
log_amx("Ошибка чтения конфига: указан неправильный класс оружия (%s)", szData);
return true;
}
eWeaponData[WEAPON_DATA_ID] = WeaponIdType:rg_get_weapon_info(szWeaponClassName, WI_ID);
if(eWeaponData[WEAPON_DATA_ID] == WEAPON_NONE) {
log_amx("Ошибка чтения конфига: указан неправильный класс оружия (%s)", szData);
return true;
}
if(!file_exists(eWeaponData[WEAPON_DATA_MODEL_VIEW])) {
log_amx("Ошибка чтения конфига: проверьте наличие модели (%s)", szData);
return true;
}
if(!file_exists(eWeaponData[WEAPON_DATA_MODEL_WEAPON])) {
log_amx("Ошибка чтения конфига: проверьте наличие модели (%s)", szData);
return true;
}
if(!file_exists(eWeaponData[WEAPON_DATA_MODEL_WORLD])) {
log_amx("Ошибка чтения конфига: проверьте наличие модели (%s)", szData);
return true;
}
precache_model(eWeaponData[WEAPON_DATA_MODEL_VIEW]);
precache_model(eWeaponData[WEAPON_DATA_MODEL_WEAPON]);
precache_model(eWeaponData[WEAPON_DATA_MODEL_WORLD]);
eWeaponData[WEAPON_UNIQUE_IMPULSE] = g_iImpulseCounter++;
ArrayPushArray(g_aWeaponData, eWeaponData);
return true;
}