Ship.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854
  1. //-----------------------------------------------------------------------------
  2. // Ship.cs
  3. //
  4. // Microsoft XNA Community Game Platform
  5. // Copyright (C) Microsoft Corporation. All rights reserved.
  6. //-----------------------------------------------------------------------------
  7. using System;
  8. using Microsoft.Xna.Framework;
  9. using Microsoft.Xna.Framework.Graphics;
  10. using Microsoft.Xna.Framework.Input;
  11. using Microsoft.Xna.Framework.Net;
  12. using Microsoft.Xna.Framework.Content;
  13. namespace NetRumble
  14. {
  15. /// <summary>
  16. /// The ship, which is the primary playing-piece in the game.
  17. /// </summary>
  18. public class Ship : GameplayObject
  19. {
  20. /// <summary>
  21. /// The full speed possible for the ship.
  22. /// </summary>
  23. const float fullSpeed = 320f;
  24. /// <summary>
  25. /// The amount of drag applied to velocity per second,
  26. /// as a percentage of velocity.
  27. /// </summary>
  28. const float dragPerSecond = 0.9f;
  29. /// <summary>
  30. /// The amount that the right-stick must be pressed to fire, squared so that
  31. /// we can use LengthSquared instead of Length, which has a square-root in it.
  32. /// </summary>
  33. const float fireThresholdSquared = 0.25f;
  34. /// <summary>
  35. /// The number of radians that the ship can turn in a second at full left-stick.
  36. /// </summary>
  37. const float rotationRadiansPerSecond = 6f;
  38. /// <summary>
  39. /// The maximum length of the velocity vector on a ship.
  40. /// </summary>
  41. const float velocityMaximum = 320f;
  42. /// <summary>
  43. /// The maximum strength of the shield.
  44. /// </summary>
  45. const float shieldMaximum = 100f;
  46. /// <summary>
  47. /// The maximum opacity for the shield, when it's fully recharged.
  48. /// </summary>
  49. const float shieldAlphaMaximum = 150f;
  50. /// <summary>
  51. /// How much the shield recharges per second.
  52. /// </summary>
  53. const float shieldRechargePerSecond = 50f;
  54. /// <summary>
  55. /// The duration of the shield-recharge timer when the ship is hit.
  56. /// </summary>
  57. const float shieldRechargeTimerMaximum = 2.5f;
  58. /// <summary>
  59. /// The base scale for the shield, compared to the size of the ship.
  60. /// </summary>
  61. const float shieldScaleBase = 1.2f;
  62. /// <summary>
  63. /// The amplitude of the shield pulse
  64. /// </summary>
  65. const float shieldPulseAmplitude = 0.15f;
  66. /// <summary>
  67. /// The rate of the shield pulse.
  68. /// </summary>
  69. const float shieldPulseRate = 0.2f;
  70. /// <summary>
  71. /// The maximum value of the "safe" timer.
  72. /// </summary>
  73. const float safeTimerMaximum = 4f;
  74. /// <summary>
  75. /// The maximum amount of life that a ship can have.
  76. /// </summary>
  77. const float lifeMaximum = 25f;
  78. /// <summary>
  79. /// The value of the spawn timer set when the ship dies.
  80. /// </summary>
  81. const float respawnTimerOnDeath = 5f;
  82. /// <summary>
  83. /// The number of variations in textures for ships.
  84. /// </summary>
  85. const int variations = 4;
  86. /// <summary>
  87. /// The primary ship textures.
  88. /// </summary>
  89. private static Texture2D[] primaryTextures = new Texture2D[variations];
  90. /// <summary>
  91. /// The overlay ship textures, which get tinted.
  92. /// </summary>
  93. private static Texture2D[] overlayTextures = new Texture2D[variations];
  94. /// <summary>
  95. /// The ship shield texture.
  96. /// </summary>
  97. private static Texture2D shieldTexture;
  98. /// <summary>
  99. /// The colors used for each ship.
  100. /// </summary>
  101. public static readonly Color[] ShipColors =
  102. {
  103. Color.Lime, Color.CornflowerBlue, Color.Fuchsia,
  104. Color.Red, Color.LightSeaGreen, Color.LightGray,
  105. Color.Gold, Color.ForestGreen, Color.Beige,
  106. Color.LightPink, Color.Lavender, Color.OrangeRed,
  107. Color.Plum, Color.Tan, Color.YellowGreen,
  108. Color.Azure, Color.Aqua, Color.Salmon
  109. };
  110. /// <summary>
  111. /// The particle-effect manager which recieves the effects from ships.
  112. /// </summary>
  113. public static ParticleEffectManager ParticleEffectManager;
  114. /// <summary>
  115. /// The score for this ship.
  116. /// </summary>
  117. private int score = 0;
  118. public int Score
  119. {
  120. get { return score; }
  121. set { score = value; }
  122. }
  123. /// <summary>
  124. /// The amount of damage that the ship can take before exploding.
  125. /// </summary>
  126. private float life;
  127. public float Life
  128. {
  129. get { return life; }
  130. set { life = value; }
  131. }
  132. /// <summary>
  133. /// The ship's primary weapon.
  134. /// </summary>
  135. private Weapon weapon;
  136. public Weapon Weapon
  137. {
  138. get { return weapon; }
  139. set
  140. {
  141. if (value == null)
  142. {
  143. throw new ArgumentNullException("value");
  144. }
  145. weapon = value;
  146. }
  147. }
  148. /// <summary>
  149. /// The ship's mine-laying weapon.
  150. /// </summary>
  151. private MineWeapon mineWeapon;
  152. /// <summary>
  153. /// All of the projectiles fired by this ship.
  154. /// </summary>
  155. private BatchRemovalCollection<Projectile> projectiles =
  156. new BatchRemovalCollection<Projectile>();
  157. public BatchRemovalCollection<Projectile> Projectiles
  158. {
  159. get { return projectiles; }
  160. }
  161. /// <summary>
  162. /// The strength of the shield.
  163. /// </summary>
  164. private float shield;
  165. public float Shield
  166. {
  167. get { return shield; }
  168. set { shield = value; }
  169. }
  170. /// <summary>
  171. /// Timer for how long until the shield starts to recharge.
  172. /// </summary>
  173. private float shieldRechargeTimer;
  174. /// <summary>
  175. /// Timer for how long the player is safe after spawning.
  176. /// </summary>
  177. private float safeTimer;
  178. public bool Safe
  179. {
  180. get { return (safeTimer > 0f); }
  181. set
  182. {
  183. if (value)
  184. {
  185. safeTimer = safeTimerMaximum;
  186. }
  187. else
  188. {
  189. safeTimer = 0f;
  190. }
  191. }
  192. }
  193. /// <summary>
  194. /// The tint of the ship.
  195. /// </summary>
  196. private Color color = Color.White;
  197. public Color Color
  198. {
  199. get { return color; }
  200. set { color = value; }
  201. }
  202. /// <summary>
  203. /// The amount of time left before respawning the ship.
  204. /// </summary>
  205. private float respawnTimer;
  206. public float RespawnTimer
  207. {
  208. get { return respawnTimer; }
  209. set { respawnTimer = value; }
  210. }
  211. /// <summary>
  212. /// The last object to damage the ship.
  213. /// </summary>
  214. private GameplayObject lastDamagedBy = null;
  215. public GameplayObject LastDamagedBy
  216. {
  217. get { return lastDamagedBy; }
  218. }
  219. /// <summary>
  220. /// The current player input for the ship.
  221. /// </summary>
  222. private ShipInput shipInput;
  223. public ShipInput ShipInput
  224. {
  225. get { return shipInput; }
  226. set { shipInput = value; }
  227. }
  228. /// <summary>
  229. /// The variation of this ship.
  230. /// </summary>
  231. private int variation = 0;
  232. public int Variation
  233. {
  234. get { return variation; }
  235. set
  236. {
  237. if ((value < 0) || (value >= variations))
  238. {
  239. throw new ArgumentOutOfRangeException("value");
  240. }
  241. variation = value;
  242. }
  243. }
  244. /// <summary>
  245. /// The time accumulator for the shield pulse.
  246. /// </summary>
  247. private float shieldPulseTime = 0f;
  248. /// <summary>
  249. /// Construct a new ship.
  250. /// </summary>
  251. public Ship()
  252. : base()
  253. {
  254. // set the collision data
  255. this.radius = 24f;
  256. this.mass = 32f;
  257. }
  258. /// <summary>
  259. /// Initialize a ship to its default gameplay states.
  260. /// </summary>
  261. public override void Initialize()
  262. {
  263. if (!active)
  264. {
  265. // set the initial gameplay data values
  266. shipInput = ShipInput.Empty;
  267. rotation = 0f;
  268. velocity = Vector2.Zero;
  269. life = lifeMaximum;
  270. shield = shieldMaximum;
  271. shieldRechargeTimer = 0f;
  272. safeTimer = safeTimerMaximum;
  273. weapon = new LaserWeapon(this);
  274. mineWeapon = new MineWeapon(this);
  275. // play the player-spawn sound
  276. AudioManager.PlaySoundEffect("player_spawn");
  277. // add the ship-spawn particle effect
  278. if (ParticleEffectManager != null)
  279. {
  280. ParticleEffectManager.SpawnEffect(ParticleEffectType.ShipSpawn,
  281. this);
  282. }
  283. // clear out the projectiles list
  284. projectiles.Clear();
  285. }
  286. base.Initialize();
  287. }
  288. /// <summary>
  289. /// Update the ship.
  290. /// </summary>
  291. /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
  292. public override void Update(float elapsedTime)
  293. {
  294. // calculate the current forward vector
  295. Vector2 forward = new Vector2((float)Math.Sin(Rotation),
  296. -(float)Math.Cos(Rotation));
  297. Vector2 right = new Vector2(-forward.Y, forward.X);
  298. // calculate the new forward vector with the left stick
  299. shipInput.LeftStick.Y *= -1f;
  300. if (shipInput.LeftStick.LengthSquared() > 0f)
  301. {
  302. // change the direction
  303. Vector2 wantedForward = Vector2.Normalize(shipInput.LeftStick);
  304. float angleDiff = (float)Math.Acos(
  305. Vector2.Dot(wantedForward, forward));
  306. float facing = (Vector2.Dot(wantedForward, right) > 0f) ?
  307. 1f : -1f;
  308. if (angleDiff > 0.001f)
  309. {
  310. Rotation += Math.Min(angleDiff, facing * elapsedTime *
  311. rotationRadiansPerSecond);
  312. }
  313. // add velocity
  314. Velocity += shipInput.LeftStick * (elapsedTime * fullSpeed);
  315. if (Velocity.Length() > velocityMaximum)
  316. {
  317. Velocity = Vector2.Normalize(Velocity) *
  318. velocityMaximum;
  319. }
  320. }
  321. shipInput.LeftStick = Vector2.Zero;
  322. // apply drag to the velocity
  323. Velocity -= Velocity * (elapsedTime * dragPerSecond);
  324. if (Velocity.LengthSquared() <= 0f)
  325. {
  326. Velocity = Vector2.Zero;
  327. }
  328. // check for firing with the right stick
  329. shipInput.RightStick.Y *= -1f;
  330. if (shipInput.RightStick.LengthSquared() > fireThresholdSquared)
  331. {
  332. weapon.Fire(Vector2.Normalize(shipInput.RightStick));
  333. }
  334. shipInput.RightStick = Vector2.Zero;
  335. // check for laying mines
  336. if (shipInput.MineFired)
  337. {
  338. // fire behind the ship
  339. mineWeapon.Fire(-forward);
  340. }
  341. shipInput.MineFired = false;
  342. // recharge the shields
  343. if (shieldRechargeTimer > 0f)
  344. {
  345. shieldRechargeTimer = Math.Max(shieldRechargeTimer - elapsedTime,
  346. 0f);
  347. }
  348. if (shieldRechargeTimer <= 0f)
  349. {
  350. if (shield < shieldMaximum)
  351. {
  352. shield = Math.Min(shieldMaximum,
  353. shield + shieldRechargePerSecond * elapsedTime);
  354. }
  355. }
  356. // update the radius based on the shield
  357. radius = (shield > 0f) ? 24f : 20f;
  358. // update the weapons
  359. if (weapon != null)
  360. {
  361. weapon.Update(elapsedTime);
  362. }
  363. if (mineWeapon != null)
  364. {
  365. mineWeapon.Update(elapsedTime);
  366. }
  367. // decrement the safe timer
  368. if (safeTimer > 0f)
  369. {
  370. safeTimer = Math.Max(safeTimer - elapsedTime, 0f);
  371. }
  372. // update the projectiles
  373. foreach (Projectile projectile in projectiles)
  374. {
  375. if (projectile.Active)
  376. {
  377. projectile.Update(elapsedTime);
  378. }
  379. else
  380. {
  381. projectiles.QueuePendingRemoval(projectile);
  382. }
  383. }
  384. projectiles.ApplyPendingRemovals();
  385. base.Update(elapsedTime);
  386. }
  387. /// <summary>
  388. /// Draw the ship.
  389. /// </summary>
  390. /// <param name="elapsedTime">The amount of elapsed time, in seconds.</param>
  391. /// <param name="spriteBatch">The SpriteBatch object used to draw.</param>
  392. public void Draw(float elapsedTime, SpriteBatch spriteBatch)
  393. {
  394. // draw the uniform section of the ship
  395. base.Draw(elapsedTime, spriteBatch, primaryTextures[variation],
  396. null, Color.White);
  397. // draw the tinted section of the ship
  398. base.Draw(elapsedTime, spriteBatch, overlayTextures[variation],
  399. null, color);
  400. if (shield > 0)
  401. {
  402. // calculate the current shield radius
  403. float oldRadius = radius;
  404. shieldPulseTime += elapsedTime;
  405. radius *= shieldScaleBase + shieldPulseAmplitude *
  406. (float)Math.Sin(shieldPulseTime / shieldPulseRate);
  407. // draw the shield
  408. base.Draw(elapsedTime, spriteBatch, shieldTexture, null,
  409. new Color(color.R, color.G, color.B,
  410. (byte)Math.Floor(shieldAlphaMaximum * shield / shieldMaximum)));
  411. // return to the old radius
  412. radius = oldRadius;
  413. }
  414. // draw the projectiles
  415. foreach (Projectile projectile in projectiles)
  416. {
  417. projectile.Draw(elapsedTime, spriteBatch);
  418. }
  419. }
  420. /// <summary>
  421. /// Damage this ship by the amount provided.
  422. /// </summary>
  423. /// <remarks>
  424. /// This function is provided in lieu of a Life mutation property to allow
  425. /// classes of objects to restrict which kinds of objects may damage them,
  426. /// and under what circumstances they may be damaged.
  427. /// </remarks>
  428. /// <param name="source">The GameplayObject responsible for the damage.</param>
  429. /// <param name="damageAmount">The amount of damage.</param>
  430. /// <returns>If true, this object was damaged.</returns>
  431. public override bool Damage(GameplayObject source, float damageAmount)
  432. {
  433. // if the safe timer hasn't yet gone off, then the ship can't be hurt
  434. if ((safeTimer > 0f) || (damageAmount <= 0f))
  435. {
  436. return false;
  437. }
  438. // once you're hit, the shield-recharge timer starts over
  439. shieldRechargeTimer = 2.5f;
  440. // damage the shield first, then life
  441. if (shield <= 0f)
  442. {
  443. life -= damageAmount;
  444. }
  445. else
  446. {
  447. shield -= damageAmount;
  448. if (shield < 0f)
  449. {
  450. // shield has the overflow value as a negative value, just add it
  451. life += shield;
  452. shield = 0f;
  453. }
  454. }
  455. Projectile sourceAsProjectile = source as Projectile;
  456. if (sourceAsProjectile != null)
  457. {
  458. lastDamagedBy = sourceAsProjectile.Owner;
  459. }
  460. else
  461. {
  462. lastDamagedBy = source;
  463. }
  464. return true;
  465. }
  466. /// <summary>
  467. /// Kills this ship, in response to the given GameplayObject.
  468. /// </summary>
  469. /// <param name="source">The GameplayObject responsible for the kill.</param>
  470. /// <param name="cleanupOnly">
  471. /// If true, the object dies without any further effects.
  472. /// </param>
  473. public override void Die(GameplayObject source, bool cleanupOnly)
  474. {
  475. if (active)
  476. {
  477. if (!cleanupOnly)
  478. {
  479. // update the score
  480. Ship ship = source as Ship;
  481. if (ship == null)
  482. {
  483. Projectile projectile = source as Projectile;
  484. if (projectile != null)
  485. {
  486. ship = projectile.Owner;
  487. }
  488. }
  489. if (ship != null)
  490. {
  491. if (ship == this)
  492. {
  493. // reduce the score, since i blew myself up
  494. ship.Score--;
  495. }
  496. else
  497. {
  498. // add score to the ship who shot this object
  499. ship.Score++;
  500. }
  501. }
  502. else
  503. {
  504. // if it wasn't a ship, then this object loses score
  505. this.Score--;
  506. }
  507. // play the player-death sound
  508. AudioManager.PlaySoundEffect("explosion_shockwave");
  509. AudioManager.PlaySoundEffect("explosion_large");
  510. // display the ship explosion
  511. if (ParticleEffectManager != null)
  512. {
  513. ParticleEffectManager.SpawnEffect(
  514. ParticleEffectType.ShipExplosion, Position);
  515. }
  516. }
  517. // clear out the projectiles list
  518. foreach (Projectile projectile in projectiles)
  519. {
  520. projectile.Die(null, true);
  521. }
  522. projectiles.Clear();
  523. // set the respawn timer
  524. respawnTimer = respawnTimerOnDeath;
  525. }
  526. base.Die(source, cleanupOnly);
  527. }
  528. /// <summary>
  529. /// Load all of the static graphics content for this class.
  530. /// </summary>
  531. /// <param name="contentManager">The content manager to load with.</param>
  532. public static void LoadContent(ContentManager contentManager)
  533. {
  534. // safety-check the parameters
  535. if (contentManager == null)
  536. {
  537. throw new ArgumentNullException("contentManager");
  538. }
  539. // load each ship's texture
  540. for (int i = 0; i < variations; i++)
  541. {
  542. primaryTextures[i] = contentManager.Load<Texture2D>(
  543. "Textures/ship" + i.ToString());
  544. overlayTextures[i] = contentManager.Load<Texture2D>(
  545. "Textures/ship" + i.ToString() + "Overlay");
  546. }
  547. // load the shield texture
  548. shieldTexture = contentManager.Load<Texture2D>("Textures/shipShields");
  549. }
  550. /// <summary>
  551. /// Unload all of the static graphics content for this class.
  552. /// </summary>
  553. public static void UnloadContent()
  554. {
  555. for (int i = 0; i < variations; i++)
  556. {
  557. primaryTextures[i] = overlayTextures[i] = null;
  558. }
  559. shieldTexture = null;
  560. }
  561. /// <summary>
  562. /// Determines if a color index is unique.
  563. /// </summary>
  564. /// <param name="networkGamer">The gamer with the color index.</param>
  565. /// <param name="networkSession">The session the player belongs to.</param>
  566. /// <returns>If true, the gamer has a unique color ID.</returns>
  567. public static bool HasUniqueColorIndex(NetworkGamer networkGamer,
  568. NetworkSession networkSession)
  569. {
  570. // safety-check the parameters
  571. if (networkGamer == null)
  572. {
  573. throw new ArgumentNullException("networkGamer");
  574. }
  575. if (networkSession == null)
  576. {
  577. throw new ArgumentNullException("networkSession");
  578. }
  579. PlayerData playerData = networkGamer.Tag as PlayerData;
  580. if (playerData == null)
  581. {
  582. throw new ArgumentNullException("networkGamer.Tag as PlayerData");
  583. }
  584. // search for a match
  585. foreach (NetworkGamer gamer in networkSession.AllGamers)
  586. {
  587. if (gamer == networkGamer)
  588. {
  589. continue;
  590. }
  591. PlayerData gamerData = gamer.Tag as PlayerData;
  592. if ((gamerData != null) &&
  593. (gamerData.ShipColor == playerData.ShipColor))
  594. {
  595. return false;
  596. }
  597. }
  598. return true;
  599. }
  600. /// <summary>
  601. /// Find the next unique color index among the players.
  602. /// </summary>
  603. /// <param name="currentColorIndex">The current color index.</param>
  604. /// <param name="networkSession">The network session.</param>
  605. /// <returns>The next unique color index.</returns>
  606. public static byte GetNextUniqueColorIndex(byte currentColorIndex,
  607. NetworkSession networkSession)
  608. {
  609. // safety-check the parameters
  610. if ((currentColorIndex < 0) || (currentColorIndex >= ShipColors.Length))
  611. {
  612. throw new ArgumentOutOfRangeException("currentColorIndex");
  613. }
  614. if (networkSession == null)
  615. {
  616. throw new ArgumentNullException("networkSession");
  617. }
  618. if (networkSession.AllGamers.Count > ShipColors.Length)
  619. {
  620. throw new InvalidOperationException(
  621. "There are more gamers than there are colors.");
  622. }
  623. // if there are as many gamers as there are colors, then we can't change
  624. if (networkSession.AllGamers.Count == ShipColors.Length)
  625. {
  626. return currentColorIndex;
  627. }
  628. bool colorFound;
  629. byte newColorIndex = currentColorIndex;
  630. do
  631. {
  632. newColorIndex++;
  633. if (newColorIndex >= ShipColors.Length)
  634. {
  635. newColorIndex = 0;
  636. }
  637. colorFound = false;
  638. foreach (NetworkGamer networkGamer in networkSession.AllGamers)
  639. {
  640. PlayerData playerData = networkGamer.Tag as PlayerData;
  641. if ((playerData != null) && (playerData.ShipColor == newColorIndex))
  642. {
  643. colorFound = true;
  644. break;
  645. }
  646. }
  647. }
  648. while (colorFound && (newColorIndex != currentColorIndex));
  649. return newColorIndex;
  650. }
  651. /// <summary>
  652. /// Find the previous unique color index among the players.
  653. /// </summary>
  654. /// <param name="currentColorIndex">The current color index.</param>
  655. /// <param name="networkSession">The network session..</param>
  656. /// <returns>The previous unique color index.</returns>
  657. public static byte GetPreviousUniqueColorIndex(byte currentColorIndex,
  658. NetworkSession networkSession)
  659. {
  660. // safety-check the parameters
  661. if ((currentColorIndex < 0) || (currentColorIndex >= ShipColors.Length))
  662. {
  663. throw new ArgumentOutOfRangeException("currentColorIndex");
  664. }
  665. if (networkSession == null)
  666. {
  667. throw new ArgumentNullException("networkSession");
  668. }
  669. if (networkSession.AllGamers.Count > ShipColors.Length)
  670. {
  671. throw new InvalidOperationException(
  672. "There are more gamers than there are colors.");
  673. }
  674. // if there are as many gamers as there are colors, then we can't change
  675. if (networkSession.AllGamers.Count == ShipColors.Length)
  676. {
  677. return currentColorIndex;
  678. }
  679. bool colorFound;
  680. byte newColorIndex = currentColorIndex;
  681. do
  682. {
  683. if (newColorIndex == 0)
  684. {
  685. newColorIndex = (byte)(ShipColors.Length - 1);
  686. }
  687. else
  688. {
  689. newColorIndex--;
  690. }
  691. colorFound = false;
  692. foreach (NetworkGamer networkGamer in networkSession.AllGamers)
  693. {
  694. PlayerData playerData = networkGamer.Tag as PlayerData;
  695. if ((playerData != null) && (playerData.ShipColor == newColorIndex))
  696. {
  697. colorFound = true;
  698. break;
  699. }
  700. }
  701. }
  702. while (colorFound && (newColorIndex != currentColorIndex));
  703. return newColorIndex;
  704. }
  705. /// <summary>
  706. /// The number of variations in ships.
  707. /// </summary>
  708. public static int Variations
  709. {
  710. get { return variations; }
  711. }
  712. }
  713. }