mirror of
https://github.com/magefree/mage.git
synced 2025-12-26 05:22:02 -08:00
* Kicker - added support of X and mana cost interactions like Rosheen Meanderer + Verdeloth the Ancient combo (#3538);
* Rosheen Meanderer - fixed that mana can be payed for mana cost with X instead any cost with X (#3538);
This commit is contained in:
parent
49fc094546
commit
cc54a92daa
7 changed files with 216 additions and 147 deletions
|
|
@ -0,0 +1,73 @@
|
|||
package mage.abilities.dynamicvalue.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.OptionalAdditionalCost;
|
||||
import mage.abilities.costs.OptionalAdditionalCostImpl;
|
||||
import mage.abilities.costs.VariableCost;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.keyword.KickerAbility;
|
||||
import mage.game.Game;
|
||||
import mage.game.stack.Spell;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public enum GetKickerXValue implements DynamicValue {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public int calculate(Game game, Ability source, Effect effect) {
|
||||
// calcs only kicker with X values
|
||||
|
||||
// kicker adds additional costs to spell ability
|
||||
// only one X value per card possible
|
||||
// kicker can be calls multiple times (use getKickedCounter)
|
||||
|
||||
int finalValue = 0;
|
||||
Spell spell = game.getSpellOrLKIStack(source.getSourceId());
|
||||
if (spell != null && spell.getSpellAbility() != null) {
|
||||
int xValue = spell.getSpellAbility().getManaCostsToPay().getX();
|
||||
for (Ability ability : spell.getAbilities()) {
|
||||
if (ability instanceof KickerAbility) {
|
||||
|
||||
// search that kicker used X value
|
||||
KickerAbility kickerAbility = (KickerAbility) ability;
|
||||
boolean haveVarCost = false;
|
||||
for (OptionalAdditionalCost cost : kickerAbility.getKickerCosts()) {
|
||||
List<VariableCost> varCosts = ((OptionalAdditionalCostImpl) cost).getVariableCosts();
|
||||
if (!varCosts.isEmpty()) {
|
||||
haveVarCost = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (haveVarCost) {
|
||||
int kickedCount = ((KickerAbility) ability).getKickedCounter(game, source);
|
||||
if (kickedCount > 0) {
|
||||
finalValue += kickedCount * xValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return finalValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GetKickerXValue copy() {
|
||||
return GetKickerXValue.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "X";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +1,10 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.StaticAbility;
|
||||
import mage.abilities.costs.*;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.costs.mana.VariableManaCost;
|
||||
import mage.constants.AbilityType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
|
|
@ -17,6 +12,12 @@ import mage.game.Game;
|
|||
import mage.game.events.GameEvent;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 20121001 702.31. Kicker 702.31a Kicker is a static ability that functions
|
||||
* while the spell with kicker is on the stack. "Kicker [cost]" means "You may
|
||||
|
|
@ -57,7 +58,6 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
|
|||
protected String keywordText;
|
||||
protected String reminderText;
|
||||
protected List<OptionalAdditionalCost> kickerCosts = new LinkedList<>();
|
||||
private int xManaValue = 0;
|
||||
|
||||
public KickerAbility(String manaString) {
|
||||
this(KICKER_KEYWORD, KICKER_REMINDER_MANA);
|
||||
|
|
@ -79,10 +79,11 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
|
|||
|
||||
public KickerAbility(final KickerAbility ability) {
|
||||
super(ability);
|
||||
this.kickerCosts.addAll(ability.kickerCosts);
|
||||
for (OptionalAdditionalCost cost : ability.kickerCosts) {
|
||||
this.kickerCosts.add((OptionalAdditionalCost) cost.copy());
|
||||
}
|
||||
this.keywordText = ability.keywordText;
|
||||
this.reminderText = ability.reminderText;
|
||||
this.xManaValue = ability.xManaValue;
|
||||
this.activations.putAll(ability.activations);
|
||||
}
|
||||
|
||||
|
|
@ -108,7 +109,7 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
|
|||
cost.reset();
|
||||
}
|
||||
String key = getActivationKey(source, "", game);
|
||||
for (Iterator<String> iterator = activations.keySet().iterator(); iterator.hasNext();) {
|
||||
for (Iterator<String> iterator = activations.keySet().iterator(); iterator.hasNext(); ) {
|
||||
String activationKey = iterator.next();
|
||||
if (activationKey.startsWith(key) && activations.get(activationKey) > 0) {
|
||||
activations.put(key, 0);
|
||||
|
|
@ -116,10 +117,6 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
|
|||
}
|
||||
}
|
||||
|
||||
public int getXManaValue() {
|
||||
return xManaValue;
|
||||
}
|
||||
|
||||
public int getKickedCounter(Game game, Ability source) {
|
||||
String key = getActivationKey(source, "", game);
|
||||
return activations.getOrDefault(key, 0);
|
||||
|
|
@ -167,7 +164,7 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
|
|||
if (zcc > 0 && (source.getAbilityType() == AbilityType.TRIGGERED)) {
|
||||
--zcc;
|
||||
}
|
||||
return String.valueOf(zcc) + ((kickerCosts.size() > 1) ? costText : "");
|
||||
return zcc + ((kickerCosts.size() > 1) ? costText : "");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -182,16 +179,16 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
|
|||
String times = "";
|
||||
if (kickerCost.isRepeatable()) {
|
||||
int activatedCount = getKickedCounter(game, ability);
|
||||
times = Integer.toString(activatedCount + 1) + (activatedCount == 0 ? " time " : " times ");
|
||||
times = (activatedCount + 1) + (activatedCount == 0 ? " time " : " times ");
|
||||
}
|
||||
if (kickerCost.canPay(ability, sourceId, controllerId, game)
|
||||
&& player.chooseUse(Outcome.Benefit, "Pay " + times + kickerCost.getText(false) + " ?", ability, game)) {
|
||||
this.activateKicker(kickerCost, ability, game);
|
||||
if (kickerCost instanceof Costs) {
|
||||
for (Iterator itKickerCost = ((Costs) kickerCost).iterator(); itKickerCost.hasNext();) {
|
||||
for (Iterator itKickerCost = ((Costs) kickerCost).iterator(); itKickerCost.hasNext(); ) {
|
||||
Object kickerCostObject = itKickerCost.next();
|
||||
if ((kickerCostObject instanceof Costs) || (kickerCostObject instanceof CostsImpl)) {
|
||||
for (@SuppressWarnings("unchecked") Iterator<Cost> itDetails = ((Costs) kickerCostObject).iterator(); itDetails.hasNext();) {
|
||||
for (@SuppressWarnings("unchecked") Iterator<Cost> itDetails = ((Costs) kickerCostObject).iterator(); itDetails.hasNext(); ) {
|
||||
addKickerCostsToAbility(itDetails.next(), ability, game);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -199,7 +196,7 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
|
|||
}
|
||||
}
|
||||
} else {
|
||||
addKickerCostsToAbility((Cost) kickerCost, ability, game);
|
||||
addKickerCostsToAbility(kickerCost, ability, game);
|
||||
}
|
||||
again = kickerCost.isRepeatable();
|
||||
} else {
|
||||
|
|
@ -212,26 +209,9 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
|
|||
}
|
||||
|
||||
private void addKickerCostsToAbility(Cost cost, Ability ability, Game game) {
|
||||
// can contains multiple costs from multikicker ability
|
||||
if (cost instanceof ManaCostsImpl) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<VariableManaCost> varCosts = ((ManaCostsImpl) cost).getVariableCosts();
|
||||
if (!varCosts.isEmpty()) {
|
||||
// use only first variable cost
|
||||
xManaValue = game.getPlayer(this.controllerId).announceXMana(varCosts.get(0).getMinX(), Integer.MAX_VALUE, "Announce kicker value for " + varCosts.get(0).getText(), game, this);
|
||||
// kicker variable X costs handled internally as multikicker with {1} cost (no multikicker on card)
|
||||
if (!game.isSimulation()) {
|
||||
game.informPlayers(game.getPlayer(this.controllerId).getLogName() + " announced a value of " + xManaValue + " for " + " kicker X ");
|
||||
}
|
||||
ability.getManaCostsToPay().add(new GenericManaCost(xManaValue));
|
||||
ManaCostsImpl<ManaCost> kickerManaCosts = (ManaCostsImpl) cost;
|
||||
for (ManaCost manaCost : kickerManaCosts) {
|
||||
if (!(manaCost instanceof VariableManaCost)) {
|
||||
ability.getManaCostsToPay().add(manaCost.copy());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy());
|
||||
}
|
||||
ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy());
|
||||
} else {
|
||||
ability.getCosts().add(cost.copy());
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue