From 4941da593f4b6747530d02ff7f4cf4a2b259c3fd Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Thu, 20 Jul 2023 20:56:24 +0200 Subject: [PATCH 1/3] Fix casting with unpayable cost if no alternative provided --- .../java/forge/game/ability/effects/PlayEffect.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java index 7ec1c6447a0..e1439b8e9c4 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/PlayEffect.java @@ -370,15 +370,23 @@ public class PlayEffect extends SpellAbilityEffect { if ((sa.hasParam("WithoutManaCost") || sa.hasParam("PlayCost")) && tgtSA.costHasManaX() && !tgtSA.getPayCosts().getCostMana().canXbe0()) { continue; } + + boolean unpayableCost = tgtSA.getHostCard().getManaCost().isNoCost(); if (sa.hasParam("WithoutManaCost")) { tgtSA = tgtSA.copyWithNoManaCost(); } else if (sa.hasParam("PlayCost")) { Cost abCost; String cost = sa.getParam("PlayCost"); if (cost.equals("ManaCost")) { + if (unpayableCost) { + continue; + } abCost = new Cost(source.getManaCost(), false); } else { if (cost.contains("ConvertedManaCost")) { + if (unpayableCost) { + continue; + } final String costcmc = Integer.toString(tgtCard.getCMC()); cost = cost.replace("ConvertedManaCost", costcmc); } @@ -386,6 +394,8 @@ public class PlayEffect extends SpellAbilityEffect { } tgtSA = tgtSA.copyWithManaCostReplaced(tgtSA.getActivatingPlayer(), abCost); + } else if (unpayableCost) { + continue; } if (!optional) { From 574af343bc0ea00df6cdbc296f23145b734bc226 Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Thu, 20 Jul 2023 21:01:53 +0200 Subject: [PATCH 2/3] Battle fix --- .../StaticAbilityCantAttackBlock.java | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantAttackBlock.java b/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantAttackBlock.java index 930457af01b..df7cef82130 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantAttackBlock.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantAttackBlock.java @@ -90,7 +90,17 @@ public class StaticAbilityCantAttackBlock { } } - final Player defender = target instanceof Card ? ((Card) target).getController() : (Player) target; + final Player defender; + if (target instanceof Player) { + defender = (Player) target; + } else { + Card c = (Card) target; + if (c.isBattle()) { + defender = c.getProtectingPlayer(); + } else { + defender = c.getController(); + } + } if (stAb.hasParam("UnlessDefenderControls")) { String type = stAb.getParam("UnlessDefenderControls"); @@ -108,9 +118,20 @@ public class StaticAbilityCantAttackBlock { return false; } } - if (stAb.hasParam("DefenderNotNearestToYouInChosenDirection") && (hostCard.getChosenDirection() == null - || defender.equals(game.getNextPlayerAfter(card.getController(), hostCard.getChosenDirection())))) { - return false; + if (stAb.hasParam("DefenderNotNearestToYouInChosenDirection")) { + if (hostCard.getChosenDirection() == null) { + return false; + } + if (target instanceof Card && ((Card) target).isBattle()) { + return false; + } + Player next = card.getController(); + while (!next.isOpponentOf(card.getController())) { + next = game.getNextPlayerAfter(next, hostCard.getChosenDirection()); + } + if (defender.equals(next)) { + return false; + } } if (stAb.hasParam("UnlessDefender")) { final String type = stAb.getParam("UnlessDefender"); From a7aff0f80d2d6a4278df854be399007763d107bd Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Thu, 20 Jul 2023 21:02:11 +0200 Subject: [PATCH 3/3] Fix scripts --- forge-gui/res/cardsfolder/a/ascendant_spirit.txt | 4 ++-- forge-gui/res/cardsfolder/b/bee_sting.txt | 2 +- forge-gui/res/cardsfolder/c/comet_storm.txt | 2 +- forge-gui/res/cardsfolder/f/figure_of_destiny.txt | 6 +++--- forge-gui/res/cardsfolder/k/kazuul_tyrant_of_the_cliffs.txt | 2 +- forge-gui/res/cardsfolder/n/next_of_kin.txt | 3 ++- forge-gui/res/cardsfolder/o/oskar_rubbish_reclaimer.txt | 2 +- forge-gui/res/cardsfolder/s/strength_of_the_tajuru.txt | 2 +- forge-gui/res/cardsfolder/w/warden_of_the_first_tree.txt | 4 ++-- 9 files changed, 14 insertions(+), 13 deletions(-) diff --git a/forge-gui/res/cardsfolder/a/ascendant_spirit.txt b/forge-gui/res/cardsfolder/a/ascendant_spirit.txt index 4403b42dba4..53158ba6bbb 100644 --- a/forge-gui/res/cardsfolder/a/ascendant_spirit.txt +++ b/forge-gui/res/cardsfolder/a/ascendant_spirit.txt @@ -2,9 +2,9 @@ Name:Ascendant Spirit ManaCost:U Types:Snow Creature Spirit PT:1/1 -A:AB$ Animate | Cost$ S S | Types$ Spirit,Warrior | Duration$ Permanent | Power$ 2 | Toughness$ 3 | StackDescription$ SpellDescription | SpellDescription$ CARDNAME becomes a Spirit Warrior with base power and toughness 2/3. +A:AB$ Animate | Cost$ S S | Types$ Spirit,Warrior | RemoveCreatureTypes$ True | Duration$ Permanent | Power$ 2 | Toughness$ 3 | StackDescription$ SpellDescription | SpellDescription$ CARDNAME becomes a Spirit Warrior with base power and toughness 2/3. A:AB$ PutCounter | Cost$ S S S | ConditionPresent$ Card.Self+Warrior | CounterType$ Flying | CounterNum$ 1 | SubAbility$ TrigAnimate | StackDescription$ SpellDescription | SpellDescription$ If CARDNAME is a Warrior, put a flying counter on it and it becomes an Angel Spirit Warrior with base power and toughness 4/4. -SVar:TrigAnimate:DB$ Animate | ConditionPresent$ Card.Self+Warrior | Types$ Angel,Spirit,Warrior | Duration$ Permanent | Power$ 4 | Toughness$ 4 +SVar:TrigAnimate:DB$ Animate | ConditionPresent$ Card.Self+Warrior | Types$ Angel,Spirit,Warrior | RemoveCreatureTypes$ True | Duration$ Permanent | Power$ 4 | Toughness$ 4 A:AB$ PutCounter | Cost$ S S S S | ConditionPresent$ Card.Self+Angel | CounterType$ P1P1 | CounterNum$ 2 | SubAbility$ AddTrigger | StackDescription$ SpellDescription | SpellDescription$ If CARDNAME is an Angel, put two +1/+1 counters on it and it gains "Whenever this creature deals combat damage to a player, draw a card." SVar:AddTrigger:DB$ Animate | Defined$ Self | ConditionPresent$ Card.Self+Angel | Triggers$ DamageDraw | Duration$ Permanent SVar:DamageDraw:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | TriggerZones$ Battlefield | Execute$ TrigDraw | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, draw a card. diff --git a/forge-gui/res/cardsfolder/b/bee_sting.txt b/forge-gui/res/cardsfolder/b/bee_sting.txt index 61b0aac0d11..c29dd2c1349 100644 --- a/forge-gui/res/cardsfolder/b/bee_sting.txt +++ b/forge-gui/res/cardsfolder/b/bee_sting.txt @@ -1,5 +1,5 @@ Name:Bee Sting ManaCost:3 G Types:Sorcery -A:SP$ DealDamage | Cost$ 3 G | ValidTgts$ Any | NumDmg$ 2 | SpellDescription$ Bee Sting deals 2 damage to any target. +A:SP$ DealDamage | Cost$ 3 G | ValidTgts$ Any | NumDmg$ 2 | SpellDescription$ CARDNAME deals 2 damage to any target. Oracle:Bee Sting deals 2 damage to any target. diff --git a/forge-gui/res/cardsfolder/c/comet_storm.txt b/forge-gui/res/cardsfolder/c/comet_storm.txt index ba5a9f7e80b..72bc4985af8 100644 --- a/forge-gui/res/cardsfolder/c/comet_storm.txt +++ b/forge-gui/res/cardsfolder/c/comet_storm.txt @@ -1,7 +1,7 @@ Name:Comet Storm ManaCost:X R R Types:Instant -A:SP$ DealDamage | Cost$ X R R | Announce$ Multikicker,X | ValidTgts$ Any | NumDmg$ X | TargetMin$ TargetsNum | TargetMax$ TargetsNum | SpellDescription$ CARDNAME deals X damage to each targets. +A:SP$ DealDamage | Cost$ X R R | Announce$ Multikicker | ValidTgts$ Any | NumDmg$ X | TargetMin$ TargetsNum | TargetMax$ TargetsNum | SpellDescription$ CARDNAME deals X damage to each targets. K:Multikicker:1 SVar:TargetsNum:Count$TimesKicked/Plus.1 SVar:X:Count$xPaid diff --git a/forge-gui/res/cardsfolder/f/figure_of_destiny.txt b/forge-gui/res/cardsfolder/f/figure_of_destiny.txt index 2411d27e038..ca9731d7318 100644 --- a/forge-gui/res/cardsfolder/f/figure_of_destiny.txt +++ b/forge-gui/res/cardsfolder/f/figure_of_destiny.txt @@ -2,7 +2,7 @@ Name:Figure of Destiny ManaCost:RW Types:Creature Kithkin PT:1/1 -A:AB$ Animate | Cost$ RW | Types$ Kithkin,Spirit | Duration$ Permanent | Power$ 2 | Toughness$ 2 | SpellDescription$ CARDNAME becomes a Kithkin Spirit with base power and toughness 2/2. -A:AB$ Animate | Cost$ RW RW RW | ConditionPresent$ Card.Self+Spirit | Types$ Kithkin,Spirit,Warrior | Duration$ Permanent | Power$ 4 | Toughness$ 4 | SpellDescription$ If CARDNAME is a Spirit, it becomes a Kithkin Spirit Warrior with base power and toughness 4/4. -A:AB$ Animate | Cost$ RW RW RW RW RW RW | ConditionPresent$ Card.Self+Warrior | Types$ Kithkin,Spirit,Warrior,Avatar | Duration$ Permanent | Power$ 8 | Toughness$ 8 | Keywords$ Flying & First Strike | SpellDescription$ If CARDNAME is a Warrior, it becomes a Kithkin Spirit Warrior Avatar with base power and toughness 8/8, flying, and first strike. +A:AB$ Animate | Cost$ RW | Types$ Kithkin,Spirit | RemoveCreatureTypes$ True | Duration$ Permanent | Power$ 2 | Toughness$ 2 | SpellDescription$ CARDNAME becomes a Kithkin Spirit with base power and toughness 2/2. +A:AB$ Animate | Cost$ RW RW RW | ConditionPresent$ Card.Self+Spirit | Types$ Kithkin,Spirit,Warrior | RemoveCreatureTypes$ True | Duration$ Permanent | Power$ 4 | Toughness$ 4 | SpellDescription$ If CARDNAME is a Spirit, it becomes a Kithkin Spirit Warrior with base power and toughness 4/4. +A:AB$ Animate | Cost$ RW RW RW RW RW RW | ConditionPresent$ Card.Self+Warrior | Types$ Kithkin,Spirit,Warrior,Avatar | RemoveCreatureTypes$ True | Duration$ Permanent | Power$ 8 | Toughness$ 8 | Keywords$ Flying & First Strike | SpellDescription$ If CARDNAME is a Warrior, it becomes a Kithkin Spirit Warrior Avatar with base power and toughness 8/8, flying, and first strike. Oracle:{R/W}: Figure of Destiny becomes a Kithkin Spirit with base power and toughness 2/2.\n{R/W}{R/W}{R/W}: If Figure of Destiny is a Spirit, it becomes a Kithkin Spirit Warrior with base power and toughness 4/4.\n{R/W}{R/W}{R/W}{R/W}{R/W}{R/W}: If Figure of Destiny is a Warrior, it becomes a Kithkin Spirit Warrior Avatar with base power and toughness 8/8, flying, and first strike. diff --git a/forge-gui/res/cardsfolder/k/kazuul_tyrant_of_the_cliffs.txt b/forge-gui/res/cardsfolder/k/kazuul_tyrant_of_the_cliffs.txt index ee5f6ea7b8d..b7f8dfed82a 100644 --- a/forge-gui/res/cardsfolder/k/kazuul_tyrant_of_the_cliffs.txt +++ b/forge-gui/res/cardsfolder/k/kazuul_tyrant_of_the_cliffs.txt @@ -2,6 +2,6 @@ Name:Kazuul, Tyrant of the Cliffs ManaCost:3 R R Types:Legendary Creature Ogre Warrior PT:5/4 -T:Mode$ Attacks | ValidCard$ Creature.OppCtrl | Attacked$ You,Planeswalker.YouCtrl | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Whenever a creature an opponent controls attacks, if you're the defending player, create a 3/3 red Ogre creature token unless that creature's controller pays {3}. +T:Mode$ Attacks | ValidCard$ Creature.OppCtrl | Attacked$ You,Planeswalker.YouCtrl,Battle.ProtectedBy You | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Whenever a creature an opponent controls attacks, if you're the defending player, create a 3/3 red Ogre creature token unless that creature's controller pays {3}. SVar:TrigToken:DB$ Token | TokenOwner$ You | TokenAmount$ 1 | TokenScript$ r_3_3_ogre | UnlessCost$ 3 | UnlessPayer$ TriggeredAttackerController Oracle:Whenever a creature an opponent controls attacks, if you're the defending player, create a 3/3 red Ogre creature token unless that creature's controller pays {3}. diff --git a/forge-gui/res/cardsfolder/n/next_of_kin.txt b/forge-gui/res/cardsfolder/n/next_of_kin.txt index 863c63cf59a..18e1800484d 100644 --- a/forge-gui/res/cardsfolder/n/next_of_kin.txt +++ b/forge-gui/res/cardsfolder/n/next_of_kin.txt @@ -6,7 +6,8 @@ A:SP$ Attach | ValidTgts$ Creature | AILogic$ Pump T:Mode$ ChangesZone | ValidCard$ Card.EnchantedBy | Origin$ Battlefield | Destination$ Graveyard | Execute$ TrigChangeZone | OptionalDecider$ You | TriggerDescription$ When enchanted creature dies, you may put a creature card you own with lesser mana value from your hand or from the command zone onto the battlefield. If you do, return CARDNAME to the battlefield attached to that creature at the beginning of the next end step. SVar:TrigChangeZone:DB$ ChangeZone | Origin$ Hand,Command | Destination$ Battlefield | ChangeType$ Creature.cmcLTX+YouOwn | RememberChanged$ True | SubAbility$ DBDelayedTrigger SVar:X:TriggeredCard$CardManaCost -SVar:DBDelayedTrigger:DB$ DelayedTrigger | Mode$ Phase | Phase$ End Of Turn | Execute$ TrigReturn | RememberObjects$ Remembered | TriggerDescription$ If you do, return CARDNAME to the battlefield attached to that creature at the beginning of the next end step. +SVar:DBDelayedTrigger:DB$ DelayedTrigger | Mode$ Phase | Phase$ End Of Turn | Execute$ TrigReturn | RememberObjects$ Remembered | ConditionDefined$ Remembered | ConditionPresent$ Card | SubAbility$ DBCleanup | TriggerDescription$ If you do, return CARDNAME to the battlefield attached to that creature at the beginning of the next end step. SVar:TrigReturn:DB$ ChangeZone | Defined$ Self | Origin$ Graveyard | Destination$ Battlefield | AttachedTo$ DelayTriggerRememberedLKI +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True DeckHas:Ability$Graveyard Oracle:Enchant creature\nWhen enchanted creature dies, you may put a creature card you own with lesser mana value from your hand or from the command zone onto the battlefield. If you do, return Next of Kin to the battlefield attached to that creature at the beginning of the next end step. diff --git a/forge-gui/res/cardsfolder/o/oskar_rubbish_reclaimer.txt b/forge-gui/res/cardsfolder/o/oskar_rubbish_reclaimer.txt index 0b640cfb508..127d4a6b43c 100644 --- a/forge-gui/res/cardsfolder/o/oskar_rubbish_reclaimer.txt +++ b/forge-gui/res/cardsfolder/o/oskar_rubbish_reclaimer.txt @@ -4,7 +4,7 @@ Types:Legendary Creature Human Wizard PT:3/3 S:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ X | EffectZone$ All | Description$ This spell costs {1} less to cast for each different mana value among cards in your graveyard. SVar:X:Count$ValidGraveyard Card.YouOwn$DifferentCMC -T:Mode$ Discarded | ValidPlayer$ You | ValidCard$ Card.nonLand | TriggerZones$ Battlefield | Execute$ TrigPlay | TriggerDescription$ Whenever you discard a card, you may cast it from your graveyard. +T:Mode$ Discarded | ValidPlayer$ You | ValidCard$ Card.nonLand | TriggerZones$ Battlefield | Execute$ TrigPlay | TriggerDescription$ Whenever you discard a nonland card, you may cast it from your graveyard. SVar:TrigPlay:DB$ Play | Defined$ TriggeredCard | ValidSA$ Spell | Controller$ You | Optional$ True | Amount$ All DeckHas:Ability$Graveyard DeckNeeds:Ability$Discard diff --git a/forge-gui/res/cardsfolder/s/strength_of_the_tajuru.txt b/forge-gui/res/cardsfolder/s/strength_of_the_tajuru.txt index 745a47e14a5..1294bbc4321 100644 --- a/forge-gui/res/cardsfolder/s/strength_of_the_tajuru.txt +++ b/forge-gui/res/cardsfolder/s/strength_of_the_tajuru.txt @@ -2,7 +2,7 @@ Name:Strength of the Tajuru ManaCost:X G G Types:Instant K:Multikicker:1 -A:SP$ PutCounter | CounterType$ P1P1 | CounterNum$ X | Cost$ X G G | Announce$ Multikicker,X | ValidTgts$ Creature | TgtPrompt$ Select target creature | TargetMin$ TargetsNum | TargetMax$ TargetsNum | SpellDescription$ Choose target creature, then choose another target creature for each time this spell was kicked. Put X +1/+1 counters on each of them. +A:SP$ PutCounter | CounterType$ P1P1 | CounterNum$ X | Cost$ X G G | Announce$ Multikicker | ValidTgts$ Creature | TgtPrompt$ Select target creature | TargetMin$ TargetsNum | TargetMax$ TargetsNum | SpellDescription$ Choose target creature, then choose another target creature for each time this spell was kicked. Put X +1/+1 counters on each of them. SVar:X:Count$xPaid SVar:TargetsNum:Count$TimesKicked/Plus.1 DeckHas:Ability$Counters diff --git a/forge-gui/res/cardsfolder/w/warden_of_the_first_tree.txt b/forge-gui/res/cardsfolder/w/warden_of_the_first_tree.txt index aa931dc1cf7..d0c5aa5470a 100644 --- a/forge-gui/res/cardsfolder/w/warden_of_the_first_tree.txt +++ b/forge-gui/res/cardsfolder/w/warden_of_the_first_tree.txt @@ -2,7 +2,7 @@ Name:Warden of the First Tree ManaCost:G Types:Creature Human PT:1/1 -A:AB$ Animate | Cost$ 1 WB | Types$ Human,Warrior | Duration$ Permanent | Power$ 3 | Toughness$ 3 | SpellDescription$ CARDNAME becomes a Human Warrior with base power and toughness 3/3. -A:AB$ Animate | Cost$ 2 WB WB | Defined$ Self | ConditionPresent$ Card.Self+Warrior | Types$ Human,Warrior,Spirit | Duration$ Permanent | Keywords$ Trample & Lifelink | SpellDescription$ If CARDNAME is a Warrior, it becomes a Human Spirit Warrior with trample and lifelink. +A:AB$ Animate | Cost$ 1 WB | Types$ Human,Warrior | RemoveCreatureTypes$ True | Duration$ Permanent | Power$ 3 | Toughness$ 3 | SpellDescription$ CARDNAME becomes a Human Warrior with base power and toughness 3/3. +A:AB$ Animate | Cost$ 2 WB WB | Defined$ Self | ConditionPresent$ Card.Self+Warrior | Types$ Human,Warrior,Spirit | RemoveCreatureTypes$ True | Duration$ Permanent | Keywords$ Trample & Lifelink | SpellDescription$ If CARDNAME is a Warrior, it becomes a Human Spirit Warrior with trample and lifelink. A:AB$ PutCounter | Cost$ 3 WB WB WB | ConditionPresent$ Card.Self+Spirit | CounterType$ P1P1 | CounterNum$ 5 | SpellDescription$ If CARDNAME is a Spirit, put five +1/+1 counters on it. Oracle:{1}{W/B}: Warden of the First Tree becomes a Human Warrior with base power and toughness 3/3.\n{2}{W/B}{W/B}: If Warden of the First Tree is a Warrior, it becomes a Human Spirit Warrior with trample and lifelink.\n{3}{W/B}{W/B}{W/B}: If Warden of the First Tree is a Spirit, put five +1/+1 counters on it.