From 001106ea7bdcebbb919f82b8e4222273967f6789 Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Tue, 15 Jun 2021 16:36:33 +0200 Subject: [PATCH 1/7] Small fixes --- forge-ai/src/main/java/forge/ai/ability/SkipTurnAi.java | 1 - .../src/main/java/forge/game/ability/AbilityUtils.java | 1 - .../java/forge/game/ability/effects/ChangeZoneEffect.java | 3 +-- forge-game/src/main/java/forge/game/card/CardUtil.java | 2 +- forge-game/src/main/java/forge/game/cost/CostPartMana.java | 2 -- forge-gui/res/cardsfolder/c/crypt_champion.txt | 2 +- forge-gui/res/cardsfolder/e/exhume.txt | 2 +- forge-gui/res/cardsfolder/i/infernal_offering.txt | 4 ++-- forge-gui/res/cardsfolder/p/plane_merge_elf.txt | 2 +- forge-gui/res/cardsfolder/s/sigil_captain.txt | 5 ++--- .../main/java/forge/gamemodes/match/input/InputPayMana.java | 2 +- .../gamemodes/match/input/InputPayManaOfCostPayment.java | 1 - 12 files changed, 10 insertions(+), 17 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ability/SkipTurnAi.java b/forge-ai/src/main/java/forge/ai/ability/SkipTurnAi.java index 14cae9165fc..fb7f3415e1a 100644 --- a/forge-ai/src/main/java/forge/ai/ability/SkipTurnAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/SkipTurnAi.java @@ -1,6 +1,5 @@ package forge.ai.ability; - import forge.ai.SpellAbilityAi; import forge.game.player.Player; import forge.game.spellability.SpellAbility; 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 dc6ad094dd8..cfe291cb69d 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -2731,7 +2731,6 @@ public class AbilityUtils { return doXMath(powers.size(), expr, c, ctb); } - if (sq[0].startsWith("MostProminentCreatureType")) { String restriction = l[0].split(" ")[1]; CardCollection list = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), restriction, player, c, ctb); diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java index 5e903cfbc13..5ed22a22f26 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChangeZoneEffect.java @@ -291,7 +291,6 @@ public class ChangeZoneEffect extends SpellAbilityEffect { * @return a {@link java.lang.String} object. */ private static String changeKnownOriginStackDescription(final SpellAbility sa) { - final StringBuilder sb = new StringBuilder(); final Card host = sa.getHostCard(); @@ -1047,7 +1046,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect { // only multi-select if player can select more than one if (changeNum > 1 && allowMultiSelect(decider, sa)) { List selectedCards; - if (! sa.hasParam("SelectPrompt")) { + if (!sa.hasParam("SelectPrompt")) { // new default messaging for multi select if (fetchList.size() > changeNum) { //Select up to %changeNum cards from %players %origin diff --git a/forge-game/src/main/java/forge/game/card/CardUtil.java b/forge-game/src/main/java/forge/game/card/CardUtil.java index f6181cdf596..6c00b9158a7 100644 --- a/forge-game/src/main/java/forge/game/card/CardUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardUtil.java @@ -275,7 +275,7 @@ public final class CardUtil { newCopy.addRemembered(in.getRemembered()); newCopy.addImprintedCards(in.getImprintedCards()); - for(Table.Cell cl : in.getEtbCounters()) { + for (Table.Cell cl : in.getEtbCounters()) { newCopy.addEtbCounter(cl.getColumnKey(), cl.getValue(), cl.getRowKey()); } diff --git a/forge-game/src/main/java/forge/game/cost/CostPartMana.java b/forge-game/src/main/java/forge/game/cost/CostPartMana.java index cdc958d7962..19d7d609d93 100644 --- a/forge-game/src/main/java/forge/game/cost/CostPartMana.java +++ b/forge-game/src/main/java/forge/game/cost/CostPartMana.java @@ -112,13 +112,11 @@ public class CostPartMana extends CostPart { @Override public boolean isUndoable() { return true; } - @Override public final String toString() { return cost.toString(); } - @Override public final boolean canPay(final SpellAbility ability, final Player payer) { // For now, this will always return true. But this should probably be diff --git a/forge-gui/res/cardsfolder/c/crypt_champion.txt b/forge-gui/res/cardsfolder/c/crypt_champion.txt index 27812dbc796..67ce5c9e9de 100644 --- a/forge-gui/res/cardsfolder/c/crypt_champion.txt +++ b/forge-gui/res/cardsfolder/c/crypt_champion.txt @@ -6,7 +6,7 @@ K:Double Strike T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigChangeZone | TriggerDescription$ When CARDNAME enters the battlefield, each player puts a creature card with mana value 3 or less from their graveyard onto the battlefield. T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigSac | ManaNotSpent$ R | TriggerDescription$ When CARDNAME enters the battlefield, sacrifice it unless {R} was spent to cast it. SVar:TrigChangeZone:DB$ RepeatEach | RepeatPlayers$ Player | RepeatSubAbility$ DBChangeZone -SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.RememberedPlayerCtrl+cmcLE3 | ChangeNum$ 1 | Hidden$ True | DefinedPlayer$ Player.IsRemembered | Chooser$ Player.IsRemembered +SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.RememberedPlayerCtrl+cmcLE3 | ChangeNum$ 1 | Hidden$ True | DefinedPlayer$ Player.IsRemembered | Chooser$ Player.IsRemembered | Mandatory$ True SVar:TrigSac:DB$ Sacrifice | Defined$ Self SVar:ManaNeededToAvoidNegativeEffect:red SVar:Picture:http://www.wizards.com/global/images/magic/general/crypt_champion.jpg diff --git a/forge-gui/res/cardsfolder/e/exhume.txt b/forge-gui/res/cardsfolder/e/exhume.txt index 1cb43db32b8..eb8a9202200 100644 --- a/forge-gui/res/cardsfolder/e/exhume.txt +++ b/forge-gui/res/cardsfolder/e/exhume.txt @@ -2,7 +2,7 @@ Name:Exhume ManaCost:1 B Types:Sorcery A:SP$ RepeatEach | Cost$ 1 B | RepeatSubAbility$ DBChangeZone | RepeatPlayers$ Player | SpellDescription$ Each player puts a creature card from their graveyard onto the battlefield. -SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.RememberedPlayerCtrl | DefinedPlayer$ Player.IsRemembered | Chooser$ Player.IsRemembered | ChangeNum$ 1 | Hidden$ True +SVar:DBChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.RememberedPlayerCtrl | DefinedPlayer$ Player.IsRemembered | Chooser$ Player.IsRemembered | ChangeNum$ 1 | Hidden$ True | Mandatory$ True SVar:X:Count$TypeInYourYard.Creature SVar:NeedsToPlayVar:X GE1 SVar:Picture:http://www.wizards.com/global/images/magic/general/exhume.jpg diff --git a/forge-gui/res/cardsfolder/i/infernal_offering.txt b/forge-gui/res/cardsfolder/i/infernal_offering.txt index 39090272fda..40f9f46daad 100644 --- a/forge-gui/res/cardsfolder/i/infernal_offering.txt +++ b/forge-gui/res/cardsfolder/i/infernal_offering.txt @@ -7,8 +7,8 @@ SVar:DBRepeat:DB$ RepeatEach | RepeatPlayers$ ChosenAndYou | RepeatSubAbility$ D SVar:DBDraw:DB$ Draw | Defined$ Player.IsRemembered | NumCards$ 2 | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 SVar:X:RememberedLKI$Valid Creature.RememberedPlayerCtrl SVar:DBChoose:DB$ ChoosePlayer | Defined$ You | Choices$ Player.Opponent | SubAbility$ DBReturnYou -SVar:DBReturnYou:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.YouCtrl | ChangeNum$ 1 | Hidden$ True | SubAbility$ DBReturnOpp -SVar:DBReturnOpp:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.ChosenCtrl | DefinedPlayer$ ChosenPlayer | Chooser$ ChosenPlayer | ChangeNum$ 1 | Hidden$ True | SubAbility$ DBCleanup +SVar:DBReturnYou:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.YouCtrl | ChangeNum$ 1 | Hidden$ True | Mandatory$ True | SubAbility$ DBReturnOpp +SVar:DBReturnOpp:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Creature.ChosenCtrl | DefinedPlayer$ ChosenPlayer | Chooser$ ChosenPlayer | ChangeNum$ 1 | Hidden$ True | Mandatory$ True | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True AI:RemoveDeck:All AI:RemoveDeck:Random diff --git a/forge-gui/res/cardsfolder/p/plane_merge_elf.txt b/forge-gui/res/cardsfolder/p/plane_merge_elf.txt index d9fe2eecb7b..d2ce1b63b8e 100644 --- a/forge-gui/res/cardsfolder/p/plane_merge_elf.txt +++ b/forge-gui/res/cardsfolder/p/plane_merge_elf.txt @@ -6,7 +6,7 @@ T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | Execute$ TrigLandship | Trigg SVar:TrigLandship:DB$ PeekAndReveal | PeekAmount$ 1 | RevealValid$ Land | RevealOptional$ True | RememberRevealed$ True | SubAbility$ DBToken SVar:DBToken:DB$ Token | TokenScript$ g_1_1_elf_warrior | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ1 | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True -T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.sharesCreatureTypeWith | TriggerZones$ Battlefield | Execute$ TrigPumpAll | TriggerDescription$ Kinfall — Whenever a creature enters the battlefield under your control, if it shares a creature type with Plane-Merge Elf, creatures you control get +1/+1 until end of turn. +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.YouCtrl+sharesCreatureTypeWith | TriggerZones$ Battlefield | Execute$ TrigPumpAll | TriggerDescription$ Kinfall — Whenever a creature enters the battlefield under your control, if it shares a creature type with Plane-Merge Elf, creatures you control get +1/+1 until end of turn. SVar:TrigPumpAll:DB$ PumpAll | ValidCards$ Creature.YouCtrl | NumAtt$ +1 | NumDef$ +1 | ConditionDefined$ TriggeredCard | ConditionPresent$ Card.sharesCreatureTypeWith DeckHas:Ability$Token Oracle:Landship — At the beginning of your upkeep, you may look at the top card of your library. If it's a land, you may reveal it. If you do, create a 1/1 green Elf Warrior creature token.\nKinfall — Whenever a creature enters the battlefield under your control, if it shares a creature type with Plane-Merge Elf, creatures you control get +1/+1 until end of turn. diff --git a/forge-gui/res/cardsfolder/s/sigil_captain.txt b/forge-gui/res/cardsfolder/s/sigil_captain.txt index 549ad5bdc45..130aa522cc8 100644 --- a/forge-gui/res/cardsfolder/s/sigil_captain.txt +++ b/forge-gui/res/cardsfolder/s/sigil_captain.txt @@ -2,7 +2,6 @@ Name:Sigil Captain ManaCost:1 G W W Types:Creature Rhino Soldier PT:3/3 -T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.powerEQ1+toughnessEQ1+Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Whenever a creature enters the battlefield under your control, if that creature is 1/1, put two +1/+1 counters on it. -SVar:TrigPutCounter:DB$ PutCounter | Defined$ TriggeredCardLKICopy | CounterType$ P1P1 | CounterNum$ 2 -SVar:Picture:http://www.wizards.com/global/images/magic/general/sigil_captain.jpg +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.powerEQ1+toughnessEQ1+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Whenever a creature enters the battlefield under your control, if that creature is 1/1, put two +1/+1 counters on it. +SVar:TrigPutCounter:DB$ PutCounter | Defined$ TriggeredCardLKICopy | CounterType$ P1P1 | CounterNum$ 2 | ConditionDefined$ TriggeredCard | ConditionPresent$ Card.powerEQ1+toughnessEQ1 Oracle:Whenever a creature enters the battlefield under your control, if that creature is 1/1, put two +1/+1 counters on it. 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 a913181585c..68f3d28c69d 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 @@ -271,7 +271,7 @@ public abstract class InputPayMana extends InputSyncronizedBase { } // Store some information about color costs to help with any mana choices - if (colorNeeded == 0) { // only colorless left + if (colorNeeded == 0) { // only colorless left if (saPaidFor.getHostCard() != null && saPaidFor.getHostCard().hasSVar("ManaNeededToAvoidNegativeEffect")) { String[] negEffects = saPaidFor.getHostCard().getSVar("ManaNeededToAvoidNegativeEffect").split(","); for (String negColor : negEffects) { diff --git a/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayManaOfCostPayment.java b/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayManaOfCostPayment.java index dceeebe121c..7b84fe7df0b 100644 --- a/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayManaOfCostPayment.java +++ b/forge-gui/src/main/java/forge/gamemodes/match/input/InputPayManaOfCostPayment.java @@ -72,7 +72,6 @@ public class InputPayManaOfCostPayment extends InputPayMana { msg.append(messagePrefix).append("\n"); } if (FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_DETAILED_SPELLDESC_IN_PROMPT)) { - // msg.append(saPaidFor.getStackDescription().replace("(Targeting ERROR)", "")); if (saPaidFor.isSpell()) { msg.append(saPaidFor.getStackDescription().replace("(Targeting ERROR)", "")).append("\n\n"); } else { From f584c581d8216d5fb5572a2691fa86e9569d0270 Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Tue, 15 Jun 2021 16:46:22 +0200 Subject: [PATCH 2/7] Improve AI hint --- forge-gui/res/cardsfolder/k/kindred_summons.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/forge-gui/res/cardsfolder/k/kindred_summons.txt b/forge-gui/res/cardsfolder/k/kindred_summons.txt index 66d52cd0549..826d15be225 100644 --- a/forge-gui/res/cardsfolder/k/kindred_summons.txt +++ b/forge-gui/res/cardsfolder/k/kindred_summons.txt @@ -6,7 +6,6 @@ SVar:DBDigUntil:DB$ DigUntil | Amount$ X | ConditionCheckSVar$ X | ConditionSVar SVar:DBShuffle:DB$ Shuffle | Defined$ You SVar:X:Count$Valid Creature.ChosenType+YouCtrl AI:RemoveDeck:Random -#TODO: This could benefit from something like "Creature.YouCtrl+sharesCreatureTypeWithAnotherCreature" (doesn't exist in code yet) -SVar:NeedsToPlay:Creature.YouCtrl+inZoneBattlefield -SVar:Picture:http://www.wizards.com/global/images/magic/general/kindred_summons.jpg +SVar:NeedsToPlayVar:MaxTypes GE2 +SVar:MaxTypes:Count$MostProminentCreatureType Creature.YouCtrl Oracle:Choose a creature type. Reveal cards from the top of your library until you reveal X creature cards of the chosen type, where X is the number of creatures you control of that type. Put those cards onto the battlefield, then shuffle the rest of the revealed cards into your library. From 93d80b3ee54588e8fe54d2acc987373d61a7656c Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Tue, 15 Jun 2021 17:01:59 +0200 Subject: [PATCH 3/7] Basic SkipPhase AI --- .../main/java/forge/ai/ability/ControlGainAi.java | 1 - .../main/java/forge/ai/ability/SkipPhaseAi.java | 14 +++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) 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 5358f6e670d..bbe277b07f0 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ControlGainAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ControlGainAi.java @@ -68,7 +68,6 @@ import forge.util.Aggregates; public class ControlGainAi extends SpellAbilityAi { @Override protected boolean canPlayAI(final Player ai, final SpellAbility sa) { - final List lose = Lists.newArrayList(); if (sa.hasParam("LoseControl")) { diff --git a/forge-ai/src/main/java/forge/ai/ability/SkipPhaseAi.java b/forge-ai/src/main/java/forge/ai/ability/SkipPhaseAi.java index d72eedd0249..c3dea810f1e 100644 --- a/forge-ai/src/main/java/forge/ai/ability/SkipPhaseAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/SkipPhaseAi.java @@ -1,5 +1,6 @@ package forge.ai.ability; +import forge.ai.AiAttackController; import forge.ai.SpellAbilityAi; import forge.game.player.Player; import forge.game.player.PlayerActionConfirmMode; @@ -8,12 +9,23 @@ import forge.game.spellability.SpellAbility; public class SkipPhaseAi extends SpellAbilityAi { @Override protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) { + if (sa.usesTargeting()) { + final Player opp = AiAttackController.choosePreferredDefenderPlayer(aiPlayer); + if (sa.canTarget(opp)) { + sa.resetTargets(); + sa.getTargets().add(opp); + } + else { + return false; + } + } + return true; } @Override protected boolean doTriggerAINoCost(Player aiPlayer, SpellAbility sa, boolean mandatory) { - return mandatory || canPlayAI(aiPlayer, sa); + return canPlayAI(aiPlayer, sa) || mandatory; } @Override From 9dada96de3ecb4f3e753bd25678831bf0b693179 Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Tue, 15 Jun 2021 17:25:00 +0200 Subject: [PATCH 4/7] Clean up --- forge-gui/res/cardsfolder/m/martyrs_cause.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forge-gui/res/cardsfolder/m/martyrs_cause.txt b/forge-gui/res/cardsfolder/m/martyrs_cause.txt index 0252267dcc1..0e6479ff3e0 100644 --- a/forge-gui/res/cardsfolder/m/martyrs_cause.txt +++ b/forge-gui/res/cardsfolder/m/martyrs_cause.txt @@ -4,7 +4,7 @@ Types:Enchantment A:AB$ ChooseSource | Cost$ Sac<1/Creature> | Choices$ Card,Emblem | AILogic$ NeedsPrevention | SubAbility$ DBEffect | SpellDescription$ The next time a source of your choice would deal damage to any target this turn, prevent that damage. SVar:DBEffect:DB$ Effect | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target to prevent damage to | Triggers$ OutOfSight | ReplacementEffects$ RPreventNextFromSource | RememberObjects$ Targeted | SubAbility$ DBCleanup | ConditionDefined$ ChosenCard | ConditionPresent$ Card,Emblem | ConditionCompare$ GE1 SVar:OutOfSight:Mode$ ChangesZone | TriggerZones$ Command | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.IsRemembered | Execute$ ExileEffect | Static$ True -SVar:RPreventNextFromSource:Event$ DamageDone | ValidSource$ Card.ChosenCard,Emblem.ChosenCard | ValidTarget$ Card.IsRemembered,Player.IsRemembered | ReplaceWith$ ExileEffect | PreventionEffect$ True | Description$ The next time the chosen source deals damage to the any target, prevent that damage. +SVar:RPreventNextFromSource:Event$ DamageDone | ValidSource$ Card.ChosenCard,Emblem.ChosenCard | ValidTarget$ Card.IsRemembered,Player.IsRemembered | ReplaceWith$ ExileEffect | PreventionEffect$ True | Description$ The next time the chosen source deals damage to the target, prevent that damage. SVar:ExileEffect:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True AI:RemoveDeck:All From b1b06dd0f42ef9e571863bd87ffa291be2ffa8d7 Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Tue, 15 Jun 2021 17:41:02 +0200 Subject: [PATCH 5/7] Fix Reflect --- .../forge/game/ability/effects/ImmediateTriggerEffect.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/forge-game/src/main/java/forge/game/ability/effects/ImmediateTriggerEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ImmediateTriggerEffect.java index fa30bbe8fe8..16d97edd34d 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ImmediateTriggerEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ImmediateTriggerEffect.java @@ -58,8 +58,8 @@ public class ImmediateTriggerEffect extends SpellAbilityEffect { Card lki = CardUtil.getLKICopy(gameCard); lki.clearControllers(); lki.setOwner(sa.getActivatingPlayer()); - // if this trigger is part of ETBReplacement it shouldn't run with LKI from incomplete zone change (Wall of Stolen Identity) - final Card trigHost = sa.getRootAbility().getReplacementEffect() != null && sa.getRootAbility().getReplacementEffect().getMode().equals(ReplacementType.Moved) ? gameCard : lki; + // if this trigger is part of ETBReplacement it shouldn't run with LKI from incomplete zone change (Mimic Vat + Wall of Stolen Identity) + final Card trigHost = sa.getRootAbility().getReplacementEffect() != null && sa.getRootAbility().getReplacementEffect().getMode().equals(ReplacementType.Moved) && gameCard.getZone() == null ? gameCard : lki; final Trigger immediateTrig = TriggerHandler.parseTrigger(mapParams, trigHost, sa.isIntrinsic(), null); immediateTrig.setSpawningAbility(sa.copy(lki, sa.getActivatingPlayer(), true)); From 9697d697bda688006300c1303cb841d7266701aa Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Tue, 15 Jun 2021 18:09:12 +0200 Subject: [PATCH 6/7] Multiplayer improvements --- .../java/forge/ai/ability/DamageDealAi.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java b/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java index 8c2df450d8b..1a8bbc4de42 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java @@ -39,6 +39,7 @@ import forge.game.keyword.Keyword; import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseType; import forge.game.player.Player; +import forge.game.player.PlayerCollection; import forge.game.spellability.AbilitySub; import forge.game.spellability.SpellAbility; import forge.game.spellability.TargetChoices; @@ -844,7 +845,7 @@ public class DamageDealAi extends DamageAiBase { // this is for Triggered targets that are mandatory final boolean noPrevention = sa.hasParam("NoPrevention"); final boolean divided = sa.isDividedAsYouChoose(); - final Player opp = ai.getWeakestOpponent(); + PlayerCollection opps = ai.getOpponents(); while (sa.canAddMoreTarget()) { if (tgt.canTgtPlaneswalker()) { @@ -872,13 +873,17 @@ public class DamageDealAi extends DamageAiBase { } } - if (sa.canTarget(opp)) { - if (sa.getTargets().add(opp)) { - if (divided) { - sa.addDividedAllocation(opp, dmg); - break; + if (!opps.isEmpty()) { + Player opp = opps.getFirst(); + opps.remove(opp); + if (sa.canTarget(opp)) { + if (sa.getTargets().add(opp)) { + if (divided) { + sa.addDividedAllocation(opp, dmg); + break; + } + continue; } - continue; } } From b3fe2a55db7a0b212ed0bca7ca0f86d9fd0cb20d Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Tue, 15 Jun 2021 18:15:16 +0200 Subject: [PATCH 7/7] Improve AI --- .../java/forge/ai/ability/SkipPhaseAi.java | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ability/SkipPhaseAi.java b/forge-ai/src/main/java/forge/ai/ability/SkipPhaseAi.java index c3dea810f1e..608e91a3f82 100644 --- a/forge-ai/src/main/java/forge/ai/ability/SkipPhaseAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/SkipPhaseAi.java @@ -9,27 +9,33 @@ import forge.game.spellability.SpellAbility; public class SkipPhaseAi extends SpellAbilityAi { @Override protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) { - if (sa.usesTargeting()) { - final Player opp = AiAttackController.choosePreferredDefenderPlayer(aiPlayer); - if (sa.canTarget(opp)) { - sa.resetTargets(); - sa.getTargets().add(opp); - } - else { - return false; - } - } - - return true; + return targetPlayer(aiPlayer, sa, false); } @Override protected boolean doTriggerAINoCost(Player aiPlayer, SpellAbility sa, boolean mandatory) { - return canPlayAI(aiPlayer, sa) || mandatory; + return targetPlayer(aiPlayer, sa, mandatory); } @Override public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) { return true; } + + public boolean targetPlayer(Player ai, SpellAbility sa, boolean mandatory) { + if (sa.usesTargeting()) { + final Player opp = AiAttackController.choosePreferredDefenderPlayer(ai); + sa.resetTargets(); + if (sa.canTarget(opp)) { + sa.getTargets().add(opp); + } + else if (mandatory && sa.canTarget(ai)) { + sa.getTargets().add(ai); + } + else { + return false; + } + } + return true; + } }