From 3b594d239c3a134a273d993f767ca6ef4be8da8d Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Wed, 2 Jun 2021 17:30:31 +0200 Subject: [PATCH 1/6] Update script --- forge-gui/res/cardsfolder/g/giant_opportunity.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forge-gui/res/cardsfolder/g/giant_opportunity.txt b/forge-gui/res/cardsfolder/g/giant_opportunity.txt index 2442c4b1d57..bfc1a755929 100644 --- a/forge-gui/res/cardsfolder/g/giant_opportunity.txt +++ b/forge-gui/res/cardsfolder/g/giant_opportunity.txt @@ -1,7 +1,7 @@ Name:Giant Opportunity ManaCost:2 G Types:Sorcery -A:SP$ Sacrifice | Cost$ 2 G | SacValid$ Food | Defined$ You | Amount$ 2 | Optional$ True | StrictAmount$ True | RememberSacrificed$ True | SubAbility$ DBToken | SpellDescription$ You may sacrifice two Foods. If you do, create a 7/7 green Giant creature token. Otherwise, create three Food tokens. (They're artifacts with "{2}, {T}, Sacrifice this artifact: You gain 3 life.") +A:SP$ Sacrifice | Cost$ 2 G | SacValid$ Food | Defined$ You | Amount$ 2 | OptionalSacrifice$ True | StrictAmount$ True | RememberSacrificed$ True | SubAbility$ DBToken | SpellDescription$ You may sacrifice two Foods. If you do, create a 7/7 green Giant creature token. Otherwise, create three Food tokens. (They're artifacts with "{2}, {T}, Sacrifice this artifact: You gain 3 life.") SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ g_7_7_giant | TokenOwner$ You | ConditionDefined$ RememberedLKI | ConditionPresent$ Food | ConditionCompare$ EQ2 | SubAbility$ DBToken2 SVar:DBToken2:DB$ Token | TokenAmount$ 3 | TokenScript$ c_a_food_sac | TokenOwner$ You | ConditionDefined$ RememberedLKI | ConditionPresent$ Food | ConditionCompare$ EQ0 | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True From 196b48cbd33786bb445ffcee79cbc3df03f10142 Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Thu, 3 Jun 2021 10:14:16 +0200 Subject: [PATCH 2/6] Reduce FailedToTarget scenario --- forge-ai/src/main/java/forge/ai/AiController.java | 1 - forge-ai/src/main/java/forge/ai/SpellAbilityAi.java | 4 ++-- forge-ai/src/main/java/forge/ai/ability/PumpAi.java | 1 - forge-ai/src/main/java/forge/ai/ability/PumpAiBase.java | 2 -- forge-ai/src/main/java/forge/ai/ability/PumpAllAi.java | 6 ++++++ forge-ai/src/main/java/forge/ai/ability/TapOrUntapAi.java | 2 -- .../java/forge/game/spellability/SpellAbilityCondition.java | 1 - 7 files changed, 8 insertions(+), 9 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/AiController.java b/forge-ai/src/main/java/forge/ai/AiController.java index eff1abb586b..e1a9e70e8da 100644 --- a/forge-ai/src/main/java/forge/ai/AiController.java +++ b/forge-ai/src/main/java/forge/ai/AiController.java @@ -313,7 +313,6 @@ public class AiController { // need to set TriggeredObject exSA.setTriggeringObject(AbilityKey.Card, card); - // for trigger test, need to ignore the conditions SpellAbilityCondition cons = exSA.getConditions(); if (cons != null) { diff --git a/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java b/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java index 6b65082c41a..cab5c81ed2a 100644 --- a/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java +++ b/forge-ai/src/main/java/forge/ai/SpellAbilityAi.java @@ -162,7 +162,7 @@ public abstract class SpellAbilityAi { if (ComputerUtil.preventRunAwayActivations(sa)) { return false; // prevent infinite loop } - return MyRandom.getRandom().nextFloat() < .8f; // random success + return MyRandom.getRandom().nextFloat() < .8f; // random success } public final boolean doTriggerAI(final Player aiPlayer, final SpellAbility sa, final boolean mandatory) { @@ -193,7 +193,7 @@ public abstract class SpellAbilityAi { * Handles the AI decision to play a triggered SpellAbility */ protected boolean doTriggerAINoCost(final Player aiPlayer, final SpellAbility sa, final boolean mandatory) { - if (canPlayWithoutRestrict(aiPlayer, sa)) { + if (canPlayWithoutRestrict(aiPlayer, sa) && (!mandatory || sa.isTargetNumberValid())) { return true; } diff --git a/forge-ai/src/main/java/forge/ai/ability/PumpAi.java b/forge-ai/src/main/java/forge/ai/ability/PumpAi.java index 43d4e48fe80..02e582b8e69 100644 --- a/forge-ai/src/main/java/forge/ai/ability/PumpAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/PumpAi.java @@ -400,7 +400,6 @@ public class PumpAi extends PumpAiBase { if (ComputerUtilCard.shouldPumpCard(ai, sa, card, defense, attack, keywords, false)) { return true; } else if (containsUsefulKeyword(ai, keywords, card, sa, attack)) { - Card pumped = ComputerUtilCard.getPumpedCreature(ai, sa, card, 0, 0, keywords); if (game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_ATTACKERS, ai) || game.getPhaseHandler().is(PhaseType.COMBAT_BEGIN, ai)) { diff --git a/forge-ai/src/main/java/forge/ai/ability/PumpAiBase.java b/forge-ai/src/main/java/forge/ai/ability/PumpAiBase.java index 5c100147fb8..5e708dbdd9f 100644 --- a/forge-ai/src/main/java/forge/ai/ability/PumpAiBase.java +++ b/forge-ai/src/main/java/forge/ai/ability/PumpAiBase.java @@ -44,7 +44,6 @@ public abstract class PumpAiBase extends SpellAbilityAi { return false; } - public boolean grantsUsefulExtraBlockOpts(final Player ai, final SpellAbility sa, final Card card, List keywords) { PhaseHandler ph = ai.getGame().getPhaseHandler(); Card pumped = ComputerUtilCard.getPumpedCreature(ai, sa, card, 0, 0, keywords); @@ -506,7 +505,6 @@ public abstract class PumpAiBase extends SpellAbilityAi { else { final boolean addsKeywords = !keywords.isEmpty(); if (addsKeywords) { - // If the keyword can prevent a creature from attacking, see if there's some kind of viable prioritization if (keywords.contains("CARDNAME can't attack.") || keywords.contains("CARDNAME can't attack or block.") || keywords.contains("HIDDEN CARDNAME can't attack.") || keywords.contains("HIDDEN CARDNAME can't attack or block.")) { diff --git a/forge-ai/src/main/java/forge/ai/ability/PumpAllAi.java b/forge-ai/src/main/java/forge/ai/ability/PumpAllAi.java index d6fc76bad15..cb68ba3a711 100644 --- a/forge-ai/src/main/java/forge/ai/ability/PumpAllAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/PumpAllAi.java @@ -151,6 +151,12 @@ public class PumpAllAi extends PumpAiBase { return true; } + @Override + protected boolean doTriggerAINoCost(Player ai, SpellAbility sa, boolean mandatory) { + // important to call canPlay first so targets are added if needed + return canPlayAI(ai, sa) || mandatory; + } + boolean pumpAgainstRemoval(Player ai, SpellAbility sa, List comp) { final List objects = ComputerUtil.predictThreatenedObjects(sa.getActivatingPlayer(), sa, true); for (final Card c : comp) { diff --git a/forge-ai/src/main/java/forge/ai/ability/TapOrUntapAi.java b/forge-ai/src/main/java/forge/ai/ability/TapOrUntapAi.java index e1f7e5b90c0..e052b4737c9 100644 --- a/forge-ai/src/main/java/forge/ai/ability/TapOrUntapAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/TapOrUntapAi.java @@ -39,6 +39,4 @@ public class TapOrUntapAi extends TapAiBase { return randomReturn; } - - } diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbilityCondition.java b/forge-game/src/main/java/forge/game/spellability/SpellAbilityCondition.java index c52a7dca849..6439f786c3a 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbilityCondition.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbilityCondition.java @@ -244,7 +244,6 @@ public class SpellAbilityCondition extends SpellAbilityVariables { * @return a boolean. */ public final boolean areMet(final SpellAbility sa) { - Player activator = sa.getActivatingPlayer(); if (activator == null) { activator = sa.getHostCard().getController(); From 1af8cee7191e83844dfccef9f3ed408c98c20b7e Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Thu, 3 Jun 2021 10:39:50 +0200 Subject: [PATCH 3/6] Fix crash on payment with Channel --- .../forge/gamemodes/match/input/InputPayMana.java | 12 +++++++----- .../gamemodes/match/input/InputSyncronizedBase.java | 4 ++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayMana.java b/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayMana.java index 0fe7d9b1fd0..a913181585c 100644 --- a/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayMana.java +++ b/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayMana.java @@ -66,12 +66,14 @@ public abstract class InputPayMana extends InputSyncronizedBase { @Override protected void onStop() { - // Clear current Mana cost being paid for SA - saPaidFor.setManaCostBeingPaid(null); - player.popPaidForSA(); + if (!isFinished()) { + // Clear current Mana cost being paid for SA + saPaidFor.setManaCostBeingPaid(null); + player.popPaidForSA(); - if (wasFloatingMana) { //hide mana pool if it was shown due to floating mana - getController().getGui().hideManaPool(PlayerView.get(player)); + if (wasFloatingMana) { //hide mana pool if it was shown due to floating mana + getController().getGui().hideManaPool(PlayerView.get(player)); + } } } diff --git a/forge-gui/src/main/java/forge/gamemodes/match/input/InputSyncronizedBase.java b/forge-gui/src/main/java/forge/gamemodes/match/input/InputSyncronizedBase.java index df10c4fc797..54fe6a737a7 100644 --- a/forge-gui/src/main/java/forge/gamemodes/match/input/InputSyncronizedBase.java +++ b/forge-gui/src/main/java/forge/gamemodes/match/input/InputSyncronizedBase.java @@ -36,8 +36,6 @@ public abstract class InputSyncronizedBase extends InputBase implements InputSyn } protected final void stop() { - onStop(); - // ensure input won't accept any user actions. FThreads.invokeInEdtNowOrLater(new Runnable() { @Override @@ -46,6 +44,8 @@ public abstract class InputSyncronizedBase extends InputBase implements InputSyn } }); + onStop(); + // thread irrelevant if (getController().getInputQueue().getInput() != null) { getController().getInputQueue().removeInput(InputSyncronizedBase.this); From 08fd9b98c811d5450e26aa0b6159d831e56ab8f6 Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Thu, 3 Jun 2021 11:19:50 +0200 Subject: [PATCH 4/6] Fix missing sub --- forge-ai/src/main/java/forge/ai/ComputerUtilCard.java | 2 +- forge-gui/res/cardsfolder/d/draconic_intervention.txt | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java index 56e58d3474e..b710879376f 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java @@ -881,7 +881,7 @@ public class ComputerUtilCard { public boolean apply(Deck d) { for (Entry cp: d) { for (Entry e : cp.getValue()) { - if ( e.getKey().getRules().getAiHints().getRemAIDecks() ) + if (e.getKey().getRules().getAiHints().getRemAIDecks()) return false; } } diff --git a/forge-gui/res/cardsfolder/d/draconic_intervention.txt b/forge-gui/res/cardsfolder/d/draconic_intervention.txt index 3dc05503dfe..40146325017 100644 --- a/forge-gui/res/cardsfolder/d/draconic_intervention.txt +++ b/forge-gui/res/cardsfolder/d/draconic_intervention.txt @@ -2,6 +2,7 @@ Name:Draconic Intervention ManaCost:2 R R Types:Sorcery A:SP$ DamageAll | Cost$ 2 R R ExileFromGrave<1/Instant;Sorcery> | NumDmg$ X | ValidCards$ Creature.nonDragon | RememberDamaged$ True | ReplaceDyingDefined$ Remembered | SubAbility$ DBCleanup | SpellDescription$ CARDNAME deals X damage to each non-Dragon creature, where X is the exiled card’s mana value. If a creature dealt damage this way would die this turn, exile it instead. -SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | SubAbility$ DBChange +SVar:DBChange:DB$ ChangeZone | Origin$ Stack | Destination$ Exile SVar:X:Exiled$CardManaCost Oracle:As an additional cost to cast this spell, exile an instant or sorcery card from your graveyard.\nDraconic Intervention deals X damage to each non-Dragon creature, where X is the exiled card's mana value. If a creature dealt damage this way would die this turn, exile it instead.\nExile Draconic Intervention. From fc7540ed1e0d5607a99b9e67efc38900347e04ca Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Thu, 3 Jun 2021 11:52:37 +0200 Subject: [PATCH 5/6] Fix multiplayer rulings (count player who lost) --- forge-gui/res/cardsfolder/c/chandras_incinerator.txt | 2 +- forge-gui/res/cardsfolder/s/sygg_river_cutthroat.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/forge-gui/res/cardsfolder/c/chandras_incinerator.txt b/forge-gui/res/cardsfolder/c/chandras_incinerator.txt index 3b1b293a1d1..2b516889be5 100644 --- a/forge-gui/res/cardsfolder/c/chandras_incinerator.txt +++ b/forge-gui/res/cardsfolder/c/chandras_incinerator.txt @@ -3,7 +3,7 @@ ManaCost:5 R Types:Creature Elemental PT:6/6 S:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ X | EffectZone$ All | Description$ This spell costs {X} less to cast, where X is the total amount of noncombat damage dealt to your opponents this turn. -SVar:X:PlayerCountOpponents$NonCombatDamageDealtThisTurn +SVar:X:PlayerCountRegisteredOpponents$NonCombatDamageDealtThisTurn K:Trample T:Mode$ DamageDone | ValidSource$ Card.YouCtrl,Emblem.YouCtrl | ValidTarget$ Opponent | CombatDamage$ False | TriggerZones$ Battlefield | Execute$ TrigDmg | TriggerDescription$ Whenever a source you control deals noncombat damage to an opponent, CARDNAME deals that much damage to target creature or planeswalker that player controls. SVar:TrigDmg:DB$ DealDamage | ValidTgts$ Creature,Planeswalker | TgtPrompt$ Select target creature or planeswalker that player controls | TargetsWithDefinedController$ TriggeredTarget | NumDmg$ Y diff --git a/forge-gui/res/cardsfolder/s/sygg_river_cutthroat.txt b/forge-gui/res/cardsfolder/s/sygg_river_cutthroat.txt index eea2d2b4a34..e79b989a368 100644 --- a/forge-gui/res/cardsfolder/s/sygg_river_cutthroat.txt +++ b/forge-gui/res/cardsfolder/s/sygg_river_cutthroat.txt @@ -4,6 +4,6 @@ Types:Legendary Creature Merfolk Rogue PT:1/3 T:Mode$ Phase | Phase$ End of Turn | TriggerZones$ Battlefield | Execute$ TrigDraw | OptionalDecider$ You | CheckSVar$ X | SVarCompare$ GE3 | TriggerDescription$ At the beginning of each end step, if an opponent lost 3 or more life this turn, you may draw a card. (Damage causes loss of life.) SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ 1 -SVar:X:PlayerCountOpponents$HighestLifeLostThisTurn +SVar:X:PlayerCountRegisteredOpponents$HighestLifeLostThisTurn SVar:Picture:http://www.wizards.com/global/images/magic/general/sygg_river_cutthroat.jpg Oracle:At the beginning of each end step, if an opponent lost 3 or more life this turn, you may draw a card. (Damage causes loss of life.) From 069403ab6c3d2897c7452d113d23926b8d736ffd Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Thu, 3 Jun 2021 14:22:56 +0200 Subject: [PATCH 6/6] Clean up --- forge-core/src/main/java/forge/card/CardDb.java | 2 -- forge-gui/res/cardsfolder/m/mutiny.txt | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/forge-core/src/main/java/forge/card/CardDb.java b/forge-core/src/main/java/forge/card/CardDb.java index 99c8f5e47cc..366be7e81f8 100644 --- a/forge-core/src/main/java/forge/card/CardDb.java +++ b/forge-core/src/main/java/forge/card/CardDb.java @@ -772,7 +772,6 @@ public final class CardDb implements ICardDatabase, IDeckGenPool { } public PaperCard createUnsupportedCard(String cardName) { - CardRequest request = CardRequest.fromString(cardName); CardEdition cardEdition = CardEdition.UNKNOWN; CardRarity cardRarity = CardRarity.Unknown; @@ -813,7 +812,6 @@ public final class CardDb implements ICardDatabase, IDeckGenPool { } return new PaperCard(CardRules.getUnsupportedCardNamed(request.cardName), cardEdition.getCode(), cardRarity, 1); - } private final Editor editor = new Editor(); diff --git a/forge-gui/res/cardsfolder/m/mutiny.txt b/forge-gui/res/cardsfolder/m/mutiny.txt index 45ca72f5c1d..04501e24088 100644 --- a/forge-gui/res/cardsfolder/m/mutiny.txt +++ b/forge-gui/res/cardsfolder/m/mutiny.txt @@ -5,5 +5,5 @@ A:SP$ Pump | Cost$ R | ValidTgts$ Creature.OppCtrl | AILogic$ PowerDmg | TgtProm SVar:MutinyDamage:DB$ DealDamage | ValidTgts$ Creature.OppCtrl | TargetUnique$ True | AILogic$ PowerDmg | NumDmg$ X | DamageSource$ ParentTarget SVar:X:ParentTargeted$CardPower SVar:Picture:http://www.wizards.com/global/images/magic/general/mutiny.jpg -//Not perfect yet, there seems to be no check whether the creature's controller is the same? +//TODO Not perfect yet, there seems to be no check whether the creature's controller is the same? Oracle:Target creature an opponent controls deals damage equal to its power to another target creature that player controls. \ No newline at end of file