PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/Classes/Map.cs

http://github.com/Concliff/Maze
C# | 532 lines | 323 code | 80 blank | 129 comment | 57 complexity | ff5ea796cc0291a369ac42c9e0ad1a25 MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.IO;
  6. namespace Maze.Classes
  7. {
  8. public class Map
  9. {
  10. //
  11. // SINGLETON PART
  12. //
  13. #region singleton_part
  14. /// <summary>
  15. /// Singleton instance
  16. /// </summary>
  17. private static Map instance;
  18. /// <summary>
  19. /// Gets reference to World Map instance
  20. /// </summary>
  21. public static Map Instance
  22. {
  23. get
  24. {
  25. if (instance == null)
  26. instance = new Map();
  27. return instance;
  28. }
  29. }
  30. /// <summary>
  31. /// Private constructor for hiding singleton instance
  32. /// </summary>
  33. private Map()
  34. {
  35. LoadMapNameList();
  36. // Undefined level
  37. this.pr_CurrentLevel = -1;
  38. }
  39. #endregion
  40. /// <summary>
  41. /// Collection of the Cell objects on current Map.
  42. /// </summary>
  43. private Dictionary<GridLocation, Cell> mapCells;
  44. /// <summary>
  45. /// Collection of the Cells' locations on the Map.
  46. /// Key = Cell Id.
  47. /// Value = Location of cell.
  48. /// </summary>
  49. private Dictionary<int, GridLocation> mapCellsIds;
  50. /// <summary>
  51. /// Count of Ooze Drops at every level of the map. These count values are values at the current time and are changed when a Drop has been collected.
  52. /// </summary>
  53. private int[] dropsCount;
  54. /// <summary>
  55. /// Names of all loaded maps.
  56. /// </summary>
  57. private string[] mapNames;
  58. private Dictionary<int, GridLocation> startPoints;
  59. private Dictionary<int, GridLocation> finishPoints;
  60. /// <summary>
  61. /// Indicating whether the current Map is randomly generated.
  62. /// </summary>
  63. private bool isRandom;
  64. /// <summary>
  65. /// Levels count on the current Map.
  66. /// </summary>
  67. private int levelsCount;
  68. /// <summary>
  69. /// Gets the count of non-collected Ooze drops on current level.
  70. /// </summary>
  71. public int DropsRemain
  72. {
  73. get
  74. {
  75. return this.dropsCount[CurrentLevel];
  76. }
  77. }
  78. /// <summary>
  79. /// Gets the levels count of the current map
  80. /// </summary>
  81. public int LevelCount
  82. {
  83. get { return this.levelsCount; }
  84. }
  85. /// <summary>
  86. /// Gets the number of the Cells on current Map
  87. /// </summary>
  88. public int CellsCount
  89. {
  90. get
  91. {
  92. if (this.mapCells != null)
  93. return this.mapCells.Count;
  94. return 0;
  95. }
  96. }
  97. /// <summary>
  98. /// Gets a value endicating whether the current Map is randomly generated.
  99. /// </summary>
  100. public bool IsRandom
  101. {
  102. get
  103. {
  104. return this.isRandom;
  105. }
  106. }
  107. private int pr_CurrentMap;
  108. /// <summary>
  109. /// Gets or sets the current map index.
  110. /// </summary>
  111. public int CurrentMap
  112. {
  113. get
  114. {
  115. return this.pr_CurrentMap;
  116. }
  117. set
  118. {
  119. this.pr_CurrentMap = value;
  120. // Random map is loading at CurrentLevel loading.
  121. if (this.pr_CurrentMap == -1)
  122. this.isRandom = true;
  123. else
  124. LoadMap(this.pr_CurrentMap);
  125. }
  126. }
  127. private int pr_CurrentLevel;
  128. /// <summary>
  129. /// Gets or sets the index of the current level of the map.
  130. /// </summary>
  131. public int CurrentLevel
  132. {
  133. get
  134. {
  135. return this.pr_CurrentLevel;
  136. }
  137. set
  138. {
  139. this.pr_CurrentLevel = value;
  140. LoadLevel();
  141. }
  142. }
  143. /// <summary>
  144. /// Gets a location of the start point on the current level.
  145. /// </summary>
  146. public GridLocation StartLocation
  147. {
  148. get
  149. {
  150. GridLocation result = new GridLocation();
  151. // The map was not loaded
  152. if (this.mapCells == null)
  153. return result;
  154. result.Level = CurrentLevel;
  155. if (CurrentLevel < LevelCount)
  156. result = this.startPoints[CurrentLevel];
  157. return result;
  158. }
  159. }
  160. /// <summary>
  161. /// Gets a location of the finish point on the current level.
  162. /// </summary>
  163. public GridLocation FinishLocation
  164. {
  165. get
  166. {
  167. GridLocation result = new GridLocation();
  168. // The map was not loaded
  169. if (this.mapCells == null)
  170. return result;
  171. result.Level = CurrentLevel;
  172. if (CurrentLevel < LevelCount)
  173. result = this.finishPoints[CurrentLevel];
  174. return result;
  175. }
  176. }
  177. /// <summary>
  178. /// Loads Names of maps with scanning for map files in the game directory.
  179. /// </summary>
  180. private void LoadMapNameList()
  181. {
  182. DirectoryInfo mapDirectory = new DirectoryInfo(GlobalConstants.MAPS_PATH);
  183. FileInfo[] mapFiles = mapDirectory.GetFiles();
  184. List<string> mapNames = new List<string>();
  185. foreach (FileInfo fi in mapFiles)
  186. {
  187. if (fi.Extension == ".map")
  188. mapNames.Add(Path.GetFileNameWithoutExtension(fi.FullName));
  189. }
  190. this.mapNames = mapNames.ToArray();
  191. }
  192. /// <summary>
  193. /// Creates random level with <see cref="MazeGenerator"/> and assigns cells attributes for Start/Finish points, Drops, Portals and so on.
  194. /// </summary>
  195. private void GenerateRandomLevel()
  196. {
  197. // TODO: Vary level size depending on CurrentLevel increase.
  198. this.mapCells = new Dictionary<GridLocation, Cell>();
  199. this.mapCellsIds = new Dictionary<int, GridLocation>();
  200. // Geneate cell blocks
  201. MazeGenerator generator = new MazeGenerator();
  202. List<Cell> generatorCells = generator.Generate(0);
  203. foreach (Cell cell in generatorCells)
  204. {
  205. AddCell(cell);
  206. }
  207. this.startPoints = new Dictionary<int, GridLocation>();
  208. this.finishPoints = new Dictionary<int, GridLocation>();
  209. this.startPoints.Add(CurrentLevel, generator.StartPoint.Location);
  210. this.finishPoints.Add(CurrentLevel, generator.FinishPoint.Location);
  211. this.levelsCount = CurrentLevel + 1;
  212. this.dropsCount = new int[levelsCount];
  213. // Generate Drops Count
  214. // Every 15th block should have a drop
  215. int dropsCounter = CellsCount / 15;
  216. // Generate Drops Location
  217. int currentDropsCount = 0;
  218. while (currentDropsCount < dropsCounter)
  219. {
  220. Cell cell = GetCell(Random.Int(CellsCount));
  221. // Cell has not been found
  222. if (cell.ID == -1)
  223. continue;
  224. if (cell.HasAttribute(CellAttributes.HasDrop) ||
  225. cell.HasAttribute(CellAttributes.IsStart) ||
  226. cell.HasAttribute(CellAttributes.IsFinish))
  227. continue;
  228. cell.Attribute += (uint)CellAttributes.HasDrop;
  229. ++currentDropsCount;
  230. AddCell(cell, true);
  231. }
  232. // Generate Portals
  233. // Every 50th block
  234. int portalCounter = CellsCount / 50;
  235. int portalCount = 0;
  236. while (portalCount < portalCounter)
  237. {
  238. Cell portalBlock = GetCell(Random.Int(CellsCount));
  239. Cell destinationBlock = GetCell(Random.Int(CellsCount));
  240. // Cells have not been found
  241. if (portalBlock.ID == -1 || destinationBlock.ID == -1)
  242. continue;
  243. if (portalBlock.ID == destinationBlock.ID ||
  244. portalBlock.HasAttribute(CellAttributes.HasDrop) ||
  245. portalBlock.HasAttribute(CellAttributes.IsStart) ||
  246. portalBlock.HasAttribute(CellAttributes.IsFinish) ||
  247. destinationBlock.HasAttribute(CellAttributes.IsStart))
  248. continue;
  249. portalBlock.Option += (uint)CellOptions.Portal;
  250. portalBlock.OptionValue = destinationBlock.ID;
  251. ++portalCount;
  252. AddCell(portalBlock, true);
  253. }
  254. }
  255. /// <summary>
  256. /// Loads Map Cells for specific map.
  257. /// </summary>
  258. /// <param name="mapIndex">An index in the map names collection</param>
  259. private void LoadMap(int mapIndex)
  260. {
  261. // Remove all the existing objects
  262. ObjectContainer.Instance.ClearEnvironment(true);
  263. this.isRandom = false;
  264. this.mapCells = new Dictionary<GridLocation, Cell>();
  265. this.mapCellsIds = new Dictionary<int, GridLocation>();
  266. this.startPoints = new Dictionary<int, GridLocation>();
  267. this.finishPoints = new Dictionary<int,GridLocation>();
  268. int levelIndicator = 0;
  269. StreamReader CellStream = File.OpenText(GlobalConstants.MAPS_PATH + this.mapNames[mapIndex] + ".map");
  270. string CurrentString;
  271. while ((CurrentString = CellStream.ReadLine()) != null)
  272. {
  273. string[] StringStruct = new string[10];
  274. StringStruct = CurrentString.Split(' ');
  275. // Processing
  276. Cell CellStruct;
  277. CellStruct.ID = Convert.ToInt32(StringStruct[0]);
  278. CellStruct.Location.X = Convert.ToInt32(StringStruct[1]);
  279. CellStruct.Location.Y = Convert.ToInt32(StringStruct[2]);
  280. CellStruct.Location.Z = Convert.ToInt32(StringStruct[3]);
  281. CellStruct.Location.Level = Convert.ToInt32(StringStruct[4]);
  282. CellStruct.Type = Convert.ToUInt32(StringStruct[5]);
  283. CellStruct.Attribute = Convert.ToUInt32(StringStruct[6]);
  284. CellStruct.Option = Convert.ToUInt32(StringStruct[7]);
  285. CellStruct.OptionValue = Convert.ToInt32(StringStruct[8]);
  286. CellStruct.ND4 = Convert.ToInt32(StringStruct[9]);
  287. AddCell(CellStruct);
  288. if (Convert.ToInt32(StringStruct[4]) >= levelIndicator)
  289. levelIndicator++;
  290. if (CellStruct.HasAttribute(CellAttributes.IsStart))
  291. this.startPoints.Add(CellStruct.Location.Level, CellStruct.Location);
  292. if (CellStruct.HasAttribute(CellAttributes.IsFinish))
  293. this.finishPoints.Add(CellStruct.Location.Level, CellStruct.Location);
  294. }
  295. CellStream.Close();
  296. this.levelsCount = levelIndicator;
  297. dropsCount = new int[LevelCount];
  298. }
  299. /// <summary>
  300. /// Loads (or reloads) all the objects of the current level.
  301. /// </summary>
  302. private void LoadLevel()
  303. {
  304. // Remove all old objects and units of the previous level
  305. // Needed when existing game was resetted and started the new one.
  306. ObjectContainer.Instance.ClearEnvironment(false);
  307. // Load the map for random game
  308. if (IsRandom)
  309. GenerateRandomLevel();
  310. FillMapWithUnits(); // Add units to map
  311. FillMapWithObjects(); // Add objects
  312. // Change the rewpawn location for the Slug
  313. World.PlayForm.Player.LevelChanged();
  314. }
  315. /// <summary>
  316. /// Places units (Phobos and Deimos) on the map at the appropriate positions.
  317. /// </summary>
  318. public void FillMapWithUnits()
  319. {
  320. // Random levels alwways have units
  321. // No units on the first two levels
  322. if (CurrentLevel < 2 && !IsRandom)
  323. return;
  324. foreach (KeyValuePair<GridLocation, Cell> kvp in this.mapCells)
  325. {
  326. // Current level only
  327. if (kvp.Key.Level != CurrentLevel)
  328. continue;
  329. if (kvp.Value.HasAttribute(CellAttributes.HasDrop))
  330. // Create Deimos at Ooze Drop Location
  331. {
  332. Deimos deimos = new Deimos();
  333. deimos.Create(kvp.Key);
  334. deimos.StartMotion();
  335. // Level 2 has only one Deimos
  336. if (CurrentLevel == 2 && !IsRandom)
  337. return;
  338. }
  339. }
  340. // No Phoboses until level 8
  341. if (CurrentLevel < 8 && !IsRandom)
  342. return;
  343. // Test-created monsters
  344. Phobos phobos = new Phobos();
  345. phobos.Create(this.finishPoints[CurrentLevel]);
  346. phobos.StartMotion();
  347. }
  348. /// <summary>
  349. /// Places gridObjects (Drops and Portals) on the map at the appropriate positions.
  350. /// </summary>
  351. public void FillMapWithObjects()
  352. {
  353. foreach (KeyValuePair<GridLocation, Cell> kvp in this.mapCells)
  354. {
  355. // Current level only
  356. if (kvp.Key.Level != CurrentLevel)
  357. continue;
  358. if (kvp.Value.HasAttribute(CellAttributes.HasDrop))
  359. {
  360. OozeDrop drop = new OozeDrop();
  361. drop.Create(new GPS(kvp.Key));
  362. ++dropsCount[kvp.Key.Level];
  363. }
  364. if (kvp.Value.HasOption(CellOptions.Portal))
  365. {
  366. Portal portal = new Portal();
  367. portal.Create(new GPS(kvp.Key));
  368. portal.SetDestination(GetCell(kvp.Value.OptionValue));
  369. }
  370. }
  371. }
  372. /// <summary>
  373. /// Gets a Cell of the map with the specified ID.
  374. /// </summary>
  375. /// <param name="cellId">ID of the Cell.</param>
  376. /// <returns>Found Cell or default Cell value when no cells were found.</returns>
  377. public Cell GetCell(int cellId)
  378. {
  379. if (this.mapCellsIds.ContainsKey(cellId) && this.mapCells.ContainsKey(this.mapCellsIds[cellId]))
  380. return this.mapCells[this.mapCellsIds[cellId]];
  381. // return default cell
  382. Cell defaultCell = new Cell();
  383. defaultCell.Initialize();
  384. return defaultCell;
  385. }
  386. /// <summary>
  387. /// Gets a Cell of the map with the specified Location.
  388. /// </summary>
  389. /// <param name="location">Location where the Cell is expected to be.</param>
  390. /// <returns>Found Cell or default Cell value when no cells were found.</returns>
  391. public Cell GetCell(GridLocation location)
  392. {
  393. if (this.mapCells.ContainsKey(location))
  394. return this.mapCells[location];
  395. // return default cell
  396. Cell cell = new Cell();
  397. cell.Initialize();
  398. return cell;
  399. }
  400. /// <summary>
  401. /// Gets a Cell of the map with the specified Position.
  402. /// </summary>
  403. /// <param name="location">Location where the Cell is expected to be.</param>
  404. /// <returns>Found Cell or default Cell value when no cells were found.</returns>
  405. public Cell GetCell(GPS position)
  406. {
  407. return GetCell(position.Location);
  408. }
  409. private bool AddCell(Cell newCell, bool isReplaceOnExist = false)
  410. {
  411. // A Cell with the same id or at the same location exists
  412. if (this.mapCellsIds.ContainsKey(newCell.ID) || this.mapCells.ContainsKey(newCell.Location))
  413. {
  414. if (!isReplaceOnExist)
  415. return false;
  416. this.mapCells.Remove(newCell.Location);
  417. this.mapCellsIds.Remove(newCell.ID);
  418. }
  419. this.mapCells.Add(newCell.Location, newCell);
  420. this.mapCellsIds.Add(newCell.ID, newCell.Location);
  421. return true;
  422. }
  423. public string[] GetMapNames()
  424. {
  425. if (this.mapNames == null || this.mapNames.Length == 0)
  426. return null;
  427. string[] result = new string[this.mapNames.Length];
  428. Array.Copy(this.mapNames, result, this.mapNames.Length);
  429. return result;
  430. }
  431. /// <summary>
  432. /// Determies if the specifed Map name is exists in the list of loaded maps.
  433. /// </summary>
  434. /// <param name="MapName">Name of the map to check</param>
  435. /// <returns><c>true</c> if the map file with the specified name was loaded; otherwise, <c>false</c>.</returns>
  436. private bool IsMapExist(string MapName)
  437. {
  438. for (int i = 0; i < this.mapNames.Count(); ++i)
  439. if (this.mapNames[i].Equals(MapName))
  440. return true;
  441. return false;
  442. }
  443. /// <summary>
  444. /// Processes picking up the Drop on the map by the <see cref="Slug"/>.
  445. /// </summary>
  446. /// <param name="drop">The reference to an Drop object that has been collected.</param>
  447. public void CollectDrop(OozeDrop drop)
  448. {
  449. --dropsCount[CurrentLevel];
  450. }
  451. }
  452. }