CardEffectCommons.cs 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using System;
  4. using System.Linq;
  5. using UnityEngine;
  6. using UnityEditor;
  7. public partial class CardEffectCommons
  8. {
  9. #region Play cards as new permanents
  10. public static IEnumerator PlayPermanentCards(List<CardSource> cardSources, ICardEffect activateClass, bool payCost, bool isTapped, SelectCardEffect.Root root, bool activateETB, bool isBreedingArea = false, int fixedCost = -1)
  11. {
  12. if (cardSources == null) yield break;
  13. cardSources = cardSources
  14. .Filter(cardSource => cardSource != null)
  15. .Filter(cardSource => CanPlayAsNewPermanent(
  16. cardSource: cardSource,
  17. payCost: payCost,
  18. cardEffect: activateClass,
  19. isBreedingArea: isBreedingArea,
  20. fixedCost: fixedCost));
  21. if (cardSources.Count == 0) yield break;
  22. PlayCardClass playCardClass = new PlayCardClass(
  23. cardSources: cardSources,
  24. hashtable: CardEffectHashtable(activateClass),
  25. payCost: payCost,
  26. targetPermanent: null,
  27. isTapped: isTapped,
  28. root: root,
  29. activateETB: activateETB);
  30. if (isBreedingArea)
  31. playCardClass.SetIsBreedingArea();
  32. playCardClass.SetFixedCost(fixedCost);
  33. yield return ContinuousController.instance.StartCoroutine(playCardClass.PlayCard());
  34. }
  35. #endregion
  36. #region Play option cards
  37. public static IEnumerator PlayOptionCards(List<CardSource> cardSources, ICardEffect activateClass, bool payCost, SelectCardEffect.Root root,
  38. bool setAddSecurityEndOption = false)
  39. {
  40. if (cardSources == null) yield break;
  41. cardSources = cardSources
  42. .Filter(cardSource => cardSource != null)
  43. .Filter(cardSource => !cardSource.CanNotPlayThisOption);
  44. if (cardSources.Count == 0) yield break;
  45. PlayCardClass playCard = new PlayCardClass(
  46. cardSources: cardSources,
  47. hashtable: CardEffectHashtable(activateClass),
  48. payCost: payCost,
  49. targetPermanent: null,
  50. isTapped: false,
  51. root: root,
  52. activateETB: true);
  53. if (activateClass != null)
  54. {
  55. playCard.SetShowEffect();
  56. }
  57. if (setAddSecurityEndOption)
  58. {
  59. playCard.SetAddSecurityEndOption();
  60. }
  61. yield return ContinuousController.instance.StartCoroutine(playCard.PlayCard());
  62. }
  63. #endregion
  64. #region Play Delay Option cards as new permanents
  65. public static IEnumerator PlaceDelayOptionCards(CardSource card, ICardEffect cardEffect, SelectCardEffect.Root root = SelectCardEffect.Root.Execution)
  66. {
  67. if (CanPlayAsNewPermanent(cardSource: card, payCost: false, cardEffect: cardEffect, isPlayOption: true))
  68. {
  69. PlayPermanentClass playPermanent = new PlayPermanentClass(
  70. cardSources: new List<CardSource>() { card },
  71. hashtable: CardEffectHashtable(cardEffect),
  72. targetPermanent: null,
  73. isTapped: false,
  74. root: root,
  75. ActivateETB: true);
  76. playPermanent.SetISPlayOption();
  77. yield return ContinuousController.instance.StartCoroutine(playPermanent.PlayPermanent());
  78. if (IsExistOnBattleArea(card))
  79. {
  80. card.PermanentOfThisCard().IsPlayedOptionPermanent = true;
  81. }
  82. }
  83. }
  84. #endregion
  85. #region Play 1 Token
  86. public static IEnumerator PlayToken(CEntity_Base tokenData, ICardEffect activateClass, bool isOwnerPermanent, bool isTapped, int quantity = 1)
  87. {
  88. if (activateClass == null) yield break;
  89. if (activateClass.EffectSourceCard == null) yield break;
  90. if (tokenData == null) yield break;
  91. CardSource card = activateClass.EffectSourceCard;
  92. Player player = isOwnerPermanent ? card.Owner : card.Owner.Enemy;
  93. if (card.Owner.fieldCardFrames.Count((frame) => frame.IsEmptyFrame() && frame.IsBattleAreaFrame()) >= quantity)
  94. {
  95. List<CardSource> playCards = new List<CardSource>();
  96. for (int i = 0; i < quantity; i++)
  97. {
  98. CardSource tokenCard = CardObjectController.CreateCardSource(
  99. player.PlayerID,
  100. tokenData,
  101. true);
  102. playCards.Add(tokenCard);
  103. }
  104. if (CanPlayAsNewPermanent(cardSource: playCards[0], payCost: false, cardEffect: activateClass))
  105. {
  106. yield return ContinuousController.instance.StartCoroutine(new PlayCardClass(
  107. cardSources: playCards,
  108. hashtable: CardEffectHashtable(activateClass),
  109. payCost: false,
  110. targetPermanent: null,
  111. isTapped: isTapped,
  112. root: SelectCardEffect.Root.None,
  113. activateETB: true).PlayCard());
  114. }
  115. }
  116. }
  117. #endregion
  118. #region Play 1 [Diaboromon] Token
  119. public static IEnumerator PlayDiaboromonToken(ICardEffect activateClass,int quantity = 1)
  120. {
  121. yield return ContinuousController.instance.StartCoroutine(PlayToken(
  122. tokenData: ContinuousController.instance.DiaboromonToken,
  123. activateClass: activateClass,
  124. isOwnerPermanent: true,
  125. isTapped: false,
  126. quantity: quantity
  127. ));
  128. }
  129. #endregion
  130. #region Play 1 [Amon of Crimson Flame] Token
  131. public static IEnumerator PlayAmonToken(ICardEffect activateClass)
  132. {
  133. yield return ContinuousController.instance.StartCoroutine(PlayToken(
  134. tokenData: ContinuousController.instance.AmonToken,
  135. activateClass: activateClass,
  136. isOwnerPermanent: true,
  137. isTapped: false
  138. ));
  139. }
  140. #endregion
  141. #region Play 1 [Umon of Blue Thunder] Token
  142. public static IEnumerator PlayUmonToken(ICardEffect activateClass)
  143. {
  144. yield return ContinuousController.instance.StartCoroutine(PlayToken(
  145. tokenData: ContinuousController.instance.UmonToken,
  146. activateClass: activateClass,
  147. isOwnerPermanent: true,
  148. isTapped: false
  149. ));
  150. }
  151. #endregion
  152. #region Play 1 [Fujitsumon] Token
  153. public static IEnumerator PlayFujitsumonToken(ICardEffect activateClass, bool isOwnerPermanent)
  154. {
  155. yield return ContinuousController.instance.StartCoroutine(PlayToken(
  156. tokenData: ContinuousController.instance.FujitsumonToken,
  157. activateClass: activateClass,
  158. isOwnerPermanent: isOwnerPermanent,
  159. isTapped: true
  160. ));
  161. }
  162. #endregion
  163. #region Play 1 [Gyuukimon] Token
  164. public static IEnumerator PlayGyuukimonToken(ICardEffect activateClass)
  165. {
  166. yield return ContinuousController.instance.StartCoroutine(PlayToken(
  167. tokenData: ContinuousController.instance.GyuukimonToken,
  168. activateClass: activateClass,
  169. isOwnerPermanent: true,
  170. isTapped: false
  171. ));
  172. }
  173. #endregion
  174. #region Play 1 [KoHagurumon] Token
  175. public static IEnumerator PlayKoHagurumonToken(ICardEffect activateClass)
  176. {
  177. yield return ContinuousController.instance.StartCoroutine(PlayToken(
  178. tokenData: ContinuousController.instance.KoHagurumonToken,
  179. activateClass: activateClass,
  180. isOwnerPermanent: true,
  181. isTapped: false
  182. ));
  183. }
  184. #endregion
  185. #region Play 1 [Familiar] Token
  186. public static IEnumerator PlayFamiliarToken(ICardEffect activateClass, int quantity = 1)
  187. {
  188. yield return ContinuousController.instance.StartCoroutine(PlayToken(
  189. tokenData: ContinuousController.instance.FamiliarToken,
  190. activateClass: activateClass,
  191. isOwnerPermanent: true,
  192. isTapped: false,
  193. quantity: quantity
  194. ));
  195. }
  196. #endregion
  197. #region Play 1 [Volée & Zerdrücken] Token
  198. public static IEnumerator PlayVoléeZerdrücken(ICardEffect activateClass)
  199. {
  200. yield return ContinuousController.instance.StartCoroutine(PlayToken(
  201. tokenData: ContinuousController.instance.VoléeZerdrückenToken,
  202. activateClass: activateClass,
  203. isOwnerPermanent: true,
  204. isTapped: false
  205. ));
  206. }
  207. #endregion
  208. #region Security effect of "add this card to hand"
  209. public static IEnumerator AddThisCardToHand(CardSource card1, ICardEffect activateClass)
  210. {
  211. yield return new WaitForSeconds(0.5f);
  212. yield return ContinuousController.instance.StartCoroutine(card1.Owner.brainStormObject.CloseBrainstrorm(card1));
  213. yield return ContinuousController.instance.StartCoroutine(CardObjectController.AddHandCards(new List<CardSource>() { card1 }, false, activateClass));
  214. }
  215. #endregion
  216. #region Delete target permanents, and the effect determines whether the permanent has been deleted or not
  217. public static IEnumerator DeletePeremanentAndProcessAccordingToResult(List<Permanent> targetPermanents, ICardEffect activateClass, Func<List<Permanent>, IEnumerator> successProcess, Func<IEnumerator> failureProcess)
  218. {
  219. DestroyPermanentsClass destroyPermanentsClass = new DestroyPermanentsClass(targetPermanents, CardEffectHashtable(activateClass));
  220. yield return ContinuousController.instance.StartCoroutine(destroyPermanentsClass.Destroy());
  221. if (targetPermanents.Some((permanent) => destroyPermanentsClass.IsDestroyed(permanent)))
  222. {
  223. if (successProcess != null)
  224. {
  225. yield return ContinuousController.instance.StartCoroutine(successProcess(destroyPermanentsClass.DestroyedPermanents));
  226. }
  227. }
  228. else
  229. {
  230. if (failureProcess != null)
  231. {
  232. yield return ContinuousController.instance.StartCoroutine(failureProcess());
  233. }
  234. }
  235. }
  236. #endregion
  237. #region Bounce target 1 permanent, and the effect determines whether the permanent has been bounced or not
  238. public static IEnumerator BouncePeremanentAndProcessAccordingToResult(List<Permanent> targetPermanents, ICardEffect activateClass, IEnumerator successProcess, IEnumerator failureProcess)
  239. {
  240. HandBounceClaass bouncePermanentClass = new HandBounceClaass(targetPermanents, CardEffectHashtable(activateClass));
  241. yield return ContinuousController.instance.StartCoroutine(bouncePermanentClass.Bounce());
  242. if (targetPermanents.Some((permanent) => bouncePermanentClass.IsBounced(permanent)))
  243. {
  244. if (successProcess != null)
  245. {
  246. yield return ContinuousController.instance.StartCoroutine(successProcess);
  247. }
  248. }
  249. else
  250. {
  251. if (failureProcess != null)
  252. {
  253. yield return ContinuousController.instance.StartCoroutine(failureProcess);
  254. }
  255. }
  256. }
  257. #endregion
  258. #region Deck Bounce target 1 permanent, and the effect determines whether the permanent has been bounced or not
  259. public static IEnumerator DeckBouncePeremanentAndProcessAccordingToResult(List<Permanent> targetPermanents, ICardEffect activateClass, IEnumerator successProcess, IEnumerator failureProcess)
  260. {
  261. DeckBottomBounceClass deckBounceClass = new DeckBottomBounceClass(targetPermanents, CardEffectHashtable(activateClass));
  262. yield return ContinuousController.instance.StartCoroutine(deckBounceClass.DeckBounce());
  263. if (targetPermanents.Some((permanent) => deckBounceClass.IsDeckBounced(permanent)))
  264. {
  265. if (successProcess != null)
  266. {
  267. yield return ContinuousController.instance.StartCoroutine(successProcess);
  268. }
  269. }
  270. else
  271. {
  272. if (failureProcess != null)
  273. {
  274. yield return ContinuousController.instance.StartCoroutine(failureProcess);
  275. }
  276. }
  277. }
  278. #endregion
  279. #region Trash digivolution cards from top or bottom
  280. public static IEnumerator TrashDigivolutionCardsFromTopOrBottom(Permanent targetPermanent, int trashCount, bool isFromTop, ICardEffect activateClass)
  281. {
  282. if (activateClass == null) yield break;
  283. if (targetPermanent == null) yield break;
  284. if (targetPermanent.TopCard == null) yield break;
  285. if (targetPermanent.DigivolutionCards.Count((cardSource) => !cardSource.CanNotTrashFromDigivolutionCards(activateClass)) == 0) yield break;
  286. Debug.Log($"Trashing Digivolution Cards From Top/Bottom: Target Can Not Be Affected - {targetPermanent.TopCard.CanNotBeAffected(activateClass)}");
  287. if (targetPermanent.TopCard.CanNotBeAffected(activateClass)) yield break;
  288. if (trashCount <= 0) yield break;
  289. List<CardSource> trashTargetCards = new List<CardSource>();
  290. for (int i = 0; i < trashCount; i++)
  291. {
  292. if (targetPermanent.DigivolutionCards.Count >= i + 1)
  293. {
  294. int index = isFromTop ? i : targetPermanent.DigivolutionCards.Count - 1 - i;
  295. CardSource trashTargetCard = targetPermanent.DigivolutionCards[index];
  296. trashTargetCards.Add(trashTargetCard);
  297. }
  298. }
  299. yield return ContinuousController.instance.StartCoroutine(new ITrashDigivolutionCards(targetPermanent, trashTargetCards, activateClass).TrashDigivolutionCards());
  300. }
  301. #endregion
  302. #region this Option card's Main effect
  303. public static ActivateClass OptionMainEffect(CardSource card) => card.EffectList(EffectTiming.OptionSkill).Find(cardEffect => cardEffect != null && cardEffect is ActivateClass && cardEffect.EffectDiscription.Contains("[Main]")) as ActivateClass;
  304. #endregion
  305. #region this Option card's Security effect
  306. public static ActivateClass OptionSecurityEffect(CardSource card) => card.EffectList(EffectTiming.SecuritySkill).Find(cardEffect => cardEffect != null && cardEffect is ActivateClass && cardEffect.EffectDiscription.Contains("[Security]")) as ActivateClass;
  307. #endregion
  308. #region Add Option's Security effect that "Activate this card's Main effect" to cardEffects
  309. public static void AddActivateMainOptionSecurityEffect(CardSource card, ref List<ICardEffect> cardEffects, string effectName, string effectDiscription = "", Func<ICardEffect, IEnumerator> afterMainEffect = null)
  310. {
  311. if (OptionMainEffect(card) == null) return;
  312. cardEffects.Add(CardEffectFactory.ActivateMainOptionSecurityEffect(card, effectName, effectDiscription, afterMainEffect));
  313. }
  314. #endregion
  315. #region Target permanent Digivolves into Digimon card from hand or trash
  316. public static IEnumerator DigivolveIntoHandOrTrashCard(
  317. Permanent targetPermanent,
  318. Func<CardSource, bool> cardCondition,
  319. bool payCost,
  320. (int reduceCost, Func<CardSource, bool> reduceCostCardCondition)? reduceCostTuple,
  321. (int fixedCost, Func<CardSource, bool> fixedCostCardCondition)? fixedCostTuple,
  322. int ignoreDigivolutionRequirementFixedCost,
  323. bool isHand,
  324. ICardEffect activateClass,
  325. IEnumerator successProcess,
  326. bool ignoreLevel = false,
  327. bool ignoreSelection = false)
  328. {
  329. if (targetPermanent == null) yield break;
  330. if (targetPermanent.TopCard == null) yield break;
  331. if (activateClass == null) yield break;
  332. if (activateClass.EffectSourceCard == null) yield break;
  333. Player owner = targetPermanent.TopCard.Owner;
  334. SelectCardEffect.Root root = isHand ? SelectCardEffect.Root.Hand : SelectCardEffect.Root.Trash;
  335. bool ignoreDigivolutionRequirement = ignoreDigivolutionRequirementFixedCost >= 0;
  336. int fixedCost = -1;
  337. if (fixedCostTuple != null)
  338. {
  339. fixedCost = fixedCostTuple.Value.fixedCost;
  340. }
  341. if (ignoreDigivolutionRequirement)
  342. {
  343. fixedCost = ignoreDigivolutionRequirementFixedCost;
  344. }
  345. bool CanSelectCardCondition(CardSource cardSource)
  346. {
  347. if (cardSource.IsDigimon)
  348. {
  349. if (cardCondition == null || cardCondition(cardSource))
  350. {
  351. if (!cardSource.CanNotEvolve(targetPermanent))
  352. {
  353. if (ignoreLevel
  354. || cardSource.CanPlayCardTargetFrame(
  355. frame: targetPermanent.PermanentFrame,
  356. PayCost: payCost,
  357. cardEffect: activateClass,
  358. root: root,
  359. fixedCost: fixedCost))
  360. {
  361. return true;
  362. }
  363. }
  364. }
  365. }
  366. return false;
  367. }
  368. #region reduce cost
  369. Func<EffectTiming, ICardEffect> getChangeCostEffect = null;
  370. if (reduceCostTuple != null)
  371. {
  372. bool PermanentCondition(Permanent permanent)
  373. {
  374. return permanent == targetPermanent;
  375. }
  376. bool CardCondition(CardSource cardSource)
  377. {
  378. if (cardSource != null)
  379. {
  380. if (cardSource.Owner == owner)
  381. {
  382. if (reduceCostTuple.Value.reduceCostCardCondition == null || reduceCostTuple.Value.reduceCostCardCondition(cardSource))
  383. {
  384. return true;
  385. }
  386. }
  387. }
  388. return false;
  389. }
  390. getChangeCostEffect = ChangeDigivolutionCostPlayerEffect(
  391. permanentCondition: PermanentCondition,
  392. cardCondition: CardCondition,
  393. rootCondition: null,
  394. changeValue: -reduceCostTuple.Value.reduceCost,
  395. activateClass: activateClass,
  396. setFixedCost: false);
  397. if (getChangeCostEffect != null)
  398. {
  399. AddEffectToPlayer(
  400. effectDuration: EffectDuration.UntilCalculateFixedCost,
  401. card: targetPermanent.TopCard,
  402. cardEffect: null,
  403. timing: EffectTiming.None,
  404. getCardEffect: getChangeCostEffect);
  405. }
  406. }
  407. #endregion
  408. #region set fixed cost
  409. Func<EffectTiming, ICardEffect> getFixedCostEffect = null;
  410. if (fixedCostTuple != null)
  411. {
  412. bool PermanentCondition(Permanent permanent)
  413. {
  414. return permanent == targetPermanent;
  415. }
  416. bool CardCondition(CardSource cardSource)
  417. {
  418. if (cardSource != null)
  419. {
  420. if (cardSource.Owner == owner)
  421. {
  422. if (fixedCostTuple.Value.fixedCostCardCondition == null || fixedCostTuple.Value.fixedCostCardCondition(cardSource))
  423. {
  424. return true;
  425. }
  426. }
  427. }
  428. return false;
  429. }
  430. getFixedCostEffect = ChangeDigivolutionCostPlayerEffect(
  431. permanentCondition: PermanentCondition,
  432. cardCondition: CardCondition,
  433. rootCondition: null,
  434. changeValue: fixedCost,
  435. activateClass: activateClass,
  436. setFixedCost: true);
  437. if (getChangeCostEffect != null)
  438. {
  439. AddEffectToPlayer(
  440. effectDuration: EffectDuration.UntilCalculateFixedCost,
  441. card: targetPermanent.TopCard,
  442. cardEffect: null,
  443. timing: EffectTiming.None,
  444. getCardEffect: getFixedCostEffect);
  445. }
  446. }
  447. #endregion
  448. #region ignore digivolution requirement
  449. Func<EffectTiming, ICardEffect> getIgnoreDigivolutionRequirementEffect = null;
  450. if (ignoreDigivolutionRequirement)
  451. {
  452. bool PermanentCondition(Permanent permanent)
  453. {
  454. return permanent == targetPermanent;
  455. }
  456. bool CardCondition(CardSource cardSource)
  457. {
  458. if (cardSource == null)
  459. {
  460. return false;
  461. }
  462. if (cardSource.Owner != owner)
  463. {
  464. return false;
  465. }
  466. if (cardCondition == null || cardCondition(cardSource))
  467. {
  468. return true;
  469. }
  470. return false;
  471. }
  472. getIgnoreDigivolutionRequirementEffect = GainIgnoreDigivolutionRequirementPlayerEffect(
  473. permanentCondition: PermanentCondition,
  474. cardCondition: CardCondition,
  475. ignoreDigivolutionRequirement: ignoreDigivolutionRequirement,
  476. digivolutionCost: fixedCost,
  477. activateClass: activateClass);
  478. if (getIgnoreDigivolutionRequirementEffect != null)
  479. {
  480. AddEffectToPlayer(
  481. effectDuration: EffectDuration.UntilCalculateFixedCost,
  482. card: targetPermanent.TopCard,
  483. cardEffect: null,
  484. timing: EffectTiming.None,
  485. getCardEffect: getIgnoreDigivolutionRequirementEffect);
  486. }
  487. }
  488. #endregion
  489. List<CardSource> selectedCards = new List<CardSource>();
  490. IEnumerator SelectCardCoroutine(CardSource cardSource)
  491. {
  492. selectedCards.Add(cardSource);
  493. yield return null;
  494. }
  495. if (isHand)
  496. {
  497. if (owner.HandCards.Count(CanSelectCardCondition) >= 1)
  498. {
  499. int maxCount = Mathf.Min(1, owner.HandCards.Count(CanSelectCardCondition));
  500. SelectHandEffect selectHandEffect = GManager.instance.GetComponent<SelectHandEffect>();
  501. selectHandEffect.SetUp(
  502. selectPlayer: owner,
  503. canTargetCondition: CanSelectCardCondition,
  504. canTargetCondition_ByPreSelecetedList: null,
  505. canEndSelectCondition: null,
  506. maxCount: maxCount,
  507. canNoSelect: true,
  508. canEndNotMax: false,
  509. isShowOpponent: true,
  510. selectCardCoroutine: SelectCardCoroutine,
  511. afterSelectCardCoroutine: null,
  512. mode: SelectHandEffect.Mode.Custom,
  513. cardEffect: activateClass);
  514. selectHandEffect.SetUpCustomMessage("Select 1 card to digivolve.", "The opponent is selecting 1 card to digivolve.");
  515. selectHandEffect.SetUpCustomMessage_ShowCard("Selected Card");
  516. yield return ContinuousController.instance.StartCoroutine(selectHandEffect.Activate());
  517. }
  518. }
  519. else
  520. {
  521. if (HasMatchConditionOwnersCardInTrash(targetPermanent.TopCard, CanSelectCardCondition) && !ignoreSelection)
  522. {
  523. int maxCount = 1;
  524. SelectCardEffect selectCardEffect = GManager.instance.GetComponent<SelectCardEffect>();
  525. selectCardEffect.SetUp(
  526. canTargetCondition: CanSelectCardCondition,
  527. canTargetCondition_ByPreSelecetedList: null,
  528. canEndSelectCondition: null,
  529. canNoSelect: () => true,
  530. selectCardCoroutine: SelectCardCoroutine,
  531. afterSelectCardCoroutine: null,
  532. message: "Select 1 card to digivolve.",
  533. maxCount: maxCount,
  534. canEndNotMax: false,
  535. isShowOpponent: true,
  536. mode: SelectCardEffect.Mode.Custom,
  537. root: SelectCardEffect.Root.Trash,
  538. customRootCardList: null,
  539. canLookReverseCard: true,
  540. selectPlayer: owner,
  541. cardEffect: activateClass);
  542. selectCardEffect.SetUpCustomMessage("Select 1 card to digivolve.", "The opponent is selecting 1 card to digivolve.");
  543. selectCardEffect.SetUpCustomMessage_ShowCard("Selected Card");
  544. yield return ContinuousController.instance.StartCoroutine(selectCardEffect.Activate());
  545. }
  546. else
  547. {
  548. selectedCards.Add(activateClass.EffectSourceCard);
  549. }
  550. }
  551. PlayCardClass playCardClass = new PlayCardClass(
  552. cardSources: selectedCards,
  553. hashtable: CardEffectHashtable(activateClass),
  554. payCost: payCost,
  555. targetPermanent: targetPermanent,
  556. isTapped: false,
  557. root: root,
  558. activateETB: true);
  559. if (ignoreLevel) playCardClass.SetIgnoreLevel();
  560. if (!ignoreDigivolutionRequirement && fixedCost >= 0) playCardClass.SetFixedCost(fixedCost);
  561. yield return ContinuousController.instance.StartCoroutine(playCardClass.PlayCard());
  562. #region release effect
  563. if (getChangeCostEffect != null) owner.UntilCalculateFixedCostEffect.Remove(getChangeCostEffect);
  564. #endregion
  565. #region release effect
  566. if (getFixedCostEffect != null) owner.UntilCalculateFixedCostEffect.Remove(getFixedCostEffect);
  567. #endregion
  568. #region release effect
  569. if (getIgnoreDigivolutionRequirementEffect != null) owner.UntilCalculateFixedCostEffect.Remove(getIgnoreDigivolutionRequirementEffect);
  570. #endregion
  571. if (selectedCards.Count >= 1)
  572. {
  573. if (IsDigivolvedByTheEffect(targetPermanent, selectedCards[0], activateClass))
  574. {
  575. if (successProcess != null)
  576. {
  577. yield return ContinuousController.instance.StartCoroutine(successProcess);
  578. }
  579. }
  580. }
  581. }
  582. #endregion
  583. #region Target permanent Digivolves into Digimon card execution area
  584. public static IEnumerator DigivolveIntoExcecutingAreaCard(
  585. Permanent targetPermanent,
  586. Func<CardSource, bool> cardCondition,
  587. bool payCost,
  588. (int reduceCost, Func<CardSource, bool> reduceCostCardCondition)? reduceCostTuple,
  589. (int fixedCost, Func<CardSource, bool> fixedCostCardCondition)? fixedCostTuple,
  590. int ignoreDigivolutionRequirementFixedCost,
  591. ICardEffect activateClass,
  592. IEnumerator successProcess,
  593. bool ignoreLevel = false,
  594. bool ignoreSelection = false)
  595. {
  596. if (targetPermanent == null) yield break;
  597. if (targetPermanent.TopCard == null) yield break;
  598. if (activateClass == null) yield break;
  599. if (activateClass.EffectSourceCard == null) yield break;
  600. Player owner = targetPermanent.TopCard.Owner;
  601. SelectCardEffect.Root root = SelectCardEffect.Root.Execution;
  602. bool ignoreDigivolutionRequirement = ignoreDigivolutionRequirementFixedCost >= 0;
  603. int fixedCost = -1;
  604. if (fixedCostTuple != null)
  605. {
  606. fixedCost = fixedCostTuple.Value.fixedCost;
  607. }
  608. if (ignoreDigivolutionRequirement)
  609. {
  610. fixedCost = ignoreDigivolutionRequirementFixedCost;
  611. }
  612. bool CanSelectCardCondition(CardSource cardSource)
  613. {
  614. if (cardSource.IsDigimon)
  615. {
  616. if (cardCondition == null || cardCondition(cardSource))
  617. {
  618. if (!cardSource.CanNotEvolve(targetPermanent))
  619. {
  620. if (ignoreLevel
  621. || cardSource.CanPlayCardTargetFrame(
  622. frame: targetPermanent.PermanentFrame,
  623. PayCost: payCost,
  624. cardEffect: activateClass,
  625. root: root,
  626. fixedCost: fixedCost))
  627. {
  628. return true;
  629. }
  630. }
  631. }
  632. }
  633. return false;
  634. }
  635. #region reduce cost
  636. Func<EffectTiming, ICardEffect> getChangeCostEffect = null;
  637. if (reduceCostTuple != null)
  638. {
  639. bool PermanentCondition(Permanent permanent)
  640. {
  641. return permanent == targetPermanent;
  642. }
  643. bool CardCondition(CardSource cardSource)
  644. {
  645. if (cardSource != null)
  646. {
  647. if (cardSource.Owner == owner)
  648. {
  649. if (reduceCostTuple.Value.reduceCostCardCondition == null || reduceCostTuple.Value.reduceCostCardCondition(cardSource))
  650. {
  651. return true;
  652. }
  653. }
  654. }
  655. return false;
  656. }
  657. getChangeCostEffect = ChangeDigivolutionCostPlayerEffect(
  658. permanentCondition: PermanentCondition,
  659. cardCondition: CardCondition,
  660. rootCondition: null,
  661. changeValue: -reduceCostTuple.Value.reduceCost,
  662. activateClass: activateClass,
  663. setFixedCost: false);
  664. if (getChangeCostEffect != null)
  665. {
  666. AddEffectToPlayer(
  667. effectDuration: EffectDuration.UntilCalculateFixedCost,
  668. card: targetPermanent.TopCard,
  669. cardEffect: null,
  670. timing: EffectTiming.None,
  671. getCardEffect: getChangeCostEffect);
  672. }
  673. }
  674. #endregion
  675. #region set fixed cost
  676. Func<EffectTiming, ICardEffect> getFixedCostEffect = null;
  677. if (fixedCostTuple != null)
  678. {
  679. bool PermanentCondition(Permanent permanent)
  680. {
  681. return permanent == targetPermanent;
  682. }
  683. bool CardCondition(CardSource cardSource)
  684. {
  685. if (cardSource != null)
  686. {
  687. if (cardSource.Owner == owner)
  688. {
  689. if (fixedCostTuple.Value.fixedCostCardCondition == null || fixedCostTuple.Value.fixedCostCardCondition(cardSource))
  690. {
  691. return true;
  692. }
  693. }
  694. }
  695. return false;
  696. }
  697. getFixedCostEffect = ChangeDigivolutionCostPlayerEffect(
  698. permanentCondition: PermanentCondition,
  699. cardCondition: CardCondition,
  700. rootCondition: null,
  701. changeValue: fixedCost,
  702. activateClass: activateClass,
  703. setFixedCost: true);
  704. if (getChangeCostEffect != null)
  705. {
  706. AddEffectToPlayer(
  707. effectDuration: EffectDuration.UntilCalculateFixedCost,
  708. card: targetPermanent.TopCard,
  709. cardEffect: null,
  710. timing: EffectTiming.None,
  711. getCardEffect: getFixedCostEffect);
  712. }
  713. }
  714. #endregion
  715. #region ignore digivolution requirement
  716. Func<EffectTiming, ICardEffect> getIgnoreDigivolutionRequirementEffect = null;
  717. if (ignoreDigivolutionRequirement)
  718. {
  719. bool PermanentCondition(Permanent permanent)
  720. {
  721. return permanent == targetPermanent;
  722. }
  723. bool CardCondition(CardSource cardSource)
  724. {
  725. if (cardSource == null)
  726. {
  727. return false;
  728. }
  729. if (cardSource.Owner != owner)
  730. {
  731. return false;
  732. }
  733. if (cardCondition == null || cardCondition(cardSource))
  734. {
  735. return true;
  736. }
  737. return false;
  738. }
  739. getIgnoreDigivolutionRequirementEffect = GainIgnoreDigivolutionRequirementPlayerEffect(
  740. permanentCondition: PermanentCondition,
  741. cardCondition: CardCondition,
  742. ignoreDigivolutionRequirement: ignoreDigivolutionRequirement,
  743. digivolutionCost: fixedCost,
  744. activateClass: activateClass);
  745. if (getIgnoreDigivolutionRequirementEffect != null)
  746. {
  747. AddEffectToPlayer(
  748. effectDuration: EffectDuration.UntilCalculateFixedCost,
  749. card: targetPermanent.TopCard,
  750. cardEffect: null,
  751. timing: EffectTiming.None,
  752. getCardEffect: getIgnoreDigivolutionRequirementEffect);
  753. }
  754. }
  755. #endregion
  756. List<CardSource> selectedCards = new List<CardSource>();
  757. IEnumerator SelectCardCoroutine(CardSource cardSource)
  758. {
  759. selectedCards.Add(cardSource);
  760. yield return null;
  761. }
  762. if (owner.ExecutingCards.Count(CanSelectCardCondition) >= 1)
  763. {
  764. int maxCount = 1;
  765. SelectCardEffect selectCardEffect = GManager.instance.GetComponent<SelectCardEffect>();
  766. selectCardEffect.SetUp(
  767. canTargetCondition: CanSelectCardCondition,
  768. canTargetCondition_ByPreSelecetedList: null,
  769. canEndSelectCondition: null,
  770. canNoSelect: () => true,
  771. selectCardCoroutine: SelectCardCoroutine,
  772. afterSelectCardCoroutine: null,
  773. message: "Select 1 card to digivolve.",
  774. maxCount: maxCount,
  775. canEndNotMax: false,
  776. isShowOpponent: true,
  777. mode: SelectCardEffect.Mode.Custom,
  778. root: SelectCardEffect.Root.Execution,
  779. customRootCardList: null,
  780. canLookReverseCard: true,
  781. selectPlayer: owner,
  782. cardEffect: activateClass);
  783. selectCardEffect.SetUpCustomMessage("Select 1 card to digivolve.", "The opponent is selecting 1 card to digivolve.");
  784. selectCardEffect.SetUpCustomMessage_ShowCard("Selected Card");
  785. yield return ContinuousController.instance.StartCoroutine(selectCardEffect.Activate());
  786. }
  787. else
  788. {
  789. selectedCards.Add(activateClass.EffectSourceCard);
  790. }
  791. PlayCardClass playCardClass = new PlayCardClass(
  792. cardSources: selectedCards,
  793. hashtable: CardEffectHashtable(activateClass),
  794. payCost: payCost,
  795. targetPermanent: targetPermanent,
  796. isTapped: false,
  797. root: root,
  798. activateETB: true);
  799. if (ignoreLevel) playCardClass.SetIgnoreLevel();
  800. if (!ignoreDigivolutionRequirement && fixedCost >= 0) playCardClass.SetFixedCost(fixedCost);
  801. yield return ContinuousController.instance.StartCoroutine(playCardClass.PlayCard());
  802. #region release effect
  803. if (getChangeCostEffect != null) owner.UntilCalculateFixedCostEffect.Remove(getChangeCostEffect);
  804. #endregion
  805. #region release effect
  806. if (getFixedCostEffect != null) owner.UntilCalculateFixedCostEffect.Remove(getFixedCostEffect);
  807. #endregion
  808. #region release effect
  809. if (getIgnoreDigivolutionRequirementEffect != null) owner.UntilCalculateFixedCostEffect.Remove(getIgnoreDigivolutionRequirementEffect);
  810. #endregion
  811. if (selectedCards.Count >= 1)
  812. {
  813. if (IsDigivolvedByTheEffect(targetPermanent, selectedCards[0], activateClass))
  814. {
  815. if (successProcess != null)
  816. {
  817. yield return ContinuousController.instance.StartCoroutine(successProcess);
  818. }
  819. }
  820. }
  821. }
  822. #endregion
  823. #region Get the effect given by EffectTiming
  824. public static Func<EffectTiming, ICardEffect> GetCardEffectByEffectTiming(EffectTiming timing, ICardEffect cardEffect) => (_timing) => _timing == timing ? cardEffect : null;
  825. #endregion
  826. }