t2-mapper/docs/base/@vl2/TR2final105-server.vl2/scripts/TR2ObserverQueue.cs
2025-09-11 16:56:30 -07:00

640 lines
17 KiB
C#

// updated ObserverQueue
// Create queue container...
if( !isObject("ObserverQueue") )
{
new SimGroup("ObserverQueue");
//ObserverQueue.setPersistent(1); // whats this do..?
}
function validateQueue()
{
if( !$TR2::SpecLock && !$Host::TournamentMode )
{
%active = GetActiveCount();
%count = 12 - %active;
for( %i = 0; %i < %count && ObserverQueue.getCount() > 0; %i++ )
{
%cl = getClientFromQueue();
if( isObject(%cl) )
{
Game.assignClientTeam(%cl, $MatchStarted);
Game.spawnPlayer(%cl, $MatchStarted);
reindexQueue();
}
}
}
}
function getActiveCount()
{
%count = 0;
for( %i = 0; %i < ClientGroup.getCount(); %i++)
{
%cl = ClientGroup.getObject(%i);
if( %cl.team > 0 )
%count++;
}
return %count;
}
function addToQueue(%client)
{
if( %client.team > 0 )
return 0;
if( !isObject(%client) )
return 0;
%unique = 1;
%count = ObserverQueue.getCount();
for( %i = 0; %i < %count; %i++ )
{
%node = ObserverQueue.getObject(%i);
if( %node.id == %client )
{
%unique = 0;
}
}
reindexQueue();
if( %unique == 1 )
{
%node = new ScriptObject()
{
id = %client.getId();
name = %client.nameBase;
};
ObserverQueue.add(%node);
ObserverQueue.pushToBack(%node);
}
%client.allowedToJoinTeam = 1;
reindexQueue();
messageQueue();
return %unique; // 0 = client already added to queue, 1 = client successfully added
}
function removeFromQueue(%client)
{
// if( !isObject(%client) )
// return 0;
// we shouldn't have duplicates in the queue, but why take a chance..
%idx = 0;
%count = ObserverQueue.getCount();
for( %i = 0; %i < %count; %i++ )
{
%node = ObserverQueue.getObject(%i);
if( %node.id == %client.getId() )
{
ObserverQueue.pushToBack(%node);
%node.delete();
break;
}
}
reindexQueue();
messageQueue();
// schedule(100, 0, "reindexQueue");
// schedule(101, 0, "messageQueue");
return %idx; // 0 if client not found to remove
}
function messageQueue()
{
%total = reindexQueue();
%count = ObserverQueue.getCount();
for( %i = 0; %i < %count; %i++ )
{
%cl = ObserverQueue.getObject(%i).id;
if( !%cl.specOnly )
{
if( %cl.queueSlot == 1 )
messageClient(%cl, 'MsgTR2QueuePos', '\c0You are currently \c1NEXT\c0 of \c1%2\c0 in the Observer Queue.~wfx/misc/bounty_objrem2.wav', %cl.queueSlot, %total);
else
messageClient(%cl, 'MsgTR2QueuePos', '\c0You are currently \c1%1\c0 of \c1%2\c0 in the Observer Queue.', %cl.queueSlot, %total);
}
}
}
function messageQueueClient(%client)
{
if( %client.team != 0 )
{
messageClient(%client, 'MsgNotObserver', '\c0You are not currently in observer mode.~wfx/powered/station_denied.wav');
return;
}
if( %client.specOnly )
{
messageClient(%client, 'MsgSpecOnly', '\c0You are currently in individual spectator only mode.~wfx/powered/station_denied.wav');
return;
}
%total = reindexQueue();
%pos = %client.queueSlot;
if( %pos $= "" )
return;
if( %pos == 1 )
messageClient(%client, 'MsgTR2QueuePos', '\c0You are currently \c1NEXT\c0 of \c1%2\c0 in the Observer Queue.!~wfx/misc/bounty_objrem2.wav', %pos, %total);
else
messageClient(%client, 'MsgTR2QueuePos', '\c0You are currently \c1%1\c0 of \c1%2\c0 in the Observer Queue.', %pos, %total);
}
function reindexQueue()
{
// reassigns client 'slots' in the queue
// returns the current number of assigned 'slots'
// only people who are actively in the queue (not spec locked) are counted.
%slot = 0;
//%count = ObserverQueue.getCount();
for( %i = 0; %i < ObserverQueue.getCount(); %i++ )
{
%node = ObserverQueue.getObject(%i);
%client = %node.id;
if( !isObject(%client) )
{
error("Client " @ %client @ " does not exist!! Removing from queue.");
if( isObject(%node) )
{
ObserverQueue.pushToBack(%node);
%node.delete();
}
}
else
{
if( %node.id.team > 0 )
{
ObserverQueue.pushToBack(%node);
%node.delete();
}
else if( !%client.specOnly )
{
%slot++;
%client.queueSlot = %slot;
}
else
{
%client.queueSlot = "";
}
}
}
return %slot;
}
function getClientFromQueue()
{
reindexQueue();
%count = ObserverQueue.getCount();
%client = -1;
for( %i = 0; %i < %count; %i++ )
{
%cl = ObserverQueue.getObject(%i).id;
if( %cl.queueSlot == 1 )
{
%client = %cl;
break;
}
}
return %client;
}
function TR2Game::forceObserver(%game, %client, %reason)
{
//make sure we have a valid client...
if (%client <= 0 || %client.team == 0)
return;
// TR2
// First set to outer role (just to be safe)
%game.assignOuterMostRole(%client);
// Then release client's role
%game.releaseRole(%client);
// Get rid of the corpse after the force
%client.forceRespawn = true;
%client.inSpawnBuilding = true;
// first kill this player
if(%client.player)
%client.player.scriptKill(0);
// TR2: Fix observer timeouts; for some reason %client.player is already 0
// in that case, so scriptKill() won't get called
if (%client.playerToDelete !$= "")
{
%client.enableZones = false;
%client.playerToDelete.delete();
}
if( %client.respawnTimer )
cancel(%client.respawnTimer);
%client.respawnTimer = "";
// remove them from the team rank array
%game.removeFromTeamRankArray(%client);
// place them in observer mode
%client.lastObserverSpawn = -1;
%client.observerStartTime = getSimTime();
%adminForce = 0;
switch$ ( %reason )
{
case "playerChoose":
messageClient(%client, 'MsgClientJoinTeam', '\c2You have become an observer.', %client.name, %game.getTeamName(0), %client, 0 );
echo(%client.nameBase@" (cl "@%client@") entered observer mode");
%client.lastTeam = %client.team;
%client.specOnly = true; // this guy wants to sit out...
case "AdminForce":
messageClient(%client, 'MsgClientJoinTeam', '\c2You have been forced into observer mode by the admin.', %client.name, %game.getTeamName(0), %client, 0 );
echo(%client.nameBase@" (cl "@%client@") was forced into observer mode by admin");
%client.lastTeam = %client.team;
%adminForce = 1;
if($Host::TournamentMode)
{
if(!$matchStarted)
{
if(%client.camera.Mode $= "pickingTeam")
{
commandToClient( %client, 'processPickTeam');
clearBottomPrint( %client );
}
else
{
clearCenterPrint(%client);
%client.notReady = true;
}
}
}
case "spawnTimeout":
messageClient(%client, 'MsgClientJoinTeam', '\c2You have been placed in observer mode due to delay in respawning.', %client.name, %game.getTeamName(0), %client, 0 );
echo(%client.nameBase@" (cl "@%client@") was placed in observer mode due to spawn delay");
// save the team the player was on - only if this was a delay in respawning
%client.lastTeam = %client.team;
%client.specOnly = true; // why force an afk player back into the game?
case "specLockEnabled":
messageClient(%client, 'MsgClientJoinTeam', '\c2Spectator lock is enabled. You were automatically forced to observer.', %client.name, %game.getTeamName(0), %client, 0 );
%client.lastTeam = %client.team;
case "teamsMaxed":
messageClient(%client, 'MsgClientJoinTeam', '\c2Teams are at capacity. You were automatically forced to observer.', %client.name, %game.getTeamName(0), %client, 0 );
%client.lastTeam = %client.team;
case "gameForce":
messageClient(%client, 'MsgClientJoinTeam', '\c2You have become an observer.', %client.name, %game.getTeamName(0), %client, 0 );
%client.lastTeam = %client.team;
}
// switch client to team 0 (observer)
%client.team = 0;
%client.player.team = 0;
setTargetSensorGroup( %client.target, %client.team );
%client.setSensorGroup( %client.team );
// set their control to the obs. cam
%client.setControlObject( %client.camera );
commandToClient(%client, 'setHudMode', 'Observer');
// display the hud
//displayObserverHud(%client, 0);
updateObserverFlyHud(%client);
// message everyone about this event
if( !%adminForce )
messageAllExcept(%client, -1, 'MsgClientJoinTeam', '\c2%1 has become an observer.', %client.name, %game.getTeamName(0), %client, 0 );
else
messageAllExcept(%client, -1, 'MsgClientJoinTeam', '\c2The admin has forced %1 to become an observer.', %client.name, %game.getTeamName(0), %client, 0 );
updateCanListenState( %client );
// call the onEvent for this game type
%game.onClientEnterObserverMode(%client); //Bounty uses this to remove this client from others' hit lists
if( !%client.tr2SpecMode )
{
%client.camera.getDataBlock().setMode( %client.camera, "observerFly" );
}
else
{
if( $TheFlag.carrier.client !$= "" )
%game.observeObject(%client, $TheFlag.carrier.client, 1);
else
%game.observeObject(%client, $TheFlag, 2);
}
// Queuing...
if( %reason !$= "specLockEnabled" && %reason !$= "teamsMaxed" && !$Host::TournamentMode )
{
%vacant = ((6 * 2) - getActiveCount());
%nextCl = getClientFromQueue();
if( isObject(%nextCl) && %vacant > 0 && %nextCl.queueSlot <= %vacant )
{
%game.assignClientTeam(%nextCl, $MatchStarted );
%game.spawnPlayer(%nextCl, $MatchStarted);
}
}
addToQueue(%client);
%client.allowedToJoinTeam = 1;
}
function TR2Game::clientJoinTeam( %game, %client, %team, %fromObs )
{
//%game.assignClientTeam(%client, $MatchStarted);
if( (12 - getActiveCount()) > 0 || $Host::TournamentMode )
{
%client.allowedToJoinTeam = 1;
//first, remove the client from the team rank array
//the player will be added to the new team array as soon as he respawns...
%game.removeFromTeamRankArray(%client);
%pl = %client.player;
if(isObject(%pl))
{
if(%pl.isMounted())
%pl.getDataBlock().doDismount(%pl);
%pl.scriptKill(0);
}
// reset the client's targets and tasks only
clientResetTargets(%client, true);
// give this client a new handle to disassociate ownership of deployed objects
if( %team $= "" && (%team > 0 && %team <= %game.numTeams))
{
if( %client.team == 1 )
%client.team = 2;
else
%client.team = 1;
}
else
%client.team = %team;
// Set the client's skin:
if (!%client.isAIControlled())
setTargetSkin( %client.target, %game.getTeamSkin(%client.team) );
setTargetSensorGroup( %client.target, %client.team );
%client.setSensorGroup( %client.team );
// Spawn the player:
%game.spawnPlayer(%client, $MatchStarted);
if(%fromObs $= "" || !%fromObs)
{
messageAllExcept( %client, -1, 'MsgClientJoinTeam', '\c1%1 switched to team %2.', %client.name, %game.getTeamName(%client.team), %client, %client.team );
messageClient( %client, 'MsgClientJoinTeam', '\c1You switched to team %2.', $client.name, %game.getTeamName(%client.team), %client, %client.team );
}
else
{
messageAllExcept( %client, -1, 'MsgClientJoinTeam', '\c1%1 joined team %2.', %client.name, %game.getTeamName(%client.team), %client, %team );
messageClient( %client, 'MsgClientJoinTeam', '\c1You joined team %2.', $client.name, %game.getTeamName(%client.team), %client, %client.team );
}
updateCanListenState( %client );
// MES - switch objective hud lines when client switches teams
messageClient(%client, 'MsgCheckTeamLines', "", %client.team);
logEcho(%client.nameBase@" (cl "@%client@") switched to team "@%client.team);
removeFromQueue(%client);
}
else
{
//error("Forced to observer: " @%client.nameBase @ " via JoinTeam");
%game.forceObserver(%client, "gameForce");
}
}
// if( %client.allowedToJoinTeam == 1 )
// {
// DefaultGame::clientJoinTeam( %game, %client, %team, %respawn );
// removeFromQueue(%client);
// }
// else
// {
// %game.forceObserver(%client, "gameForce");
// }
function TR2Game::assignClientTeam(%game, %client, %respawn )
{
if( %client.team > 0 )
return;
%size[0] = 0;
%size[1] = 0;
%size[2] = 0;
%leastTeam = 0;
for( %i = 0; %i < ClientGroup.getCount(); %i++ )
{
%cl = ClientGroup.getObject(%i);
if( %cl != %client )
%size[%cl.team]++;
}
%playing = %size[1] + %size[2];
if( %playing < (6 << 1) ) // HEH HEH
{
%game.removeFromTeamRankArray(%client);
%leastTeam = (%size[1] <= %size[2]) ? 1 : 2;
removeFromQueue(%client);
%client.lastTeam = %client.team;
%client.team = %leastTeam;
// Assign the team skin:
if ( %client.isAIControlled() )
{
if ( %leastTeam & 1 )
{
%client.skin = addTaggedString( "basebot" );
setTargetSkin( %client.target, 'basebot' );
}
else
{
%client.skin = addTaggedString( "basebbot" );
setTargetSkin( %client.target, 'basebbot' );
}
}
else
setTargetSkin( %client.target, %game.getTeamSkin(%client.team) );
messageAllExcept( %client, -1, 'MsgClientJoinTeam', '\c1%1 joined %2.', %client.name, %game.getTeamName(%client.team), %client, %client.team );
messageClient( %client, 'MsgClientJoinTeam', '\c1You joined the %2 team.', %client.name, %game.getTeamName(%client.team), %client, %client.team );
updateCanListenState( %client );
clearBottomPrint(%client); // clear out the observer hud...
echo(%client.nameBase@" (cl "@%client@") joined team "@%client.team);
//error("Assigned: " @%client.nameBase @ " to team: " @ %team @ " via AssignTeam");
}
else
{
//error("Forced to observer: " @%client.nameBase @ " via AssignTeam");
%game.forceObserver(%client, "teamsMaxed");
}
// hes been checked for team join ability..
%client.allowedToJoinTeam = 1;
}
function TR2Game::ObserverOnTrigger(%game, %data, %obj, %trigger, %state)
{
//trigger types: 0:fire 1:altTrigger 2:jump 3:jet 4:throw
if (!$missionRunning)
{
return false;
}
%client = %obj.getControllingClient();
if (!isObject(%client))
{
return false;
}
// Knockdowns
// Moved up since players in the game should have a little priority over observers
// save a little execution time and effort :
if (%obj.mode $= "playerDeath")
{
if(!%client.waitRespawn && getSimTime() > %client.suicideRespawnTime)
{
commandToClient(%client, 'setHudMode', 'Standard');
if (%client.playerToDelete !$= "")
{
%client.enableZones = false;
%client.playerToDelete.delete();
}
// Use current flymode rotation
%transform = %client.camera.getTransform();
%oldTrans = %client.plyrTransformAtDeath;
%oldPos = getWord(%oldTrans, 0) SPC getWord(%oldTrans, 1) SPC getWord(%oldTrans, 2);
%newRot = getWord(%transform, 3) SPC getWord(%transform, 4) SPC getWord(%transform, 5) SPC getWord(%transform, 6);
%client.plyrTransformAtDeath = %oldPos SPC %newRot;
Game.spawnPlayer( %client, true );
%client.camera.setFlyMode();
%client.setControlObject(%client.player);
}
return false;
}
// Observer zoom
if( %obj.mode $= "followFlag" || %obj.mode $= "observerFollow" )
{
if( %trigger == 3 )
{
%client.obsZoomLevel++;
if (%client.obsZoomLevel >= $TR2::numObsZoomLevels)
%client.obsZoomLevel = 0;
// Move the camera
%game.observeObject(%client, %client.observeTarget, %client.observeType);
//%pos = %client.camera.getPosition();
//%rot = %client.camera
return false;
}
else
return false;
}
if( %obj.mode $= "observerFly" )
{
// unfortunately, it seems that sometimes the "observer speed up" thing doesn't always happen...
if (%trigger == 0)
{
clearBottomPrint(%client);
return false;
}
//press JET
else if (%trigger == 3)
{
%markerObj = Game.pickObserverSpawn(%client, true);
%transform = %markerObj.getTransform();
%obj.setTransform(%transform);
%obj.setFlyMode();
clearBottomPrint(%client);
return false;
}
//press JUMP
else if (%trigger == 2)
{
clearBottomPrint(%client);
return false;
}
}
if( %obj.mode $= "pre-game" )
{
return true; // use default action
}
if( %obj.mode $= "justJoined" )
{
if( !$TR2::SpecLock && !$Host::TournamentMode )
{
if( %client.team <= 0 )
{
if( getActiveCount() < ($TR2::DefaultTeamSize * 2) )
{
%game.assignClientTeam(%client, 0);
%game.spawnPlayer(%client, 0);
}
else
{
%game.forceObserver(%client, "teamsMaxed");
}
}
else if( %client.team >= 1 )
{
%game.spawnPlayer(%client, 0);
}
if( isObject(%client.player) ) // player was successfully created...
{
if(!$MatchStarted && !$CountdownStarted)
%client.camera.getDataBlock().setMode( %client.camera, "pre-game", %client.player );
else if(!$MatchStarted && $CountdownStarted)
%client.camera.getDataBlock().setMode( %client.camera, "pre-game", %client.player );
else
{
%client.camera.setFlyMode();
commandToClient(%client, 'setHudMode', 'Standard');
%client.setControlObject( %client.player );
}
}
}
else
{
// kind of weak, but tourney mode *is* a form of spec lock :/
%game.forceObserver(%client, "specLockEnabled");
}
return false;
}
// Queue
if( %trigger == 0 )
{
if( %obj.mode !$= "playerDeath" )
{
return false;
}
}
return true;
}