diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java index 59ae2a469b8..cb0aa7aa541 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java @@ -1563,7 +1563,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } private Abilities getManaAbilitiesSortedByManaCount(MageObject mageObject, final Game game) { - Abilities manaAbilities = mageObject.getAbilities().getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, game); + Abilities manaAbilities = mageObject.getAbilities().getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, playerId, game); if (manaAbilities.size() > 1) { // Sort mana abilities by number of produced manas, to use ability first that produces most mana (maybe also conditional if possible) Collections.sort(manaAbilities, new Comparator() { @@ -1609,7 +1609,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { int score = 0; for (ManaCost cost : unpaid) { Abilities: - for (ActivatedManaAbilityImpl ability : mageObject.getAbilities().getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, game)) { + for (ActivatedManaAbilityImpl ability : mageObject.getAbilities().getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, playerId, game)) { for (Mana netMana : ability.getNetMana(game)) { if (cost.testPay(netMana)) { score++; @@ -1619,7 +1619,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } if (score > 0) { // score mana producers that produce other mana types and have other uses higher - score += mageObject.getAbilities().getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, game).size(); + score += mageObject.getAbilities().getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, playerId, game).size(); score += mageObject.getAbilities().getActivatedAbilities(Zone.BATTLEFIELD).size(); if (!mageObject.getCardType().contains(CardType.LAND)) { score += 2; diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/mana/NonTappingManaAbilitiesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/mana/NonTappingManaAbilitiesTest.java index a0caa235493..4fef84ad09c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/mana/NonTappingManaAbilitiesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/mana/NonTappingManaAbilitiesTest.java @@ -289,4 +289,49 @@ public class NonTappingManaAbilitiesTest extends CardTestPlayerBase { Assert.assertEquals("mana variations don't fit", 1, manaOptions.size()); assertManaOptions("{B}{B}{B}{B}", manaOptions); } + + @Test + public void Test_ManaCache() { + setStrictChooseMode(true); + + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); + + // At the beginning of each player's end step, put a charge counter on Mana Cache for each untapped land that player controls. + // Remove a charge counter from Mana Cache: Add {C}. Any player may activate this ability but only during their turn before the end step. + addCard(Zone.BATTLEFIELD, playerA, "Mana Cache", 1); + + setStopAt(3, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertAllCommandsUsed(); + + assertCounterCount("Mana Cache", CounterType.CHARGE, 2); + + ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); + Assert.assertEquals("mana variations don't fit", 1, manaOptions.size()); + assertManaOptions("{C}{C}{B}{B}", manaOptions); + } + + @Test + public void Test_ManaCacheOpponent() { + setStrictChooseMode(true); + + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); + + // At the beginning of each player's end step, put a charge counter on Mana Cache for each untapped land that player controls. + // Remove a charge counter from Mana Cache: Add {C}. Any player may activate this ability but only during their turn before the end step. + addCard(Zone.BATTLEFIELD, playerA, "Mana Cache", 1); + + setStopAt(2, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertAllCommandsUsed(); + + assertCounterCount("Mana Cache", CounterType.CHARGE, 2); + + ManaOptions manaOptions = playerB.getAvailableManaTest(currentGame); + Assert.assertEquals("mana variations don't fit", 1, manaOptions.size()); + assertManaOptions("{C}{C}", manaOptions); + } + } diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index 016adfd48dd..87a259bd185 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -613,7 +613,7 @@ public class TestPlayer implements Player { for (MageObject mageObject : manaObjects) { if (mageObject instanceof Permanent) { - for (Ability manaAbility : ((Permanent) mageObject).getAbilities(game).getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, game)) { + for (Ability manaAbility : ((Permanent) mageObject).getAbilities(game).getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, getId(), game)) { if (hasAbilityTargetNameOrAlias(game, manaAbility, groups[0])) { Ability newManaAbility = manaAbility.copy(); computerPlayer.activateAbility((ActivatedAbility) newManaAbility, game); @@ -622,7 +622,7 @@ public class TestPlayer implements Player { } } } else if (mageObject instanceof Card) { - for (Ability manaAbility : ((Card) mageObject).getAbilities(game).getAvailableActivatedManaAbilities(game.getState().getZone(mageObject.getId()), game)) { + for (Ability manaAbility : ((Card) mageObject).getAbilities(game).getAvailableActivatedManaAbilities(game.getState().getZone(mageObject.getId()), getId(), game)) { if (hasAbilityTargetNameOrAlias(game, manaAbility, groups[0])) { Ability newManaAbility = manaAbility.copy(); computerPlayer.activateAbility((ActivatedAbility) newManaAbility, game); @@ -631,7 +631,7 @@ public class TestPlayer implements Player { } } } else { - for (Ability manaAbility : mageObject.getAbilities().getAvailableActivatedManaAbilities(game.getState().getZone(mageObject.getId()), game)) { + for (Ability manaAbility : mageObject.getAbilities().getAvailableActivatedManaAbilities(game.getState().getZone(mageObject.getId()), getId(), game)) { if (hasAbilityTargetNameOrAlias(game, manaAbility, groups[0])) { Ability newManaAbility = manaAbility.copy(); computerPlayer.activateAbility((ActivatedAbility) newManaAbility, game); @@ -643,7 +643,7 @@ public class TestPlayer implements Player { } List manaPermsWithCost = computerPlayer.getAvailableManaProducersWithCost(game); for (Permanent perm : manaPermsWithCost) { - for (ActivatedManaAbilityImpl manaAbility : perm.getAbilities().getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, game)) { + for (ActivatedManaAbilityImpl manaAbility : perm.getAbilities().getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, getId(), game)) { if (hasAbilityTargetNameOrAlias(game, manaAbility, groups[0]) && manaAbility.canActivate(computerPlayer.getId(), game).canActivate()) { Ability newManaAbility = manaAbility.copy(); diff --git a/Mage/src/main/java/mage/abilities/Abilities.java b/Mage/src/main/java/mage/abilities/Abilities.java index cbceb72bc34..1c5054ab1a2 100644 --- a/Mage/src/main/java/mage/abilities/Abilities.java +++ b/Mage/src/main/java/mage/abilities/Abilities.java @@ -90,6 +90,7 @@ public interface Abilities extends List, Serializable { * * @param zone The {@link Zone} to search for * {@link ActivatedManaAbilityImpl mana abilities}. + * @param playerId The id of the player to check availability for * @return All {@link ActivatedManaAbilityImpl mana abilities} for the given * {@link Zone} that can be used. * @@ -97,7 +98,7 @@ public interface Abilities extends List, Serializable { * @see mage.players.PlayerImpl#getManaAvailable(mage.game.Game) * @see mage.players.PlayerImpl#getAvailableManaProducers(mage.game.Game) */ - Abilities getAvailableActivatedManaAbilities(Zone zone, Game game); + Abilities getAvailableActivatedManaAbilities(Zone zone, UUID playerId, Game game); /** * Retrieves all {@link StaticAbility static abilities} in the given diff --git a/Mage/src/main/java/mage/abilities/AbilitiesImpl.java b/Mage/src/main/java/mage/abilities/AbilitiesImpl.java index d46348ac008..93de7e94498 100644 --- a/Mage/src/main/java/mage/abilities/AbilitiesImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilitiesImpl.java @@ -131,11 +131,11 @@ public class AbilitiesImpl extends ArrayList implements Ab } @Override - public Abilities getAvailableActivatedManaAbilities(Zone zone, Game game) { + public Abilities getAvailableActivatedManaAbilities(Zone zone, UUID playerId, Game game) { return stream() .filter(ability -> ability instanceof ActivatedManaAbilityImpl) .filter(ability -> ability.getZone().match(zone)) - .filter(ability -> (((ActivatedManaAbilityImpl) ability).canActivate(ability.getControllerId(), game).canActivate())) + .filter(ability -> (((ActivatedManaAbilityImpl) ability).canActivate(playerId, game).canActivate())) .map(ability -> (ActivatedManaAbilityImpl) ability) .collect(Collectors.toCollection(AbilitiesImpl::new)); diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index b14373b33d9..1364bdc6c0e 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -2891,18 +2891,18 @@ public abstract class PlayerImpl implements Player, Serializable { List> sourceWithoutManaCosts = new ArrayList<>(); List> sourceWithCosts = new ArrayList<>(); - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(playerId)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(playerId, game)) { // Some permanents allow use of abilities from non controlling players. so check all permanents in range Boolean canUse = null; boolean canAdd = false; boolean withCost = false; Abilities manaAbilities - = permanent.getAbilities().getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, game); + = permanent.getAbilities().getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, playerId, game); // returns ability only if canActivate is true for (Iterator it = manaAbilities.iterator(); it.hasNext();) { ActivatedManaAbilityImpl ability = it.next(); if (canUse == null) { canUse = permanent.canUseActivatedAbilities(game); } - if (canUse && ability.canActivate(playerId, game).canActivate()) { + if (canUse) { // abilities without Tap costs have to be handled as separate sources, because they can be used also if (!ability.hasTapCost()) { it.remove(); @@ -2985,7 +2985,7 @@ public abstract class PlayerImpl implements Player, Serializable { // returns only mana producers that don't require mana payment protected List getAvailableManaProducers(Game game) { List result = new ArrayList<>(); - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(playerId)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(playerId, game)) { // Some permanents allow use of abilities from non controlling players. so check all permanents in range Boolean canUse = null; boolean canAdd = false; for (ActivatedManaAbilityImpl ability : permanent.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD)) { @@ -3025,7 +3025,7 @@ public abstract class PlayerImpl implements Player, Serializable { // returns only mana producers that require mana payment public List getAvailableManaProducersWithCost(Game game) { List result = new ArrayList<>(); - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(playerId)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(playerId, game)) { Boolean canUse = null; for (ActivatedManaAbilityImpl ability : permanent.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD)) { if (canUse == null) {