Merge branch 'miscfix' into 'master'

ControlGain Lose fix

See merge request core-developers/forge!6379
This commit is contained in:
Michael Kamensky
2022-03-11 10:28:32 +00:00
25 changed files with 53 additions and 29 deletions

View File

@@ -890,7 +890,7 @@ public class AiBlockController {
CardCollection pwsWithChumpBlocks = new CardCollection();
CardCollection chosenChumpBlockers = new CardCollection();
CardCollection chumpPWDefenders = CardLists.filter(new CardCollection(this.blockersLeft), new Predicate<Card>() {
CardCollection chumpPWDefenders = CardLists.filter(this.blockersLeft, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return ComputerUtilCard.evaluateCreature(card) <= (card.isToken() ? evalThresholdToken

View File

@@ -1187,7 +1187,7 @@ public class AiController {
if ("DiscardUncastableAndExcess".equals(sa.getParam("AILogic"))) {
CardCollection discards = new CardCollection();
final CardCollectionView inHand = player.getCardsIn(ZoneType.Hand);
final int numLandsOTB = CardLists.count(player.getCardsIn(ZoneType.Hand), CardPredicates.Presets.LANDS);
final int numLandsOTB = CardLists.count(inHand, CardPredicates.Presets.LANDS);
int numOppInHand = 0;
for (Player p : player.getGame().getPlayers()) {
if (p.getCardsIn(ZoneType.Hand).size() > numOppInHand) {

View File

@@ -106,8 +106,7 @@ public class ChangeZoneAllAi extends SpellAbilityAi {
}
return false;
} else if ("ManifestCreatsFromGraveyard".equals(sa.getParam("AILogic"))) {
PlayerCollection players = new PlayerCollection();
players.addAll(ai.getOpponents());
PlayerCollection players = ai.getOpponents();
players.add(ai);
int maxSize = 1;
for (Player player : players) {

View File

@@ -142,6 +142,10 @@ public class ControlGainAi extends SpellAbilityAi {
return true;
}
if (c.canBeControlledBy(ai)) {
return false;
}
// do not take perm control on something that leaves the play end of turn
if (!lose.contains("EOT") && c.hasSVar("EndOfTurnLeavePlay")) {
return false;

View File

@@ -747,7 +747,7 @@ public class CountersPutAi extends CountersAi {
if (!sa.usesTargeting()) {
// No target. So must be defined
list = new CardCollection(AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa));
list = AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa);
if (amountStr.equals("X")
&& root.getXManaCostPaid() != null /* SubAbility on something that already had set PayX, e.g. Endless One ETB counters */
@@ -988,6 +988,9 @@ public class CountersPutAi extends CountersAi {
if (!negative.isEmpty()) {
return ComputerUtilCard.getBestAI(negative);
}
if (!isOptional) {
return ComputerUtilCard.getBestAI(opponents);
}
}
}

View File

@@ -99,6 +99,12 @@ public class RearrangeTopOfLibraryAi extends SpellAbilityAi {
PlayerCollection pc = sa.usesTargeting() ? new PlayerCollection(sa.getTargets().getTargetPlayers())
: AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam("Defined"), sa);
Player p = pc.getFirst(); // currently always a single target spell
Card top = p.getCardsIn(ZoneType.Library).isEmpty() ? null : p.getCardsIn(ZoneType.Library).getFirst();
if (top == null) {
return false;
}
int uncastableCMCThreshold = 2;
int minLandsToScryLandsAway = 4;
if (player.getController().isAI()) {
@@ -107,8 +113,6 @@ public class RearrangeTopOfLibraryAi extends SpellAbilityAi {
uncastableCMCThreshold = aic.getIntProperty(AiProps.SCRY_IMMEDIATELY_UNCASTABLE_CMC_DIFF);
}
Player p = pc.getFirst(); // currently always a single target spell
Card top = p.getCardsIn(ZoneType.Library).getFirst();
int landsOTB = CardLists.count(p.getCardsIn(ZoneType.Battlefield), CardPredicates.Presets.LANDS_PRODUCING_MANA);
int cmc = top.isSplitCard() ? Math.min(top.getCMC(Card.SplitCMCMode.LeftSplitCMC), top.getCMC(Card.SplitCMCMode.RightSplitCMC))
: top.getCMC();

View File

@@ -1519,7 +1519,7 @@ public class GameAction {
}
if (c.hasCardAttachments()) {
for (final Card attach : Lists.newArrayList(c.getAttachedCards())) {
for (final Card attach : c.getAttachedCards()) {
if (!attach.isInPlay()) {
unAttachList.add(attach);
checkAgain = true;

View File

@@ -33,6 +33,9 @@ public class AnimateEffect extends AnimateEffectBase {
&& !source.isInPlay()) {
return;
}
if ("UntilLoseControlOfHost".equals(sa.getParam("Duration")) && source.getController() != sa.getActivatingPlayer()) {
return;
}
// Remember Objects
if (sa.hasParam("RememberObjects")) {

View File

@@ -574,13 +574,15 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
gameCard.addEtbCounter(cType, cAmount, player);
}
if (sa.hasParam("GainControl")) {
Player newController = player;
if (sa.hasParam("NewController")) {
final Player p = Iterables.getFirst(AbilityUtils.getDefinedPlayers(hostCard, sa.getParam("NewController"), sa), null);
if (p != null) {
gameCard.setController(p, game.getNextTimestamp());
newController = Iterables.getFirst(AbilityUtils.getDefinedPlayers(hostCard, sa.getParam("NewController"), sa), null);
}
if (newController != null) {
if (newController != gameCard.getController()) {
gameCard.runChangeControllerCommands();
}
} else {
gameCard.setController(player, game.getNextTimestamp());
gameCard.setController(newController, game.getNextTimestamp());
}
}
if (sa.hasParam("AttachedTo")) {
@@ -959,7 +961,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
boolean shuffleMandatory = true;
boolean searchedLibrary = false;
if (defined) {
fetchList = new CardCollection(AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa));
fetchList = AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa);
if (!sa.hasParam("ChangeNum")) {
changeNum = fetchList.size();
}
@@ -1239,6 +1241,9 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
if (sa.hasParam("NewController")) {
newController = AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam("NewController"), sa).get(0);
}
if (newController != c.getController()) {
c.runChangeControllerCommands();
}
c.setController(newController, game.getNextTimestamp());
}

View File

@@ -130,6 +130,9 @@ public class ControlGainEffect extends SpellAbilityEffect {
if (lose != null && lose.contains("LeavesPlay") && !source.isInPlay()) {
return;
}
if (lose != null && lose.contains("LoseControl") && source.getController() != sa.getActivatingPlayer()) {
return;
}
if (lose != null && lose.contains("Untap") && !source.isTapped()) {
return;
}

View File

@@ -58,6 +58,15 @@ public class EffectEffect extends SpellAbilityEffect {
String noteCounterDefined = null;
List<Player> effectOwner = null;
boolean imprintOnHost = false;
final String duration = sa.getParam("Duration");
if (("UntilHostLeavesPlay".equals(duration) || "UntilLoseControlOfHost".equals(duration))
&& !hostCard.isInPlay()) {
return;
}
if ("UntilLoseControlOfHost".equals(duration) && hostCard.getController() != sa.getActivatingPlayer()) {
return;
}
if (sa.hasParam("Abilities")) {
effectAbilities = sa.getParam("Abilities").split(",");
@@ -275,7 +284,6 @@ public class EffectEffect extends SpellAbilityEffect {
}
// Duration
final String duration = sa.getParam("Duration");
if (duration == null || !duration.equals("Permanent")) {
final GameCommand endEffect = new GameCommand() {
private static final long serialVersionUID = -5861759814760561373L;

View File

@@ -69,7 +69,7 @@ public class MultiplePilesEffect extends SpellAbilityEffect {
if ((tgt == null) || p.canBeTargetedBy(sa)) {
CardCollection pool;
if (sa.hasParam("DefinedCards")) {
pool = new CardCollection(AbilityUtils.getDefinedCards(source, sa.getParam("DefinedCards"), sa));
pool = AbilityUtils.getDefinedCards(source, sa.getParam("DefinedCards"), sa);
} else {
pool = new CardCollection(p.getCardsIn(zone));
}

View File

@@ -43,6 +43,9 @@ public class PumpEffect extends SpellAbilityEffect {
&& !(host.isInPlay() || host.isInZone(ZoneType.Stack))) {
return;
}
if ("UntilLoseControlOfHost".equals(sa.getParam("Duration")) && host.getController() != sa.getActivatingPlayer()) {
return;
}
// do Game Check there in case of LKI
final Card gameCard = game.getCardState(applyTo, null);

View File

@@ -19,5 +19,4 @@ Types:Legendary Creature Spirit
PT:4/3
K:Trample
A:AB$ Pump | Cost$ SubCounter<1/KI> | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ 2 | NumDef$ 2 | SpellDescription$ Target creature gets +2/+2 until end of turn.
# This link may be a temporary solution and could change in the near future.
Oracle:Trample\nRemove a ki counter from Ichiga, Who Topples Oaks: Target creature gets +2/+2 until end of turn.

View File

@@ -18,5 +18,4 @@ Colors:blue
Types:Legendary Creature Spirit
PT:3/4
A:AB$ Counter | Cost$ SubCounter<1/KI> | TargetType$ Spell | ValidTgts$ Card | TgtPrompt$ Select target spell. | Destination$ Graveyard | UnlessCost$ 2 | UnlessPayer$ TargetedController | SpellDescription$ Counter target spell unless its controller pays 2.
# This link may be a temporary solution and could change in the near future.
Oracle:Remove a ki counter from Jaraku the Interloper: Counter target spell unless its controller pays {2}.

View File

@@ -18,5 +18,4 @@ Colors:red
Types:Legendary Creature Spirit
PT:5/2
A:AB$ GainControl | Cost$ SubCounter<1/KI> | ValidTgts$ Creature | TgtPrompt$ Select target creature | LoseControl$ EOT | SpellDescription$ Gain control of target creature until end of turn.
# This link may be a temporary solution and could change in the near future.
Oracle:Remove a ki counter from Azamuki, Treachery Incarnate: Gain control of target creature until end of turn.

View File

@@ -16,5 +16,4 @@ ManaCost:1 U
Types:Legendary Enchantment
T:Mode$ SpellCast | ValidActivatingPlayer$ Player.Opponent | ActivatorThisTurnCast$ EQ1 | NoResolvingCheck$ True | Execute$ TrigCounter | TriggerZones$ Battlefield | TriggerDescription$ Whenever an opponent casts their first spell each turn, counter that spell.
SVar:TrigCounter:DB$ Counter | Defined$ TriggeredSpellAbility | Destination$ Graveyard
# This link may be a temporary solution and could change in the near future.
Oracle:Whenever an opponent casts their first spell each turn, counter that spell.

View File

@@ -19,5 +19,4 @@ Types:Legendary Creature Spirit
PT:3/4
K:Flying
A:AB$ Pump | Cost$ SubCounter<1/KI> | KW$ Prevent all damage that would be dealt to CARDNAME. | ValidTgts$ Creature | TgtPrompt$ Select target creature | SpellDescription$ Prevent all damage that would be dealt to target creature this turn.
# This link may be a temporary solution and could change in the near future.
Oracle:Flying\nRemove a ki counter from Kaiso, Memory of Loyalty: Prevent all damage that would be dealt to target creature this turn.

View File

@@ -2,7 +2,7 @@ Name:Gather Specimens
ManaCost:3 U U U
Types:Instant
A:SP$ Effect | Cost$ 3 U U U | Name$ Gather Specimens Effect | ReplacementEffects$ OppCreatEnters | SpellDescription$ If a creature would enter the battlefield under an opponent's control this turn, it enters the battlefield under your control instead.
SVar:OppCreatEnters:Event$ Moved | Destination$ Battlefield | ValidCard$ Creature.OppCtrl | ReplaceWith$ ETBYourCtrl | Description$ If a creature would enter the battlefield under an opponent's control this turn, it enters the battlefield under your control instead.
SVar:OppCreatEnters:Event$ Moved | Destination$ Battlefield | ValidCard$ Creature.OppCtrl | ReplaceWith$ ETBYourCtrl | Layer$ Control | Description$ If a creature would enter the battlefield under an opponent's control this turn, it enters the battlefield under your control instead.
SVar:ETBYourCtrl:DB$ ChangeZone | Origin$ All | Destination$ Battlefield | Defined$ ReplacedCard | GainControl$ True
AI:RemoveDeck:All
Oracle:If a creature would enter the battlefield under an opponent's control this turn, it enters the battlefield under your control instead.

View File

@@ -2,9 +2,9 @@ Name:Haphazard Bombardment
ManaCost:5 R
Types:Enchantment
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ DBPutCounter | TriggerDescription$ When CARDNAME enters the battlefield, choose four nonenchantment permanents you don't control and put an aim counter on each of them.
SVar:DBPutCounter:DB$ PutCounter | Choices$ Permanent.YouDontCtrl+nonEnchantment | ChoiceAmount$ 4 | Defined$ ChosenCard | CounterType$ AIM | CounterNum$ 1
SVar:DBPutCounter:DB$ PutCounter | Choices$ Permanent.YouDontCtrl+nonEnchantment | ChoiceAmount$ 4 | Defined$ ChosenCard | CounterType$ AIM | CounterNum$ 1 | IsCurse$ True
T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | IsPresent$ Permanent.YouDontCtrl+counters_GE1_AIM | PresentCompare$ GE2 | Execute$ TrigDestroy | TriggerDescription$ At the beginning of your end step, if two or more permanents you don't control have an aim counter on them, destroy one of those permanents at random.
SVar:TrigDestroy:DB$ ChooseCard | Amount$ 1 | AtRandom$ True | Choices$ Permanent.YouDontCtrl+counters_GE1_AIM | SubAbility$ DBDestroy
SVar:TrigDestroy:DB$ ChooseCard | Amount$ 1 | AtRandom$ True | Choices$ Permanent.YouDontCtrl+counters_GE1_AIM+withoutIndestructible | SubAbility$ DBDestroy
SVar:DBDestroy:DB$ Destroy | Defined$ ChosenCard | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearChosenCard$ True
Oracle:When Haphazard Bombardment enters the battlefield, choose four nonenchantment permanents you don't control and put an aim counter on each of them.\nAt the beginning of your end step, if two or more permanents you don't control have an aim counter on them, destroy one of those permanents at random.

View File

@@ -18,5 +18,4 @@ Colors:black
Types:Legendary Creature Spirit
PT:4/4
A:AB$ Pump | Cost$ SubCounter<1/KI> | KW$ Fear | ValidTgts$ Creature | TgtPrompt$ Select target creature | SpellDescription$ Target creature gains fear until end of turn. (It can't be blocked except by artifact creatures and/or black creatures.)
# This link may be a temporary solution and could change in the near future.
Oracle:Remove a ki counter from Scarmaker: Target creature gains fear until end of turn. (It can't be blocked except by artifact creatures and/or black creatures.)

View File

@@ -16,5 +16,4 @@ Colors:black
Types:Legendary Enchantment
T:Mode$ Phase | Phase$ Upkeep | TriggerZones$ Battlefield | Execute$ TrigSac | TriggerDescription$ At the beginning of each player's upkeep, that player sacrifices a creature.
SVar:TrigSac:DB$ Sacrifice | Defined$ TriggeredPlayer | SacValid$ Creature
# This link may be a temporary solution and could change in the near future.
Oracle:At the beginning of each player's upkeep, that player sacrifices a creature.

View File

@@ -3,6 +3,6 @@ ManaCost:2 U U
Types:Creature Human Rogue
PT:2/2
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigChange | TriggerDescription$ When CARDNAME enters the battlefield, gain control of target artifact for as long as you control CARDNAME.
SVar:TrigChange:DB$ GainControl | TgtPrompt$ Choose target artifact | ValidTgts$ Artifact | LoseControl$ LeavesPlay, LoseControl | SpellDescription$ Gain control of target artifact for as long as you control CARDNAME.
SVar:TrigChange:DB$ GainControl | TgtPrompt$ Choose target artifact | ValidTgts$ Artifact | LoseControl$ LeavesPlay,LoseControl | SpellDescription$ Gain control of target artifact for as long as you control CARDNAME.
SVar:PlayMain1:TRUE
Oracle:When Master Thief enters the battlefield, gain control of target artifact for as long as you control Master Thief.

View File

@@ -13,5 +13,4 @@ Name:Rune-Tail's Essence
ManaCost:2 W
Types:Legendary Enchantment
R:Event$ DamageDone | Prevent$ True | ValidTarget$ Creature.YouCtrl | Description$ Prevent all damage that would be dealt to creatures you control.
# This link may be a temporary solution and could change in the near future.
Oracle:Prevent all damage that would be dealt to creatures you control.

View File

@@ -8,6 +8,6 @@ R:Event$ AddCounter | ActiveZones$ Battlefield | ValidSource$ You | ValidObject$
SVar:DoubleCounters:DB$ ReplaceCounter | ValidSource$ You | Amount$ X
SVar:X:ReplaceCount$CounterNum/Twice
R:Event$ AddCounter | ActiveZones$ Battlefield | ValidSource$ Opponent | ValidObject$ Permanent.inZoneBattlefield,Player | ReplaceWith$ HalfCounters | Description$ If an opponent would put one or more counters on a permanent or player, they put half that many of each of those kinds of counters on that permanent or player instead, rounded down.
SVar:HalfCounters:DB$ ReplaceCounter | ValidSource$ Opponent | Amount$ DB$ Y
SVar:HalfCounters:DB$ ReplaceCounter | ValidSource$ Opponent | Amount$ Y
SVar:Y:ReplaceCount$CounterNum/HalfDown
Oracle:Trample, haste\nIf you would put one or more counters on a permanent or player, put twice that many of each of those kinds of counters on that permanent or player instead.\nIf an opponent would put one or more counters on a permanent or player, they put half that many of each of those kinds of counters on that permanent or player instead, rounded down.