mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 02:30:08 -08:00
Refactor: private fields and performance tweaks (#9625)
1a. Make `costs`, `manaCosts`, and `manaCostsToPay` private in `AbilityImpl` with access through getters/setters 1b. fix cost adjuster for imprinted cards affected by the above 2a. Lazy instantiation for rarely used `data` field in `TargetPointerImpl` 3a. Pre-allocate certain array sizes in `Modes` and `CostsImpl` 4a. Make `manaTemplate` private in `BasicManaEffect`, copy when passing outside the class 4b. Don't copy `manaTemplate` in copy constructor since it doesn't change 4c. Add comments explaining copy usage for `manaTemplate` 4d. Remove redundant variable assignment and make fields final --------- Co-authored-by: xenohedron <xenohedron@users.noreply.github.com>
This commit is contained in:
parent
53be4f384e
commit
a2162ec3e7
65 changed files with 262 additions and 196 deletions
|
|
@ -153,7 +153,7 @@ public class SimulatedPlayer2 extends ComputerPlayer {
|
|||
if (newAbility instanceof AbilityImpl) {
|
||||
xMultiplier = ((AbilityImpl) newAbility).handleManaXMultiplier(game, xMultiplier);
|
||||
}
|
||||
newAbility.getManaCostsToPay().add(new ManaCostsImpl<>(new StringBuilder("{").append(xAnnounceValue).append('}').toString()));
|
||||
newAbility.addManaCostsToPay(new ManaCostsImpl<>(new StringBuilder("{").append(xAnnounceValue).append('}').toString()));
|
||||
newAbility.getManaCostsToPay().setX(xAnnounceValue * xMultiplier, xAnnounceValue * xInstancesCount);
|
||||
if (varCost != null) {
|
||||
varCost.setPaid();
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ public class MCTSPlayer extends ComputerPlayer {
|
|||
}
|
||||
for (int i = start; i < numAvailable; i++) {
|
||||
Ability newAbility = ability.copy();
|
||||
newAbility.getManaCostsToPay().add(new GenericManaCost(i));
|
||||
newAbility.addManaCostsToPay(new GenericManaCost(i));
|
||||
options.add(newAbility);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ public class SimulatedPlayerMCTS extends MCTSPlayer {
|
|||
int amount = getAvailableManaProducers(game).size() - ability.getManaCosts().manaValue();
|
||||
if (amount > 0) {
|
||||
ability = ability.copy();
|
||||
ability.getManaCostsToPay().add(new GenericManaCost(RandomUtil.nextInt(amount)));
|
||||
ability.addManaCostsToPay(new GenericManaCost(RandomUtil.nextInt(amount)));
|
||||
}
|
||||
}
|
||||
// check if ability kills player, if not then it's ok to play
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ public class SimulatedPlayer extends ComputerPlayer {
|
|||
}
|
||||
for (int i = start; i < numAvailable; i++) {
|
||||
Ability newAbility = ability.copy();
|
||||
newAbility.getManaCostsToPay().add(new GenericManaCost(i));
|
||||
newAbility.addManaCostsToPay(new GenericManaCost(i));
|
||||
allActions.add(newAbility);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ enum BargainingTableAdjuster implements CostAdjuster {
|
|||
handSize = player.getHand().size();
|
||||
}
|
||||
}
|
||||
ability.getManaCostsToPay().clear();
|
||||
ability.getManaCostsToPay().add(new GenericManaCost(handSize));
|
||||
ability.clearManaCostsToPay();
|
||||
ability.addManaCostsToPay(new GenericManaCost(handSize));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,8 +122,8 @@ class BruenorBattlehammerCostEffect extends CostModificationEffectImpl {
|
|||
}
|
||||
|
||||
if (applyReduce) {
|
||||
abilityToModify.getCosts().clear();
|
||||
abilityToModify.getManaCostsToPay().clear();
|
||||
abilityToModify.clearCosts();
|
||||
abilityToModify.clearManaCostsToPay();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -68,14 +68,17 @@ class CadaverousBloomManaEffect extends BasicManaEffect {
|
|||
if (player != null) {
|
||||
int count = player.getHand().size();
|
||||
if (count > 0) {
|
||||
Mana newManaTemplate = getManaTemplate(); // returns a copy so only copying once for below checks
|
||||
Mana mana = new Mana(
|
||||
getManaTemplate().getWhite() * count, getManaTemplate().getBlue() * count, getManaTemplate().getBlack() * count, getManaTemplate().getRed() * count,
|
||||
getManaTemplate().getGreen() * count,
|
||||
getManaTemplate().getGeneric() * count,
|
||||
getManaTemplate().getAny() * count,
|
||||
getManaTemplate().getColorless() * count
|
||||
newManaTemplate.getWhite() * count,
|
||||
newManaTemplate.getBlue() * count,
|
||||
newManaTemplate.getBlack() * count,
|
||||
newManaTemplate.getRed() * count,
|
||||
newManaTemplate.getGreen() * count,
|
||||
newManaTemplate.getGeneric() * count,
|
||||
newManaTemplate.getAny() * count,
|
||||
newManaTemplate.getColorless() * count
|
||||
);
|
||||
|
||||
netMana.add(mana);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ class DefenseGridCostModificationEffect extends CostModificationEffectImpl {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source, Ability abilityToModify) {
|
||||
SpellAbility spellAbility = (SpellAbility) abilityToModify;
|
||||
spellAbility.getManaCostsToPay().add(new GenericManaCost(3));
|
||||
spellAbility.addManaCostsToPay(new GenericManaCost(3));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -75,8 +75,8 @@ enum EliteArcanistAdjuster implements CostAdjuster {
|
|||
}
|
||||
int cmc = imprintedInstant.getManaValue();
|
||||
if (cmc > 0) {
|
||||
ability.getManaCostsToPay().clear();
|
||||
ability.getManaCostsToPay().add(new GenericManaCost(cmc));
|
||||
ability.clearManaCostsToPay();
|
||||
ability.addManaCostsToPay(new GenericManaCost(cmc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ enum FireballAdjuster implements CostAdjuster {
|
|||
public void adjustCosts(Ability ability, Game game) {
|
||||
int numTargets = ability.getTargets().isEmpty() ? 0 : ability.getTargets().get(0).getTargets().size();
|
||||
if (numTargets > 1) {
|
||||
ability.getManaCostsToPay().add(new GenericManaCost(numTargets - 1));
|
||||
ability.addManaCostsToPay(new GenericManaCost(numTargets - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,9 +96,9 @@ class CyclingZeroCostEffect extends CostModificationEffectImpl {
|
|||
if (player == null || !player.chooseUse(outcome, "Pay {0} to cycle this card?", source, game)) {
|
||||
return true;
|
||||
}
|
||||
abilityToModify.getManaCostsToPay().clear();
|
||||
abilityToModify.clearManaCostsToPay();
|
||||
abilityToModify.getCosts().removeIf(cost -> !CyclingDiscardCost.class.isInstance(cost));
|
||||
abilityToModify.getManaCostsToPay().add(new GenericManaCost(0));
|
||||
abilityToModify.addManaCostsToPay(new GenericManaCost(0));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -70,9 +70,9 @@ class NewPerspectivesCostModificationEffect extends CostModificationEffectImpl {
|
|||
if (controller != null) {
|
||||
if (game.inCheckPlayableState()
|
||||
|| controller.chooseUse(Outcome.PlayForFree, "Pay {0} to cycle?", source, game)) {
|
||||
abilityToModify.getCosts().clear();
|
||||
abilityToModify.getManaCostsToPay().clear();
|
||||
abilityToModify.getCosts().add(new CyclingDiscardCost());
|
||||
abilityToModify.clearCosts();
|
||||
abilityToModify.clearManaCostsToPay();
|
||||
abilityToModify.addCost(new CyclingDiscardCost());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ enum PhyrexianPurgeCostAdjuster implements CostAdjuster {
|
|||
public void adjustCosts(Ability ability, Game game) {
|
||||
int numTargets = ability.getTargets().get(0).getTargets().size();
|
||||
if (numTargets > 0) {
|
||||
ability.getCosts().add(new PayLifeCost(numTargets * 3));
|
||||
ability.addCost(new PayLifeCost(numTargets * 3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,7 +69,8 @@ enum PrototypePortalAdjuster implements CostAdjuster {
|
|||
if (!card.getImprinted().isEmpty()) {
|
||||
Card imprinted = game.getCard(card.getImprinted().get(0));
|
||||
if (imprinted != null) {
|
||||
ability.getManaCostsToPay().add(0, new GenericManaCost(imprinted.getManaValue()));
|
||||
ability.clearManaCostsToPay();
|
||||
ability.addManaCostsToPay(new GenericManaCost(imprinted.getManaValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,8 +80,8 @@ class RanarTheEverWatchfulCostReductionEffect extends CostModificationEffectImpl
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source, Ability abilityToModify) {
|
||||
abilityToModify.getManaCostsToPay().clear();
|
||||
abilityToModify.getManaCostsToPay().addAll(new ManaCostsImpl<>("{0}"));
|
||||
abilityToModify.clearManaCostsToPay();
|
||||
abilityToModify.addManaCostsToPay(new ManaCostsImpl<>("{0}"));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,8 +69,8 @@ enum SoulFoundryAdjuster implements CostAdjuster {
|
|||
if (!sourcePermanent.getImprinted().isEmpty()) {
|
||||
Card imprinted = game.getCard(sourcePermanent.getImprinted().get(0));
|
||||
if (imprinted != null) {
|
||||
ability.getManaCostsToPay().clear();
|
||||
ability.getManaCostsToPay().add(0, new GenericManaCost(imprinted.getManaValue()));
|
||||
ability.clearManaCostsToPay();
|
||||
ability.addManaCostsToPay(new GenericManaCost(imprinted.getManaValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import mage.abilities.Ability;
|
|||
import mage.abilities.common.BeginningOfEndStepTriggeredAbility;
|
||||
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.condition.InvertCondition;
|
||||
import mage.abilities.condition.common.SourceTappedCondition;
|
||||
import mage.abilities.costs.CostAdjuster;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
|
|
@ -78,8 +77,8 @@ enum VoodooDollAdjuster implements CostAdjuster {
|
|||
Permanent sourcePermanent = game.getPermanent(ability.getSourceId());
|
||||
if (sourcePermanent != null) {
|
||||
int pin = sourcePermanent.getCounters(game).getCount(CounterType.PIN);
|
||||
ability.getManaCostsToPay().clear();
|
||||
ability.getManaCostsToPay().add(0, new GenericManaCost(pin * 2));
|
||||
ability.clearManaCostsToPay();
|
||||
ability.addManaCostsToPay(new GenericManaCost(pin * 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ class WellOfKnowledgeConditionalActivatedAbility extends ActivatedAbilityImpl {
|
|||
@Override
|
||||
public ActivationStatus canActivate(UUID playerId, Game game) {
|
||||
if (condition.apply(game, this)
|
||||
&& costs.canPay(this, this, playerId, game)
|
||||
&& getCosts().canPay(this, this, playerId, game)
|
||||
&& game.isActivePlayer(playerId)) {
|
||||
this.activatorId = playerId;
|
||||
return ActivationStatus.getTrue(this, game);
|
||||
|
|
|
|||
|
|
@ -118,8 +118,8 @@ class WordOfCommandEffect extends OneShotEffect {
|
|||
&& !targetPlayer.playCard(card, game, false, new ApprovingObject(source, game))) {
|
||||
SpellAbility spellAbility = card.getSpellAbility();
|
||||
if (spellAbility != null) {
|
||||
spellAbility.getManaCostsToPay().clear();
|
||||
spellAbility.getManaCostsToPay().addAll(spellAbility.getManaCosts());
|
||||
spellAbility.clearManaCostsToPay();
|
||||
spellAbility.addManaCostsToPay(spellAbility.getManaCosts());
|
||||
((ManaCostsImpl) spellAbility.getManaCostsToPay()).forceManaRollback(game, manaPool); // force rollback if card was deemed playable
|
||||
canPlay = checkPlayability(card, targetPlayer, game, source);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
package org.mage.test.performance;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* These tests are used to benchmark the performance of the copying of the state.
|
||||
* <p>
|
||||
* Leave the tests comment out when pushing, uncomment only when testing locally.
|
||||
*
|
||||
* @author Alex-Vasile
|
||||
*/
|
||||
public class StateCopying extends CardTestPlayerBase {
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void copyingBattlefield() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 10);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Sol Ring", 10);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Sapphire Medallion", 10);
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
currentGame.getBattlefield().reset(currentGame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -102,6 +102,18 @@ public interface Ability extends Controllable, Serializable {
|
|||
*/
|
||||
void setSourceId(UUID sourceID);
|
||||
|
||||
default void clearCosts() {
|
||||
getCosts().clear();
|
||||
}
|
||||
|
||||
default void clearManaCosts() {
|
||||
getManaCosts().clear();
|
||||
}
|
||||
|
||||
default void clearManaCostsToPay() {
|
||||
getManaCostsToPay().clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all {@link Costs} associated with this ability.
|
||||
*
|
||||
|
|
@ -151,6 +163,8 @@ public interface Ability extends Controllable, Serializable {
|
|||
*/
|
||||
void addManaCost(ManaCost cost);
|
||||
|
||||
void addManaCostsToPay(ManaCost manaCost);
|
||||
|
||||
/**
|
||||
* Retrieves the effects that are put into the place by the resolution of
|
||||
* this ability.
|
||||
|
|
|
|||
|
|
@ -56,9 +56,9 @@ public abstract class AbilityImpl implements Ability {
|
|||
protected AbilityType abilityType;
|
||||
protected UUID controllerId;
|
||||
protected UUID sourceId;
|
||||
protected ManaCosts<ManaCost> manaCosts;
|
||||
protected ManaCosts<ManaCost> manaCostsToPay;
|
||||
protected Costs<Cost> costs;
|
||||
private ManaCosts<ManaCost> manaCosts;
|
||||
private ManaCosts<ManaCost> manaCostsToPay;
|
||||
private Costs<Cost> costs;
|
||||
protected Modes modes; // access to it by GetModes only (it can be overridden by some abilities)
|
||||
protected Zone zone;
|
||||
protected String name;
|
||||
|
|
@ -253,14 +253,14 @@ public abstract class AbilityImpl implements Ability {
|
|||
if (noMana) {
|
||||
if (!this.getManaCostsToPay().getVariableCosts().isEmpty()) {
|
||||
int xValue = this.getManaCostsToPay().getX();
|
||||
this.getManaCostsToPay().clear();
|
||||
this.clearManaCostsToPay();
|
||||
VariableManaCost xCosts = new VariableManaCost(VariableCostType.ADDITIONAL);
|
||||
// no x events - rules from Unbound Flourishing:
|
||||
// - Spells with additional costs that include X won't be affected by Unbound Flourishing. X must be in the spell's mana cost.
|
||||
xCosts.setAmount(xValue, xValue, false);
|
||||
this.getManaCostsToPay().add(xCosts);
|
||||
addManaCostsToPay(xCosts);
|
||||
} else {
|
||||
this.getManaCostsToPay().clear();
|
||||
this.clearManaCostsToPay();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -379,7 +379,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
}
|
||||
|
||||
// this is a hack to prevent mana abilities with mana costs from causing endless loops - pay other costs first
|
||||
if (this instanceof ActivatedManaAbilityImpl && !costs.pay(this, game, this, controllerId, noMana, null)) {
|
||||
if (this instanceof ActivatedManaAbilityImpl && !getCosts().pay(this, game, this, controllerId, noMana, null)) {
|
||||
logger.debug("activate mana ability failed - non mana costs");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -396,12 +396,12 @@ public abstract class AbilityImpl implements Ability {
|
|||
}
|
||||
|
||||
//20100716 - 601.2f (noMana is not used here, because mana costs were cleared for this ability before adding additional costs and applying cost modification effects)
|
||||
if (!manaCostsToPay.pay(this, game, this, activatorId, false, null)) {
|
||||
if (!getManaCostsToPay().pay(this, game, this, activatorId, false, null)) {
|
||||
return false; // cancel during mana payment
|
||||
}
|
||||
|
||||
//20100716 - 601.2g
|
||||
if (!costs.pay(this, game, this, activatorId, noMana, null)) {
|
||||
if (!getCosts().pay(this, game, this, activatorId, noMana, null)) {
|
||||
logger.debug("activate failed - non mana costs");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -509,13 +509,11 @@ public abstract class AbilityImpl implements Ability {
|
|||
*/
|
||||
protected String handleOtherXCosts(Game game, Player controller) {
|
||||
StringBuilder announceString = new StringBuilder();
|
||||
for (VariableCost variableCost : this.costs.getVariableCosts()) {
|
||||
for (VariableCost variableCost : this.getCosts().getVariableCosts()) {
|
||||
if (!(variableCost instanceof VariableManaCost) && !((Cost) variableCost).isPaid()) {
|
||||
int xValue = variableCost.announceXValue(this, game);
|
||||
Cost fixedCost = variableCost.getFixedCostsFromAnnouncedValue(xValue);
|
||||
if (fixedCost != null) {
|
||||
costs.add(fixedCost);
|
||||
}
|
||||
addCost(fixedCost);
|
||||
// set the xcosts to paid
|
||||
// no x events - rules from Unbound Flourishing:
|
||||
// - Spells with additional costs that include X won't be affected by Unbound Flourishing. X must be in the spell's mana cost.
|
||||
|
|
@ -534,7 +532,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
* life or the corresponding colored mana cost for each of those symbols.
|
||||
*/
|
||||
private void handlePhyrexianManaCosts(Game game, Player controller) {
|
||||
Iterator<ManaCost> costIterator = manaCostsToPay.iterator();
|
||||
Iterator<ManaCost> costIterator = getManaCostsToPay().iterator();
|
||||
while (costIterator.hasNext()) {
|
||||
ManaCost cost = costIterator.next();
|
||||
|
||||
|
|
@ -545,8 +543,8 @@ public abstract class AbilityImpl implements Ability {
|
|||
if (payLifeCost.canPay(this, this, controller.getId(), game)
|
||||
&& controller.chooseUse(Outcome.LoseLife, "Pay 2 life instead of " + cost.getText().replace("/P", "") + '?', this, game)) {
|
||||
costIterator.remove();
|
||||
costs.add(payLifeCost);
|
||||
manaCostsToPay.incrPhyrexianPaid();
|
||||
addCost(payLifeCost);
|
||||
getManaCostsToPay().incrPhyrexianPaid();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -580,7 +578,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
|
||||
// TODO: Handle announcing other variable costs here like: RemoveVariableCountersSourceCost
|
||||
VariableManaCost variableManaCost = null;
|
||||
for (ManaCost cost : manaCostsToPay) {
|
||||
for (ManaCost cost : getManaCostsToPay()) {
|
||||
if (cost instanceof VariableManaCost) {
|
||||
if (variableManaCost == null) {
|
||||
variableManaCost = (VariableManaCost) cost;
|
||||
|
|
@ -625,8 +623,8 @@ public abstract class AbilityImpl implements Ability {
|
|||
manaString.append('{').append(manaSymbol).append('}');
|
||||
}
|
||||
}
|
||||
manaCostsToPay.add(new ManaCostsImpl<>(manaString.toString()));
|
||||
manaCostsToPay.setX(xValue * xValueMultiplier, amountMana);
|
||||
addManaCostsToPay(new ManaCostsImpl<>(manaString.toString()));
|
||||
getManaCostsToPay().setX(xValue * xValueMultiplier, amountMana);
|
||||
}
|
||||
variableManaCost.setPaid();
|
||||
}
|
||||
|
|
@ -788,14 +786,14 @@ public abstract class AbilityImpl implements Ability {
|
|||
public String getRule(boolean all) {
|
||||
StringBuilder sbRule = threadLocalBuilder.get();
|
||||
if (all || this.abilityType != AbilityType.SPELL) { // TODO: Why the override for non-spells?
|
||||
if (!manaCosts.isEmpty()) {
|
||||
sbRule.append(manaCosts.getText());
|
||||
if (!getManaCosts().isEmpty()) {
|
||||
sbRule.append(getManaCosts().getText());
|
||||
}
|
||||
if (!costs.isEmpty()) {
|
||||
if (!getCosts().isEmpty()) {
|
||||
if (sbRule.length() > 0) {
|
||||
sbRule.append(", ");
|
||||
}
|
||||
sbRule.append(costs.getText());
|
||||
sbRule.append(getCosts().getText());
|
||||
}
|
||||
if (sbRule.length() > 0) {
|
||||
sbRule.append(": ");
|
||||
|
|
@ -866,19 +864,46 @@ public abstract class AbilityImpl implements Ability {
|
|||
} else {
|
||||
// as single cost
|
||||
if (cost instanceof ManaCost) {
|
||||
this.addManaCost((ManaCost) cost);
|
||||
addManaCost((ManaCost) cost);
|
||||
} else {
|
||||
this.costs.add(cost);
|
||||
if (costs == null) {
|
||||
costs = new CostsImpl<>();
|
||||
}
|
||||
costs.add(cost);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addManaCost(ManaCost cost) {
|
||||
if (cost != null) {
|
||||
this.manaCosts.add(cost);
|
||||
this.manaCostsToPay.add(cost);
|
||||
public void addManaCostsToPay(ManaCost manaCost) {
|
||||
if (manaCost == null) {
|
||||
return;
|
||||
}
|
||||
if (manaCostsToPay == null) {
|
||||
manaCostsToPay = new ManaCostsImpl<>();
|
||||
}
|
||||
if (manaCost instanceof ManaCosts) {
|
||||
manaCostsToPay.addAll((ManaCosts) manaCost);
|
||||
} else {
|
||||
manaCostsToPay.add(manaCost);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addManaCost(ManaCost manaCost) {
|
||||
if (manaCost == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (manaCosts == null) {
|
||||
manaCosts = new ManaCostsImpl<>();
|
||||
}
|
||||
if (manaCostsToPay == null) {
|
||||
manaCostsToPay = new ManaCostsImpl<>();
|
||||
}
|
||||
|
||||
manaCosts.add(manaCost);
|
||||
manaCostsToPay.add(manaCost);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
|||
}
|
||||
|
||||
// targets and costs check
|
||||
if (!costs.canPay(this, this, playerId, game)
|
||||
if (!getCosts().canPay(this, this, playerId, game)
|
||||
|| !canChooseTarget(game, playerId)) {
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ public class LoyaltyAbility extends ActivatedAbilityImpl {
|
|||
|
||||
// cost modification support only 1 cost item
|
||||
int staticCount = 0;
|
||||
for (Cost cost : costs) {
|
||||
for (Cost cost : getCosts()) {
|
||||
if (cost instanceof PayLoyaltyCost) {
|
||||
// static cost
|
||||
PayLoyaltyCost staticCost = (PayLoyaltyCost) cost;
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
|
||||
public List<UUID> getSelectedModes() {
|
||||
// modes can be selected in any order by user, but execution must be in rule's order
|
||||
List<UUID> res = new ArrayList<>();
|
||||
List<UUID> res = new ArrayList<>(this.size());
|
||||
for (Mode mode : this.values()) {
|
||||
for (UUID selectedId : this.selectedModes) {
|
||||
// selectedModes contains original mode and 2+ selected as duplicates (new modes)
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ public class SpellAbility extends ActivatedAbilityImpl {
|
|||
}
|
||||
|
||||
// can pay all costs and choose targets
|
||||
if (costs.canPay(this, this, playerId, game)) {
|
||||
if (getCosts().canPay(this, this, playerId, game)) {
|
||||
if (getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED) {
|
||||
SplitCard splitCard = (SplitCard) game.getCard(getSourceId());
|
||||
if (splitCard != null) {
|
||||
|
|
@ -180,12 +180,6 @@ public class SpellAbility extends ActivatedAbilityImpl {
|
|||
return super.getRule(false);
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
getTargets().clearChosen();
|
||||
this.manaCosts.clearPaid();
|
||||
this.costs.clearPaid();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ class StriveCostIncreasingEffect extends CostModificationEffectImpl {
|
|||
sb.append(striveCosts.getText());
|
||||
}
|
||||
String finalCost = ManaUtil.condenseManaCostString(sb.toString());
|
||||
abilityToModify.getManaCostsToPay().add(new ManaCostsImpl<>(finalCost));
|
||||
abilityToModify.addManaCostsToPay(new ManaCostsImpl<>(finalCost));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -146,19 +146,19 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter
|
|||
CardUtil.reduceCost((SpellAbility) ability, ability.getManaCosts());
|
||||
|
||||
} else {
|
||||
ability.getManaCostsToPay().clear();
|
||||
ability.clearManaCostsToPay();
|
||||
}
|
||||
if (!onlyMana) {
|
||||
ability.getCosts().clear();
|
||||
ability.clearCosts();
|
||||
}
|
||||
for (AlternativeCost alternateCost : alternativeCostsToCheck) {
|
||||
alternateCost.activate();
|
||||
for (Iterator it = ((Costs) alternateCost).iterator(); it.hasNext(); ) {
|
||||
Cost costDetailed = (Cost) it.next();
|
||||
if (costDetailed instanceof ManaCost) {
|
||||
ability.getManaCostsToPay().add((ManaCost) costDetailed.copy());
|
||||
ability.addManaCostsToPay((ManaCost) costDetailed.copy());
|
||||
} else if (costDetailed != null) {
|
||||
ability.getCosts().add(costDetailed.copy());
|
||||
ability.addCost(costDetailed.copy());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,14 +67,14 @@ public abstract class AlternativeSourceCostsImpl extends StaticAbility implement
|
|||
throw new IllegalArgumentException("source card not found");
|
||||
}
|
||||
}
|
||||
ability.getManaCostsToPay().clear();
|
||||
ability.getCosts().clear();
|
||||
ability.clearManaCostsToPay();
|
||||
ability.clearCosts();
|
||||
for (Iterator<Cost> it = ((Costs<Cost>) alternativeCost).iterator(); it.hasNext(); ) {
|
||||
Cost cost = it.next();
|
||||
if (cost instanceof ManaCost) {
|
||||
ability.getManaCostsToPay().add((ManaCost) cost.copy());
|
||||
ability.addManaCostsToPay((ManaCost) cost.copy());
|
||||
} else {
|
||||
ability.getCosts().add(cost.copy());
|
||||
ability.addCost(cost.copy());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ public class CostsImpl<T extends Cost> extends ArrayList<T> implements Costs<T>
|
|||
}
|
||||
|
||||
public CostsImpl(final CostsImpl<T> costs) {
|
||||
this.ensureCapacity(costs.size());
|
||||
for (Cost cost : costs) {
|
||||
this.add((T) cost.copy());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ public class ExileFromHandCost extends CostImpl {
|
|||
// TODO: wtf, look at setXFromCMC usage -- it used in cards with alternative costs, not additional... need to fix?
|
||||
vmc.setAmount(cmc, cmc, false);
|
||||
vmc.setPaid();
|
||||
ability.getManaCostsToPay().add(vmc);
|
||||
ability.addManaCostsToPay(vmc);
|
||||
}
|
||||
}
|
||||
return paid;
|
||||
|
|
|
|||
|
|
@ -17,16 +17,15 @@ import java.util.List;
|
|||
*/
|
||||
public class ConditionalManaEffect extends ManaEffect {
|
||||
|
||||
private BasicManaEffect effect;
|
||||
private BasicManaEffect otherwiseEffect;
|
||||
private Condition condition;
|
||||
|
||||
public ConditionalManaEffect(BasicManaEffect effect, Condition condition, String text) {
|
||||
this(effect, null, condition, text);
|
||||
}
|
||||
private final BasicManaEffect effect;
|
||||
private final BasicManaEffect otherwiseEffect;
|
||||
private final Condition condition;
|
||||
|
||||
public ConditionalManaEffect(BasicManaEffect effect, BasicManaEffect otherwiseEffect, Condition condition, String text) {
|
||||
super();
|
||||
if (effect == null || otherwiseEffect == null) {
|
||||
throw new IllegalArgumentException("Wrong code usage: mana effect must not be null");
|
||||
}
|
||||
this.effect = effect;
|
||||
this.otherwiseEffect = otherwiseEffect;
|
||||
this.condition = condition;
|
||||
|
|
@ -36,9 +35,7 @@ public class ConditionalManaEffect extends ManaEffect {
|
|||
public ConditionalManaEffect(ConditionalManaEffect effect) {
|
||||
super(effect);
|
||||
this.effect = effect.effect.copy();
|
||||
if (effect.otherwiseEffect != null) {
|
||||
this.otherwiseEffect = effect.otherwiseEffect.copy();
|
||||
}
|
||||
this.otherwiseEffect = effect.otherwiseEffect.copy();
|
||||
this.condition = effect.condition;
|
||||
}
|
||||
|
||||
|
|
@ -67,9 +64,9 @@ public class ConditionalManaEffect extends ManaEffect {
|
|||
return mana;
|
||||
}
|
||||
if (condition.apply(game, source)) {
|
||||
mana = effect.getManaTemplate().copy();
|
||||
} else if (otherwiseEffect != null) {
|
||||
mana = otherwiseEffect.getManaTemplate().copy();
|
||||
mana = effect.getManaTemplate(); // getManaTemplate returns a copy already
|
||||
} else {
|
||||
mana = otherwiseEffect.getManaTemplate(); // getManaTemplate returns a copy already
|
||||
}
|
||||
if (mana.getAny() > 0) {
|
||||
int amount = mana.getAny();
|
||||
|
|
|
|||
|
|
@ -71,9 +71,6 @@ public interface ContinuousEffect extends Effect {
|
|||
|
||||
boolean isYourNextUpkeepStep(Game game);
|
||||
|
||||
@Override
|
||||
void newId();
|
||||
|
||||
@Override
|
||||
ContinuousEffect copy();
|
||||
|
||||
|
|
|
|||
|
|
@ -129,13 +129,6 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu
|
|||
this.order = order;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void newId() {
|
||||
if (!(this instanceof MageSingleton)) {
|
||||
this.id = UUID.randomUUID();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasLayer(Layer layer) {
|
||||
return this.layer == layer;
|
||||
|
|
|
|||
|
|
@ -12,12 +12,11 @@ import mage.game.Game;
|
|||
|
||||
public class BasicManaEffect extends ManaEffect {
|
||||
|
||||
protected Mana manaTemplate;
|
||||
private final Mana manaTemplate; // This field must not become directly accessible outside this class
|
||||
private final DynamicValue netAmount;
|
||||
|
||||
public BasicManaEffect(Mana mana) {
|
||||
this(mana, null);
|
||||
this.manaTemplate = mana;
|
||||
}
|
||||
|
||||
public BasicManaEffect(Mana mana, DynamicValue netAmount) {
|
||||
|
|
@ -40,9 +39,8 @@ public class BasicManaEffect extends ManaEffect {
|
|||
|
||||
protected BasicManaEffect(final BasicManaEffect effect) {
|
||||
super(effect);
|
||||
this.manaTemplate = effect.manaTemplate.copy();
|
||||
this.manaTemplate = effect.manaTemplate; // Not copying for performance reasons. Never modified within the class.
|
||||
this.netAmount = effect.netAmount;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -88,7 +86,7 @@ public class BasicManaEffect extends ManaEffect {
|
|||
}
|
||||
|
||||
public Mana getManaTemplate() {
|
||||
return manaTemplate;
|
||||
return manaTemplate.copy(); // Copy is needed here to prevent unintentional modification
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -43,8 +43,8 @@ public class AwakenAbility extends SpellAbility {
|
|||
zone = Zone.HAND;
|
||||
spellAbilityType = SpellAbilityType.BASE_ALTERNATE;
|
||||
|
||||
this.getManaCosts().clear();
|
||||
this.getManaCostsToPay().clear();
|
||||
this.clearManaCosts();
|
||||
this.clearManaCostsToPay();
|
||||
this.addManaCost(new ManaCostsImpl<>(awakenCosts));
|
||||
|
||||
this.addTarget(new TargetControlledPermanent(new FilterControlledLandPermanent(filterMessage)));
|
||||
|
|
|
|||
|
|
@ -58,15 +58,15 @@ public class BlitzAbility extends SpellAbility {
|
|||
@Override
|
||||
public String getRule() {
|
||||
StringBuilder sb = new StringBuilder("Blitz");
|
||||
if (costs.isEmpty()) {
|
||||
if (getCosts().isEmpty()) {
|
||||
sb.append(' ');
|
||||
} else {
|
||||
sb.append("—");
|
||||
}
|
||||
sb.append(manaCosts.getText());
|
||||
if (!costs.isEmpty()) {
|
||||
sb.append(getManaCosts().getText());
|
||||
if (!getCosts().isEmpty()) {
|
||||
sb.append(", ");
|
||||
sb.append(costs.getText());
|
||||
sb.append(getCosts().getText());
|
||||
sb.append('.');
|
||||
}
|
||||
sb.append(" <i>(If you cast this spell for its blitz cost, it gains haste ");
|
||||
|
|
|
|||
|
|
@ -144,9 +144,9 @@ public class BuybackAbility extends StaticAbility implements OptionalAdditionalS
|
|||
for (Iterator it = ((Costs) buybackCost).iterator(); it.hasNext(); ) {
|
||||
Cost cost = (Cost) it.next();
|
||||
if (cost instanceof ManaCostsImpl) {
|
||||
ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy());
|
||||
ability.addManaCostsToPay((ManaCostsImpl) cost.copy());
|
||||
} else {
|
||||
ability.getCosts().add(cost.copy());
|
||||
ability.addCost(cost.copy());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ public class CasualtyAbility extends StaticAbility implements OptionalAdditional
|
|||
|
||||
additionalCost.activate();
|
||||
for (Cost cost : ((Costs<Cost>) additionalCost)) {
|
||||
ability.getCosts().add(cost.copy());
|
||||
ability.addCost(cost.copy());
|
||||
}
|
||||
game.fireReflexiveTriggeredAbility(new ReflexiveTriggeredAbility(
|
||||
new CopySourceSpellEffect(), false, "when you do, copy this spell"
|
||||
|
|
|
|||
|
|
@ -133,9 +133,9 @@ public class ConspireAbility extends StaticAbility implements OptionalAdditional
|
|||
ability.getAllEffects().setValue("ConspireActivation" + conspireId + addedById, true);
|
||||
for (Cost cost : (Costs<Cost>) conspireCost) {
|
||||
if (cost instanceof ManaCostsImpl) {
|
||||
ability.getManaCostsToPay().add((ManaCostsImpl<?>) cost.copy());
|
||||
ability.addManaCostsToPay((ManaCostsImpl<?>) cost.copy());
|
||||
} else {
|
||||
ability.getCosts().add(cost.copy());
|
||||
ability.addCost(cost.copy());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@ public class DisturbAbility extends SpellAbility {
|
|||
this.setSpellAbilityCastMode(SpellAbilityCastMode.DISTURB);
|
||||
|
||||
this.manaCost = manaCost;
|
||||
this.getManaCosts().clear();
|
||||
this.getManaCostsToPay().clear();
|
||||
this.clearManaCosts();
|
||||
this.clearManaCostsToPay();
|
||||
this.addManaCost(new ManaCostsImpl<>(manaCost));
|
||||
this.addSubAbility(new TransformAbility());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ public class EchoAbility extends TriggeredAbilityImpl {
|
|||
super(Zone.BATTLEFIELD, new EchoEffect(amount), false);
|
||||
this.amount = amount;
|
||||
this.echoPaid = false;
|
||||
this.echoCosts.add(costs);
|
||||
this.echoCosts.add(getCosts());
|
||||
this.lastController = null;
|
||||
this.manaEcho = true;
|
||||
this.rule = rule;
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ public class EmergeAbility extends SpellAbility {
|
|||
zone = Zone.HAND;
|
||||
spellAbilityType = SpellAbilityType.BASE_ALTERNATE;
|
||||
|
||||
this.getManaCosts().clear();
|
||||
this.getManaCostsToPay().clear();
|
||||
this.clearManaCosts();
|
||||
this.clearManaCostsToPay();
|
||||
this.addManaCost(emergeCost.copy());
|
||||
|
||||
this.setRuleAtTheTop(true);
|
||||
|
|
|
|||
|
|
@ -92,9 +92,9 @@ public class EntwineAbility extends StaticAbility implements OptionalAdditionalM
|
|||
for (Iterator it = ((Costs) entwineCost).iterator(); it.hasNext(); ) {
|
||||
Cost cost = (Cost) it.next();
|
||||
if (cost instanceof ManaCostsImpl) {
|
||||
ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy());
|
||||
ability.addManaCostsToPay((ManaCostsImpl) cost.copy());
|
||||
} else {
|
||||
ability.getCosts().add(cost.copy());
|
||||
ability.addCost(cost.copy());
|
||||
}
|
||||
}
|
||||
activateEntwine(game, ability);
|
||||
|
|
|
|||
|
|
@ -63,19 +63,19 @@ public class EquipAbility extends ActivatedAbilityImpl {
|
|||
@Override
|
||||
public String getRule() {
|
||||
String targetText = getTargets().get(0) != null ? getTargets().get(0).getFilter().getMessage() : "creature";
|
||||
String reminderText = " <i>(" + manaCosts.getText() + ": Attach to target " + targetText + ". Equip only as a sorcery.)</i>";
|
||||
String reminderText = " <i>(" + getManaCosts().getText() + ": Attach to target " + targetText + ". Equip only as a sorcery.)</i>";
|
||||
|
||||
StringBuilder sb = new StringBuilder("Equip");
|
||||
if (!targetText.equals("creature you control")) {
|
||||
sb.append(' ').append(targetText);
|
||||
}
|
||||
String costText = costs.getText();
|
||||
String costText = getCosts().getText();
|
||||
if (costText != null && !costText.isEmpty()) {
|
||||
sb.append("—").append(costText).append('.');
|
||||
} else {
|
||||
sb.append(' ');
|
||||
}
|
||||
sb.append(manaCosts.getText());
|
||||
sb.append(getManaCosts().getText());
|
||||
if (costReduceText != null && !costReduceText.isEmpty()) {
|
||||
sb.append(". ");
|
||||
sb.append(costReduceText);
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ public class EscapeAbility extends SpellAbility {
|
|||
|
||||
this.manaCost = manaCost;
|
||||
this.exileCount = exileCount;
|
||||
this.getManaCosts().clear();
|
||||
this.getManaCostsToPay().clear();
|
||||
this.clearManaCosts();
|
||||
this.clearManaCostsToPay();
|
||||
this.addManaCost(new ManaCostsImpl<>(manaCost));
|
||||
this.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(exileCount, filter), "")); // hide additional cost text from rules
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,9 +113,9 @@ public class FlashbackAbility extends SpellAbility {
|
|||
return null;
|
||||
}
|
||||
spellAbilityCopy.setId(this.getId());
|
||||
spellAbilityCopy.getManaCosts().clear();
|
||||
spellAbilityCopy.getManaCostsToPay().clear();
|
||||
spellAbilityCopy.getCosts().addAll(this.getCosts().copy());
|
||||
spellAbilityCopy.clearManaCosts();
|
||||
spellAbilityCopy.clearManaCostsToPay();
|
||||
spellAbilityCopy.addCost(this.getCosts().copy());
|
||||
spellAbilityCopy.addCost(this.getManaCosts().copy());
|
||||
spellAbilityCopy.setSpellAbilityCastMode(this.getSpellAbilityCastMode());
|
||||
spellAbilityToResolve = spellAbilityCopy;
|
||||
|
|
@ -148,19 +148,19 @@ public class FlashbackAbility extends SpellAbility {
|
|||
@Override
|
||||
public String getRule() {
|
||||
StringBuilder sbRule = new StringBuilder("Flashback");
|
||||
if (!costs.isEmpty()) {
|
||||
if (!getCosts().isEmpty()) {
|
||||
sbRule.append("—");
|
||||
} else {
|
||||
sbRule.append(' ');
|
||||
}
|
||||
if (!manaCosts.isEmpty()) {
|
||||
sbRule.append(manaCosts.getText());
|
||||
if (!getManaCosts().isEmpty()) {
|
||||
sbRule.append(getManaCosts().getText());
|
||||
}
|
||||
if (!costs.isEmpty()) {
|
||||
if (!manaCosts.isEmpty()) {
|
||||
if (!getCosts().isEmpty()) {
|
||||
if (!getManaCosts().isEmpty()) {
|
||||
sbRule.append(", ");
|
||||
}
|
||||
sbRule.append(costs.getText());
|
||||
sbRule.append(getCosts().getText());
|
||||
sbRule.append('.');
|
||||
}
|
||||
if (abilityName != null) {
|
||||
|
|
|
|||
|
|
@ -404,9 +404,9 @@ public class ForetellAbility extends SpecialAction {
|
|||
return null;
|
||||
}
|
||||
spellAbilityCopy.setId(this.getId());
|
||||
spellAbilityCopy.getManaCosts().clear();
|
||||
spellAbilityCopy.getManaCostsToPay().clear();
|
||||
spellAbilityCopy.getCosts().addAll(this.getCosts().copy());
|
||||
spellAbilityCopy.clearManaCosts();
|
||||
spellAbilityCopy.clearManaCostsToPay();
|
||||
spellAbilityCopy.addCost(this.getCosts().copy());
|
||||
spellAbilityCopy.addCost(this.getManaCosts().copy());
|
||||
spellAbilityCopy.setSpellAbilityCastMode(this.getSpellAbilityCastMode());
|
||||
spellAbilityToResolve = spellAbilityCopy;
|
||||
|
|
@ -431,19 +431,19 @@ public class ForetellAbility extends SpecialAction {
|
|||
@Override
|
||||
public String getRule(boolean all) {
|
||||
StringBuilder sbRule = new StringBuilder("Foretell");
|
||||
if (!costs.isEmpty()) {
|
||||
if (!getCosts().isEmpty()) {
|
||||
sbRule.append("—");
|
||||
} else {
|
||||
sbRule.append(' ');
|
||||
}
|
||||
if (!manaCosts.isEmpty()) {
|
||||
sbRule.append(manaCosts.getText());
|
||||
if (!getManaCosts().isEmpty()) {
|
||||
sbRule.append(getManaCosts().getText());
|
||||
}
|
||||
if (!costs.isEmpty()) {
|
||||
if (!manaCosts.isEmpty()) {
|
||||
if (!getCosts().isEmpty()) {
|
||||
if (!getManaCosts().isEmpty()) {
|
||||
sbRule.append(", ");
|
||||
}
|
||||
sbRule.append(costs.getText());
|
||||
sbRule.append(getCosts().getText());
|
||||
sbRule.append('.');
|
||||
}
|
||||
if (abilityName != null) {
|
||||
|
|
|
|||
|
|
@ -44,6 +44,6 @@ public class FortifyAbility extends ActivatedAbilityImpl {
|
|||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Fortify " + costs.getText() + manaCosts.getText() + " (" + manaCosts.getText() + ": <i>Attach to target land you control. Fortify only as a sorcery.)</i>";
|
||||
return "Fortify " + getCosts().getText() + getManaCosts().getText() + " (" + getManaCosts().getText() + ": <i>Attach to target land you control. Fortify only as a sorcery.)</i>";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -282,9 +282,9 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
|
|||
// can contain multiple costs from multikicker ability
|
||||
// must be additional cost type
|
||||
if (cost instanceof ManaCostsImpl) {
|
||||
ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy());
|
||||
ability.addManaCostsToPay((ManaCostsImpl) cost.copy());
|
||||
} else {
|
||||
ability.getCosts().add(cost.copy());
|
||||
ability.addCost(cost.copy());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ public class LevelUpAbility extends ActivatedAbilityImpl {
|
|||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return new StringBuilder("Level up ").append(manaCostsToPay.getText())
|
||||
.append(" <i>(").append(manaCostsToPay.getText()).append(": Put a level counter on this. Level up only as a sorcery.)</i>").toString();
|
||||
return new StringBuilder("Level up ").append(getManaCostsToPay().getText())
|
||||
.append(" <i>(").append(getManaCostsToPay().getText()).append(": Put a level counter on this. Level up only as a sorcery.)</i>").toString();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -267,7 +267,7 @@ class MadnessCastEffect extends OneShotEffect {
|
|||
ManaCosts<ManaCost> costRef = castByMadness.getManaCostsToPay();
|
||||
castByMadness.setSpellAbilityType(SpellAbilityType.BASE_ALTERNATE);
|
||||
castByMadness.setSpellAbilityCastMode(SpellAbilityCastMode.MADNESS);
|
||||
castByMadness.getCosts().clear();
|
||||
castByMadness.clearCosts();
|
||||
castByMadness.addCost(new PayLifeCost(this.lifeCost));
|
||||
costRef.clear();
|
||||
costRef.add(madnessCost);
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ public class MeditateAbility extends ActivatedAbilityImpl {
|
|||
|
||||
@Override
|
||||
public String getRule() {
|
||||
StringBuilder sb = new StringBuilder("Meditate ").append(manaCosts.getText());
|
||||
StringBuilder sb = new StringBuilder("Meditate ").append(getManaCosts().getText());
|
||||
sb.append(" <i>(Return this creature to its owner's hand. Meditate only as a sorcery.)</i>");
|
||||
return sb.toString();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ public class MoreThanMeetsTheEyeAbility extends SpellAbility {
|
|||
this.setSpellAbilityCastMode(SpellAbilityCastMode.MORE_THAN_MEETS_THE_EYE);
|
||||
|
||||
this.manaCost = manaCost;
|
||||
this.getManaCosts().clear();
|
||||
this.getManaCostsToPay().clear();
|
||||
this.clearManaCosts();
|
||||
this.clearManaCostsToPay();
|
||||
this.addManaCost(new ManaCostsImpl<>(manaCost));
|
||||
this.addSubAbility(new TransformAbility());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public class OutlastAbility extends ActivatedAbilityImpl {
|
|||
|
||||
@Override
|
||||
public String getRule() {
|
||||
StringBuilder sb = new StringBuilder("Outlast ").append(manaCosts.getText());
|
||||
StringBuilder sb = new StringBuilder("Outlast ").append(getManaCosts().getText());
|
||||
sb.append(" <i>(").append(getManaCosts().getText()).append(", ").append(getCosts().getText()).append(": Put a +1/+1 counter on this creature. Outlast only as a sorcery.)</i>");
|
||||
return sb.toString();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,9 +106,9 @@ public class ReplicateAbility extends StaticAbility implements OptionalAdditiona
|
|||
for (Iterator it = ((Costs) additionalCost).iterator(); it.hasNext(); ) {
|
||||
Cost cost = (Cost) it.next();
|
||||
if (cost instanceof ManaCostsImpl) {
|
||||
ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy());
|
||||
ability.addManaCostsToPay((ManaCostsImpl) cost.copy());
|
||||
} else {
|
||||
ability.getCosts().add(cost.copy());
|
||||
ability.addCost(cost.copy());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ public class SpectacleAbility extends SpellAbility {
|
|||
zone = Zone.HAND;
|
||||
spellAbilityType = SpellAbilityType.BASE_ALTERNATE;
|
||||
|
||||
this.getManaCosts().clear();
|
||||
this.getManaCostsToPay().clear();
|
||||
this.clearManaCosts();
|
||||
this.clearManaCostsToPay();
|
||||
this.addManaCost(spectacleCosts.copy());
|
||||
|
||||
this.setRuleAtTheTop(true);
|
||||
|
|
|
|||
|
|
@ -174,9 +174,9 @@ class SpliceCardEffectImpl extends ContinuousEffectImpl implements SpliceCardEff
|
|||
for (Iterator it = ((SpliceAbility) source).getSpliceCosts().iterator(); it.hasNext();) {
|
||||
Cost cost = (Cost) it.next();
|
||||
if (cost instanceof ManaCost) {
|
||||
spell.getSpellAbility().getManaCostsToPay().add((ManaCost) cost.copy());
|
||||
spell.getSpellAbility().addManaCostsToPay((ManaCost) cost.copy());
|
||||
} else {
|
||||
spell.getSpellAbility().getCosts().add(cost.copy());
|
||||
spell.getSpellAbility().addCost(cost.copy());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ public class SurgeAbility extends SpellAbility {
|
|||
zone = Zone.HAND;
|
||||
spellAbilityType = SpellAbilityType.BASE_ALTERNATE;
|
||||
|
||||
this.getManaCosts().clear();
|
||||
this.getManaCostsToPay().clear();
|
||||
this.clearManaCosts();
|
||||
this.clearManaCostsToPay();
|
||||
this.addManaCost(new ManaCostsImpl<>(surgeCosts));
|
||||
|
||||
this.setRuleAtTheTop(true);
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ class AdventureCardSpellAbility extends SpellAbility {
|
|||
StringBuilder sbRule = new StringBuilder();
|
||||
sbRule.append(this.nameFull);
|
||||
sbRule.append(" ");
|
||||
sbRule.append(manaCosts.getText());
|
||||
sbRule.append(getManaCosts().getText());
|
||||
sbRule.append(" — ");
|
||||
Modes modes = this.getModes();
|
||||
if (modes.size() <= 1) {
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ public interface Card extends MageObject {
|
|||
CommanderPlaysCountWatcher watcher = game.getState().getWatcher(CommanderPlaysCountWatcher.class);
|
||||
int castCount = watcher.getPlaysCount(getMainCard().getId());
|
||||
if (castCount > 0) {
|
||||
abilityToModify.getManaCostsToPay().add(ManaUtil.createManaCost(2 * castCount, false));
|
||||
abilityToModify.addManaCostsToPay(ManaUtil.createManaCost(2 * castCount, false));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -394,7 +394,13 @@ public class StackAbility extends StackObjectImpl implements Ability {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void addManaCost(ManaCost cost) {
|
||||
public void addManaCost(ManaCost manaCost) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addManaCostsToPay(ManaCost manaCost) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1194,15 +1194,12 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
if (alternateCosts == null) {
|
||||
noMana = true;
|
||||
} else {
|
||||
spellAbility.getManaCosts().clear();
|
||||
spellAbility.getManaCostsToPay().clear();
|
||||
spellAbility.getManaCosts().add(alternateCosts.copy());
|
||||
spellAbility.getManaCostsToPay().add(alternateCosts.copy());
|
||||
}
|
||||
spellAbility.getCosts().clear();
|
||||
if (costs != null) {
|
||||
spellAbility.getCosts().addAll(costs);
|
||||
spellAbility.clearManaCosts();
|
||||
spellAbility.clearManaCostsToPay();
|
||||
spellAbility.addManaCost(alternateCosts.copy());
|
||||
}
|
||||
spellAbility.clearCosts();
|
||||
spellAbility.addCost(costs);
|
||||
}
|
||||
clearCastSourceIdManaCosts(); // TODO: test multiple alternative cost for different cards as same time
|
||||
|
||||
|
|
@ -3620,8 +3617,8 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
// alternative cost reduce
|
||||
copyAbility = ability.copy();
|
||||
copyAbility.getManaCostsToPay().clear();
|
||||
copyAbility.getManaCostsToPay().addAll(manaCosts.copy());
|
||||
copyAbility.clearManaCostsToPay();
|
||||
copyAbility.addManaCostsToPay(manaCosts.copy());
|
||||
copyAbility.adjustCosts(game);
|
||||
game.getContinuousEffects().costModification(copyAbility, game);
|
||||
|
||||
|
|
@ -3686,12 +3683,12 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
|
||||
// alternative cost reduce
|
||||
copyAbility = ability.copy();
|
||||
copyAbility.getManaCostsToPay().clear();
|
||||
copyAbility.clearManaCostsToPay();
|
||||
// TODO: IDE warning:
|
||||
// Unchecked assignment: 'mage.abilities.costs.mana.ManaCosts' to
|
||||
// 'java.util.Collection<? extends mage.abilities.costs.mana.ManaCost>'.
|
||||
// Reason: 'manaCosts' has raw type, so result of copy is erased
|
||||
copyAbility.getManaCostsToPay().addAll(manaCosts.copy());
|
||||
copyAbility.addManaCostsToPay(manaCosts.copy());
|
||||
copyAbility.adjustCosts(game);
|
||||
game.getContinuousEffects().costModification(copyAbility, game);
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import java.util.Map;
|
|||
public abstract class TargetPointerImpl implements TargetPointer {
|
||||
|
||||
// Store custom data here. Use it to keep unique values for ability instances on stack (example: Gruul Ragebeast)
|
||||
Map<String, String> data = new HashMap<>();
|
||||
private Map<String, String> data;
|
||||
|
||||
public TargetPointerImpl() {
|
||||
super();
|
||||
|
|
@ -17,17 +17,26 @@ public abstract class TargetPointerImpl implements TargetPointer {
|
|||
|
||||
protected TargetPointerImpl(final TargetPointerImpl targetPointer) {
|
||||
super();
|
||||
this.data.putAll(targetPointer.data);
|
||||
if (targetPointer.data != null) {
|
||||
this.data = new HashMap<>();
|
||||
this.data.putAll(targetPointer.data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getData(String key) {
|
||||
return this.data.getOrDefault(key, "");
|
||||
if (data == null) {
|
||||
return "";
|
||||
}
|
||||
return data.getOrDefault(key, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetPointer withData(String key, String value) {
|
||||
this.data.put(key, value);
|
||||
if (data == null) {
|
||||
data = new HashMap<>();
|
||||
}
|
||||
data.put(key, value);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,8 +141,8 @@ public final class CardUtil {
|
|||
*/
|
||||
private static void adjustAbilityCost(Ability ability, int reduceCount) {
|
||||
ManaCosts<ManaCost> adjustedCost = adjustCost(ability.getManaCostsToPay(), reduceCount);
|
||||
ability.getManaCostsToPay().clear();
|
||||
ability.getManaCostsToPay().addAll(adjustedCost);
|
||||
ability.clearManaCostsToPay();
|
||||
ability.addManaCostsToPay(adjustedCost);
|
||||
}
|
||||
|
||||
private static ManaCosts<ManaCost> adjustCost(ManaCosts<ManaCost> manaCosts, int reduceCount) {
|
||||
|
|
@ -304,8 +304,8 @@ public final class CardUtil {
|
|||
increasedCost.add(manaCost.copy());
|
||||
}
|
||||
|
||||
spellAbility.getManaCostsToPay().clear();
|
||||
spellAbility.getManaCostsToPay().addAll(increasedCost);
|
||||
spellAbility.clearManaCostsToPay();
|
||||
spellAbility.addManaCostsToPay(increasedCost);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -468,8 +468,8 @@ public final class CardUtil {
|
|||
adjustedCost.add(new GenericManaCost(0)); // neede to check if cost was reduced to 0
|
||||
}
|
||||
adjustedCost.setSourceFilter(previousCost.getSourceFilter()); // keep mana source restrictions
|
||||
spellAbility.getManaCostsToPay().clear();
|
||||
spellAbility.getManaCostsToPay().addAll(adjustedCost);
|
||||
spellAbility.clearManaCostsToPay();
|
||||
spellAbility.addManaCostsToPay(adjustedCost);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue