mirror of
https://github.com/magefree/mage.git
synced 2025-12-23 03:51:58 -08:00
* Mana Clash - Fixed use in available mana calculation (related to #6698).
This commit is contained in:
parent
674fd6b1a5
commit
6a65e5bb23
6 changed files with 61 additions and 15 deletions
|
|
@ -1563,7 +1563,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Abilities<ActivatedManaAbilityImpl> getManaAbilitiesSortedByManaCount(MageObject mageObject, final Game game) {
|
private Abilities<ActivatedManaAbilityImpl> getManaAbilitiesSortedByManaCount(MageObject mageObject, final Game game) {
|
||||||
Abilities<ActivatedManaAbilityImpl> manaAbilities = mageObject.getAbilities().getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, game);
|
Abilities<ActivatedManaAbilityImpl> manaAbilities = mageObject.getAbilities().getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, playerId, game);
|
||||||
if (manaAbilities.size() > 1) {
|
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)
|
// 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<ActivatedManaAbilityImpl>() {
|
Collections.sort(manaAbilities, new Comparator<ActivatedManaAbilityImpl>() {
|
||||||
|
|
@ -1609,7 +1609,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
|
||||||
int score = 0;
|
int score = 0;
|
||||||
for (ManaCost cost : unpaid) {
|
for (ManaCost cost : unpaid) {
|
||||||
Abilities:
|
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)) {
|
for (Mana netMana : ability.getNetMana(game)) {
|
||||||
if (cost.testPay(netMana)) {
|
if (cost.testPay(netMana)) {
|
||||||
score++;
|
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
|
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();
|
score += mageObject.getAbilities().getActivatedAbilities(Zone.BATTLEFIELD).size();
|
||||||
if (!mageObject.getCardType().contains(CardType.LAND)) {
|
if (!mageObject.getCardType().contains(CardType.LAND)) {
|
||||||
score += 2;
|
score += 2;
|
||||||
|
|
|
||||||
|
|
@ -289,4 +289,49 @@ public class NonTappingManaAbilitiesTest extends CardTestPlayerBase {
|
||||||
Assert.assertEquals("mana variations don't fit", 1, manaOptions.size());
|
Assert.assertEquals("mana variations don't fit", 1, manaOptions.size());
|
||||||
assertManaOptions("{B}{B}{B}{B}", manaOptions);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -613,7 +613,7 @@ public class TestPlayer implements Player {
|
||||||
|
|
||||||
for (MageObject mageObject : manaObjects) {
|
for (MageObject mageObject : manaObjects) {
|
||||||
if (mageObject instanceof Permanent) {
|
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])) {
|
if (hasAbilityTargetNameOrAlias(game, manaAbility, groups[0])) {
|
||||||
Ability newManaAbility = manaAbility.copy();
|
Ability newManaAbility = manaAbility.copy();
|
||||||
computerPlayer.activateAbility((ActivatedAbility) newManaAbility, game);
|
computerPlayer.activateAbility((ActivatedAbility) newManaAbility, game);
|
||||||
|
|
@ -622,7 +622,7 @@ public class TestPlayer implements Player {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (mageObject instanceof Card) {
|
} 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])) {
|
if (hasAbilityTargetNameOrAlias(game, manaAbility, groups[0])) {
|
||||||
Ability newManaAbility = manaAbility.copy();
|
Ability newManaAbility = manaAbility.copy();
|
||||||
computerPlayer.activateAbility((ActivatedAbility) newManaAbility, game);
|
computerPlayer.activateAbility((ActivatedAbility) newManaAbility, game);
|
||||||
|
|
@ -631,7 +631,7 @@ public class TestPlayer implements Player {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} 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])) {
|
if (hasAbilityTargetNameOrAlias(game, manaAbility, groups[0])) {
|
||||||
Ability newManaAbility = manaAbility.copy();
|
Ability newManaAbility = manaAbility.copy();
|
||||||
computerPlayer.activateAbility((ActivatedAbility) newManaAbility, game);
|
computerPlayer.activateAbility((ActivatedAbility) newManaAbility, game);
|
||||||
|
|
@ -643,7 +643,7 @@ public class TestPlayer implements Player {
|
||||||
}
|
}
|
||||||
List<Permanent> manaPermsWithCost = computerPlayer.getAvailableManaProducersWithCost(game);
|
List<Permanent> manaPermsWithCost = computerPlayer.getAvailableManaProducersWithCost(game);
|
||||||
for (Permanent perm : manaPermsWithCost) {
|
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])
|
if (hasAbilityTargetNameOrAlias(game, manaAbility, groups[0])
|
||||||
&& manaAbility.canActivate(computerPlayer.getId(), game).canActivate()) {
|
&& manaAbility.canActivate(computerPlayer.getId(), game).canActivate()) {
|
||||||
Ability newManaAbility = manaAbility.copy();
|
Ability newManaAbility = manaAbility.copy();
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,7 @@ public interface Abilities<T extends Ability> extends List<T>, Serializable {
|
||||||
*
|
*
|
||||||
* @param zone The {@link Zone} to search for
|
* @param zone The {@link Zone} to search for
|
||||||
* {@link ActivatedManaAbilityImpl mana abilities}.
|
* {@link ActivatedManaAbilityImpl mana abilities}.
|
||||||
|
* @param playerId The id of the player to check availability for
|
||||||
* @return All {@link ActivatedManaAbilityImpl mana abilities} for the given
|
* @return All {@link ActivatedManaAbilityImpl mana abilities} for the given
|
||||||
* {@link Zone} that can be used.
|
* {@link Zone} that can be used.
|
||||||
*
|
*
|
||||||
|
|
@ -97,7 +98,7 @@ public interface Abilities<T extends Ability> extends List<T>, Serializable {
|
||||||
* @see mage.players.PlayerImpl#getManaAvailable(mage.game.Game)
|
* @see mage.players.PlayerImpl#getManaAvailable(mage.game.Game)
|
||||||
* @see mage.players.PlayerImpl#getAvailableManaProducers(mage.game.Game)
|
* @see mage.players.PlayerImpl#getAvailableManaProducers(mage.game.Game)
|
||||||
*/
|
*/
|
||||||
Abilities<ActivatedManaAbilityImpl> getAvailableActivatedManaAbilities(Zone zone, Game game);
|
Abilities<ActivatedManaAbilityImpl> getAvailableActivatedManaAbilities(Zone zone, UUID playerId, Game game);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves all {@link StaticAbility static abilities} in the given
|
* Retrieves all {@link StaticAbility static abilities} in the given
|
||||||
|
|
|
||||||
|
|
@ -131,11 +131,11 @@ public class AbilitiesImpl<T extends Ability> extends ArrayList<T> implements Ab
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Abilities<ActivatedManaAbilityImpl> getAvailableActivatedManaAbilities(Zone zone, Game game) {
|
public Abilities<ActivatedManaAbilityImpl> getAvailableActivatedManaAbilities(Zone zone, UUID playerId, Game game) {
|
||||||
return stream()
|
return stream()
|
||||||
.filter(ability -> ability instanceof ActivatedManaAbilityImpl)
|
.filter(ability -> ability instanceof ActivatedManaAbilityImpl)
|
||||||
.filter(ability -> ability.getZone().match(zone))
|
.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)
|
.map(ability -> (ActivatedManaAbilityImpl) ability)
|
||||||
.collect(Collectors.toCollection(AbilitiesImpl::new));
|
.collect(Collectors.toCollection(AbilitiesImpl::new));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2891,18 +2891,18 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
|
|
||||||
List<Abilities<ActivatedManaAbilityImpl>> sourceWithoutManaCosts = new ArrayList<>();
|
List<Abilities<ActivatedManaAbilityImpl>> sourceWithoutManaCosts = new ArrayList<>();
|
||||||
List<Abilities<ActivatedManaAbilityImpl>> sourceWithCosts = new ArrayList<>();
|
List<Abilities<ActivatedManaAbilityImpl>> 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 canUse = null;
|
||||||
boolean canAdd = false;
|
boolean canAdd = false;
|
||||||
boolean withCost = false;
|
boolean withCost = false;
|
||||||
Abilities<ActivatedManaAbilityImpl> manaAbilities
|
Abilities<ActivatedManaAbilityImpl> manaAbilities
|
||||||
= permanent.getAbilities().getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, game);
|
= permanent.getAbilities().getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, playerId, game); // returns ability only if canActivate is true
|
||||||
for (Iterator<ActivatedManaAbilityImpl> it = manaAbilities.iterator(); it.hasNext();) {
|
for (Iterator<ActivatedManaAbilityImpl> it = manaAbilities.iterator(); it.hasNext();) {
|
||||||
ActivatedManaAbilityImpl ability = it.next();
|
ActivatedManaAbilityImpl ability = it.next();
|
||||||
if (canUse == null) {
|
if (canUse == null) {
|
||||||
canUse = permanent.canUseActivatedAbilities(game);
|
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
|
// abilities without Tap costs have to be handled as separate sources, because they can be used also
|
||||||
if (!ability.hasTapCost()) {
|
if (!ability.hasTapCost()) {
|
||||||
it.remove();
|
it.remove();
|
||||||
|
|
@ -2985,7 +2985,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
// returns only mana producers that don't require mana payment
|
// returns only mana producers that don't require mana payment
|
||||||
protected List<MageObject> getAvailableManaProducers(Game game) {
|
protected List<MageObject> getAvailableManaProducers(Game game) {
|
||||||
List<MageObject> result = new ArrayList<>();
|
List<MageObject> 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 canUse = null;
|
||||||
boolean canAdd = false;
|
boolean canAdd = false;
|
||||||
for (ActivatedManaAbilityImpl ability : permanent.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD)) {
|
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
|
// returns only mana producers that require mana payment
|
||||||
public List<Permanent> getAvailableManaProducersWithCost(Game game) {
|
public List<Permanent> getAvailableManaProducersWithCost(Game game) {
|
||||||
List<Permanent> result = new ArrayList<>();
|
List<Permanent> result = new ArrayList<>();
|
||||||
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(playerId)) {
|
for (Permanent permanent : game.getBattlefield().getActivePermanents(playerId, game)) {
|
||||||
Boolean canUse = null;
|
Boolean canUse = null;
|
||||||
for (ActivatedManaAbilityImpl ability : permanent.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD)) {
|
for (ActivatedManaAbilityImpl ability : permanent.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD)) {
|
||||||
if (canUse == null) {
|
if (canUse == null) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue