$Camera::movementSpeed = 40; datablock CameraData(Observer) { mode = "observerStatic"; firstPersonOnly = true; }; datablock CameraData(CommanderCamera) { mode = "observerStatic"; firstPersonOnly = true; }; function CommanderCamera::onTrigger( %data, %obj, %trigger, %state ) { // no need to do anything here. } function Observer::onTrigger(%data,%obj,%trigger,%state) { // state = 0 means that a trigger key was released if (%state == 0) return; //first, give the game the opportunity to prevent the observer action if (!Game.ObserverOnTrigger(%data, %obj, %trigger, %state)) return; //now observer functions if you press the "throw" if (%trigger >= 4) return; //trigger types: 0:fire 1:altTrigger 2:jump 3:jet 4:throw %client = %obj.getControllingClient(); if (%client == 0) return; switch$ (%obj.mode) { case "justJoined": if ( isDemoServer() ) clearCenterPrint( %client ); //press FIRE if (%trigger == 0) { // clear intro message clearBottomPrint( %client ); //spawn the player commandToClient(%client, 'setHudMode', 'Standard'); Game.assignClientTeam(%client); Game.spawnPlayer( %client, $MatchStarted ); if( $MatchStarted ) { %client.camera.setFlyMode(); %client.setControlObject( %client.player ); } else { %client.camera.getDataBlock().setMode( %client.camera, "pre-game", %client.player ); %client.setControlObject( %client.camera ); } } //press JET else if (%trigger == 3) { //cycle throw the static observer spawn points %markerObj = Game.pickObserverSpawn(%client, true); %transform = %markerObj.getTransform(); %obj.setTransform(%transform); %obj.setFlyMode(); } //press JUMP else if (%trigger == 2) { //switch the observer mode to observing clients if (isObject(%client.observeFlyClient)) serverCmdObserveClient(%client, %client.observeFlyClient); else serverCmdObserveClient(%client, -1); displayObserverHud(%client, %client.observeClient); messageClient(%client.observeClient, 'Observer', '\c1%1 is now observing you.', %client.name); } case "playerDeath": // Attached to a dead player - spawn regardless of trigger type if(!%client.waitRespawn && getSimTime() > %client.suicideRespawnTime) { commandToClient(%client, 'setHudMode', 'Standard'); Game.spawnPlayer( %client, true ); %client.camera.setFlyMode(); %client.setControlObject(%client.player); } case "PreviewMode": if (%trigger == 0) { commandToClient(%client, 'setHudMode', 'Standard'); if( %client.lastTeam ) Game.clientJoinTeam( %client, %client.lastTeam ); else { Game.assignClientTeam( %client, true ); // Spawn the player: Game.spawnPlayer( %client, false ); } %client.camera.setFlyMode(); %client.setControlObject( %client.player ); } case "toggleCameraFly": // this is the default camera mode case "observerFly": // Free-flying observer camera if (%trigger == 0) { if( !$Host::TournamentMode && $MatchStarted ) { // reset observer params clearBottomPrint(%client); commandToClient(%client, 'setHudMode', 'Standard'); if( %client.lastTeam !$= "" && %client.lastTeam != 0 && Game.numTeams > 1) { Game.clientJoinTeam( %client, %client.lastTeam, $MatchStarted ); %client.camera.setFlyMode(); %client.setControlObject( %client.player ); } else { Game.assignClientTeam( %client ); // Spawn the player: Game.spawnPlayer( %client, true ); %client.camera.setFlyMode(); %client.setControlObject( %client.player ); ClearBottomPrint( %client ); } } else if( !$Host::TournamentMode ) { clearBottomPrint(%client); Game.assignClientTeam( %client ); // Spawn the player: Game.spawnPlayer( %client, false ); %client.camera.getDataBlock().setMode( %client.camera, "pre-game", %client.player ); %client.setControlObject( %client.camera ); } } //press JET else if (%trigger == 3) { %markerObj = Game.pickObserverSpawn(%client, true); %transform = %markerObj.getTransform(); %obj.setTransform(%transform); %obj.setFlyMode(); } //press JUMP else if (%trigger == 2) { //switch the observer mode to observing clients if (isObject(%client.observeFlyClient)) serverCmdObserveClient(%client, %client.observeFlyClient); else serverCmdObserveClient(%client, -1); observerFollowUpdate( %client, %client.observeClient, false ); displayObserverHud(%client, %client.observeClient); messageClient(%client.observeClient, 'Observer', '\c1%1 is now observing you.', %client.name); } case "observerStatic": // Non-moving observer camera %next = (%trigger == 3 ? true : false); %markerObj = Game.pickObserverSpawn(%client, %next); %transform = %markerObj.getTransform(); %obj.setTransform(%transform); %obj.setFlyMode(); case "observerTimeout": // Player didn't respawn quickly enough if (%trigger == 0) { clearBottomPrint(%client); commandToClient(%client, 'setHudMode', 'Standard'); if( %client.lastTeam ) Game.clientJoinTeam( %client, %client.lastTeam, true ); else { Game.assignClientTeam( %client ); // Spawn the player: Game.spawnPlayer( %client, true ); } %client.camera.setFlyMode(); %client.setControlObject( %client.player ); } //press JET else if (%trigger == 3) { %markerObj = Game.pickObserverSpawn(%client, true); %transform = %markerObj.getTransform(); %obj.setTransform(%transform); %obj.setFlyMode(); } //press JUMP else if (%trigger == 2) { //switch the observer mode to observing clients if (isObject(%client.observeFlyClient)) serverCmdObserveClient(%client, %client.observeFlyClient); else serverCmdObserveClient(%client, -1); // update the observer list for this client observerFollowUpdate( %client, %client.observeClient, false ); displayObserverHud(%client, %client.observeClient); messageClient(%client.observeClient, 'Observer', '\c1%1 is now observing you.', %client.name); } case "observerFollow": // Observer attached to a moving object (assume player for now...) //press FIRE - cycle to next client if (%trigger == 0) { %nextClient = findNextObserveClient(%client); %prevObsClient = %client.observeClient; if (%nextClient > 0 && %nextClient != %client.observeClient) { // update the observer list for this client observerFollowUpdate( %client, %nextClient, true ); //set the new object %transform = %nextClient.player.getTransform(); if( !%nextClient.isMounted() ) { %obj.setOrbitMode(%nextClient.player, %transform, 0.5, 4.5, 4.5); %client.observeClient = %nextClient; } else { %mount = %nextClient.player.getObjectMount(); if( %mount.getDataBlock().observeParameters $= "" ) %params = %transform; else %params = %mount.getDataBlock().observeParameters; %obj.setOrbitMode(%mount, %mount.getTransform(), getWord( %params, 0 ), getWord( %params, 1 ), getWord( %params, 2 )); %client.observeClient = %nextClient; } //send the message(s) displayObserverHud(%client, %nextClient); messageClient(%nextClient, 'Observer', '\c1%1 is now observing you.', %client.name); messageClient(%prevObsClient, 'ObserverEnd', '\c1%1 is no longer observing you.', %client.name); } } //press JET - cycle to prev client else if (%trigger == 3) { %prevClient = findPrevObserveClient(%client); %prevObsClient = %client.observeClient; if (%prevClient > 0 && %prevClient != %client.observeClient) { // update the observer list for this client observerFollowUpdate( %client, %prevClient, true ); //set the new object %transform = %prevClient.player.getTransform(); if( !%prevClient.isMounted() ) { %obj.setOrbitMode(%prevClient.player, %transform, 0.5, 4.5, 4.5); %client.observeClient = %prevClient; } else { %mount = %prevClient.player.getObjectMount(); if( %mount.getDataBlock().observeParameters $= "" ) %params = %transform; else %params = %mount.getDataBlock().observeParameters; %obj.setOrbitMode(%mount, %mount.getTransform(), getWord( %params, 0 ), getWord( %params, 1 ), getWord( %params, 2 )); %client.observeClient = %prevClient; } //send the message(s) displayObserverHud(%client, %prevClient); messageClient(%prevClient, 'Observer', '\c1%1 is now observing you.', %client.name); messageClient(%prevObsClient, 'ObserverEnd', '\c1%1 is no longer observing you.', %client.name); } } //press JUMP else if (%trigger == 2) { // update the observer list for this client observerFollowUpdate( %client, -1, false ); //toggle back to observer fly mode %obj.mode = "observerFly"; %obj.setFlyMode(); updateObserverFlyHud(%client); messageClient(%client.observeClient, 'ObserverEnd', '\c1%1 is no longer observing you.', %client.name); } case "pre-game": if(!$Host::TournamentMode || $CountdownStarted) return; if(%client.notReady) { %client.notReady = ""; MessageAll( 0, '\c1%1 is READY.', %client.name ); if(%client.notReadyCount < 3) centerprint( %client, "\nWaiting for match start (FIRE if not ready)", 0, 3); else centerprint( %client, "\nWaiting for match start", 0, 3); } else { %client.notReadyCount++; if(%client.notReadyCount < 4) { %client.notReady = true; MessageAll( 0, '\c1%1 is not READY.', %client.name ); centerprint( %client, "\nPress FIRE when ready.", 0, 3 ); } return; } CheckTourneyMatchStart(); } } function Observer::setMode(%data, %obj, %mode, %targetObj) { if(%mode $= "") return; %client = %obj.getControllingClient(); switch$ (%mode) { case "justJoined": commandToClient(%client, 'setHudMode', 'Observer'); %markerObj = Game.pickObserverSpawn(%client, true); %transform = %markerObj.getTransform(); %obj.setTransform(%transform); %obj.setFlyMode(); case "pre-game": commandToClient(%client, 'setHudMode', 'Observer'); %obj.setOrbitMode( %targetObj, %targetObj.getTransform(), 0.5, 4.5, 4.5); case "observerFly": // Free-flying observer camera commandToClient(%client, 'setHudMode', 'Observer'); %markerObj = Game.pickObserverSpawn(%client, true); %transform = %markerObj.getTransform(); %obj.setTransform(%transform); %obj.setFlyMode(); case "observerStatic": // Non-moving observer camera %markerObj = Game.pickObserverSpawn(%client, true); %transform = %markerObj.getTransform(); %obj.setTransform(%transform); case "observerFollow": // Observer attached to a moving object (assume player for now...) %transform = %targetObj.getTransform(); if( !%targetObj.isMounted() ) %obj.setOrbitMode(%targetObj, %transform, 0.5, 4.5, 4.5); else { %mount = %targetObj.getObjectMount(); if( %mount.getDataBlock().observeParameters $= "" ) %params = %transform; else %params = %mount.getDataBlock().observeParameters; %obj.setOrbitMode(%mount, %mount.getTransform(), getWord( %params, 0 ), getWord( %params, 1 ), getWord( %params, 2 )); } case "observerTimeout": commandToClient(%client, 'setHudMode', 'Observer'); %markerObj = Game.pickObserverSpawn(%client, true); %transform = %markerObj.getTransform(); %obj.setTransform(%transform); %obj.setFlyMode(); } %obj.mode = %mode; } function findNextObserveClient(%client) { %index = -1; %count = ClientGroup.getCount(); if (%count <= 1) return -1; for (%i = 0; %i < %count; %i++) { %cl = ClientGroup.getObject(%i); if (%cl == %client.observeClient) { %index = %i; break; } } //now find the next client (note, if not found, %index still == -1) %index++; if (%index >= %count) %index = 0; %newClient = -1; for (%i = %index; %i < %count; %i++) { %cl = ClientGroup.getObject(%i); if (%cl != %client && %cl.player > 0) { %newClient = %cl; break; } } //if we didn't find anyone, search from the beginning again if (%newClient < 0) { for (%i = 0; %i < %count; %i++) { %cl = ClientGroup.getObject(%i); if (%cl != %client && %cl.player > 0) { %newClient = %cl; break; } } } //if we still haven't found anyone (new), give up.. if (%newClient < 0 || %newClient.player == %player) return -1; } function findPrevObserveClient(%client) { %index = -1; %count = ClientGroup.getCount(); if (%count <= 1) return -1; for (%i = 0; %i < %count; %i++) { %cl = ClientGroup.getObject(%i); if (%cl == %client.observeClient) { %index = %i; break; } } //now find the prev client %index--; if (%index < 0) %index = %count - 1; %newClient = -1; for (%i = %index; %i >= 0; %i--) { %cl = ClientGroup.getObject(%i); if (%cl != %client && %cl.player > 0) { %newClient = %cl; break; } } //if we didn't find anyone, search from the end again if (%newClient < 0) { for (%i = %count - 1; %i >= 0; %i--) { %cl = ClientGroup.getObject(%i); if (%cl != %client && %cl.player > 0) { %newClient = %cl; break; } } } //if we still haven't found anyone (new), give up.. if (%newClient < 0 || %newClient.player == %player) return -1; } function observeClient(%client) { if( $testcheats ) { //pass in -1 to choose any client... commandToServer('observeClient', %client); } } function serverCmdObserveClient(%client, %target) { //clear the observer fly mode var... %client.observeFlyClient = -1; //cancel any scheduled update cancel(%client.obsHudSchedule); // must be an observer when observing other clients if( %client.getControlObject() != %client.camera) return; //can't observer yourself if (%client == %target) return; %count = ClientGroup.getCount(); //can't go into observer mode if you're the only client if (%count <= 1) return; //make sure the target actually exists if (%target > 0) { %found = false; for (%i = 0; %i < %count; %i++) { %cl = ClientGroup.getObject(%i); if (%cl == %target) { %found = true; break; } } if (!%found) return; } else { %client.observeClient = -1; %target = findNextObserveClient(%client); if (%target <= 0) return; } //send the message if (%client.camera.mode !$= "observerFollow") { if (isObject(%client.player)) %client.player.scriptKill(0); //messageAllExcept(%client, -1, 'ClientNowObserver', '\c1%1 is now an observer.', %client.name); //messageClient(%client, 'YouNowObserver', '\c1You are now observing %1.', %target.name); } %client.camera.getDataBlock().setMode(%client.camera, "observerFollow", %target.player); %client.setControlObject(%client.camera); //tag is used if a client who is being observed dies... %client.observeClient = %target; } function observerFollowUpdate( %client, %nextClient, %cycle ) { %Oclient = %client.observeClient; if( %Oclient $= "" ) return; // changed to observer fly... if( %nextClient == -1 ) { // find us in their observer list and remove, then reshuffle the list... for( %i = 0; %i < %Oclient.observeCount; %i++ ) { if( %Oclient.observers[%i] == %client ) { %Oclient.observeCount--; %Oclient.observers[%i] = %Oclient.observers[%Oclient.observeCount]; %Oclient.observers[%Oclient.observeCount] = ""; break; } } return; // were done.. } // changed from observer fly to observer follow... if( !%cycle && %nextClient != -1 ) { // if nobody is observing this guy, initialize their observer count... if( %nextClient.observeCount $= "" ) %nextClient.observeCount = 0; // add us to their list of observers... %nextClient.observers[%nextClient.observeCount] = %client; %nextClient.observeCount++; return; // were done. } if( %nextClient != -1 ) { // cycling to the next client... for( %i = 0; %i < %Oclient.observeCount; %i++ ) { // first remove us from our prev client's list... if( %Oclient.observers[%i] == %client ) { %Oclient.observeCount--; %Oclient.observers[%i] = %Oclient.observers[%Oclient.observeCount]; %Oclient.observers[%Oclient.observeCount] = ""; break; // screw you guys, i'm goin home! } } // if nobody is observing this guy, initialize their observer count... if( %nextClient.observeCount $= "" ) %nextClient.observeCount = 0; // now add us to the new clients list... %nextClient.observeCount++; %nextClient.observers[%nextClient.observeCount - 1] = %client; } } function updateObserverFlyHud(%client) { //just in case there are two threads going... cancel(%client.obsHudSchedule); %client.observeFlyClient = -1; //make sure the client is supposed to be in observer fly mode... if (!isObject(%client) || %client.team != 0 || %client.getControlObject() != %client.camera || %client.camera.mode $= "observerFollow") return; //get various info about the player's eye %srcEyeTransform = %client.camera.getTransform(); %srcEyePoint = firstWord(%srcEyeTransform) @ " " @ getWord(%srcEyeTransform, 1) @ " " @ getWord(%srcEyeTransform, 2); %srcEyeVector = MatrixMulVector("0 0 0 " @ getWords(%srcEyeTransform, 3, 6), "0 1 0"); %srcEyeVector = VectorNormalize(%srcEyeVector); //see if there's an enemy near our defense location... %clientCount = 0; %count = ClientGroup.getCount(); %viewedClient = -1; %clientDot = -1; for(%i = 0; %i < %count; %i++) { %cl = ClientGroup.getObject(%i); //make sure we find an AI who's alive and not the client if (%cl != %client && isObject(%cl.player)) { //make sure the player is within range %clPos = %cl.player.getWorldBoxCenter(); %distance = VectorDist(%clPos, %srcEyePoint); if (%distance <= 30) { //create the vector from the client to the client %clVector = VectorNormalize(VectorSub(%clPos, %srcEyePoint)); //see if the dot product is greater than our current, and greater than 0.6 %dot = VectorDot(%clVector, %srcEyeVector); if (%dot > 0.6 && %dot > %clientDot) { //make sure we're not looking through walls... %mask = $TypeMasks::TerrainObjectType | $TypeMasks::InteriorObjectType | $TypeMasks::StaticShapeObjectType; %losResult = containerRayCast(%srcEyePoint, %clPos, %mask); %losObject = GetWord(%losResult, 0); if (!isObject(%losObject)) { %viewedClient = %cl; %clientDot = %dot; } } } } } if (isObject(%viewedClient)) displayObserverHud(%client, 0, %viewedClient); else displayObserverHud(%client, 0); %client.observeFlyClient = %viewedClient; //schedule the next... %client.obsHudSchedule = schedule(500, %client, updateObserverFlyHud, %client); }