You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

Map.cs 14 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. using System.Collections.Generic;
  2. using System.Threading;
  3. using Preparation.Interface;
  4. using Preparation.Utility;
  5. using System;
  6. using System.Collections.Concurrent;
  7. namespace GameClass.GameObj
  8. {
  9. public partial class Map : IMap
  10. {
  11. private readonly Dictionary<uint, XY> birthPointList; // 出生点列表
  12. public Dictionary<uint, XY> BirthPointList => birthPointList;
  13. private uint numOfRepairedGenerators = 0;
  14. public uint NumOfRepairedGenerators
  15. {
  16. get => Interlocked.CompareExchange(ref numOfRepairedGenerators, 0, 0);
  17. }
  18. public void AddNumOfRepairedGenerators()
  19. {
  20. uint value = Interlocked.Increment(ref numOfRepairedGenerators);
  21. if (value == GameData.numOfGeneratorRequiredForEmergencyExit)
  22. {
  23. Random r = new(Environment.TickCount);
  24. EmergencyExit emergencyExit = (EmergencyExit)(GameObjDict[GameObjType.EmergencyExit][r.Next(0, GameObjDict[GameObjType.EmergencyExit].Count)]);
  25. emergencyExit.CanOpen.SetReturnOri(true);
  26. Preparation.Utility.Debugger.Output(emergencyExit, emergencyExit.Position.ToString());
  27. }
  28. else
  29. if (value == GameData.numOfGeneratorRequiredForRepair)
  30. {
  31. GameObjDict[GameObjType.Doorway].ForEach(delegate (IGameObj doorway)
  32. {
  33. ((Doorway)doorway).PowerSupply.SetReturnOri(true);
  34. });
  35. }
  36. }
  37. private uint numOfDeceasedStudent = 0;
  38. public uint NumOfDeceasedStudent
  39. {
  40. get => Interlocked.CompareExchange(ref numOfDeceasedStudent, 0, 0);
  41. }
  42. private uint numOfEscapedStudent = 0;
  43. public uint NumOfEscapedStudent
  44. {
  45. get => Interlocked.CompareExchange(ref numOfEscapedStudent, 0, 0);
  46. }
  47. private uint numOfNoHpStudent = 0;
  48. public uint NumOfNoHpStudent
  49. {
  50. get => Interlocked.CompareExchange(ref numOfNoHpStudent, 0, 0);
  51. }
  52. private uint numOfRemovedStudent = 0;
  53. public uint NumOfRemovedStudent
  54. {
  55. get => Interlocked.CompareExchange(ref numOfRemovedStudent, 0, 0);
  56. }
  57. public void MapEscapeStudent()
  58. {
  59. if (Interlocked.Increment(ref numOfRemovedStudent) == GameData.numOfStudent - 1)
  60. OpenEmergencyExit();
  61. if (Interlocked.Increment(ref numOfNoHpStudent) == GameData.numOfStudent)
  62. {
  63. AddScoreFromAddict();
  64. Timer.IsGaming = false;
  65. return;
  66. }
  67. Interlocked.Increment(ref numOfEscapedStudent);
  68. }
  69. public void MapDieStudent()
  70. {
  71. if (Interlocked.Increment(ref numOfRemovedStudent) == GameData.numOfStudent - 1)
  72. OpenEmergencyExit();
  73. uint noHp = Interlocked.Increment(ref numOfNoHpStudent);
  74. ghost!.AddScore(GameData.TrickerScoreStudentDie);
  75. if (noHp == GameData.numOfStudent)
  76. {
  77. AddScoreFromAddict();
  78. Timer.IsGaming = false;
  79. return;
  80. }
  81. Interlocked.Increment(ref numOfDeceasedStudent);
  82. }
  83. public void MapAddictStudent()
  84. {
  85. if (Interlocked.Increment(ref numOfNoHpStudent) == GameData.numOfStudent)
  86. {
  87. AddScoreFromAddict();
  88. Timer.IsGaming = false;
  89. }
  90. }
  91. public void MapRescueStudent()
  92. {
  93. if (Timer.IsGaming)
  94. Interlocked.Decrement(ref numOfNoHpStudent);
  95. }
  96. private void OpenEmergencyExit()
  97. {
  98. EmergencyExit? emergencyExit =
  99. (EmergencyExit?)GameObjDict[GameObjType.EmergencyExit].Find(gameObj => ((EmergencyExit)gameObj).CanOpen);
  100. if (emergencyExit != null)
  101. emergencyExit.IsOpen = true;
  102. }
  103. private void AddScoreFromAddict()
  104. {
  105. ghost!.AddScore(GameData.TrickerScoreStudentDie * (GameData.numOfStudent - NumOfRemovedStudent));
  106. }
  107. private Dictionary<GameObjType, LockedClassList<IGameObj>> gameObjDict;
  108. public Dictionary<GameObjType, LockedClassList<IGameObj>> GameObjDict => gameObjDict;
  109. public readonly uint[,] protoGameMap;
  110. public uint[,] ProtoGameMap => protoGameMap;
  111. public PlaceType GetPlaceType(IGameObj obj)
  112. {
  113. try
  114. {
  115. return (PlaceType)protoGameMap[obj.Position.x / GameData.numOfPosGridPerCell, obj.Position.y / GameData.numOfPosGridPerCell];
  116. }
  117. catch
  118. {
  119. return PlaceType.Null;
  120. }
  121. }
  122. public PlaceType GetPlaceType(XY pos)
  123. {
  124. try
  125. {
  126. return (PlaceType)protoGameMap[pos.x / GameData.numOfPosGridPerCell, pos.y / GameData.numOfPosGridPerCell];
  127. }
  128. catch
  129. {
  130. return PlaceType.Null;
  131. }
  132. }
  133. public bool IsOutOfBound(IGameObj obj)
  134. {
  135. return obj.Position.x >= GameData.lengthOfMap - obj.Radius || obj.Position.x <= obj.Radius || obj.Position.y >= GameData.lengthOfMap - obj.Radius || obj.Position.y <= obj.Radius;
  136. }
  137. public IOutOfBound GetOutOfBound(XY pos)
  138. {
  139. return new OutOfBoundBlock(pos);
  140. }
  141. public Character? FindPlayerInID(long playerID)
  142. {
  143. return (Character?)GameObjDict[GameObjType.Character].Find(gameObj => (playerID == ((Character)gameObj).ID));
  144. }
  145. public Character? FindPlayerInPlayerID(long playerID)
  146. {
  147. return (Character?)GameObjDict[GameObjType.Character].Find(gameObj => (playerID == ((Character)gameObj).PlayerID));
  148. }
  149. public Ghost? ghost = null;
  150. public Character? FindPlayerToAction(long playerID)
  151. {
  152. Character? player = (Character?)GameObjDict[GameObjType.Character].Find(gameObj => (playerID == ((Character)gameObj).ID));
  153. if (player == null) return null;
  154. if (player.CharacterType == CharacterType.TechOtaku)
  155. player = (Character?)GameObjDict[GameObjType.Character].Find(
  156. gameObj => (
  157. ((UseRobot)player.FindActiveSkill(ActiveSkillType.UseRobot)).NowPlayerID == ((Character)gameObj).PlayerID
  158. )
  159. );
  160. return player;
  161. }
  162. public GameObj? OneForInteract(XY Pos, GameObjType gameObjType)
  163. {
  164. return (GameObj?)GameObjDict[gameObjType].Find(gameObj => GameData.ApproachToInteract(gameObj.Position, Pos));
  165. }
  166. public Student? StudentForInteract(Student AStudent)
  167. {
  168. return (Student?)GameObjDict[GameObjType.Character].Find(gameObj =>
  169. {
  170. Character character = (Character)gameObj;
  171. return !character.IsGhost() && character != AStudent && GameData.ApproachToInteract(character.Position, AStudent.Position);
  172. });
  173. }
  174. public GameObj? OneInTheSameCell(XY Pos, GameObjType gameObjType)
  175. {
  176. return (GameObj?)GameObjDict[gameObjType].Find(gameObj =>
  177. GameData.IsInTheSameCell(gameObj.Position, Pos)
  178. );
  179. }
  180. public GameObj? PartInTheSameCell(XY Pos, GameObjType gameObjType)
  181. {
  182. return (GameObj?)GameObjDict[gameObjType].Find(gameObj =>
  183. GameData.PartInTheSameCell(gameObj.Position, Pos)
  184. );
  185. }
  186. public GameObj? OneForInteractInACross(XY Pos, GameObjType gameObjType)
  187. {
  188. return (GameObj?)GameObjDict[gameObjType].Find(gameObj =>
  189. GameData.ApproachToInteractInACross(gameObj.Position, Pos));
  190. }
  191. public bool CanSee(Character player, GameObj gameObj)
  192. {
  193. if ((gameObj.Type == GameObjType.Character) && ((Character)gameObj).HasInvisible) return false;
  194. XY pos1 = player.Position;
  195. XY pos2 = gameObj.Position;
  196. XY del = pos1 - pos2;
  197. if (del * del > player.ViewRange * player.ViewRange) return false;
  198. if (del.x > del.y)
  199. {
  200. if (GetPlaceType(pos1) == PlaceType.Grass && GetPlaceType(pos2) == PlaceType.Grass)
  201. {
  202. for (int x = GameData.PosGridToCellX(pos1) + GameData.numOfPosGridPerCell; x < GameData.PosGridToCellX(pos2); x += GameData.numOfPosGridPerCell)
  203. {
  204. if (GetPlaceType(pos1 + del * (x / del.x)) != PlaceType.Grass)
  205. return false;
  206. }
  207. }
  208. else
  209. {
  210. for (int x = GameData.PosGridToCellX(pos1) + GameData.numOfPosGridPerCell; x < GameData.PosGridToCellX(pos2); x += GameData.numOfPosGridPerCell)
  211. {
  212. if (GetPlaceType(pos1 + del * (x / del.x)) == PlaceType.Wall)
  213. return false;
  214. }
  215. }
  216. }
  217. else
  218. {
  219. if (GetPlaceType(pos1) == PlaceType.Grass && GetPlaceType(pos2) == PlaceType.Grass)
  220. {
  221. for (int y = GameData.PosGridToCellY(pos1) + GameData.numOfPosGridPerCell; y < GameData.PosGridToCellY(pos2); y += GameData.numOfPosGridPerCell)
  222. {
  223. if (GetPlaceType(pos1 + del * (y / del.y)) != PlaceType.Grass)
  224. return false;
  225. }
  226. }
  227. else
  228. {
  229. for (int y = GameData.PosGridToCellY(pos1) + GameData.numOfPosGridPerCell; y < GameData.PosGridToCellY(pos2); y += GameData.numOfPosGridPerCell)
  230. {
  231. if (GetPlaceType(pos1 + del * (y / del.y)) == PlaceType.Wall)
  232. return false;
  233. }
  234. }
  235. }
  236. return true;
  237. }
  238. public bool Remove(GameObj gameObj)
  239. {
  240. if (GameObjDict[gameObj.Type].RemoveOne(obj => gameObj.ID == obj.ID))
  241. {
  242. gameObj.TryToRemove();
  243. return true;
  244. }
  245. return false;
  246. }
  247. public bool RemoveJustFromMap(GameObj gameObj)
  248. {
  249. if (GameObjDict[gameObj.Type].Remove(gameObj))
  250. {
  251. gameObj.TryToRemove();
  252. return true;
  253. }
  254. return false;
  255. }
  256. public void Add(GameObj gameObj)
  257. {
  258. GameObjDict[gameObj.Type].Add(gameObj);
  259. }
  260. public Map(uint[,] mapResource)
  261. {
  262. gameObjDict = new Dictionary<GameObjType, LockedClassList<IGameObj>>();
  263. foreach (GameObjType idx in Enum.GetValues(typeof(GameObjType)))
  264. {
  265. if (idx != GameObjType.Null)
  266. {
  267. gameObjDict.TryAdd(idx, new LockedClassList<IGameObj>());
  268. }
  269. }
  270. protoGameMap = new uint[mapResource.GetLength(0), mapResource.GetLength(1)];
  271. Array.Copy(mapResource, protoGameMap, mapResource.Length);
  272. birthPointList = new Dictionary<uint, XY>(GameData.numOfBirthPoint);
  273. for (int i = 0; i < GameData.rows; ++i)
  274. {
  275. for (int j = 0; j < GameData.cols; ++j)
  276. {
  277. switch (mapResource[i, j])
  278. {
  279. case (uint)PlaceType.Wall:
  280. {
  281. Add(new Wall(GameData.GetCellCenterPos(i, j)));
  282. break;
  283. }
  284. case (uint)PlaceType.Doorway:
  285. {
  286. Add(new Doorway(GameData.GetCellCenterPos(i, j)));
  287. break;
  288. }
  289. case (uint)PlaceType.EmergencyExit:
  290. {
  291. Add(new EmergencyExit(GameData.GetCellCenterPos(i, j)));
  292. break;
  293. }
  294. case (uint)PlaceType.Generator:
  295. {
  296. Add(new Generator(GameData.GetCellCenterPos(i, j)));
  297. break;
  298. }
  299. case (uint)PlaceType.Chest:
  300. {
  301. Add(new Chest(GameData.GetCellCenterPos(i, j)));
  302. break;
  303. }
  304. case (uint)PlaceType.Door3:
  305. {
  306. Add(new Door(GameData.GetCellCenterPos(i, j), PlaceType.Door3));
  307. break;
  308. }
  309. case (uint)PlaceType.Door5:
  310. {
  311. Add(new Door(GameData.GetCellCenterPos(i, j), PlaceType.Door5));
  312. break;
  313. }
  314. case (uint)PlaceType.Door6:
  315. {
  316. Add(new Door(GameData.GetCellCenterPos(i, j), PlaceType.Door6));
  317. break;
  318. }
  319. case (uint)PlaceType.Window:
  320. {
  321. Add(new Window(GameData.GetCellCenterPos(i, j)));
  322. break;
  323. }
  324. case (uint)PlaceType.BirthPoint1:
  325. case (uint)PlaceType.BirthPoint2:
  326. case (uint)PlaceType.BirthPoint3:
  327. case (uint)PlaceType.BirthPoint4:
  328. case (uint)PlaceType.BirthPoint5:
  329. {
  330. birthPointList.Add(mapResource[i, j], GameData.GetCellCenterPos(i, j));
  331. break;
  332. }
  333. }
  334. }
  335. }
  336. }
  337. }
  338. }