CardEffectCommons.cs 35 KB

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