From 3b86f4f0c2484a442950bd50c0db0c0bc5f44c29 Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Thu, 14 Oct 2021 13:26:31 +0200 Subject: [PATCH] Fix NPE with Mount Velus Manticore --- forge-ai/src/main/java/forge/ai/ComputerUtil.java | 9 +++++++-- .../main/java/forge/ai/ability/BecomesBlockedAi.java | 2 +- .../src/main/java/forge/ai/ability/ControlGainAi.java | 2 +- forge-ai/src/main/java/forge/ai/ability/DebuffAi.java | 4 ++-- forge-ai/src/main/java/forge/ai/ability/ProtectAi.java | 6 +++--- forge-ai/src/main/java/forge/ai/ability/PumpAi.java | 8 ++++---- .../src/main/java/forge/ai/ability/TwoPilesAi.java | 2 +- forge-ai/src/main/java/forge/ai/ability/UntapAi.java | 5 ++--- .../src/main/java/forge/game/ability/AbilityUtils.java | 2 +- .../src/main/java/forge/screens/match/CMatchUI.java | 10 +++------- forge-gui/res/cardsfolder/s/snapcaster_mage.txt | 2 +- 11 files changed, 26 insertions(+), 26 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtil.java b/forge-ai/src/main/java/forge/ai/ComputerUtil.java index bd0c2704273..71c5754b2e3 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtil.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtil.java @@ -2239,7 +2239,7 @@ public class ComputerUtil { if (validString.contains("Creature") && !validString.contains("nonCreature")) { final Card c = ComputerUtilCard.getBestCreatureAI(goodChoices); if (c != null) { - dChoices.add(ComputerUtilCard.getBestCreatureAI(goodChoices)); + dChoices.add(c); } } } @@ -2764,7 +2764,8 @@ public class ComputerUtil { || (type.is(CounterEnumType.TIME) && (!c.isInPlay() || "Chronozoa".equals(c.getName()))) || type.is(CounterEnumType.GOLD) || type.is(CounterEnumType.MUSIC) || type.is(CounterEnumType.PUPA) || type.is(CounterEnumType.PARALYZATION) || type.is(CounterEnumType.SHELL) || type.is(CounterEnumType.SLEEP) - || type.is(CounterEnumType.SLUMBER) || type.is(CounterEnumType.SLEIGHT) || type.is(CounterEnumType.WAGE); + || type.is(CounterEnumType.SLUMBER) || type.is(CounterEnumType.SLEIGHT) || type.is(CounterEnumType.WAGE) + || type.is(CounterEnumType.INCARNATION) || type.is(CounterEnumType.RUST); } // this countertypes has no effect @@ -2892,6 +2893,8 @@ public class ComputerUtil { public static boolean targetPlayableSpellCard(final Player ai, CardCollection options, final SpellAbility sa, final boolean withoutPayingManaCost, boolean mandatory) { // determine and target a card with a SA that the AI can afford and will play AiController aic = ((PlayerControllerAi) ai.getController()).getAi(); + sa.resetTargets(); + CardCollection targets = new CardCollection(); for (Card c : options) { if (withoutPayingManaCost && c.getManaCost() != null && c.getManaCost().countX() > 0) { @@ -2917,6 +2920,7 @@ public class ComputerUtil { } } } + if (targets.isEmpty()) { if (mandatory && !options.isEmpty()) { targets = options; @@ -2924,6 +2928,7 @@ public class ComputerUtil { return false; } } + sa.getTargets().add(ComputerUtilCard.getBestAI(targets)); return true; } diff --git a/forge-ai/src/main/java/forge/ai/ability/BecomesBlockedAi.java b/forge-ai/src/main/java/forge/ai/ability/BecomesBlockedAi.java index 9efd36f9a44..076825e0846 100644 --- a/forge-ai/src/main/java/forge/ai/ability/BecomesBlockedAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/BecomesBlockedAi.java @@ -33,7 +33,7 @@ public class BecomesBlockedAi extends SpellAbilityAi { list = CardLists.getTargetableCards(list, sa); list = CardLists.getNotKeyword(list, Keyword.TRAMPLE); - while (sa.getTargets().size() < tgt.getMaxTargets(source, sa)) { + while (sa.canAddMoreTarget()) { Card choice = null; if (list.isEmpty()) { diff --git a/forge-ai/src/main/java/forge/ai/ability/ControlGainAi.java b/forge-ai/src/main/java/forge/ai/ability/ControlGainAi.java index 44bdaca5177..cd084ef06a3 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ControlGainAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ControlGainAi.java @@ -196,7 +196,7 @@ public class ControlGainAi extends SpellAbilityAi { } } - while (sa.getTargets().size() < tgt.getMaxTargets(sa.getHostCard(), sa)) { + while (sa.canAddMoreTarget()) { Card t = null; if (list.isEmpty()) { diff --git a/forge-ai/src/main/java/forge/ai/ability/DebuffAi.java b/forge-ai/src/main/java/forge/ai/ability/DebuffAi.java index f69d878d806..f151d99fdee 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DebuffAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DebuffAi.java @@ -136,7 +136,7 @@ public class DebuffAi extends SpellAbilityAi { return mandatory && debuffMandatoryTarget(ai, sa, mandatory); } - while (sa.getTargets().size() < tgt.getMaxTargets(sa.getHostCard(), sa)) { + while (sa.canAddMoreTarget()) { Card t = null; if (list.isEmpty()) { @@ -216,7 +216,7 @@ public class DebuffAi extends SpellAbilityAi { final CardCollection forced = CardLists.filterControlledBy(list, ai); final Card source = sa.getHostCard(); - while (sa.getTargets().size() < tgt.getMaxTargets(source, sa)) { + while (sa.canAddMoreTarget()) { if (pref.isEmpty()) { break; } diff --git a/forge-ai/src/main/java/forge/ai/ability/ProtectAi.java b/forge-ai/src/main/java/forge/ai/ability/ProtectAi.java index 95a6b387a28..5131ce1c3e9 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ProtectAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ProtectAi.java @@ -230,7 +230,7 @@ public class ProtectAi extends SpellAbilityAi { return mandatory && protectMandatoryTarget(ai, sa, mandatory); } - while (sa.getTargets().size() < tgt.getMaxTargets(source, sa)) { + while (sa.canAddMoreTarget()) { Card t = null; // boolean goodt = false; @@ -289,7 +289,7 @@ public class ProtectAi extends SpellAbilityAi { final List forced = CardLists.filterControlledBy(list, ai); final Card source = sa.getHostCard(); - while (sa.getTargets().size() < tgt.getMaxTargets(source, sa)) { + while (sa.canAddMoreTarget()) { if (pref.isEmpty()) { break; } @@ -306,7 +306,7 @@ public class ProtectAi extends SpellAbilityAi { sa.getTargets().add(c); } - while (sa.getTargets().size() < tgt.getMaxTargets(source, sa)) { + while (sa.canAddMoreTarget()) { if (pref2.isEmpty()) { break; } 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 57e5cd1142f..f5e0e4a3efe 100644 --- a/forge-ai/src/main/java/forge/ai/ability/PumpAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/PumpAi.java @@ -437,7 +437,7 @@ public class PumpAi extends PumpAiBase { && !(sa.isCurse() && defense < 0) && !containsNonCombatKeyword(keywords) && !"UntilYourNextTurn".equals(sa.getParam("Duration")) - && !"Snapcaster".equals(sa.getParam("AILogic")) + && !"ReplaySpell".equals(sa.getParam("AILogic")) && !isFight) { return false; } @@ -595,8 +595,8 @@ public class PumpAi extends PumpAiBase { }); } - if ("Snapcaster".equals(sa.getParam("AILogic"))) { - if (!ComputerUtil.targetPlayableSpellCard(ai, list, sa, false, false)) { + if ("ReplaySpell".equals(sa.getParam("AILogic"))) { + if (!ComputerUtil.targetPlayableSpellCard(ai, list, sa, false, mandatory)) { return false; } } @@ -662,7 +662,7 @@ public class PumpAi extends PumpAiBase { forced = CardLists.filterControlledBy(list, ai.getOpponents()); } - while (sa.getTargets().size() < tgt.getMaxTargets(source, sa)) { + while (sa.canAddMoreTarget()) { if (pref.isEmpty()) { break; } diff --git a/forge-ai/src/main/java/forge/ai/ability/TwoPilesAi.java b/forge-ai/src/main/java/forge/ai/ability/TwoPilesAi.java index fd55af81ab8..b0416572962 100644 --- a/forge-ai/src/main/java/forge/ai/ability/TwoPilesAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/TwoPilesAi.java @@ -34,7 +34,7 @@ public class TwoPilesAi extends SpellAbilityAi { final TargetRestrictions tgt = sa.getTargetRestrictions(); if (tgt != null) { sa.resetTargets(); - if (tgt.canTgtPlayer()) { + if (sa.canTarget(opp)) { sa.getTargets().add(opp); } } diff --git a/forge-ai/src/main/java/forge/ai/ability/UntapAi.java b/forge-ai/src/main/java/forge/ai/ability/UntapAi.java index 4bf6140e6ac..57de703793a 100644 --- a/forge-ai/src/main/java/forge/ai/ability/UntapAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/UntapAi.java @@ -239,8 +239,7 @@ public class UntapAi extends SpellAbilityAi { tgt.getValidTgts(), source.getController(), source, sa); list = CardLists.getTargetableCards(list, sa); - // filter by enchantments and planeswalkers, their tapped state doesn't - // matter. + // filter by enchantments and planeswalkers, their tapped state doesn't matter. final String[] tappablePermanents = { "Enchantment", "Planeswalker" }; CardCollection tapList = CardLists.getValidCards(list, tappablePermanents, source.getController(), source, sa); @@ -271,7 +270,7 @@ public class UntapAi extends SpellAbilityAi { return false; } - while (sa.getTargets().size() < tgt.getMaxTargets(source, sa)) { + while (sa.canAddMoreTarget()) { Card choice = null; if (tapList.isEmpty()) { diff --git a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java index bb3c46eaf00..ef26747b4a5 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -2040,7 +2040,7 @@ public class AbilityUtils { } else { ce = c; } - return doXMath(getNumberOfTypes(ce), expr, c, ctb); + return doXMath(ce == null ? 0 : getNumberOfTypes(ce), expr, c, ctb); } if (sq[0].contains("CardNumColors")) { diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java index e9b82968393..f56ced7e01d 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java @@ -401,8 +401,7 @@ public final class CMatchUI selectedDocBeforeCombat = combatDoc.getParentCell().getSelected(); if (selectedDocBeforeCombat != combatDoc) { SDisplayUtil.showTab(combatDoc); - } - else { + } else { selectedDocBeforeCombat = null; //don't need to cache combat doc this way } } @@ -744,8 +743,6 @@ public final class CMatchUI //else if (toFocus == btn1) //btn2.setFocusable(false); - - final Runnable focusRoutine = new Runnable() { @Override public final void run() { @@ -754,11 +751,11 @@ public final class CMatchUI // and then using the keyboard to try to select it btn1.setEnabled(enable1); btn2.setEnabled(enable2); - btn1.setFocusable(enable1 && focus1 ); + btn1.setFocusable(enable1 && focus1); btn2.setFocusable(enable2 && !focus1); // ensure we don't steal focus from an overlay if (toFocus != null && !FNetOverlay.SINGLETON_INSTANCE.getTxtInput().hasFocus() ) { - toFocus.requestFocus(); // focus here even if another window has focus - shouldn't have to do it this way but some popups grab window focus + toFocus.requestFocus(); // focus here even if another window has focus - shouldn't have to do it this way but some popups grab window focus } } }; @@ -1364,7 +1361,6 @@ public final class CMatchUI } // In any case, I have to increase the counter nextNotifiableStackIndex++; - } else { // Not yet time to show the modal - schedule the method again, and try again later Runnable tryAgainThread = new Runnable() { diff --git a/forge-gui/res/cardsfolder/s/snapcaster_mage.txt b/forge-gui/res/cardsfolder/s/snapcaster_mage.txt index 9cb18d33903..79a86292ac1 100644 --- a/forge-gui/res/cardsfolder/s/snapcaster_mage.txt +++ b/forge-gui/res/cardsfolder/s/snapcaster_mage.txt @@ -4,6 +4,6 @@ Types:Creature Human Wizard PT:2/1 K:Flash T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigRearrange | TriggerDescription$ When CARDNAME enters the battlefield, target instant or sorcery card in your graveyard gains flashback until end of turn. The flashback cost is equal to its mana cost. (You may cast that card from your graveyard for its flashback cost. Then exile it.) -SVar:TrigRearrange:DB$ Pump | ValidTgts$ Instant.YouCtrl,Sorcery.YouCtrl | TgtZone$ Graveyard | TgtPrompt$ Select target instant or sorcery card | KW$ Flashback | PumpZone$ Graveyard | AILogic$ Snapcaster +SVar:TrigRearrange:DB$ Pump | ValidTgts$ Instant.YouCtrl,Sorcery.YouCtrl | TgtZone$ Graveyard | TgtPrompt$ Select target instant or sorcery card | KW$ Flashback | PumpZone$ Graveyard | AILogic$ ReplaySpell SVar:Picture:http://www.wizards.com/global/images/magic/general/snapcaster_mage.jpg Oracle:Flash\nWhen Snapcaster Mage enters the battlefield, target instant or sorcery card in your graveyard gains flashback until end of turn. The flashback cost is equal to its mana cost. (You may cast that card from your graveyard for its flashback cost. Then exile it.)