Merge branch 'master' into akh-card-frame

This commit is contained in:
Mark Langen 2017-04-04 18:36:37 -06:00 committed by GitHub
commit a2e8cedd02
272 changed files with 7641 additions and 2593 deletions

View file

@ -29,6 +29,7 @@ package mage.abilities;
import java.io.Serializable;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import mage.abilities.keyword.ProtectionAbility;
import mage.abilities.mana.ActivatedManaAbilityImpl;
@ -245,7 +246,7 @@ public interface Abilities<T extends Ability> extends List<T>, Serializable {
* @param abilityId
* @return
*/
T get(UUID abilityId);
Optional<T> get(UUID abilityId);
/**
* TODO The usage of this method seems redundant to that of

View file

@ -27,13 +27,6 @@
*/
package mage.abilities;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import mage.abilities.common.ZoneChangeTriggeredAbility;
import mage.abilities.costs.Cost;
import mage.abilities.keyword.ProtectionAbility;
@ -44,6 +37,8 @@ import mage.game.Game;
import mage.util.ThreadLocalStringBuilder;
import org.apache.log4j.Logger;
import java.util.*;
/**
* @param <T>
* @author BetaSteward_at_googlemail.com
@ -277,12 +272,7 @@ public class AbilitiesImpl<T extends Ability> extends ArrayList<T> implements Ab
@Override
public boolean containsRule(T ability) {
for (T test : this) {
if (ability.getRule().equals(test.getRule())) {
return true;
}
}
return false;
return stream().anyMatch(rule -> rule.getRule().equals(ability.getRule()));
}
@Override
@ -301,32 +291,16 @@ public class AbilitiesImpl<T extends Ability> extends ArrayList<T> implements Ab
@Override
public boolean containsKey(UUID abilityId) {
for (T ability : this) {
if (ability.getId().equals(abilityId)) {
return true;
}
}
return false;
return stream().anyMatch(ability -> ability.getId().equals(abilityId));
}
@Override
public boolean containsClass(Class classObject) {
for (T ability : this) {
if (ability.getClass().equals(classObject)) {
return true;
}
}
return false;
return stream().anyMatch(ability -> ability.getClass().equals(classObject));
}
@Override
public T get(UUID abilityId) {
for (T ability : this) {
if (ability.getId().equals(abilityId)) {
return ability;
}
}
return null;
public Optional<T> get(UUID abilityId) {
return stream().filter(ability -> ability.getId().equals(abilityId)).findFirst();
}
@Override

View file

@ -27,6 +27,10 @@
*/
package mage.abilities;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import mage.MageObject;
import mage.MageObjectReference;
import mage.Mana;
@ -59,11 +63,6 @@ import mage.util.ThreadLocalStringBuilder;
import mage.watchers.Watcher;
import org.apache.log4j.Logger;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
/**
* @author BetaSteward_at_googlemail.com
*/
@ -489,7 +488,7 @@ public abstract class AbilityImpl implements Ability {
protected String handleOtherXCosts(Game game, Player controller) {
StringBuilder announceString = new StringBuilder();
for (VariableCost variableCost : this.costs.getVariableCosts()) {
if (!(variableCost instanceof VariableManaCost)) {
if (!(variableCost instanceof VariableManaCost) && !((Cost) variableCost).isPaid()) {
int xValue = variableCost.announceXValue(this, game);
Cost fixedCost = variableCost.getFixedCostsFromAnnouncedValue(xValue);
if (fixedCost != null) {
@ -506,19 +505,20 @@ public abstract class AbilityImpl implements Ability {
}
/**
* 601.2b
* If a cost that will be paid as the spell is being cast includes Phyrexian mana symbols,
* the player announces whether he or she intends to pay 2 life or the corresponding colored mana cost for each of those symbols.
* 601.2b If a cost that will be paid as the spell is being cast includes
* Phyrexian mana symbols, the player announces whether he or she intends to
* pay 2 life or the corresponding colored mana cost for each of those
* symbols.
*/
private void handlePhyrexianManaCosts(Game game, UUID sourceId, Player controller) {
Iterator<ManaCost> costIterator = manaCostsToPay.iterator();
while(costIterator.hasNext()) {
while (costIterator.hasNext()) {
ManaCost cost = costIterator.next();
if(cost instanceof PhyrexianManaCost) {
PhyrexianManaCost phyrexianManaCost = (PhyrexianManaCost)cost;
if (cost instanceof PhyrexianManaCost) {
PhyrexianManaCost phyrexianManaCost = (PhyrexianManaCost) cost;
PayLifeCost payLifeCost = new PayLifeCost(2);
if(payLifeCost.canPay(this, sourceId, controller.getId(), game) &&
controller.chooseUse(Outcome.LoseLife, "Pay 2 life instead of " + phyrexianManaCost.getBaseText() + '?', this, game)) {
if (payLifeCost.canPay(this, sourceId, controller.getId(), game)
&& controller.chooseUse(Outcome.LoseLife, "Pay 2 life instead of " + phyrexianManaCost.getBaseText() + '?', this, game)) {
costIterator.remove();
costs.add(payLifeCost);
}
@ -558,7 +558,11 @@ public abstract class AbilityImpl implements Ability {
} else {
String manaSymbol = null;
if (variableManaCost.getFilter().isBlack()) {
manaSymbol = "B";
if (variableManaCost.getFilter().isRed()) {
manaSymbol = "B/R";
} else {
manaSymbol = "B";
}
} else if (variableManaCost.getFilter().isRed()) {
manaSymbol = "R";
} else if (variableManaCost.getFilter().isBlue()) {

View file

@ -28,20 +28,21 @@
package mage.abilities;
import java.util.Iterator;
import mage.constants.Duration;
import mage.game.Game;
import mage.game.events.GameEvent;
import java.util.Iterator;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class DelayedTriggeredAbilities extends AbilitiesImpl<DelayedTriggeredAbility> {
public class DelayedTriggeredAbilities extends AbilitiesImpl<DelayedTriggeredAbility> {
public DelayedTriggeredAbilities() {}
public DelayedTriggeredAbilities() {
}
public DelayedTriggeredAbilities(final DelayedTriggeredAbilities abilities) {
public DelayedTriggeredAbilities(final DelayedTriggeredAbilities abilities) {
super(abilities);
}
@ -52,9 +53,9 @@ import mage.game.events.GameEvent;
public void checkTriggers(GameEvent event, Game game) {
if (this.size() > 0) {
for (Iterator<DelayedTriggeredAbility> it = this.iterator();it.hasNext();) {
for (Iterator<DelayedTriggeredAbility> it = this.iterator(); it.hasNext(); ) {
DelayedTriggeredAbility ability = it.next();
if (ability.getDuration()== Duration.Custom){
if (ability.getDuration() == Duration.Custom) {
if (ability.isInactive(game)) {
it.remove();
continue;

View file

@ -45,7 +45,6 @@ import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.targetpointer.FixedTarget;
import mage.util.CardUtil;
/**
*
@ -126,7 +125,7 @@ class KinshipBaseEffect extends OneShotEffect {
if (card != null) {
Cards cards = new CardsImpl(card);
controller.lookAtCards(sourcePermanent.getName(), cards, game);
if (CardUtil.shareSubtypes(sourcePermanent, card, game)) {
if (sourcePermanent.shareSubtypes(card, game)) {
if (controller.chooseUse(outcome,new StringBuilder("Kinship - Reveal ").append(card.getLogName()).append('?').toString(), source, game)) {
controller.revealCards(sourcePermanent.getName(), cards, game);
for (Effect effect: kinshipEffects) {

View file

@ -29,7 +29,9 @@ package mage.abilities.costs;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.keyword.FlashbackAbility;
import mage.game.Game;
import mage.game.stack.StackObject;
import mage.players.Player;
import mage.target.Target;
import mage.target.Targets;
@ -131,13 +133,15 @@ public abstract class VariableCostImpl implements Cost, VariableCost {
@Override
public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) {
return true; /* not used */
return true;
/* not used */
}
@Override
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) {
return true; /* not used */
return true;
/* not used */
}
@ -165,7 +169,9 @@ public abstract class VariableCostImpl implements Cost, VariableCost {
public int announceXValue(Ability source, Game game) {
int xValue = 0;
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
StackObject stackObject = game.getStack().getStackObject(source.getId());
if (controller != null
&& (source instanceof FlashbackAbility || stackObject != null)) {
xValue = controller.announceXCost(getMinValue(source, game), getMaxValue(source, game),
"Announce the number of " + actionText, game, source, this);
}

View file

@ -25,7 +25,6 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.costs.common;
import mage.abilities.Ability;
@ -40,7 +39,6 @@ import mage.target.common.TargetCardInHand;
*
* @author LevelX2
*/
public class DiscardXTargetCost extends VariableCostImpl {
protected FilterCard filter;
@ -50,9 +48,8 @@ public class DiscardXTargetCost extends VariableCostImpl {
}
public DiscardXTargetCost(FilterCard filter, boolean additionalCostText) {
super(new StringBuilder(filter.getMessage()).append(" to discard").toString());
this.text = new StringBuilder(additionalCostText ? "As an additional cost to cast {source}, discard ":"Discard ")
.append(xText).append(' ').append(filter.getMessage()).toString();
super(filter.getMessage() + " to discard");
this.text = (additionalCostText ? "As an additional cost to cast {source}, discard " : "Discard ") + xText + ' ' + filter.getMessage();
this.filter = filter;
}

View file

@ -40,6 +40,15 @@ import mage.players.ManaPoolItem;
public interface AsThoughManaEffect extends AsThoughEffect {
// return a mana type that can be used to pay a mana cost instead of the normally needed mana type
/**
*
* @param manaType type of mana with which the player wants to pay the cost
* @param mana mana pool item to pay from the cost
* @param affectedControllerId
* @param source
* @param game
* @return
*/
ManaType getAsThoughManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game);
}

View file

@ -27,6 +27,9 @@
*/
package mage.abilities.effects;
import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;
import mage.MageObject;
import mage.abilities.*;
import mage.abilities.keyword.SpliceOntoArcaneAbility;
@ -49,10 +52,6 @@ import mage.players.Player;
import mage.target.common.TargetCardInHand;
import org.apache.log4j.Logger;
import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;
/**
* @author BetaSteward_at_googlemail.com
*/
@ -691,8 +690,7 @@ public class ContinuousEffects implements Serializable {
spliceAbilities.remove(selectedAbility);
}
}
}
while (!spliceAbilities.isEmpty() && controller.chooseUse(Outcome.Benefit, "Splice another card?", abilityToModify, game));
} while (!spliceAbilities.isEmpty() && controller.chooseUse(Outcome.Benefit, "Splice another card?", abilityToModify, game));
controller.revealCards("Spliced cards", cardsToReveal, game);
}
}
@ -702,10 +700,10 @@ public class ContinuousEffects implements Serializable {
* Checks if an event won't happen because of an rule modifying effect
*
* @param event
* @param targetAbility ability the event is attached to. can be null.
* @param targetAbility ability the event is attached to. can be null.
* @param game
* @param checkPlayableMode true if the event does not really happen but
* it's checked if the event would be replaced
* it's checked if the event would be replaced
* @return
*/
public boolean preventedByRuleModification(GameEvent event, Ability targetAbility, Game game, boolean checkPlayableMode) {
@ -752,7 +750,7 @@ public class ContinuousEffects implements Serializable {
do {
HashMap<ReplacementEffect, HashSet<Ability>> rEffects = getApplicableReplacementEffects(event, game);
// Remove all consumed effects (ability dependant)
for (Iterator<ReplacementEffect> it1 = rEffects.keySet().iterator(); it1.hasNext(); ) {
for (Iterator<ReplacementEffect> it1 = rEffects.keySet().iterator(); it1.hasNext();) {
ReplacementEffect entry = it1.next();
if (consumed.containsKey(entry.getId())) {
HashSet<UUID> consumedAbilitiesIds = consumed.get(entry.getId());
@ -933,7 +931,7 @@ public class ContinuousEffects implements Serializable {
if (!waitingEffects.isEmpty()) {
// check if waiting effects can be applied now
for (Iterator<Map.Entry<ContinuousEffect, Set<UUID>>> iterator = waitingEffects.entrySet().iterator(); iterator.hasNext(); ) {
for (Iterator<Map.Entry<ContinuousEffect, Set<UUID>>> iterator = waitingEffects.entrySet().iterator(); iterator.hasNext();) {
Map.Entry<ContinuousEffect, Set<UUID>> entry = iterator.next();
if (appliedEffects.containsAll(entry.getValue())) { // all dependent to effects are applied now so apply the effect itself
appliedAbilities = appliedEffectAbilities.get(entry.getKey());

View file

@ -148,6 +148,7 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl {
if (spell != null) {
effect.setValue(SOURCE_CAST_SPELL_ABILITY, spell.getSpellAbility());
}
effect.setValue("appliedEffects", event.getAppliedEffects());
effect.apply(game, source);
}
// }

View file

@ -48,7 +48,7 @@ public class EndTurnEffect extends OneShotEffect {
if (!game.isSimulation()) {
game.informPlayers("The current turn ends");
}
return game.endTurn();
return game.endTurn(source);
}
@Override

View file

@ -27,6 +27,8 @@
*/
package mage.abilities.effects.common;
import java.util.ArrayList;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.effects.EntersBattlefieldEffect;
@ -75,7 +77,8 @@ public class EntersBattlefieldWithXCountersEffect extends OneShotEffect {
if (amount > 0) {
Counter counterToAdd = counter.copy();
counterToAdd.add(amount - counter.getCount());
permanent.addCounters(counterToAdd, source, game);
ArrayList<UUID> appliedEffects = (ArrayList<UUID>) this.getValue("appliedEffects");
permanent.addCounters(counterToAdd, source, game, appliedEffects);
}
}
}

View file

@ -27,6 +27,8 @@
*/
package mage.abilities.effects.common.counter;
import java.util.ArrayList;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.StaticValue;
@ -103,7 +105,8 @@ public class AddCountersSourceEffect extends OneShotEffect {
countersToAdd--;
}
newCounter.add(countersToAdd);
card.addCounters(newCounter, source, game);
ArrayList<UUID> appliedEffects = (ArrayList<UUID>) this.getValue("appliedEffects");
card.addCounters(newCounter, source, game, appliedEffects);
if (informPlayers && !game.isSimulation()) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
@ -128,7 +131,8 @@ public class AddCountersSourceEffect extends OneShotEffect {
}
newCounter.add(countersToAdd);
int before = permanent.getCounters(game).getCount(newCounter.getName());
permanent.addCounters(newCounter, source, game);
ArrayList<UUID> appliedEffects = (ArrayList<UUID>) this.getValue("appliedEffects");
permanent.addCounters(newCounter, source, game, appliedEffects); // if used from a replacement effect, the basic event determines if an effect was already applied to an event
if (informPlayers && !game.isSimulation()) {
int amountAdded = permanent.getCounters(game).getCount(newCounter.getName()) - before;
Player player = game.getPlayer(source.getControllerId());
@ -150,12 +154,10 @@ public class AddCountersSourceEffect extends OneShotEffect {
sb.append("put ");
if (counter.getCount() > 1) {
sb.append(CardUtil.numberToText(counter.getCount())).append(' ');
} else if (amount.toString().equals("X") && amount.getMessage().isEmpty()) {
sb.append("X ");
} else {
if (amount.toString().equals("X") && amount.getMessage().isEmpty()) {
sb.append("X ");
} else {
sb.append("a ");
}
sb.append("a ");
}
sb.append(counter.getName().toLowerCase()).append(" counter on {this}");
if (!amount.getMessage().isEmpty()) {

View file

@ -1,5 +1,7 @@
package mage.abilities.keyword;
import java.util.ArrayList;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldAbility;
import mage.abilities.effects.OneShotEffect;
@ -71,7 +73,8 @@ class BloodthirstEffect extends OneShotEffect {
if (watcher != null && watcher.conditionMet()) {
Permanent permanent = game.getPermanentEntering(source.getSourceId());
if (permanent != null) {
permanent.addCounters(CounterType.P1P1.createInstance(amount), source, game);
ArrayList<UUID> appliedEffects = (ArrayList<UUID>) this.getValue("appliedEffects"); // the basic event is the EntersBattlefieldEvent, so use already applied replacement effects from that event
permanent.addCounters(CounterType.P1P1.createInstance(amount), source, game, appliedEffects);
}
}
return true;

View file

@ -0,0 +1,121 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.keyword;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.ActivatedAbilityImpl;
import mage.abilities.costs.Cost;
import mage.abilities.costs.common.ExileSourceFromGraveCost;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.constants.Outcome;
import mage.constants.TimingRule;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.token.EmptyToken;
import mage.players.Player;
import mage.util.CardUtil;
/**
*
* @author LevelX2
*/
public class EmbalmAbility extends ActivatedAbilityImpl {
private String rule;
public EmbalmAbility(Cost cost, Card card) {
super(Zone.GRAVEYARD, new EmbalmEffect(), cost);
addCost(new ExileSourceFromGraveCost());
this.rule = setRule(cost, card);
this.timing = TimingRule.SORCERY;
setRule(cost, card);
}
public EmbalmAbility(final EmbalmAbility ability) {
super(ability);
this.rule = ability.rule;
}
@Override
public EmbalmAbility copy() {
return new EmbalmAbility(this);
}
@Override
public String getRule() {
return rule;
}
private String setRule(Cost cost, Card card) {
StringBuilder sb = new StringBuilder("Embalm ").append(cost.getText());
sb.append(" <i>(").append(cost.getText());
sb.append(", Exile this card from your graveyard: Create a token that's a copy of it, except it's a white Zombie ");
for (String subtype : card.getSubtype(null)) {
sb.append(subtype).append(" ");
}
sb.append(" with no mana cost. Embalm only as a sorcery.)</i>");
return sb.toString();
}
}
class EmbalmEffect extends OneShotEffect {
public EmbalmEffect() {
super(Outcome.PutCreatureInPlay);
}
public EmbalmEffect(final EmbalmEffect effect) {
super(effect);
}
@Override
public EmbalmEffect copy() {
return new EmbalmEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Card card = game.getCard(source.getSourceId());
Player controller = game.getPlayer(source.getControllerId());
if (controller != null && card != null) {
EmptyToken token = new EmptyToken();
CardUtil.copyTo(token).from(card); // needed so that entersBattlefied triggered abilities see the attributes (e.g. Master Biomancer)
token.getColor(game).setColor(ObjectColor.WHITE);
if (!token.getSubtype(game).contains("Zombie")) {
token.getSubtype(game).add(0, "Zombie");
}
token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId(), false, false, null);
return true;
}
return false;
}
}

View file

@ -1,7 +1,6 @@
package mage.abilities.keyword;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
@ -14,7 +13,6 @@ import mage.target.targetpointer.FixedTarget;
/**
*
* @author Plopman
*/
@ -38,16 +36,12 @@ public class FlankingAbility extends TriggeredAbilityImpl {
public boolean checkTrigger(GameEvent event, Game game) {
if (event.getTargetId().equals(this.getSourceId())) {
Permanent permanent = game.getPermanent(event.getSourceId());
if(permanent != null)
{
boolean hasFlankingAbility = false;
for(Ability ability : permanent.getAbilities()){
if(ability instanceof FlankingAbility){
hasFlankingAbility = true;
}
}
if(!hasFlankingAbility){
if (permanent != null) {
boolean hasFlankingAbility =
permanent.getAbilities().stream().anyMatch(ability -> ability instanceof FlankingAbility);
if (!hasFlankingAbility) {
for (Effect effect : this.getEffects()) {
effect.setTargetPointer(new FixedTarget(event.getSourceId()));
}
@ -68,5 +62,5 @@ public class FlankingAbility extends TriggeredAbilityImpl {
return new FlankingAbility(this);
}
}

View file

@ -27,20 +27,10 @@
*/
package mage.abilities.keyword;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.StaticAbility;
import mage.abilities.costs.Cost;
import mage.abilities.costs.Costs;
import mage.abilities.costs.CostsImpl;
import mage.abilities.costs.OptionalAdditionalCost;
import mage.abilities.costs.OptionalAdditionalCostImpl;
import mage.abilities.costs.OptionalAdditionalSourceCosts;
import mage.abilities.costs.*;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCostsImpl;
@ -51,8 +41,9 @@ import mage.constants.Zone;
import mage.game.Game;
import mage.players.Player;
import java.util.*;
/**
*
* 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
* pay an additional [cost] as you cast this spell." Paying a spell's kicker
@ -80,7 +71,6 @@ import mage.players.Player;
* 601.2c.
*
* @author LevelX2
*
*/
public class KickerAbility extends StaticAbility implements OptionalAdditionalSourceCosts {
@ -159,10 +149,7 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
public int getKickedCounter(Game game, Ability source) {
String key = getActivationKey(source, "", game);
if (activations.containsKey(key)) {
return activations.get(key);
}
return 0;
return activations.getOrDefault(key, 0);
}
public boolean isKicked(Game game, Ability source, String costText) {
@ -227,10 +214,10 @@ public class KickerAbility extends StaticAbility implements OptionalAdditionalSo
&& 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 {

View file

@ -1,5 +1,7 @@
package mage.abilities.keyword;
import java.util.ArrayList;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.StaticAbility;
import mage.abilities.common.DiesTriggeredAbility;
@ -159,7 +161,8 @@ class ModularDistributeCounterEffect extends OneShotEffect {
if (sourcePermanent != null && targetArtifact != null && player != null) {
int numberOfCounters = sourcePermanent.getCounters(game).getCount(CounterType.P1P1);
if (numberOfCounters > 0) {
targetArtifact.addCounters(CounterType.P1P1.createInstance(numberOfCounters), source, game);
ArrayList<UUID> appliedEffects = (ArrayList<UUID>) this.getValue("appliedEffects"); // the basic event is the EntersBattlefieldEvent, so use already applied replacement effects from that event
targetArtifact.addCounters(CounterType.P1P1.createInstance(numberOfCounters), source, game, appliedEffects);
}
return true;
}

View file

@ -10,6 +10,8 @@ import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import java.util.Optional;
/**
* Split Second
*
@ -66,8 +68,8 @@ class SplitSecondEffect extends ContinuousRuleModifyingEffectImpl {
return true;
}
if (event.getType() == GameEvent.EventType.ACTIVATE_ABILITY) {
Ability ability = game.getAbility(event.getTargetId(), event.getSourceId());
if (ability != null && !(ability instanceof ActivatedManaAbilityImpl)) {
Optional<Ability> ability = game.getAbility(event.getTargetId(), event.getSourceId());
if (ability != null && !(ability.get() instanceof ActivatedManaAbilityImpl)) {
return true;
}
}

View file

@ -27,13 +27,14 @@
*/
package mage.abilities.keyword;
import java.util.ArrayList;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.SunburstCount;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.counters.Counter;
import mage.counters.CounterType;
@ -97,8 +98,8 @@ class SunburstEffect extends OneShotEffect {
counter = CounterType.CHARGE.createInstance(amount.calculate(game, source, this));
}
if (counter != null) {
permanent.addCounters(counter, source, game);
ArrayList<UUID> appliedEffects = (ArrayList<UUID>) this.getValue("appliedEffects"); // the basic event is the EntersBattlefieldEvent, so use already applied replacement effects from that event
permanent.addCounters(counter, source, game, appliedEffects);
if (!game.isSimulation()) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {

View file

@ -105,7 +105,7 @@ class UnleashReplacementEffect extends ReplacementEffectImpl {
if (!game.isSimulation()) {
game.informPlayers(controller.getLogName() + " unleashes " + creature.getName());
}
creature.addCounters(CounterType.P1P1.createInstance(), source, game);
creature.addCounters(CounterType.P1P1.createInstance(), source, game, event.getAppliedEffects());
}
}
return false;