Session.cs 84 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189
  1. //-----------------------------------------------------------------------------
  2. // Session.cs
  3. //
  4. // Microsoft XNA Community Game Platform
  5. // Copyright (C) Microsoft Corporation. All rights reserved.
  6. //-----------------------------------------------------------------------------
  7. using System;
  8. using System.Collections.Generic;
  9. using System.IO;
  10. using System.Linq;
  11. using System.Xml.Linq;
  12. using System.Xml.Serialization;
  13. using Microsoft.Xna.Framework;
  14. using Microsoft.Xna.Framework.Content;
  15. using Microsoft.Xna.Framework.Graphics;
  16. using RolePlaying.Data;
  17. namespace RolePlaying
  18. {
  19. class Session
  20. {
  21. /// <summary>
  22. /// The single Session instance that can be active at a time.
  23. /// </summary>
  24. private static Session singleton;
  25. /// <summary>
  26. /// The party that is playing the game right now.
  27. /// </summary>
  28. private Party party;
  29. /// <summary>
  30. /// The party that is playing the game right now.
  31. /// </summary>
  32. public static Party Party
  33. {
  34. get { return (singleton == null ? null : singleton.party); }
  35. }
  36. /// <summary>
  37. /// Change the current map, arriving at the given portal if any.
  38. /// </summary>
  39. /// <param name="contentName">The asset name of the new map.</param>
  40. /// <param name="originalPortal">The portal from the previous map.</param>
  41. public static void ChangeMap(string contentName, Portal originalPortal)
  42. {
  43. // make sure the content name is valid
  44. string mapContentName = contentName;
  45. if (!mapContentName.StartsWith(@"Maps\"))
  46. {
  47. mapContentName = Path.Combine(@"Maps", mapContentName);
  48. }
  49. // check for trivial movement - typically intra-map portals
  50. if ((TileEngine.Map != null) && (TileEngine.Map.AssetName == mapContentName))
  51. {
  52. TileEngine.SetMap(TileEngine.Map, originalPortal == null ? null :
  53. TileEngine.Map.FindPortal(originalPortal.DestinationMapPortalName));
  54. }
  55. // load the map
  56. ContentManager content = singleton.screenManager.Game.Content;
  57. //Map map = content.Load<Map>(mapContentName).Clone() as Map;
  58. var map = Map.Load(mapContentName, content);
  59. // modify the map based on the world changes (removed chests, etc.).
  60. singleton.ModifyMap(map);
  61. // start playing the music for the new map
  62. AudioManager.PlayMusic(map.MusicCueName);
  63. // set the new map into the tile engine
  64. TileEngine.SetMap(map, originalPortal == null ? null :
  65. map.FindPortal(originalPortal.DestinationMapPortalName));
  66. }
  67. /// <summary>
  68. /// Perform any actions associated withe the given tile.
  69. /// </summary>
  70. /// <param name="mapPosition">The tile to check.</param>
  71. /// <returns>True if anything was encountered, false otherwise.</returns>
  72. public static bool EncounterTile(Point mapPosition)
  73. {
  74. // look for fixed-combats from the quest
  75. if ((singleton.quest != null) &&
  76. ((singleton.quest.Stage == Quest.QuestStage.InProgress) ||
  77. (singleton.quest.Stage == Quest.QuestStage.RequirementsMet)))
  78. {
  79. MapEntry<FixedCombat> fixedCombatEntry =
  80. singleton.quest.FixedCombatEntries.Find(
  81. delegate (WorldEntry<FixedCombat> worldEntry)
  82. {
  83. return
  84. TileEngine.Map.AssetName.EndsWith(
  85. worldEntry.MapContentName) &&
  86. worldEntry.MapPosition == mapPosition;
  87. });
  88. if (fixedCombatEntry != null)
  89. {
  90. Session.EncounterFixedCombat(fixedCombatEntry);
  91. return true;
  92. }
  93. }
  94. // look for fixed-combats from the map
  95. MapEntry<FixedCombat> fixedCombatMapEntry =
  96. TileEngine.Map.FixedCombatEntries.Find(
  97. delegate (MapEntry<FixedCombat> mapEntry)
  98. {
  99. return mapEntry.MapPosition == mapPosition;
  100. });
  101. if (fixedCombatMapEntry != null)
  102. {
  103. Session.EncounterFixedCombat(fixedCombatMapEntry);
  104. return true;
  105. }
  106. // look for chests from the current quest
  107. if (singleton.quest != null)
  108. {
  109. MapEntry<Chest> chestEntry = singleton.quest.ChestEntries.Find(
  110. delegate (WorldEntry<Chest> worldEntry)
  111. {
  112. return
  113. TileEngine.Map.AssetName.EndsWith(
  114. worldEntry.MapContentName) &&
  115. worldEntry.MapPosition == mapPosition;
  116. });
  117. if (chestEntry != null)
  118. {
  119. Session.EncounterChest(chestEntry);
  120. return true;
  121. }
  122. }
  123. // look for chests from the map
  124. MapEntry<Chest> chestMapEntry =
  125. TileEngine.Map.ChestEntries.Find(delegate (MapEntry<Chest> mapEntry)
  126. {
  127. return mapEntry.MapPosition == mapPosition;
  128. });
  129. if (chestMapEntry != null)
  130. {
  131. Session.EncounterChest(chestMapEntry);
  132. return true;
  133. }
  134. // look for player NPCs from the map
  135. MapEntry<Player> playerNpcEntry =
  136. TileEngine.Map.PlayerNpcEntries.Find(delegate (MapEntry<Player> mapEntry)
  137. {
  138. return mapEntry.MapPosition == mapPosition;
  139. });
  140. if (playerNpcEntry != null)
  141. {
  142. Session.EncounterPlayerNpc(playerNpcEntry);
  143. return true;
  144. }
  145. // look for quest NPCs from the map
  146. MapEntry<QuestNpc> questNpcEntry =
  147. TileEngine.Map.QuestNpcEntries.Find(delegate (MapEntry<QuestNpc> mapEntry)
  148. {
  149. return mapEntry.MapPosition == mapPosition;
  150. });
  151. if (questNpcEntry != null)
  152. {
  153. Session.EncounterQuestNpc(questNpcEntry);
  154. return true;
  155. }
  156. // look for portals from the map
  157. MapEntry<Portal> portalEntry =
  158. TileEngine.Map.PortalEntries.Find(delegate (MapEntry<Portal> mapEntry)
  159. {
  160. return mapEntry.MapPosition == mapPosition;
  161. });
  162. if (portalEntry != null)
  163. {
  164. Session.EncounterPortal(portalEntry);
  165. return true;
  166. }
  167. // look for inns from the map
  168. MapEntry<Inn> innEntry =
  169. TileEngine.Map.InnEntries.Find(delegate (MapEntry<Inn> mapEntry)
  170. {
  171. return mapEntry.MapPosition == mapPosition;
  172. });
  173. if (innEntry != null)
  174. {
  175. Session.EncounterInn(innEntry);
  176. return true;
  177. }
  178. // look for stores from the map
  179. MapEntry<Store> storeEntry =
  180. TileEngine.Map.StoreEntries.Find(delegate (MapEntry<Store> mapEntry)
  181. {
  182. return mapEntry.MapPosition == mapPosition;
  183. });
  184. if (storeEntry != null)
  185. {
  186. Session.EncounterStore(storeEntry);
  187. return true;
  188. }
  189. // nothing encountered
  190. return false;
  191. }
  192. /// <summary>
  193. /// Performs the actions associated with encountering a FixedCombat entry.
  194. /// </summary>
  195. public static void EncounterFixedCombat(MapEntry<FixedCombat> fixedCombatEntry)
  196. {
  197. // check the parameter
  198. if ((fixedCombatEntry == null) || (fixedCombatEntry.Content == null))
  199. {
  200. throw new ArgumentNullException("fixedCombatEntry");
  201. }
  202. if (!CombatEngine.IsActive)
  203. {
  204. // start combat
  205. CombatEngine.StartNewCombat(fixedCombatEntry);
  206. }
  207. }
  208. /// <summary>
  209. /// Performs the actions associated with encountering a Chest entry.
  210. /// </summary>
  211. public static void EncounterChest(MapEntry<Chest> chestEntry)
  212. {
  213. // check the parameter
  214. if ((chestEntry == null) || (chestEntry.Content == null))
  215. {
  216. throw new ArgumentNullException("chestEntry");
  217. }
  218. // add the chest screen
  219. singleton.screenManager.AddScreen(new ChestScreen(chestEntry));
  220. }
  221. /// <summary>
  222. /// Performs the actions associated with encountering a player-NPC entry.
  223. /// </summary>
  224. public static void EncounterPlayerNpc(MapEntry<Player> playerEntry)
  225. {
  226. // check the parameter
  227. if ((playerEntry == null) || (playerEntry.Content == null))
  228. {
  229. throw new ArgumentNullException("playerEntry");
  230. }
  231. // add the player-NPC screen
  232. singleton.screenManager.AddScreen(new PlayerNpcScreen(playerEntry));
  233. }
  234. /// <summary>
  235. /// Performs the actions associated with encountering a QuestNpc entry.
  236. /// </summary>
  237. public static void EncounterQuestNpc(MapEntry<QuestNpc> questNpcEntry)
  238. {
  239. // check the parameter
  240. if ((questNpcEntry == null) || (questNpcEntry.Content == null))
  241. {
  242. throw new ArgumentNullException("questNpcEntry");
  243. }
  244. // add the quest-NPC screen
  245. singleton.screenManager.AddScreen(new QuestNpcScreen(questNpcEntry));
  246. }
  247. /// <summary>
  248. /// Performs the actions associated with encountering an Inn entry.
  249. /// </summary>
  250. public static void EncounterInn(MapEntry<Inn> innEntry)
  251. {
  252. // check the parameter
  253. if ((innEntry == null) || (innEntry.Content == null))
  254. {
  255. throw new ArgumentNullException("innEntry");
  256. }
  257. // add the inn screen
  258. singleton.screenManager.AddScreen(new InnScreen(innEntry.Content));
  259. }
  260. /// <summary>
  261. /// Performs the actions associated with encountering a Store entry.
  262. /// </summary>
  263. public static void EncounterStore(MapEntry<Store> storeEntry)
  264. {
  265. // check the parameter
  266. if ((storeEntry == null) || (storeEntry.Content == null))
  267. {
  268. throw new ArgumentNullException("storeEntry");
  269. }
  270. // add the store screen
  271. singleton.screenManager.AddScreen(new StoreScreen(storeEntry.Content));
  272. }
  273. /// <summary>
  274. /// Performs the actions associated with encountering a Portal entry.
  275. /// </summary>
  276. public static void EncounterPortal(MapEntry<Portal> portalEntry)
  277. {
  278. // check the parameter
  279. if ((portalEntry == null) || (portalEntry.Content == null))
  280. {
  281. throw new ArgumentNullException("portalEntry");
  282. }
  283. // change to the new map
  284. ChangeMap(portalEntry.Content.DestinationMapContentName,
  285. portalEntry.Content);
  286. }
  287. /// <summary>
  288. /// Check if a random combat should start. If so, start combat immediately.
  289. /// </summary>
  290. /// <returns>True if combat was started, false otherwise.</returns>
  291. public static bool CheckForRandomCombat(RandomCombat randomCombat)
  292. {
  293. // check the parameter
  294. if ((randomCombat == null) || (randomCombat.CombatProbability <= 0))
  295. {
  296. return false;
  297. }
  298. // check to see if combat has already started
  299. if (CombatEngine.IsActive)
  300. {
  301. return false;
  302. }
  303. // check to see if the random combat starts
  304. int randomCombatCheck = random.Next(100);
  305. if (randomCombatCheck < randomCombat.CombatProbability)
  306. {
  307. // start combat immediately
  308. CombatEngine.StartNewCombat(randomCombat);
  309. return true;
  310. }
  311. // combat not started
  312. return false;
  313. }
  314. /// <summary>
  315. /// The main quest line for this session.
  316. /// </summary>
  317. private QuestLine questLine;
  318. /// <summary>
  319. /// The main quest line for this session.
  320. /// </summary>
  321. public static QuestLine QuestLine
  322. {
  323. get { return (singleton == null ? null : singleton.questLine); }
  324. }
  325. /// <summary>
  326. /// If true, the main quest line for this session is complete.
  327. /// </summary>
  328. public static bool IsQuestLineComplete
  329. {
  330. get
  331. {
  332. if ((singleton == null) || (singleton.questLine == null) ||
  333. (singleton.questLine.QuestContentNames == null))
  334. {
  335. return false;
  336. }
  337. return singleton.currentQuestIndex >=
  338. singleton.questLine.QuestContentNames.Count;
  339. }
  340. }
  341. /// <summary>
  342. /// The current quest in this session.
  343. /// </summary>
  344. private Quest quest;
  345. /// <summary>
  346. /// The current quest in this session.
  347. /// </summary>
  348. public static Quest Quest
  349. {
  350. get { return (singleton == null ? null : singleton.quest); }
  351. }
  352. /// <summary>
  353. /// The index of the current quest into the quest line.
  354. /// </summary>
  355. private int currentQuestIndex = 0;
  356. /// <summary>
  357. /// The index of the current quest into the quest line.
  358. /// </summary>
  359. public static int CurrentQuestIndex
  360. {
  361. get { return (singleton == null ? -1 : singleton.currentQuestIndex); }
  362. }
  363. /// <summary>
  364. /// Update the current quest and quest line for this session.
  365. /// </summary>
  366. public void UpdateQuest()
  367. {
  368. // check the singleton's state to see if we should care about quests
  369. if ((party == null) || (questLine == null))
  370. {
  371. return;
  372. }
  373. // if we don't have a quest, then take the next one from teh list
  374. if ((quest == null) && (questLine.Quests.Count > 0) &&
  375. !Session.IsQuestLineComplete)
  376. {
  377. quest = questLine.Quests[currentQuestIndex];
  378. quest.Stage = Quest.QuestStage.NotStarted;
  379. // clear the monster-kill record
  380. party.MonsterKills.Clear();
  381. // clear the modified-quest lists
  382. modifiedQuestChests.Clear();
  383. removedQuestChests.Clear();
  384. removedQuestFixedCombats.Clear();
  385. }
  386. // handle quest-stage transitions
  387. if ((quest != null) && !Session.IsQuestLineComplete)
  388. {
  389. switch (quest.Stage)
  390. {
  391. case Quest.QuestStage.NotStarted:
  392. // start the new quest
  393. quest.Stage = Quest.QuestStage.InProgress;
  394. if (!quest.AreRequirementsMet)
  395. {
  396. // show the announcement of the quest and the requirements
  397. ScreenManager.AddScreen(new QuestLogScreen(quest));
  398. }
  399. break;
  400. case Quest.QuestStage.InProgress:
  401. // update monster requirements
  402. foreach (QuestRequirement<Monster> monsterRequirement in
  403. quest.MonsterRequirements)
  404. {
  405. monsterRequirement.CompletedCount = 0;
  406. Monster monster = monsterRequirement.Content;
  407. if (party.MonsterKills.ContainsKey(monster.AssetName))
  408. {
  409. monsterRequirement.CompletedCount =
  410. party.MonsterKills[monster.AssetName];
  411. }
  412. }
  413. // update gear requirements
  414. foreach (QuestRequirement<Gear> gearRequirement in
  415. quest.GearRequirements)
  416. {
  417. gearRequirement.CompletedCount = 0;
  418. foreach (ContentEntry<Gear> entry in party.Inventory)
  419. {
  420. if (entry.Content == gearRequirement.Content)
  421. {
  422. gearRequirement.CompletedCount += entry.Count;
  423. }
  424. }
  425. }
  426. // check to see if the requirements have been met
  427. if (quest.AreRequirementsMet)
  428. {
  429. // immediately remove the gear
  430. foreach (QuestRequirement<Gear> gearRequirement in
  431. quest.GearRequirements)
  432. {
  433. Gear gear = gearRequirement.Content;
  434. party.RemoveFromInventory(gear,
  435. gearRequirement.Count);
  436. }
  437. // check to see if there is a destination
  438. if (String.IsNullOrEmpty(
  439. quest.DestinationMapContentName))
  440. {
  441. // complete the quest
  442. quest.Stage = Quest.QuestStage.Completed;
  443. // show the completion dialogue
  444. if (!String.IsNullOrEmpty(quest.CompletionMessage))
  445. {
  446. DialogueScreen dialogueScreen = new DialogueScreen();
  447. dialogueScreen.TitleText = "Quest Complete";
  448. dialogueScreen.BackText = String.Empty;
  449. dialogueScreen.DialogueText =
  450. quest.CompletionMessage;
  451. ScreenManager.AddScreen(dialogueScreen);
  452. }
  453. }
  454. else
  455. {
  456. quest.Stage = Quest.QuestStage.RequirementsMet;
  457. // remind the player about the destination
  458. screenManager.AddScreen(new QuestLogScreen(quest));
  459. }
  460. }
  461. break;
  462. case Quest.QuestStage.RequirementsMet:
  463. break;
  464. case Quest.QuestStage.Completed:
  465. // show the quest rewards screen
  466. RewardsScreen rewardsScreen =
  467. new RewardsScreen(RewardsScreen.RewardScreenMode.Quest,
  468. Quest.ExperienceReward, Quest.GoldReward, Quest.GearRewards);
  469. screenManager.AddScreen(rewardsScreen);
  470. // advance to the next quest
  471. currentQuestIndex++;
  472. quest = null;
  473. break;
  474. }
  475. }
  476. }
  477. /// <summary>
  478. /// The chests removed from the map asset by player actions.
  479. /// </summary>
  480. private List<WorldEntry<Chest>> removedMapChests =
  481. new List<WorldEntry<Chest>>();
  482. /// <summary>
  483. /// The chests removed from the current quest asset by player actions.
  484. /// </summary>
  485. private List<WorldEntry<Chest>> removedQuestChests =
  486. new List<WorldEntry<Chest>>();
  487. /// <summary>
  488. /// Remove the given chest entry from the current map or quest.
  489. /// </summary>
  490. public static void RemoveChest(MapEntry<Chest> mapEntry)
  491. {
  492. // check the parameter
  493. if (mapEntry == null)
  494. {
  495. return;
  496. }
  497. // check the map for the item first
  498. if (TileEngine.Map != null)
  499. {
  500. int removedEntries = TileEngine.Map.ChestEntries.RemoveAll(
  501. delegate (MapEntry<Chest> entry)
  502. {
  503. return ((entry.ContentName == mapEntry.ContentName) &&
  504. (entry.MapPosition == mapEntry.MapPosition));
  505. });
  506. if (removedEntries > 0)
  507. {
  508. WorldEntry<Chest> worldEntry = new WorldEntry<Chest>();
  509. worldEntry.Content = mapEntry.Content;
  510. worldEntry.ContentName = mapEntry.ContentName;
  511. worldEntry.Count = mapEntry.Count;
  512. worldEntry.Direction = mapEntry.Direction;
  513. worldEntry.MapContentName = TileEngine.Map.AssetName;
  514. worldEntry.MapPosition = mapEntry.MapPosition;
  515. singleton.removedMapChests.Add(worldEntry);
  516. return;
  517. }
  518. }
  519. // look for the map entry within the quest
  520. if (singleton.quest != null)
  521. {
  522. int removedEntries = singleton.quest.ChestEntries.RemoveAll(
  523. delegate (WorldEntry<Chest> entry)
  524. {
  525. return ((entry.ContentName == mapEntry.ContentName) &&
  526. (entry.MapPosition == mapEntry.MapPosition) &&
  527. TileEngine.Map.AssetName.EndsWith(entry.MapContentName));
  528. });
  529. if (removedEntries > 0)
  530. {
  531. WorldEntry<Chest> worldEntry = new WorldEntry<Chest>();
  532. worldEntry.Content = mapEntry.Content;
  533. worldEntry.ContentName = mapEntry.ContentName;
  534. worldEntry.Count = mapEntry.Count;
  535. worldEntry.Direction = mapEntry.Direction;
  536. worldEntry.MapContentName = TileEngine.Map.AssetName;
  537. worldEntry.MapPosition = mapEntry.MapPosition;
  538. singleton.removedQuestChests.Add(worldEntry);
  539. return;
  540. }
  541. }
  542. }
  543. /// <summary>
  544. /// The fixed-combats removed from the map asset by player actions.
  545. /// </summary>
  546. private List<WorldEntry<FixedCombat>> removedMapFixedCombats =
  547. new List<WorldEntry<FixedCombat>>();
  548. /// <summary>
  549. /// The fixed-combats removed from the current quest asset by player actions.
  550. /// </summary>
  551. private List<WorldEntry<FixedCombat>> removedQuestFixedCombats =
  552. new List<WorldEntry<FixedCombat>>();
  553. /// <summary>
  554. /// Remove the given fixed-combat entry from the current map or quest.
  555. /// </summary>
  556. public static void RemoveFixedCombat(MapEntry<FixedCombat> mapEntry)
  557. {
  558. // check the parameter
  559. if (mapEntry == null)
  560. {
  561. return;
  562. }
  563. // check the map for the item first
  564. if (TileEngine.Map != null)
  565. {
  566. int removedEntries = TileEngine.Map.FixedCombatEntries.RemoveAll(
  567. delegate (MapEntry<FixedCombat> entry)
  568. {
  569. return ((entry.ContentName == mapEntry.ContentName) &&
  570. (entry.MapPosition == mapEntry.MapPosition));
  571. });
  572. if (removedEntries > 0)
  573. {
  574. WorldEntry<FixedCombat> worldEntry = new WorldEntry<FixedCombat>();
  575. worldEntry.Content = mapEntry.Content;
  576. worldEntry.ContentName = mapEntry.ContentName;
  577. worldEntry.Count = mapEntry.Count;
  578. worldEntry.Direction = mapEntry.Direction;
  579. worldEntry.MapContentName = TileEngine.Map.AssetName;
  580. worldEntry.MapPosition = mapEntry.MapPosition;
  581. singleton.removedMapFixedCombats.Add(worldEntry);
  582. return;
  583. }
  584. }
  585. // look for the map entry within the quest
  586. if (singleton.quest != null)
  587. {
  588. int removedEntries = singleton.quest.FixedCombatEntries.RemoveAll(
  589. delegate (WorldEntry<FixedCombat> entry)
  590. {
  591. return ((entry.ContentName == mapEntry.ContentName) &&
  592. (entry.MapPosition == mapEntry.MapPosition) &&
  593. TileEngine.Map.AssetName.EndsWith(entry.MapContentName));
  594. });
  595. if (removedEntries > 0)
  596. {
  597. WorldEntry<FixedCombat> worldEntry = new WorldEntry<FixedCombat>();
  598. worldEntry.Content = mapEntry.Content;
  599. worldEntry.ContentName = mapEntry.ContentName;
  600. worldEntry.Count = mapEntry.Count;
  601. worldEntry.Direction = mapEntry.Direction;
  602. worldEntry.MapContentName = TileEngine.Map.AssetName;
  603. worldEntry.MapPosition = mapEntry.MapPosition;
  604. singleton.removedQuestFixedCombats.Add(worldEntry);
  605. return;
  606. }
  607. }
  608. }
  609. /// <summary>
  610. /// The player NPCs removed from the map asset by player actions.
  611. /// </summary>
  612. private List<WorldEntry<Player>> removedMapPlayerNpcs =
  613. new List<WorldEntry<Player>>();
  614. /// <summary>
  615. /// Remove the given player NPC entry from the current map or quest.
  616. /// </summary>
  617. public static void RemovePlayerNpc(MapEntry<Player> mapEntry)
  618. {
  619. // check the parameter
  620. if (mapEntry == null)
  621. {
  622. return;
  623. }
  624. // check the map for the item
  625. if (TileEngine.Map != null)
  626. {
  627. int removedEntries = TileEngine.Map.PlayerNpcEntries.RemoveAll(
  628. delegate (MapEntry<Player> entry)
  629. {
  630. return ((entry.ContentName == mapEntry.ContentName) &&
  631. (entry.MapPosition == mapEntry.MapPosition));
  632. });
  633. if (removedEntries > 0)
  634. {
  635. WorldEntry<Player> worldEntry = new WorldEntry<Player>();
  636. worldEntry.Content = mapEntry.Content;
  637. worldEntry.ContentName = mapEntry.ContentName;
  638. worldEntry.Count = mapEntry.Count;
  639. worldEntry.Direction = mapEntry.Direction;
  640. worldEntry.MapContentName = TileEngine.Map.AssetName;
  641. worldEntry.MapPosition = mapEntry.MapPosition;
  642. singleton.removedMapPlayerNpcs.Add(worldEntry);
  643. return;
  644. }
  645. }
  646. // quests don't have a list of player NPCs
  647. }
  648. /// <summary>
  649. /// The chests that have been modified, but not emptied, by player action.
  650. /// </summary>
  651. private List<ModifiedChestEntry> modifiedMapChests =
  652. new List<ModifiedChestEntry>();
  653. /// <summary>
  654. /// The chests belonging to the current quest that have been modified,
  655. /// but not emptied, by player action.
  656. /// </summary>
  657. private List<ModifiedChestEntry> modifiedQuestChests =
  658. new List<ModifiedChestEntry>();
  659. /// <summary>
  660. /// Stores the entry for a chest on the current map or quest that has been
  661. /// modified but not emptied.
  662. /// </summary>
  663. public static void StoreModifiedChest(MapEntry<Chest> mapEntry)
  664. {
  665. // check the parameter
  666. if ((mapEntry == null) || (mapEntry.Content == null))
  667. {
  668. throw new ArgumentNullException("mapEntry");
  669. }
  670. Predicate<ModifiedChestEntry> checkModifiedChests =
  671. delegate (ModifiedChestEntry entry)
  672. {
  673. return
  674. (TileEngine.Map.AssetName.EndsWith(
  675. entry.WorldEntry.MapContentName) &&
  676. (entry.WorldEntry.ContentName == mapEntry.ContentName) &&
  677. (entry.WorldEntry.MapPosition == mapEntry.MapPosition));
  678. };
  679. // check the map for the item first
  680. if ((TileEngine.Map != null) && TileEngine.Map.ChestEntries.Exists(
  681. delegate (MapEntry<Chest> entry)
  682. {
  683. return ((entry.ContentName == mapEntry.ContentName) &&
  684. (entry.MapPosition == mapEntry.MapPosition));
  685. }))
  686. {
  687. singleton.modifiedMapChests.RemoveAll(checkModifiedChests);
  688. ModifiedChestEntry modifiedChestEntry = new ModifiedChestEntry();
  689. modifiedChestEntry.WorldEntry.Content = mapEntry.Content;
  690. modifiedChestEntry.WorldEntry.ContentName = mapEntry.ContentName;
  691. modifiedChestEntry.WorldEntry.Count = mapEntry.Count;
  692. modifiedChestEntry.WorldEntry.Direction = mapEntry.Direction;
  693. modifiedChestEntry.WorldEntry.MapContentName =
  694. TileEngine.Map.AssetName;
  695. modifiedChestEntry.WorldEntry.MapPosition = mapEntry.MapPosition;
  696. Chest chest = mapEntry.Content;
  697. modifiedChestEntry.ChestEntries.AddRange(chest.Entries);
  698. modifiedChestEntry.Gold = chest.Gold;
  699. singleton.modifiedMapChests.Add(modifiedChestEntry);
  700. return;
  701. }
  702. // look for the map entry within the quest
  703. if ((singleton.quest != null) && singleton.quest.ChestEntries.Exists(
  704. delegate (WorldEntry<Chest> entry)
  705. {
  706. return ((entry.ContentName == mapEntry.ContentName) &&
  707. (entry.MapPosition == mapEntry.MapPosition) &&
  708. TileEngine.Map.AssetName.EndsWith(entry.MapContentName));
  709. }))
  710. {
  711. singleton.modifiedQuestChests.RemoveAll(checkModifiedChests);
  712. ModifiedChestEntry modifiedChestEntry = new ModifiedChestEntry();
  713. modifiedChestEntry.WorldEntry.Content = mapEntry.Content;
  714. modifiedChestEntry.WorldEntry.ContentName = mapEntry.ContentName;
  715. modifiedChestEntry.WorldEntry.Count = mapEntry.Count;
  716. modifiedChestEntry.WorldEntry.Direction = mapEntry.Direction;
  717. modifiedChestEntry.WorldEntry.MapContentName = TileEngine.Map.AssetName;
  718. modifiedChestEntry.WorldEntry.MapPosition = mapEntry.MapPosition;
  719. Chest chest = mapEntry.Content;
  720. modifiedChestEntry.ChestEntries.AddRange(chest.Entries);
  721. modifiedChestEntry.Gold = chest.Gold;
  722. singleton.modifiedQuestChests.Add(modifiedChestEntry);
  723. return;
  724. }
  725. }
  726. /// <summary>
  727. /// Remove the specified content from the map, typically from an earlier session.
  728. /// </summary>
  729. private void ModifyMap(Map map)
  730. {
  731. // check the parameter
  732. if (map == null)
  733. {
  734. throw new ArgumentNullException("map");
  735. }
  736. // remove all chests that were emptied already
  737. if ((removedMapChests != null) && (removedMapChests.Count > 0))
  738. {
  739. // check each removed-content entry
  740. map.ChestEntries.RemoveAll(delegate (MapEntry<Chest> mapEntry)
  741. {
  742. return (removedMapChests.Exists(
  743. delegate (WorldEntry<Chest> removedEntry)
  744. {
  745. return
  746. (map.AssetName.EndsWith(removedEntry.MapContentName) &&
  747. (removedEntry.ContentName == mapEntry.ContentName) &&
  748. (removedEntry.MapPosition == mapEntry.MapPosition));
  749. }));
  750. });
  751. }
  752. // remove all fixed-combats that were defeated already
  753. if ((removedMapFixedCombats != null) && (removedMapFixedCombats.Count > 0))
  754. {
  755. // check each removed-content entry
  756. map.FixedCombatEntries.RemoveAll(delegate (MapEntry<FixedCombat> mapEntry)
  757. {
  758. return (removedMapFixedCombats.Exists(
  759. delegate (WorldEntry<FixedCombat> removedEntry)
  760. {
  761. return
  762. (map.AssetName.EndsWith(removedEntry.MapContentName) &&
  763. (removedEntry.ContentName == mapEntry.ContentName) &&
  764. (removedEntry.MapPosition == mapEntry.MapPosition));
  765. }));
  766. });
  767. }
  768. // remove the player NPCs that have already joined the party
  769. if ((removedMapPlayerNpcs != null) && (removedMapPlayerNpcs.Count > 0))
  770. {
  771. // check each removed-content entry
  772. map.PlayerNpcEntries.RemoveAll(delegate (MapEntry<Player> mapEntry)
  773. {
  774. return (removedMapPlayerNpcs.Exists(
  775. delegate (WorldEntry<Player> removedEntry)
  776. {
  777. return
  778. (map.AssetName.EndsWith(removedEntry.MapContentName) &&
  779. (removedEntry.ContentName == mapEntry.ContentName) &&
  780. (removedEntry.MapPosition == mapEntry.MapPosition));
  781. }));
  782. });
  783. }
  784. // replace the chest entries of modified chests - they are already clones
  785. if ((modifiedMapChests != null) && (modifiedMapChests.Count > 0))
  786. {
  787. foreach (MapEntry<Chest> entry in map.ChestEntries)
  788. {
  789. ModifiedChestEntry modifiedEntry = modifiedMapChests.Find(
  790. delegate (ModifiedChestEntry modifiedTestEntry)
  791. {
  792. return
  793. (map.AssetName.EndsWith(
  794. modifiedTestEntry.WorldEntry.MapContentName) &&
  795. (modifiedTestEntry.WorldEntry.ContentName ==
  796. entry.ContentName) &&
  797. (modifiedTestEntry.WorldEntry.MapPosition ==
  798. entry.MapPosition));
  799. });
  800. // if the chest has been modified, apply the changes
  801. if (modifiedEntry != null)
  802. {
  803. ModifyChest(entry.Content, modifiedEntry);
  804. }
  805. }
  806. }
  807. }
  808. /// <summary>
  809. /// Remove the specified content from the map, typically from an earlier session.
  810. /// </summary>
  811. private void ModifyQuest(Quest quest)
  812. {
  813. // check the parameter
  814. if (quest == null)
  815. {
  816. throw new ArgumentNullException("quest");
  817. }
  818. // remove all chests that were emptied arleady
  819. if ((removedQuestChests != null) && (removedQuestChests.Count > 0))
  820. {
  821. // check each removed-content entry
  822. quest.ChestEntries.RemoveAll(
  823. delegate (WorldEntry<Chest> worldEntry)
  824. {
  825. return (removedQuestChests.Exists(
  826. delegate (WorldEntry<Chest> removedEntry)
  827. {
  828. return
  829. (removedEntry.MapContentName.EndsWith(
  830. worldEntry.MapContentName) &&
  831. (removedEntry.ContentName ==
  832. worldEntry.ContentName) &&
  833. (removedEntry.MapPosition ==
  834. worldEntry.MapPosition));
  835. }));
  836. });
  837. }
  838. // remove all of the fixed-combats that have already been defeated
  839. if ((removedQuestFixedCombats != null) &&
  840. (removedQuestFixedCombats.Count > 0))
  841. {
  842. // check each removed-content entry
  843. quest.FixedCombatEntries.RemoveAll(
  844. delegate (WorldEntry<FixedCombat> worldEntry)
  845. {
  846. return (removedQuestFixedCombats.Exists(
  847. delegate (WorldEntry<FixedCombat> removedEntry)
  848. {
  849. return
  850. (removedEntry.MapContentName.EndsWith(
  851. worldEntry.MapContentName) &&
  852. (removedEntry.ContentName ==
  853. worldEntry.ContentName) &&
  854. (removedEntry.MapPosition ==
  855. worldEntry.MapPosition));
  856. }));
  857. });
  858. }
  859. // replace the chest entries of modified chests - they are already clones
  860. if ((modifiedQuestChests != null) && (modifiedQuestChests.Count > 0))
  861. {
  862. foreach (WorldEntry<Chest> entry in quest.ChestEntries)
  863. {
  864. ModifiedChestEntry modifiedEntry = modifiedQuestChests.Find(
  865. delegate (ModifiedChestEntry modifiedTestEntry)
  866. {
  867. return
  868. ((modifiedTestEntry.WorldEntry.MapContentName ==
  869. entry.MapContentName) &&
  870. (modifiedTestEntry.WorldEntry.ContentName ==
  871. entry.ContentName) &&
  872. (modifiedTestEntry.WorldEntry.MapPosition ==
  873. entry.MapPosition));
  874. });
  875. // if the chest has been modified, apply the changes
  876. if (modifiedEntry != null)
  877. {
  878. ModifyChest(entry.Content, modifiedEntry);
  879. }
  880. }
  881. }
  882. }
  883. /// <summary>
  884. /// Modify a Chest object based on the data in a ModifiedChestEntry object.
  885. /// </summary>
  886. private void ModifyChest(Chest chest, ModifiedChestEntry modifiedChestEntry)
  887. {
  888. // check the parameters
  889. if ((chest == null) || (modifiedChestEntry == null))
  890. {
  891. return;
  892. }
  893. // set the new gold amount
  894. chest.Gold = modifiedChestEntry.Gold;
  895. // remove all contents not found in the modified version
  896. chest.Entries.RemoveAll(delegate (ContentEntry<Gear> contentEntry)
  897. {
  898. return !modifiedChestEntry.ChestEntries.Exists(
  899. delegate (ContentEntry<Gear> modifiedTestEntry)
  900. {
  901. return (contentEntry.ContentName ==
  902. modifiedTestEntry.ContentName);
  903. });
  904. });
  905. // set the new counts on the remaining content items
  906. foreach (ContentEntry<Gear> contentEntry in chest.Entries)
  907. {
  908. ContentEntry<Gear> modifiedGearEntry =
  909. modifiedChestEntry.ChestEntries.Find(
  910. delegate (ContentEntry<Gear> modifiedTestEntry)
  911. {
  912. return (contentEntry.ContentName ==
  913. modifiedTestEntry.ContentName);
  914. });
  915. if (modifiedGearEntry != null)
  916. {
  917. contentEntry.Count = modifiedGearEntry.Count;
  918. }
  919. }
  920. }
  921. /// <summary>
  922. /// The ScreenManager used to manage all UI in the game.
  923. /// </summary>
  924. private ScreenManager screenManager;
  925. /// <summary>
  926. /// The ScreenManager used to manage all UI in the game.
  927. /// </summary>
  928. public static ScreenManager ScreenManager
  929. {
  930. get { return (singleton == null ? null : singleton.screenManager); }
  931. }
  932. /// <summary>
  933. /// The GameplayScreen object that created this session.
  934. /// </summary>
  935. private GameplayScreen gameplayScreen;
  936. /// <summary>
  937. /// The heads-up-display menu shown on the map and combat screens.
  938. /// </summary>
  939. private Hud hud;
  940. /// <summary>
  941. /// The heads-up-display menu shown on the map and combat screens.
  942. /// </summary>
  943. public static Hud Hud
  944. {
  945. get { return (singleton == null ? null : singleton.hud); }
  946. }
  947. /// <summary>
  948. /// Returns true if there is an active session.
  949. /// </summary>
  950. public static bool IsActive
  951. {
  952. get { return singleton != null; }
  953. }
  954. /// <summary>
  955. /// Private constructor of a Session object.
  956. /// </summary>
  957. /// <remarks>
  958. /// The lack of public constructors forces the singleton model.
  959. /// </remarks>
  960. private Session(ScreenManager screenManager, GameplayScreen gameplayScreen)
  961. {
  962. // check the parameter
  963. if (screenManager == null)
  964. {
  965. throw new ArgumentNullException("screenManager");
  966. }
  967. if (gameplayScreen == null)
  968. {
  969. throw new ArgumentNullException("gameplayScreen");
  970. }
  971. // assign the parameter
  972. this.screenManager = screenManager;
  973. this.gameplayScreen = gameplayScreen;
  974. // create the HUD interface
  975. this.hud = new Hud(screenManager);
  976. this.hud.LoadContent();
  977. }
  978. /// <summary>
  979. /// Update the session for this frame.
  980. /// </summary>
  981. /// <remarks>This should only be called if there are no menus in use.</remarks>
  982. public static void Update(GameTime gameTime)
  983. {
  984. // check the singleton
  985. if (singleton == null)
  986. {
  987. return;
  988. }
  989. if (CombatEngine.IsActive)
  990. {
  991. CombatEngine.Update(gameTime);
  992. }
  993. else
  994. {
  995. singleton.UpdateQuest();
  996. TileEngine.Update(gameTime);
  997. }
  998. }
  999. /// <summary>
  1000. /// Draws the session environment to the screen
  1001. /// </summary>
  1002. public static void Draw(GameTime gameTime)
  1003. {
  1004. SpriteBatch spriteBatch = singleton.screenManager.SpriteBatch;
  1005. if (CombatEngine.IsActive)
  1006. {
  1007. // draw the combat background
  1008. if (TileEngine.Map.CombatTexture != null)
  1009. {
  1010. spriteBatch.Begin();
  1011. spriteBatch.Draw(TileEngine.Map.CombatTexture, Vector2.Zero,
  1012. Color.White);
  1013. spriteBatch.End();
  1014. }
  1015. // draw the combat itself
  1016. spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
  1017. CombatEngine.Draw(gameTime);
  1018. spriteBatch.End();
  1019. }
  1020. else
  1021. {
  1022. singleton.DrawNonCombat(gameTime);
  1023. }
  1024. singleton.hud.Draw();
  1025. }
  1026. /// <summary>
  1027. /// Draws everything related to the non-combat part of the screen
  1028. /// </summary>
  1029. /// <param name="gameTime">Provides a snapshot of timing values</param>
  1030. private void DrawNonCombat(GameTime gameTime)
  1031. {
  1032. SpriteBatch spriteBatch = screenManager.SpriteBatch;
  1033. // draw the background
  1034. spriteBatch.Begin();
  1035. if (TileEngine.Map.Texture != null)
  1036. {
  1037. // draw the ground layer
  1038. TileEngine.DrawLayers(spriteBatch, true, true, false);
  1039. // draw the character shadows
  1040. DrawShadows(spriteBatch);
  1041. }
  1042. spriteBatch.End();
  1043. // Sort the object layer and player according to depth
  1044. spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
  1045. float elapsedSeconds = (float)gameTime.ElapsedGameTime.TotalSeconds;
  1046. // draw the party leader
  1047. {
  1048. Player player = party.Players[0];
  1049. Vector2 position = TileEngine.PartyLeaderPosition.ScreenPosition;
  1050. player.Direction = TileEngine.PartyLeaderPosition.Direction;
  1051. player.ResetAnimation(TileEngine.PartyLeaderPosition.IsMoving);
  1052. switch (player.State)
  1053. {
  1054. case Character.CharacterState.Idle:
  1055. if (player.MapSprite != null)
  1056. {
  1057. player.MapSprite.UpdateAnimation(elapsedSeconds);
  1058. player.MapSprite.Draw(spriteBatch, position,
  1059. 1f - position.Y / (float)TileEngine.Viewport.Height);
  1060. }
  1061. break;
  1062. case Character.CharacterState.Walking:
  1063. if (player.WalkingSprite != null)
  1064. {
  1065. player.WalkingSprite.UpdateAnimation(elapsedSeconds);
  1066. player.WalkingSprite.Draw(spriteBatch, position,
  1067. 1f - position.Y / (float)TileEngine.Viewport.Height);
  1068. }
  1069. else if (player.MapSprite != null)
  1070. {
  1071. player.MapSprite.UpdateAnimation(elapsedSeconds);
  1072. player.MapSprite.Draw(spriteBatch, position,
  1073. 1f - position.Y / (float)TileEngine.Viewport.Height);
  1074. }
  1075. break;
  1076. }
  1077. }
  1078. // draw the player NPCs
  1079. foreach (MapEntry<Player> playerEntry in TileEngine.Map.PlayerNpcEntries)
  1080. {
  1081. if (playerEntry.Content == null)
  1082. {
  1083. continue;
  1084. }
  1085. Vector2 position =
  1086. TileEngine.GetScreenPosition(playerEntry.MapPosition);
  1087. playerEntry.Content.ResetAnimation(false);
  1088. switch (playerEntry.Content.State)
  1089. {
  1090. case Character.CharacterState.Idle:
  1091. if (playerEntry.Content.MapSprite != null)
  1092. {
  1093. playerEntry.Content.MapSprite.UpdateAnimation(
  1094. elapsedSeconds);
  1095. playerEntry.Content.MapSprite.Draw(spriteBatch, position,
  1096. 1f - position.Y / (float)TileEngine.Viewport.Height);
  1097. }
  1098. break;
  1099. case Character.CharacterState.Walking:
  1100. if (playerEntry.Content.WalkingSprite != null)
  1101. {
  1102. playerEntry.Content.WalkingSprite.UpdateAnimation(
  1103. elapsedSeconds);
  1104. playerEntry.Content.WalkingSprite.Draw(spriteBatch, position,
  1105. 1f - position.Y / (float)TileEngine.Viewport.Height);
  1106. }
  1107. else if (playerEntry.Content.MapSprite != null)
  1108. {
  1109. playerEntry.Content.MapSprite.UpdateAnimation(
  1110. elapsedSeconds);
  1111. playerEntry.Content.MapSprite.Draw(spriteBatch, position,
  1112. 1f - position.Y / (float)TileEngine.Viewport.Height);
  1113. }
  1114. break;
  1115. }
  1116. }
  1117. // draw the quest NPCs
  1118. foreach (MapEntry<QuestNpc> questNpcEntry in TileEngine.Map.QuestNpcEntries)
  1119. {
  1120. if (questNpcEntry.Content == null)
  1121. {
  1122. continue;
  1123. }
  1124. Vector2 position =
  1125. TileEngine.GetScreenPosition(questNpcEntry.MapPosition);
  1126. questNpcEntry.Content.ResetAnimation(false);
  1127. switch (questNpcEntry.Content.State)
  1128. {
  1129. case Character.CharacterState.Idle:
  1130. if (questNpcEntry.Content.MapSprite != null)
  1131. {
  1132. questNpcEntry.Content.MapSprite.UpdateAnimation(
  1133. elapsedSeconds);
  1134. questNpcEntry.Content.MapSprite.Draw(spriteBatch, position,
  1135. 1f - position.Y / (float)TileEngine.Viewport.Height);
  1136. }
  1137. break;
  1138. case Character.CharacterState.Walking:
  1139. if (questNpcEntry.Content.WalkingSprite != null)
  1140. {
  1141. questNpcEntry.Content.WalkingSprite.UpdateAnimation(
  1142. elapsedSeconds);
  1143. questNpcEntry.Content.WalkingSprite.Draw(spriteBatch,
  1144. position,
  1145. 1f - position.Y / (float)TileEngine.Viewport.Height);
  1146. }
  1147. else if (questNpcEntry.Content.MapSprite != null)
  1148. {
  1149. questNpcEntry.Content.MapSprite.UpdateAnimation(
  1150. elapsedSeconds);
  1151. questNpcEntry.Content.MapSprite.Draw(spriteBatch, position,
  1152. 1f - position.Y / (float)TileEngine.Viewport.Height);
  1153. }
  1154. break;
  1155. }
  1156. }
  1157. // draw the fixed-combat monsters NPCs from the TileEngine.Map
  1158. // -- since there may be many of the same FixedCombat object
  1159. // on the TileEngine.Map, but their animations are handled differently
  1160. foreach (MapEntry<FixedCombat> fixedCombatEntry in
  1161. TileEngine.Map.FixedCombatEntries)
  1162. {
  1163. if ((fixedCombatEntry.Content == null) ||
  1164. (fixedCombatEntry.Content.Entries.Count <= 0))
  1165. {
  1166. continue;
  1167. }
  1168. Vector2 position =
  1169. TileEngine.GetScreenPosition(fixedCombatEntry.MapPosition);
  1170. fixedCombatEntry.MapSprite.UpdateAnimation(elapsedSeconds);
  1171. fixedCombatEntry.MapSprite.Draw(spriteBatch, position,
  1172. 1f - position.Y / (float)TileEngine.Viewport.Height);
  1173. }
  1174. // draw the fixed-combat monsters NPCs from the current quest
  1175. // -- since there may be many of the same FixedCombat object
  1176. // on the TileEngine.Map, their animations are handled differently
  1177. if ((quest != null) && ((quest.Stage == Quest.QuestStage.InProgress) ||
  1178. (quest.Stage == Quest.QuestStage.RequirementsMet)))
  1179. {
  1180. foreach (WorldEntry<FixedCombat> fixedCombatEntry
  1181. in quest.FixedCombatEntries)
  1182. {
  1183. if ((fixedCombatEntry.Content == null) ||
  1184. (fixedCombatEntry.Content.Entries.Count <= 0) ||
  1185. !TileEngine.Map.AssetName.EndsWith(
  1186. fixedCombatEntry.MapContentName))
  1187. {
  1188. continue;
  1189. }
  1190. Vector2 position =
  1191. TileEngine.GetScreenPosition(fixedCombatEntry.MapPosition);
  1192. fixedCombatEntry.MapSprite.UpdateAnimation(elapsedSeconds);
  1193. fixedCombatEntry.MapSprite.Draw(spriteBatch, position,
  1194. 1f - position.Y / (float)TileEngine.Viewport.Height);
  1195. }
  1196. }
  1197. // draw the chests from the TileEngine.Map
  1198. foreach (MapEntry<Chest> chestEntry in TileEngine.Map.ChestEntries)
  1199. {
  1200. if (chestEntry.Content == null)
  1201. {
  1202. continue;
  1203. }
  1204. Vector2 position = TileEngine.GetScreenPosition(chestEntry.MapPosition);
  1205. spriteBatch.Draw(chestEntry.Content.Texture,
  1206. position, null, Color.White, 0f, Vector2.Zero, 1f,
  1207. SpriteEffects.None,
  1208. MathHelper.Clamp(1f - position.Y /
  1209. (float)TileEngine.Viewport.Height, 0f, 1f));
  1210. }
  1211. // draw the chests from the current quest
  1212. if ((quest != null) && ((quest.Stage == Quest.QuestStage.InProgress) ||
  1213. (quest.Stage == Quest.QuestStage.RequirementsMet)))
  1214. {
  1215. foreach (WorldEntry<Chest> chestEntry in quest.ChestEntries)
  1216. {
  1217. if ((chestEntry.Content == null) ||
  1218. !TileEngine.Map.AssetName.EndsWith(chestEntry.MapContentName))
  1219. {
  1220. continue;
  1221. }
  1222. Vector2 position =
  1223. TileEngine.GetScreenPosition(chestEntry.MapPosition);
  1224. spriteBatch.Draw(chestEntry.Content.Texture,
  1225. position, null, Color.White, 0f, Vector2.Zero, 1f,
  1226. SpriteEffects.None,
  1227. MathHelper.Clamp(1f - position.Y /
  1228. (float)TileEngine.Viewport.Height, 0f, 1f));
  1229. }
  1230. }
  1231. spriteBatch.End();
  1232. // draw the foreground
  1233. spriteBatch.Begin();
  1234. if (TileEngine.Map.Texture != null)
  1235. {
  1236. TileEngine.DrawLayers(spriteBatch, false, false, true);
  1237. }
  1238. spriteBatch.End();
  1239. }
  1240. /// <summary>
  1241. /// Draw the shadows that appear under all characters.
  1242. /// </summary>
  1243. private void DrawShadows(SpriteBatch spriteBatch)
  1244. {
  1245. // draw the shadow of the party leader
  1246. Player player = party.Players[0];
  1247. if (player.ShadowTexture != null)
  1248. {
  1249. spriteBatch.Draw(player.ShadowTexture,
  1250. TileEngine.PartyLeaderPosition.ScreenPosition, null, Color.White, 0f,
  1251. new Vector2(
  1252. (player.ShadowTexture.Width - TileEngine.Map.TileSize.X) / 2,
  1253. (player.ShadowTexture.Height - TileEngine.Map.TileSize.Y) / 2 -
  1254. player.ShadowTexture.Height / 6),
  1255. 1f, SpriteEffects.None, 1f);
  1256. }
  1257. // draw the player NPCs' shadows
  1258. foreach (MapEntry<Player> playerEntry in TileEngine.Map.PlayerNpcEntries)
  1259. {
  1260. if (playerEntry.Content == null)
  1261. {
  1262. continue;
  1263. }
  1264. if (playerEntry.Content.ShadowTexture != null)
  1265. {
  1266. Vector2 position =
  1267. TileEngine.GetScreenPosition(playerEntry.MapPosition);
  1268. spriteBatch.Draw(playerEntry.Content.ShadowTexture, position,
  1269. null, Color.White, 0f,
  1270. new Vector2(
  1271. (playerEntry.Content.ShadowTexture.Width -
  1272. TileEngine.Map.TileSize.X) / 2,
  1273. (playerEntry.Content.ShadowTexture.Height -
  1274. TileEngine.Map.TileSize.Y) / 2 -
  1275. playerEntry.Content.ShadowTexture.Height / 6),
  1276. 1f, SpriteEffects.None, 1f);
  1277. }
  1278. }
  1279. // draw the quest NPCs' shadows
  1280. foreach (MapEntry<QuestNpc> questNpcEntry in TileEngine.Map.QuestNpcEntries)
  1281. {
  1282. if (questNpcEntry.Content == null)
  1283. {
  1284. continue;
  1285. }
  1286. if (questNpcEntry.Content.ShadowTexture != null)
  1287. {
  1288. Vector2 position =
  1289. TileEngine.GetScreenPosition(questNpcEntry.MapPosition);
  1290. spriteBatch.Draw(questNpcEntry.Content.ShadowTexture, position,
  1291. null, Color.White, 0f,
  1292. new Vector2(
  1293. (questNpcEntry.Content.ShadowTexture.Width -
  1294. TileEngine.Map.TileSize.X) / 2,
  1295. (questNpcEntry.Content.ShadowTexture.Height -
  1296. TileEngine.Map.TileSize.Y) / 2 -
  1297. questNpcEntry.Content.ShadowTexture.Height / 6),
  1298. 1f, SpriteEffects.None, 1f);
  1299. }
  1300. }
  1301. // draw the fixed-combat monsters NPCs' shadows
  1302. foreach (MapEntry<FixedCombat> fixedCombatEntry in
  1303. TileEngine.Map.FixedCombatEntries)
  1304. {
  1305. if ((fixedCombatEntry.Content == null) ||
  1306. (fixedCombatEntry.Content.Entries.Count <= 0))
  1307. {
  1308. continue;
  1309. }
  1310. Monster monster = fixedCombatEntry.Content.Entries[0].Content;
  1311. if (monster.ShadowTexture != null)
  1312. {
  1313. Vector2 position =
  1314. TileEngine.GetScreenPosition(fixedCombatEntry.MapPosition);
  1315. spriteBatch.Draw(monster.ShadowTexture, position,
  1316. null, Color.White, 0f,
  1317. new Vector2(
  1318. (monster.ShadowTexture.Width - TileEngine.Map.TileSize.X) / 2,
  1319. (monster.ShadowTexture.Height - TileEngine.Map.TileSize.Y) / 2 -
  1320. monster.ShadowTexture.Height / 6),
  1321. 1f, SpriteEffects.None, 1f);
  1322. }
  1323. }
  1324. }
  1325. /// <summary>
  1326. /// Start a new session based on the data provided.
  1327. /// </summary>
  1328. public static void StartNewSession(GameStartDescription gameStartDescription,
  1329. ScreenManager screenManager, GameplayScreen gameplayScreen)
  1330. {
  1331. // check the parameters
  1332. if (gameStartDescription == null)
  1333. {
  1334. throw new ArgumentNullException("gameStartDescripton");
  1335. }
  1336. if (screenManager == null)
  1337. {
  1338. throw new ArgumentNullException("screenManager");
  1339. }
  1340. if (gameplayScreen == null)
  1341. {
  1342. throw new ArgumentNullException("gameplayScreen");
  1343. }
  1344. // end any existing session
  1345. EndSession();
  1346. // create a new singleton
  1347. singleton = new Session(screenManager, gameplayScreen);
  1348. // set up the initial map
  1349. ChangeMap(gameStartDescription.MapContentName, null);
  1350. // set up the initial party
  1351. ContentManager content = singleton.screenManager.Game.Content;
  1352. singleton.party = new Party(gameStartDescription, content);
  1353. /* var loadedQuestLine = content.Load<QuestLine>(
  1354. Path.Combine(@"Quests\QuestLines",
  1355. gameStartDescription.QuestLineContentName)).Clone() as QuestLine;*/
  1356. var loadedQuestLine = QuestLine.Load(Path.Combine(@"Quests\QuestLines",
  1357. gameStartDescription.QuestLineContentName));
  1358. // load the quest line
  1359. singleton.questLine = loadedQuestLine;
  1360. }
  1361. /// <summary>
  1362. /// End the current session.
  1363. /// </summary>
  1364. public static void EndSession()
  1365. {
  1366. // exit the gameplay screen
  1367. // -- store the gameplay session, for re-entrance
  1368. if (singleton != null)
  1369. {
  1370. GameplayScreen gameplayScreen = singleton.gameplayScreen;
  1371. singleton.gameplayScreen = null;
  1372. // pop the music
  1373. AudioManager.PopMusic();
  1374. // clear the singleton
  1375. singleton = null;
  1376. if (gameplayScreen != null)
  1377. {
  1378. gameplayScreen.ExitScreen();
  1379. }
  1380. }
  1381. }
  1382. /// <summary>
  1383. /// Start a new session, using the data in the given save game.
  1384. /// </summary>
  1385. /// <param name="saveGameDescription">The description of the save game.</param>
  1386. /// <param name="screenManager">The ScreenManager for the new session.</param>
  1387. public static void LoadSession(SaveGameDescription saveGameDescription,
  1388. ScreenManager screenManager, GameplayScreen gameplayScreen)
  1389. {
  1390. // check the parameters
  1391. if (saveGameDescription == null)
  1392. {
  1393. throw new ArgumentNullException("saveGameDescription");
  1394. }
  1395. if (screenManager == null)
  1396. {
  1397. throw new ArgumentNullException("screenManager");
  1398. }
  1399. if (gameplayScreen == null)
  1400. {
  1401. throw new ArgumentNullException("gameplayScreen");
  1402. }
  1403. // end any existing session
  1404. EndSession();
  1405. // create the new session
  1406. singleton = new Session(screenManager, gameplayScreen);
  1407. // get the storage device and load the session
  1408. // TODO: Re-enable when Storage API returns in future MonoGame version
  1409. /*
  1410. GetStorageDevice(
  1411. delegate(StorageDevice storageDevice)
  1412. {
  1413. LoadSessionResult(storageDevice, saveGameDescription);
  1414. });
  1415. */
  1416. }
  1417. /// <summary>
  1418. /// Receives the storage device and starts a new session,
  1419. /// using the data in the given save game.
  1420. /// </summary>
  1421. /// <remarks>The new session is created in LoadSessionResult.</remarks>
  1422. /// <param name="storageDevice">The chosen storage device.</param>
  1423. /// <param name="saveGameDescription">The description of the save game.</param>
  1424. // TODO: Re-enable when Storage API returns in future MonoGame version
  1425. /*
  1426. public static void LoadSessionResult(StorageDevice storageDevice,
  1427. SaveGameDescription saveGameDescription)
  1428. {
  1429. // check the parameters
  1430. if (saveGameDescription == null)
  1431. {
  1432. throw new ArgumentNullException("saveGameDescription");
  1433. }
  1434. // check the parameter
  1435. if ((storageDevice == null) || !storageDevice.IsConnected)
  1436. {
  1437. return;
  1438. }
  1439. // open the container
  1440. using (StorageContainer storageContainer = OpenContainer(storageDevice))
  1441. {
  1442. using (Stream stream =
  1443. storageContainer.OpenFile(saveGameDescription.FileName, FileMode.Open))
  1444. {
  1445. using (XmlReader xmlReader = XmlReader.Create(stream))
  1446. {
  1447. // <rolePlayingGameData>
  1448. xmlReader.ReadStartElement("rolePlayingGameSaveData");
  1449. // read the map information
  1450. xmlReader.ReadStartElement("mapData");
  1451. string mapAssetName =
  1452. xmlReader.ReadElementString("mapContentName");
  1453. PlayerPosition playerPosition = new XmlSerializer(
  1454. typeof(PlayerPosition)).Deserialize(xmlReader)
  1455. as PlayerPosition;
  1456. singleton.removedMapChests = new XmlSerializer(
  1457. typeof(List<WorldEntry<Chest>>)).Deserialize(xmlReader)
  1458. as List<WorldEntry<Chest>>;
  1459. singleton.removedMapFixedCombats = new XmlSerializer(
  1460. typeof(List<WorldEntry<FixedCombat>>)).Deserialize(xmlReader)
  1461. as List<WorldEntry<FixedCombat>>;
  1462. singleton.removedMapPlayerNpcs = new XmlSerializer(
  1463. typeof(List<WorldEntry<Player>>)).Deserialize(xmlReader)
  1464. as List<WorldEntry<Player>>;
  1465. singleton.modifiedMapChests = new XmlSerializer(
  1466. typeof(List<ModifiedChestEntry>)).Deserialize(xmlReader)
  1467. as List<ModifiedChestEntry>;
  1468. ChangeMap(mapAssetName, null);
  1469. TileEngine.PartyLeaderPosition = playerPosition;
  1470. xmlReader.ReadEndElement();
  1471. // read the quest information
  1472. ContentManager content = Session.ScreenManager.Game.Content;
  1473. xmlReader.ReadStartElement("questData");
  1474. singleton.questLine = content.Load<QuestLine>(
  1475. xmlReader.ReadElementString("questLineContentName")).Clone()
  1476. as QuestLine;
  1477. singleton.currentQuestIndex = Convert.ToInt32(
  1478. xmlReader.ReadElementString("currentQuestIndex"));
  1479. for (int i = 0; i < singleton.currentQuestIndex; i++)
  1480. {
  1481. singleton.questLine.Quests[i].Stage =
  1482. Quest.QuestStage.Completed;
  1483. }
  1484. singleton.removedQuestChests = new XmlSerializer(
  1485. typeof(List<WorldEntry<Chest>>)).Deserialize(xmlReader)
  1486. as List<WorldEntry<Chest>>;
  1487. singleton.removedQuestFixedCombats = new XmlSerializer(
  1488. typeof(List<WorldEntry<FixedCombat>>)).Deserialize(xmlReader)
  1489. as List<WorldEntry<FixedCombat>>;
  1490. singleton.modifiedQuestChests = new XmlSerializer(
  1491. typeof(List<ModifiedChestEntry>)).Deserialize(xmlReader)
  1492. as List<ModifiedChestEntry>;
  1493. Quest.QuestStage questStage = (Quest.QuestStage)Enum.Parse(
  1494. typeof(Quest.QuestStage),
  1495. xmlReader.ReadElementString("currentQuestStage"), true);
  1496. if ((singleton.questLine != null) && !IsQuestLineComplete)
  1497. {
  1498. singleton.quest =
  1499. singleton.questLine.Quests[CurrentQuestIndex];
  1500. singleton.ModifyQuest(singleton.quest);
  1501. singleton.quest.Stage = questStage;
  1502. }
  1503. xmlReader.ReadEndElement();
  1504. // read the party data
  1505. singleton.party = new Party(new XmlSerializer(
  1506. typeof(PartySaveData)).Deserialize(xmlReader)
  1507. as PartySaveData, content);
  1508. // </rolePlayingGameSaveData>
  1509. xmlReader.ReadEndElement();
  1510. }
  1511. }
  1512. }
  1513. }
  1514. */
  1515. /// <summary>
  1516. /// Save the current state of the session.
  1517. /// </summary>
  1518. /// <param name="overwriteDescription">
  1519. /// The description of the save game to over-write, if any.
  1520. /// </param>
  1521. public static void SaveSession(SaveGameDescription overwriteDescription)
  1522. {
  1523. // TODO: Re-enable when Storage API returns in future MonoGame version
  1524. /*
  1525. // retrieve the storage device, asynchronously
  1526. GetStorageDevice(delegate(StorageDevice storageDevice)
  1527. {
  1528. SaveSessionResult(storageDevice, overwriteDescription);
  1529. });
  1530. */
  1531. }
  1532. /// <summary>
  1533. /// Save the current state of the session, with the given storage device.
  1534. /// </summary>
  1535. /// <param name="storageDevice">The chosen storage device.</param>
  1536. /// <param name="overwriteDescription">
  1537. /// The description of the save game to over-write, if any.
  1538. /// </param>
  1539. // TODO: Re-enable when Storage API returns in future MonoGame version
  1540. /*
  1541. private static void SaveSessionResult(StorageDevice storageDevice,
  1542. SaveGameDescription overwriteDescription)
  1543. {
  1544. // check the parameter
  1545. if ((storageDevice == null) || !storageDevice.IsConnected)
  1546. {
  1547. return;
  1548. }
  1549. // open the container
  1550. using (StorageContainer storageContainer =
  1551. OpenContainer(storageDevice))
  1552. {
  1553. string filename;
  1554. string descriptionFilename;
  1555. // get the filenames
  1556. if (overwriteDescription == null)
  1557. {
  1558. int saveGameIndex = 0;
  1559. string testFilename;
  1560. do
  1561. {
  1562. saveGameIndex++;
  1563. testFilename = "SaveGame" + saveGameIndex.ToString() + ".xml";
  1564. }
  1565. while (storageContainer.FileExists(testFilename));
  1566. filename = testFilename;
  1567. descriptionFilename = "SaveGameDescription" +
  1568. saveGameIndex.ToString() + ".xml";
  1569. }
  1570. else
  1571. {
  1572. filename = overwriteDescription.FileName;
  1573. descriptionFilename = "SaveGameDescription" +
  1574. Path.GetFileNameWithoutExtension(
  1575. overwriteDescription.FileName).Substring(8) + ".xml";
  1576. }
  1577. using (Stream stream = storageContainer.OpenFile(filename, FileMode.Create))
  1578. {
  1579. using (XmlWriter xmlWriter = XmlWriter.Create(stream))
  1580. {
  1581. // <rolePlayingGameData>
  1582. xmlWriter.WriteStartElement("rolePlayingGameSaveData");
  1583. // write the map information
  1584. xmlWriter.WriteStartElement("mapData");
  1585. xmlWriter.WriteElementString("mapContentName",
  1586. TileEngine.Map.AssetName);
  1587. new XmlSerializer(typeof(PlayerPosition)).Serialize(
  1588. xmlWriter, TileEngine.PartyLeaderPosition);
  1589. new XmlSerializer(typeof(List<WorldEntry<Chest>>)).Serialize(
  1590. xmlWriter, singleton.removedMapChests);
  1591. new XmlSerializer(
  1592. typeof(List<WorldEntry<FixedCombat>>)).Serialize(
  1593. xmlWriter, singleton.removedMapFixedCombats);
  1594. new XmlSerializer(typeof(List<WorldEntry<Player>>)).Serialize(
  1595. xmlWriter, singleton.removedMapPlayerNpcs);
  1596. new XmlSerializer(typeof(List<ModifiedChestEntry>)).Serialize(
  1597. xmlWriter, singleton.modifiedMapChests);
  1598. xmlWriter.WriteEndElement();
  1599. // write the quest information
  1600. xmlWriter.WriteStartElement("questData");
  1601. xmlWriter.WriteElementString("questLineContentName",
  1602. singleton.questLine.AssetName);
  1603. xmlWriter.WriteElementString("currentQuestIndex",
  1604. singleton.currentQuestIndex.ToString());
  1605. new XmlSerializer(typeof(List<WorldEntry<Chest>>)).Serialize(
  1606. xmlWriter, singleton.removedQuestChests);
  1607. new XmlSerializer(
  1608. typeof(List<WorldEntry<FixedCombat>>)).Serialize(
  1609. xmlWriter, singleton.removedQuestFixedCombats);
  1610. new XmlSerializer(typeof(List<ModifiedChestEntry>)).Serialize(
  1611. xmlWriter, singleton.modifiedQuestChests);
  1612. xmlWriter.WriteElementString("currentQuestStage",
  1613. IsQuestLineComplete ?
  1614. Quest.QuestStage.NotStarted.ToString() :
  1615. singleton.quest.Stage.ToString());
  1616. xmlWriter.WriteEndElement();
  1617. // write the party data
  1618. new XmlSerializer(typeof(PartySaveData)).Serialize(xmlWriter,
  1619. new PartySaveData(singleton.party));
  1620. // </rolePlayingGameSaveData>
  1621. xmlWriter.WriteEndElement();
  1622. }
  1623. }
  1624. // create the save game description
  1625. SaveGameDescription description = new SaveGameDescription();
  1626. description.FileName = Path.GetFileName(filename);
  1627. description.ChapterName = IsQuestLineComplete ? "Quest Line Complete" :
  1628. Quest.Name;
  1629. description.Description = DateTime.Now.ToString();
  1630. using (Stream stream =
  1631. storageContainer.OpenFile(descriptionFilename, FileMode.Create))
  1632. {
  1633. new XmlSerializer(typeof(SaveGameDescription)).Serialize(stream,
  1634. description);
  1635. }
  1636. }
  1637. }
  1638. */
  1639. /// <summary>
  1640. /// Delete the save game specified by the description.
  1641. /// </summary>
  1642. /// <param name="saveGameDescription">The description of the save game.</param>
  1643. // TODO: Re-enable when Storage API returns in future MonoGame version
  1644. /*
  1645. public static void DeleteSaveGame(SaveGameDescription saveGameDescription)
  1646. {
  1647. // check the parameters
  1648. if (saveGameDescription == null)
  1649. {
  1650. throw new ArgumentNullException("saveGameDescription");
  1651. }
  1652. // get the storage device and load the session
  1653. GetStorageDevice(
  1654. delegate(StorageDevice storageDevice)
  1655. {
  1656. DeleteSaveGameResult(storageDevice, saveGameDescription);
  1657. });
  1658. }
  1659. */
  1660. /// <summary>
  1661. /// Delete the save game specified by the description.
  1662. /// </summary>
  1663. /// <param name="storageDevice">The chosen storage device.</param>
  1664. /// <param name="saveGameDescription">The description of the save game.</param>
  1665. // TODO: Re-enable when Storage API returns in future MonoGame version
  1666. /*
  1667. public static void DeleteSaveGameResult(StorageDevice storageDevice,
  1668. SaveGameDescription saveGameDescription)
  1669. {
  1670. // check the parameters
  1671. if (saveGameDescription == null)
  1672. {
  1673. throw new ArgumentNullException("saveGameDescription");
  1674. }
  1675. // check the parameter
  1676. if ((storageDevice == null) || !storageDevice.IsConnected)
  1677. {
  1678. return;
  1679. }
  1680. // open the container
  1681. using (StorageContainer storageContainer =
  1682. OpenContainer(storageDevice))
  1683. {
  1684. storageContainer.DeleteFile(saveGameDescription.FileName);
  1685. storageContainer.DeleteFile("SaveGameDescription" +
  1686. Path.GetFileNameWithoutExtension(
  1687. saveGameDescription.FileName).Substring(8) + ".xml");
  1688. }
  1689. // refresh the save game descriptions
  1690. Session.RefreshSaveGameDescriptions();
  1691. }
  1692. */
  1693. /// <summary>
  1694. /// Save game descriptions for the current set of save games.
  1695. /// </summary>
  1696. private static List<SaveGameDescription> saveGameDescriptions = null;
  1697. /// <summary>
  1698. /// Save game descriptions for the current set of save games.
  1699. /// </summary>
  1700. public static List<SaveGameDescription> SaveGameDescriptions
  1701. {
  1702. get { return saveGameDescriptions; }
  1703. }
  1704. /// <summary>
  1705. /// The maximum number of save-game descriptions that the list may hold.
  1706. /// </summary>
  1707. public const int MaximumSaveGameDescriptions = 5;
  1708. /// <summary>
  1709. /// XML serializer for SaveGameDescription objects.
  1710. /// </summary>
  1711. private static XmlSerializer saveGameDescriptionSerializer =
  1712. new XmlSerializer(typeof(SaveGameDescription));
  1713. /// <summary>
  1714. /// Refresh the list of save-game descriptions.
  1715. /// </summary>
  1716. // TODO: Re-enable when Storage API returns in future MonoGame version
  1717. /*
  1718. public static void RefreshSaveGameDescriptions()
  1719. {
  1720. // clear the list
  1721. saveGameDescriptions = null;
  1722. // retrieve the storage device, asynchronously
  1723. GetStorageDevice(RefreshSaveGameDescriptionsResult);
  1724. }
  1725. */
  1726. /// <summary>
  1727. /// Asynchronous storage-device callback for
  1728. /// refreshing the save-game descriptions.
  1729. /// </summary>
  1730. // TODO: Re-enable when Storage API returns in future MonoGame version
  1731. /*
  1732. private static void RefreshSaveGameDescriptionsResult(
  1733. StorageDevice storageDevice)
  1734. {
  1735. // check the parameter
  1736. if ((storageDevice == null) || !storageDevice.IsConnected)
  1737. {
  1738. return;
  1739. }
  1740. // open the container
  1741. using (StorageContainer storageContainer =
  1742. OpenContainer(storageDevice))
  1743. {
  1744. saveGameDescriptions = new List<SaveGameDescription>();
  1745. // get the description list
  1746. string[] filenames =
  1747. storageContainer.GetFileNames("SaveGameDescription*.xml");
  1748. // add each entry to the list
  1749. foreach (string filename in filenames)
  1750. {
  1751. SaveGameDescription saveGameDescription;
  1752. // check the size of the list
  1753. if (saveGameDescriptions.Count >= MaximumSaveGameDescriptions)
  1754. {
  1755. break;
  1756. }
  1757. // open the file stream
  1758. using (Stream fileStream = storageContainer.OpenFile(filename, FileMode.Open))
  1759. {
  1760. // deserialize the object
  1761. saveGameDescription =
  1762. saveGameDescriptionSerializer.Deserialize(fileStream)
  1763. as SaveGameDescription;
  1764. // if it's valid, add it to the list
  1765. if (saveGameDescription != null)
  1766. {
  1767. saveGameDescriptions.Add(saveGameDescription);
  1768. }
  1769. }
  1770. }
  1771. }
  1772. }
  1773. */
  1774. /// <summary>
  1775. /// The stored StorageDevice object.
  1776. /// </summary>
  1777. // TODO: Re-enable when Storage API returns in future MonoGame version
  1778. /*
  1779. private static StorageDevice storageDevice;
  1780. */
  1781. /// <summary>
  1782. /// The container name used for save games.
  1783. /// </summary>
  1784. // TODO: Re-enable when Storage API returns in future MonoGame version
  1785. /*
  1786. public static string SaveGameContainerName = "RolePlayingGame";
  1787. */
  1788. /// <summary>
  1789. /// A delegate for receiving StorageDevice objects.
  1790. /// </summary>
  1791. // TODO: Re-enable when Storage API returns in future MonoGame version
  1792. /*
  1793. public delegate void StorageDeviceDelegate(StorageDevice storageDevice);
  1794. */
  1795. /// <summary>
  1796. /// Asynchronously retrieve a storage device.
  1797. /// </summary>
  1798. /// <param name="retrievalDelegate">
  1799. /// The delegate called when the device is available.
  1800. /// </param>
  1801. /// <remarks>
  1802. /// If there is a suitable cached storage device,
  1803. /// the delegate may be called directly by this function.
  1804. /// </remarks>
  1805. // TODO: Re-enable when Storage API returns in future MonoGame version
  1806. /*
  1807. public static void GetStorageDevice(StorageDeviceDelegate retrievalDelegate)
  1808. {
  1809. // check the parameter
  1810. if (retrievalDelegate == null)
  1811. {
  1812. throw new ArgumentNullException("retrievalDelegate");
  1813. }
  1814. // check the stored storage device
  1815. if ((storageDevice != null) && storageDevice.IsConnected)
  1816. {
  1817. retrievalDelegate(storageDevice);
  1818. return;
  1819. }
  1820. // the storage device must be retrieved
  1821. if (!Guide.IsVisible)
  1822. {
  1823. // Reset the device
  1824. storageDevice = null;
  1825. StorageDevice.BeginShowSelector(GetStorageDeviceResult, retrievalDelegate);
  1826. }
  1827. }
  1828. */
  1829. /// <summary>
  1830. /// Asynchronous callback to the guide's BeginShowStorageDeviceSelector call.
  1831. /// </summary>
  1832. /// <param name="result">The IAsyncResult object with the device.</param>
  1833. // TODO: Re-enable when Storage API returns in future MonoGame version
  1834. /*
  1835. private static void GetStorageDeviceResult(IAsyncResult result)
  1836. {
  1837. // check the parameter
  1838. if ((result == null) || !result.IsCompleted)
  1839. {
  1840. return;
  1841. }
  1842. // retrieve and store the storage device
  1843. storageDevice = StorageDevice.EndShowSelector(result);
  1844. // check the new storage device
  1845. if ((storageDevice != null) && storageDevice.IsConnected)
  1846. {
  1847. // it passes; call the stored delegate
  1848. StorageDeviceDelegate func = result.AsyncState as StorageDeviceDelegate;
  1849. if (func != null)
  1850. {
  1851. func(storageDevice);
  1852. }
  1853. }
  1854. }
  1855. */
  1856. /// <summary>
  1857. /// Synchronously opens storage container
  1858. /// </summary>
  1859. // TODO: Re-enable when Storage API returns in future MonoGame version
  1860. /*
  1861. private static StorageContainer OpenContainer(StorageDevice storageDevice)
  1862. {
  1863. IAsyncResult result =
  1864. storageDevice.BeginOpenContainer(Session.SaveGameContainerName, null, null);
  1865. // Wait for the WaitHandle to become signaled.
  1866. result.AsyncWaitHandle.WaitOne();
  1867. StorageContainer container = storageDevice.EndOpenContainer(result);
  1868. // Close the wait handle.
  1869. result.AsyncWaitHandle.Close();
  1870. return container;
  1871. }
  1872. */
  1873. /// <summary>
  1874. /// The random-number generator used with game events.
  1875. /// </summary>
  1876. private static Random random = new Random();
  1877. /// <summary>
  1878. /// The random-number generator used with game events.
  1879. /// </summary>
  1880. public static Random Random
  1881. {
  1882. get { return random; }
  1883. }
  1884. }
  1885. }