Hud.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. #region File Description
  2. //-----------------------------------------------------------------------------
  3. // Hud.cs
  4. //
  5. // Microsoft XNA Community Game Platform
  6. // Copyright (C) Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #endregion
  9. #region Using Statements
  10. using System;
  11. using System.Collections.Generic;
  12. using Microsoft.Xna.Framework;
  13. using Microsoft.Xna.Framework.Graphics;
  14. using Microsoft.Xna.Framework.Content;
  15. using RolePlayingGameData;
  16. #endregion
  17. namespace RolePlaying
  18. {
  19. /// <summary>
  20. /// Displays each player's basic statistics and the combat action menu.
  21. /// </summary>
  22. class Hud
  23. {
  24. private ScreenManager screenManager;
  25. public const int HudHeight = 183;
  26. #region Graphics Data
  27. private Texture2D backgroundHudTexture;
  28. private Texture2D topHudTexture;
  29. private Texture2D combatPopupTexture;
  30. private Texture2D activeCharInfoTexture;
  31. private Texture2D inActiveCharInfoTexture;
  32. private Texture2D cantUseCharInfoTexture;
  33. private Texture2D selectionBracketTexture;
  34. private Texture2D menuTexture;
  35. private Texture2D statsTexture;
  36. private Texture2D deadPortraitTexture;
  37. private Texture2D charSelFadeLeftTexture;
  38. private Texture2D charSelFadeRightTexture;
  39. private Texture2D charSelArrowLeftTexture;
  40. private Texture2D charSelArrowRightTexture;
  41. private Texture2D actionTexture;
  42. private Texture2D yButtonTexture;
  43. private Texture2D startButtonTexture;
  44. private Vector2 topHudPosition = new Vector2(353f, 30f);
  45. private Vector2 charSelLeftPosition = new Vector2(70f, 600f);
  46. private Vector2 charSelRightPosition = new Vector2(1170f, 600f);
  47. private Vector2 yButtonPosition = new Vector2(0f, 560f + 20f);
  48. private Vector2 startButtonPosition = new Vector2(0f, 560f + 35f);
  49. private Vector2 yTextPosition = new Vector2(0f, 560f + 70f);
  50. private Vector2 startTextPosition = new Vector2(0f, 560f + 70f);
  51. private Vector2 actionTextPosition = new Vector2(640f, 55f);
  52. private Vector2 backgroundHudPosition = new Vector2(0f, 525f);
  53. private Vector2 portraitPosition = new Vector2(640f, 55f);
  54. private Vector2 startingInfoPosition = new Vector2(0f, 550f);
  55. private Vector2 namePosition;
  56. private Vector2 levelPosition;
  57. private Vector2 detailPosition;
  58. private readonly Color activeNameColor = new Color(200, 200, 200);
  59. private readonly Color inActiveNameColor = new Color(100, 100, 100);
  60. private readonly Color nonSelColor = new Color(86, 26, 5);
  61. private readonly Color selColor = new Color(229, 206, 144);
  62. #endregion
  63. #region Action Text
  64. /// <summary>
  65. /// The text that is shown in the action bar at the top of the combat screen.
  66. /// </summary>
  67. private string actionText = String.Empty;
  68. /// <summary>
  69. /// The text that is shown in the action bar at the top of the combat screen.
  70. /// </summary>
  71. public string ActionText
  72. {
  73. get { return actionText; }
  74. set { actionText = value; }
  75. }
  76. #endregion
  77. #region Initialization
  78. /// <summary>
  79. /// Creates a new Hud object using the given ScreenManager.
  80. /// </summary>
  81. public Hud(ScreenManager screenManager)
  82. {
  83. // check the parameter
  84. if (screenManager == null)
  85. {
  86. throw new ArgumentNullException("screenManager");
  87. }
  88. this.screenManager = screenManager;
  89. }
  90. /// <summary>
  91. /// Load the graphics content from the content manager.
  92. /// </summary>
  93. public void LoadContent()
  94. {
  95. ContentManager content = screenManager.Game.Content;
  96. backgroundHudTexture =
  97. content.Load<Texture2D>(@"Textures\HUD\HudBkgd");
  98. topHudTexture =
  99. content.Load<Texture2D>(@"Textures\HUD\CombatStateInfoStrip");
  100. activeCharInfoTexture =
  101. content.Load<Texture2D>(@"Textures\HUD\PlankActive");
  102. inActiveCharInfoTexture =
  103. content.Load<Texture2D>(@"Textures\HUD\PlankInActive");
  104. cantUseCharInfoTexture =
  105. content.Load<Texture2D>(@"Textures\HUD\PlankCantUse");
  106. selectionBracketTexture =
  107. content.Load<Texture2D>(@"Textures\HUD\SelectionBrackets");
  108. deadPortraitTexture =
  109. content.Load<Texture2D>(@"Textures\Characters\Portraits\Tombstone");
  110. combatPopupTexture =
  111. content.Load<Texture2D>(@"Textures\HUD\CombatPopup");
  112. charSelFadeLeftTexture =
  113. content.Load<Texture2D>(@"Textures\Buttons\CharSelectFadeLeft");
  114. charSelFadeRightTexture =
  115. content.Load<Texture2D>(@"Textures\Buttons\CharSelectFadeRight");
  116. charSelArrowLeftTexture =
  117. content.Load<Texture2D>(@"Textures\Buttons\CharSelectHlLeft");
  118. charSelArrowRightTexture =
  119. content.Load<Texture2D>(@"Textures\Buttons\CharSelectHlRight");
  120. actionTexture =
  121. content.Load<Texture2D>(@"Textures\HUD\HudSelectButton");
  122. yButtonTexture =
  123. content.Load<Texture2D>(@"Textures\Buttons\YButton");
  124. startButtonTexture =
  125. content.Load<Texture2D>(@"Textures\Buttons\StartButton");
  126. menuTexture =
  127. content.Load<Texture2D>(@"Textures\HUD\Menu");
  128. statsTexture =
  129. content.Load<Texture2D>(@"Textures\HUD\Stats");
  130. }
  131. #endregion
  132. #region Drawing
  133. /// <summary>
  134. /// Draw the screen.
  135. /// </summary>
  136. public void Draw()
  137. {
  138. SpriteBatch spriteBatch = screenManager.SpriteBatch;
  139. spriteBatch.Begin();
  140. startingInfoPosition.X = 640f;
  141. startingInfoPosition.X -= Session.Party.Players.Count / 2 * 200f;
  142. if (Session.Party.Players.Count % 2 != 0)
  143. {
  144. startingInfoPosition.X -= 100f;
  145. }
  146. spriteBatch.Draw(backgroundHudTexture, backgroundHudPosition, Color.White);
  147. if (CombatEngine.IsActive)
  148. {
  149. DrawForCombat();
  150. }
  151. else
  152. {
  153. DrawForNonCombat();
  154. }
  155. spriteBatch.End();
  156. }
  157. /// <summary>
  158. /// Draws HUD for Combat Mode
  159. /// </summary>
  160. private void DrawForCombat()
  161. {
  162. SpriteBatch spriteBatch = screenManager.SpriteBatch;
  163. Vector2 position = startingInfoPosition;
  164. foreach (CombatantPlayer combatantPlayer in CombatEngine.Players)
  165. {
  166. DrawCombatPlayerDetails(combatantPlayer, position);
  167. position.X += activeCharInfoTexture.Width - 6f;
  168. }
  169. charSelLeftPosition.X = startingInfoPosition.X - 5f -
  170. charSelArrowLeftTexture.Width;
  171. charSelRightPosition.X = position.X + 5f;
  172. // Draw character Selection Arrows
  173. if (CombatEngine.IsPlayersTurn)
  174. {
  175. spriteBatch.Draw(charSelArrowLeftTexture, charSelLeftPosition,
  176. Color.White);
  177. spriteBatch.Draw(charSelArrowRightTexture, charSelRightPosition,
  178. Color.White);
  179. }
  180. else
  181. {
  182. spriteBatch.Draw(charSelFadeLeftTexture, charSelLeftPosition,
  183. Color.White);
  184. spriteBatch.Draw(charSelFadeRightTexture, charSelRightPosition,
  185. Color.White);
  186. }
  187. if (actionText.Length > 0)
  188. {
  189. spriteBatch.Draw(topHudTexture, topHudPosition, Color.White);
  190. // Draw Action Text
  191. Fonts.DrawCenteredText(spriteBatch, Fonts.PlayerStatisticsFont,
  192. actionText, actionTextPosition, Color.Black);
  193. }
  194. }
  195. /// <summary>
  196. /// Draws HUD for non Combat Mode
  197. /// </summary>
  198. private void DrawForNonCombat()
  199. {
  200. SpriteBatch spriteBatch = screenManager.SpriteBatch;
  201. Vector2 position = startingInfoPosition;
  202. foreach (Player player in Session.Party.Players)
  203. {
  204. DrawNonCombatPlayerDetails(player, position);
  205. position.X += inActiveCharInfoTexture.Width - 6f;
  206. }
  207. yTextPosition.X = position.X + 5f;
  208. yButtonPosition.X = position.X + 9f;
  209. // Draw Select Button
  210. spriteBatch.Draw(statsTexture, yTextPosition, Color.White);
  211. spriteBatch.Draw(yButtonTexture, yButtonPosition, Color.White);
  212. startTextPosition.X = startingInfoPosition.X -
  213. startButtonTexture.Width - 25f;
  214. startButtonPosition.X = startingInfoPosition.X -
  215. startButtonTexture.Width - 10f;
  216. // Draw Back Button
  217. spriteBatch.Draw(menuTexture, startTextPosition, Color.White);
  218. spriteBatch.Draw(startButtonTexture, startButtonPosition, Color.White);
  219. }
  220. enum PlankState
  221. {
  222. Active,
  223. InActive,
  224. CantUse,
  225. }
  226. /// <summary>
  227. /// Draws Player Details
  228. /// </summary>
  229. /// <param name="playerIndex">Index of player details to draw</param>
  230. /// <param name="position">Position where to draw</param>
  231. private void DrawCombatPlayerDetails(CombatantPlayer player, Vector2 position)
  232. {
  233. SpriteBatch spriteBatch = screenManager.SpriteBatch;
  234. PlankState plankState;
  235. bool isPortraitActive = false;
  236. bool isCharDead = false;
  237. Color color;
  238. portraitPosition.X = position.X + 7f;
  239. portraitPosition.Y = position.Y + 7f;
  240. namePosition.X = position.X + 84f;
  241. namePosition.Y = position.Y + 12f;
  242. levelPosition.X = position.X + 84f;
  243. levelPosition.Y = position.Y + 39f;
  244. detailPosition.X = position.X + 25f;
  245. detailPosition.Y = position.Y + 66f;
  246. position.X -= 2;
  247. position.Y -= 4;
  248. if (player.IsTurnTaken)
  249. {
  250. plankState = PlankState.CantUse;
  251. isPortraitActive = false;
  252. }
  253. else
  254. {
  255. plankState = PlankState.InActive;
  256. isPortraitActive = true;
  257. }
  258. if (((CombatEngine.HighlightedCombatant == player) && !player.IsTurnTaken) ||
  259. (CombatEngine.PrimaryTargetedCombatant == player) ||
  260. (CombatEngine.SecondaryTargetedCombatants.Contains(player)))
  261. {
  262. plankState = PlankState.Active;
  263. }
  264. if (player.IsDeadOrDying)
  265. {
  266. isCharDead = true;
  267. isPortraitActive = false;
  268. plankState = PlankState.CantUse;
  269. }
  270. // Draw Info Slab
  271. if (plankState == PlankState.Active)
  272. {
  273. color = activeNameColor;
  274. spriteBatch.Draw(activeCharInfoTexture, position, Color.White);
  275. // Draw Brackets
  276. if ((CombatEngine.HighlightedCombatant == player) && !player.IsTurnTaken)
  277. {
  278. spriteBatch.Draw(selectionBracketTexture, position, Color.White);
  279. }
  280. if (isPortraitActive &&
  281. (CombatEngine.HighlightedCombatant == player) &&
  282. (CombatEngine.HighlightedCombatant.CombatAction == null) &&
  283. !CombatEngine.IsDelaying)
  284. {
  285. position.X += activeCharInfoTexture.Width / 2;
  286. position.X -= combatPopupTexture.Width / 2;
  287. position.Y -= combatPopupTexture.Height;
  288. // Draw Action
  289. DrawActionsMenu(position);
  290. }
  291. }
  292. else if (plankState == PlankState.InActive)
  293. {
  294. color = inActiveNameColor;
  295. spriteBatch.Draw(inActiveCharInfoTexture, position, Color.White);
  296. }
  297. else
  298. {
  299. color = Color.Black;
  300. spriteBatch.Draw(cantUseCharInfoTexture, position, Color.White);
  301. }
  302. if (isCharDead)
  303. {
  304. spriteBatch.Draw(deadPortraitTexture, portraitPosition, Color.White);
  305. }
  306. else
  307. {
  308. // Draw Player Portrait
  309. DrawPortrait(player.Player, portraitPosition, plankState);
  310. }
  311. // Draw Player Name
  312. spriteBatch.DrawString(Fonts.PlayerStatisticsFont,
  313. player.Player.Name,
  314. namePosition, color);
  315. color = Color.Black;
  316. // Draw Player Details
  317. spriteBatch.DrawString(Fonts.HudDetailFont,
  318. "Lvl: " + player.Player.CharacterLevel,
  319. levelPosition, color);
  320. spriteBatch.DrawString(Fonts.HudDetailFont,
  321. "HP: " + player.Statistics.HealthPoints +
  322. "/" + player.Player.CharacterStatistics.HealthPoints,
  323. detailPosition, color);
  324. detailPosition.Y += 30f;
  325. spriteBatch.DrawString(Fonts.HudDetailFont,
  326. "MP: " + player.Statistics.MagicPoints +
  327. "/" + player.Player.CharacterStatistics.MagicPoints,
  328. detailPosition, color);
  329. }
  330. /// <summary>
  331. /// Draws Player Details
  332. /// </summary>
  333. /// <param name="playerIndex">Index of player details to draw</param>
  334. /// <param name="position">Position where to draw</param>
  335. private void DrawNonCombatPlayerDetails(Player player, Vector2 position)
  336. {
  337. SpriteBatch spriteBatch = screenManager.SpriteBatch;
  338. PlankState plankState;
  339. bool isCharDead = false;
  340. Color color;
  341. portraitPosition.X = position.X + 7f;
  342. portraitPosition.Y = position.Y + 7f;
  343. namePosition.X = position.X + 84f;
  344. namePosition.Y = position.Y + 12f;
  345. levelPosition.X = position.X + 84f;
  346. levelPosition.Y = position.Y + 39f;
  347. detailPosition.X = position.X + 25f;
  348. detailPosition.Y = position.Y + 66f;
  349. position.X -= 2;
  350. position.Y -= 4;
  351. plankState = PlankState.Active;
  352. // Draw Info Slab
  353. if (plankState == PlankState.Active)
  354. {
  355. color = activeNameColor;
  356. spriteBatch.Draw(activeCharInfoTexture, position, Color.White);
  357. }
  358. else if (plankState == PlankState.InActive)
  359. {
  360. color = inActiveNameColor;
  361. spriteBatch.Draw(inActiveCharInfoTexture, position, Color.White);
  362. }
  363. else
  364. {
  365. color = Color.Black;
  366. spriteBatch.Draw(cantUseCharInfoTexture, position, Color.White);
  367. }
  368. if (isCharDead)
  369. {
  370. spriteBatch.Draw(deadPortraitTexture, portraitPosition, Color.White);
  371. }
  372. else
  373. {
  374. // Draw Player Portrait
  375. DrawPortrait(player, portraitPosition, plankState);
  376. }
  377. // Draw Player Name
  378. spriteBatch.DrawString(Fonts.PlayerStatisticsFont,
  379. player.Name,
  380. namePosition, color);
  381. color = Color.Black;
  382. // Draw Player Details
  383. spriteBatch.DrawString(Fonts.HudDetailFont,
  384. "Lvl: " + player.CharacterLevel,
  385. levelPosition, color);
  386. spriteBatch.DrawString(Fonts.HudDetailFont,
  387. "HP: " + player.CurrentStatistics.HealthPoints +
  388. "/" + player.CharacterStatistics.HealthPoints,
  389. detailPosition, color);
  390. detailPosition.Y += 30f;
  391. spriteBatch.DrawString(Fonts.HudDetailFont,
  392. "MP: " + player.CurrentStatistics.MagicPoints +
  393. "/" + player.CharacterStatistics.MagicPoints,
  394. detailPosition, color);
  395. }
  396. /// <summary>
  397. /// Draw the portrait of the given player at the given position.
  398. /// </summary>
  399. private void DrawPortrait(Player player, Vector2 position,
  400. PlankState plankState)
  401. {
  402. switch (plankState)
  403. {
  404. case PlankState.Active:
  405. screenManager.SpriteBatch.Draw(player.ActivePortraitTexture,
  406. position, Color.White);
  407. break;
  408. case PlankState.InActive:
  409. screenManager.SpriteBatch.Draw(player.InactivePortraitTexture,
  410. position, Color.White);
  411. break;
  412. case PlankState.CantUse:
  413. screenManager.SpriteBatch.Draw(player.UnselectablePortraitTexture,
  414. position, Color.White);
  415. break;
  416. }
  417. }
  418. #endregion
  419. #region Combat Action Menu
  420. /// <summary>
  421. /// The list of entries in the combat action menu.
  422. /// </summary>
  423. private string[] actionList = new string[5]
  424. {
  425. "Attack",
  426. "Spell",
  427. "Item",
  428. "Defend",
  429. "Flee",
  430. };
  431. /// <summary>
  432. /// The currently highlighted item.
  433. /// </summary>
  434. private int highlightedAction = 0;
  435. /// <summary>
  436. /// Handle user input to the actions menu.
  437. /// </summary>
  438. public void UpdateActionsMenu()
  439. {
  440. // cursor up
  441. if (InputManager.IsActionTriggered(InputManager.Action.CursorUp))
  442. {
  443. if (highlightedAction > 0)
  444. {
  445. highlightedAction--;
  446. }
  447. return;
  448. }
  449. // cursor down
  450. if (InputManager.IsActionTriggered(InputManager.Action.CursorDown))
  451. {
  452. if (highlightedAction < actionList.Length - 1)
  453. {
  454. highlightedAction++;
  455. }
  456. return;
  457. }
  458. // select an action
  459. if (InputManager.IsActionTriggered(InputManager.Action.Ok))
  460. {
  461. switch (actionList[highlightedAction])
  462. {
  463. case "Attack":
  464. {
  465. ActionText = "Performing a Melee Attack";
  466. CombatEngine.HighlightedCombatant.CombatAction =
  467. new MeleeCombatAction(CombatEngine.HighlightedCombatant);
  468. CombatEngine.HighlightedCombatant.CombatAction.Target =
  469. CombatEngine.FirstEnemyTarget;
  470. }
  471. break;
  472. case "Spell":
  473. {
  474. SpellbookScreen spellbookScreen = new SpellbookScreen(
  475. CombatEngine.HighlightedCombatant.Character,
  476. CombatEngine.HighlightedCombatant.Statistics);
  477. spellbookScreen.SpellSelected +=
  478. new SpellbookScreen.SpellSelectedHandler(
  479. spellbookScreen_SpellSelected);
  480. Session.ScreenManager.AddScreen(spellbookScreen);
  481. }
  482. break;
  483. case "Item":
  484. {
  485. InventoryScreen inventoryScreen = new InventoryScreen(true);
  486. inventoryScreen.GearSelected +=
  487. new InventoryScreen.GearSelectedHandler(
  488. inventoryScreen_GearSelected);
  489. Session.ScreenManager.AddScreen(inventoryScreen);
  490. }
  491. break;
  492. case "Defend":
  493. {
  494. ActionText = "Defending";
  495. CombatEngine.HighlightedCombatant.CombatAction =
  496. new DefendCombatAction(
  497. CombatEngine.HighlightedCombatant);
  498. CombatEngine.HighlightedCombatant.CombatAction.Start();
  499. }
  500. break;
  501. case "Flee":
  502. CombatEngine.AttemptFlee();
  503. break;
  504. }
  505. return;
  506. }
  507. }
  508. /// <summary>
  509. /// Recieves the spell from the Spellbook screen and casts it.
  510. /// </summary>
  511. void spellbookScreen_SpellSelected(Spell spell)
  512. {
  513. if (spell != null)
  514. {
  515. ActionText = "Casting " + spell.Name;
  516. CombatEngine.HighlightedCombatant.CombatAction =
  517. new SpellCombatAction(CombatEngine.HighlightedCombatant, spell);
  518. if (spell.IsOffensive)
  519. {
  520. CombatEngine.HighlightedCombatant.CombatAction.Target =
  521. CombatEngine.FirstEnemyTarget;
  522. }
  523. else
  524. {
  525. CombatEngine.HighlightedCombatant.CombatAction.Target =
  526. CombatEngine.HighlightedCombatant;
  527. }
  528. }
  529. }
  530. /// <summary>
  531. /// Receives the item back from the Inventory screen and uses it.
  532. /// </summary>
  533. void inventoryScreen_GearSelected(Gear gear)
  534. {
  535. Item item = gear as Item;
  536. if (item != null)
  537. {
  538. ActionText = "Using " + item.Name;
  539. CombatEngine.HighlightedCombatant.CombatAction =
  540. new ItemCombatAction(CombatEngine.HighlightedCombatant, item);
  541. if (item.IsOffensive)
  542. {
  543. CombatEngine.HighlightedCombatant.CombatAction.Target =
  544. CombatEngine.FirstEnemyTarget;
  545. }
  546. else
  547. {
  548. CombatEngine.HighlightedCombatant.CombatAction.Target =
  549. CombatEngine.HighlightedCombatant;
  550. }
  551. }
  552. }
  553. /// <summary>
  554. /// Draws the combat action menu.
  555. /// </summary>
  556. /// <param name="position">The position of the menu.</param>
  557. private void DrawActionsMenu(Vector2 position)
  558. {
  559. ActionText = "Choose an Action";
  560. SpriteBatch spriteBatch = screenManager.SpriteBatch;
  561. Vector2 arrowPosition;
  562. float height = 25f;
  563. spriteBatch.Draw(combatPopupTexture, position, Color.White);
  564. position.Y += 21f;
  565. arrowPosition = position;
  566. arrowPosition.X += 10f;
  567. arrowPosition.Y += 2f;
  568. arrowPosition.Y += height * (int)highlightedAction;
  569. spriteBatch.Draw(actionTexture, arrowPosition, Color.White);
  570. position.Y += 4f;
  571. position.X += 50f;
  572. // Draw Action Text
  573. for (int i = 0; i < actionList.Length; i++)
  574. {
  575. spriteBatch.DrawString(Fonts.GearInfoFont, actionList[i], position,
  576. i == highlightedAction ? selColor : nonSelColor);
  577. position.Y += height;
  578. }
  579. }
  580. #endregion
  581. }
  582. }