AttackProcess.cs 25 KB

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