mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-02-15 12:43:50 +00:00
710 lines
No EOL
25 KiB
C#
710 lines
No EOL
25 KiB
C#
//-----------------------------------------------------------------------------
|
|
// Copyright (c) 2012 GarageGames, LLC
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to
|
|
// deal in the Software without restriction, including without limitation the
|
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
// sell copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
// IN THE SOFTWARE.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// DeathmatchGame
|
|
// ----------------------------------------------------------------------------
|
|
// Depends on methods found in gameCore.cs. Those added here are specific to
|
|
// this game type and/or over-ride the "default" game functionaliy.
|
|
//
|
|
// The desired Game Type must be added to each mission's LevelInfo object.
|
|
// - gameType = "Deathmatch";
|
|
// If this information is missing then the GameCore will default to Deathmatch.
|
|
// ----------------------------------------------------------------------------
|
|
function DeathMatchGame::onCreateGame()
|
|
{
|
|
// Note: The Game object will be cleaned up by MissionCleanup. Therefore its lifetime is
|
|
// limited to that of the mission.
|
|
new ScriptObject(DeathMatchGame){};
|
|
|
|
return DeathMatchGame;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// The server has started up so do some game start up
|
|
//-----------------------------------------------------------------------------
|
|
function DeathMatchGame::onMissionStart(%this)
|
|
{
|
|
//set up the game and game variables
|
|
%this.initGameVars();
|
|
|
|
%this.Duration = 30 * 60;
|
|
%this.EndGameScore = 20;
|
|
%this.EndGamePause = 10;
|
|
%this.AllowCycling = false; // Is mission cycling allowed?
|
|
|
|
//echo (%game @"\c4 -> "@ %game.class @" -> GameCore::onStartGame");
|
|
if (%this.Running)
|
|
{
|
|
error("startGame: End the game first!");
|
|
return;
|
|
}
|
|
|
|
// Inform the client we're starting up
|
|
for (%clientIndex = 0; %clientIndex < ClientGroup.getCount(); %clientIndex++)
|
|
{
|
|
%cl = ClientGroup.getObject(%clientIndex);
|
|
commandToClient(%cl, 'GameStart');
|
|
|
|
// Other client specific setup..
|
|
%cl.score = 0;
|
|
%cl.kills = 0;
|
|
%cl.deaths = 0;
|
|
}
|
|
|
|
// Start the game timer
|
|
if (%this.Duration)
|
|
%this.Schedule = schedule(%this.Duration * 1000, "onGameDurationEnd");
|
|
|
|
%this.Running = true;
|
|
}
|
|
|
|
function DeathMatchGame::onMissionEnded(%this)
|
|
{
|
|
if (!%this.Running)
|
|
{
|
|
error("endGame: No game running!");
|
|
return;
|
|
}
|
|
|
|
// Stop any game timers
|
|
cancel(%this.Schedule);
|
|
|
|
for (%clientIndex = 0; %clientIndex < ClientGroup.getCount(); %clientIndex++)
|
|
{
|
|
%cl = ClientGroup.getObject(%clientIndex);
|
|
commandToClient(%cl, 'GameEnd', %this.EndGamePause);
|
|
}
|
|
|
|
%this.Running = false;
|
|
%this.Cycling = false;
|
|
}
|
|
|
|
function DeathMatchGame::onMissionReset(%this)
|
|
{
|
|
// Called by resetMission(), after all the temporary mission objects
|
|
// have been deleted.
|
|
%this.initGameVars();
|
|
|
|
%this.Duration = %this.duration;
|
|
%this.EndGameScore = %this.endgameScore;
|
|
%this.EndGamePause = %this.endgamePause;
|
|
}
|
|
|
|
function DeathMatchGame::initGameVars(%this)
|
|
{
|
|
//-----------------------------------------------------------------------------
|
|
// What kind of "player" is spawned is either controlled directly by the
|
|
// SpawnSphere or it defaults back to the values set here. This also controls
|
|
// which SimGroups to attempt to select the spawn sphere's from by walking down
|
|
// the list of SpawnGroups till it finds a valid spawn object.
|
|
// These override the values set in core/scripts/server/spawn.cs
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Leave %this.defaultPlayerClass and %this.defaultPlayerDataBlock as empty strings ("")
|
|
// to spawn a the %this.defaultCameraClass as the control object.
|
|
%this.defaultPlayerClass = "Player";
|
|
%this.defaultPlayerDataBlock = "DefaultPlayerData";
|
|
%this.defaultPlayerSpawnGroups = "PlayerSpawnPoints PlayerDropPoints";
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// What kind of "camera" is spawned is either controlled directly by the
|
|
// SpawnSphere or it defaults back to the values set here. This also controls
|
|
// which SimGroups to attempt to select the spawn sphere's from by walking down
|
|
// the list of SpawnGroups till it finds a valid spawn object.
|
|
// These override the values set in core/scripts/server/spawn.cs
|
|
//-----------------------------------------------------------------------------
|
|
%this.defaultCameraClass = "Camera";
|
|
%this.defaultCameraDataBlock = "Observer";
|
|
%this.defaultCameraSpawnGroups = "CameraSpawnPoints PlayerSpawnPoints PlayerDropPoints";
|
|
|
|
// Set the gameplay parameters
|
|
%this.Duration = 30 * 60;
|
|
%this.EndGameScore = 20;
|
|
%this.EndGamePause = 10;
|
|
%this.AllowCycling = false; // Is mission cycling allowed?
|
|
}
|
|
|
|
function DeathMatchGame::onGameDurationEnd(%this)
|
|
{
|
|
// This "redirect" is here so that we can abort the game cycle if
|
|
// the %this.Duration variable has been cleared, without having
|
|
// to have a function to cancel the schedule.
|
|
|
|
if (%this.Duration && !(EditorIsActive() && GuiEditorIsActive()))
|
|
%this.onGameDurationEnd();
|
|
}
|
|
|
|
function DeathMatchGame::onClientEnterGame(%this, %client)
|
|
{
|
|
// This function currently relies on some helper functions defined in
|
|
// core/scripts/spawn.cs. For custom spawn behaviors one can either
|
|
// override the properties on the SpawnSphere's or directly override the
|
|
// functions themselves.
|
|
|
|
//echo (%game @"\c4 -> "@ %game.class @" -> GameCore::onClientEntergame");
|
|
|
|
// Sync the client's clocks to the server's
|
|
commandToClient(%client, 'SyncClock', $Sim::Time - %this.StartTime);
|
|
|
|
//Set the player name based on the client's connection data
|
|
%client.setPlayerName(%client.connectData);
|
|
|
|
// Find a spawn point for the camera
|
|
// This function currently relies on some helper functions defined in
|
|
// core/scripts/server/spawn.cs. For custom spawn behaviors one can either
|
|
// override the properties on the SpawnSphere's or directly override the
|
|
// functions themselves.
|
|
%cameraSpawnPoint = pickCameraSpawnPoint(%this.DefaultCameraSpawnGroups);
|
|
// Spawn a camera for this client using the found %spawnPoint
|
|
%client.spawnCamera(%cameraSpawnPoint);
|
|
|
|
// Setup game parameters, the onConnect method currently starts
|
|
// everyone with a 0 score.
|
|
%client.score = 0;
|
|
%client.kills = 0;
|
|
%client.deaths = 0;
|
|
|
|
// weaponHUD
|
|
%client.RefreshWeaponHud(0, "", "");
|
|
|
|
// Prepare the player object.
|
|
%this.preparePlayer(%client);
|
|
|
|
// Inform the client of all the other clients
|
|
%count = ClientGroup.getCount();
|
|
for (%cl = 0; %cl < %count; %cl++)
|
|
{
|
|
%other = ClientGroup.getObject(%cl);
|
|
if ((%other != %client))
|
|
{
|
|
// These should be "silent" versions of these messages...
|
|
messageClient(%client, 'MsgClientJoin', "",
|
|
%other.playerName,
|
|
%other,
|
|
%other.sendGuid,
|
|
%other.team,
|
|
%other.score,
|
|
%other.kills,
|
|
%other.deaths,
|
|
%other.isAIControlled(),
|
|
%other.isAdmin,
|
|
%other.isSuperAdmin);
|
|
}
|
|
}
|
|
|
|
// Inform the client we've joined up
|
|
messageClient(%client,
|
|
'MsgClientJoin', '\c2Welcome to the Torque demo app %1.',
|
|
%client.playerName,
|
|
%client,
|
|
%client.sendGuid,
|
|
%client.team,
|
|
%client.score,
|
|
%client.kills,
|
|
%client.deaths,
|
|
%client.isAiControlled(),
|
|
%client.isAdmin,
|
|
%client.isSuperAdmin);
|
|
|
|
// Inform all the other clients of the new guy
|
|
messageAllExcept(%client, -1, 'MsgClientJoin', '\c1%1 joined the game.',
|
|
%client.playerName,
|
|
%client,
|
|
%client.sendGuid,
|
|
%client.team,
|
|
%client.score,
|
|
%client.kills,
|
|
%client.deaths,
|
|
%client.isAiControlled(),
|
|
%client.isAdmin,
|
|
%client.isSuperAdmin);
|
|
}
|
|
|
|
function DeathMatchGame::onClientLeaveGame(%this, %client)
|
|
{
|
|
// Cleanup the camera
|
|
if (isObject(%client.camera))
|
|
%client.camera.delete();
|
|
|
|
}
|
|
|
|
function DeathMatchGame::onInitialControlSet(%this)
|
|
{
|
|
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
// Functions that implement game-play
|
|
// These are here for backwards compatibilty only, games and/or mods should
|
|
// really be overloading the server and mission functions listed ubove.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Added this stage to creating a player so game types can override it easily.
|
|
// This is a good place to initiate team selection.
|
|
function DeathMatchGame::preparePlayer(%this, %client)
|
|
{
|
|
//echo (%game @"\c4 -> "@ %game.class @" -> GameCore::preparePlayer");
|
|
|
|
// Find a spawn point for the player
|
|
// This function currently relies on some helper functions defined in
|
|
// core/scripts/spawn.cs. For custom spawn behaviors one can either
|
|
// override the properties on the SpawnSphere's or directly override the
|
|
// functions themselves.
|
|
%playerSpawnPoint = pickPlayerSpawnPoint(%this.DefaultPlayerSpawnGroups);
|
|
// Spawn a camera for this client using the found %spawnPoint
|
|
//%client.spawnPlayer(%playerSpawnPoint);
|
|
%this.spawnPlayer(%client, %playerSpawnPoint);
|
|
|
|
// Starting equipment
|
|
%this.loadOut(%client.player);
|
|
}
|
|
|
|
function DeathMatchGame::loadOut(%this, %player)
|
|
{
|
|
//echo (%game @"\c4 -> "@ %game.class @" -> GameCore::loadOut");
|
|
|
|
%player.clearWeaponCycle();
|
|
|
|
%player.setInventory(Ryder, 1);
|
|
%player.setInventory(RyderClip, %player.maxInventory(RyderClip));
|
|
%player.setInventory(RyderAmmo, %player.maxInventory(RyderAmmo)); // Start the gun loaded
|
|
%player.addToWeaponCycle(Ryder);
|
|
|
|
%player.setInventory(Lurker, 1);
|
|
%player.setInventory(LurkerClip, %player.maxInventory(LurkerClip));
|
|
%player.setInventory(LurkerAmmo, %player.maxInventory(LurkerAmmo)); // Start the gun loaded
|
|
%player.addToWeaponCycle(Lurker);
|
|
|
|
%player.setInventory(LurkerGrenadeLauncher, 1);
|
|
%player.setInventory(LurkerGrenadeAmmo, %player.maxInventory(LurkerGrenadeAmmo));
|
|
%player.addToWeaponCycle(LurkerGrenadeLauncher);
|
|
|
|
%player.setInventory(ProxMine, %player.maxInventory(ProxMine));
|
|
%player.addToWeaponCycle(ProxMine);
|
|
|
|
%player.setInventory(DeployableTurret, %player.maxInventory(DeployableTurret));
|
|
%player.addToWeaponCycle(DeployableTurret);
|
|
|
|
if (%player.getDatablock().mainWeapon.image !$= "")
|
|
{
|
|
%player.mountImage(%player.getDatablock().mainWeapon.image, 0);
|
|
}
|
|
else
|
|
{
|
|
%player.mountImage(Ryder, 0);
|
|
}
|
|
}
|
|
|
|
function DeathMatchGame::onDeath(%this, %client, %sourceObject, %sourceClient, %damageType, %damLoc)
|
|
{
|
|
//echo (%game @"\c4 -> "@ %game.class @" -> GameCore::onDeath");
|
|
|
|
// clear the weaponHUD
|
|
%client.RefreshWeaponHud(0, "", "");
|
|
|
|
// Clear out the name on the corpse
|
|
%client.player.setShapeName("");
|
|
|
|
// Switch the client over to the death cam and unhook the player object.
|
|
if (isObject(%client.camera) && isObject(%client.player))
|
|
{
|
|
%client.camera.setMode("Corpse", %client.player);
|
|
%client.setControlObject(%client.camera);
|
|
}
|
|
%client.player = 0;
|
|
|
|
// Display damage appropriate kill message
|
|
%sendMsgFunction = "sendMsgClientKilled_" @ %damageType;
|
|
if ( !isFunction( %sendMsgFunction ) )
|
|
%sendMsgFunction = "sendMsgClientKilled_Default";
|
|
call( %sendMsgFunction, 'MsgClientKilled', %client, %sourceClient, %damLoc );
|
|
|
|
// Dole out points and check for win
|
|
if (( %damageType $= "Suicide" || %sourceClient == %client ) && isObject(%sourceClient))
|
|
{
|
|
%this.incDeaths( %client, 1, true );
|
|
%this.incScore( %client, -1, false );
|
|
}
|
|
else
|
|
{
|
|
%this.incDeaths( %client, 1, false );
|
|
%this.incScore( %sourceClient, 1, true );
|
|
%this.incKills( %sourceClient, 1, false );
|
|
|
|
// If the game may be ended by a client getting a particular score, check that now.
|
|
if ( %this.EndGameScore > 0 && %sourceClient.kills >= %this.EndGameScore )
|
|
%this.cycleGame();
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Spawning
|
|
// ----------------------------------------------------------------------------
|
|
|
|
function DeathMatchGame::spawnPlayer(%this, %client, %spawnPoint, %noControl)
|
|
{
|
|
//echo (%game @"\c4 -> "@ %game.class @" -> GameCore::spawnPlayer");
|
|
|
|
if (isObject(%client.player))
|
|
{
|
|
// The client should not already have a player. Assigning
|
|
// a new one could result in an uncontrolled player object.
|
|
error("Attempting to create a player for a client that already has one!");
|
|
}
|
|
|
|
// Attempt to treat %spawnPoint as an object
|
|
if (getWordCount(%spawnPoint) == 1 && isObject(%spawnPoint))
|
|
{
|
|
// Defaults
|
|
%spawnClass = %this.DefaultPlayerClass;
|
|
%spawnDataBlock = %this.DefaultPlayerDataBlock;
|
|
|
|
// Overrides by the %spawnPoint
|
|
if (isDefined("%spawnPoint.spawnClass"))
|
|
{
|
|
%spawnClass = %spawnPoint.spawnClass;
|
|
%spawnDataBlock = %spawnPoint.spawnDatablock;
|
|
}
|
|
else if (isDefined("%spawnPoint.spawnDatablock"))
|
|
{
|
|
// This may seem redundant given the above but it allows
|
|
// the SpawnSphere to override the datablock without
|
|
// overriding the default player class
|
|
%spawnDataBlock = %spawnPoint.spawnDatablock;
|
|
}
|
|
|
|
%spawnProperties = %spawnPoint.spawnProperties;
|
|
%spawnScript = %spawnPoint.spawnScript;
|
|
|
|
// Spawn with the engine's Sim::spawnObject() function
|
|
%player = spawnObject(%spawnClass, %spawnDatablock, "",
|
|
%spawnProperties, %spawnScript);
|
|
|
|
// If we have an object do some initial setup
|
|
if (isObject(%player))
|
|
{
|
|
// Pick a location within the spawn sphere.
|
|
%spawnLocation = %this.pickPointInSpawnSphere(%player, %spawnPoint);
|
|
%player.setTransform(%spawnLocation);
|
|
}
|
|
else
|
|
{
|
|
// If we weren't able to create the player object then warn the user
|
|
// When the player clicks OK in one of these message boxes, we will fall through
|
|
// to the "if (!isObject(%player))" check below.
|
|
if (isDefined("%spawnDatablock"))
|
|
{
|
|
MessageBoxOK("Spawn Player Failed",
|
|
"Unable to create a player with class " @ %spawnClass @
|
|
" and datablock " @ %spawnDatablock @ ".\n\nStarting as an Observer instead.",
|
|
"");
|
|
}
|
|
else
|
|
{
|
|
MessageBoxOK("Spawn Player Failed",
|
|
"Unable to create a player with class " @ %spawnClass @
|
|
".\n\nStarting as an Observer instead.",
|
|
"");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
// Create a default player
|
|
%player = spawnObject(%this.DefaultPlayerClass, %this.DefaultPlayerDataBlock);
|
|
|
|
if (!%player.isMemberOfClass("Player"))
|
|
warn("Trying to spawn a class that does not derive from Player.");
|
|
|
|
// Treat %spawnPoint as a transform
|
|
%player.setTransform(%spawnPoint);
|
|
}
|
|
|
|
// If we didn't actually create a player object then bail
|
|
if (!isObject(%player))
|
|
{
|
|
// Make sure we at least have a camera
|
|
%client.spawnCamera(%spawnPoint);
|
|
|
|
return;
|
|
}
|
|
|
|
// Update the default camera to start with the player
|
|
if (isObject(%client.camera) && !isDefined("%noControl"))
|
|
{
|
|
if (%player.getClassname() $= "Player")
|
|
%client.camera.setTransform(%player.getEyeTransform());
|
|
else
|
|
%client.camera.setTransform(%player.getTransform());
|
|
}
|
|
|
|
// Add the player object to MissionCleanup so that it
|
|
// won't get saved into the level files and will get
|
|
// cleaned up properly
|
|
MissionCleanup.add(%player);
|
|
|
|
// Store the client object on the player object for
|
|
// future reference
|
|
%player.client = %client;
|
|
|
|
// If the player's client has some owned turrets, make sure we let them
|
|
// know that we're a friend too.
|
|
if (%client.ownedTurrets)
|
|
{
|
|
for (%i=0; %i<%client.ownedTurrets.getCount(); %i++)
|
|
{
|
|
%turret = %client.ownedTurrets.getObject(%i);
|
|
%turret.addToIgnoreList(%player);
|
|
}
|
|
}
|
|
|
|
// Player setup...
|
|
if (%player.isMethod("setShapeName"))
|
|
%player.setShapeName(%client.playerName);
|
|
|
|
if (%player.isMethod("setEnergyLevel"))
|
|
%player.setEnergyLevel(%player.getDataBlock().maxEnergy);
|
|
|
|
if (!isDefined("%client.skin"))
|
|
{
|
|
// Determine which character skins are not already in use
|
|
%availableSkins = %player.getDatablock().availableSkins; // TAB delimited list of skin names
|
|
%count = ClientGroup.getCount();
|
|
for (%cl = 0; %cl < %count; %cl++)
|
|
{
|
|
%other = ClientGroup.getObject(%cl);
|
|
if (%other != %client)
|
|
{
|
|
%availableSkins = strreplace(%availableSkins, %other.skin, "");
|
|
%availableSkins = strreplace(%availableSkins, "\t\t", ""); // remove empty fields
|
|
}
|
|
}
|
|
|
|
// Choose a random, unique skin for this client
|
|
%count = getFieldCount(%availableSkins);
|
|
%client.skin = addTaggedString( getField(%availableSkins, getRandom(%count)) );
|
|
}
|
|
|
|
%player.setSkinName(%client.skin);
|
|
|
|
// Give the client control of the player
|
|
%client.player = %player;
|
|
|
|
// Give the client control of the camera if in the editor
|
|
if( $startWorldEditor )
|
|
{
|
|
%control = %client.camera;
|
|
%control.mode = "Fly";
|
|
EditorGui.syncCameraGui();
|
|
}
|
|
else
|
|
%control = %player;
|
|
|
|
// Allow the player/camera to receive move data from the GameConnection. Without this
|
|
// the user is unable to control the player/camera.
|
|
if (!isDefined("%noControl"))
|
|
%client.setControlObject(%control);
|
|
}
|
|
|
|
function DeathMatchGame::pickPointInSpawnSphere(%this, %objectToSpawn, %spawnSphere)
|
|
{
|
|
%SpawnLocationFound = false;
|
|
%attemptsToSpawn = 0;
|
|
while(!%SpawnLocationFound && (%attemptsToSpawn < 5))
|
|
{
|
|
%sphereLocation = %spawnSphere.getTransform();
|
|
|
|
// Attempt to spawn the player within the bounds of the spawnsphere.
|
|
%angleY = mDegToRad(getRandom(0, 100) * m2Pi());
|
|
%angleXZ = mDegToRad(getRandom(0, 100) * m2Pi());
|
|
|
|
%sphereLocation = setWord( %sphereLocation, 0, getWord(%sphereLocation, 0) + (mCos(%angleY) * mSin(%angleXZ) * getRandom(-%spawnSphere.radius, %spawnSphere.radius)));
|
|
%sphereLocation = setWord( %sphereLocation, 1, getWord(%sphereLocation, 1) + (mCos(%angleXZ) * getRandom(-%spawnSphere.radius, %spawnSphere.radius)));
|
|
|
|
%SpawnLocationFound = true;
|
|
|
|
// Now have to check that another object doesn't already exist at this spot.
|
|
// Use the bounding box of the object to check if where we are about to spawn in is
|
|
// clear.
|
|
%boundingBoxSize = %objectToSpawn.getDatablock().boundingBox;
|
|
%searchRadius = getWord(%boundingBoxSize, 0);
|
|
%boxSizeY = getWord(%boundingBoxSize, 1);
|
|
|
|
// Use the larger dimention as the radius to search
|
|
if (%boxSizeY > %searchRadius)
|
|
%searchRadius = %boxSizeY;
|
|
|
|
// Search a radius about the area we're about to spawn for players.
|
|
initContainerRadiusSearch( %sphereLocation, %searchRadius, $TypeMasks::PlayerObjectType );
|
|
while ( (%objectNearExit = containerSearchNext()) != 0 )
|
|
{
|
|
// If any player is found within this radius, mark that we need to look
|
|
// for another spot.
|
|
%SpawnLocationFound = false;
|
|
break;
|
|
}
|
|
|
|
// If the attempt at finding a clear spawn location failed
|
|
// try no more than 5 times.
|
|
%attemptsToSpawn++;
|
|
}
|
|
|
|
// If we couldn't find a spawn location after 5 tries, spawn the object
|
|
// At the center of the sphere and give a warning.
|
|
if (!%SpawnLocationFound)
|
|
{
|
|
%sphereLocation = %spawnSphere.getTransform();
|
|
warn("WARNING: Could not spawn player after" SPC %attemptsToSpawn
|
|
SPC "tries in spawnsphere" SPC %spawnSphere SPC "without overlapping another player. Attempting spawn in center of sphere.");
|
|
}
|
|
|
|
return %sphereLocation;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Observer
|
|
// ----------------------------------------------------------------------------
|
|
|
|
function DeathMatchGame::spawnObserver(%this, %client)
|
|
{
|
|
//echo (%game @"\c4 -> "@ %game.class @" -> GameCore::spawnObserver");
|
|
|
|
// Position the camera on one of our observer spawn points
|
|
%client.camera.setTransform(%this.pickObserverSpawnPoint());
|
|
|
|
// Set control to the camera
|
|
%client.setControlObject(%client.camera);
|
|
}
|
|
|
|
function DeathMatchGame::pickObserverSpawnPoint(%this)
|
|
{
|
|
//echo (%game @"\c4 -> "@ %game.class @" -> GameCore::pickObserverSpawnPoint");
|
|
|
|
%groupName = "MissionGroup/ObserverSpawnPoints";
|
|
%group = nameToID(%groupName);
|
|
|
|
if (%group != -1)
|
|
{
|
|
%count = %group.getCount();
|
|
if (%count != 0)
|
|
{
|
|
%index = getRandom(%count-1);
|
|
%spawn = %group.getObject(%index);
|
|
return %spawn.getTransform();
|
|
}
|
|
else
|
|
error("No spawn points found in "@ %groupName);
|
|
}
|
|
else
|
|
error("Missing spawn points group "@ %groupName);
|
|
|
|
// Could be no spawn points, in which case we'll stick the
|
|
// player at the center of the world.
|
|
return "0 0 300 1 0 0 0";
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Scoring
|
|
// ----------------------------------------------------------------------------
|
|
function DeathMatchGame::incKills(%this, %client, %kill, %dontMessageAll)
|
|
{
|
|
%client.kills += %kill;
|
|
|
|
if( !%dontMessageAll )
|
|
messageAll('MsgClientScoreChanged', "", %client.score, %client.kills, %client.deaths, %client);
|
|
}
|
|
|
|
function DeathMatchGame::incDeaths(%this, %client, %death, %dontMessageAll)
|
|
{
|
|
%client.deaths += %death;
|
|
|
|
if( !%dontMessageAll )
|
|
messageAll('MsgClientScoreChanged', "", %client.score, %client.kills, %client.deaths, %client);
|
|
}
|
|
|
|
function DeathMatchGame::incScore(%this, %client, %score, %dontMessageAll)
|
|
{
|
|
%client.score += %score;
|
|
|
|
if( !%dontMessageAll )
|
|
messageAll('MsgClientScoreChanged', "", %client.score, %client.kills, %client.deaths, %client);
|
|
}
|
|
|
|
function DeathMatchGame::getScore(%this, %client) { return %client.score; }
|
|
function DeathMatchGame::getKills(%this, %client) { return %client.kills; }
|
|
function DeathMatchGame::getDeaths(%this, %client) { return %client.deaths; }
|
|
|
|
function DeathMatchGame::getTeamScore(%this, %client)
|
|
{
|
|
%score = %client.score;
|
|
if ( %client.team !$= "" )
|
|
{
|
|
// Compute team score
|
|
for (%i = 0; %i < ClientGroup.getCount(); %i++)
|
|
{
|
|
%other = ClientGroup.getObject(%i);
|
|
if ((%other != %client) && (%other.team $= %client.team))
|
|
%score += %other.score;
|
|
}
|
|
}
|
|
return %score;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Messages
|
|
// -----------------------------------------------------------------------------
|
|
// Customized kill message for falling deaths
|
|
function sendMsgClientKilled_Impact( %msgType, %client, %sourceClient, %damLoc )
|
|
{
|
|
messageAll( %msgType, '%1 fell to his death!', %client.playerName );
|
|
}
|
|
|
|
// Customized kill message for suicides
|
|
function sendMsgClientKilled_Suicide( %msgType, %client, %sourceClient, %damLoc )
|
|
{
|
|
messageAll( %msgType, '%1 takes his own life!', %client.playerName );
|
|
}
|
|
|
|
// Default death message
|
|
function sendMsgClientKilled_Default( %msgType, %client, %sourceClient, %damLoc )
|
|
{
|
|
if ( %sourceClient == %client )
|
|
sendMsgClientKilled_Suicide(%client, %sourceClient, %damLoc);
|
|
else if ( %sourceClient.team !$= "" && %sourceClient.team $= %client.team )
|
|
messageAll( %msgType, '%1 killed by %2 - friendly fire!', %client.playerName, %sourceClient.playerName );
|
|
else
|
|
messageAll( %msgType, '%1 gets nailed by %2!', %client.playerName, %sourceClient.playerName );
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// weapon HUD
|
|
// ----------------------------------------------------------------------------
|
|
function GameConnection::setAmmoAmountHud(%client, %amount, %amountInClips )
|
|
{
|
|
commandToClient(%client, 'SetAmmoAmountHud', %amount, %amountInClips);
|
|
}
|
|
|
|
function GameConnection::RefreshWeaponHud(%client, %amount, %preview, %ret, %zoomRet, %amountInClips)
|
|
{
|
|
commandToClient(%client, 'RefreshWeaponHud', %amount, %preview, %ret, %zoomRet, %amountInClips);
|
|
} |