360 lines
13 KiB
Plaintext
360 lines
13 KiB
Plaintext
#include maps\mp\_utility;
|
|
#include maps\mp\gametypes\_hud_util;
|
|
#include common_scripts\utility;
|
|
|
|
init()
|
|
{
|
|
if ( !isDefined( game["gamestarted"] ) )
|
|
{
|
|
//setMatchDataDef( "mp/matchdata_" + level.gametype + ".def" );
|
|
setMatchDataDef( "mp/matchdata.def" );
|
|
setMatchData( "map", level.script );
|
|
setMatchData( "gametype", level.gametype );
|
|
setMatchData( "buildVersion", getBuildVersion() );
|
|
setMatchData( "buildNumber", getBuildNumber() );
|
|
setMatchData( "dateTime", getSystemTime() );
|
|
}
|
|
|
|
level.MaxLives = 250; // must match MaxKills in matchdata definition
|
|
level.MaxNameLength = 21; // must match Player xuid size in clientmatchdata definition
|
|
level.MaxEvents = 150;
|
|
level.MaxKillstreaks = 125;
|
|
level.MaxLogClients = 128;
|
|
|
|
level thread gameEndListener();
|
|
}
|
|
|
|
|
|
logKillstreakEvent( event, position )
|
|
{
|
|
assertEx( isPlayer( self ), "self is not a player: " + self.code_classname );
|
|
|
|
if ( !matchMakingGame() || !canLogClient( self ) || !canLogKillstreak() )
|
|
return;
|
|
|
|
eventId = getMatchData( "killstreakCount" );
|
|
setMatchData( "killstreakCount", eventId+1 );
|
|
|
|
setMatchData( "killstreaks", eventId, "eventType", event );
|
|
setMatchData( "killstreaks", eventId, "player", self.clientid );
|
|
setMatchData( "killstreaks", eventId, "eventTime", getTime() );
|
|
setMatchData( "killstreaks", eventId, "eventPos", 0, int( position[0] ) );
|
|
setMatchData( "killstreaks", eventId, "eventPos", 1, int( position[1] ) );
|
|
setMatchData( "killstreaks", eventId, "eventPos", 2, int( position[2] ) );
|
|
}
|
|
|
|
|
|
logGameEvent( event, position )
|
|
{
|
|
assertEx( isPlayer( self ), "self is not a player: " + self.code_classname );
|
|
|
|
if ( !matchMakingGame() || !canLogClient( self ) || !canLogEvent() )
|
|
return;
|
|
|
|
eventId = getMatchData( "eventCount" );
|
|
setMatchData( "eventCount", eventId+1 );
|
|
|
|
setMatchData( "events", eventId, "eventType", event );
|
|
setMatchData( "events", eventId, "player", self.clientid );
|
|
setMatchData( "events", eventId, "eventTime", getTime() );
|
|
setMatchData( "events", eventId, "eventPos", 0, int( position[0] ) );
|
|
setMatchData( "events", eventId, "eventPos", 1, int( position[1] ) );
|
|
setMatchData( "events", eventId, "eventPos", 2, int( position[2] ) );
|
|
}
|
|
|
|
|
|
logKillEvent( lifeId, eventRef )
|
|
{
|
|
if ( !matchMakingGame() || !canLogLife( lifeId ) )
|
|
return;
|
|
|
|
setMatchData( "lives", lifeId, "modifiers", eventRef, true );
|
|
}
|
|
|
|
|
|
logMultiKill( lifeId, multikillCount )
|
|
{
|
|
if ( !matchMakingGame() || !canLogLife( lifeId ) )
|
|
return;
|
|
|
|
setMatchData( "lives", lifeId, "multikill", multikillCount );
|
|
}
|
|
|
|
|
|
logPlayerLife( lifeId )
|
|
{
|
|
if ( !matchMakingGame() || !canLogClient( self ) || !canLogLife( lifeId ) )
|
|
return;
|
|
|
|
setMatchData( "lives", lifeId, "player", self.clientid );
|
|
setMatchData( "lives", lifeId, "spawnPos", 0, int( self.spawnPos[0] ) );
|
|
setMatchData( "lives", lifeId, "spawnPos", 1, int( self.spawnPos[1] ) );
|
|
setMatchData( "lives", lifeId, "spawnPos", 2, int( self.spawnPos[2] ) );
|
|
setMatchData( "lives", lifeId, "wasTacticalInsertion", self.wasTI );
|
|
setMatchData( "lives", lifeId, "team", self.team );
|
|
setMatchData( "lives", lifeId, "spawnTime", self.spawnTime );
|
|
setMatchData( "lives", lifeId, "duration", getTime() - self.spawnTime );
|
|
|
|
self logLoadout( lifeId );
|
|
}
|
|
|
|
|
|
logLoadout( lifeId )
|
|
{
|
|
if ( !matchMakingGame() || !canLogClient( self ) || !canLogLife( lifeId ) )
|
|
return;
|
|
|
|
class = self.curClass;
|
|
|
|
if ( class == "copycat" )
|
|
{
|
|
clonedLoadout = self.pers["copyCatLoadout"];
|
|
|
|
loadoutPrimary = clonedLoadout["loadoutPrimary"];
|
|
loadoutPrimaryAttachment = clonedLoadout["loadoutPrimaryAttachment"];
|
|
loadoutPrimaryAttachment2 = clonedLoadout["loadoutPrimaryAttachment2"] ;
|
|
loadoutPrimaryCamo = clonedLoadout["loadoutPrimaryCamo"];
|
|
loadoutSecondary = clonedLoadout["loadoutSecondary"];
|
|
loadoutSecondaryAttachment = clonedLoadout["loadoutSecondaryAttachment"];
|
|
loadoutSecondaryAttachment2 = clonedLoadout["loadoutSecondaryAttachment2"];
|
|
loadoutSecondaryCamo = clonedLoadout["loadoutSecondaryCamo"];
|
|
loadoutEquipment = clonedLoadout["loadoutEquipment"];
|
|
loadoutPerk1 = clonedLoadout["loadoutPerk1"];
|
|
loadoutPerk2 = clonedLoadout["loadoutPerk2"];
|
|
loadoutPerk3 = clonedLoadout["loadoutPerk3"];
|
|
loadoutOffhand = clonedLoadout["loadoutOffhand"];
|
|
loadoutDeathStreak = "specialty_copycat";
|
|
}
|
|
else if( isSubstr( class, "custom" ) )
|
|
{
|
|
class_num = maps\mp\gametypes\_class::getClassIndex( class );
|
|
|
|
loadoutPrimary = maps\mp\gametypes\_class::cac_getWeapon( class_num, 0 );
|
|
loadoutPrimaryAttachment = maps\mp\gametypes\_class::cac_getWeaponAttachment( class_num, 0 );
|
|
loadoutPrimaryAttachment2 = maps\mp\gametypes\_class::cac_getWeaponAttachmentTwo( class_num, 0 );
|
|
|
|
loadoutSecondary = maps\mp\gametypes\_class::cac_getWeapon( class_num, 1 );
|
|
loadoutSecondaryAttachment = maps\mp\gametypes\_class::cac_getWeaponAttachment( class_num, 1 );
|
|
loadoutSecondaryAttachment2 = maps\mp\gametypes\_class::cac_getWeaponAttachmentTwo( class_num, 1 );
|
|
|
|
loadoutOffhand = maps\mp\gametypes\_class::cac_getOffhand( class_num );
|
|
|
|
loadoutEquipment = maps\mp\gametypes\_class::cac_getPerk( class_num, 0 );
|
|
loadoutPerk1 = maps\mp\gametypes\_class::cac_getPerk( class_num, 1 );
|
|
loadoutPerk2 = maps\mp\gametypes\_class::cac_getPerk( class_num, 2 );
|
|
loadoutPerk3 = maps\mp\gametypes\_class::cac_getPerk( class_num, 3 );
|
|
}
|
|
else
|
|
{
|
|
class_num = maps\mp\gametypes\_class::getClassIndex( class );
|
|
|
|
loadoutPrimary = maps\mp\gametypes\_class::table_getWeapon( level.classTableName, class_num, 0 );
|
|
loadoutPrimaryAttachment = maps\mp\gametypes\_class::table_getWeaponAttachment( level.classTableName, class_num, 0 , 0);
|
|
loadoutPrimaryAttachment2 = maps\mp\gametypes\_class::table_getWeaponAttachment( level.classTableName, class_num, 0, 1 );
|
|
|
|
loadoutSecondary = maps\mp\gametypes\_class::table_getWeapon( level.classTableName, class_num, 1 );
|
|
loadoutSecondaryAttachment = maps\mp\gametypes\_class::table_getWeaponAttachment( level.classTableName, class_num, 1 , 0);
|
|
loadoutSecondaryAttachment2 = maps\mp\gametypes\_class::table_getWeaponAttachment( level.classTableName, class_num, 1, 1 );;
|
|
|
|
loadoutOffhand = maps\mp\gametypes\_class::table_getOffhand( level.classTableName, class_num );
|
|
|
|
loadoutEquipment = maps\mp\gametypes\_class::table_getEquipment( level.classTableName, class_num, 0 );
|
|
loadoutPerk1 = maps\mp\gametypes\_class::table_getPerk( level.classTableName, class_num, 1 );
|
|
loadoutPerk2 = maps\mp\gametypes\_class::table_getPerk( level.classTableName, class_num, 2 );
|
|
loadoutPerk3 = maps\mp\gametypes\_class::table_getPerk( level.classTableName, class_num, 3 );
|
|
}
|
|
|
|
setMatchData( "lives", lifeId, "primaryWeapon", loadoutPrimary );
|
|
setMatchData( "lives", lifeId, "primaryAttachments", 0, loadoutPrimaryAttachment );
|
|
setMatchData( "lives", lifeId, "primaryAttachments", 1, loadoutPrimaryAttachment2 );
|
|
|
|
setMatchData( "lives", lifeId, "secondaryWeapon", loadoutSecondary );
|
|
setMatchData( "lives", lifeId, "secondaryAttachments", 0, loadoutSecondaryAttachment );
|
|
setMatchData( "lives", lifeId, "secondaryAttachments", 1, loadoutSecondaryAttachment );
|
|
|
|
setMatchData( "lives", lifeId, "offhandWeapon", loadoutOffhand );
|
|
|
|
setMatchData( "lives", lifeId, "equipment", loadoutEquipment );
|
|
setMatchData( "lives", lifeId, "perks", 0, loadoutPerk1 );
|
|
setMatchData( "lives", lifeId, "perks", 1, loadoutPerk2 );
|
|
setMatchData( "lives", lifeId, "perks", 2, loadoutPerk3 );
|
|
}
|
|
|
|
|
|
logPlayerDeath( lifeId, attacker, iDamage, sMeansOfDeath, sWeapon, sPrimaryWeapon, sHitLoc )
|
|
{
|
|
if ( !matchMakingGame() || !canLogClient( self ) || ( isPlayer( attacker ) && !canLogClient( attacker ) ) || !canLogLife( lifeId ) )
|
|
return;
|
|
|
|
if ( lifeId >= level.MaxLives )
|
|
return;
|
|
|
|
if ( sWeapon == "none" )
|
|
{
|
|
sWeaponType = "none";
|
|
sWeaponClass = "none";
|
|
}
|
|
else
|
|
{
|
|
sWeaponType = weaponInventoryType( sWeapon );
|
|
sWeaponClass = weaponClass( sWeapon );
|
|
}
|
|
|
|
if ( isDefined( sWeaponType ) && (sWeaponType == "primary" || sWeaponType == "altmode") && (sWeaponClass == "pistol" || sWeaponClass == "smg" || sWeaponClass == "rifle" || sWeaponClass == "spread" || sWeaponClass == "mg" || sWeaponClass == "grenade" || sWeaponClass == "rocketlauncher" || sWeaponClass == "sniper") )
|
|
{
|
|
sWeaponOriginal = undefined;
|
|
|
|
if ( sWeaponType == "altmode" )
|
|
{
|
|
sWeaponOriginal = sWeapon;
|
|
sWeapon = sPrimaryWeapon;
|
|
|
|
setMatchData( "lives", lifeId, "altMode", true );
|
|
}
|
|
|
|
weaponTokens = strTok( sWeapon, "_" );
|
|
|
|
/#
|
|
if ( !(weaponTokens.size > 1 && weaponTokens.size <= 4) )
|
|
{
|
|
PrintLn( "attacker: ", attacker );
|
|
PrintLn( "iDamage: ", iDamage );
|
|
PrintLn( "sMeansOfDeath: ", sMeansOfDeath );
|
|
|
|
if ( isDefined( sWeaponOriginal ) )
|
|
PrintLn( "sWeaponOriginal: ", sWeaponOriginal );
|
|
|
|
PrintLn( "sWeapon: ", sWeapon );
|
|
PrintLn( "sPrimaryWeapon: ", sPrimaryWeapon );
|
|
PrintLn( "--------------------------------" );
|
|
PrintLn( "sWeaponType: ", sWeaponType );
|
|
PrintLn( "sWeaponClass: ", sWeaponClass );
|
|
PrintLn( "--------------------------------" );
|
|
PrintLn( "weaponTokens.size: ", weaponTokens.size );
|
|
|
|
tokenCount = 0;
|
|
foreach ( token in weaponTokens )
|
|
{
|
|
PrintLn( "weaponTokens[", tokenCount, "]: ", weaponTokens[tokenCount] );
|
|
tokenCount++;
|
|
}
|
|
}
|
|
#/
|
|
assert( weaponTokens.size > 1 && weaponTokens.size <= 4 );
|
|
|
|
assertEx( weaponTokens[weaponTokens.size - 1] == "mp", "weaponTokens[weaponTokens.size - 1]: " + weaponTokens[weaponTokens.size - 1] );
|
|
weaponTokens[weaponTokens.size - 1] = undefined; // remove the trailing "mp"
|
|
|
|
setMatchData( "lives", lifeId, "weapon", weaponTokens[0] );
|
|
|
|
if ( isDefined( weaponTokens[1] ) )
|
|
setMatchData( "lives", lifeId, "attachments", 0, weaponTokens[1] );
|
|
|
|
if ( isDefined( weaponTokens[2] ) )
|
|
setMatchData( "lives", lifeId, "attachments", 1, weaponTokens[2] );
|
|
}
|
|
else if ( sWeaponType == "item" || sWeaponType == "offhand" )
|
|
{
|
|
weaponName = strip_suffix( sWeapon, "_mp" );
|
|
setMatchData( "lives", lifeId, "weapon", weaponName );
|
|
}
|
|
else
|
|
{
|
|
setMatchData( "lives", lifeId, "weapon", sWeapon );
|
|
}
|
|
|
|
if ( isKillstreakWeapon( sWeapon ) )
|
|
setMatchData( "lives", lifeId, "modifiers", "killstreak", true );
|
|
|
|
setMatchData( "lives", lifeId, "mod", sMeansOfDeath );
|
|
if ( isPlayer( attacker ) )
|
|
{
|
|
setMatchData( "lives", lifeId, "attacker", attacker.clientid );
|
|
setMatchData( "lives", lifeId, "attackerPos", 0, int( attacker.origin[0] ) );
|
|
setMatchData( "lives", lifeId, "attackerPos", 1, int( attacker.origin[1] ) );
|
|
setMatchData( "lives", lifeId, "attackerPos", 2, int( attacker.origin[2] ) );
|
|
|
|
victimForward = anglesToForward( (0,self.angles[1],0) );
|
|
attackDirection = (self.origin - attacker.origin);
|
|
attackDirection = VectorNormalize( (attackDirection[0], attackDirection[1], 0) );
|
|
setMatchData( "lives", lifeId, "dotOfDeath", VectorDot( victimForward, attackDirection ) );
|
|
}
|
|
else
|
|
{
|
|
// 255 is world
|
|
setMatchData( "lives", lifeId, "attacker", 255 );
|
|
setMatchData( "lives", lifeId, "attackerPos", 0, int( self.origin[0] ) );
|
|
setMatchData( "lives", lifeId, "attackerPos", 1, int( self.origin[1] ) );
|
|
setMatchData( "lives", lifeId, "attackerPos", 2, int( self.origin[2] ) );
|
|
}
|
|
|
|
setMatchData( "lives", lifeId, "player", self.clientid );
|
|
setMatchData( "lives", lifeId, "deathPos", 0, int( self.origin[0] ) );
|
|
setMatchData( "lives", lifeId, "deathPos", 1, int( self.origin[1] ) );
|
|
setMatchData( "lives", lifeId, "deathPos", 2, int( self.origin[2] ) );
|
|
|
|
setMatchData( "lives", lifeId, "deathAngles", 0, int( self.angles[0] ) );
|
|
setMatchData( "lives", lifeId, "deathAngles", 1, int( self.angles[1] ) );
|
|
setMatchData( "lives", lifeId, "deathAngles", 2, int( self.angles[2] ) );
|
|
}
|
|
|
|
|
|
logPlayerData()
|
|
{
|
|
if ( !matchMakingGame() || !canLogClient( self ) )
|
|
return;
|
|
|
|
setMatchData( "players", self.clientid, "score", self getPersStat( "score" ) );
|
|
setMatchData( "players", self.clientid, "assists", self getPersStat( "assists" ) );
|
|
setMatchData( "players", self.clientid, "longestStreak", self getPersStat( "longestStreak" ) );
|
|
}
|
|
|
|
|
|
// log the lives of players who are still alive at match end.
|
|
gameEndListener()
|
|
{
|
|
if ( !matchMakingGame() )
|
|
return;
|
|
|
|
level waittill ( "game_ended" );
|
|
|
|
setMatchData( "gameLength", int( getTimePassed() ) );
|
|
|
|
foreach ( player in level.players )
|
|
{
|
|
if ( player.team != "allies" && player.team != "axis" )
|
|
continue;
|
|
|
|
player logPlayerData();
|
|
|
|
if ( !isAlive( player ) )
|
|
continue;
|
|
|
|
lifeId = getNextLifeId();
|
|
player logPlayerLife( lifeId );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
canLogClient( client )
|
|
{
|
|
assertEx( isPlayer( client ) , "Client is not a player: " + client.code_classname );
|
|
return ( client.clientid < level.MaxLogClients );
|
|
}
|
|
|
|
canLogEvent()
|
|
{
|
|
return ( getMatchData( "eventCount" ) < level.MaxEvents );
|
|
}
|
|
|
|
canLogKillstreak()
|
|
{
|
|
return ( getMatchData( "killstreakCount" ) < level.MaxKillstreaks );
|
|
}
|
|
|
|
canLogLife( lifeId )
|
|
{
|
|
return ( getMatchData( "lifeCount" ) < level.MaxLives );
|
|
}
|