#include <amxmodx>
#include <fakemeta>
#include <reapi>
#pragma semicolon 1
//#define SWITCH_P_W_MODELS
//#define NoRoundMod 180.0 // 3 minutes
#define MAX_MODELS_LENGTH 128
enum _:ArrayData
{
SaveType: iWmType,
WeaponIdType: iWmWeapon,
iWmModelW,
TeamName: iTeam,
szWmParam[64],
szWmModelP[MAX_MODELS_LENGTH],
szWmModelV[MAX_MODELS_LENGTH],
szWmModelW[MAX_MODELS_LENGTH]
}
enum _:PlayerModels
{
SaveType: iPriority,
iModelW,
szModelP[MAX_MODELS_LENGTH],
szModelV[MAX_MODELS_LENGTH],
szModelW[MAX_MODELS_LENGTH]
}
enum SaveType
{
WM_NONE,
WM_ALL,
WM_TEAM,
WM_ONLY_STEAM,
WM_FLAGS,
WM_STEAM,
WM_NICK
}
new Array: g_aWeapons, SaveType: g_iType;
new g_aPlayerWeapon[MAX_PLAYERS * 3 + 1][WeaponIdType][PlayerModels], g_iTotalLoaded;
new bool: g_bSWP[MAX_PLAYERS + 1];
new g_bitFlags[MAX_PLAYERS + 1];
public plugin_init()
{
register_plugin("[GM] Weapon Models", "1.2.0", "[GM] NWC");
register_dictionary("gm_weapon_models.txt");
register_clcmd("say /weapons", "@SwitchWeaponModels");
register_clcmd("say_team /weapons", "@SwitchWeaponModels");
RegisterHookChain(RG_CBasePlayerWeapon_DefaultDeploy, "@CBasePlayerWeapon_DefaultDeploy_Pre");
RegisterHookChain(RG_CWeaponBox_SetModel, "@CWeaponBox_SetModel_Pre");
RegisterHookChain(RG_CBasePlayer_ThrowGrenade, "@CBasePlayer_ThrowGrenade_Post", true);
RegisterHookChain(RG_PlantBomb, "@PlantBomb_Post", true);
#if defined NoRoundMod
set_task(NoRoundMod, "@CBasePlayer_OnSpawnEquip_Post", iPlayer);
#else
RegisterHookChain(RG_CBasePlayer_OnSpawnEquip, "@CBasePlayer_OnSpawnEquip_Post", true);
#endif
#if defined SWITCH_P_W_MODELS
register_forward(FM_AddToFullPack, "@AddToFullPack_Post", true);
#endif
}
public plugin_precache()
{
new szDir[128];
get_localinfo("amxx_configsdir", szDir, charsmax(szDir));
add(szDir, charsmax(szDir), "/plugins/gm_plugins/weapon_models.ini");
g_aWeapons = ArrayCreate(ArrayData);
new INIParser: hParser = INI_CreateParser();
INI_SetReaders(hParser, "parse_key_value", "parse_new_section");
if (!INI_ParseFile(hParser, szDir))
{
INI_DestroyParser(hParser);
set_fail_state("%l %l", "WM_FILE_CANT", file_exists(szDir) ? "WM_READ" : "WM_FIND", szDir);
}
INI_DestroyParser(hParser);
log_amx("%l", "WM_LOADED", ArraySize(g_aWeapons), g_iTotalLoaded);
}
@SwitchWeaponModels(const iPlayer)
{
g_bSWP[iPlayer] ^= true;
client_print_color(iPlayer, g_bSWP[iPlayer] ? print_team_red : print_team_blue, "^4Models ^3%s", g_bSWP[iPlayer] ? "OFF" : "ON");
if (!is_user_alive(iPlayer)) return PLUGIN_CONTINUE;
new iEnt = get_member(iPlayer, m_pActiveItem);
new WeaponIdType: iWeapon = get_member(iEnt, m_iId);
if (g_bSWP[iPlayer])
{
new szWeapon[32];
get_entvar(iEnt, var_classname, szWeapon, charsmax(szWeapon));
set_entvar(iPlayer, var_viewmodel, "models/v_%s.mdl", szWeapon[7]);
}
else
{
if (g_aPlayerWeapon[get_plWeapon(iPlayer)][iWeapon][szModelV])
set_entvar(iPlayer, var_viewmodel, g_aPlayerWeapon[get_plWeapon(iPlayer)][iWeapon][szModelV]);
else
if (g_aPlayerWeapon[iPlayer][iWeapon][szModelV])
set_entvar(iPlayer, var_viewmodel, g_aPlayerWeapon[iPlayer][iWeapon][szModelV]);
}
return PLUGIN_CONTINUE;
}
#if defined SWITCH_P_W_MODELS
public @AddToFullPack_Post(iEs, e, iEnt, iPlayer, hostflags, isPlayer, pSet)
{
if (!is_user_connected(iPlayer)) return FMRES_IGNORED;
new szWeapon[32];
get_entvar(iEnt, var_classname, szWeapon, charsmax(szWeapon));
if (!equal(szWeapon, "weapon", 6)) return FMRES_IGNORED;
if (g_bSWP[iPlayer])
{
set_es(iEs, ES_WeaponModel, engfunc(EngFunc_ModelIndex, fmt("models/p_%s", szWeapon[7])));
if (!isPlayer)
{
set_es(iEs, ES_ModelIndex, get_entvar(iEnt, var_modelindex));
}
}
return FMRES_IGNORED;
}
#endif
@CBasePlayerWeapon_DefaultDeploy_Pre(const iEnt)
{
if (is_nullent(iEnt)) return HC_CONTINUE;
new iPlayer = get_member(iEnt, m_pPlayer);
if (g_bSWP[iPlayer]) return HC_CONTINUE;
new WeaponIdType: iWeapon = WeaponIdType: get_member(iEnt, m_iId);
if (g_aPlayerWeapon[get_plWeapon(iPlayer)][iWeapon][szModelV])
SetHookChainArg(2, ATYPE_STRING, g_aPlayerWeapon[get_plWeapon(iPlayer)][iWeapon][szModelV]);
else
if (g_aPlayerWeapon[iPlayer][iWeapon][szModelV])
SetHookChainArg(2, ATYPE_STRING, g_aPlayerWeapon[iPlayer][iWeapon][szModelV]);
if (g_aPlayerWeapon[get_plWeapon(iPlayer)][iWeapon][szModelP])
SetHookChainArg(3, ATYPE_STRING, g_aPlayerWeapon[get_plWeapon(iPlayer)][iWeapon][szModelP]);
else
if (g_aPlayerWeapon[iPlayer][iWeapon][szModelP])
SetHookChainArg(3, ATYPE_STRING, g_aPlayerWeapon[iPlayer][iWeapon][szModelP]);
return HC_CONTINUE;
}
@CWeaponBox_SetModel_Pre(const iWeaponBox)
{
new iEnt = func_GetWeaponBoxWeapon(iWeaponBox);
if (iEnt == NULLENT) return HC_CONTINUE;
new WeaponIdType: iWeapon = WeaponIdType: get_member(iEnt, m_iId);
new iPlayer = get_entvar(iWeaponBox, var_owner);
if (g_aPlayerWeapon[get_plWeapon(iPlayer)][iWeapon][szModelW])
SetHookChainArg(2, ATYPE_STRING, g_aPlayerWeapon[get_plWeapon(iPlayer)][iWeapon][szModelW]);
else
if (g_aPlayerWeapon[iPlayer][iWeapon][szModelW])
SetHookChainArg(2, ATYPE_STRING, g_aPlayerWeapon[iPlayer][iWeapon][szModelW]);
return HC_CONTINUE;
}
// Grenade
@CBasePlayer_ThrowGrenade_Post(const iPlayer, const iGrenade)
{
new iEnt = GetHookChainReturn(ATYPE_INTEGER);
if (is_nullent(iEnt)) return HC_CONTINUE;
new WeaponIdType: iWeapon = WeaponIdType: get_member(iGrenade, m_iId);
if (g_aPlayerWeapon[get_plWeapon(iPlayer)][iWeapon][szModelW])
{
set_entvar(iEnt, var_modelindex, g_aPlayerWeapon[get_plWeapon(iPlayer)][iWeapon][iModelW]);
set_entvar(iEnt, var_model, g_aPlayerWeapon[get_plWeapon(iPlayer)][iWeapon][szModelW]);
}
else
if (g_aPlayerWeapon[iPlayer][iWeapon][szModelW])
{
set_entvar(iEnt, var_modelindex, g_aPlayerWeapon[iPlayer][iWeapon][iModelW]);
set_entvar(iEnt, var_model, g_aPlayerWeapon[iPlayer][iWeapon][szModelW]);
}
return HC_CONTINUE;
}
@PlantBomb_Post(const iPlayer)
{
new iEnt = GetHookChainReturn(ATYPE_INTEGER);
if (g_aPlayerWeapon[get_plWeapon(iPlayer)][WEAPON_C4][szModelW])
{
set_entvar(iEnt, var_modelindex, g_aPlayerWeapon[get_plWeapon(iPlayer)][WEAPON_C4][iModelW]);
set_entvar(iEnt, var_model, g_aPlayerWeapon[get_plWeapon(iPlayer)][WEAPON_C4][szModelW]);
}
return HC_CONTINUE;
}
@CBasePlayer_OnSpawnEquip_Post(const iPlayer)
{
if (g_bitFlags[iPlayer] != get_user_flags(iPlayer))
{
g_bitFlags[iPlayer] = get_user_flags(iPlayer);
@LoadWeaponModels(iPlayer);
if (is_user_alive(iPlayer))
{
new iEntity = get_member(iPlayer, m_pActiveItem);
new WeaponIdType: iWeapon = get_member(iEntity, m_iId);
if (g_aPlayerWeapon[get_plWeapon(iPlayer)][iWeapon][szModelV])
{
set_entvar(iPlayer, var_viewmodel, g_aPlayerWeapon[get_plWeapon(iPlayer)][iWeapon][szModelV]);
}
else
if (g_aPlayerWeapon[iPlayer][iWeapon][szModelV])
{
set_entvar(iPlayer, var_viewmodel, g_aPlayerWeapon[iPlayer][iWeapon][szModelV]);
}
if (g_aPlayerWeapon[get_plWeapon(iPlayer)][iWeapon][szModelP])
{
set_entvar(iPlayer, var_weaponmodel, g_aPlayerWeapon[get_plWeapon(iPlayer)][iWeapon][szModelV]);
}
else
if (g_aPlayerWeapon[iPlayer][iWeapon][szModelP])
{
set_entvar(iPlayer, var_weaponmodel, g_aPlayerWeapon[iPlayer][iWeapon][szModelV]);
}
}
}
}
public client_putinserver(iPlayer)
{
g_bitFlags[iPlayer] = get_user_flags(iPlayer);
@LoadWeaponModels(iPlayer);
}
@LoadWeaponModels(const iPlayer)
{
for (new TeamName: j,k; j < TEAM_SPECTATOR; j++)
{
switch (j)
{
case TEAM_UNASSIGNED: {k = iPlayer;}
case TEAM_TERRORIST: {k = MAX_PLAYERS + iPlayer;}
case TEAM_CT: {k = MAX_PLAYERS * 2 + iPlayer;}
default: {k = 0;}
}
for (new WeaponIdType: i = WEAPON_P228; i <= WEAPON_P90; i++)
{
g_aPlayerWeapon[k][i][iPriority] = WM_NONE;
g_aPlayerWeapon[k][i][szModelP][0] = EOS;
g_aPlayerWeapon[k][i][szModelV][0] = EOS;
g_aPlayerWeapon[k][i][szModelW][0] = EOS;
}
}
new iSize = ArraySize(g_aWeapons);
new aData[ArrayData], WeaponIdType: iWeapon;
for (new i, k; i < iSize; i++)
{
ArrayGetArray(g_aWeapons, i, aData);
iWeapon = aData[iWmWeapon];
switch (aData[iTeam])
{
case TEAM_UNASSIGNED: {k = iPlayer;}
case TEAM_TERRORIST: {k = MAX_PLAYERS + iPlayer;}
case TEAM_CT: {k = MAX_PLAYERS * 2 + iPlayer;}
default: {k = 0;}
}
if (g_aPlayerWeapon[k][iWeapon][iPriority] < aData[iWmType])
{
if (is_replace(iPlayer, aData[iWmType], aData[szWmParam]))
{
g_aPlayerWeapon[k][iWeapon][iPriority] = aData[iWmType];
if (aData[szWmModelP]) copy(g_aPlayerWeapon[k][iWeapon][szModelP], MAX_MODELS_LENGTH - 1, aData[szWmModelP]);
if (aData[szWmModelV]) copy(g_aPlayerWeapon[k][iWeapon][szModelV], MAX_MODELS_LENGTH - 1, aData[szWmModelV]);
if (aData[szWmModelW]) copy(g_aPlayerWeapon[k][iWeapon][szModelW], MAX_MODELS_LENGTH - 1, aData[szWmModelW]);
if (aData[iWmModelW]) g_aPlayerWeapon[k][iWeapon][iModelW] = aData[iWmModelW];
}
}
else
if (aData[iWmType] == WM_ONLY_STEAM && is_user_steam(iPlayer))
{
if (!aData[szWmModelP]) copy(g_aPlayerWeapon[k][iWeapon][szModelP], MAX_MODELS_LENGTH - 1, aData[szWmModelP]);
if (!aData[szWmModelV]) copy(g_aPlayerWeapon[k][iWeapon][szModelV], MAX_MODELS_LENGTH - 1, aData[szWmModelV]);
if (!aData[szWmModelW]) copy(g_aPlayerWeapon[k][iWeapon][szModelW], MAX_MODELS_LENGTH - 1, aData[szWmModelW]);
if (aData[iWmModelW]) g_aPlayerWeapon[k][iWeapon][iModelW] = aData[iWmModelW];
}
else
if (aData[iWmType] == WM_ALL)
{
if (!aData[szWmModelP]) copy(g_aPlayerWeapon[k][iWeapon][szModelP], MAX_MODELS_LENGTH - 1, aData[szWmModelP]);
if (!aData[szWmModelV]) copy(g_aPlayerWeapon[k][iWeapon][szModelV], MAX_MODELS_LENGTH - 1, aData[szWmModelV]);
if (!aData[szWmModelW]) copy(g_aPlayerWeapon[k][iWeapon][szModelW], MAX_MODELS_LENGTH - 1, aData[szWmModelW]);
if (aData[iWmModelW]) g_aPlayerWeapon[k][iWeapon][iModelW] = aData[iWmModelW];
}
}
}
stock func_GetWeaponBoxWeapon(const iWeaponBox)
{
for (new i, iWeapon; i < MAX_ITEM_TYPES; i++)
{
iWeapon = get_member(iWeaponBox, m_WeaponBox_rgpPlayerItems, i);
if (!is_nullent(iWeapon)) return iWeapon;
}
return NULLENT;
}
stock get_plWeapon(iPlayer)
{
switch (get_member(iPlayer, m_iTeam))
{
case TEAM_UNASSIGNED: {return iPlayer;}
case TEAM_TERRORIST: {return MAX_PLAYERS + iPlayer;}
case TEAM_CT: {return MAX_PLAYERS * 2 + iPlayer;}
}
return 0;
}
stock bool: is_replace(const iPlayer, const SaveType: szType, const szParam[])
{
if (szType == WM_ALL) return true;
if (szType == WM_ONLY_STEAM && is_user_steam(iPlayer)) return true;
new szCopy[MAX_AUTHID_LENGTH];
if (szType == WM_NICK) get_user_name(iPlayer, szCopy, charsmax(szCopy));
else if (szType == WM_STEAM) get_user_authid(iPlayer, szCopy, charsmax(szCopy));
if (strcmp(szParam, szCopy) == 0) return true;
if (szType == WM_FLAGS && get_user_flags(iPlayer) & read_flags(szParam)) return true;
return false;
}
public bool: parse_key_value(INIParser: hParser, const szBuffer[])
{
if (g_iType == WM_NONE) return true;
new aData[ArrayData], szWeapon[16], szTeam[2];
aData[iWmType] = g_iType;
if (g_iType < WM_FLAGS)
{
parse(szBuffer, szTeam, charsmax(szTeam),
szWeapon, charsmax(szWeapon),
aData[szWmModelP], MAX_MODELS_LENGTH - 1,
aData[szWmModelV], MAX_MODELS_LENGTH - 1,
aData[szWmModelW], MAX_MODELS_LENGTH - 1);
}
else
{
parse(szBuffer, aData[szWmParam], charsmax(aData[szWmParam]),
szTeam, charsmax(szTeam),
szWeapon, charsmax(szWeapon),
aData[szWmModelP], MAX_MODELS_LENGTH - 1,
aData[szWmModelV], MAX_MODELS_LENGTH - 1,
aData[szWmModelW], MAX_MODELS_LENGTH - 1);
}
++g_iTotalLoaded;
if (!aData[szWmModelP] && !aData[szWmModelV] && !aData[szWmModelW]) return true;
switch (szTeam[0])
{
case 'T', 't': {aData[iTeam] = TEAM_TERRORIST;}
case 'C', 'c': {aData[iTeam] = TEAM_CT;}
case EOS: {aData[iTeam] = TEAM_UNASSIGNED;}
default:
{
log_amx("%l", "WM_NONE_PARAM_FOR_TEAM", szTeam);
return true;
}
}
if ((aData[iWmWeapon] = rg_get_weapon_info(fmt("weapon_%s", szWeapon), WI_ID)) == WEAPON_NONE)
{
log_amx("%l", "WM_BAD_WEAPON", szWeapon);
return true;
}
if ((g_iType >= WM_FLAGS) && !aData[szWmParam])
{
log_amx("%l", "WM_NONE_PARAM_FOR_TYPE", g_iType, szBuffer);
return true;
}
if (aData[szWmModelP]) precache_model(aData[szWmModelP]);
if (aData[szWmModelV]) precache_model(aData[szWmModelV]);
if (aData[szWmModelW])
{
switch (aData[iWmWeapon])
{
case WEAPON_FLASHBANG, WEAPON_HEGRENADE, WEAPON_SMOKEGRENADE, WEAPON_C4: {aData[iWmModelW] = precache_model(aData[szWmModelW]);}
default : {precache_model(aData[szWmModelW]);}
}
}
ArrayPushArray(g_aWeapons, aData);
return true;
}
public bool: parse_new_section(INIParser: hParser, const szSection[])
{
if (equal(szSection, "ALL STEAMS")) g_iType = WM_ONLY_STEAM;
else
{
switch (szSection[0])
{
case 'A': {g_iType = WM_ALL;}
case 'F': {g_iType = WM_FLAGS;}
case 'S': {g_iType = WM_STEAM;}
case 'N': {g_iType = WM_NICK;}
default: {g_iType = WM_NONE; log_amx("%l", "WM_BAD_TYPE", szSection);}
}
}
return true;
}