deathMatchGame.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. // ----------------------------------------------------------------------------
  23. // DeathmatchGame
  24. // ----------------------------------------------------------------------------
  25. // Depends on methods found in gameCore.cs. Those added here are specific to
  26. // this game type and/or over-ride the "default" game functionaliy.
  27. //
  28. // The desired Game Type must be added to each mission's LevelInfo object.
  29. // - gameType = "Deathmatch";
  30. // If this information is missing then the GameCore will default to Deathmatch.
  31. // ----------------------------------------------------------------------------
  32. function DeathMatchGame::initGameVars(%game)
  33. {
  34. //echo (%game @"\c4 -> "@ %game.class @" -> DeathMatchGame::initGameVars");
  35. //-----------------------------------------------------------------------------
  36. // What kind of "player" is spawned is either controlled directly by the
  37. // SpawnSphere or it defaults back to the values set here. This also controls
  38. // which SimGroups to attempt to select the spawn sphere's from by walking down
  39. // the list of SpawnGroups till it finds a valid spawn object.
  40. // These override the values set in core/scripts/server/spawn.cs
  41. //-----------------------------------------------------------------------------
  42. // Leave $Game::defaultPlayerClass and $Game::defaultPlayerDataBlock as empty strings ("")
  43. // to spawn a the $Game::defaultCameraClass as the control object.
  44. $Game::defaultPlayerClass = "Player";
  45. $Game::defaultPlayerDataBlock = "DefaultPlayerData";
  46. $Game::defaultPlayerSpawnGroups = "PlayerSpawnPoints PlayerDropPoints";
  47. //-----------------------------------------------------------------------------
  48. // What kind of "camera" is spawned is either controlled directly by the
  49. // SpawnSphere or it defaults back to the values set here. This also controls
  50. // which SimGroups to attempt to select the spawn sphere's from by walking down
  51. // the list of SpawnGroups till it finds a valid spawn object.
  52. // These override the values set in core/scripts/server/spawn.cs
  53. //-----------------------------------------------------------------------------
  54. $Game::defaultCameraClass = "Camera";
  55. $Game::defaultCameraDataBlock = "Observer";
  56. $Game::defaultCameraSpawnGroups = "CameraSpawnPoints PlayerSpawnPoints PlayerDropPoints";
  57. // Set the gameplay parameters
  58. %game.duration = 30 * 60;
  59. %game.endgameScore = 20;
  60. %game.endgamePause = 10;
  61. %game.allowCycling = false; // Is mission cycling allowed?
  62. }
  63. function DeathMatchGame::onGameDurationEnd(%game)
  64. {
  65. // This "redirect" is here so that we can abort the game cycle if
  66. // the $Game::Duration variable has been cleared, without having
  67. // to have a function to cancel the schedule.
  68. if ($Game::Duration && !(EditorIsActive() && GuiEditorIsActive()))
  69. Game.onGameDurationEnd();
  70. }
  71. function DeathMatchGame::onClientEnterGame(%this, %client)
  72. {
  73. // This function currently relies on some helper functions defined in
  74. // core/scripts/spawn.cs. For custom spawn behaviors one can either
  75. // override the properties on the SpawnSphere's or directly override the
  76. // functions themselves.
  77. //echo (%game @"\c4 -> "@ %game.class @" -> GameCore::onClientEntergame");
  78. // Sync the client's clocks to the server's
  79. commandToClient(%client, 'SyncClock', $Sim::Time - $Game::StartTime);
  80. //Set the player name based on the client's connection data
  81. %client.setPlayerName(%client.connectData);
  82. // Find a spawn point for the camera
  83. // This function currently relies on some helper functions defined in
  84. // core/scripts/server/spawn.cs. For custom spawn behaviors one can either
  85. // override the properties on the SpawnSphere's or directly override the
  86. // functions themselves.
  87. %cameraSpawnPoint = pickCameraSpawnPoint($Game::DefaultCameraSpawnGroups);
  88. // Spawn a camera for this client using the found %spawnPoint
  89. %client.spawnCamera(%cameraSpawnPoint);
  90. // Setup game parameters, the onConnect method currently starts
  91. // everyone with a 0 score.
  92. %client.score = 0;
  93. %client.kills = 0;
  94. %client.deaths = 0;
  95. // weaponHUD
  96. %client.RefreshWeaponHud(0, "", "");
  97. // Prepare the player object.
  98. %this.preparePlayer(%client);
  99. // Inform the client of all the other clients
  100. %count = ClientGroup.getCount();
  101. for (%cl = 0; %cl < %count; %cl++)
  102. {
  103. %other = ClientGroup.getObject(%cl);
  104. if ((%other != %client))
  105. {
  106. // These should be "silent" versions of these messages...
  107. messageClient(%client, 'MsgClientJoin', "",
  108. %other.playerName,
  109. %other,
  110. %other.sendGuid,
  111. %other.team,
  112. %other.score,
  113. %other.kills,
  114. %other.deaths,
  115. %other.isAIControlled(),
  116. %other.isAdmin,
  117. %other.isSuperAdmin);
  118. }
  119. }
  120. // Inform the client we've joined up
  121. messageClient(%client,
  122. 'MsgClientJoin', '\c2Welcome to the Torque demo app %1.',
  123. %client.playerName,
  124. %client,
  125. %client.sendGuid,
  126. %client.team,
  127. %client.score,
  128. %client.kills,
  129. %client.deaths,
  130. %client.isAiControlled(),
  131. %client.isAdmin,
  132. %client.isSuperAdmin);
  133. // Inform all the other clients of the new guy
  134. messageAllExcept(%client, -1, 'MsgClientJoin', '\c1%1 joined the game.',
  135. %client.playerName,
  136. %client,
  137. %client.sendGuid,
  138. %client.team,
  139. %client.score,
  140. %client.kills,
  141. %client.deaths,
  142. %client.isAiControlled(),
  143. %client.isAdmin,
  144. %client.isSuperAdmin);
  145. }
  146. function DeathMatchGame::onClientLeaveGame(%this, %client)
  147. {
  148. // Cleanup the camera
  149. if (isObject(%this.camera))
  150. %this.camera.delete();
  151. }
  152. //-----------------------------------------------------------------------------
  153. // The server has started up so do some game start up
  154. //-----------------------------------------------------------------------------
  155. function DeathMatchGame::onMissionStart(%this)
  156. {
  157. //set up the game and game variables
  158. %this.initGameVars();
  159. $Game::Duration = %this.duration;
  160. $Game::EndGameScore = %this.endgameScore;
  161. $Game::EndGamePause = %this.endgamePause;
  162. //echo (%game @"\c4 -> "@ %game.class @" -> GameCore::onStartGame");
  163. if ($Game::Running)
  164. {
  165. error("startGame: End the game first!");
  166. return;
  167. }
  168. // Inform the client we're starting up
  169. for (%clientIndex = 0; %clientIndex < ClientGroup.getCount(); %clientIndex++)
  170. {
  171. %cl = ClientGroup.getObject(%clientIndex);
  172. commandToClient(%cl, 'GameStart');
  173. // Other client specific setup..
  174. %cl.score = 0;
  175. %cl.kills = 0;
  176. %cl.deaths = 0;
  177. }
  178. // Start the game timer
  179. if ($Game::Duration)
  180. $Game::Schedule = %this.schedule($Game::Duration * 1000, "onGameDurationEnd");
  181. $Game::Running = true;
  182. $Game = %this;
  183. }
  184. function DeathMatchGame::onMissionEnded(%this)
  185. {
  186. if (!$Game::Running)
  187. {
  188. error("endGame: No game running!");
  189. return;
  190. }
  191. // Stop any game timers
  192. cancel($Game::Schedule);
  193. for (%clientIndex = 0; %clientIndex < ClientGroup.getCount(); %clientIndex++)
  194. {
  195. %cl = ClientGroup.getObject(%clientIndex);
  196. commandToClient(%cl, 'GameEnd', $Game::EndGamePause);
  197. }
  198. $Game::Running = false;
  199. $Game::Cycling = false;
  200. $Game = "";
  201. }
  202. function DeathMatchGame::onMissionReset(%this)
  203. {
  204. // Called by resetMission(), after all the temporary mission objects
  205. // have been deleted.
  206. %this.initGameVars();
  207. $Game::Duration = %this.duration;
  208. $Game::EndGameScore = %this.endgameScore;
  209. $Game::EndGamePause = %this.endgamePause;
  210. }
  211. //-----------------------------------------------------------------------------
  212. // Functions that implement game-play
  213. // These are here for backwards compatibilty only, games and/or mods should
  214. // really be overloading the server and mission functions listed ubove.
  215. //-----------------------------------------------------------------------------
  216. // Added this stage to creating a player so game types can override it easily.
  217. // This is a good place to initiate team selection.
  218. function DeathMatchGame::preparePlayer(%this, %client)
  219. {
  220. //echo (%game @"\c4 -> "@ %game.class @" -> GameCore::preparePlayer");
  221. // Find a spawn point for the player
  222. // This function currently relies on some helper functions defined in
  223. // core/scripts/spawn.cs. For custom spawn behaviors one can either
  224. // override the properties on the SpawnSphere's or directly override the
  225. // functions themselves.
  226. %playerSpawnPoint = pickPlayerSpawnPoint($Game::DefaultPlayerSpawnGroups);
  227. // Spawn a camera for this client using the found %spawnPoint
  228. //%client.spawnPlayer(%playerSpawnPoint);
  229. %this.spawnPlayer(%client, %playerSpawnPoint);
  230. // Starting equipment
  231. %this.loadOut(%client.player);
  232. }
  233. function DeathMatchGame::loadOut(%game, %player)
  234. {
  235. //echo (%game @"\c4 -> "@ %game.class @" -> GameCore::loadOut");
  236. %player.clearWeaponCycle();
  237. %player.setInventory(Ryder, 1);
  238. %player.setInventory(RyderClip, %player.maxInventory(RyderClip));
  239. %player.setInventory(RyderAmmo, %player.maxInventory(RyderAmmo)); // Start the gun loaded
  240. %player.addToWeaponCycle(Ryder);
  241. %player.setInventory(Lurker, 1);
  242. %player.setInventory(LurkerClip, %player.maxInventory(LurkerClip));
  243. %player.setInventory(LurkerAmmo, %player.maxInventory(LurkerAmmo)); // Start the gun loaded
  244. %player.addToWeaponCycle(Lurker);
  245. %player.setInventory(LurkerGrenadeLauncher, 1);
  246. %player.setInventory(LurkerGrenadeAmmo, %player.maxInventory(LurkerGrenadeAmmo));
  247. %player.addToWeaponCycle(LurkerGrenadeLauncher);
  248. %player.setInventory(ProxMine, %player.maxInventory(ProxMine));
  249. %player.addToWeaponCycle(ProxMine);
  250. %player.setInventory(DeployableTurret, %player.maxInventory(DeployableTurret));
  251. %player.addToWeaponCycle(DeployableTurret);
  252. if (%player.getDatablock().mainWeapon.image !$= "")
  253. {
  254. %player.mountImage(%player.getDatablock().mainWeapon.image, 0);
  255. }
  256. else
  257. {
  258. %player.mountImage(Ryder, 0);
  259. }
  260. }
  261. // Customized kill message for falling deaths
  262. function sendMsgClientKilled_Impact( %msgType, %client, %sourceClient, %damLoc )
  263. {
  264. messageAll( %msgType, '%1 fell to his death!', %client.playerName );
  265. }
  266. // Customized kill message for suicides
  267. function sendMsgClientKilled_Suicide( %msgType, %client, %sourceClient, %damLoc )
  268. {
  269. messageAll( %msgType, '%1 takes his own life!', %client.playerName );
  270. }
  271. // Default death message
  272. function sendMsgClientKilled_Default( %msgType, %client, %sourceClient, %damLoc )
  273. {
  274. if ( %sourceClient == %client )
  275. sendMsgClientKilled_Suicide(%client, %sourceClient, %damLoc);
  276. else if ( %sourceClient.team !$= "" && %sourceClient.team $= %client.team )
  277. messageAll( %msgType, '%1 killed by %2 - friendly fire!', %client.playerName, %sourceClient.playerName );
  278. else
  279. messageAll( %msgType, '%1 gets nailed by %2!', %client.playerName, %sourceClient.playerName );
  280. }
  281. function DeathMatchGame::onDeath(%game, %client, %sourceObject, %sourceClient, %damageType, %damLoc)
  282. {
  283. //echo (%game @"\c4 -> "@ %game.class @" -> GameCore::onDeath");
  284. // clear the weaponHUD
  285. %client.RefreshWeaponHud(0, "", "");
  286. // Clear out the name on the corpse
  287. %client.player.setShapeName("");
  288. // Switch the client over to the death cam and unhook the player object.
  289. if (isObject(%client.camera) && isObject(%client.player))
  290. {
  291. %client.camera.setMode("Corpse", %client.player);
  292. %client.setControlObject(%client.camera);
  293. }
  294. %client.player = 0;
  295. // Display damage appropriate kill message
  296. %sendMsgFunction = "sendMsgClientKilled_" @ %damageType;
  297. if ( !isFunction( %sendMsgFunction ) )
  298. %sendMsgFunction = "sendMsgClientKilled_Default";
  299. call( %sendMsgFunction, 'MsgClientKilled', %client, %sourceClient, %damLoc );
  300. // Dole out points and check for win
  301. if (( %damageType $= "Suicide" || %sourceClient == %client ) && isObject(%sourceClient))
  302. {
  303. %game.incDeaths( %client, 1, true );
  304. %game.incScore( %client, -1, false );
  305. }
  306. else
  307. {
  308. %game.incDeaths( %client, 1, false );
  309. %game.incScore( %sourceClient, 1, true );
  310. %game.incKills( %sourceClient, 1, false );
  311. // If the game may be ended by a client getting a particular score, check that now.
  312. if ( $Game::EndGameScore > 0 && %sourceClient.kills >= $Game::EndGameScore )
  313. %game.cycleGame();
  314. }
  315. }
  316. // ----------------------------------------------------------------------------
  317. // Scoring
  318. // ----------------------------------------------------------------------------
  319. function DeathMatchGame::incKills(%game, %client, %kill, %dontMessageAll)
  320. {
  321. %client.kills += %kill;
  322. if( !%dontMessageAll )
  323. messageAll('MsgClientScoreChanged', "", %client.score, %client.kills, %client.deaths, %client);
  324. }
  325. function DeathMatchGame::incDeaths(%game, %client, %death, %dontMessageAll)
  326. {
  327. %client.deaths += %death;
  328. if( !%dontMessageAll )
  329. messageAll('MsgClientScoreChanged', "", %client.score, %client.kills, %client.deaths, %client);
  330. }
  331. function DeathMatchGame::incScore(%game, %client, %score, %dontMessageAll)
  332. {
  333. %client.score += %score;
  334. if( !%dontMessageAll )
  335. messageAll('MsgClientScoreChanged', "", %client.score, %client.kills, %client.deaths, %client);
  336. }
  337. function DeathMatchGame::getScore(%client) { return %client.score; }
  338. function DeathMatchGame::getKills(%client) { return %client.kills; }
  339. function DeathMatchGame::getDeaths(%client) { return %client.deaths; }
  340. function DeathMatchGame::getTeamScore(%client)
  341. {
  342. %score = %client.score;
  343. if ( %client.team !$= "" )
  344. {
  345. // Compute team score
  346. for (%i = 0; %i < ClientGroup.getCount(); %i++)
  347. {
  348. %other = ClientGroup.getObject(%i);
  349. if ((%other != %client) && (%other.team $= %client.team))
  350. %score += %other.score;
  351. }
  352. }
  353. return %score;
  354. }
  355. // ----------------------------------------------------------------------------
  356. // Spawning
  357. // ----------------------------------------------------------------------------
  358. function DeathMatchGame::spawnPlayer(%game, %client, %spawnPoint, %noControl)
  359. {
  360. //echo (%game @"\c4 -> "@ %game.class @" -> GameCore::spawnPlayer");
  361. if (isObject(%client.player))
  362. {
  363. // The client should not already have a player. Assigning
  364. // a new one could result in an uncontrolled player object.
  365. error("Attempting to create a player for a client that already has one!");
  366. }
  367. // Attempt to treat %spawnPoint as an object
  368. if (getWordCount(%spawnPoint) == 1 && isObject(%spawnPoint))
  369. {
  370. // Defaults
  371. %spawnClass = $Game::DefaultPlayerClass;
  372. %spawnDataBlock = $Game::DefaultPlayerDataBlock;
  373. // Overrides by the %spawnPoint
  374. if (isDefined("%spawnPoint.spawnClass"))
  375. {
  376. %spawnClass = %spawnPoint.spawnClass;
  377. %spawnDataBlock = %spawnPoint.spawnDatablock;
  378. }
  379. else if (isDefined("%spawnPoint.spawnDatablock"))
  380. {
  381. // This may seem redundant given the above but it allows
  382. // the SpawnSphere to override the datablock without
  383. // overriding the default player class
  384. %spawnDataBlock = %spawnPoint.spawnDatablock;
  385. }
  386. %spawnProperties = %spawnPoint.spawnProperties;
  387. %spawnScript = %spawnPoint.spawnScript;
  388. // Spawn with the engine's Sim::spawnObject() function
  389. %player = spawnObject(%spawnClass, %spawnDatablock, "",
  390. %spawnProperties, %spawnScript);
  391. // If we have an object do some initial setup
  392. if (isObject(%player))
  393. {
  394. // Pick a location within the spawn sphere.
  395. %spawnLocation = %game.pickPointInSpawnSphere(%player, %spawnPoint);
  396. %player.setTransform(%spawnLocation);
  397. }
  398. else
  399. {
  400. // If we weren't able to create the player object then warn the user
  401. // When the player clicks OK in one of these message boxes, we will fall through
  402. // to the "if (!isObject(%player))" check below.
  403. if (isDefined("%spawnDatablock"))
  404. {
  405. MessageBoxOK("Spawn Player Failed",
  406. "Unable to create a player with class " @ %spawnClass @
  407. " and datablock " @ %spawnDatablock @ ".\n\nStarting as an Observer instead.",
  408. "");
  409. }
  410. else
  411. {
  412. MessageBoxOK("Spawn Player Failed",
  413. "Unable to create a player with class " @ %spawnClass @
  414. ".\n\nStarting as an Observer instead.",
  415. "");
  416. }
  417. }
  418. }
  419. else
  420. {
  421. // Create a default player
  422. %player = spawnObject($Game::DefaultPlayerClass, $Game::DefaultPlayerDataBlock);
  423. if (!%player.isMemberOfClass("Player"))
  424. warn("Trying to spawn a class that does not derive from Player.");
  425. // Treat %spawnPoint as a transform
  426. %player.setTransform(%spawnPoint);
  427. }
  428. // If we didn't actually create a player object then bail
  429. if (!isObject(%player))
  430. {
  431. // Make sure we at least have a camera
  432. %client.spawnCamera(%spawnPoint);
  433. return;
  434. }
  435. // Update the default camera to start with the player
  436. if (isObject(%client.camera) && !isDefined("%noControl"))
  437. {
  438. if (%player.getClassname() $= "Player")
  439. %client.camera.setTransform(%player.getEyeTransform());
  440. else
  441. %client.camera.setTransform(%player.getTransform());
  442. }
  443. // Add the player object to MissionCleanup so that it
  444. // won't get saved into the level files and will get
  445. // cleaned up properly
  446. MissionCleanup.add(%player);
  447. // Store the client object on the player object for
  448. // future reference
  449. %player.client = %client;
  450. // If the player's client has some owned turrets, make sure we let them
  451. // know that we're a friend too.
  452. if (%client.ownedTurrets)
  453. {
  454. for (%i=0; %i<%client.ownedTurrets.getCount(); %i++)
  455. {
  456. %turret = %client.ownedTurrets.getObject(%i);
  457. %turret.addToIgnoreList(%player);
  458. }
  459. }
  460. // Player setup...
  461. if (%player.isMethod("setShapeName"))
  462. %player.setShapeName(%client.playerName);
  463. if (%player.isMethod("setEnergyLevel"))
  464. %player.setEnergyLevel(%player.getDataBlock().maxEnergy);
  465. if (!isDefined("%client.skin"))
  466. {
  467. // Determine which character skins are not already in use
  468. %availableSkins = %player.getDatablock().availableSkins; // TAB delimited list of skin names
  469. %count = ClientGroup.getCount();
  470. for (%cl = 0; %cl < %count; %cl++)
  471. {
  472. %other = ClientGroup.getObject(%cl);
  473. if (%other != %client)
  474. {
  475. %availableSkins = strreplace(%availableSkins, %other.skin, "");
  476. %availableSkins = strreplace(%availableSkins, "\t\t", ""); // remove empty fields
  477. }
  478. }
  479. // Choose a random, unique skin for this client
  480. %count = getFieldCount(%availableSkins);
  481. %client.skin = addTaggedString( getField(%availableSkins, getRandom(%count)) );
  482. }
  483. %player.setSkinName(%client.skin);
  484. // Give the client control of the player
  485. %client.player = %player;
  486. // Give the client control of the camera if in the editor
  487. if( $startWorldEditor )
  488. {
  489. %control = %client.camera;
  490. %control.mode = "Fly";
  491. EditorGui.syncCameraGui();
  492. }
  493. else
  494. %control = %player;
  495. // Allow the player/camera to receive move data from the GameConnection. Without this
  496. // the user is unable to control the player/camera.
  497. if (!isDefined("%noControl"))
  498. %client.setControlObject(%control);
  499. }
  500. function DeathMatchGame::pickPointInSpawnSphere(%this, %objectToSpawn, %spawnSphere)
  501. {
  502. %SpawnLocationFound = false;
  503. %attemptsToSpawn = 0;
  504. while(!%SpawnLocationFound && (%attemptsToSpawn < 5))
  505. {
  506. %sphereLocation = %spawnSphere.getTransform();
  507. // Attempt to spawn the player within the bounds of the spawnsphere.
  508. %angleY = mDegToRad(getRandom(0, 100) * m2Pi());
  509. %angleXZ = mDegToRad(getRandom(0, 100) * m2Pi());
  510. %sphereLocation = setWord( %sphereLocation, 0, getWord(%sphereLocation, 0) + (mCos(%angleY) * mSin(%angleXZ) * getRandom(-%spawnSphere.radius, %spawnSphere.radius)));
  511. %sphereLocation = setWord( %sphereLocation, 1, getWord(%sphereLocation, 1) + (mCos(%angleXZ) * getRandom(-%spawnSphere.radius, %spawnSphere.radius)));
  512. %SpawnLocationFound = true;
  513. // Now have to check that another object doesn't already exist at this spot.
  514. // Use the bounding box of the object to check if where we are about to spawn in is
  515. // clear.
  516. %boundingBoxSize = %objectToSpawn.getDatablock().boundingBox;
  517. %searchRadius = getWord(%boundingBoxSize, 0);
  518. %boxSizeY = getWord(%boundingBoxSize, 1);
  519. // Use the larger dimention as the radius to search
  520. if (%boxSizeY > %searchRadius)
  521. %searchRadius = %boxSizeY;
  522. // Search a radius about the area we're about to spawn for players.
  523. initContainerRadiusSearch( %sphereLocation, %searchRadius, $TypeMasks::PlayerObjectType );
  524. while ( (%objectNearExit = containerSearchNext()) != 0 )
  525. {
  526. // If any player is found within this radius, mark that we need to look
  527. // for another spot.
  528. %SpawnLocationFound = false;
  529. break;
  530. }
  531. // If the attempt at finding a clear spawn location failed
  532. // try no more than 5 times.
  533. %attemptsToSpawn++;
  534. }
  535. // If we couldn't find a spawn location after 5 tries, spawn the object
  536. // At the center of the sphere and give a warning.
  537. if (!%SpawnLocationFound)
  538. {
  539. %sphereLocation = %spawnSphere.getTransform();
  540. warn("WARNING: Could not spawn player after" SPC %attemptsToSpawn
  541. SPC "tries in spawnsphere" SPC %spawnSphere SPC "without overlapping another player. Attempting spawn in center of sphere.");
  542. }
  543. return %sphereLocation;
  544. }
  545. // ----------------------------------------------------------------------------
  546. // Observer
  547. // ----------------------------------------------------------------------------
  548. function DeathMatchGame::spawnObserver(%game, %client)
  549. {
  550. //echo (%game @"\c4 -> "@ %game.class @" -> GameCore::spawnObserver");
  551. // Position the camera on one of our observer spawn points
  552. %client.camera.setTransform(%game.pickObserverSpawnPoint());
  553. // Set control to the camera
  554. %client.setControlObject(%client.camera);
  555. }
  556. function DeathMatchGame::pickObserverSpawnPoint(%game)
  557. {
  558. //echo (%game @"\c4 -> "@ %game.class @" -> GameCore::pickObserverSpawnPoint");
  559. %groupName = "MissionGroup/ObserverSpawnPoints";
  560. %group = nameToID(%groupName);
  561. if (%group != -1)
  562. {
  563. %count = %group.getCount();
  564. if (%count != 0)
  565. {
  566. %index = getRandom(%count-1);
  567. %spawn = %group.getObject(%index);
  568. return %spawn.getTransform();
  569. }
  570. else
  571. error("No spawn points found in "@ %groupName);
  572. }
  573. else
  574. error("Missing spawn points group "@ %groupName);
  575. // Could be no spawn points, in which case we'll stick the
  576. // player at the center of the world.
  577. return "0 0 300 1 0 0 0";
  578. }
  579. // ----------------------------------------------------------------------------
  580. // Server
  581. // ----------------------------------------------------------------------------
  582. // Called by GameCore::cycleGame() when we need to destroy the server
  583. // because we're done playing. We don't want to call destroyServer()
  584. // directly so we can first check that we're about to destroy the
  585. // correct server session.
  586. function DeathMatchGame::DestroyServer(%serverSession)
  587. {
  588. if (%serverSession == $Server::Session)
  589. {
  590. if (isObject(LocalClientConnection))
  591. {
  592. // We're a local connection so issue a disconnect. The server will
  593. // be automatically destroyed for us.
  594. disconnect();
  595. }
  596. else
  597. {
  598. // We're a stand alone server
  599. destroyServer();
  600. }
  601. }
  602. }
  603. // ----------------------------------------------------------------------------
  604. // weapon HUD
  605. // ----------------------------------------------------------------------------
  606. function GameConnection::setAmmoAmountHud(%client, %amount, %amountInClips )
  607. {
  608. commandToClient(%client, 'SetAmmoAmountHud', %amount, %amountInClips);
  609. }
  610. function GameConnection::RefreshWeaponHud(%client, %amount, %preview, %ret, %zoomRet, %amountInClips)
  611. {
  612. commandToClient(%client, 'RefreshWeaponHud', %amount, %preview, %ret, %zoomRet, %amountInClips);
  613. }