Fix Game Interface / AC Callbacks + support for T5ZM, T6MP and T6ZM for the Game Interface. (#288)

* Fix trying to write to a struct before its initialized.

Same issue on IW4, IW5 and T5 game modules.

* Fix path issues in the scripts + add support for t5zm.

* Fix deploy.bat
* Change paths inside the gsc scripts used to call functions in other scripts
* Remove mp includes from base gsc file.
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
* Define GetXuid as overrideMethod as t5zm doesn't have it.
* Define GetPlayerFromClientNum as getting all players is slightly different on t5zm.

* Remove the precompiled gsc file for T6 as PlutoT6 can load uncompiled GSC now.

* Fix _customcallbacks.gsc for T6

* Add T6 support to the game interface.

* Update _integration_base.gsc

use camelCase for functionName

* Make sure the Setup functions are always called in the right order.

Base -> shared -> game
Otherwise we might write to structs before they are created.

* Move functions interacting with the game from _base to _shared

GetPlayerFromClientNum
OnPlayerJoinedTeam
OnPlayerJoinedSpectators
GenerateJoinTeamString
PlayerTrackingOnInterval
SaveTrackingMetrics

* Block execution until game specific setup is done

Block _shared execution until the game specific file finished.
This allows the game specific file to override the events in _shared.

* Fix setup event flow

Move check of sv_iw4madmin_integration_enabled dvar after waittill in _shared so _base has a chance to set it to 1.
Move check of sv_iw4madmin_autobalance dvar to OnPlayerConnect in _shared so the game specific script has a chance to set the dvar.

* ignore bots

* add more spaces
This commit is contained in:
xerxes-at 2023-05-29 03:15:52 +02:00 committed by GitHub
parent c26489d71f
commit 7d436ac0c5
12 changed files with 1446 additions and 458 deletions

View File

@ -1,263 +0,0 @@
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
#include common_scripts\utility;
init()
{
SetDvarIfUninitialized( "sv_customcallbacks", true );
SetDvarIfUninitialized( "sv_framewaittime", 0.05 );
SetDvarIfUninitialized( "sv_additionalwaittime", 0.1 );
SetDvarIfUninitialized( "sv_maxstoredframes", 12 );
SetDvarIfUninitialized( "sv_printradarupdates", 0 );
SetDvarIfUninitialized( "sv_printradar_updateinterval", 500 );
SetDvarIfUninitialized( "sv_iw4madmin_url", "http://127.0.0.1:1624" );
level thread onPlayerConnect();
if (getDvarInt("sv_printradarupdates") == 1)
{
level thread runRadarUpdates();
}
level waittill( "prematch_over" );
level.callbackPlayerKilled = ::Callback_PlayerKilled;
level.callbackPlayerDamage = ::Callback_PlayerDamage;
level.callbackPlayerDisconnect = ::Callback_PlayerDisconnect;
}
//It's called slightly different in T6
//set_dvar_if_unset(dvar, val, reset)
SetDvarIfUninitialized(dvar, val)
{
set_dvar_if_unset(dvar,val);
}
onPlayerConnect( player )
{
for( ;; )
{
level waittill( "connected", player );
player thread waitForFrameThread();
player thread waitForAttack();
}
}
//Got added to T6 on April 2020
waitForAttack()
{
self endon( "disconnect" );
self notifyOnPlayerCommand( "player_shot", "+attack" );
self.lastAttackTime = 0;
for( ;; )
{
self waittill( "player_shot" );
self.lastAttackTime = getTime();
}
}
runRadarUpdates()
{
interval = getDvarInt( "sv_printradar_updateinterval" );
for ( ;; )
{
for ( i = 0; i <= 17; i++ )
{
player = level.players[i];
if ( isDefined( player ) )
{
payload = player.guid + ";" + player.origin + ";" + player getPlayerAngles() + ";" + player.team + ";" + player.kills + ";" + player.deaths + ";" + player.score + ";" + player GetCurrentWeapon() + ";" + player.health + ";" + isAlive(player) + ";" + player.timePlayed["total"];
logPrint( "LiveRadar;" + payload + "\n" );
}
}
wait( interval / 1000 );
}
}
hitLocationToBone( hitloc )
{
switch( hitloc )
{
case "helmet":
return "j_helmet";
case "head":
return "j_head";
case "neck":
return "j_neck";
case "torso_upper":
return "j_spineupper";
case "torso_lower":
return "j_spinelower";
case "right_arm_upper":
return "j_shoulder_ri";
case "left_arm_upper":
return "j_shoulder_le";
case "right_arm_lower":
return "j_elbow_ri";
case "left_arm_lower":
return "j_elbow_le";
case "right_hand":
return "j_wrist_ri";
case "left_hand":
return "j_wrist_le";
case "right_leg_upper":
return "j_hip_ri";
case "left_leg_upper":
return "j_hip_le";
case "right_leg_lower":
return "j_knee_ri";
case "left_leg_lower":
return "j_knee_le";
case "right_foot":
return "j_ankle_ri";
case "left_foot":
return "j_ankle_le";
default:
return "tag_origin";
}
}
waitForFrameThread()
{
self endon( "disconnect" );
self.currentAnglePosition = 0;
self.anglePositions = [];
for (i = 0; i < getDvarInt( "sv_maxstoredframes" ); i++)
{
self.anglePositions[i] = self getPlayerAngles();
}
for( ;; )
{
self.anglePositions[self.currentAnglePosition] = self getPlayerAngles();
wait( getDvarFloat( "sv_framewaittime" ) );
self.currentAnglePosition = (self.currentAnglePosition + 1) % getDvarInt( "sv_maxstoredframes" );
}
}
waitForAdditionalAngles( logString, beforeFrameCount, afterFrameCount )
{
currentIndex = self.currentAnglePosition;
wait( 0.05 * afterFrameCount );
self.angleSnapshot = [];
for( j = 0; j < self.anglePositions.size; j++ )
{
self.angleSnapshot[j] = self.anglePositions[j];
}
anglesStr = "";
collectedFrames = 0;
i = currentIndex - beforeFrameCount;
while (collectedFrames < beforeFrameCount)
{
fixedIndex = i;
if (i < 0)
{
fixedIndex = self.angleSnapshot.size - abs(i);
}
anglesStr += self.angleSnapshot[int(fixedIndex)] + ":";
collectedFrames++;
i++;
}
if (i == currentIndex)
{
anglesStr += self.angleSnapshot[i] + ":";
i++;
}
collectedFrames = 0;
while (collectedFrames < afterFrameCount)
{
fixedIndex = i;
if (i > self.angleSnapshot.size - 1)
{
fixedIndex = i % self.angleSnapshot.size;
}
anglesStr += self.angleSnapshot[int(fixedIndex)] + ":";
collectedFrames++;
i++;
}
lastAttack = getTime() - self.lastAttackTime;
isAlive = isAlive(self);
logPrint(logString + ";" + anglesStr + ";" + isAlive + ";" + lastAttack + "\n" );
}
vectorScale( vector, scale )
{
return ( vector[0] * scale, vector[1] * scale, vector[2] * scale );
}
Process_Hit( type, attacker, sHitLoc, sMeansOfDeath, iDamage, sWeapon )
{
if (sMeansOfDeath == "MOD_FALLING" || !isPlayer(attacker))
{
return;
}
victim = self;
_attacker = attacker;
if ( !isPlayer( attacker ) && isDefined( attacker.owner ) )
{
_attacker = attacker.owner;
}
else if( !isPlayer( attacker ) && sMeansOfDeath == "MOD_FALLING" )
{
_attacker = victim;
}
location = victim GetTagOrigin( hitLocationToBone( sHitLoc ) );
isKillstreakKill = false;
if(!isPlayer(attacker))
{
isKillstreakKill = true;
}
if(maps/mp/killstreaks/_killstreaks::iskillstreakweapon(sWeapon))
{
isKillstreakKill = true;
}
logLine = "Script" + type + ";" + _attacker.guid + ";" + victim.guid + ";" + _attacker GetTagOrigin("tag_eye") + ";" + location + ";" + iDamage + ";" + sWeapon + ";" + sHitLoc + ";" + sMeansOfDeath + ";" + _attacker getPlayerAngles() + ";" + int(gettime()) + ";" + isKillstreakKill + ";" + _attacker playerADS() + ";0;0";
attacker thread waitForAdditionalAngles( logLine, 2, 2 );
}
Callback_PlayerDamage( eInflictor, attacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, boneIndex )
{
if ( level.teamBased && isDefined( attacker ) && ( self != attacker ) && isDefined( attacker.team ) && ( self.pers[ "team" ] == attacker.team ) )
{
return;
}
if ( self.health - iDamage > 0 )
{
self Process_Hit( "Damage", attacker, sHitLoc, sMeansOfDeath, iDamage, sWeapon );
}
self [[maps/mp/gametypes/_globallogic_player::callback_playerdamage]]( eInflictor, attacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, boneIndex );
}
Callback_PlayerKilled(eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration)
{
Process_Hit( "Kill", attacker, sHitLoc, sMeansOfDeath, iDamage, sWeapon );
self [[maps/mp/gametypes/_globallogic_player::callback_playerkilled]]( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration );
}
Callback_PlayerDisconnect()
{
level notify( "disconnected", self );
self [[maps/mp/gametypes/_globallogic_player::callback_playerdisconnect]]();
}

View File

@ -1,6 +1,4 @@
#include common_scripts\utility; #include common_scripts\utility;
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
Init() Init()
{ {
@ -19,14 +17,17 @@ Setup()
level.eventBus.timeoutKey = "timeout"; level.eventBus.timeoutKey = "timeout";
level.eventBus.timeout = 30; level.eventBus.timeout = 30;
level.commonFunctions = spawnstruct(); level.commonFunctions = spawnstruct();
level.commonFunctions.setDvar = "SetDvarIfUninitialized"; level.commonFunctions.setDvar = "SetDvarIfUninitialized";
level.commonFunctions.isBot = "IsBot"; level.commonFunctions.isBot = "IsBot";
level.commonFunctions.getXuid = "GetXuid";
level.commonFunctions.getPlayerFromClientNum = "GetPlayerFromClientNum";
level.commonKeys = spawnstruct(); level.commonKeys = spawnstruct();
level.notifyTypes = spawnstruct(); level.notifyTypes = spawnstruct();
level.notifyTypes.gameFunctionsInitialized = "GameFunctionsInitialized"; level.notifyTypes.gameFunctionsInitialized = "GameFunctionsInitialized";
level.notifyTypes.sharedFunctionsInitialized = "SharedFunctionsInitialized";
level.notifyTypes.integrationBootstrapInitialized = "IntegrationBootstrapInitialized"; level.notifyTypes.integrationBootstrapInitialized = "IntegrationBootstrapInitialized";
level.clientDataKey = "clientData"; level.clientDataKey = "clientData";
@ -102,9 +103,6 @@ OnPlayerConnect()
} }
player thread OnPlayerSpawned(); player thread OnPlayerSpawned();
player thread OnPlayerJoinedTeam();
player thread OnPlayerJoinedSpectators();
player thread PlayerTrackingOnInterval();
} }
} }
@ -119,30 +117,6 @@ OnPlayerSpawned()
} }
} }
OnPlayerJoinedTeam()
{
self endon( "disconnect" );
for( ;; )
{
self waittill( "joined_team" );
// join spec and join team occur at the same moment - out of order logging would be problematic
wait( 0.25 );
LogPrint( GenerateJoinTeamString( false ) );
}
}
OnPlayerJoinedSpectators()
{
self endon( "disconnect" );
for( ;; )
{
self waittill( "joined_spectators" );
LogPrint( GenerateJoinTeamString( true ) );
}
}
OnGameEnded() OnGameEnded()
{ {
for ( ;; ) for ( ;; )
@ -187,20 +161,6 @@ PlayerSpawnEvents()
self RequestClientBasicData(); self RequestClientBasicData();
} }
PlayerTrackingOnInterval()
{
self endon( "disconnect" );
for ( ;; )
{
wait ( 120 );
if ( IsAlive( self ) )
{
self SaveTrackingMetrics();
}
}
}
MonitorClientEvents() MonitorClientEvents()
{ {
level endon( "game_ended" ); level endon( "game_ended" );
@ -344,37 +304,6 @@ DecrementClientMeta( metaKey, decrementValue, clientId )
SetClientMeta( metaKey, decrementValue, clientId, "decrement" ); SetClientMeta( metaKey, decrementValue, clientId, "decrement" );
} }
GenerateJoinTeamString( isSpectator )
{
team = self.team;
if ( IsDefined( self.joining_team ) )
{
team = self.joining_team;
}
else
{
if ( isSpectator || !IsDefined( team ) )
{
team = "spectator";
}
}
guid = self GetXuid();
if ( guid == "0" )
{
guid = self.guid;
}
if ( !IsDefined( guid ) || guid == "0" )
{
guid = "undefined";
}
return "JT;" + guid + ";" + self getEntityNumber() + ";" + team + ";" + self.name + "\n";
}
SetClientMeta( metaKey, metaValue, clientId, direction ) SetClientMeta( metaKey, metaValue, clientId, direction )
{ {
data = "key=" + metaKey + "|value=" + metaValue; data = "key=" + metaKey + "|value=" + metaValue;
@ -400,39 +329,6 @@ SetClientMeta( metaKey, metaValue, clientId, direction )
level thread QueueEvent( setClientMetaEvent, level.eventTypes.setClientDataRequested, self ); level thread QueueEvent( setClientMetaEvent, level.eventTypes.setClientDataRequested, self );
} }
SaveTrackingMetrics()
{
if ( !IsDefined( self.persistentClientId ) )
{
return;
}
LogDebug( "Saving tracking metrics for " + self.persistentClientId );
if ( !IsDefined( self.lastShotCount ) )
{
self.lastShotCount = 0;
}
currentShotCount = self [[level.overrideMethods["GetTotalShotsFired"]]]();
change = currentShotCount - self.lastShotCount;
self.lastShotCount = currentShotCount;
LogDebug( "Total Shots Fired increased by " + change );
if ( !IsDefined( change ) )
{
change = 0;
}
if ( change == 0 )
{
return;
}
IncrementClientMeta( "TotalShotsFired", change, self.persistentClientId );
}
BuildEventRequest( responseExpected, eventType, eventSubtype, entOrId, data ) BuildEventRequest( responseExpected, eventType, eventSubtype, entOrId, data )
{ {
if ( !IsDefined( data ) ) if ( !IsDefined( data ) )
@ -565,8 +461,8 @@ NotifyClientEventTimeout( eventType )
NotifyClientEvent( eventInfo ) NotifyClientEvent( eventInfo )
{ {
origin = getPlayerFromClientNum( int( eventInfo[3] ) ); origin = [[level.overrideMethods[level.commonFunctions.getPlayerFromClientNum]]]( int( eventInfo[3] ) );
target = getPlayerFromClientNum( int( eventInfo[4] ) ); target = [[level.overrideMethods[level.commonFunctions.getPlayerFromClientNum]]]( int( eventInfo[4] ) );
event = spawnstruct(); event = spawnstruct();
event.type = eventInfo[1]; event.type = eventInfo[1];
@ -608,24 +504,6 @@ NotifyClientEvent( eventInfo )
level notify( level.eventTypes.localClientEvent, client ); level notify( level.eventTypes.localClientEvent, client );
} }
GetPlayerFromClientNum( clientNum )
{
if ( clientNum < 0 )
{
return undefined;
}
for ( i = 0; i < level.players.size; i++ )
{
if ( level.players[i] getEntityNumber() == clientNum )
{
return level.players[i];
}
}
return undefined;
}
AddClientCommand( commandName, shouldRunAsTarget, callback, shouldOverwrite ) AddClientCommand( commandName, shouldRunAsTarget, callback, shouldOverwrite )
{ {
if ( IsDefined( level.clientCommandCallbacks[commandName] ) && IsDefined( shouldOverwrite ) && !shouldOverwrite ) if ( IsDefined( level.clientCommandCallbacks[commandName] ) && IsDefined( shouldOverwrite ) && !shouldOverwrite )

View File

@ -2,8 +2,6 @@
Init() Init()
{ {
level.eventBus.gamename = "IW4";
thread Setup(); thread Setup();
} }
@ -12,13 +10,15 @@ Setup()
level endon( "game_ended" ); level endon( "game_ended" );
// it's possible that the notify type has not been defined yet so we have to hard code it // it's possible that the notify type has not been defined yet so we have to hard code it
level waittill( "IntegrationBootstrapInitialized" ); level waittill( "SharedFunctionsInitialized" );
level.eventBus.gamename = "IW4";
scripts\_integration_base::RegisterLogger( ::Log2Console ); scripts\_integration_base::RegisterLogger( ::Log2Console );
level.overrideMethods["GetTotalShotsFired"] = ::GetTotalShotsFired; level.overrideMethods["GetTotalShotsFired"] = ::GetTotalShotsFired;
level.overrideMethods[level.commonFunctions.setDvar] = ::_SetDvarIfUninitialized; level.overrideMethods[level.commonFunctions.setDvar] = ::_SetDvarIfUninitialized;
level.overrideMethods[level.commonFunctions.isBot] = ::IsTestClient; level.overrideMethods[level.commonFunctions.isBot] = ::IsTestClient;
level.overrideMethods[level.commonFunctions.getXuid] = ::_GetXUID;
level.overrideMethods["waittill_notify_or_timeout"] = ::_waittill_notify_or_timeout; level.overrideMethods["waittill_notify_or_timeout"] = ::_waittill_notify_or_timeout;
level.overrideMethods[level.commonFunctions.changeTeam] = ::ChangeTeam; level.overrideMethods[level.commonFunctions.changeTeam] = ::ChangeTeam;
level.overrideMethods[level.commonFunctions.getTeamCounts] = ::CountPlayers; level.overrideMethods[level.commonFunctions.getTeamCounts] = ::CountPlayers;
@ -31,6 +31,8 @@ Setup()
RegisterClientCommands(); RegisterClientCommands();
_SetDvarIfUninitialized( "sv_iw4madmin_autobalance", 0 );
level notify( level.notifyTypes.gameFunctionsInitialized ); level notify( level.notifyTypes.gameFunctionsInitialized );
if ( GetDvarInt( "sv_iw4madmin_integration_enabled" ) != 1 ) if ( GetDvarInt( "sv_iw4madmin_integration_enabled" ) != 1 )
@ -199,6 +201,11 @@ Log2Console( logLevel, message )
PrintConsole( "[" + logLevel + "] " + message + "\n" ); PrintConsole( "[" + logLevel + "] " + message + "\n" );
} }
_GetXUID()
{
return self GetXUID();
}
////////////////////////////////// //////////////////////////////////
// GUID helpers // GUID helpers
///////////////////////////////// /////////////////////////////////

View File

@ -2,8 +2,6 @@
Init() Init()
{ {
level.eventBus.gamename = "IW5";
thread Setup(); thread Setup();
} }
@ -12,17 +10,21 @@ Setup()
level endon( "game_ended" ); level endon( "game_ended" );
// it's possible that the notify type has not been defined yet so we have to hard code it // it's possible that the notify type has not been defined yet so we have to hard code it
level waittill( "IntegrationBootstrapInitialized" ); level waittill( "SharedFunctionsInitialized" );
level.eventBus.gamename = "IW5";
scripts\mp\_integration_base::RegisterLogger( ::Log2Console ); scripts\_integration_base::RegisterLogger( ::Log2Console );
level.overrideMethods["GetTotalShotsFired"] = ::GetTotalShotsFired; level.overrideMethods["GetTotalShotsFired"] = ::GetTotalShotsFired;
level.overrideMethods["SetDvarIfUninitialized"] = ::_SetDvarIfUninitialized; level.overrideMethods["SetDvarIfUninitialized"] = ::_SetDvarIfUninitialized;
level.overrideMethods["waittill_notify_or_timeout"] = ::_waittill_notify_or_timeout; level.overrideMethods["waittill_notify_or_timeout"] = ::_waittill_notify_or_timeout;
level.overrideMethods[level.commonFunctions.isBot] = ::IsTestClient; level.overrideMethods[level.commonFunctions.isBot] = ::IsTestClient;
level.overrideMethods[level.commonFunctions.getXuid] = ::_GetXUID;
RegisterClientCommands(); RegisterClientCommands();
_SetDvarIfUninitialized( "sv_iw4madmin_autobalance", 0 );
level notify( level.notifyTypes.gameFunctionsInitialized ); level notify( level.notifyTypes.gameFunctionsInitialized );
if ( GetDvarInt( "sv_iw4madmin_integration_enabled" ) != 1 ) if ( GetDvarInt( "sv_iw4madmin_integration_enabled" ) != 1 )
@ -54,17 +56,17 @@ OnPlayerConnect()
RegisterClientCommands() RegisterClientCommands()
{ {
scripts\mp\_integration_base::AddClientCommand( "GiveWeapon", true, ::GiveWeaponImpl ); scripts\_integration_base::AddClientCommand( "GiveWeapon", true, ::GiveWeaponImpl );
scripts\mp\_integration_base::AddClientCommand( "TakeWeapons", true, ::TakeWeaponsImpl ); scripts\_integration_base::AddClientCommand( "TakeWeapons", true, ::TakeWeaponsImpl );
scripts\mp\_integration_base::AddClientCommand( "SwitchTeams", true, ::TeamSwitchImpl ); scripts\_integration_base::AddClientCommand( "SwitchTeams", true, ::TeamSwitchImpl );
scripts\mp\_integration_base::AddClientCommand( "Hide", false, ::HideImpl ); scripts\_integration_base::AddClientCommand( "Hide", false, ::HideImpl );
scripts\mp\_integration_base::AddClientCommand( "Alert", true, ::AlertImpl ); scripts\_integration_base::AddClientCommand( "Alert", true, ::AlertImpl );
scripts\mp\_integration_base::AddClientCommand( "Goto", false, ::GotoImpl ); scripts\_integration_base::AddClientCommand( "Goto", false, ::GotoImpl );
scripts\mp\_integration_base::AddClientCommand( "Kill", true, ::KillImpl ); scripts\_integration_base::AddClientCommand( "Kill", true, ::KillImpl );
scripts\mp\_integration_base::AddClientCommand( "SetSpectator", true, ::SetSpectatorImpl ); scripts\_integration_base::AddClientCommand( "SetSpectator", true, ::SetSpectatorImpl );
scripts\mp\_integration_base::AddClientCommand( "LockControls", true, ::LockControlsImpl ); scripts\_integration_base::AddClientCommand( "LockControls", true, ::LockControlsImpl );
scripts\mp\_integration_base::AddClientCommand( "PlayerToMe", true, ::PlayerToMeImpl ); scripts\_integration_base::AddClientCommand( "PlayerToMe", true, ::PlayerToMeImpl );
scripts\mp\_integration_base::AddClientCommand( "NoClip", false, ::NoClipImpl ); scripts\_integration_base::AddClientCommand( "NoClip", false, ::NoClipImpl );
} }
WaitForClientEvents() WaitForClientEvents()
@ -73,13 +75,13 @@ WaitForClientEvents()
// example of requesting a meta value // example of requesting a meta value
lastServerMetaKey = "LastServerPlayed"; lastServerMetaKey = "LastServerPlayed";
// self scripts\mp\_integration_base::RequestClientMeta( lastServerMetaKey ); // self scripts\_integration_base::RequestClientMeta( lastServerMetaKey );
for ( ;; ) for ( ;; )
{ {
self waittill( level.eventTypes.localClientEvent, event ); self waittill( level.eventTypes.localClientEvent, event );
scripts\mp\_integration_base::LogDebug( "Received client event " + event.type ); scripts\_integration_base::LogDebug( "Received client event " + event.type );
if ( event.type == level.eventTypes.clientDataReceived && event.data[0] == lastServerMetaKey ) if ( event.type == level.eventTypes.clientDataReceived && event.data[0] == lastServerMetaKey )
{ {
@ -109,6 +111,11 @@ Log2Console( logLevel, message )
Print( "[" + logLevel + "] " + message + "\n" ); Print( "[" + logLevel + "] " + message + "\n" );
} }
_GetXUID()
{
return self GetXUID();
}
////////////////////////////////// //////////////////////////////////
// GUID helpers // GUID helpers
///////////////////////////////// /////////////////////////////////
@ -126,14 +133,14 @@ SetPersistentData()
{ {
// give IW4MAdmin time to collect IP // give IW4MAdmin time to collect IP
wait( 15 ); wait( 15 );
scripts\mp\_integration_base::LogDebug( "Uploading persistent guid " + persistentGuid ); scripts\_integration_base::LogDebug( "Uploading persistent guid " + persistentGuid );
scripts\mp\_integration_base::SetClientMeta( "PersistentClientGuid", persistentGuid ); scripts\_integration_base::SetClientMeta( "PersistentClientGuid", persistentGuid );
return; return;
} }
guid = self SplitGuid(); guid = self SplitGuid();
scripts\mp\_integration_base::LogDebug( "Persisting client guid " + guidHigh + "," + guidLow ); scripts\_integration_base::LogDebug( "Persisting client guid " + guidHigh + "," + guidLow );
self SetPlayerData( "bests", "none", guid["high"] ); self SetPlayerData( "bests", "none", guid["high"] );
self SetPlayerData( "awards", "none", guid["low"] ); self SetPlayerData( "awards", "none", guid["low"] );

View File

@ -8,6 +8,9 @@ Setup()
{ {
level endon( "game_ended" ); level endon( "game_ended" );
// it's possible that the notify type has not been defined yet so we have to hard code it
level waittill( "IntegrationBootstrapInitialized" );
level.commonFunctions.changeTeam = "ChangeTeam"; level.commonFunctions.changeTeam = "ChangeTeam";
level.commonFunctions.getTeamCounts = "GetTeamCounts"; level.commonFunctions.getTeamCounts = "GetTeamCounts";
level.commonFunctions.getMaxClients = "GetMaxClients"; level.commonFunctions.getMaxClients = "GetMaxClients";
@ -25,6 +28,7 @@ Setup()
level.overrideMethods[level.commonFunctions.getClientKillStreak] = scripts\_integration_base::NotImplementedFunction; level.overrideMethods[level.commonFunctions.getClientKillStreak] = scripts\_integration_base::NotImplementedFunction;
level.overrideMethods[level.commonFunctions.backupRestoreClientKillStreakData] = scripts\_integration_base::NotImplementedFunction; level.overrideMethods[level.commonFunctions.backupRestoreClientKillStreakData] = scripts\_integration_base::NotImplementedFunction;
level.overrideMethods[level.commonFunctions.waitTillAnyTimeout] = scripts\_integration_base::NotImplementedFunction; level.overrideMethods[level.commonFunctions.waitTillAnyTimeout] = scripts\_integration_base::NotImplementedFunction;
level.overrideMethods["GetPlayerFromClientNum"] = ::GetPlayerFromClientNum;
// these can be overridden per game if needed // these can be overridden per game if needed
level.commonKeys.team1 = "allies"; level.commonKeys.team1 = "allies";
@ -39,12 +43,10 @@ Setup()
level.iw4madminIntegrationDefaultPerformance = 200; level.iw4madminIntegrationDefaultPerformance = 200;
if ( GetDvarInt( "sv_iw4madmin_integration_enabled" ) != 1 ) level notify( level.notifyTypes.sharedFunctionsInitialized );
{ level waittill( level.notifyTypes.gameFunctionsInitialized );
return;
}
if ( GetDvarInt( "sv_iw4madmin_autobalance" ) != 1 ) if ( GetDvarInt( "sv_iw4madmin_integration_enabled" ) != 1 )
{ {
return; return;
} }
@ -60,6 +62,21 @@ OnPlayerConnect()
{ {
level waittill( level.eventTypes.connect, player ); level waittill( level.eventTypes.connect, player );
if ( scripts\_integration_base::_IsBot( player ) )
{
// we don't want to track bots
continue;
}
player thread OnPlayerJoinedTeam();
player thread OnPlayerJoinedSpectators();
player thread PlayerTrackingOnInterval();
if ( GetDvarInt( "sv_iw4madmin_autobalance" ) != 1 || !IsDefined( [[level.overrideMethods[level.commonFunctions.getTeamBased]]]() ) )
{
continue;
}
if ( ![[level.overrideMethods[level.commonFunctions.getTeamBased]]]() ) if ( ![[level.overrideMethods[level.commonFunctions.getTeamBased]]]() )
{ {
continue; continue;
@ -449,3 +466,123 @@ GetClientPerformanceOrDefault()
return performance; return performance;
} }
GetPlayerFromClientNum( clientNum )
{
if ( clientNum < 0 )
{
return undefined;
}
for ( i = 0; i < level.players.size; i++ )
{
if ( level.players[i] getEntityNumber() == clientNum )
{
return level.players[i];
}
}
return undefined;
}
OnPlayerJoinedTeam()
{
self endon( "disconnect" );
for( ;; )
{
self waittill( "joined_team" );
// join spec and join team occur at the same moment - out of order logging would be problematic
wait( 0.25 );
LogPrint( GenerateJoinTeamString( false ) );
}
}
OnPlayerJoinedSpectators()
{
self endon( "disconnect" );
for( ;; )
{
self waittill( "joined_spectators" );
LogPrint( GenerateJoinTeamString( true ) );
}
}
GenerateJoinTeamString( isSpectator )
{
team = self.team;
if ( IsDefined( self.joining_team ) )
{
team = self.joining_team;
}
else
{
if ( isSpectator || !IsDefined( team ) )
{
team = "spectator";
}
}
guid = self [[level.overrideMethods[level.commonFunctions.getXuid]]]();
if ( guid == "0" )
{
guid = self.guid;
}
if ( !IsDefined( guid ) || guid == "0" )
{
guid = "undefined";
}
return "JT;" + guid + ";" + self getEntityNumber() + ";" + team + ";" + self.name + "\n";
}
PlayerTrackingOnInterval()
{
self endon( "disconnect" );
for ( ;; )
{
wait ( 120 );
if ( IsAlive( self ) )
{
self SaveTrackingMetrics();
}
}
}
SaveTrackingMetrics()
{
if ( !IsDefined( self.persistentClientId ) )
{
return;
}
scripts\_integration_base::LogDebug( "Saving tracking metrics for " + self.persistentClientId );
if ( !IsDefined( self.lastShotCount ) )
{
self.lastShotCount = 0;
}
currentShotCount = self [[level.overrideMethods["GetTotalShotsFired"]]]();
change = currentShotCount - self.lastShotCount;
self.lastShotCount = currentShotCount;
scripts\_integration_base::LogDebug( "Total Shots Fired increased by " + change );
if ( !IsDefined( change ) )
{
change = 0;
}
if ( change == 0 )
{
return;
}
scripts\_integration_base::IncrementClientMeta( "TotalShotsFired", change, self.persistentClientId );
}

View File

@ -2,8 +2,6 @@
Init() Init()
{ {
level.eventBus.gamename = "T5";
thread Setup(); thread Setup();
} }
@ -12,16 +10,20 @@ Setup()
level endon( "game_ended" ); level endon( "game_ended" );
// it's possible that the notify type has not been defined yet so we have to hard code it // it's possible that the notify type has not been defined yet so we have to hard code it
level waittill( "IntegrationBootstrapInitialized" ); level waittill( "SharedFunctionsInitialized" );
level.eventBus.gamename = "T5";
scripts\mp\_integration_base::RegisterLogger( ::Log2Console ); scripts\_integration_base::RegisterLogger( ::Log2Console );
level.overrideMethods["GetTotalShotsFired"] = ::GetTotalShotsFired; level.overrideMethods["GetTotalShotsFired"] = ::GetTotalShotsFired;
level.overrideMethods["SetDvarIfUninitialized"] = ::_SetDvarIfUninitialized; level.overrideMethods["SetDvarIfUninitialized"] = ::_SetDvarIfUninitialized;
level.overrideMethods["waittill_notify_or_timeout"] = ::_waittill_notify_or_timeout; level.overrideMethods["waittill_notify_or_timeout"] = ::_waittill_notify_or_timeout;
level.overrideMethods[level.commonFunctions.getXuid] = ::_GetXUID;
RegisterClientCommands(); RegisterClientCommands();
_SetDvarIfUninitialized( "sv_iw4madmin_autobalance", 0 );
level notify( level.notifyTypes.gameFunctionsInitialized ); level notify( level.notifyTypes.gameFunctionsInitialized );
if ( GetDvarInt( "sv_iw4madmin_integration_enabled" ) != 1 ) if ( GetDvarInt( "sv_iw4madmin_integration_enabled" ) != 1 )
@ -40,7 +42,7 @@ OnPlayerConnect()
{ {
level waittill( "connected", player ); level waittill( "connected", player );
if ( scripts\mp\_integration_base::_IsBot( player ) ) if ( scripts\_integration_base::_IsBot( player ) )
{ {
// we don't want to track bots // we don't want to track bots
continue; continue;
@ -53,17 +55,17 @@ OnPlayerConnect()
RegisterClientCommands() RegisterClientCommands()
{ {
scripts\mp\_integration_base::AddClientCommand( "GiveWeapon", true, ::GiveWeaponImpl ); scripts\_integration_base::AddClientCommand( "GiveWeapon", true, ::GiveWeaponImpl );
scripts\mp\_integration_base::AddClientCommand( "TakeWeapons", true, ::TakeWeaponsImpl ); scripts\_integration_base::AddClientCommand( "TakeWeapons", true, ::TakeWeaponsImpl );
scripts\mp\_integration_base::AddClientCommand( "SwitchTeams", true, ::TeamSwitchImpl ); scripts\_integration_base::AddClientCommand( "SwitchTeams", true, ::TeamSwitchImpl );
scripts\mp\_integration_base::AddClientCommand( "Hide", false, ::HideImpl ); scripts\_integration_base::AddClientCommand( "Hide", false, ::HideImpl );
scripts\mp\_integration_base::AddClientCommand( "Alert", true, ::AlertImpl ); scripts\_integration_base::AddClientCommand( "Alert", true, ::AlertImpl );
scripts\mp\_integration_base::AddClientCommand( "Goto", false, ::GotoImpl ); scripts\_integration_base::AddClientCommand( "Goto", false, ::GotoImpl );
scripts\mp\_integration_base::AddClientCommand( "Kill", true, ::KillImpl ); scripts\_integration_base::AddClientCommand( "Kill", true, ::KillImpl );
scripts\mp\_integration_base::AddClientCommand( "SetSpectator", true, ::SetSpectatorImpl ); scripts\_integration_base::AddClientCommand( "SetSpectator", true, ::SetSpectatorImpl );
scripts\mp\_integration_base::AddClientCommand( "LockControls", true, ::LockControlsImpl ); scripts\_integration_base::AddClientCommand( "LockControls", true, ::LockControlsImpl );
scripts\mp\_integration_base::AddClientCommand( "PlayerToMe", true, ::PlayerToMeImpl ); scripts\_integration_base::AddClientCommand( "PlayerToMe", true, ::PlayerToMeImpl );
scripts\mp\_integration_base::AddClientCommand( "NoClip", false, ::NoClipImpl ); scripts\_integration_base::AddClientCommand( "NoClip", false, ::NoClipImpl );
} }
WaitForClientEvents() WaitForClientEvents()
@ -72,13 +74,13 @@ WaitForClientEvents()
// example of requesting a meta value // example of requesting a meta value
lastServerMetaKey = "LastServerPlayed"; lastServerMetaKey = "LastServerPlayed";
// self scripts\mp\_integration_base::RequestClientMeta( lastServerMetaKey ); // self scripts\_integration_base::RequestClientMeta( lastServerMetaKey );
for ( ;; ) for ( ;; )
{ {
self waittill( level.eventTypes.localClientEvent, event ); self waittill( level.eventTypes.localClientEvent, event );
scripts\mp\_integration_base::LogDebug( "Received client event " + event.type ); scripts\_integration_base::LogDebug( "Received client event " + event.type );
if ( event.type == level.eventTypes.clientDataReceived && event.data[0] == lastServerMetaKey ) if ( event.type == level.eventTypes.clientDataReceived && event.data[0] == lastServerMetaKey )
{ {
@ -129,6 +131,11 @@ God()
} }
} }
_GetXUID()
{
return self GetXUID();
}
////////////////////////////////// //////////////////////////////////
// GUID helpers // GUID helpers
///////////////////////////////// /////////////////////////////////
@ -146,14 +153,14 @@ God()
{ {
// give IW4MAdmin time to collect IP // give IW4MAdmin time to collect IP
wait( 15 ); wait( 15 );
scripts\mp\_integration_base::LogDebug( "Uploading persistent guid " + persistentGuid ); scripts\_integration_base::LogDebug( "Uploading persistent guid " + persistentGuid );
scripts\mp\_integration_base::SetClientMeta( "PersistentClientGuid", persistentGuid ); scripts\_integration_base::SetClientMeta( "PersistentClientGuid", persistentGuid );
return; return;
} }
guid = self SplitGuid(); guid = self SplitGuid();
scripts\mp\_integration_base::LogDebug( "Persisting client guid " + guidHigh + "," + guidLow ); scripts\_integration_base::LogDebug( "Persisting client guid " + guidHigh + "," + guidLow );
self SetPlayerData( "bests", "none", guid["high"] ); self SetPlayerData( "bests", "none", guid["high"] );
self SetPlayerData( "awards", "none", guid["low"] ); self SetPlayerData( "awards", "none", guid["low"] );
@ -395,7 +402,7 @@ NoClipImpl( event, data )
self IPrintLnBold( "NoClip enabled" );*/ self IPrintLnBold( "NoClip enabled" );*/
scripts\mp\_integration_base::LogWarning( "NoClip is not supported on T5!" ); scripts\_integration_base::LogWarning( "NoClip is not supported on T5!" );
} }

View File

@ -0,0 +1,552 @@
#include common_scripts\utility;
Init()
{
thread Setup();
}
Setup()
{
level endon( "game_ended" );
// it's possible that the notify type has not been defined yet so we have to hard code it
level waittill( "SharedFunctionsInitialized" );
level.eventBus.gamename = "T5";
scripts\_integration_base::RegisterLogger( ::Log2Console );
level.overrideMethods["GetTotalShotsFired"] = ::GetTotalShotsFired;
level.overrideMethods["SetDvarIfUninitialized"] = ::_SetDvarIfUninitialized;
level.overrideMethods["waittill_notify_or_timeout"] = ::_waittill_notify_or_timeout;
level.overrideMethods["GetPlayerFromClientNum"] = ::_GetPlayerFromClientNum;
RegisterClientCommands();
_SetDvarIfUninitialized( "sv_iw4madmin_autobalance", 0 );
level notify( level.notifyTypes.gameFunctionsInitialized );
if ( GetDvarInt( "sv_iw4madmin_integration_enabled" ) != 1 )
{
return;
}
level thread OnPlayerConnect();
}
OnPlayerConnect()
{
level endon ( "game_ended" );
for ( ;; )
{
level waittill( "connected", player );
if ( scripts\_integration_base::_IsBot( player ) )
{
// we don't want to track bots
continue;
}
//player thread SetPersistentData();
player thread WaitForClientEvents();
}
}
RegisterClientCommands()
{
scripts\_integration_base::AddClientCommand( "GiveWeapon", true, ::GiveWeaponImpl );
scripts\_integration_base::AddClientCommand( "TakeWeapons", true, ::TakeWeaponsImpl );
scripts\_integration_base::AddClientCommand( "SwitchTeams", true, ::TeamSwitchImpl );
scripts\_integration_base::AddClientCommand( "Hide", false, ::HideImpl );
scripts\_integration_base::AddClientCommand( "Alert", true, ::AlertImpl );
scripts\_integration_base::AddClientCommand( "Goto", false, ::GotoImpl );
scripts\_integration_base::AddClientCommand( "Kill", true, ::KillImpl );
scripts\_integration_base::AddClientCommand( "SetSpectator", true, ::SetSpectatorImpl );
scripts\_integration_base::AddClientCommand( "LockControls", true, ::LockControlsImpl );
scripts\_integration_base::AddClientCommand( "PlayerToMe", true, ::PlayerToMeImpl );
scripts\_integration_base::AddClientCommand( "NoClip", false, ::NoClipImpl );
}
WaitForClientEvents()
{
self endon( "disconnect" );
// example of requesting a meta value
lastServerMetaKey = "LastServerPlayed";
// self scripts\_integration_base::RequestClientMeta( lastServerMetaKey );
for ( ;; )
{
self waittill( level.eventTypes.localClientEvent, event );
scripts\_integration_base::LogDebug( "Received client event " + event.type );
if ( event.type == level.eventTypes.clientDataReceived && event.data[0] == lastServerMetaKey )
{
clientData = self.pers[level.clientDataKey];
lastServerPlayed = clientData.meta[lastServerMetaKey];
}
}
}
GetTotalShotsFired()
{
return 0; //ZM has no shot tracking. TODO: add tracking function for event weapon_fired
}
_SetDvarIfUninitialized(dvar, value)
{
if (GetDvar(dvar)=="" )
{
SetDvar(dvar, value);
return value;
}
return GetDvar(dvar);
}
_waittill_notify_or_timeout( msg, timer )
{
self endon( msg );
wait( timer );
}
Log2Console( logLevel, message )
{
Print( "[" + logLevel + "] " + message + "\n" );
}
God()
{
if ( !IsDefined( self.godmode ) )
{
self.godmode = false;
}
if (!self.godmode )
{
self enableInvulnerability();
self.godmode = true;
}
else
{
self.godmode = false;
self disableInvulnerability();
}
}
_GetPlayerFromClientNum( clientNum )
{
if ( clientNum < 0 )
{
return undefined;
}
players = GetPlayers("all");
for ( i = 0; i < players.size; i++ )
{
scripts\_integration_base::LogDebug(i+"/"+players.size+ "=" + players[i].name);
if ( players[i] getEntityNumber() == clientNum )
{
return players[i];
}
}
return undefined;
}
//////////////////////////////////
// GUID helpers
/////////////////////////////////
/*SetPersistentData()
{
self endon( "disconnect" );
guidHigh = self GetPlayerData( "bests", "none" );
guidLow = self GetPlayerData( "awards", "none" );
persistentGuid = guidHigh + "," + guidLow;
guidIsStored = guidHigh != 0 && guidLow != 0;
if ( guidIsStored )
{
// give IW4MAdmin time to collect IP
wait( 15 );
scripts\_integration_base::LogDebug( "Uploading persistent guid " + persistentGuid );
scripts\_integration_base::SetClientMeta( "PersistentClientGuid", persistentGuid );
return;
}
guid = self SplitGuid();
scripts\_integration_base::LogDebug( "Persisting client guid " + guidHigh + "," + guidLow );
self SetPlayerData( "bests", "none", guid["high"] );
self SetPlayerData( "awards", "none", guid["low"] );
}
SplitGuid()
{
guid = self GetGuid();
if ( isDefined( self.guid ) )
{
guid = self.guid;
}
firstPart = 0;
secondPart = 0;
stringLength = 17;
firstPartExp = 0;
secondPartExp = 0;
for ( i = stringLength - 1; i > 0; i-- )
{
char = GetSubStr( guid, i - 1, i );
if ( char == "" )
{
char = "0";
}
if ( i > stringLength / 2 )
{
value = GetIntForHexChar( char );
power = Pow( 16, secondPartExp );
secondPart = secondPart + ( value * power );
secondPartExp++;
}
else
{
value = GetIntForHexChar( char );
power = Pow( 16, firstPartExp );
firstPart = firstPart + ( value * power );
firstPartExp++;
}
}
split = [];
split["low"] = int( secondPart );
split["high"] = int( firstPart );
return split;
}
Pow( num, exponent )
{
result = 1;
while( exponent != 0 )
{
result = result * num;
exponent--;
}
return result;
}
GetIntForHexChar( char )
{
char = ToLower( char );
// generated by co-pilot because I can't be bothered to make it more "elegant"
switch( char )
{
case "0":
return 0;
case "1":
return 1;
case "2":
return 2;
case "3":
return 3;
case "4":
return 4;
case "5":
return 5;
case "6":
return 6;
case "7":
return 7;
case "8":
return 8;
case "9":
return 9;
case "a":
return 10;
case "b":
return 11;
case "c":
return 12;
case "d":
return 13;
case "e":
return 14;
case "f":
return 15;
default:
return 0;
}
}*/
//////////////////////////////////
// Command Implementations
/////////////////////////////////
GiveWeaponImpl( event, data )
{
if ( !IsAlive( self ) )
{
return self.name + "^7 is not alive";
}
self IPrintLnBold( "You have been given a new weapon" );
self GiveWeapon( data["weaponName"] );
self SwitchToWeapon( data["weaponName"] );
return self.name + "^7 has been given ^5" + data["weaponName"];
}
TakeWeaponsImpl( event, data )
{
if ( !IsAlive( self ) )
{
return self.name + "^7 is not alive";
}
self TakeAllWeapons();
self IPrintLnBold( "All your weapons have been taken" );
return "Took weapons from " + self.name;
}
TeamSwitchImpl( event, data )
{
if ( !IsAlive( self ) )
{
return self + "^7 is not alive";
}
team = level.allies;
if ( self.team == "allies" )
{
team = level.axis;
}
self IPrintLnBold( "You are being team switched" );
wait( 2 );
self [[team]]();
return self.name + "^7 switched to " + self.team;
}
LockControlsImpl( event, data )
{
if ( !IsAlive( self ) )
{
return self.name + "^7 is not alive";
}
if ( !IsDefined ( self.isControlLocked ) )
{
self.isControlLocked = false;
}
if ( !self.isControlLocked )
{
self freezeControls( true );
self God();
self Hide();
info = [];
info[ "alertType" ] = "Alert!";
info[ "message" ] = "You have been frozen!";
self AlertImpl( undefined, info );
self.isControlLocked = true;
return self.name + "\'s controls are locked";
}
else
{
self freezeControls( false );
self God();
self Show();
self.isControlLocked = false;
return self.name + "\'s controls are unlocked";
}
}
NoClipImpl( event, data )
{
/*if ( !IsAlive( self ) )
{
self IPrintLnBold( "You are not alive" );
}
if ( !IsDefined ( self.isNoClipped ) )
{
self.isNoClipped = false;
}
if ( !self.isNoClipped )
{
self SetClientDvar( "sv_cheats", 1 );
self SetClientDvar( "cg_thirdperson", 1 );
self SetClientDvar( "sv_cheats", 0 );
self God();
self Noclip();
self Hide();
self.isNoClipped = true;
self IPrintLnBold( "NoClip enabled" );
}
else
{
self SetClientDvar( "sv_cheats", 1 );
self SetClientDvar( "cg_thirdperson", 1 );
self SetClientDvar( "sv_cheats", 0 );
self God();
self Noclip();
self Hide();
self.isNoClipped = false;
self IPrintLnBold( "NoClip disabled" );
}
self IPrintLnBold( "NoClip enabled" );*/
scripts\_integration_base::LogWarning( "NoClip is not supported on T5!" );
}
HideImpl( event, data )
{
if ( !IsAlive( self ) )
{
self IPrintLnBold( "You are not alive" );
return;
}
if ( !IsDefined ( self.isHidden ) )
{
self.isHidden = false;
}
if ( !self.isHidden )
{
self SetClientDvar( "sv_cheats", 1 );
self SetClientDvar( "cg_thirdperson", 1 );
self SetClientDvar( "sv_cheats", 0 );
self God();
self Hide();
self.isHidden = true;
self IPrintLnBold( "Hide enabled" );
}
else
{
self SetClientDvar( "sv_cheats", 1 );
self SetClientDvar( "cg_thirdperson", 0 );
self SetClientDvar( "sv_cheats", 0 );
self God();
self Show();
self.isHidden = false;
self IPrintLnBold( "Hide disabled" );
}
}
AlertImpl( event, data )
{
//self thread maps\mp\gametypes\_hud_message::oldNotifyMessage( data["alertType"], data["message"], undefined, ( 1, 0, 0 ), "mpl_sab_ui_suitcasebomb_timer", 7.5 );
self IPrintLnBold(data["message"]);
return "Sent alert to " + self.name;
}
GotoImpl( event, data )
{
if ( IsDefined( event.target ) )
{
return self GotoPlayerImpl( event.target );
}
else
{
return self GotoCoordImpl( data );
}
}
GotoCoordImpl( data )
{
if ( !IsAlive( self ) )
{
self IPrintLnBold( "You are not alive" );
return;
}
position = ( int( data["x"] ), int( data["y"] ), int( data["z"]) );
self SetOrigin( position );
self IPrintLnBold( "Moved to " + "("+ position[0] + "," + position[1] + "," + position[2] + ")" );
}
GotoPlayerImpl( target )
{
if ( !IsAlive( target ) )
{
self IPrintLnBold( target.name + " is not alive" );
return;
}
self SetOrigin( target GetOrigin() );
self IPrintLnBold( "Moved to " + target.name );
}
PlayerToMeImpl( event, data )
{
if ( !IsAlive( self ) )
{
return self.name + " is not alive";
}
self SetOrigin( event.origin GetOrigin() );
return "Moved here " + self.name;
}
KillImpl( event, data )
{
if ( !IsAlive( self ) )
{
return self.name + " is not alive";
}
self Suicide();
self IPrintLnBold( "You were killed by " + self.name );
return "You killed " + self.name;
}
SetSpectatorImpl( event, data )
{
if ( self.pers["team"] == "spectator" )
{
return self.name + " is already spectating";
}
self [[level.spectator]]();
self IPrintLnBold( "You have been moved to spectator" );
return self.name + " has been moved to spectator";
}

View File

@ -0,0 +1,571 @@
#include common_scripts\utility;
#include maps\mp\_utility;
Init()
{
thread Setup();
}
Setup()
{
level endon( "game_ended" );
// it's possible that the notify type has not been defined yet so we have to hard code it
level waittill( "SharedFunctionsInitialized" );
level.eventBus.gamename = "T6";
scripts\_integration_base::RegisterLogger( ::Log2Console );
level.overrideMethods["GetTotalShotsFired"] = ::GetTotalShotsFired;
level.overrideMethods["SetDvarIfUninitialized"] = ::_SetDvarIfUninitialized;
level.overrideMethods["waittill_notify_or_timeout"] = ::_waittill_notify_or_timeout;
level.overrideMethods[level.commonFunctions.getXuid] = ::_GetXUID;
RegisterClientCommands();
_SetDvarIfUninitialized( "sv_iw4madmin_autobalance", 0 );
level notify( level.notifyTypes.gameFunctionsInitialized );
if ( GetDvarInt( "sv_iw4madmin_integration_enabled" ) != 1 )
{
return;
}
level thread OnPlayerConnect();
}
OnPlayerConnect()
{
level endon ( "game_ended" );
for ( ;; )
{
level waittill( "connected", player );
if ( scripts\_integration_base::_IsBot( player ) )
{
// we don't want to track bots
continue;
}
//player thread SetPersistentData();
player thread WaitForClientEvents();
}
}
RegisterClientCommands()
{
scripts\_integration_base::AddClientCommand( "GiveWeapon", true, ::GiveWeaponImpl );
scripts\_integration_base::AddClientCommand( "TakeWeapons", true, ::TakeWeaponsImpl );
scripts\_integration_base::AddClientCommand( "SwitchTeams", true, ::TeamSwitchImpl );
scripts\_integration_base::AddClientCommand( "Hide", false, ::HideImpl );
scripts\_integration_base::AddClientCommand( "Alert", true, ::AlertImpl );
scripts\_integration_base::AddClientCommand( "Goto", false, ::GotoImpl );
scripts\_integration_base::AddClientCommand( "Kill", true, ::KillImpl );
scripts\_integration_base::AddClientCommand( "SetSpectator", true, ::SetSpectatorImpl );
scripts\_integration_base::AddClientCommand( "LockControls", true, ::LockControlsImpl );
scripts\_integration_base::AddClientCommand( "PlayerToMe", true, ::PlayerToMeImpl );
scripts\_integration_base::AddClientCommand( "NoClip", false, ::NoClipImpl );
}
WaitForClientEvents()
{
self endon( "disconnect" );
// example of requesting a meta value
lastServerMetaKey = "LastServerPlayed";
// self scripts\_integration_base::RequestClientMeta( lastServerMetaKey );
for ( ;; )
{
self waittill( level.eventTypes.localClientEvent, event );
scripts\_integration_base::LogDebug( "Received client event " + event.type );
if ( event.type == level.eventTypes.clientDataReceived && event.data[0] == lastServerMetaKey )
{
clientData = self.pers[level.clientDataKey];
lastServerPlayed = clientData.meta[lastServerMetaKey];
}
}
}
GetTotalShotsFired()
{
return self.pers[ "total_shots" ];
}
_SetDvarIfUninitialized(dvar, value)
{
maps\mp\_utility::set_dvar_if_unset(dvar, value);
}
_waittill_notify_or_timeout( msg, timer )
{
self endon( msg );
wait( timer );
}
Log2Console( logLevel, message )
{
Print( "[" + logLevel + "] " + message + "\n" );
}
God()
{
if ( !IsDefined( self.godmode ) )
{
self.godmode = false;
}
if (!self.godmode )
{
self enableInvulnerability();
self.godmode = true;
}
else
{
self.godmode = false;
self disableInvulnerability();
}
}
_GetXUID()
{
return self GetXUID();
}
//////////////////////////////////
// GUID helpers
/////////////////////////////////
/*SetPersistentData()
{
self endon( "disconnect" );
guidHigh = self GetPlayerData( "bests", "none" );
guidLow = self GetPlayerData( "awards", "none" );
persistentGuid = guidHigh + "," + guidLow;
guidIsStored = guidHigh != 0 && guidLow != 0;
if ( guidIsStored )
{
// give IW4MAdmin time to collect IP
wait( 15 );
scripts\_integration_base::LogDebug( "Uploading persistent guid " + persistentGuid );
scripts\_integration_base::SetClientMeta( "PersistentClientGuid", persistentGuid );
return;
}
guid = self SplitGuid();
scripts\_integration_base::LogDebug( "Persisting client guid " + guidHigh + "," + guidLow );
self SetPlayerData( "bests", "none", guid["high"] );
self SetPlayerData( "awards", "none", guid["low"] );
}
SplitGuid()
{
guid = self GetGuid();
if ( isDefined( self.guid ) )
{
guid = self.guid;
}
firstPart = 0;
secondPart = 0;
stringLength = 17;
firstPartExp = 0;
secondPartExp = 0;
for ( i = stringLength - 1; i > 0; i-- )
{
char = GetSubStr( guid, i - 1, i );
if ( char == "" )
{
char = "0";
}
if ( i > stringLength / 2 )
{
value = GetIntForHexChar( char );
power = Pow( 16, secondPartExp );
secondPart = secondPart + ( value * power );
secondPartExp++;
}
else
{
value = GetIntForHexChar( char );
power = Pow( 16, firstPartExp );
firstPart = firstPart + ( value * power );
firstPartExp++;
}
}
split = [];
split["low"] = int( secondPart );
split["high"] = int( firstPart );
return split;
}
Pow( num, exponent )
{
result = 1;
while( exponent != 0 )
{
result = result * num;
exponent--;
}
return result;
}
GetIntForHexChar( char )
{
char = ToLower( char );
// generated by co-pilot because I can't be bothered to make it more "elegant"
switch( char )
{
case "0":
return 0;
case "1":
return 1;
case "2":
return 2;
case "3":
return 3;
case "4":
return 4;
case "5":
return 5;
case "6":
return 6;
case "7":
return 7;
case "8":
return 8;
case "9":
return 9;
case "a":
return 10;
case "b":
return 11;
case "c":
return 12;
case "d":
return 13;
case "e":
return 14;
case "f":
return 15;
default:
return 0;
}
}*/
//////////////////////////////////
// Command Implementations
/////////////////////////////////
GiveWeaponImpl( event, data )
{
if ( !IsAlive( self ) )
{
return self.name + "^7 is not alive";
}
if ( isDefined( level.player_too_many_weapons_monitor ) && level.player_too_many_weapons_monitor )
{
level.player_too_many_weapons_monitor = false;
self notify( "stop_player_too_many_weapons_monitor" );
}
self IPrintLnBold( "You have been given a new weapon" );
self GiveWeapon( data["weaponName"] );
self SwitchToWeapon( data["weaponName"] );
return self.name + "^7 has been given ^5" + data["weaponName"];
}
TakeWeaponsImpl( event, data )
{
if ( !IsAlive( self ) )
{
return self.name + "^7 is not alive";
}
self TakeAllWeapons();
self IPrintLnBold( "All your weapons have been taken" );
return "Took weapons from " + self.name;
}
TeamSwitchImpl( event, data )
{
if ( !IsAlive( self ) )
{
return self + "^7 is not alive";
}
team = level.allies;
if ( self.team == "allies" )
{
team = level.axis;
}
self IPrintLnBold( "You are being team switched" );
wait( 2 );
self [[team]]();
return self.name + "^7 switched to " + self.team;
}
LockControlsImpl( event, data )
{
if ( !IsAlive( self ) )
{
return self.name + "^7 is not alive";
}
if ( !IsDefined ( self.isControlLocked ) )
{
self.isControlLocked = false;
}
if ( !self.isControlLocked )
{
self freezeControls( true );
self God();
self Hide();
info = [];
info[ "alertType" ] = "Alert!";
info[ "message" ] = "You have been frozen!";
self AlertImpl( undefined, info );
self.isControlLocked = true;
return self.name + "\'s controls are locked";
}
else
{
self freezeControls( false );
self God();
self Show();
self.isControlLocked = false;
return self.name + "\'s controls are unlocked";
}
}
NoClipImpl( event, data )
{
/*if ( !IsAlive( self ) )
{
self IPrintLnBold( "You are not alive" );
}
if ( !IsDefined ( self.isNoClipped ) )
{
self.isNoClipped = false;
}
if ( !self.isNoClipped )
{
self SetClientDvar( "sv_cheats", 1 );
self SetClientDvar( "cg_thirdperson", 1 );
self SetClientDvar( "sv_cheats", 0 );
self God();
self Noclip();
self Hide();
self.isNoClipped = true;
self IPrintLnBold( "NoClip enabled" );
}
else
{
self SetClientDvar( "sv_cheats", 1 );
self SetClientDvar( "cg_thirdperson", 1 );
self SetClientDvar( "sv_cheats", 0 );
self God();
self Noclip();
self Hide();
self.isNoClipped = false;
self IPrintLnBold( "NoClip disabled" );
}
self IPrintLnBold( "NoClip enabled" );*/
scripts\_integration_base::LogWarning( "NoClip is not supported on T6!" );
}
HideImpl( event, data )
{
if ( !IsAlive( self ) )
{
self IPrintLnBold( "You are not alive" );
return;
}
if ( !IsDefined ( self.isHidden ) )
{
self.isHidden = false;
}
if ( !self.isHidden )
{
self SetClientDvar( "sv_cheats", 1 );
self SetClientDvar( "cg_thirdperson", 1 );
self SetClientDvar( "sv_cheats", 0 );
self God();
self Hide();
self.isHidden = true;
self IPrintLnBold( "Hide enabled" );
}
else
{
self SetClientDvar( "sv_cheats", 1 );
self SetClientDvar( "cg_thirdperson", 0 );
self SetClientDvar( "sv_cheats", 0 );
self God();
self Show();
self.isHidden = false;
self IPrintLnBold( "Hide disabled" );
}
}
AlertImpl( event, data )
{
/*if ( !sessionmodeiszombiesgame() )
{*/
self thread oldNotifyMessage( data["alertType"], data["message"], undefined, ( 1, 0, 0 ), "mpl_sab_ui_suitcasebomb_timer", 7.5 );
/*}
else
{
self IPrintLnBold( data["alertType"] );
self IPrintLnBold( data["message"] );
}*/
return "Sent alert to " + self.name;
}
GotoImpl( event, data )
{
if ( IsDefined( event.target ) )
{
return self GotoPlayerImpl( event.target );
}
else
{
return self GotoCoordImpl( data );
}
}
GotoCoordImpl( event, data )
{
if ( !IsAlive( self ) )
{
self IPrintLnBold( "You are not alive" );
return;
}
position = ( int( data["x"] ), int( data["y"] ), int( data["z"]) );
self SetOrigin( position );
self IPrintLnBold( "Moved to " + "("+ position[0] + "," + position[1] + "," + position[2] + ")" );
}
GotoPlayerImpl( target )
{
if ( !IsAlive( target ) )
{
self IPrintLnBold( target.name + " is not alive" );
return;
}
self SetOrigin( target GetOrigin() );
self IPrintLnBold( "Moved to " + target.name );
}
PlayerToMeImpl( event, data )
{
if ( !IsAlive( self ) )
{
return self.name + " is not alive";
}
self SetOrigin( event.origin GetOrigin() );
return "Moved here " + self.name;
}
KillImpl( event, data )
{
if ( !IsAlive( self ) )
{
return self.name + " is not alive";
}
self Suicide();
self IPrintLnBold( "You were killed by " + self.name );
return "You killed " + self.name;
}
SetSpectatorImpl( event, data )
{
if ( self.pers["team"] == "spectator" )
{
return self.name + " is already spectating";
}
self [[level.spectator]]();
self IPrintLnBold( "You have been moved to spectator" );
return self.name + " has been moved to spectator";
}
//////////////////////////////////
// T6 specific functions
/////////////////////////////////
/*
1:1 the same on MP and ZM but in different includes. Since we probably want to be able to send Alerts on non teambased wagermatechs use our own copy.
*/
oldnotifymessage( titletext, notifytext, iconname, glowcolor, sound, duration )
{
/*if ( level.wagermatch && !level.teambased )
{
return;
}*/
notifydata = spawnstruct();
notifydata.titletext = titletext;
notifydata.notifytext = notifytext;
notifydata.iconname = iconname;
notifydata.sound = sound;
notifydata.duration = duration;
self.startmessagenotifyqueue[ self.startmessagenotifyqueue.size ] = notifydata;
self notify( "received award" );
}

View File

@ -0,0 +1,86 @@
init()
{
level.startmessagedefaultduration = 2;
level.regulargamemessages = spawnstruct();
level.regulargamemessages.waittime = 6;
level thread onplayerconnect();
}
onplayerconnect()
{
for ( ;; )
{
level waittill( "connecting", player );
player thread displaypopupswaiter();
}
}
displaypopupswaiter()
{
self endon( "disconnect" );
self.ranknotifyqueue = [];
if ( !isDefined( self.pers[ "challengeNotifyQueue" ] ) )
{
self.pers[ "challengeNotifyQueue" ] = [];
}
if ( !isDefined( self.pers[ "contractNotifyQueue" ] ) )
{
self.pers[ "contractNotifyQueue" ] = [];
}
self.messagenotifyqueue = [];
self.startmessagenotifyqueue = [];
self.wagernotifyqueue = [];
while ( !level.gameended )
{
if ( self.startmessagenotifyqueue.size == 0 && self.messagenotifyqueue.size == 0 )
{
self waittill( "received award" );
}
waittillframeend;
if ( level.gameended )
{
return;
}
else
{
if ( self.startmessagenotifyqueue.size > 0 )
{
nextnotifydata = self.startmessagenotifyqueue[ 0 ];
arrayremoveindex( self.startmessagenotifyqueue, 0, 0 );
if ( isDefined( nextnotifydata.duration ) )
{
duration = nextnotifydata.duration;
}
else
{
duration = level.startmessagedefaultduration;
}
self maps\mp\gametypes_zm\_hud_message::shownotifymessage( nextnotifydata, duration );
wait duration;
continue;
}
else if ( self.messagenotifyqueue.size > 0 )
{
nextnotifydata = self.messagenotifyqueue[ 0 ];
arrayremoveindex( self.messagenotifyqueue, 0, 0 );
if ( isDefined( nextnotifydata.duration ) )
{
duration = nextnotifydata.duration;
}
else
{
duration = level.regulargamemessages.waittime;
}
self maps\mp\gametypes_zm\_hud_message::shownotifymessage( nextnotifydata, duration );
continue;
}
else
{
wait 1;
}
}
}
}

View File

@ -1,14 +1,20 @@
@echo off @echo off
ECHO "Pluto IW5" ECHO "Pluto IW5"
xcopy /y .\GameInterface\_integration_base.gsc "%LOCALAPPDATA%\Plutonium\storage\iw5\scripts\mp" xcopy /y .\GameInterface\_integration_base.gsc "%LOCALAPPDATA%\Plutonium\storage\iw5\scripts"
xcopy /y .\GameInterface\_integration_iw5.gsc "%LOCALAPPDATA%\Plutonium\storage\iw5\scripts\mp" xcopy /y .\GameInterface\_integration_shared.gsc "%LOCALAPPDATA%\Plutonium\storage\iw5\scripts"
xcopy /y .\GameInterface\_integration_iw5.gsc "%LOCALAPPDATA%\Plutonium\storage\iw5\scripts"
xcopy /y .\AntiCheat\IW5\storage\iw5\scripts\_customcallbacks.gsc "%LOCALAPPDATA%\Plutonium\storage\iw5\scripts\mp" xcopy /y .\AntiCheat\IW5\storage\iw5\scripts\_customcallbacks.gsc "%LOCALAPPDATA%\Plutonium\storage\iw5\scripts\mp"
ECHO "Pluto T5" ECHO "Pluto T5"
xcopy /y .\GameInterface\_integration_base.gsc "%LOCALAPPDATA%\Plutonium\storage\t5\scripts\mp" xcopy /y .\GameInterface\_integration_base.gsc "%LOCALAPPDATA%\Plutonium\storage\t5\scripts"
xcopy /y .\GameInterface\_integration_shared.gsc "%LOCALAPPDATA%\Plutonium\storage\t5\scripts"
xcopy /y .\GameInterface\_integration_t5.gsc "%LOCALAPPDATA%\Plutonium\storage\t5\scripts\mp" xcopy /y .\GameInterface\_integration_t5.gsc "%LOCALAPPDATA%\Plutonium\storage\t5\scripts\mp"
xcopy /y .\GameInterface\_integration_t5zm.gsc "%LOCALAPPDATA%\Plutonium\storage\t5\scripts\sp\zom"
ECHO "Pluto T6" ECHO "Pluto T6"
xcopy /y .\AntiCheat\PT6\storage\t6\scripts\mp\_customcallbacks.gsc "%LOCALAPPDATA%\Plutonium\storage\t6\scripts\mp" xcopy /y .\AntiCheat\PT6\storage\t6\scripts\mp\_customcallbacks.gsc "%LOCALAPPDATA%\Plutonium\storage\t6\scripts\mp"
xcopy /y .\AntiCheat\PT6\storage\t6\scripts\mp\_customcallbacks.gsc.src "%LOCALAPPDATA%\Plutonium\storage\t6\scripts\mp" xcopy /y .\GameInterface\_integration_base.gsc "%LOCALAPPDATA%\Plutonium\storage\t6\scripts"
xcopy /y .\GameInterface\_integration_shared.gsc "%LOCALAPPDATA%\Plutonium\storage\t6\scripts"
xcopy /y .\GameInterface\_integration_t6.gsc "%LOCALAPPDATA%\Plutonium\storage\t6\scripts"
xcopy /y .\GameInterface\_integration_t6zm_helper.gsc "%LOCALAPPDATA%\Plutonium\storage\t6\scripts\zm"

View File

@ -385,7 +385,7 @@ const commands = [{
required: true required: true
} }
], ],
supportedGames: ['IW4', 'IW5', 'T5'], supportedGames: ['IW4', 'IW5', 'T5', 'T6'],
execute: (gameEvent) => { execute: (gameEvent) => {
if (!validateEnabled(gameEvent.owner, gameEvent.origin)) { if (!validateEnabled(gameEvent.owner, gameEvent.origin)) {
return; return;
@ -405,7 +405,7 @@ const commands = [{
name: 'player', name: 'player',
required: true required: true
}], }],
supportedGames: ['IW4', 'IW5', 'T5'], supportedGames: ['IW4', 'IW5', 'T5', 'T6'],
execute: (gameEvent) => { execute: (gameEvent) => {
if (!validateEnabled(gameEvent.owner, gameEvent.origin)) { if (!validateEnabled(gameEvent.owner, gameEvent.origin)) {
return; return;
@ -423,7 +423,7 @@ const commands = [{
name: 'player', name: 'player',
required: true required: true
}], }],
supportedGames: ['IW4', 'IW5', 'T5'], supportedGames: ['IW4', 'IW5', 'T5', 'T6'],
execute: (gameEvent) => { execute: (gameEvent) => {
if (!validateEnabled(gameEvent.owner, gameEvent.origin)) { if (!validateEnabled(gameEvent.owner, gameEvent.origin)) {
return; return;
@ -441,7 +441,7 @@ const commands = [{
name: 'player', name: 'player',
required: true required: true
}], }],
supportedGames: ['IW4', 'IW5', 'T5'], supportedGames: ['IW4', 'IW5', 'T5', 'T6'],
execute: (gameEvent) => { execute: (gameEvent) => {
if (!validateEnabled(gameEvent.owner, gameEvent.origin)) { if (!validateEnabled(gameEvent.owner, gameEvent.origin)) {
return; return;
@ -471,7 +471,7 @@ const commands = [{
permission: 'SeniorAdmin', permission: 'SeniorAdmin',
targetRequired: false, targetRequired: false,
arguments: [], arguments: [],
supportedGames: ['IW4', 'IW5', 'T5'], supportedGames: ['IW4', 'IW5', 'T5', 'T6'],
execute: (gameEvent) => { execute: (gameEvent) => {
if (!validateEnabled(gameEvent.owner, gameEvent.origin)) { if (!validateEnabled(gameEvent.owner, gameEvent.origin)) {
return; return;
@ -494,7 +494,7 @@ const commands = [{
required: true required: true
} }
], ],
supportedGames: ['IW4', 'IW5', 'T5'], supportedGames: ['IW4', 'IW5', 'T5', 'T6'],
execute: (gameEvent) => { execute: (gameEvent) => {
if (!validateEnabled(gameEvent.owner, gameEvent.origin)) { if (!validateEnabled(gameEvent.owner, gameEvent.origin)) {
return; return;
@ -515,7 +515,7 @@ const commands = [{
name: 'player', name: 'player',
required: true required: true
}], }],
supportedGames: ['IW4', 'IW5', 'T5'], supportedGames: ['IW4', 'IW5', 'T5', 'T6'],
execute: (gameEvent) => { execute: (gameEvent) => {
if (!validateEnabled(gameEvent.owner, gameEvent.origin)) { if (!validateEnabled(gameEvent.owner, gameEvent.origin)) {
return; return;
@ -533,7 +533,7 @@ const commands = [{
name: 'player', name: 'player',
required: true required: true
}], }],
supportedGames: ['IW4', 'IW5', 'T5'], supportedGames: ['IW4', 'IW5', 'T5', 'T6'],
execute: (gameEvent) => { execute: (gameEvent) => {
if (!validateEnabled(gameEvent.owner, gameEvent.origin)) { if (!validateEnabled(gameEvent.owner, gameEvent.origin)) {
return; return;
@ -560,7 +560,7 @@ const commands = [{
required: true required: true
} }
], ],
supportedGames: ['IW4', 'IW5', 'T5'], supportedGames: ['IW4', 'IW5', 'T5', 'T6'],
execute: (gameEvent) => { execute: (gameEvent) => {
if (!validateEnabled(gameEvent.owner, gameEvent.origin)) { if (!validateEnabled(gameEvent.owner, gameEvent.origin)) {
return; return;
@ -584,7 +584,7 @@ const commands = [{
name: 'player', name: 'player',
required: true required: true
}], }],
supportedGames: ['IW4', 'IW5', 'T5'], supportedGames: ['IW4', 'IW5', 'T5', 'T6'],
execute: (gameEvent) => { execute: (gameEvent) => {
if (!validateEnabled(gameEvent.owner, gameEvent.origin)) { if (!validateEnabled(gameEvent.owner, gameEvent.origin)) {
return; return;
@ -602,7 +602,7 @@ const commands = [{
name: 'player', name: 'player',
required: true required: true
}], }],
supportedGames: ['IW4', 'IW5', 'T5'], supportedGames: ['IW4', 'IW5', 'T5', 'T6'],
execute: (gameEvent) => { execute: (gameEvent) => {
if (!validateEnabled(gameEvent.owner, gameEvent.origin)) { if (!validateEnabled(gameEvent.owner, gameEvent.origin)) {
return; return;