QuestProgressInfo.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. using Server.MirObjects;
  2. using Server.MirEnvir;
  3. namespace Server.MirDatabase
  4. {
  5. public class QuestProgressInfo
  6. {
  7. protected static Envir Envir
  8. {
  9. get { return Envir.Main; }
  10. }
  11. public PlayerObject Owner;
  12. public int Index;
  13. public QuestInfo Info;
  14. public DateTime StartDateTime = DateTime.MinValue;
  15. public DateTime EndDateTime = DateTime.MaxValue;
  16. public List<QuestKillTaskProgress> KillTaskCount = new List<QuestKillTaskProgress>();
  17. public List<QuestItemTaskProgress> ItemTaskCount = new List<QuestItemTaskProgress>();
  18. public List<QuestFlagTaskProgress> FlagTaskSet = new List<QuestFlagTaskProgress>();
  19. public List<string> TaskList = new List<string>();
  20. public bool IsOrphan { get; private set; }
  21. public bool Taken
  22. {
  23. get { return StartDateTime > DateTime.MinValue; }
  24. }
  25. public bool Completed
  26. {
  27. get { return EndDateTime < DateTime.MaxValue; }
  28. }
  29. public bool New
  30. {
  31. get { return StartDateTime > Envir.Now.AddDays(-1); }
  32. }
  33. public QuestProgressInfo(int index)
  34. {
  35. Index = index;
  36. Info = Envir.QuestInfoList.FirstOrDefault(e => e.Index == index);
  37. if (Info == null)
  38. {
  39. IsOrphan = true;
  40. return;
  41. }
  42. foreach (var kill in Info.KillTasks)
  43. {
  44. KillTaskCount.Add(new QuestKillTaskProgress
  45. {
  46. MonsterID = kill.Monster.Index,
  47. Info = kill
  48. });
  49. }
  50. foreach (var item in Info.ItemTasks)
  51. {
  52. ItemTaskCount.Add(new QuestItemTaskProgress
  53. {
  54. ItemID = item.Item.Index,
  55. Info = item
  56. });
  57. }
  58. foreach (var flag in Info.FlagTasks)
  59. {
  60. FlagTaskSet.Add(new QuestFlagTaskProgress
  61. {
  62. Number = flag.Number,
  63. Info = flag
  64. });
  65. }
  66. }
  67. public QuestProgressInfo(BinaryReader reader, int version, int customVersion)
  68. {
  69. Index = reader.ReadInt32();
  70. Info = Envir.QuestInfoList.FirstOrDefault(e => e.Index == Index);
  71. StartDateTime = DateTime.FromBinary(reader.ReadInt64());
  72. EndDateTime = DateTime.FromBinary(reader.ReadInt64());
  73. if (Info == null)
  74. {
  75. IsOrphan = true;
  76. if (version < 90)
  77. {
  78. int count = reader.ReadInt32();
  79. for (int i = 0; i < count; i++) reader.ReadInt32(); // Kill counts
  80. count = reader.ReadInt32();
  81. for (int i = 0; i < count; i++) reader.ReadInt32(); // Item counts
  82. count = reader.ReadInt32();
  83. for (int i = 0; i < count; i++) reader.ReadBoolean(); // Flag states
  84. }
  85. else
  86. {
  87. int count = reader.ReadInt32();
  88. for (int i = 0; i < count; i++)
  89. {
  90. reader.ReadInt32(); // MonsterID
  91. reader.ReadInt32(); // Count
  92. }
  93. count = reader.ReadInt32();
  94. for (int i = 0; i < count; i++)
  95. {
  96. reader.ReadInt32(); // ItemID
  97. reader.ReadInt32(); // Count
  98. }
  99. count = reader.ReadInt32();
  100. for (int i = 0; i < count; i++)
  101. {
  102. reader.ReadInt32(); // Flag Number
  103. reader.ReadBoolean(); // State
  104. }
  105. }
  106. return; // Skip rest of constructor if quest is missing
  107. }
  108. if (version < 90)
  109. {
  110. int count = reader.ReadInt32();
  111. for (int i = 0; i < count; i++)
  112. {
  113. var killCount = reader.ReadInt32();
  114. if (Info.KillTasks.Count > i)
  115. {
  116. var progress = new QuestKillTaskProgress
  117. {
  118. MonsterID = Info.KillTasks[i].Monster.Index,
  119. Count = killCount,
  120. Info = Info.KillTasks[i]
  121. };
  122. KillTaskCount.Add(progress);
  123. }
  124. }
  125. count = reader.ReadInt32();
  126. for (int i = 0; i < count; i++)
  127. {
  128. var itemCount = reader.ReadInt32();
  129. if (Info.ItemTasks.Count > i)
  130. {
  131. var progress = new QuestItemTaskProgress
  132. {
  133. ItemID = Info.ItemTasks[i].Item.Index,
  134. Count = itemCount,
  135. Info = Info.ItemTasks[i]
  136. };
  137. ItemTaskCount.Add(progress);
  138. }
  139. }
  140. count = reader.ReadInt32();
  141. for (int i = 0; i < count; i++)
  142. {
  143. var flagState = reader.ReadBoolean();
  144. if (Info.FlagTasks.Count > i)
  145. {
  146. var progress = new QuestFlagTaskProgress
  147. {
  148. Number = Info.FlagTasks[i].Number,
  149. State = flagState,
  150. Info = Info.FlagTasks[i]
  151. };
  152. FlagTaskSet.Add(progress);
  153. }
  154. }
  155. }
  156. else
  157. {
  158. int count = reader.ReadInt32();
  159. for (int i = 0; i < count; i++)
  160. {
  161. var progress = new QuestKillTaskProgress
  162. {
  163. MonsterID = reader.ReadInt32(),
  164. Count = reader.ReadInt32()
  165. };
  166. foreach (var task in Info.KillTasks)
  167. {
  168. if (task.Monster.Index != progress.MonsterID) continue;
  169. progress.Info = task;
  170. KillTaskCount.Add(progress);
  171. break;
  172. }
  173. }
  174. count = reader.ReadInt32();
  175. for (int i = 0; i < count; i++)
  176. {
  177. var progress = new QuestItemTaskProgress
  178. {
  179. ItemID = reader.ReadInt32(),
  180. Count = reader.ReadInt32()
  181. };
  182. foreach (var task in Info.ItemTasks)
  183. {
  184. if (task.Item.Index != progress.ItemID) continue;
  185. progress.Info = task;
  186. ItemTaskCount.Add(progress);
  187. break;
  188. }
  189. }
  190. count = reader.ReadInt32();
  191. for (int i = 0; i < count; i++)
  192. {
  193. var progress = new QuestFlagTaskProgress
  194. {
  195. Number = reader.ReadInt32(),
  196. State = reader.ReadBoolean()
  197. };
  198. foreach (var task in Info.FlagTasks)
  199. {
  200. if (task.Number != progress.Number) continue;
  201. progress.Info = task;
  202. FlagTaskSet.Add(progress);
  203. break;
  204. }
  205. }
  206. //Add any new tasks which may have been added
  207. foreach (var kill in Info.KillTasks)
  208. {
  209. if (KillTaskCount.Any(x => x.MonsterID == kill.Monster.Index)) continue;
  210. KillTaskCount.Add(new QuestKillTaskProgress
  211. {
  212. MonsterID = kill.Monster.Index,
  213. Info = kill
  214. });
  215. }
  216. foreach (var item in Info.ItemTasks)
  217. {
  218. if (ItemTaskCount.Any(x => x.ItemID == item.Item.Index)) continue;
  219. ItemTaskCount.Add(new QuestItemTaskProgress
  220. {
  221. ItemID = item.Item.Index,
  222. Info = item
  223. });
  224. }
  225. foreach (var flag in Info.FlagTasks)
  226. {
  227. if (FlagTaskSet.Any(x => x.Number == flag.Number)) continue;
  228. FlagTaskSet.Add(new QuestFlagTaskProgress
  229. {
  230. Number = flag.Number,
  231. Info = flag
  232. });
  233. }
  234. }
  235. }
  236. public void Init(PlayerObject player)
  237. {
  238. Owner = player;
  239. if (StartDateTime == DateTime.MinValue)
  240. {
  241. StartDateTime = Envir.Now;
  242. }
  243. }
  244. public void Save(BinaryWriter writer)
  245. {
  246. writer.Write(Index);
  247. writer.Write(StartDateTime.ToBinary());
  248. writer.Write(EndDateTime.ToBinary());
  249. writer.Write(KillTaskCount.Count);
  250. for (int i = 0; i < KillTaskCount.Count; i++)
  251. {
  252. writer.Write(KillTaskCount[i].MonsterID);
  253. writer.Write(KillTaskCount[i].Count);
  254. }
  255. writer.Write(ItemTaskCount.Count);
  256. for (int i = 0; i < ItemTaskCount.Count; i++)
  257. {
  258. writer.Write(ItemTaskCount[i].ItemID);
  259. writer.Write(ItemTaskCount[i].Count);
  260. }
  261. writer.Write(FlagTaskSet.Count);
  262. for (int i = 0; i < FlagTaskSet.Count; i++)
  263. {
  264. writer.Write(FlagTaskSet[i].Number);
  265. writer.Write(FlagTaskSet[i].State);
  266. }
  267. }
  268. public bool CheckCompleted()
  269. {
  270. UpdateTasks();
  271. bool canComplete = true;
  272. for (int j = 0; j < KillTaskCount.Count; j++)
  273. {
  274. if (KillTaskCount[j].Complete) continue;
  275. canComplete = false;
  276. }
  277. for (int j = 0; j < ItemTaskCount.Count; j++)
  278. {
  279. if (ItemTaskCount[j].Complete) continue;
  280. canComplete = false;
  281. }
  282. for (int j = 0; j < FlagTaskSet.Count; j++)
  283. {
  284. if (FlagTaskSet[j].Complete) continue;
  285. canComplete = false;
  286. }
  287. if (!canComplete) return false;
  288. if (!Completed)
  289. {
  290. EndDateTime = Envir.Now;
  291. if (Info.TimeLimitInSeconds > 0)
  292. {
  293. Owner.ExpireTimer($"Quest-{Index}");
  294. }
  295. }
  296. // updatetask again to show gototask
  297. UpdateTasks();
  298. return true;
  299. }
  300. #region Need Requirement
  301. public bool NeedItem(ItemInfo iInfo)
  302. {
  303. return ItemTaskCount.Where((task, i) => task.Info.Item == iInfo && !task.Complete).Any();
  304. }
  305. public bool NeedKill(MonsterInfo mInfo)
  306. {
  307. return KillTaskCount.Where((task, i) => mInfo.Name.StartsWith(task.Info.Monster.Name, StringComparison.OrdinalIgnoreCase) && !task.Complete).Any();
  308. }
  309. public bool NeedFlag(int flagNumber)
  310. {
  311. return FlagTaskSet.Where((task, i) => task.Number == flagNumber && !task.Complete).Any();
  312. }
  313. #endregion
  314. #region Process Quest Task
  315. public void ProcessKill(MonsterInfo mInfo)
  316. {
  317. if (Info.KillTasks.Count < 1) return;
  318. for (int i = 0; i < KillTaskCount.Count; i++)
  319. {
  320. if (!mInfo.Name.StartsWith(KillTaskCount[i].Info.Monster.Name, StringComparison.OrdinalIgnoreCase)) continue;
  321. KillTaskCount[i].Count++;
  322. return;
  323. }
  324. }
  325. public void ProcessItem(UserItem[] inventory)
  326. {
  327. for (int i = 0; i < ItemTaskCount.Count; i++)
  328. {
  329. var count = inventory.Where(item => item != null).
  330. Where(item => item.Info.Name == ItemTaskCount[i].Info.Item.Name).
  331. Aggregate<UserItem, int>(0, (current, item) => current + item.Count);
  332. ItemTaskCount[i].Count = count;
  333. }
  334. }
  335. public void ProcessFlag(bool[] Flags)
  336. {
  337. for (int i = 0; i < FlagTaskSet.Count; i++)
  338. {
  339. for (int j = 0; j < Flags.Length - 1000; j++)
  340. {
  341. if (FlagTaskSet[i].Number != j || !Flags[j]) continue;
  342. FlagTaskSet[i].State = Flags[j];
  343. break;
  344. }
  345. }
  346. }
  347. #endregion
  348. #region Update Task Messages
  349. public void UpdateTasks()
  350. {
  351. TaskList = new List<string>();
  352. UpdateKillTasks();
  353. UpdateItemTasks();
  354. UpdateFlagTasks();
  355. UpdateGotoTask();
  356. }
  357. public void UpdateKillTasks()
  358. {
  359. if(Info.KillMessage.Length > 0 && Info.KillTasks.Count > 0)
  360. {
  361. bool allComplete = true;
  362. for (int i = 0; i < KillTaskCount.Count; i++)
  363. {
  364. if (KillTaskCount[i].Complete) continue;
  365. allComplete = false;
  366. }
  367. TaskList.Add(string.Format("{0} {1}", Info.KillMessage, allComplete ? GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.TaskCompleted) : ""));
  368. return;
  369. }
  370. for (int i = 0; i < KillTaskCount.Count; i++)
  371. {
  372. if (string.IsNullOrEmpty(Info.KillTasks[i].Message))
  373. {
  374. TaskList.Add(GameLanguage.ServerTextMap.GetLocalization((ServerTextKeys.KillCountProgress), KillTaskCount[i].Info.Monster.GameName, KillTaskCount[i].Count,
  375. KillTaskCount[i].Info.Count, KillTaskCount[i].Complete ? GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.TaskCompleted) : ""));
  376. }
  377. else
  378. {
  379. TaskList.Add(string.Format("{0} {1}", Info.KillTasks[i].Message, KillTaskCount[i].Complete ? GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.TaskCompleted) : ""));
  380. }
  381. }
  382. }
  383. public void UpdateItemTasks()
  384. {
  385. if (Info.ItemMessage.Length > 0 && Info.ItemTasks.Count > 0)
  386. {
  387. bool allComplete = true;
  388. for (int i = 0; i < ItemTaskCount.Count; i++)
  389. {
  390. if (ItemTaskCount[i].Complete) continue;
  391. allComplete = false;
  392. }
  393. TaskList.Add(string.Format("{0} {1}", Info.ItemMessage, allComplete ? GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.TaskCompleted) : ""));
  394. return;
  395. }
  396. for (int i = 0; i < ItemTaskCount.Count; i++)
  397. {
  398. if (string.IsNullOrEmpty(Info.ItemTasks[i].Message))
  399. {
  400. TaskList.Add(GameLanguage.ServerTextMap.GetLocalization((ServerTextKeys.CollectProgress), Info.ItemTasks[i].Item.FriendlyName, ItemTaskCount[i].Count,
  401. Info.ItemTasks[i].Count, ItemTaskCount[i].Complete ? GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.TaskCompleted) : ""));
  402. }
  403. else
  404. {
  405. TaskList.Add(string.Format("{0} {1}", Info.ItemTasks[i].Message, ItemTaskCount[i].Complete ? GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.TaskCompleted) : ""));
  406. }
  407. }
  408. }
  409. public void UpdateFlagTasks()
  410. {
  411. if (Info.FlagMessage.Length > 0)
  412. {
  413. bool allComplete = true;
  414. for (int i = 0; i < FlagTaskSet.Count; i++)
  415. {
  416. if (FlagTaskSet[i].State) continue;
  417. allComplete = false;
  418. }
  419. TaskList.Add(string.Format("{0} {1}", Info.FlagMessage, allComplete ? GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.TaskCompleted) : ""));
  420. return;
  421. }
  422. for (int i = 0; i < FlagTaskSet.Count; i++)
  423. {
  424. if (string.IsNullOrEmpty(Info.FlagTasks[i].Message))
  425. {
  426. TaskList.Add(GameLanguage.ServerTextMap.GetLocalization((ServerTextKeys.ActivateFlag), Info.FlagTasks[i].Number, FlagTaskSet[i].Complete ? GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.TaskCompleted) : ""));
  427. }
  428. else
  429. {
  430. TaskList.Add(string.Format("{0} {1}", Info.FlagTasks[i].Message, FlagTaskSet[i].Complete ? GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.TaskCompleted) : ""));
  431. }
  432. }
  433. }
  434. public void UpdateGotoTask()
  435. {
  436. if (Info.GotoMessage.Length <= 0 || !Completed) return;
  437. TaskList.Add(Info.GotoMessage);
  438. }
  439. #endregion
  440. #region Optional Functions
  441. public void SetTimer()
  442. {
  443. if (Owner == null)
  444. {
  445. return;
  446. }
  447. if (Info.TimeLimitInSeconds > 0)
  448. {
  449. var secondsSinceStarted = (int)(Envir.Now - StartDateTime).TotalSeconds;
  450. var remainingSeconds = Info.TimeLimitInSeconds - secondsSinceStarted;
  451. if (remainingSeconds > 0)
  452. {
  453. Owner.SetTimer($"Quest-{Index}", remainingSeconds, 1);
  454. }
  455. DelayedAction action = new DelayedAction(DelayedType.Quest, Envir.Time + (remainingSeconds * 1000), this, QuestAction.TimeExpired, true);
  456. Owner.ActionList.Add(action);
  457. }
  458. }
  459. public void RemoveTimer()
  460. {
  461. if (Owner == null)
  462. {
  463. return;
  464. }
  465. if (Info.TimeLimitInSeconds > 0)
  466. {
  467. Owner.ExpireTimer($"Quest-{Index}");
  468. }
  469. }
  470. #endregion
  471. public ClientQuestProgress CreateClientQuestProgress()
  472. {
  473. return new ClientQuestProgress
  474. {
  475. Id = Index,
  476. TaskList = TaskList,
  477. Taken = Taken,
  478. Completed = Completed,
  479. New = New
  480. };
  481. }
  482. }
  483. public class QuestKillTaskProgress
  484. {
  485. public int MonsterID { get; set; }
  486. public int Count { get; set; }
  487. public QuestKillTask Info { get; set; }
  488. public bool Complete { get { return Info != null && Count >= Info.Count; } }
  489. }
  490. public class QuestItemTaskProgress
  491. {
  492. public int ItemID { get; set; }
  493. public int Count { get; set; }
  494. public QuestItemTask Info { get; set; }
  495. public bool Complete { get { return Info != null && Count >= Info.Count; } }
  496. }
  497. public class QuestFlagTaskProgress
  498. {
  499. public int Number { get; set; }
  500. public bool State { get; set; }
  501. public QuestFlagTask Info { get; set; }
  502. public bool Complete { get { return Info != null && State == true; } }
  503. }
  504. }