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.

ActionManager.cs 22 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. using System;
  2. using System.Threading;
  3. using GameClass.GameObj;
  4. using GameEngine;
  5. using Preparation.Interface;
  6. using Preparation.Utility;
  7. using Timothy.FrameRateTask;
  8. namespace Gaming
  9. {
  10. public partial class Game
  11. {
  12. private readonly ActionManager actionManager;
  13. private class ActionManager
  14. {
  15. // 人物移动
  16. public bool MovePlayer(Character playerToMove, int moveTimeInMilliseconds, double moveDirection)
  17. {
  18. if (!playerToMove.Commandable()) return false;
  19. moveEngine.MoveObj(playerToMove, moveTimeInMilliseconds, moveDirection);
  20. return true;
  21. }
  22. public static bool Stop(Character player)
  23. {
  24. if (player.Commandable())
  25. {
  26. player.PlayerState = PlayerStateType.Null;
  27. return true;
  28. }
  29. return false;
  30. }
  31. public bool Fix(Student player)// 自动检查有无发电机可修
  32. {
  33. if (player.IsGhost() || (!player.Commandable()) || player.PlayerState == PlayerStateType.Fixing)
  34. return false;
  35. Generator? generatorForFix = null;
  36. gameMap.GameObjLockDict[GameObjType.Generator].EnterReadLock();
  37. try
  38. {
  39. foreach (Generator generator in gameMap.GameObjDict[GameObjType.Generator])
  40. {
  41. if (GameData.ApproachToInteract(generator.Position, player.Position))
  42. {
  43. generatorForFix = generator;
  44. break;
  45. }
  46. }
  47. }
  48. finally
  49. {
  50. gameMap.GameObjLockDict[GameObjType.Generator].ExitReadLock();
  51. }
  52. if (generatorForFix == null || generatorForFix.DegreeOfRepair == GameData.degreeOfFixedGenerator)
  53. return false;
  54. player.PlayerState = PlayerStateType.Fixing;
  55. new Thread
  56. (
  57. () =>
  58. {
  59. new FrameRateTaskExecutor<int>(
  60. loopCondition: () => player.PlayerState == PlayerStateType.Fixing && gameMap.Timer.IsGaming && generatorForFix.DegreeOfRepair < GameData.degreeOfFixedGenerator && GameData.ApproachToInteract(player.Position, generatorForFix.Position),
  61. loopToDo: () =>
  62. {
  63. generatorForFix.Repair(player.FixSpeed * GameData.frameDuration);
  64. },
  65. timeInterval: GameData.frameDuration,
  66. finallyReturn: () => 0
  67. )
  68. .Start();
  69. if (generatorForFix.DegreeOfRepair >= GameData.degreeOfFixedGenerator)
  70. {
  71. Doorway exit = (Doorway)gameMap.GameObjDict[GameObjType.Doorway][1];
  72. if (!exit.PowerSupply)
  73. {
  74. gameMap.GameObjLockDict[GameObjType.Generator].EnterReadLock();
  75. try
  76. {
  77. int numOfFixedGenerator = 0;
  78. foreach (Generator generator in gameMap.GameObjDict[GameObjType.Generator])
  79. if (generator.DegreeOfRepair == GameData.degreeOfFixedGenerator)
  80. ++numOfFixedGenerator;
  81. if (numOfFixedGenerator >= GameData.numOfGeneratorRequiredForRepair)
  82. {
  83. gameMap.GameObjLockDict[GameObjType.Doorway].EnterWriteLock();
  84. try
  85. {
  86. foreach (Doorway doorway in gameMap.GameObjDict[GameObjType.Doorway])
  87. doorway.PowerSupply = true;
  88. }
  89. finally
  90. {
  91. gameMap.GameObjLockDict[GameObjType.Doorway].ExitWriteLock();
  92. }
  93. }
  94. }
  95. finally
  96. {
  97. gameMap.GameObjLockDict[GameObjType.Generator].ExitReadLock();
  98. }
  99. }
  100. }
  101. }
  102. )
  103. { IsBackground = true }.Start();
  104. return true;
  105. }
  106. public bool OpenDoorWay(Student player)
  107. {
  108. if (!(player.Commandable()) || player.PlayerState == PlayerStateType.OpeningTheDoorWay)
  109. return false;
  110. Doorway? doorwayToOpen = (Doorway?)gameMap.OneForInteract(player.Position, GameObjType.Doorway);
  111. if (doorwayToOpen == null || doorwayToOpen.IsOpening || !doorwayToOpen.PowerSupply)
  112. return false;
  113. player.PlayerState = PlayerStateType.OpeningTheDoorWay;
  114. doorwayToOpen.IsOpening = true;
  115. new Thread
  116. (
  117. () =>
  118. {
  119. new FrameRateTaskExecutor<int>(
  120. loopCondition: () => doorwayToOpen.IsOpening && player.PlayerState == PlayerStateType.OpeningTheDoorWay && gameMap.Timer.IsGaming && doorwayToOpen.OpenDegree < GameData.degreeOfOpenedDoorway && GameData.ApproachToInteract(player.Position, doorwayToOpen.Position),
  121. loopToDo: () =>
  122. {
  123. doorwayToOpen.OpenDegree += GameData.frameDuration;
  124. },
  125. timeInterval: GameData.frameDuration,
  126. finallyReturn: () => 0
  127. )
  128. .Start();
  129. doorwayToOpen.IsOpening = false;
  130. if (doorwayToOpen.OpenDegree >= GameData.degreeOfOpenedDoorway)
  131. {
  132. if (player.PlayerState == PlayerStateType.OpeningTheDoorWay)
  133. player.PlayerState = PlayerStateType.Null;
  134. }
  135. }
  136. )
  137. { IsBackground = true }.Start();
  138. return true;
  139. }
  140. public bool Escape(Student player)
  141. {
  142. if (!(player.Commandable()))
  143. return false;
  144. Doorway? doorwayForEscape = null;
  145. gameMap.GameObjLockDict[GameObjType.Doorway].EnterReadLock();
  146. try
  147. {
  148. foreach (Doorway doorway in gameMap.GameObjDict[GameObjType.Doorway])
  149. {
  150. if (GameData.IsInTheSameCell(doorway.Position, player.Position))
  151. {
  152. doorwayForEscape = doorway;
  153. break;
  154. }
  155. }
  156. }
  157. finally
  158. {
  159. gameMap.GameObjLockDict[GameObjType.Doorway].ExitReadLock();
  160. }
  161. if (doorwayForEscape != null && doorwayForEscape.IsOpen())
  162. {
  163. player.Die(PlayerStateType.Escaped);
  164. return true;
  165. }
  166. else
  167. return false;
  168. }
  169. public bool Treat(Student player, Student playerTreated)
  170. {
  171. if ((!player.Commandable()) || player.PlayerState == PlayerStateType.Treating ||
  172. (!playerTreated.Commandable()) ||
  173. playerTreated.HP == playerTreated.MaxHp || !GameData.ApproachToInteract(playerTreated.Position, player.Position))
  174. return false;
  175. if (playerTreated.HP + playerTreated.DegreeOfTreatment >= playerTreated.MaxHp)
  176. {
  177. playerTreated.HP = playerTreated.MaxHp;
  178. playerTreated.DegreeOfTreatment = 0;
  179. return false;
  180. }
  181. if (playerTreated.DegreeOfTreatment >= GameData.basicTreatmentDegree)
  182. {
  183. playerTreated.HP += GameData.basicTreatmentDegree;
  184. playerTreated.DegreeOfTreatment = 0;
  185. return false;
  186. }
  187. new Thread
  188. (
  189. () =>
  190. {
  191. new FrameRateTaskExecutor<int>(
  192. loopCondition: () => playerTreated.PlayerState == PlayerStateType.Treated && player.PlayerState == PlayerStateType.Treating && gameMap.Timer.IsGaming && playerTreated.HP + playerTreated.DegreeOfTreatment < playerTreated.MaxHp && playerTreated.DegreeOfTreatment < GameData.basicTreatmentDegree && GameData.ApproachToInteract(playerTreated.Position, player.Position),
  193. loopToDo: () =>
  194. {
  195. playerTreated.DegreeOfTreatment += GameData.frameDuration * player.TreatSpeed;
  196. },
  197. timeInterval: GameData.frameDuration,
  198. finallyReturn: () => 0
  199. )
  200. .Start();
  201. if (playerTreated.PlayerState == PlayerStateType.Treated) playerTreated.PlayerState = PlayerStateType.Null;
  202. if (player.PlayerState == PlayerStateType.Treating) player.PlayerState = PlayerStateType.Null;
  203. if (playerTreated.HP + playerTreated.DegreeOfTreatment >= playerTreated.MaxHp)
  204. {
  205. playerTreated.HP = playerTreated.MaxHp;
  206. playerTreated.DegreeOfTreatment = 0;
  207. }
  208. else
  209. if (playerTreated.DegreeOfTreatment >= GameData.basicTreatmentDegree)
  210. {
  211. playerTreated.HP += GameData.basicTreatmentDegree;
  212. playerTreated.DegreeOfTreatment = 0;
  213. }
  214. }
  215. )
  216. { IsBackground = true }.Start();
  217. return true;
  218. }
  219. public bool Rescue(Student player, Student playerRescued)
  220. {
  221. if ((!player.Commandable()) || playerRescued.PlayerState != PlayerStateType.Addicted || !GameData.ApproachToInteract(playerRescued.Position, player.Position))
  222. return false;
  223. player.PlayerState = PlayerStateType.Rescuing;
  224. playerRescued.PlayerState = PlayerStateType.Rescued;
  225. player.TimeOfRescue = 0;
  226. new Thread
  227. (
  228. () =>
  229. {
  230. new FrameRateTaskExecutor<int>(
  231. loopCondition: () => playerRescued.PlayerState == PlayerStateType.Rescued && player.PlayerState == PlayerStateType.Rescuing && gameMap.Timer.IsGaming && GameData.ApproachToInteract(playerRescued.Position, player.Position),
  232. loopToDo: () =>
  233. {
  234. player.TimeOfRescue += GameData.frameDuration;
  235. },
  236. timeInterval: GameData.frameDuration,
  237. finallyReturn: () => 0,
  238. maxTotalDuration: GameData.basicTimeOfRescue
  239. )
  240. .Start();
  241. if (player.TimeOfRescue >= GameData.basicTimeOfRescue)
  242. {
  243. if (playerRescued.PlayerState == PlayerStateType.Rescued) playerRescued.PlayerState = PlayerStateType.Null;
  244. if (player.PlayerState == PlayerStateType.Rescuing) player.PlayerState = PlayerStateType.Null;
  245. }
  246. else
  247. {
  248. if (playerRescued.PlayerState == PlayerStateType.Rescued) playerRescued.PlayerState = PlayerStateType.Null;
  249. if (player.PlayerState == PlayerStateType.Rescuing) player.PlayerState = PlayerStateType.Addicted;
  250. }
  251. player.TimeOfRescue = 0;
  252. }
  253. )
  254. { IsBackground = true }.Start();
  255. return true;
  256. }
  257. public bool OpenChest(Character player)
  258. {
  259. if ((!player.Commandable()) || player.PlayerState == PlayerStateType.OpeningTheChest)
  260. return false;
  261. Chest? chestToOpen = (Chest?)gameMap.OneForInteract(player.Position, GameObjType.Chest);
  262. if (chestToOpen == null || chestToOpen.IsOpen)
  263. return false;
  264. player.PlayerState = PlayerStateType.OpeningTheChest;
  265. new Thread
  266. (
  267. () =>
  268. {
  269. int OpenDegree = 0;
  270. new FrameRateTaskExecutor<int>(
  271. loopCondition: () => player.PlayerState == PlayerStateType.OpeningTheChest && gameMap.Timer.IsGaming && OpenDegree < player.TimeOfOpenChest,
  272. loopToDo: () =>
  273. {
  274. OpenDegree += GameData.frameDuration;
  275. },
  276. timeInterval: GameData.frameDuration,
  277. finallyReturn: () => 0
  278. )
  279. .Start();
  280. if (OpenDegree >= player.TimeOfOpenChest)
  281. {
  282. chestToOpen.IsOpen = true;
  283. if (player.PlayerState == PlayerStateType.OpeningTheChest)
  284. player.PlayerState = PlayerStateType.Null;
  285. for (int i = 0; i < GameData.maxNumOfPropInChest; ++i)
  286. {
  287. Prop prop = chestToOpen.PropInChest[i];
  288. chestToOpen.PropInChest[i] = new NullProp();
  289. prop.ReSetPos(player.Position, gameMap.GetPlaceType(player.Position));
  290. gameMap.Add(prop);
  291. }
  292. }
  293. }
  294. )
  295. { IsBackground = true }.Start();
  296. return true;
  297. }
  298. public bool ClimbingThroughWindow(Character player)
  299. {
  300. if (!player.Commandable())
  301. return false;
  302. Window? windowForClimb = (Window?)gameMap.OneForInteractInACross(player.Position, GameObjType.Window);
  303. if (windowForClimb == null || windowForClimb.WhoIsClimbing != null)
  304. return false;
  305. player.PlayerState = PlayerStateType.ClimbingThroughWindows;
  306. windowForClimb.WhoIsClimbing = player;
  307. XY windowToPlayer = new XY(
  308. (Math.Abs(player.Position.x - windowForClimb.Position.x) > GameData.numOfPosGridPerCell / 2) ? (GameData.numOfPosGridPerCell / 2 * (player.Position.x > windowForClimb.Position.x ? 1 : -1)) : 0,
  309. (Math.Abs(player.Position.y - windowForClimb.Position.y) > GameData.numOfPosGridPerCell / 2) ? (GameData.numOfPosGridPerCell / 2 * (player.Position.y > windowForClimb.Position.y ? 1 : -1)) : 0)
  310. ;
  311. new Thread
  312. (
  313. () =>
  314. {
  315. new FrameRateTaskExecutor<int>(
  316. loopCondition: () => player.PlayerState == PlayerStateType.ClimbingThroughWindows && gameMap.Timer.IsGaming,
  317. loopToDo: () => { },
  318. timeInterval: GameData.frameDuration,
  319. finallyReturn: () => 0,
  320. maxTotalDuration: (int)((windowToPlayer + windowForClimb.Position - player.Position).Length() / player.MoveSpeed)
  321. )
  322. .Start();
  323. if (player.PlayerState != PlayerStateType.ClimbingThroughWindows)
  324. {
  325. windowForClimb.WhoIsClimbing = null;
  326. return;
  327. }
  328. player.ReSetPos(windowToPlayer + windowForClimb.Position, PlaceType.Window);
  329. player.MoveSpeed = player.SpeedOfClimbingThroughWindows;
  330. MovePlayer(player, (int)(windowToPlayer.Length() * 3.0 / player.MoveSpeed), (-1 * windowToPlayer).Angle());
  331. new FrameRateTaskExecutor<int>(
  332. loopCondition: () => player.PlayerState == PlayerStateType.ClimbingThroughWindows && player.IsMoving && gameMap.Timer.IsGaming,
  333. loopToDo: () => { },
  334. timeInterval: GameData.frameDuration,
  335. finallyReturn: () => 0,
  336. maxTotalDuration: (int)(windowToPlayer.Length() * 3.0 / player.MoveSpeed)
  337. )
  338. .Start();
  339. XY PosJumpOff = windowForClimb.Position - 2 * windowToPlayer;
  340. player.ReSetPos(PosJumpOff, gameMap.GetPlaceType(PosJumpOff));
  341. player.MoveSpeed = player.buffManager.ReCalculateFloatBuff(BuffType.AddSpeed, player.OrgMoveSpeed, GameData.MaxSpeed, GameData.MinSpeed);
  342. windowForClimb.WhoIsClimbing = null;
  343. if (player.PlayerState == PlayerStateType.ClimbingThroughWindows)
  344. {
  345. player.PlayerState = PlayerStateType.Null;
  346. }
  347. }
  348. )
  349. { IsBackground = true }.Start();
  350. return true;
  351. }
  352. public bool LockOrOpenDoor(Character player)
  353. {
  354. if (!(player.Commandable()) || player.PlayerState == PlayerStateType.LockingOrOpeningTheDoor)
  355. return false;
  356. Door? doorToLock = (Door?)gameMap.OneForInteract(player.Position, GameObjType.Door);
  357. if (doorToLock == null)
  358. return false;
  359. bool flag = false;
  360. foreach (Prop prop in player.PropInventory)
  361. {
  362. switch (prop.GetPropType())
  363. {
  364. case PropType.Key3:
  365. if (doorToLock.Place == PlaceType.Door3)
  366. flag = true;
  367. break;
  368. case PropType.Key5:
  369. if (doorToLock.Place == PlaceType.Door5)
  370. flag = true;
  371. break;
  372. case PropType.Key6:
  373. if (doorToLock.Place == PlaceType.Door6)
  374. flag = true;
  375. break;
  376. default:
  377. break;
  378. }
  379. if (flag) break;
  380. }
  381. if (!flag) return false;
  382. player.PlayerState = PlayerStateType.LockingOrOpeningTheDoor;
  383. /* new Thread
  384. (
  385. () =>
  386. {
  387. new FrameRateTaskExecutor<int>(
  388. loopCondition: () => doorToLock.IsOpening && player.PlayerState == PlayerStateType.OpeningTheDoorWay && gameMap.Timer.IsGaming && doorToLock.OpenDegree < GameData.degreeOfOpenedDoorway && GameData.ApproachToInteract(player.Position, doorToLock.Position),
  389. loopToDo: () =>
  390. {
  391. doorToLock.OpenDegree += GameData.frameDuration;
  392. },
  393. timeInterval: GameData.frameDuration,
  394. finallyReturn: () => 0
  395. )
  396. .Start();
  397. doorToLock.IsOpening = false;
  398. if (doorToLock.OpenDegree >= GameData.degreeOfOpenedDoorway)
  399. {
  400. if (player.PlayerState == PlayerStateType.OpeningTheDoorWay)
  401. player.PlayerState = PlayerStateType.Null;
  402. }
  403. }
  404. )
  405. { IsBackground = true }.Start();
  406. */
  407. return true;
  408. }
  409. /*
  410. private void ActivateMine(Character player, Mine mine)
  411. {
  412. gameMap.ObjListLock.EnterWriteLock();
  413. try { gameMap.ObjList.Remove(mine); }
  414. catch { }
  415. finally { gameMap.ObjListLock.ExitWriteLock(); }
  416. switch (mine.GetPropType())
  417. {
  418. case PropType.Dirt:
  419. player.AddMoveSpeed(Constant.dirtMoveSpeedDebuff, Constant.buffPropTime);
  420. break;
  421. case PropType.Attenuator:
  422. player.AddAP(Constant.attenuatorAtkDebuff, Constant.buffPropTime);
  423. break;
  424. case PropType.Divider:
  425. player.ChangeCD(Constant.dividerCdDiscount, Constant.buffPropTime);
  426. break;
  427. }
  428. }
  429. */
  430. private readonly Map gameMap;
  431. private readonly MoveEngine moveEngine;
  432. public ActionManager(Map gameMap)
  433. {
  434. this.gameMap = gameMap;
  435. this.moveEngine = new MoveEngine(
  436. gameMap: gameMap,
  437. OnCollision: (obj, collisionObj, moveVec) =>
  438. {
  439. //if (collisionObj is Mine)
  440. //{
  441. // ActivateMine((Character)obj, (Mine)collisionObj);
  442. // return MoveEngine.AfterCollision.ContinueCheck;
  443. //}
  444. return MoveEngine.AfterCollision.MoveMax;
  445. },
  446. EndMove: obj =>
  447. {
  448. // Debugger.Output(obj, " end move at " + obj.Position.ToString() + " At time: " + Environment.TickCount64);
  449. }
  450. );
  451. }
  452. }
  453. }
  454. }