void *SpawnSpecial::OnSpawnSpecial(ZombieClassType zombieClassType, void *vector, void *qangle)
	{
		L4D_DEBUG_LOG("ZombieManager::SpawnSpecial has been called with class %d", zombieClassType);

		cell_t result = Pl_Continue;
		cell_t overrideZombieClass = zombieClassType;
		if(g_pFwdOnSpawnSpecial)
		{
			L4D_DEBUG_LOG("L4D_OnSpawnSpecial forward has been sent out");
			g_pFwdOnSpawnSpecial->PushCellByRef(&overrideZombieClass);
			g_pFwdOnSpawnSpecial->PushArray(reinterpret_cast<cell_t*>(vector), 3);
			g_pFwdOnSpawnSpecial->PushArray(reinterpret_cast<cell_t*>(qangle), 3);
			g_pFwdOnSpawnSpecial->Execute(&result);
		}

		if(result == Pl_Handled)
		{
			L4D_DEBUG_LOG("ZombieManager::SpawnSpecial will be skipped");
			return NULL;
		}
		else if(result == Pl_Changed)
		{
			L4D_DEBUG_LOG("ZombieManager::SpawnSpecial will be called with class %d", overrideZombieClass);
			return (this->*(GetTrampoline()))(*reinterpret_cast<ZombieClassType*>(&overrideZombieClass), vector, qangle);
		}
		else
		{
			return (this->*(GetTrampoline()))(zombieClassType, vector, qangle);
		}
	}
	void *GetScriptValueString::OnGetScriptValueString(const char *key, const char *defaultValue, char *retValue, int sizeof_retValue)
	{
		L4D_DEBUG_LOG("CDirector::GetScriptValue(%s,%s,%s,%d) is about to be called", key, defaultValue, retValue, sizeof_retValue);
		
		cell_t result = Pl_Continue;

		(this->*(GetTrampoline()))(key, defaultValue, retValue, sizeof_retValue);

		L4D_DEBUG_LOG("CDirector::GetScriptValue() passed string result: %s", retValue);
		
		if(g_pFwdOnGetScriptValueString)
		{
			//L4D_DEBUG_LOG("L4D_OnGetScriptValueString() forward has been sent out");
			g_pFwdOnGetScriptValueString->PushString(key);
			defaultValue == NULL ? g_pFwdOnGetScriptValueString->PushString("") : g_pFwdOnGetScriptValueString->PushString(key);
			g_pFwdOnGetScriptValueString->PushStringEx(retValue, sizeof_retValue, SM_PARAM_STRING_COPY, SM_PARAM_COPYBACK);
			g_pFwdOnGetScriptValueString->Execute(&result);
		}

		if(result == Pl_Handled)
		{
			L4D_DEBUG_LOG("CDirector::OnGetScriptValueString will be skipped");
			return NULL;
		}
		else
		{
			return (this->*(GetTrampoline()))(key, defaultValue, retValue, sizeof_retValue);
		}
	}
	void ChangeFinaleStage::OnChangeFinaleStage(int finaleType, const char *key)
	{
		cell_t result = Pl_Continue;

		if(g_pFwdOnChangeFinaleStage)
		{
			L4D_DEBUG_LOG("L4D2_OnChangeFinaleStage(%d, [%s]) forward has been sent out", finaleType, key);
			g_pFwdOnChangeFinaleStage->PushCellByRef(&finaleType);

			if (key != NULL)
			{
				g_pFwdOnChangeFinaleStage->PushString(key);
			}
			else
			{
				g_pFwdOnChangeFinaleStage->PushString("");
			}
			g_pFwdOnChangeFinaleStage->Execute(&result);
		}

		if(result == Pl_Handled)
		{
			L4D_DEBUG_LOG("L4D2_OnChangeFinaleStage() will be skipped");
			return;
		}
		else
		{
			(this->*(GetTrampoline()))(finaleType, key);
			return;
		}
	}
	float GetScriptValueFloat::OnGetScriptValueFloat(const char *key, float defaultValue)
	{
		//L4D_DEBUG_LOG("CDirector::GetScriptValue(%s,%d) has been called", key, defaultValue);

		cell_t result = Pl_Continue;

		float actualInvocationResult = (this->*(GetTrampoline()))(key, defaultValue);

		float overrideValue = actualInvocationResult;
		if(g_pFwdOnGetScriptValueFloat)
		{
			//L4D_DEBUG_LOG("L4D_OnGetScriptValueFloat() forward has been sent out");
			g_pFwdOnGetScriptValueFloat->PushString(key);
			g_pFwdOnGetScriptValueFloat->PushFloatByRef(&overrideValue);
			float exec = g_pFwdOnGetScriptValueFloat->Execute(&result);
			//L4D_DEBUG_LOG("L4D_OnGetScriptValueFloat() forward result = %d (0 means no error)", exec);
		}

		if(result == Pl_Handled)
		{
			//L4D_DEBUG_LOG("CDirector::OnGetScriptValueFloat return value overriden with %d", overrideValue);
			return overrideValue;
		}
		else
		{
			return actualInvocationResult;
		}
	}
	float GetRunTopSpeed::OnGetRunTopSpeed()
	{
		//L4D_DEBUG_LOG("CTerrorPlayer::GetRunTopSpeed() has been called");

		cell_t result = Pl_Continue;

		float actualInvocationResult = (this->*(GetTrampoline()))();

		float overrideValue = actualInvocationResult;
		
		if(g_pFwdOnGetRunTopSpeed)
		{
			edict_t *pEntity = gameents->BaseEntityToEdict(reinterpret_cast<CBaseEntity*>(this));
			int target = IndexOfEdict(pEntity);
		
			//L4D_DEBUG_LOG("L4D_OnGetRunTopSpeed(target %d) forward has been sent out", target);
			g_pFwdOnGetRunTopSpeed->PushCell(target);
			g_pFwdOnGetRunTopSpeed->PushFloatByRef(&overrideValue);
			g_pFwdOnGetRunTopSpeed->Execute(&result);
		}

		if(result == Pl_Handled)
		{
			//L4D_DEBUG_LOG("CTerrorPlayer::GetRunTopSpeed() return value overriden with %d", overrideValue);
			return overrideValue;
		}
		else
		{
			return actualInvocationResult;
		}
	}
	int FastGetSurvivorSet::OnFastGetSurvivorSet()
	{
		//L4D_DEBUG_LOG("FastGetSurvivorSet() has been called");

		cell_t result = Pl_Continue;

		int actualInvocationResult = (this->*(GetTrampoline()))();

		int overrideValue = actualInvocationResult;
		
		if(g_pFwdOnFastGetSurvivorSet)
		{
			//L4D_DEBUG_LOG("L4D_OnFastGetSurvivorSet(return %d) forward has been sent out", target);
			g_pFwdOnFastGetSurvivorSet->PushCellByRef(&overrideValue);
			g_pFwdOnFastGetSurvivorSet->Execute(&result);
		}

		if(result == Pl_Handled)
		{
			//L4D_DEBUG_LOG("CTerrorPlayer::FastGetSurvivorSet() return value overriden with %d", overrideValue);
			return overrideValue;
		}
		else
		{
			return actualInvocationResult;
		}
	}
	void EndVersusModeRound::OnEndVersusModeRound(bool countSurvivors)
	{
		L4D_DEBUG_LOG("CDirectorVersusMode::EndVersusModeRound(%s) has been called", countSurvivors ? "true" : "false");
		
		if(g_bRoundEnd) return;
		g_bRoundEnd = true;
		
		cell_t result = Pl_Continue;
		if(g_pFwdOnEndVersusModeRound)
		{
			L4D_DEBUG_LOG("L4D2_OnEndVersusModeRound forward has been sent out");
			g_pFwdOnEndVersusModeRound->PushCell(static_cast<bool>(countSurvivors));
			g_pFwdOnEndVersusModeRound->Execute(&result);
		}
		
		if(result == Pl_Handled) return;
		
		(this->*(GetTrampoline()))(countSurvivors);

		if(g_pFwdOnEndVersusModeRound_Post)
		{
			L4D_DEBUG_LOG("L4D2_OnEndVersusModeRound_Post forward has been sent out");
			g_pFwdOnEndVersusModeRound_Post->Execute(NULL);
		}
	   
		return;
	}
	int HasConfigurableDifficulty::OnHasConfigurableDifficulty()
	{
		//L4D_DEBUG_LOG("HasConfigurableDifficulty() has been called");

		cell_t result = Pl_Continue;

		int actualInvocationResult = (this->*(GetTrampoline()))();

		int overrideValue = actualInvocationResult;
		
		if(g_pFwdOnHasConfigurableDifficulty)
		{
			//L4D_DEBUG_LOG("L4D_OnHasConfigurableDifficulty(return %d) forward has been sent out", target);
			g_pFwdOnHasConfigurableDifficulty->PushCellByRef(&overrideValue);
			g_pFwdOnHasConfigurableDifficulty->Execute(&result);
		}

		if(result == Pl_Handled)
		{
			//L4D_DEBUG_LOG("CTerrorGameRules::HasConfigurableDifficulty() return value overriden with %d", overrideValue);
			return overrideValue;
		}
		else
		{
			return actualInvocationResult;
		}
	}
	void ClearTeamScores::OnClearTeamScores(CLEAR_TEAM_SCORES_ARG)
	{
		bool b = newCampaign;

		L4D_DEBUG_LOG("CTerrorGameRules::ClearTeamScores has been called, bool=%d", b);

		cell_t result = Pl_Continue;
		if(g_pFwdOnClearTeamScores)
		{
			L4D_DEBUG_LOG("L4D_OnClearTeamScores forward has been sent out");
			g_pFwdOnClearTeamScores->PushCell(static_cast<cell_t>(b));
			g_pFwdOnClearTeamScores->Execute(&result);
		}

		if(result == Pl_Handled)
		{
			L4D_DEBUG_LOG("CTerrorGameRules::ClearTeamScores will be skipped");
			return;
		}
		else
		{
			(this->*(GetTrampoline()))(b);
			return;
		}
	}
    void ReplaceTank::OnReplaceTank(CTerrorPlayer* tank, CTerrorPlayer* newtank)
    {
	(this->*(GetTrampoline()))(tank, newtank);
	
	if (g_pFwdOnReplaceTank)
	{
		int old_tank = IndexOfEdict(gameents->BaseEntityToEdict(reinterpret_cast<CBaseEntity *>(tank)));
		int new_tank = IndexOfEdict(gameents->BaseEntityToEdict(reinterpret_cast<CBaseEntity *>(newtank)));

		g_pFwdOnReplaceTank->PushCell(old_tank);
		g_pFwdOnReplaceTank->PushCell(new_tank);
		g_pFwdOnReplaceTank->Execute(NULL);
	}
    }
	int ShovedBySurvivor::OnShovedBySurvivor(CBaseEntity *sourceEnt, void *sourceDir)
	{
		cell_t result = Pl_Continue;

		if (g_pFwdOnShovedBySurvivor)
		{
			cell_t target = IndexOfEdict(gameents->BaseEntityToEdict(reinterpret_cast<CBaseEntity*>(this)));
			edict_t *pSource = gameents->BaseEntityToEdict(sourceEnt);

			g_pFwdOnShovedBySurvivor->PushCell(target);
			g_pFwdOnShovedBySurvivor->PushCell(pSource ? IndexOfEdict(pSource) : 0);
			g_pFwdOnShovedBySurvivor->Execute(&result);
		}

		return result == Pl_Handled ? 0 : (this->*(GetTrampoline()))(sourceEnt, sourceDir);
	}
	void *PlayerUse::OnPlayerUse(CBaseEntity *p)
	{
		cell_t result = Pl_Continue;

		if (g_pFwdOnPlayerUse)
		{
			cell_t client = IndexOfEdict(gameents->BaseEntityToEdict(reinterpret_cast<CBaseEntity*>(this)));	
			cell_t entity = IndexOfEdict(gameents->BaseEntityToEdict(p));

			g_pFwdOnPlayerUse->PushCell(client);
			g_pFwdOnPlayerUse->PushCell(entity);
			g_pFwdOnPlayerUse->Execute(&result);
		}

		return result == Pl_Handled ? 0 : (this->*(GetTrampoline()))(p);
	}
	int __thiscall RevivedByDefib::OnRevived(CBaseEntity *pInitiator, void *deathModel)
	{
		CBaseEntity* pTarget = reinterpret_cast<CBaseEntity*>(this);
		cell_t client = gamehelpers->EntityToBCompatRef(pTarget);

		IGamePlayer* pGamePlayer = playerhelpers->GetGamePlayer(client);
		if(pGamePlayer) {
			IPlayerInfo* pInfo = pGamePlayer->GetPlayerInfo();
			if(pInfo) {
				r_nowAlive(pInfo->GetAbsOrigin(), g_dead_players, arraysize(g_dead_players));
				L4D_DEBUG_LOG("RevivedByDefib called for: %s", pInfo->GetName());
			}
		}


		return (this->*(GetTrampoline()))(pInitiator, deathModel);
	}
	/*
	On Windows overwriting maxPlayers makes the server browser display that value
	On Linux overwriting maxPlayers only makes 'status' show that value as the max
	*/
	int ServerPlayerCounts::OnGetMasterServerPlayerCounts(int* currentPlayers, int* maxPlayers, int* unknownArg)
	{
		int arg1, arg2, arg3;

		int results = (this->*(GetTrampoline()))(&arg1, &arg2, &arg3);

		//spams log every 2 seconds
		//L4D_DEBUG_LOG("CServer::GetMasterServerPlayerCounts returned %d, args(%d, %d, %d) / MaxSlots = %d", results, arg1, arg2, arg3, ::PlayerSlots::MaxSlots);

		*currentPlayers = arg1;
		*maxPlayers = arg2;
		*unknownArg = arg3; //always 0 in brief testing

		if(::PlayerSlots::MaxSlots != -1)
		{
			*maxPlayers = ::PlayerSlots::MaxSlots;
		}

		return results;
	}
    void CBaseServer::OnFillServerInfo(int SVC_ServerInfo)
    {
        cell_t result = Pl_Continue;
    
        if (g_pFwdAddonsDisabler && AddonsDisabler::AddonsEclipse > 0 && vanillaModeSig)
        {
            int m_nPlayerSlot = *(int *)((unsigned char *)SVC_ServerInfo + 48);
            IClient *pClient = g_pServer->GetClient(m_nPlayerSlot);

            L4D_DEBUG_LOG("ADDONS DISABLER: Eligible client '%s' connected[%s]", pClient->GetClientName(), pClient->GetNetworkIDString());
            
            g_pFwdAddonsDisabler->PushString(pClient->GetNetworkIDString());
            g_pFwdAddonsDisabler->Execute(&result);
            
            /* uint8_t != unsigned char in terms of type */
            uint8_t disableAddons = result == Pl_Handled ? 0 : 1;
            memset((unsigned char *)SVC_ServerInfo + 25, disableAddons, sizeof(uint8_t));
        }

        (this->*(GetTrampoline()))(SVC_ServerInfo);
    }
    void *ShovedByPounceLanding::OnShovedByPounceLanding(CTerrorPlayer* jockeyOrHunter)
    {
		cell_t result = Pl_Continue;
		if (g_pFwdOnShovedByPounceLanding)
		{
			int victim = IndexOfEdict(gameents->BaseEntityToEdict(reinterpret_cast<CBaseEntity *>(this)));
			int attacker = IndexOfEdict(gameents->BaseEntityToEdict(reinterpret_cast<CBaseEntity *>(jockeyOrHunter)));

			g_pFwdOnShovedByPounceLanding->PushCell(victim);
			g_pFwdOnShovedByPounceLanding->PushCell(attacker);
			g_pFwdOnShovedByPounceLanding->Execute(&result);
		}

		if (result == Pl_Handled)
		{
			return NULL;
		}
		else
		{
			return (this->*(GetTrampoline()))(jockeyOrHunter);
		}
    }
	void *FirstSurvivorLeftSafeArea::OnFirstSurvivorLeftSafeArea(CTerrorPlayer *p)
	{
		L4D_DEBUG_LOG("CDirector::OnFirstSurvivorLeftSafeArea has been called");

		cell_t result = Pl_Continue;
		if(g_pFwdOnFirstSurvivorLeftSafeArea)
		{
			int client;
			if(p == NULL)
			{
				/*
				quite possible the survivor is NULL
				e.g. CDirectorScavengeMode::ShouldUpdateTeamReadiness
				calls OnFirstSurvivorLeftSafeArea(NULL)
				*/
				client = 0;
			}
			else
			{
				edict_t *pEntity = gameents->BaseEntityToEdict(reinterpret_cast<CBaseEntity*>(p));
				client = IndexOfEdict(pEntity);
			}

			L4D_DEBUG_LOG("L4D_OnFirstSurvivorLeftSafeArea(%d) forward has been sent out", client);
			g_pFwdOnFirstSurvivorLeftSafeArea->PushCell(client);
			g_pFwdOnFirstSurvivorLeftSafeArea->Execute(&result);
		}

		if(result == Pl_Handled)
		{
			L4D_DEBUG_LOG("CDirector::OnFirstSurvivorLeftSafeArea will be skipped");
			return NULL;
		}
		else
		{
			g_bRoundEnd = false;
			return (this->*(GetTrampoline()))(p);
		}
	}
Exemple #18
0
	void *SpawnTank::OnSpawnTank(void *vector, void *qangle)
	{
		L4D_DEBUG_LOG("ZombieManager::SpawnTank has been called");

		cell_t result = Pl_Continue;
		if(g_pFwdOnSpawnTank)
		{
			L4D_DEBUG_LOG("L4D_OnTankSpawn forward has been sent out");
			g_pFwdOnSpawnTank->PushArray(reinterpret_cast<cell_t*>(vector), 3);
			g_pFwdOnSpawnTank->PushArray(reinterpret_cast<cell_t*>(qangle), 3);
			g_pFwdOnSpawnTank->Execute(&result);
		}

		if(result == Pl_Handled)
		{
			L4D_DEBUG_LOG("ZombieManager::SpawnTank will be skipped");
			return NULL;
		}
		else
		{
			return (this->*(GetTrampoline()))(vector, qangle);
		}
	}
	void GameRulesNetworkChanged::OnGameRulesNetworkChanged()
	{		
		L4D_DEBUG_LOG("CTerrorGameRules::GameRulesNetworkChanged has been called");
		
		cell_t result = Pl_Continue;
		if(g_pFwdOnGameRulesNetworkChanged)
		{
			L4D_DEBUG_LOG("L4D_OnGameRulesNetworkChanged forward has been sent out");
			g_pFwdOnGameRulesNetworkChanged->Execute(&result);
		}

		if(result == Pl_Handled)
		{
			L4D_DEBUG_LOG("Director::GameRulesNetworkChanged will be skipped");
			return;
		}
		else
		{		
			L4D_DEBUG_LOG("CTerrorGameRules::GameRulesNetworkChanged will be invoked");

			return (this->*(GetTrampoline()))();
		}
	}
	ActionStruct_t JockeyAttackUpdate::OnJockeyAttackUpdate(Jockey* pJockey, float fu)
	{
		cell_t result = Pl_Continue;
		if(g_pFwdOnJockeyAttackUpdate)
		{
			edict_t *pJockeyEdict = gameents->BaseEntityToEdict(reinterpret_cast<CBaseEntity*>(pJockey));
			cell_t entity = IndexOfEdict(pJockeyEdict);
			cell_t victim = *(reinterpret_cast<cell_t*>(this)+13);
			g_pFwdOnJockeyAttackUpdate->PushCell(entity);
			g_pFwdOnJockeyAttackUpdate->PushCellByRef(&victim);
			g_pFwdOnJockeyAttackUpdate->Execute(&result);
			if(result == Pl_Handled)
			{
				*(reinterpret_cast<DWORD*>(this)+13) = NULL;
			}
			else if (result == Pl_Changed)
			{
				*(reinterpret_cast<DWORD*>(this)+13) = victim;
			}
		}
		ActionStruct_t ActionResult = (this->*(GetTrampoline()))(pJockey, fu);
		return ActionResult;
	}
	void SpawnITMob::OnSpawnITMob(int amount)
	{
		L4D_DEBUG_LOG("ZombieManager::SpawnITMob(%d) has been called", amount);

		cell_t result = Pl_Continue;
		if(g_pFwdOnSpawnITMob)
		{
			L4D_DEBUG_LOG("L4D_OnSpawnITMob() forward has been sent out");
			g_pFwdOnSpawnITMob->PushCellByRef(&amount);
			g_pFwdOnSpawnITMob->Execute(&result);
		}

		if(result == Pl_Handled)
		{
			L4D_DEBUG_LOG("ZombieManager::SpawnITMob will be skipped");
			return;
		}
		else
		{
			(this->*(GetTrampoline()))(amount);
			return;
		}
	}
	void RecomputeTeamScores::OnRecomputeTeamScores()
	{		
		L4D_DEBUG_LOG("CTerrorGameRules::RecomputeTeamScores has been called");
		/*
		
		//unsigned char *calloffset = *(unsigned char **)writeaddr;
		float maxflow;
		
		//-0x208694(%ebx),%ecx
		
		__asm__("mov -0xf0(%%ebx),%%eax\n\t"
				"mov (%%eax),%%eax\n\t"
				"mov 0x5a8(%%eax),%0" :"=r"(maxflow));
		//__asm__("mov -0x227040(%%ebx), %0;" :"=r"(maxflow));
		L4D_DEBUG_LOG("L4D_OnRecomputeTeamScores MaxFlow -> %.2f", maxflow);
		*/
		
		
		cell_t result = Pl_Continue;
		if(g_pFwdOnRecomputeTeamScores)
		{
			L4D_DEBUG_LOG("L4D_OnRecomputeTeamScores forward has been sent out");
			g_pFwdOnRecomputeTeamScores->Execute(&result);
		}

		if(result == Pl_Handled)
		{
			L4D_DEBUG_LOG("Director::RecomputeTeamScores will be skipped");
			return;
		}
		else
		{		
			L4D_DEBUG_LOG("CTerrorGameRules::RecomputeTeamScores will be invoked");

			return (this->*(GetTrampoline()))();
		}
	}
	void GetMissionVersusBossSpawning::OnGetMissionVersusBossSpawning(float &spawn_pos_min, float &spawn_pos_max, float &tank_chance, float &witch_chance)
	{
		L4D_DEBUG_LOG("CDirectorVersusMode::GetMissionVersusBossSpawning has been called, %f %f %f %f", spawn_pos_min, spawn_pos_max, tank_chance, witch_chance);
		
		float ov_spawn_pos_min = spawn_pos_min;
	    float ov_spawn_pos_max = spawn_pos_max;
	    float ov_tank_chance = tank_chance;
	    float ov_witch_chance = witch_chance;

		cell_t result = Pl_Continue;
		if(g_pFwdOnGetMissionVersusBossSpawning)
		{
			L4D_DEBUG_LOG("L4D_OnGetMissionVersusBossSpawning forward has been sent out");
			g_pFwdOnGetMissionVersusBossSpawning->PushFloatByRef(&ov_spawn_pos_min);
			g_pFwdOnGetMissionVersusBossSpawning->PushFloatByRef(&ov_spawn_pos_max);
			g_pFwdOnGetMissionVersusBossSpawning->PushFloatByRef(&ov_tank_chance);
			g_pFwdOnGetMissionVersusBossSpawning->PushFloatByRef(&ov_witch_chance);
			g_pFwdOnGetMissionVersusBossSpawning->Execute(&result);
		}
		switch(result)
		{
			case Pl_Changed:
				spawn_pos_min = ov_spawn_pos_min;
				spawn_pos_max = ov_spawn_pos_max;
				tank_chance = ov_tank_chance;
				witch_chance = ov_witch_chance;
			break;
			case Pl_Handled:
			break;
			case Pl_Continue:
			default:
			(this->*(GetTrampoline()))(spawn_pos_min, spawn_pos_max, tank_chance, witch_chance);
		}

	   
		return;
	}
    void *TerrorWeaponHit::OnTerrorWeaponHit(CGameTrace *trace/* a1 */, void *vector/* a2 */, bool userCall/* a3 */)
    {
        L4D_DEBUG_LOG("CTerrorWeapon::OnHit() has been called");
        cell_t result = Pl_Continue;

        int hEntity = *(int *)((unsigned char*)trace + 76);    // did the m2 trace hit anyone(i.e. an entity)
        /*  
            deadstop check: see if it's going to be versus_shove_hunter_fov_pouncing(true) or versus_shove_hunter_fov(false)
            often returns 0 when it shouldn't  - either this shit is unreliable, or the game is buggy as f**k
            probably both
        */
        int isDeadstop = *(int *)((unsigned char *)hEntity + 16024);
        int weapon = IndexOfEdict(gameents->BaseEntityToEdict(reinterpret_cast<CBaseEntity *>(this)));
        int entity = IndexOfEdict(gameents->BaseEntityToEdict(reinterpret_cast<CBaseEntity *>(hEntity)));
        CBaseHandle &weaponOwner = *(CBaseHandle *)((unsigned char *)this + 5108);  // get the weapon's owner and thus check its validity(shoves are a secondary attack of anything you're able to hold, even pills and cola)
        int client = !weaponOwner.IsValid() ? -1 : weaponOwner.GetEntryIndex();   // very simplistic and unreliable check, but meh
        /* there's another check being performed here to see if the current gamemode allows bashing... we don't need it */
        if (g_pFwdOnTerrorWeaponHit && client && entity && userCall)
        {
            g_pFwdOnTerrorWeaponHit->PushCell(client); // who shoved
            g_pFwdOnTerrorWeaponHit->PushCell(entity); // who got shoved
            g_pFwdOnTerrorWeaponHit->PushCell(weapon); // weapon that's been held while shoving
            g_pFwdOnTerrorWeaponHit->PushArray(reinterpret_cast<cell_t *>(vector), 3); // shove angles
            g_pFwdOnTerrorWeaponHit->PushCell(isDeadstop ? true : false); // reliable for high pounces only
            g_pFwdOnTerrorWeaponHit->Execute(&result);
        }

        if(result == Pl_Handled)
        {
            L4D_DEBUG_LOG("CTerrorWeapon::OnHit() will be skipped");
            return NULL;
        }
        else
        {
            return (this->*(GetTrampoline()))(trace, vector, userCall);
        }
    }