AttackProcess.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using Photon.Pun;
  5. using System;
  6. using System.Linq;
  7. using UnityEngine.UI;
  8. public class AttackProcess : MonoBehaviourPunCallbacks
  9. {
  10. public Permanent AttackingPermanent { get; private set; } = null;
  11. public Permanent DefendingPermanent { get; private set; } = null;
  12. public int AttackCount { get; set; } = 0;
  13. public bool IsAttacking { get; set; } = false;
  14. public bool HasDefender { get; set; } = false;
  15. public bool IsBlocking { get; set; } = false;
  16. public CardSource SecurityDigimon { get; set; } = null;
  17. public bool DoSecurityCheck { get; set; } = false;
  18. public bool IsEndAttack { get; set; } = false;
  19. public bool UsedBlitz { get; set; } = false;
  20. void SetAttackerDefender(Permanent attackingPermanent, Permanent defendingPermanent)
  21. {
  22. AttackingPermanent = attackingPermanent;
  23. DefendingPermanent = defendingPermanent;
  24. if (defendingPermanent != null)
  25. HasDefender = true;
  26. }
  27. public IEnumerator Attack(Permanent attackingPermanent, Permanent defendingPermanent, ICardEffect attackEffect, bool withoutTap = false, Func<IEnumerator> beforeOnAttackCoroutine = null)
  28. {
  29. if (IsAttacking)
  30. {
  31. if (beforeOnAttackCoroutine != null)
  32. {
  33. yield return ContinuousController.instance.StartCoroutine(beforeOnAttackCoroutine());
  34. }
  35. yield break;
  36. }
  37. AttackingPermanent = null;
  38. DefendingPermanent = null;
  39. DoSecurityCheck = false;
  40. IsBlocking = false;
  41. SecurityDigimon = null;
  42. IsAttacking = false;
  43. HasDefender = false;
  44. IsEndAttack = false;
  45. SetAttackerDefender(attackingPermanent, defendingPermanent);
  46. Hashtable effectHashtable = CardEffectCommons.OnAttackCheckHashtableOfPermanent(AttackingPermanent, attackEffect);
  47. Hashtable counterEffectHashtable = CardEffectCommons.OnAttackCheckHashtableOfPermanent(new Permanent(AttackingPermanent.cardSources), attackEffect);
  48. IsAttacking = true;
  49. // check timing
  50. yield return ContinuousController.instance.StartCoroutine(GManager.instance.autoProcessing.AutoProcessCheck());
  51. GManager.instance.turnStateMachine.IsSelecting = true;
  52. // force to end attack
  53. if (IsEndAttack)
  54. {
  55. goto EndAttack;
  56. }
  57. #region Attack Process
  58. if (AttackingPermanent != null)
  59. {
  60. AttackCount++;
  61. GManager.instance.turnStateMachine.IsSelecting = true;
  62. if (DefendingPermanent != null)
  63. {
  64. DefendingPermanent.ShowingPermanentCard.SetOrangeOutline();
  65. DefendingPermanent.ShowingPermanentCard.Outline_Select.gameObject.SetActive(true);
  66. GManager.instance.turnStateMachine.gameContext.NonTurnPlayer.securityObject.securityBreakGlass.gameObject.SetActive(false);
  67. }
  68. else
  69. {
  70. if (GManager.instance.turnStateMachine.gameContext.NonTurnPlayer.SecurityCards.Count >= 1)
  71. {
  72. GManager.instance.turnStateMachine.gameContext.NonTurnPlayer.securityObject.securityBreakGlass.ShowBlueMatarial();
  73. }
  74. }
  75. AttackingPermanent.ShowingPermanentCard.SetOrangeOutline();
  76. AttackingPermanent.ShowingPermanentCard.Outline_Select.gameObject.SetActive(true);
  77. // add log
  78. string log = $"\nAttack:\n{AttackingPermanent.TopCard.BaseENGCardNameFromEntity}({AttackingPermanent.TopCard.CardID})";
  79. if (DefendingPermanent != null)
  80. {
  81. log += $"\n�«\n{DefendingPermanent.TopCard.BaseENGCardNameFromEntity}({DefendingPermanent.TopCard.CardID})\n";
  82. }
  83. else
  84. {
  85. log += $"\n�«\nSecurity\n";
  86. }
  87. PlayLog.OnAddLog?.Invoke(log);
  88. List<SkillInfo> stackedSkillInfos = new List<SkillInfo>();
  89. if (GManager.instance.autoProcessing.executingMultipleSkills != null)
  90. {
  91. if (GManager.instance.autoProcessing.executingMultipleSkills.StackedSkillInfos.Count >= 1)
  92. {
  93. foreach (SkillInfo skillInfo in GManager.instance.autoProcessing.executingMultipleSkills.StackedSkillInfos)
  94. {
  95. stackedSkillInfos.Add(skillInfo);
  96. }
  97. }
  98. foreach (SkillInfo skillInfo in stackedSkillInfos)
  99. {
  100. GManager.instance.autoProcessing.executingMultipleSkills.StackedSkillInfos.Remove(skillInfo);
  101. }
  102. }
  103. // suspend
  104. if (!withoutTap)
  105. {
  106. Hashtable attackerTapHashtable = new Hashtable()
  107. {
  108. {"IsAttack", true}
  109. };
  110. yield return ContinuousController.instance.StartCoroutine(new SuspendPermanentsClass(
  111. new List<Permanent>() { AttackingPermanent },
  112. attackerTapHashtable).Tap());
  113. }
  114. // target arrow
  115. if (DefendingPermanent == null)
  116. {
  117. yield return GManager.instance.OnTargetArrow(
  118. AttackingPermanent.PermanentFrame.GetLocalCanvasPosition() + AttackingPermanent.TopCard.Owner.playerUIObjectParent.localPosition,
  119. GManager.instance.turnStateMachine.gameContext.NonTurnPlayer.SecurityAttackLocalCanvasPosition + GManager.instance.turnStateMachine.gameContext.NonTurnPlayer.playerUIObjectParent.localPosition,
  120. null,
  121. null);
  122. }
  123. else
  124. {
  125. yield return GManager.instance.OnTargetArrow(
  126. AttackingPermanent.PermanentFrame.GetLocalCanvasPosition() + AttackingPermanent.TopCard.Owner.playerUIObjectParent.localPosition,
  127. DefendingPermanent.PermanentFrame.GetLocalCanvasPosition() + DefendingPermanent.TopCard.Owner.playerUIObjectParent.localPosition,
  128. null,
  129. null);
  130. }
  131. // activate cutin effects
  132. yield return ContinuousController.instance.StartCoroutine(GManager.instance.autoProcessing.RuleProcess());
  133. //yield return ContinuousController.instance.StartCoroutine(GManager.instance.autoProcessing_CutIn.TriggeredSkillProcess(true, null));
  134. // callback that is processed before [On Attack]
  135. if (beforeOnAttackCoroutine != null)
  136. {
  137. yield return ContinuousController.instance.StartCoroutine(beforeOnAttackCoroutine());
  138. }
  139. // trigger [On Attack] effect
  140. yield return ContinuousController.instance.StartCoroutine(GManager.instance.autoProcessing_CutIn.StackSkillInfos(
  141. effectHashtable,
  142. EffectTiming.OnAllyAttack));
  143. // activate cutin effects
  144. yield return ContinuousController.instance.StartCoroutine(GManager.instance.autoProcessing.RuleProcess());
  145. yield return ContinuousController.instance.StartCoroutine(GManager.instance.autoProcessing_CutIn.TriggeredSkillProcess(true, null));
  146. if (stackedSkillInfos.Count >= 1)
  147. {
  148. foreach (SkillInfo skillInfo in stackedSkillInfos)
  149. {
  150. GManager.instance.autoProcessing.PutStackedSkill(skillInfo);
  151. }
  152. }
  153. GManager.instance.turnStateMachine.IsSelecting = true;
  154. if (AttackingPermanent.TopCard != null)
  155. {
  156. AttackingPermanent.ShowingPermanentCard.SetOrangeOutline();
  157. AttackingPermanent.ShowingPermanentCard.Outline_Select.gameObject.SetActive(true);
  158. }
  159. if (DefendingPermanent != null)
  160. {
  161. if (DefendingPermanent.TopCard != null)
  162. {
  163. DefendingPermanent.ShowingPermanentCard.SetOrangeOutline();
  164. DefendingPermanent.ShowingPermanentCard.Outline_Select.gameObject.SetActive(true);
  165. }
  166. }
  167. // check timing
  168. yield return ContinuousController.instance.StartCoroutine(GManager.instance.autoProcessing.AutoProcessCheck());
  169. GManager.instance.turnStateMachine.IsSelecting = true;
  170. // force to end attack
  171. if (IsEndAttack)
  172. {
  173. goto EndAttack;
  174. }
  175. if (AttackingPermanent.TopCard != null)
  176. {
  177. AttackingPermanent.ShowingPermanentCard.SetOrangeOutline();
  178. AttackingPermanent.ShowingPermanentCard.Outline_Select.gameObject.SetActive(true);
  179. }
  180. if (DefendingPermanent != null)
  181. {
  182. if (DefendingPermanent.TopCard != null)
  183. {
  184. DefendingPermanent.ShowingPermanentCard.SetOrangeOutline();
  185. DefendingPermanent.ShowingPermanentCard.Outline_Select.gameObject.SetActive(true);
  186. }
  187. }
  188. // trigger effects when counter timing (except [Counter] effects)
  189. yield return ContinuousController.instance.StartCoroutine(GManager.instance.autoProcessing_CutIn.StackSkillInfos(
  190. counterEffectHashtable,
  191. EffectTiming.OnCounterTiming,
  192. cardEffect => !cardEffect.IsCounterEffect));
  193. // activate cutin effects
  194. yield return ContinuousController.instance.StartCoroutine(GManager.instance.autoProcessing.RuleProcess());
  195. yield return ContinuousController.instance.StartCoroutine(GManager.instance.autoProcessing_CutIn.TriggeredSkillProcess(true, null));
  196. GManager.instance.turnStateMachine.IsSelecting = true;
  197. // force to end attack
  198. if (IsEndAttack)
  199. {
  200. goto EndAttack;
  201. }
  202. // trigger effects when counter timing ([Counter] effects)
  203. yield return ContinuousController.instance.StartCoroutine(GManager.instance.autoProcessing_CutIn.StackSkillInfos(
  204. counterEffectHashtable,
  205. EffectTiming.OnCounterTiming,
  206. cardEffect => cardEffect.IsCounterEffect));
  207. bool HasCounterEffect(List<SkillInfo> skillInfos, SkillInfo skillInfo)
  208. {
  209. return skillInfos.Count((skillInfo1) => skillInfo1.CardEffect.IsCounterEffect) >= 1;
  210. }
  211. // activate cutin effects
  212. yield return ContinuousController.instance.StartCoroutine(GManager.instance.autoProcessing.RuleProcess());
  213. yield return ContinuousController.instance.StartCoroutine(GManager.instance.autoProcessing_CutIn.TriggeredSkillProcess(true, HasCounterEffect));
  214. GManager.instance.turnStateMachine.IsSelecting = true;
  215. // force to end attack
  216. if (IsEndAttack)
  217. {
  218. goto EndAttack;
  219. }
  220. if (AttackingPermanent.TopCard == null)
  221. {
  222. goto EndAttack;
  223. }
  224. AttackingPermanent.ShowingPermanentCard.SetOrangeOutline();
  225. AttackingPermanent.ShowingPermanentCard.Outline_Select.gameObject.SetActive(true);
  226. if (DefendingPermanent != null)
  227. {
  228. if (DefendingPermanent.TopCard != null)
  229. {
  230. DefendingPermanent.ShowingPermanentCard.SetOrangeOutline();
  231. DefendingPermanent.ShowingPermanentCard.Outline_Select.gameObject.SetActive(true);
  232. }
  233. }
  234. #region select blocker
  235. bool CanSelectBlockerCondition(Permanent permanent)
  236. {
  237. if (CardEffectCommons.IsPermanentExistsOnOpponentBattleAreaDigimon(permanent, AttackingPermanent.TopCard))
  238. {
  239. if (permanent != DefendingPermanent)
  240. {
  241. if (permanent.HasBlocker && permanent.CanBlock(AttackingPermanent))
  242. {
  243. return true;
  244. }
  245. }
  246. }
  247. return false;
  248. }
  249. if (AttackingPermanent.TopCard.Owner.Enemy.GetBattleAreaDigimons().Count(CanSelectBlockerCondition) >= 1)
  250. {
  251. int maxCount = 1;
  252. Permanent selectedPermanent = null;
  253. SelectPermanentEffect selectPermanentEffect = GManager.instance.GetComponent<SelectPermanentEffect>();
  254. selectPermanentEffect.SetUp(
  255. selectPlayer: AttackingPermanent.TopCard.Owner.Enemy,
  256. canTargetCondition: CanSelectBlockerCondition,
  257. canTargetCondition_ByPreSelecetedList: null,
  258. canEndSelectCondition: null,
  259. maxCount: maxCount,
  260. canNoSelect: (!IsBlocking),
  261. canEndNotMax: false,
  262. selectPermanentCoroutine: SelectPermanentCoroutine,
  263. afterSelectPermanentCoroutine: null,
  264. mode: SelectPermanentEffect.Mode.Custom,
  265. cardEffect: null);
  266. selectPermanentEffect.SetUpCustomMessage("Select 1 Digimon that will block.", "The opponent is selecting 1 Digimon that will block.");
  267. if(!IsBlocking)
  268. selectPermanentEffect.SetUpCustomBackButtonMessage("Not Block");
  269. yield return ContinuousController.instance.StartCoroutine(selectPermanentEffect.Activate());
  270. IEnumerator SelectPermanentCoroutine(Permanent permanent)
  271. {
  272. selectedPermanent = permanent;
  273. yield return null;
  274. }
  275. if (selectedPermanent != null)
  276. {
  277. yield return ContinuousController.instance.StartCoroutine(SwitchDefender(null, true, selectedPermanent));
  278. }
  279. }
  280. #endregion
  281. GManager.instance.turnStateMachine.IsSelecting = true;
  282. //end attack
  283. if (IsEndAttack)
  284. {
  285. goto EndAttack;
  286. }
  287. if (AttackingPermanent.TopCard == null)
  288. {
  289. goto EndAttack;
  290. }
  291. AttackingPermanent.ShowingPermanentCard.SetOrangeOutline();
  292. AttackingPermanent.ShowingPermanentCard.Outline_Select.gameObject.SetActive(true);
  293. if (DefendingPermanent != null)
  294. {
  295. if (DefendingPermanent.TopCard != null)
  296. {
  297. DefendingPermanent.ShowingPermanentCard.SetOrangeOutline();
  298. DefendingPermanent.ShowingPermanentCard.Outline_Select.gameObject.SetActive(true);
  299. }
  300. }
  301. #region there is no Defending Permanent
  302. if (DefendingPermanent == null)
  303. {
  304. if (AttackingPermanent.Strike >= 1)
  305. {
  306. //if there is no security, end the game
  307. if (AttackingPermanent.TopCard.Owner.Enemy.SecurityCards.Count == 0)
  308. {
  309. GManager.instance.turnStateMachine.EndGame(AttackingPermanent.TopCard.Owner, false);
  310. yield break;
  311. }
  312. }
  313. DoSecurityCheck = true;
  314. }
  315. #endregion
  316. #region there is Defending Permanent
  317. else
  318. {
  319. if (DefendingPermanent.TopCard == null || AttackingPermanent == null || AttackingPermanent.TopCard == null)
  320. {
  321. goto EndAttack;
  322. }
  323. DefendingPermanent.TopCard.Owner.securityObject.securityBreakGlass.gameObject.SetActive(false);
  324. DefendingPermanent.ShowingPermanentCard.SetOrangeOutline();
  325. DefendingPermanent.ShowingPermanentCard.Outline_Select.gameObject.SetActive(true);
  326. // battle
  327. IBattle battle = new IBattle(AttackingPermanent: AttackingPermanent, DefendingPermanent: DefendingPermanent, null);
  328. yield return ContinuousController.instance.StartCoroutine(battle.Battle());
  329. /*#region effect when determine whether to do security check
  330. Hashtable hashtable = new Hashtable()
  331. {
  332. {"battle", battle}
  333. };
  334. List<SkillInfo> skillInfos_Pierce = AutoProcessing.GetSkillInfos(hashtable, EffectTiming.OnDetermineDoSecurityCheck)
  335. .Filter(skillInfo => skillInfo.CardEffect != null && skillInfo.CardEffect.CanActivate(skillInfo.Hashtable));
  336. if (skillInfos_Pierce.Count >= 1)
  337. {
  338. GManager.instance.autoProcessing.PutStackedSkill(skillInfos_Pierce[0]);
  339. }
  340. #endregion*/
  341. yield return ContinuousController.instance.StartCoroutine(GManager.instance.autoProcessing.TriggeredSkillProcess(true, null));
  342. GManager.instance.turnStateMachine.IsSelecting = true;
  343. }
  344. #endregion
  345. if (AttackingPermanent.TopCard == null)
  346. {
  347. goto EndAttack;
  348. }
  349. #region do security check
  350. if (DoSecurityCheck && AttackingPermanent.TopCard.Owner.Enemy.SecurityCards.Count >= 1)
  351. {
  352. //security check process
  353. yield return ContinuousController.instance.StartCoroutine(new ISecurityCheck(
  354. AttackingPermanent: AttackingPermanent,
  355. player: GManager.instance.turnStateMachine.gameContext.NonTurnPlayer).SecurityCheck());
  356. }
  357. #endregion
  358. }
  359. else
  360. {
  361. if (beforeOnAttackCoroutine != null)
  362. {
  363. yield return ContinuousController.instance.StartCoroutine(beforeOnAttackCoroutine());
  364. }
  365. }
  366. #endregion
  367. #region End Attack
  368. EndAttack:;
  369. // [On End Attack] effect
  370. if (AttackingPermanent != null && AttackingPermanent.TopCard != null)
  371. {
  372. yield return ContinuousController.instance.StartCoroutine(GManager.instance.autoProcessing.StackSkillInfos(effectHashtable, EffectTiming.OnEndAttack));
  373. }
  374. #region reset effects which continues until the end of attack
  375. foreach (Player player in GManager.instance.turnStateMachine.gameContext.Players_ForTurnPlayer)
  376. {
  377. foreach (Permanent permanent in player.GetFieldPermanents())
  378. {
  379. permanent.UntilEndAttackEffects = new List<Func<EffectTiming, ICardEffect>>();
  380. }
  381. }
  382. #endregion
  383. GManager.instance.turnStateMachine.IsSelecting = true;
  384. #endregion
  385. DoSecurityCheck = false;
  386. IsBlocking = false;
  387. SecurityDigimon = null;
  388. IsAttacking = false;
  389. IsEndAttack = false;
  390. }
  391. public IEnumerator SwitchDefender(ICardEffect cardEffect, bool isBlock, Permanent newDefendingPermanent)
  392. {
  393. if (AttackingPermanent == null) yield break;
  394. if (AttackingPermanent.TopCard == null) yield break;
  395. if (newDefendingPermanent != null && newDefendingPermanent.TopCard == null) yield break;
  396. if (!AttackingPermanent.CanSwitchAttackTarget) yield break;
  397. Permanent oldDefendingPermanent = DefendingPermanent;
  398. DefendingPermanent = newDefendingPermanent;
  399. IsBlocking = isBlock;
  400. if (DefendingPermanent != null)
  401. {
  402. if (DefendingPermanent.ShowingPermanentCard != null)
  403. {
  404. DefendingPermanent.ShowingPermanentCard.SetOrangeOutline();
  405. DefendingPermanent.ShowingPermanentCard.Outline_Select.gameObject.SetActive(true);
  406. }
  407. }
  408. Hashtable hashtable = new Hashtable(){
  409. {"AttackingPermanent", AttackingPermanent},
  410. {"DefendingPermanent", DefendingPermanent},
  411. {"CardEffect", cardEffect}
  412. };
  413. if (isBlock)
  414. {
  415. hashtable.Add("IsBlock", isBlock);
  416. }
  417. if (isBlock)
  418. {
  419. if (DefendingPermanent != null)
  420. {
  421. // add log
  422. string log1 = $"\nBlock:\n{DefendingPermanent.TopCard.BaseENGCardNameFromEntity}({DefendingPermanent.TopCard.CardID})\n";
  423. PlayLog.OnAddLog?.Invoke(log1);
  424. // suspend
  425. yield return ContinuousController.instance.StartCoroutine(new SuspendPermanentsClass(new List<Permanent>() { DefendingPermanent }, hashtable).Tap());
  426. // the effects when blocking
  427. yield return ContinuousController.instance.StartCoroutine(GManager.instance.autoProcessing.StackSkillInfos(
  428. hashtable,
  429. EffectTiming.OnBlockAnyone));
  430. }
  431. }
  432. if (AttackingPermanent != null)
  433. {
  434. if (AttackingPermanent.TopCard == null)
  435. {
  436. IsBlocking = false;
  437. yield break;
  438. }
  439. }
  440. if (DefendingPermanent != null)
  441. {
  442. if (DefendingPermanent.TopCard == null)
  443. {
  444. IsBlocking = false;
  445. yield break;
  446. }
  447. }
  448. if (AttackingPermanent != null)
  449. {
  450. // target arrow
  451. for (int i = 0; i < 3; i++)
  452. {
  453. GManager.instance.OffTargetArrow();
  454. yield return null;
  455. }
  456. if (DefendingPermanent != null)
  457. {
  458. DefendingPermanent.ShowingPermanentCard.SetOrangeOutline();
  459. DefendingPermanent.ShowingPermanentCard.Outline_Select.gameObject.SetActive(true);
  460. yield return GManager.instance.OnTargetArrow(
  461. AttackingPermanent.PermanentFrame.GetLocalCanvasPosition() + AttackingPermanent.TopCard.Owner.playerUIObjectParent.localPosition,
  462. DefendingPermanent.PermanentFrame.GetLocalCanvasPosition() + DefendingPermanent.TopCard.Owner.playerUIObjectParent.localPosition,
  463. null,
  464. null);
  465. }
  466. else
  467. {
  468. yield return GManager.instance.OnTargetArrow(
  469. AttackingPermanent.PermanentFrame.GetLocalCanvasPosition() + AttackingPermanent.TopCard.Owner.playerUIObjectParent.localPosition,
  470. GManager.instance.turnStateMachine.gameContext.NonTurnPlayer.SecurityAttackLocalCanvasPosition + GManager.instance.turnStateMachine.gameContext.NonTurnPlayer.playerUIObjectParent.localPosition,
  471. null,
  472. null);
  473. }
  474. AttackingPermanent.ShowingPermanentCard.SetOrangeOutline();
  475. AttackingPermanent.ShowingPermanentCard.Outline_Select.gameObject.SetActive(true);
  476. }
  477. if (newDefendingPermanent != oldDefendingPermanent)
  478. {
  479. // the effects when attack target switched
  480. yield return ContinuousController.instance.StartCoroutine(GManager.instance.autoProcessing.StackSkillInfos(
  481. hashtable,
  482. EffectTiming.OnAttackTargetChanged));
  483. }
  484. }
  485. }