After years of doing this stuff is, all I can recommend, don't thread to your custom callbacks from within the stock callbacks GSC file. I wont go into it in detail, but the reason to follow this advice is all about the way the engine works and timing. Even Infinity Ward did not do fiddle with the stock callbacks when building global game files like _globallogic.gsc in COD4 and onwards. Always intercept player damage, or player killed from within the gametype GSC main() method.
This is how I built my custom callbacks:
1. _callbacksetup.gsc:
Code:
/*================
Called from the gametype script to store off the default callback functions.
This allows the callbacks to be overridden by level script, but not lost.
================*/
SetDefaultCallbacks()
{
level.callbackStartGameType = maps\mp\gametypes\_globalgametypes::Callback_StartGameType;
level.callbackPlayerConnect = maps\mp\gametypes\_globalgametypes::Callback_PlayerConnect;
level.callbackPlayerDisconnect = maps\mp\gametypes\_globalgametypes::Callback_PlayerDisconnect;
level.callbackPlayerDamage = maps\mp\gametypes\_globalgametypes::Callback_PlayerDamage;
level.callbackPlayerKilled = maps\mp\gametypes\_globalgametypes::Callback_PlayerKilled;
maps\mp\gametypes\_globalgametypes::SetUpCallBacks();
demon\_globallogic::setupCallbacks();
}
2. demon\_globallogic::setupCallbacks();
Code:
setupCallbacks()
{
level.demon_onGametypeStarted = ::onGametypeStarted;
level.demon_onPlayerConnect = ::onPlayerConnect;
level.demon_onPlayerDisconnect = ::onPlayerDisconnect;
level.demon_onPlayerPreSpawned = ::onPlayerPreSpawned;
level.demon_onPlayerSpawned = ::onPlayerSpawned;
level.demon_onPlayerDamage = ::onPlayerDamage;
level.demon_onPlayerKilled = ::onPlayerKilled;
level.demon_onSpawnSpectator = ::onSpawnSpectator;
level.demon_onSwitchingTeams = ::demon_onSwitchingTeams;
level.onPlayerJoinedTeam = ::onPlayerJoinedTeam;
}
3. _globalgametypes::Callback_PlayerDamage():
Code:
Callback_PlayerDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime )
{
if( self.sessionteam == "spectator" )
return;
//--- Spawn Protection ---
if( self.spawnprotected )
return;
// specialty checks - bulletdamage and armorvest
iDamage = maps\mp\gametypes\_class::modified_damage( self, eAttacker, iDamage, sMeansOfDeath );
// Don't do knockback if the damage direction was not specified
if(!isDefined(vDir))
iDFlags |= level.iDFLAGS_NO_KNOCKBACK;
friendly = undefined;
self thread [[level.onPlayerDamage]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime );
self thread [[level.demon_onPlayerDamage]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime );
---- snip ---
You will see that I have 2 sets of callbacks - those used by the stock gametype files, and those for my mod. You don't have to do it like this - you could just have 1 set of callbacks, but the main point is that you thread to a callback from the gametype file, not the stock callbacks file.
EDIT -
I was half asleep when I wrote this. After reading through the thread again, I can see I didn't understand the issue properly. Feel free to ignore what I've said.