Added cvar mp_auto_reload_weapons

Added api hook SetClientUserInfoName
This commit is contained in:
s1lentq 2016-06-03 21:32:33 +06:00
parent 1fc388a2cc
commit c406141e47
16 changed files with 141 additions and 52 deletions

7
dist/game.cfg vendored
View File

@ -49,3 +49,10 @@ mp_nadedrops 0
//
// Default value: "20"
mp_roundrespawn_time 20
// Automatically reloaded all weapons a spawn the player
// 0 - disabled (default behaviour)
// 1 - enabled
//
// Default value: "0"
mp_auto_reload_weapons "0"

View File

@ -2584,12 +2584,11 @@ void EXT_FUNC ClientCommand(edict_t *pEntity)
{
if (!player->m_bVGUIMenus && !HandleMenu_ChooseTeam(player, slot))
{
player->m_iMenu = Menu_ChooseTeam;
if (player->m_iJoiningState == JOINED)
ShowVGUIMenu(player, VGUI_Menu_Team, (MENU_KEY_1 | MENU_KEY_2 | MENU_KEY_5 | MENU_KEY_0), "#IG_Team_Select");
else
ShowVGUIMenu(player, VGUI_Menu_Team, (MENU_KEY_1 | MENU_KEY_2 | MENU_KEY_5), "#Team_Select");
player->m_iMenu = Menu_ChooseTeam;
}
break;
}
@ -2617,26 +2616,25 @@ void EXT_FUNC ClientCommand(edict_t *pEntity)
{
case VGUI_MenuSlot_Buy_Pistol:
{
player->m_iMenu = Menu_BuyPistol;
if (player->m_iTeam == CT)
ShowVGUIMenu(player, VGUI_Menu_Buy_Pistol, (MENU_KEY_1 | MENU_KEY_2 | MENU_KEY_3 | MENU_KEY_4 | MENU_KEY_5 | MENU_KEY_0), "#CT_BuyPistol");
else
ShowVGUIMenu(player, VGUI_Menu_Buy_Pistol, (MENU_KEY_1 | MENU_KEY_2 | MENU_KEY_3 | MENU_KEY_4 | MENU_KEY_5 | MENU_KEY_0), "#T_BuyPistol");
player->m_iMenu = Menu_BuyPistol;
break;
}
case VGUI_MenuSlot_Buy_ShotGun:
{
player->m_iMenu = Menu_BuyShotgun;
if (CSGameRules()->m_iMapHasVIPSafetyZone == MAP_HAVE_VIP_SAFETYZONE_YES && player->m_iTeam == TERRORIST)
ShowVGUIMenu(player, VGUI_Menu_Buy_ShotGun, MENU_KEY_0, "#AS_BuyShotgun");
else
ShowVGUIMenu(player, VGUI_Menu_Buy_ShotGun, (MENU_KEY_1 | MENU_KEY_2 | MENU_KEY_0), "#BuyShotgun");
player->m_iMenu = Menu_BuyShotgun;
break;
}
case VGUI_MenuSlot_Buy_SubMachineGun:
{
player->m_iMenu = Menu_BuySubMachineGun;
if (CSGameRules()->m_iMapHasVIPSafetyZone == MAP_HAVE_VIP_SAFETYZONE_YES)
{
if (player->m_iTeam == CT)
@ -2651,12 +2649,11 @@ void EXT_FUNC ClientCommand(edict_t *pEntity)
else
ShowVGUIMenu(player, VGUI_Menu_Buy_SubMachineGun, (MENU_KEY_1 | MENU_KEY_2 | MENU_KEY_3 | MENU_KEY_4 | MENU_KEY_0), "#T_BuySubMachineGun");
}
player->m_iMenu = Menu_BuySubMachineGun;
break;
}
case VGUI_MenuSlot_Buy_Rifle:
{
player->m_iMenu = Menu_BuyRifle;
if (CSGameRules()->m_iMapHasVIPSafetyZone == MAP_HAVE_VIP_SAFETYZONE_YES)
{
if (player->m_iTeam == CT)
@ -2671,18 +2668,15 @@ void EXT_FUNC ClientCommand(edict_t *pEntity)
else
ShowVGUIMenu(player, VGUI_Menu_Buy_Rifle, (MENU_KEY_1 | MENU_KEY_2 | MENU_KEY_3 | MENU_KEY_4 | MENU_KEY_5 | MENU_KEY_6 | MENU_KEY_0), "#T_BuyRifle");
}
player->m_iMenu = Menu_BuyRifle;
break;
}
case VGUI_MenuSlot_Buy_MachineGun:
{
player->m_iMenu = Menu_BuyMachineGun;
if (CSGameRules()->m_iMapHasVIPSafetyZone == MAP_HAVE_VIP_SAFETYZONE_YES && player->m_iTeam == TERRORIST)
ShowVGUIMenu(player, VGUI_Menu_Buy_MachineGun, MENU_KEY_0, "#AS_T_BuyMachineGun");
else
ShowVGUIMenu(player, VGUI_Menu_Buy_MachineGun, (MENU_KEY_1 | MENU_KEY_0), "#BuyMachineGun");
player->m_iMenu = Menu_BuyMachineGun;
break;
}
case VGUI_MenuSlot_Buy_PrimAmmo:
@ -2727,6 +2721,7 @@ void EXT_FUNC ClientCommand(edict_t *pEntity)
{
if (player->m_signals.GetState() & SIGNAL_BUY)
{
player->m_iMenu = Menu_BuyItem;
if (CSGameRules()->m_bMapHasBombTarget)
{
if (player->m_iTeam == CT)
@ -2741,8 +2736,6 @@ void EXT_FUNC ClientCommand(edict_t *pEntity)
else
ShowVGUIMenu(player, VGUI_Menu_Buy_Item, (MENU_KEY_1 | MENU_KEY_2 | MENU_KEY_3 | MENU_KEY_4 | MENU_KEY_5 | MENU_KEY_6 | MENU_KEY_0), "#T_BuyItem");
}
player->m_iMenu = Menu_BuyItem;
}
break;
}
@ -2836,6 +2829,7 @@ void EXT_FUNC ClientCommand(edict_t *pEntity)
if (!CSGameRules()->IsCareer())
{
player->m_iMenu = Menu_ChooseTeam;
if (CSGameRules()->m_iMapHasVIPSafetyZone == MAP_HAVE_VIP_SAFETYZONE_YES && player->m_iJoiningState == JOINED && player->m_iTeam == CT)
{
if (CSGameRules()->IsFreezePeriod() || player->pev->deadflag != DEAD_NO)
@ -2850,8 +2844,6 @@ void EXT_FUNC ClientCommand(edict_t *pEntity)
else
ShowVGUIMenu(player, VGUI_Menu_Team, (MENU_KEY_1 | MENU_KEY_2 | MENU_KEY_5 | MENU_KEY_0), "#IG_Team_Select");
}
player->m_iMenu = Menu_ChooseTeam;
}
}
else if (FStrEq(pcmd, "showbriefing"))
@ -2979,12 +2971,11 @@ void EXT_FUNC ClientCommand(edict_t *pEntity)
}
else
{
player->m_iMenu = Menu_ChooseTeam;
if (player->m_iJoiningState == JOINED)
ShowVGUIMenu(player, VGUI_Menu_Team, (MENU_KEY_1 | MENU_KEY_2 | MENU_KEY_5 | MENU_KEY_0), "#IG_Team_Select");
else
ShowVGUIMenu(player, VGUI_Menu_Team, (MENU_KEY_1 | MENU_KEY_2 | MENU_KEY_5), "#Team_Select");
player->m_iMenu = Menu_ChooseTeam;
}
}
else if (FStrEq(pcmd, "joinclass"))
@ -3257,14 +3248,10 @@ void EXT_FUNC ClientUserInfoChanged(edict_t *pEntity, char *infobuffer)
{
// Is the client spawned yet?
if (!pEntity->pvPrivateData)
{
return;
}
CBasePlayer *pPlayer = (CBasePlayer *)CBaseEntity::Instance(pEntity);
char *szBufferName = GET_KEY_VALUE(infobuffer, "name");
int iClientIndex = pPlayer->entindex();
// msg everyone if someone changes their name, and it isn't the first time (changing no name to current name)
if (pEntity->v.netname && STRING(pEntity->v.netname)[0] != '\0' && !FStrEq(STRING(pEntity->v.netname), szBufferName))
@ -3283,30 +3270,15 @@ void EXT_FUNC ClientUserInfoChanged(edict_t *pEntity, char *infobuffer)
if (szName[0] == '#')
szName[0] = '*';
if (pPlayer->pev->deadflag != DEAD_NO)
{
pPlayer->m_bHasChangedName = true;
Q_snprintf(pPlayer->m_szNewName, sizeof(pPlayer->m_szNewName), "%s", szName);
ClientPrint(pPlayer->pev, HUD_PRINTTALK, "#Name_change_at_respawn");
SET_CLIENT_KEY_VALUE(iClientIndex, infobuffer, "name", (char *)STRING(pEntity->v.netname));
}
else
{
// Set the name
SET_CLIENT_KEY_VALUE(iClientIndex, infobuffer, "name", szName);
MESSAGE_BEGIN(MSG_BROADCAST, gmsgSayText);
WRITE_BYTE(iClientIndex);
WRITE_STRING("#Cstrike_Name_Change");
WRITE_STRING(STRING(pEntity->v.netname));
WRITE_STRING(szName);
MESSAGE_END();
UTIL_LogPrintf("\"%s<%i><%s><%s>\" changed name to \"%s\"\n", STRING(pEntity->v.netname), GETPLAYERUSERID(pEntity), GETPLAYERAUTHID(pEntity), GetTeam(pPlayer->m_iTeam), szName);
}
pPlayer->SetClientUserInfoName(infobuffer, szName);
}
// was already checking on pvPrivateData
#ifndef REGAMEDLL_FIXES
g_pGameRules->ClientUserInfoChanged(GetClassPtr<CCSPlayer>((CBasePlayer *)&pEntity->v), infobuffer);
#else
g_pGameRules->ClientUserInfoChanged(pPlayer, infobuffer);
#endif
}
void EXT_FUNC ServerDeactivate()
@ -3885,10 +3857,7 @@ void ClientPrecache()
const char *EXT_FUNC GetGameDescription()
{
if (g_bIsCzeroGame)
return "Condition Zero";
return "Counter-Strike";
return g_bIsCzeroGame ? "Condition Zero" : "Counter-Strike";
}
void EXT_FUNC Sys_Error(const char *error_string)

View File

@ -101,6 +101,7 @@ cvar_t round_infinite = { "mp_round_infinite", "0", FCVAR_SERVER, 0.0f, nullptr
cvar_t hegrenade_penetration = { "mp_hegrenade_penetration", "0", 0, 0.0f, nullptr };
cvar_t nadedrops = { "mp_nadedrops", "0", 0, 0.0f, nullptr };
cvar_t roundrespawn_time = { "mp_roundrespawn_time", "20", 0, 20.0f, nullptr };
cvar_t auto_reload_weapons = { "mp_auto_reload_weapons", "0", 0, 0.0f, nullptr };
void GameDLL_Version_f()
{
@ -228,6 +229,7 @@ void EXT_FUNC GameDLLInit()
CVAR_REGISTER(&hegrenade_penetration);
CVAR_REGISTER(&nadedrops);
CVAR_REGISTER(&roundrespawn_time);
CVAR_REGISTER(&auto_reload_weapons);
// print version
CONSOLE_ECHO("ReGameDLL build: " __TIME__ " " __DATE__ " (" APP_VERSION_STRD ")\n");

View File

@ -138,6 +138,7 @@ extern cvar_t round_infinite;
extern cvar_t hegrenade_penetration;
extern cvar_t nadedrops;
extern cvar_t roundrespawn_time;
extern cvar_t auto_reload_weapons;
#endif

View File

@ -341,6 +341,34 @@ const char *GetCSModelName(int item_id)
return modelName;
}
LINK_HOOK_CLASS_VOID_CHAIN(CBasePlayer, SetClientUserInfoName, (char *infobuffer, char *szNewName), infobuffer, szNewName);
void EXT_FUNC CBasePlayer::__API_HOOK(SetClientUserInfoName)(char *infobuffer, char *szNewName)
{
int nClientIndex = entindex();
if (pev->deadflag != DEAD_NO)
{
m_bHasChangedName = true;
Q_snprintf(m_szNewName, sizeof(m_szNewName), "%s", szNewName);
ClientPrint(pev, HUD_PRINTTALK, "#Name_change_at_respawn");
SET_CLIENT_KEY_VALUE(nClientIndex, infobuffer, "name", (char *)STRING(pev->netname));
}
else
{
// Set the name
SET_CLIENT_KEY_VALUE(nClientIndex, infobuffer, "name", szNewName);
MESSAGE_BEGIN(MSG_BROADCAST, gmsgSayText);
WRITE_BYTE(nClientIndex);
WRITE_STRING("#Cstrike_Name_Change");
WRITE_STRING(STRING(pev->netname));
WRITE_STRING(szNewName);
MESSAGE_END();
UTIL_LogPrintf("\"%s<%i><%s><%s>\" changed name to \"%s\"\n", STRING(pev->netname), GETPLAYERUSERID(edict()), GETPLAYERAUTHID(edict()), GetTeam(m_iTeam), szNewName);
}
}
void EXT_FUNC CBasePlayer::SetClientUserInfoModel_api(char *infobuffer, char *szNewModel)
{
SET_CLIENT_KEY_VALUE(entindex(), infobuffer, "model", szNewModel);
@ -5228,6 +5256,12 @@ void CBasePlayer::__API_VHOOK(Spawn)()
m_iFlashBattery = 99;
m_flFlashLightTime = 1;
#ifdef REGAMEDLL_ADD
if (auto_reload_weapons.string[0] == '1') {
ReloadWeapons();
}
#endif
if (m_bHasDefuser)
pev->body = 1;
else
@ -5383,11 +5417,12 @@ void CBasePlayer::__API_VHOOK(Spawn)()
m_flLastCommandTime[i] = -1;
#ifdef REGAMEDLL_FIXES
if (!m_bJustConnected) {
FireTargets("game_playerspawn", this, this, USE_TOGGLE, 0);
}
#endif
// everything that comes after this, this spawn of the player a the game.
if (m_bJustConnected)
return;
FireTargets("game_playerspawn", this, this, USE_TOGGLE, 0);
#endif
}
LINK_HOOK_CLASS_VOID_CHAIN2(CBasePlayer, Precache);
@ -9207,3 +9242,33 @@ void CBasePlayer::UpdateLocation(bool forceUpdate)
}
}
}
void CBasePlayer::ReloadWeapons(CBasePlayerItem *pWeapon)
{
// if we died in the previous round
// so that we have nothing to reload
if (!m_bNotKilled)
return;
// to ignore first spawn on ClientPutinServer
if (m_bJustConnected)
return;
for (int i = PRIMARY_WEAPON_SLOT; i <= PISTOL_SLOT; ++i)
{
auto item = m_rgpPlayerItems[i];
while (item != nullptr)
{
if (pWeapon == nullptr || pWeapon == item)
((CBasePlayerWeapon *)item)->InstantReload();
if (pWeapon == item)
break;
item = item->m_pNext;
}
if (pWeapon != nullptr && pWeapon == item)
break;
}
}

View File

@ -457,6 +457,8 @@ public:
void SetProgressBarTime(int time);
void SetProgressBarTime2(int time, float timeElapsed);
void SetPlayerModel(BOOL HasC4);
void SetClientUserInfoName(char *infobuffer, char *szNewName);
void SetClientUserInfoName_(char *infobuffer, char *szNewName);
void SetClientUserInfoModel(char *infobuffer, char *szNewModel);
void SetClientUserInfoModel_api(char *infobuffer, char *szNewModel);
void SetNewPlayerModel(const char *modelName);
@ -587,6 +589,7 @@ public:
void SendItemStatus();
edict_t *EntSelectSpawnPoint();
void SetScoreAttrib(CBasePlayer *dest);
void ReloadWeapons(CBasePlayerItem *pWeapon = nullptr);
#ifdef REGAMEDLL_ADD
CCSPlayer *CSPlayer() const;

View File

@ -2232,3 +2232,23 @@ void CArmoury::__MAKE_VHOOK(KeyValue)(KeyValueData *pkvd)
}
LINK_ENTITY_TO_CLASS(armoury_entity, CArmoury, CCSArmoury);
void CBasePlayerWeapon::InstantReload()
{
// if you already reload
if (m_fInReload)
return;
if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0)
return;
// complete the reload.
int j = Q_min(iMaxClip() - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]);
if (j == 0)
return;
// Add them to the clip
m_iClip += j;
m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= j;
m_pPlayer->TabulateAmmo();
}

View File

@ -398,6 +398,7 @@ public:
void SetPlayerShieldAnim();
void ResetPlayerShieldAnim();
bool ShieldSecondaryFire(int iUpAnim, int iDownAnim);
void InstantReload();
public:
static TYPEDESCRIPTION IMPL(m_SaveData)[7];

View File

@ -153,6 +153,9 @@ typedef IVoidHookChainRegistryClass<class CBasePlayer, bool> IReGameHookRegistry
typedef IVoidHookChain<char *, char *> IReGameHook_CBasePlayer_SetClientUserInfoModel;
typedef IVoidHookChainRegistryClass<class CBasePlayer, char *, char *> IReGameHookRegistry_CBasePlayer_SetClientUserInfoModel;
// CBasePlayer:SetClientUserInfoName hook
typedef IVoidHookChain<char *, char *> IReGameHook_CBasePlayer_SetClientUserInfoName;
typedef IVoidHookChainRegistryClass<class CBasePlayer, char *, char *> IReGameHookRegistry_CBasePlayer_SetClientUserInfoName;
// CBaseAnimating::ResetSequenceInfo hook
typedef IVoidHookChain<> IReGameHook_CBaseAnimating_ResetSequenceInfo;
@ -375,6 +378,8 @@ public:
virtual IReGameHookRegistry_CSGameRules_GoToIntermission* CSGameRules_GoToIntermission() = 0;
virtual IReGameHookRegistry_CSGameRules_BalanceTeams* CSGameRules_BalanceTeams() = 0;
// later sort them on the positions and change the major version
virtual IReGameHookRegistry_CBasePlayer_SetClientUserInfoName* CBasePlayer_SetClientUserInfoName() = 0;
};
struct ReGameFuncs_t {

View File

@ -76,6 +76,7 @@ public:
virtual void SetBombIcon(bool bFlash = false);
virtual void SetScoreAttrib(CBasePlayer *dest);
virtual void SendItemStatus();
virtual void ReloadWeapons(CBasePlayerItem *pWeapon = nullptr);
CBasePlayer *BasePlayer() const;
public:

View File

@ -153,6 +153,9 @@ typedef IVoidHookChainRegistryClass<class CBasePlayer, bool> IReGameHookRegistry
typedef IVoidHookChain<char *, char *> IReGameHook_CBasePlayer_SetClientUserInfoModel;
typedef IVoidHookChainRegistryClass<class CBasePlayer, char *, char *> IReGameHookRegistry_CBasePlayer_SetClientUserInfoModel;
// CBasePlayer:SetClientUserInfoName hook
typedef IVoidHookChain<char *, char *> IReGameHook_CBasePlayer_SetClientUserInfoName;
typedef IVoidHookChainRegistryClass<class CBasePlayer, char *, char *> IReGameHookRegistry_CBasePlayer_SetClientUserInfoName;
// CBaseAnimating::ResetSequenceInfo hook
typedef IVoidHookChain<> IReGameHook_CBaseAnimating_ResetSequenceInfo;
@ -375,6 +378,8 @@ public:
virtual IReGameHookRegistry_CSGameRules_GoToIntermission* CSGameRules_GoToIntermission() = 0;
virtual IReGameHookRegistry_CSGameRules_BalanceTeams* CSGameRules_BalanceTeams() = 0;
// later sort them on the positions and change the major version
virtual IReGameHookRegistry_CBasePlayer_SetClientUserInfoName* CBasePlayer_SetClientUserInfoName() = 0;
};
struct ReGameFuncs_t {

View File

@ -76,6 +76,7 @@ public:
virtual void SetBombIcon(bool bFlash = false);
virtual void SetScoreAttrib(CBasePlayer *dest);
virtual void SendItemStatus();
virtual void ReloadWeapons(CBasePlayerItem *pWeapon = nullptr);
CBasePlayer *BasePlayer() const;
public:

View File

@ -75,6 +75,7 @@ IReGameHookRegistry_CBasePlayer_GiveNamedItem* CReGameHookchains::CBasePlayer_Gi
IReGameHookRegistry_CBasePlayer_AddAccount* CReGameHookchains::CBasePlayer_AddAccount() { return &m_CBasePlayer_AddAccount; }
IReGameHookRegistry_CBasePlayer_GiveShield* CReGameHookchains::CBasePlayer_GiveShield() { return &m_CBasePlayer_GiveShield; }
IReGameHookRegistry_CBasePlayer_SetClientUserInfoModel* CReGameHookchains::CBasePlayer_SetClientUserInfoModel() { return &m_CBasePlayer_SetClientUserInfoModel; }
IReGameHookRegistry_CBasePlayer_SetClientUserInfoName* CReGameHookchains::CBasePlayer_SetClientUserInfoName() { return &m_CBasePlayer_SetClientUserInfoName; }
IReGameHookRegistry_CBaseAnimating_ResetSequenceInfo* CReGameHookchains::CBaseAnimating_ResetSequenceInfo() { return &m_CBaseAnimating_ResetSequenceInfo; }

View File

@ -148,6 +148,10 @@ typedef IVoidHookChainRegistryClassImpl<CBasePlayer, bool> CReGameHookRegistry_C
typedef IVoidHookChainClassImpl<CBasePlayer, char *, char *> CReGameHook_CBasePlayer_SetClientUserInfoModel;
typedef IVoidHookChainRegistryClassImpl<CBasePlayer, char *, char *> CReGameHookRegistry_CBasePlayer_SetClientUserInfoModel;
// CBasePlayer:SetClientUserInfoName hook
typedef IVoidHookChainClassImpl<CBasePlayer, char *, char *> CReGameHook_CBasePlayer_SetClientUserInfoName;
typedef IVoidHookChainRegistryClassImpl<CBasePlayer, char *, char *> CReGameHookRegistry_CBasePlayer_SetClientUserInfoName;
// CBaseAnimating::ResetSequenceInfo hook
typedef IVoidHookChainClassImpl<CBaseAnimating> CReGameHook_CBaseAnimating_ResetSequenceInfo;
@ -367,6 +371,7 @@ public:
CReGameHookRegistry_CSGameRules_GoToIntermission m_CSGameRules_GoToIntermission;
CReGameHookRegistry_CSGameRules_BalanceTeams m_CSGameRules_BalanceTeams;
CReGameHookRegistry_CBasePlayer_SetClientUserInfoName m_CBasePlayer_SetClientUserInfoName;
public:
virtual IReGameHookRegistry_CBasePlayer_Spawn* CBasePlayer_Spawn();
virtual IReGameHookRegistry_CBasePlayer_Precache* CBasePlayer_Precache();
@ -437,6 +442,8 @@ public:
virtual IReGameHookRegistry_CSGameRules_ChangeLevel* CSGameRules_ChangeLevel();
virtual IReGameHookRegistry_CSGameRules_GoToIntermission* CSGameRules_GoToIntermission();
virtual IReGameHookRegistry_CSGameRules_BalanceTeams* CSGameRules_BalanceTeams();
virtual IReGameHookRegistry_CBasePlayer_SetClientUserInfoName* CBasePlayer_SetClientUserInfoName();
};
extern CReGameHookchains g_ReGameHookchains;

View File

@ -84,3 +84,4 @@ edict_t *CCSPlayer::EntSelectSpawnPoint() { return BasePlayer()->EntSelectSpawnP
void CCSPlayer::SendItemStatus() { BasePlayer()->SendItemStatus(); }
void CCSPlayer::SetBombIcon(bool bFlash) { BasePlayer()->SetBombIcon(bFlash ? TRUE : FALSE); }
void CCSPlayer::SetScoreAttrib(CBasePlayer *dest) { BasePlayer()->SetScoreAttrib(dest); }
void CCSPlayer::ReloadWeapons(CBasePlayerItem *pWeapon) { BasePlayer()->ReloadWeapons(pWeapon); }

View File

@ -70,7 +70,7 @@
ret className::functionName args {\
return g_ReGameHookchains.m_##customPrefix##_##functionName.callChain(&className::functionName##_, this, __VA_ARGS__);\
}
#define LINK_HOOK_CLASS_CUSTOM_CHAIN2(ret, className, functionName)\
#define LINK_HOOK_CLASS_CUSTOM_CHAIN2(ret, className, customPrefix, functionName)\
ret className::functionName() {\
return g_ReGameHookchains.m_##customPrefix##_##functionName.callChain(&className::functionName##_, this);\
}