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

@ -4,6 +4,8 @@ import mage.abilities.Abilities;
import mage.abilities.Ability;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.keyword.ChangelingAbility;
import mage.cards.Card;
import mage.cards.FrameStyle;
import mage.constants.CardType;
import mage.constants.SuperType;
@ -132,4 +134,52 @@ public interface MageObject extends MageItem, Serializable {
default boolean isWorld() {
return getSuperType().contains(SuperType.WORLD);
}
/**
* Checks whether two cards share card types.
*
*
* @param otherCard
* @return
*/
default boolean shareTypes(Card otherCard) {
if (otherCard == null) {
throw new IllegalArgumentException("Params can't be null");
}
for (CardType type : getCardType()) {
if (otherCard.getCardType().contains(type)) {
return true;
}
}
return false;
}
default boolean shareSubtypes(Card otherCard, Game game) {
if (otherCard == null) {
throw new IllegalArgumentException("Params can't be null");
}
if (this.isCreature() && otherCard.isCreature()) {
if (this.getAbilities().contains(ChangelingAbility.getInstance())
|| this.getSubtype(game).contains(ChangelingAbility.ALL_CREATURE_TYPE)
|| otherCard.getAbilities().contains(ChangelingAbility.getInstance())
|| otherCard.getSubtype(game).contains(ChangelingAbility.ALL_CREATURE_TYPE)) {
return true;
}
}
for (String subtype : this.getSubtype(game)) {
if (otherCard.getSubtype(game).contains(subtype)) {
return true;
}
}
return false;
}
}

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;

View file

@ -76,7 +76,7 @@ public class MageDrawAction extends MageAction {
*/
protected int drawCard(Game game) {
GameEvent event = GameEvent.getEvent(GameEvent.EventType.DRAW_CARD, player.getId(), player.getId());
event.setAppliedEffects(appliedEffects);
event.addAppliedEffects(appliedEffects);
if (!game.replaceEvent(event)) {
Card card = player.getLibrary().removeFromTop(game);
if (card != null) {

View file

@ -27,24 +27,16 @@
*/
package mage.cards;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import mage.filter.FilterCard;
import mage.game.Game;
import mage.util.RandomUtil;
import mage.util.ThreadLocalStringBuilder;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class CardsImpl extends LinkedHashSet<UUID> implements Cards, Serializable {
@ -118,24 +110,13 @@ public class CardsImpl extends LinkedHashSet<UUID> implements Cards, Serializabl
@Override
public int count(FilterCard filter, Game game) {
int result = 0;
for (UUID cardId : this) {
if (filter.match(game.getCard(cardId), game)) {
result++;
}
}
return result;
return (int) stream().filter(cardId -> filter.match(game.getCard(cardId), game)).count();
}
@Override
public int count(FilterCard filter, UUID playerId, Game game) {
int result = 0;
for (UUID card : this) {
if (filter.match(game.getCard(card), playerId, game)) {
result++;
}
}
return result;
return (int) this.stream().filter(card -> filter.match(game.getCard(card), playerId, game)).count();
}
@Override
@ -143,13 +124,8 @@ public class CardsImpl extends LinkedHashSet<UUID> implements Cards, Serializabl
if (sourceId == null) {
return count(filter, playerId, game);
}
int result = 0;
for (UUID card : this) {
if (filter.match(game.getCard(card), sourceId, playerId, game)) {
result++;
}
}
return result;
return (int) this.stream().filter(card -> filter.match(game.getCard(card), sourceId, playerId, game)).count();
}
@Override
@ -169,20 +145,13 @@ public class CardsImpl extends LinkedHashSet<UUID> implements Cards, Serializabl
@Override
public Set<Card> getCards(FilterCard filter, Game game) {
Set<Card> cards = new LinkedHashSet<>();
for (UUID card : this) {
boolean match = filter.match(game.getCard(card), game);
if (match) {
cards.add(game.getCard(card));
}
}
return cards;
return stream().map(game::getCard).filter(card -> filter.match(card, game)).collect(Collectors.toSet());
}
@Override
public Set<Card> getCards(Game game) {
Set<Card> cards = new LinkedHashSet<>();
for (Iterator<UUID> it = this.iterator(); it.hasNext();) { // Changed to iterator because of ConcurrentModificationException
for (Iterator<UUID> it = this.iterator(); it.hasNext(); ) { // Changed to iterator because of ConcurrentModificationException
UUID cardId = it.next();
Card card = game.getCard(cardId);

View file

@ -36,6 +36,7 @@ import mage.util.RandomUtil;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author BetaSteward_at_googlemail.com
@ -160,13 +161,7 @@ public abstract class ExpansionSet implements Serializable {
}
public List<SetCardInfo> findCardInfoByClass(Class<?> clazz) {
ArrayList<SetCardInfo> result = new ArrayList<>();
for (SetCardInfo info : cards) {
if (info.getCardClass().equals(clazz)) {
result.add(info);
}
}
return result;
return cards.stream().filter(info -> info.getCardClass().equals(clazz)).collect(Collectors.toList());
}
public List<Card> create15CardBooster() {

View file

@ -41,6 +41,7 @@ public enum CounterType {
BLAZE("blaze"),
BOUNTY("bounty"),
BRIBERY("bribery"),
BRICK("brick"),
CARRION("carrion"),
CHARGE("charge"),
CORPSE("corpse"),

View file

@ -28,10 +28,10 @@
package mage.counters;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author BetaSteward_at_googlemail.com
@ -122,12 +122,9 @@ public class Counters extends HashMap<String, Counter> implements Serializable {
}
public List<BoostCounter> getBoostCounters() {
List<BoostCounter> boosters = new ArrayList<>();
for (Counter counter : this.values()) {
if (counter instanceof BoostCounter) {
boosters.add((BoostCounter) counter);
}
}
return boosters;
return values().stream().
filter(counter -> counter instanceof BoostCounter).
map(counter -> (BoostCounter) counter).
collect(Collectors.toList());
}
}

View file

@ -28,13 +28,7 @@
package mage.game;
import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.*;
import mage.MageItem;
import mage.MageObject;
import mage.abilities.Ability;
@ -50,11 +44,7 @@ import mage.cards.Cards;
import mage.cards.MeldCard;
import mage.cards.decks.Deck;
import mage.choices.Choice;
import mage.constants.Duration;
import mage.constants.MultiplayerAttackOption;
import mage.constants.PlayerAction;
import mage.constants.RangeOfInfluence;
import mage.constants.Zone;
import mage.constants.*;
import mage.counters.Counters;
import mage.game.combat.Combat;
import mage.game.command.Commander;
@ -128,7 +118,7 @@ public interface Game extends MageItem, Serializable {
Card getCard(UUID cardId);
Ability getAbility(UUID abilityId, UUID sourceId);
Optional<Ability> getAbility(UUID abilityId, UUID sourceId);
void setZone(UUID objectId, Zone zone);
@ -402,7 +392,7 @@ public interface Game extends MageItem, Serializable {
void playPriority(UUID activePlayerId, boolean resuming);
boolean endTurn();
boolean endTurn(Ability source);
int doAction(MageAction action);

View file

@ -27,6 +27,10 @@
*/
package mage.game;
import java.io.IOException;
import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;
import mage.MageException;
import mage.MageObject;
import mage.abilities.*;
@ -92,11 +96,6 @@ import mage.watchers.Watchers;
import mage.watchers.common.*;
import org.apache.log4j.Logger;
import java.io.IOException;
import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;
public abstract class GameImpl implements Game, Serializable {
private static final int ROLLBACK_TURNS_MAX = 4;
@ -503,12 +502,12 @@ public abstract class GameImpl implements Game, Serializable {
}
@Override
public Ability getAbility(UUID abilityId, UUID sourceId) {
public Optional<Ability> getAbility(UUID abilityId, UUID sourceId) {
MageObject object = getObject(sourceId);
if (object != null) {
return object.getAbilities().get(abilityId);
}
return null;
return Optional.empty();
}
// @Override
@ -2336,10 +2335,10 @@ public abstract class GameImpl implements Game, Serializable {
}
}
Iterator it = gameCards.entrySet().iterator();
Iterator<Entry<UUID, Card>> it = gameCards.entrySet().iterator();
while (it.hasNext()) {
Entry<UUID, Card> entry = (Entry<UUID, Card>) it.next();
Entry<UUID, Card> entry = it.next();
Card card = entry.getValue();
if (card.getOwnerId().equals(playerId)) {
it.remove();
@ -2672,8 +2671,8 @@ public abstract class GameImpl implements Game, Serializable {
}
@Override
public boolean endTurn() {
getTurn().endTurn(this, getActivePlayerId());
public boolean endTurn(Ability source) {
getTurn().endTurn(this, getActivePlayerId(), source);
return true;
}

View file

@ -27,8 +27,10 @@
*/
package mage.game;
import java.io.Serializable;
import mage.players.Player;
import mage.players.PlayerType;
import java.io.Serializable;
/**
*
@ -37,18 +39,18 @@ import mage.players.Player;
public class Seat implements Serializable {
// private static final Logger logger = Logger.getLogger(Seat.class);
private String playerType;
private PlayerType playerType;
private Player player;
public Seat(String playerType) {
public Seat(PlayerType playerType) {
this.playerType = playerType;
}
public String getPlayerType() {
public PlayerType getPlayerType() {
return playerType;
}
public void setPlayerType(String playerType) {
public void setPlayerType(PlayerType playerType) {
this.playerType = playerType;
}

View file

@ -27,13 +27,6 @@
*/
package mage.game;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import mage.cards.decks.DeckValidator;
import mage.constants.TableState;
import mage.game.events.Listener;
@ -43,9 +36,12 @@ import mage.game.match.Match;
import mage.game.result.ResultProtos.TableProto;
import mage.game.tournament.Tournament;
import mage.players.Player;
import mage.players.PlayerType;
import java.io.Serializable;
import java.util.*;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class Table implements Serializable {
@ -74,21 +70,21 @@ public class Table implements Serializable {
protected TableEventSource tableEventSource = new TableEventSource();
public Table(UUID roomId, String gameType, String name, String controllerName, DeckValidator validator, List<String> playerTypes, TableRecorder recorder, Tournament tournament, Set<String> bannedUsernames) {
public Table(UUID roomId, String gameType, String name, String controllerName, DeckValidator validator, List<PlayerType> playerTypes, TableRecorder recorder, Tournament tournament, Set<String> bannedUsernames) {
this(roomId, gameType, name, controllerName, validator, playerTypes, recorder, bannedUsernames);
this.tournament = tournament;
this.isTournament = true;
setState(TableState.WAITING);
}
public Table(UUID roomId, String gameType, String name, String controllerName, DeckValidator validator, List<String> playerTypes, TableRecorder recorder, Match match, Set<String> bannedUsernames) {
public Table(UUID roomId, String gameType, String name, String controllerName, DeckValidator validator, List<PlayerType> playerTypes, TableRecorder recorder, Match match, Set<String> bannedUsernames) {
this(roomId, gameType, name, controllerName, validator, playerTypes, recorder, bannedUsernames);
this.match = match;
this.isTournament = false;
setState(TableState.WAITING);
}
protected Table(UUID roomId, String gameType, String name, String controllerName, DeckValidator validator, List<String> playerTypes, TableRecorder recorder, Set<String> bannedUsernames) {
protected Table(UUID roomId, String gameType, String name, String controllerName, DeckValidator validator, List<PlayerType> playerTypes, TableRecorder recorder, Set<String> bannedUsernames) {
tableId = UUID.randomUUID();
this.roomId = roomId;
this.numSeats = playerTypes.size();
@ -102,10 +98,10 @@ public class Table implements Serializable {
this.bannedUsernames = new HashSet<>(bannedUsernames);
}
private void createSeats(List<String> playerTypes) {
private void createSeats(List<PlayerType> playerTypes) {
int i = 0;
seats = new Seat[numSeats];
for (String playerType : playerTypes) {
for (PlayerType playerType : playerTypes) {
seats[i] = new Seat(playerType);
i++;
}
@ -145,7 +141,6 @@ public class Table implements Serializable {
/**
* All activities of the table end (only replay of games (if active) and
* display tournament results)
*
*/
public void closeTable() {
if (getState() != TableState.WAITING && getState() != TableState.READY_TO_START) {
@ -156,7 +151,6 @@ public class Table implements Serializable {
/**
* Complete remove of the table, release all objects
*
*/
public void cleanUp() {
if (match != null) {
@ -211,9 +205,9 @@ public class Table implements Serializable {
return numSeats;
}
public Seat getNextAvailableSeat(String playerType) {
public Seat getNextAvailableSeat(PlayerType playerType) {
for (int i = 0; i < numSeats; i++) {
if (seats[i].getPlayer() == null && seats[i].getPlayerType().equals(playerType)) {
if (seats[i].getPlayer() == null && seats[i].getPlayerType() == (playerType)) {
return seats[i];
}
}

View file

@ -27,10 +27,6 @@
*/
package mage.game.command;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import mage.MageInt;
import mage.ObjectColor;
import mage.abilities.Abilities;
@ -48,18 +44,22 @@ import mage.game.Game;
import mage.game.events.ZoneChangeEvent;
import mage.util.GameLog;
import java.util.EnumSet;
import java.util.List;
import java.util.UUID;
public class Commander implements CommandObject {
private final Card sourceObject;
private final Abilities<Ability> abilites = new AbilitiesImpl<>();
private final Abilities<Ability> abilities = new AbilitiesImpl<>();
public Commander(Card card) {
this.sourceObject = card;
abilites.add(new CastCommanderAbility(card));
abilities.add(new CastCommanderAbility(card));
for (Ability ability : card.getAbilities()) {
if (!(ability instanceof SpellAbility)) {
Ability newAbility = ability.copy();
abilites.add(newAbility);
abilities.add(newAbility);
}
}
}
@ -134,7 +134,7 @@ public class Commander implements CommandObject {
@Override
public Abilities<Ability> getAbilities() {
return abilites;
return abilities;
}
@Override

View file

@ -27,8 +27,6 @@
*/
package mage.game.command;
import java.util.*;
import mage.MageInt;
import mage.MageObject;
import mage.ObjectColor;
@ -46,6 +44,11 @@ import mage.game.Game;
import mage.game.events.ZoneChangeEvent;
import mage.util.GameLog;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.UUID;
/**
* @author nantuko
*/
@ -92,7 +95,7 @@ public class Emblem implements CommandObject {
this.sourceObject = sourceObject;
if (sourceObject instanceof Card) {
if (name.isEmpty()) {
name = ((Card) sourceObject).getSubtype(null).toString();
name = sourceObject.getSubtype(null).toString();
}
if (expansionSetCodeForImage.isEmpty()) {
expansionSetCodeForImage = ((Card) sourceObject).getExpansionSetCode();

View file

@ -166,7 +166,7 @@ public class GameEvent implements Serializable {
mana the mana added
*/
MANA_ADDED,
/* MANA_PAYED
/* MANA_PAID
targetId id if the ability the mana was paid for (not the sourceId)
sourceId sourceId of the mana source
playerId controller of the ability the mana was paid for
@ -174,7 +174,7 @@ public class GameEvent implements Serializable {
flag indicates a special condition
data originalId of the mana producing ability
*/
MANA_PAYED,
MANA_PAID,
LOSES, LOST, WINS,
TARGET, TARGETED,
/* TARGETS_VALID
@ -451,12 +451,19 @@ public class GameEvent implements Serializable {
return type == EventType.CUSTOM_EVENT && this.customEventType.equals(customEventType);
}
public void setAppliedEffects(ArrayList<UUID> appliedEffects) {
if (this.appliedEffects == null) {
this.appliedEffects = new ArrayList<>();
}
public void addAppliedEffects(ArrayList<UUID> appliedEffects) {
if (appliedEffects != null) {
this.appliedEffects.addAll(appliedEffects);
}
}
public void setAppliedEffects(ArrayList<UUID> appliedEffects) {
if (appliedEffects != null) {
if (this.appliedEffects.isEmpty()) {
this.appliedEffects = appliedEffects; // Use object refecence to handle that an replacement effect can only be once applied to an event
} else {
this.appliedEffects.addAll(appliedEffects);
}
}
}
}

View file

@ -28,16 +28,18 @@
package mage.game.match;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import mage.constants.MatchTimeLimit;
import mage.constants.MultiplayerAttackOption;
import mage.constants.RangeOfInfluence;
import mage.constants.SkillLevel;
import mage.game.result.ResultProtos;
import mage.players.PlayerType;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
*
@ -53,7 +55,7 @@ public class MatchOptions implements Serializable {
protected String gameType;
protected String deckType;
protected boolean limited;
protected List<String> playerTypes = new ArrayList<>();
protected List<PlayerType> playerTypes = new ArrayList<>();
protected boolean multiPlayer;
protected int numSeats;
protected String password;
@ -154,7 +156,7 @@ public class MatchOptions implements Serializable {
this.deckType = deckType;
}
public List<String> getPlayerTypes() {
public List<PlayerType> getPlayerTypes() {
return playerTypes;
}

View file

@ -103,22 +103,20 @@ public class Battlefield implements Serializable {
* @return count
*/
public int count(FilterPermanent filter, UUID sourceId, UUID sourcePlayerId, Game game) {
int count;
if (game.getRangeOfInfluence() == RangeOfInfluence.ALL) {
count = (int) field.values()
return (int) field.values()
.stream()
.filter(permanent -> filter.match(permanent, sourceId, sourcePlayerId, game)
&& permanent.isPhasedIn())
.count();
} else {
Set<UUID> range = game.getPlayer(sourcePlayerId).getInRange();
count = (int) field.values()
return (int) field.values()
.stream()
.filter(permanent -> range.contains(permanent.getControllerId())
&& filter.match(permanent, sourceId, sourcePlayerId, game)
&& permanent.isPhasedIn()).count();
}
return count;
}
/**
@ -319,20 +317,18 @@ public class Battlefield implements Serializable {
* @see Permanent
*/
public List<Permanent> getActivePermanents(FilterPermanent filter, UUID sourcePlayerId, UUID sourceId, Game game) {
List<Permanent> active = new ArrayList<>();
if (game.getRangeOfInfluence() == RangeOfInfluence.ALL) {
active = field.values()
return field.values()
.stream()
.filter(perm -> perm.isPhasedIn() && filter.match(perm, sourceId, sourcePlayerId, game))
.collect(Collectors.toList());
} else {
Set<UUID> range = game.getPlayer(sourcePlayerId).getInRange();
active = field.values()
return field.values()
.stream()
.filter(perm -> perm.isPhasedIn() && range.contains(perm.getControllerId())
&& filter.match(perm, sourceId, sourcePlayerId, game)).collect(Collectors.toList());
}
return active;
}
/**

View file

@ -12,7 +12,7 @@ public class AngelToken extends Token {
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("AVR", "C14", "CFX", "GTC", "ISD", "M14", "ORI", "SOI", "ZEN", "C15"));
tokenImageSets.addAll(Arrays.asList("AVR", "C14", "CFX", "GTC", "ISD", "M14", "ORI", "SOI", "ZEN", "C15", "MM3"));
}
public AngelToken() {

View file

@ -42,7 +42,7 @@ public class BeastToken extends Token {
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("C14", "LRW", "M15", "M14", "DDL", "M13", "M12", "DD3GVL", "NPH", "M11", "M10", "EVE"));
tokenImageSets.addAll(Arrays.asList("C14", "LRW", "M15", "M14", "DDL", "M13", "M12", "DD3GVL", "NPH", "M11", "M10", "EVE", "MM3"));
}
public BeastToken() {
@ -71,7 +71,7 @@ public class BeastToken extends Token {
if (getOriginalExpansionSetCode().equals("M15")) {
this.setTokenType(2);
}
if (getOriginalExpansionSetCode().equals("DD3GVL") || getOriginalExpansionSetCode().equals("C14") || getOriginalExpansionSetCode().equals("DDD")) {
if (getOriginalExpansionSetCode().equals("DD3GVL") || getOriginalExpansionSetCode().equals("C14") || getOriginalExpansionSetCode().equals("DDD") || getOriginalExpansionSetCode().equals("MM3")) {
this.setTokenType(1);
}
}

View file

@ -42,7 +42,7 @@ public class BeastToken2 extends Token {
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("ZEN", "C14", "DDD", "C15", "DD3GVL"));
tokenImageSets.addAll(Arrays.asList("ZEN", "C14", "DDD", "C15", "DD3GVL", "MM3"));
}
public BeastToken2() {
@ -76,7 +76,7 @@ public class BeastToken2 extends Token {
@Override
public void setExpansionSetCodeForImage(String code) {
super.setExpansionSetCodeForImage(code);
if (getOriginalExpansionSetCode().equals("C14") || getOriginalExpansionSetCode().equals("DDD") || getOriginalExpansionSetCode().equals("DD3GVL")) {
if (getOriginalExpansionSetCode().equals("C14") || getOriginalExpansionSetCode().equals("DDD") || getOriginalExpansionSetCode().equals("DD3GVL") || getOriginalExpansionSetCode().equals("MM3")) {
this.setTokenType(2);
}
}

View file

@ -47,7 +47,7 @@ public class BirdToken extends Token {
power = new MageInt(1);
toughness = new MageInt(1);
addAbility(FlyingAbility.getInstance());
availableImageSetCodes.addAll(Arrays.asList("BNG", "RTR", "ZEN", "C16"));
availableImageSetCodes.addAll(Arrays.asList("BNG", "RTR", "ZEN", "C16", "MM3", "DGM"));
}
public BirdToken(final BirdToken token) {

View file

@ -28,6 +28,9 @@
package mage.game.permanent.token;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import mage.constants.CardType;
import mage.MageInt;
import mage.util.RandomUtil;
@ -38,6 +41,12 @@ import mage.util.RandomUtil;
*/
public class CentaurToken extends Token {
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("RTR", "MM3"));
}
public CentaurToken() {
super("Centaur", "3/3 green Centaur creature token");
cardType.add(CardType.CREATURE);
@ -46,7 +55,6 @@ public class CentaurToken extends Token {
subtype.add("Centaur");
power = new MageInt(3);
toughness = new MageInt(3);
setOriginalExpansionSetCode("RTR");
}
}

View file

@ -44,7 +44,7 @@ public class DragonToken extends Token {
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("DTK", "MMA", "ALA"));
tokenImageSets.addAll(Arrays.asList("DTK", "MMA", "ALA", "MM3"));
}
public DragonToken() {

View file

@ -43,7 +43,7 @@ public class ElephantToken extends Token {
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("C14", "CNS", "DDD", "MM2", "WWK", "OGW", "C15", "DD3GVL"));
tokenImageSets.addAll(Arrays.asList("C14", "CNS", "DDD", "MM2", "WWK", "OGW", "C15", "DD3GVL", "MM3"));
}
public ElephantToken() {

View file

@ -43,7 +43,7 @@ public class GoblinToken extends Token {
static {
tokenImageSets.addAll(Arrays.asList("10E", "ALA", "SOM", "M10", "NPH", "M13", "RTR",
"MMA", "M15", "C14", "KTK", "EVG", "DTK", "ORI", "DDG", "DDN", "DD3EVG", "MM2"));
"MMA", "M15", "C14", "KTK", "EVG", "DTK", "ORI", "DDG", "DDN", "DD3EVG", "MM2", "MM3", "EMA", "C16"));
}
public GoblinToken() {

View file

@ -43,7 +43,7 @@ public class GolemToken extends Token {
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("MM2", "NPH", "SOM"));
tokenImageSets.addAll(Arrays.asList("MM2", "NPH", "SOM", "MM3"));
}
public GolemToken() {

View file

@ -44,7 +44,7 @@ public class SaprolingToken extends Token {
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("10E", "ALA", "DDE", "DDH", "DDJ", "M12", "M13", "M14", "MM2", "MMA", "RTR", "C15"));
tokenImageSets.addAll(Arrays.asList("10E", "ALA", "DDE", "DDH", "DDJ", "M12", "M13", "M14", "MM2", "MMA", "RTR", "C15", "MM3", "C16"));
}
public SaprolingToken() {

View file

@ -44,7 +44,7 @@ public class SoldierToken extends Token {
static {
tokenImageSets.addAll(Arrays.asList("10E", "M15", "C14", "ORI", "ALA", "DDF", "THS", "M12", "M13", "MM2", "MMA", "RTR",
"SOM", "DDO", "M10", "ORI", "EMN", "EMA", "CN2", "C16"));
"SOM", "DDO", "M10", "ORI", "EMN", "EMA", "CN2", "C16", "MM3"));
}
public SoldierToken() {
@ -65,7 +65,7 @@ public class SoldierToken extends Token {
if (getOriginalExpansionSetCode() != null && getOriginalExpansionSetCode().equals("THS")) {
this.setTokenType(RandomUtil.nextInt(2) + 1);
}
if (getOriginalExpansionSetCode() != null && getOriginalExpansionSetCode().equals("CN2")) {
if (getOriginalExpansionSetCode() != null && getOriginalExpansionSetCode().equals("CN2") || getOriginalExpansionSetCode().equals("MM3")) {
setTokenType(1);
}
}

View file

@ -28,6 +28,9 @@
package mage.game.permanent.token;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import mage.constants.CardType;
import mage.MageInt;
import mage.abilities.keyword.HasteAbility;
@ -38,6 +41,12 @@ import mage.abilities.keyword.HasteAbility;
*/
public class SoldierTokenWithHaste extends Token {
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("GTC", "MM3"));
}
public SoldierTokenWithHaste() {
super("Soldier", "1/1 red and white Soldier creature token with haste");
cardType.add(CardType.CREATURE);
@ -47,6 +56,23 @@ public class SoldierTokenWithHaste extends Token {
power = new MageInt(1);
toughness = new MageInt(1);
addAbility(HasteAbility.getInstance());
setOriginalExpansionSetCode("GTC");
}
@Override
public void setExpansionSetCodeForImage(String code) {
super.setExpansionSetCodeForImage(code);
if (getOriginalExpansionSetCode() != null && getOriginalExpansionSetCode().equals("MM3")) {
setTokenType(2);
}
}
public SoldierTokenWithHaste(final SoldierTokenWithHaste token) {
super(token);
}
@Override
public SoldierTokenWithHaste copy() {
return new SoldierTokenWithHaste(this); //To change body of generated methods, choose Tools | Templates.
}
}

View file

@ -42,7 +42,7 @@ public class SpiritWhiteToken extends Token {
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("AVR", "C14", "CNS", "DDC", "DDK", "FRF", "ISD", "KTK", "M15", "MM2", "SHM", "SOI", "EMA", "C16"));
tokenImageSets.addAll(Arrays.asList("AVR", "C14", "CNS", "DDC", "DDK", "FRF", "ISD", "KTK", "M15", "MM2", "SHM", "SOI", "EMA", "C16", "MM3"));
}
public SpiritWhiteToken() {

View file

@ -0,0 +1,62 @@
/*
* 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.game.permanent.token;
import java.util.Arrays;
import mage.MageInt;
import mage.abilities.keyword.VigilanceAbility;
import mage.constants.CardType;
/**
*
* @author fireshoes
*/
public class WarriorVigilantToken extends Token {
public WarriorVigilantToken() {
super("Warrior", "1/1 white Warrior creature token with vigilance");
cardType.add(CardType.CREATURE);
color.setWhite(true);
subtype.add("Warrior");
power = new MageInt(1);
toughness = new MageInt(1);
addAbility(VigilanceAbility.getInstance());
availableImageSetCodes.addAll(Arrays.asList("AKH"));
}
public WarriorVigilantToken(final WarriorVigilantToken token) {
super(token);
}
@Override
public WarriorVigilantToken copy() {
return new WarriorVigilantToken(this);
}
}

View file

@ -28,6 +28,9 @@
package mage.game.permanent.token;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import mage.constants.CardType;
import mage.MageInt;
import mage.abilities.keyword.TrampleAbility;
@ -38,6 +41,12 @@ import mage.abilities.keyword.TrampleAbility;
*/
public class WurmToken2 extends Token {
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("RTR", "MM3"));
}
public WurmToken2() {
super("Wurm", "5/5 green Wurm creature token with trample");
cardType.add(CardType.CREATURE);
@ -46,6 +55,5 @@ public class WurmToken2 extends Token {
power = new MageInt(5);
toughness = new MageInt(5);
addAbility(TrampleAbility.getInstance());
setOriginalExpansionSetCode("RTR");
}
}

View file

@ -44,8 +44,8 @@ public class ZombieToken extends Token {
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("10E", "M10", "M11", "M12", "M13", "M14", "M15", "MBS", "ALA", "ISD", "C14", "C15", "CNS",
"MMA", "BNG", "KTK", "DTK", "ORI", "OGW", "SOI", "EMN", "EMA"));
tokenImageSets.addAll(Arrays.asList("10E", "M10", "M11", "M12", "M13", "M14", "M15", "MBS", "ALA", "ISD", "C14", "C15", "C16", "CNS",
"MMA", "BNG", "KTK", "DTK", "ORI", "OGW", "SOI", "EMN", "EMA", "MM3"));
}
public ZombieToken() {

View file

@ -27,8 +27,10 @@
*/
package mage.game.stack;
import java.util.*;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.Mana;
@ -331,8 +333,8 @@ public class Spell extends StackObjImpl implements Card {
* determine whether card was kicked or not. E.g. Desolation Angel
*/
private void updateOptionalCosts(int index) {
Ability abilityOrig = spellCards.get(index).getAbilities().get(spellAbilities.get(index).getId());
if (abilityOrig != null) {
spellCards.get(index).getAbilities().get(spellAbilities.get(index).getId()).ifPresent(abilityOrig
-> {
for (Object object : spellAbilities.get(index).getOptionalCosts()) {
Cost cost = (Cost) object;
for (Cost costOrig : abilityOrig.getOptionalCosts()) {
@ -346,7 +348,7 @@ public class Spell extends StackObjImpl implements Card {
}
}
}
}
});
}
@Override
@ -746,24 +748,7 @@ public class Spell extends StackObjImpl implements Card {
@Override
public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, ArrayList<UUID> appliedEffects) {
ZoneChangeEvent event = new ZoneChangeEvent(this.getId(), sourceId, this.getOwnerId(), Zone.STACK, Zone.EXILED, appliedEffects);
if (!game.replaceEvent(event)) {
game.getStack().remove(this);
game.rememberLKI(this.getId(), event.getFromZone(), this);
if (!this.isCopiedSpell()) {
if (exileId == null) {
game.getExile().getPermanentExile().add(this.card);
} else {
game.getExile().createZone(exileId, name).add(this.card);
}
game.setZone(this.card.getId(), event.getToZone());
}
game.fireEvent(event);
return event.getToZone() == Zone.EXILED;
}
return false;
return this.card.moveToExile(exileId, name, sourceId, game, appliedEffects);
}
@Override

View file

@ -27,10 +27,6 @@
*/
package mage.game.tournament;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import mage.cards.ExpansionSet;
import mage.cards.decks.Deck;
import mage.game.draft.Draft;
@ -39,6 +35,12 @@ import mage.game.events.PlayerQueryEvent;
import mage.game.events.TableEvent;
import mage.game.result.ResultProtos.TourneyProto;
import mage.players.Player;
import mage.players.PlayerType;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.UUID;
/**
*
@ -48,7 +50,7 @@ public interface Tournament {
UUID getId();
void addPlayer(Player player, String playerType);
void addPlayer(Player player, PlayerType playerType);
void removePlayer(UUID playerId);

View file

@ -38,6 +38,7 @@ import mage.game.match.Match;
import mage.game.match.MatchPlayer;
import mage.game.result.ResultProtos.*;
import mage.players.Player;
import mage.players.PlayerType;
import mage.util.RandomUtil;
import org.apache.log4j.Logger;
@ -82,7 +83,7 @@ public abstract class TournamentImpl implements Tournament {
}
@Override
public void addPlayer(Player player, String playerType) {
public void addPlayer(Player player, PlayerType playerType) {
players.put(player.getId(), new TournamentPlayer(player, playerType));
}

View file

@ -27,10 +27,12 @@
*/
package mage.game.tournament;
import mage.game.match.MatchOptions;
import mage.players.PlayerType;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import mage.game.match.MatchOptions;
/**
*
@ -40,7 +42,7 @@ public class TournamentOptions implements Serializable {
protected String name;
protected String tournamentType;
protected List<String> playerTypes = new ArrayList<>();
protected List<PlayerType> playerTypes = new ArrayList<>();
protected MatchOptions matchOptions;
protected LimitedOptions limitedOptions;
protected boolean watchingAllowed = true;
@ -65,7 +67,7 @@ public class TournamentOptions implements Serializable {
this.tournamentType = tournamentType;
}
public List<String> getPlayerTypes() {
public List<PlayerType> getPlayerTypes() {
return playerTypes;
}

View file

@ -28,14 +28,16 @@
package mage.game.tournament;
import java.util.Set;
import mage.cards.decks.Deck;
import mage.constants.TournamentPlayerState;
import mage.game.result.ResultProtos.TourneyPlayerProto;
import mage.game.result.ResultProtos.TourneyQuitStatus;
import mage.players.Player;
import mage.players.PlayerType;
import mage.util.TournamentUtil;
import java.util.Set;
/**
*
* @author BetaSteward_at_googlemail.com
@ -43,7 +45,7 @@ import mage.util.TournamentUtil;
public class TournamentPlayer {
protected int points;
protected String playerType;
protected PlayerType playerType;
protected TournamentPlayerState state;
protected String stateInfo;
protected String disconnectInfo;
@ -57,7 +59,7 @@ public class TournamentPlayer {
protected TourneyQuitStatus quitStatus = TourneyQuitStatus.NO_TOURNEY_QUIT;
protected TournamentPlayer replacedTournamentPlayer;
public TournamentPlayer(Player player, String playerType) {
public TournamentPlayer(Player player, PlayerType playerType) {
this.player = player;
this.playerType = playerType;
this.state = TournamentPlayerState.JOINED;
@ -70,7 +72,7 @@ public class TournamentPlayer {
return player;
}
public String getPlayerType() {
public PlayerType getPlayerType() {
return playerType;
}
@ -232,7 +234,7 @@ public class TournamentPlayer {
public TourneyPlayerProto toProto() {
return TourneyPlayerProto.newBuilder()
.setName(this.player.getName())
.setPlayerType(this.playerType)
.setPlayerType(this.playerType.toString())
.setQuit(this.quitStatus)
.build();
}

View file

@ -32,6 +32,7 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import mage.abilities.Ability;
import mage.constants.PhaseStep;
import mage.constants.TurnPhase;
import mage.counters.CounterType;
@ -268,8 +269,9 @@ public class Turn implements Serializable {
*
* @param game
* @param activePlayerId
* @param source
*/
public void endTurn(Game game, UUID activePlayerId) {
public void endTurn(Game game, UUID activePlayerId, Ability source) {
// Ending the turn this way (Time Stop) means the following things happen in order:
setEndTurnRequested(true);
@ -277,9 +279,9 @@ public class Turn implements Serializable {
// 1) All spells and abilities on the stack are exiled. This includes Time Stop, though it will continue to resolve.
// It also includes spells and abilities that can't be countered.
while (!game.getStack().isEmpty()) {
StackObject stackObject = game.getStack().removeLast();
StackObject stackObject = game.getStack().peekFirst();
if (stackObject instanceof Spell) {
((Spell) stackObject).moveToExile(null, "", null, game);
((Spell) stackObject).moveToExile(null, "", source.getSourceId(), game);
}
}
// 2) All attacking and blocking creatures are removed from combat.

View file

@ -27,26 +27,16 @@
*/
package mage.players;
import java.io.Serializable;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import mage.cards.Card;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.game.Game;
import mage.util.RandomUtil;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author BetaSteward_at_googlemail.com
*/
@ -182,11 +172,7 @@ public class Library implements Serializable {
}
public List<Card> getCards(Game game) {
List<Card> cards = new ArrayList<>();
for (UUID cardId : library) {
cards.add(game.getCard(cardId));
}
return cards;
return library.stream().map(game::getCard).collect(Collectors.toList());
}
public Set<Card> getTopCards(Game game, int amount) {
@ -214,13 +200,7 @@ public class Library implements Serializable {
}
public int count(FilterCard filter, Game game) {
int result = 0;
for (UUID card : library) {
if (filter.match(game.getCard(card), game)) {
result++;
}
}
return result;
return (int) library.stream().filter(cardId -> filter.match(game.getCard(cardId), game)).count();
}
public boolean isEmptyDraw() {

View file

@ -118,7 +118,7 @@ public class ManaPool implements Serializable {
return false;
}
if (autoPayment && autoPaymentRestricted && !wasManaAddedBeyondStock() && manaType != unlockedManaType) {
// if automatic restricted payment and there is laready mana in the pool
// if automatic restricted payment and there is already mana in the pool
// and the needed mana type was not unlocked, nothing will be paid
return false;
}
@ -146,7 +146,7 @@ public class ManaPool implements Serializable {
continue;
}
if (mana.get(usableManaType) > 0) {
GameEvent event = new GameEvent(GameEvent.EventType.MANA_PAYED, ability.getId(), mana.getSourceId(), ability.getControllerId(), 0, mana.getFlag());
GameEvent event = new GameEvent(GameEvent.EventType.MANA_PAID, ability.getId(), mana.getSourceId(), ability.getControllerId(), 0, mana.getFlag());
event.setData(mana.getOriginalId().toString());
game.fireEvent(event);
mana.remove(usableManaType);
@ -205,6 +205,10 @@ public class ManaPool implements Serializable {
doNotEmptyManaTypes.add(manaType);
}
public void init() {
manaItems.clear();
}
public int emptyPool(Game game) {
int total = 0;
Iterator<ManaPoolItem> it = manaItems.iterator();
@ -424,7 +428,7 @@ public class ManaPool implements Serializable {
for (ConditionalMana mana : getConditionalMana()) {
if (mana.get(manaType) > 0 && mana.apply(ability, game, mana.getManaProducerId(), costToPay)) {
mana.set(manaType, mana.get(manaType) - 1);
GameEvent event = new GameEvent(GameEvent.EventType.MANA_PAYED, ability.getId(), mana.getManaProducerId(), ability.getControllerId(), 0, mana.getFlag());
GameEvent event = new GameEvent(GameEvent.EventType.MANA_PAID, ability.getId(), mana.getManaProducerId(), ability.getControllerId(), 0, mana.getFlag());
event.setData(mana.getManaProducerOriginalId().toString());
game.fireEvent(event);
break;

View file

@ -422,6 +422,7 @@ public abstract class PlayerImpl implements Player, Serializable {
this.castSourceIdWithAlternateMana = null;
this.castSourceIdManaCosts = null;
this.castSourceIdCosts = null;
this.getManaPool().init(); // needed to remove mana that not empties on step change from previous game if left
}
/**

View file

@ -0,0 +1,32 @@
package mage.players;
/**
* Created by IGOUDT on 2-4-2017.
*/
public enum PlayerType {
HUMAN("Human"),
COMPUTER_DRAFT_BOT("Computer - draftbot"),
COMPUTER_MINIMAX_HYBRID("Computer - minimax hybrid"),
COMPUTER_MONTE_CARLO("Computer - monte carlo"),
COMPUTER_MAD("Computer - mad");
String description;
PlayerType(String description) {
this.description = description;
}
@Override
public String toString() {
return description;
}
public static PlayerType getByDescription(String description) {
for (PlayerType type : values()) {
if (type.description.equals(description)) {
return type;
}
}
throw new IllegalArgumentException(String.format("PlayerType (%s) is not configured", description));
}
}

View file

@ -34,6 +34,7 @@ import mage.abilities.dynamicvalue.common.StaticValue;
import mage.constants.Outcome;
import mage.game.Game;
import java.util.*;
import java.util.stream.Collectors;
/**
*
@ -142,12 +143,7 @@ public abstract class TargetAmount extends TargetImpl {
t.addTarget(targetId, n, source, game, true);
if (t.remainingAmount > 0) {
if (targets.size() > 1) {
Set<UUID> newTargets = new HashSet<>();
for (UUID newTarget: targets) {
if (!newTarget.equals(targetId)) {
newTargets.add(newTarget);
}
}
Set<UUID> newTargets = targets.stream().filter(newTarget -> !newTarget.equals(targetId)).collect(Collectors.toSet());
addTargets(t, newTargets, options, source, game);
}
}

View file

@ -27,9 +27,7 @@
*/
package mage.target;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.MageItem;
import mage.cards.Card;
import mage.cards.Cards;
import mage.constants.Zone;
@ -38,6 +36,11 @@ import mage.game.Game;
import mage.game.events.GameEvent;
import mage.players.Player;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
/**
*
* @author BetaSteward_at_googlemail.com
@ -200,11 +203,7 @@ public class TargetCard extends TargetObject {
}
public Set<UUID> possibleTargets(UUID sourceControllerId, Cards cards, Game game) {
Set<UUID> possibleTargets = new HashSet<>();
for (Card card : cards.getCards(filter, game)) {
possibleTargets.add(card.getId());
}
return possibleTargets;
return cards.getCards(filter,game).stream().map(MageItem::getId).collect(Collectors.toSet());
}
@Override

View file

@ -27,15 +27,16 @@
*/
package mage.target;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.filter.FilterPlayer;
import mage.game.Game;
import mage.players.Player;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
*
* @author BetaSteward_at_googlemail.com
@ -158,12 +159,7 @@ public class TargetPlayer extends TargetImpl {
if (getNumberOfTargets() == 0 && targets.isEmpty()) {
return true; // 0 targets selected is valid
}
for (UUID playerId : targets.keySet()) {
if (canTarget(playerId, source, game)) {
return true;
}
}
return false;
return targets.keySet().stream().anyMatch(playerId -> canTarget(playerId, source, game));
}
@Override

View file

@ -27,9 +27,6 @@
*/
package mage.target;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.abilities.Ability;
import mage.constants.Zone;
import mage.filter.FilterSpell;
@ -37,6 +34,11 @@ import mage.game.Game;
import mage.game.stack.Spell;
import mage.game.stack.StackObject;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
/**
*
* @author BetaSteward_at_googlemail.com
@ -112,13 +114,10 @@ public class TargetSpell extends TargetObject {
@Override
public Set<UUID> possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) {
Set<UUID> possibleTargets = new HashSet<>();
for (StackObject stackObject : game.getStack()) {
if (canBeChosen(stackObject, sourceId, sourceControllerId, game)) {
possibleTargets.add(stackObject.getId());
}
}
return possibleTargets;
return game.getStack().stream()
.filter(stackObject -> canBeChosen(stackObject, sourceId, sourceControllerId, game))
.map(StackObject::getId)
.collect(Collectors.toSet());
}
@Override

View file

@ -27,14 +27,16 @@
*/
package mage.target;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.abilities.Ability;
import mage.constants.Outcome;
import mage.game.Game;
import mage.game.events.GameEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
/**
*
* @author BetaSteward_at_googlemail.com
@ -51,13 +53,7 @@ public class Targets extends ArrayList<Target> {
}
public List<Target> getUnchosen() {
List<Target> unchosen = new ArrayList<>();
for (Target target : this) {
if (!target.isChosen()) {
unchosen.add(target);
}
}
return unchosen;
return stream().filter(target -> !target.isChosen()).collect(Collectors.toList());
}
public void clearChosen() {
@ -67,12 +63,7 @@ public class Targets extends ArrayList<Target> {
}
public boolean isChosen() {
for (Target target : this) {
if (!target.isChosen()) {
return false;
}
}
return true;
return stream().allMatch(Target::isChosen);
}
public boolean choose(Outcome outcome, UUID playerId, UUID sourceId, Game game) {
@ -122,12 +113,8 @@ public class Targets extends ArrayList<Target> {
public boolean stillLegal(Ability source, Game game) {
// 608.2
// The spell or ability is countered if all its targets, for every instance of the word "target," are now illegal
int illegalCount = 0;
for (Target target : this) {
if (!target.isLegal(source, game)) {
illegalCount++;
}
}
int illegalCount = (int) stream().filter(target -> !target.isLegal(source, game)).count();
// it is legal when either there is no target or not all targets are illegal
return this.isEmpty() || this.size() != illegalCount;
}
@ -142,12 +129,7 @@ public class Targets extends ArrayList<Target> {
* @return - true if enough valid targets exist
*/
public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) {
for (Target target : this) {
if (!target.canChoose(sourceId, sourceControllerId, game)) {
return false;
}
}
return true;
return stream().allMatch(target -> target.canChoose(sourceId, sourceControllerId, game));
}
/**
@ -160,12 +142,7 @@ public class Targets extends ArrayList<Target> {
* @return - true if enough valid objects exist
*/
public boolean canChoose(UUID sourceControllerId, Game game) {
for (Target target : this) {
if (!target.canChoose(sourceControllerId, game)) {
return false;
}
}
return true;
return stream().allMatch(target -> target.canChoose(sourceControllerId, game));
}
public UUID getFirstTarget() {
@ -174,7 +151,6 @@ public class Targets extends ArrayList<Target> {
}
return null;
}
public Targets copy() {
return new Targets(this);
}

View file

@ -28,27 +28,27 @@
package mage.target.common;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.constants.Zone;
import mage.abilities.Ability;
import mage.constants.AbilityType;
import mage.constants.Zone;
import mage.filter.Filter;
import mage.filter.FilterAbility;
import mage.game.Game;
import mage.game.stack.StackObject;
import mage.target.TargetObject;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
/**
*
* @author LevelX2
*/
public class TargetActivatedOrTriggeredAbility extends TargetObject {
public TargetActivatedOrTriggeredAbility() {
public TargetActivatedOrTriggeredAbility() {
this.minNumberOfTargets = 1;
this.maxNumberOfTargets = 1;
this.zone = Zone.STACK;
@ -78,12 +78,9 @@ public class TargetActivatedOrTriggeredAbility extends TargetObject {
@Override
public boolean canChoose(UUID sourceControllerId, Game game) {
for (StackObject stackObject : game.getStack()) {
if (isActivatedOrTriggeredAbility(stackObject)) {
return true;
}
}
return false;
return game.getStack()
.stream()
.anyMatch(TargetActivatedOrTriggeredAbility::isActivatedOrTriggeredAbility);
}
@Override
@ -93,13 +90,10 @@ public class TargetActivatedOrTriggeredAbility extends TargetObject {
@Override
public Set<UUID> possibleTargets(UUID sourceControllerId, Game game) {
Set<UUID> possibleTargets = new HashSet<>();
for (StackObject stackObject : game.getStack()) {
if (isActivatedOrTriggeredAbility(stackObject)) {
possibleTargets.add(stackObject.getStackAbility().getId());
}
}
return possibleTargets;
return game.getStack().stream()
.filter(TargetActivatedOrTriggeredAbility::isActivatedOrTriggeredAbility)
.map(stackObject -> stackObject.getStackAbility().getId())
.collect(Collectors.toSet());
}
@Override
@ -117,9 +111,9 @@ public class TargetActivatedOrTriggeredAbility extends TargetObject {
return false;
}
if (stackObject instanceof Ability) {
Ability ability = (Ability)stackObject;
Ability ability = (Ability) stackObject;
return ability.getAbilityType() == AbilityType.TRIGGERED
|| ability.getAbilityType() == AbilityType.ACTIVATED;
|| ability.getAbilityType() == AbilityType.ACTIVATED;
}
return false;
}

View file

@ -27,8 +27,6 @@
*/
package mage.target.common;
import java.util.Set;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.cards.Card;
@ -39,8 +37,10 @@ import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.TargetCard;
import java.util.Set;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public class TargetCardInGraveyardOrBattlefield extends TargetCard {
@ -82,8 +82,7 @@ public class TargetCardInGraveyardOrBattlefield extends TargetCard {
}
@Override
public boolean canTarget(UUID id, Ability source, Game game
) {
public boolean canTarget(UUID id, Ability source, Game game) {
Permanent permanent = game.getPermanent(id);
if (permanent != null) {
return filter.match(permanent, game);
@ -93,8 +92,7 @@ public class TargetCardInGraveyardOrBattlefield extends TargetCard {
}
@Override
public Set<UUID> possibleTargets(UUID sourceControllerId, Game game
) {
public Set<UUID> possibleTargets(UUID sourceControllerId, Game game) {
//return super.possibleTargets(sourceControllerId, game); //To change body of generated methods, choose Tools | Templates.
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, game);
for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterPermanent(), sourceControllerId, game)) {
@ -106,8 +104,7 @@ public class TargetCardInGraveyardOrBattlefield extends TargetCard {
}
@Override
public Set<UUID> possibleTargets(UUID sourceId, UUID sourceControllerId, Game game
) {
public Set<UUID> possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) {
Set<UUID> possibleTargets = super.possibleTargets(sourceId, sourceControllerId, game);
MageObject targetSource = game.getObject(sourceId);
for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterPermanent(), sourceControllerId, game)) {

View file

@ -27,12 +27,12 @@
*/
package mage.target.common;
import java.util.UUID;
import mage.abilities.Ability;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.util.CardUtil;
import java.util.UUID;
/**
*
@ -62,7 +62,7 @@ public class TargetCreaturePermanentWithDifferentTypes extends TargetCreaturePer
UUID targetId = (UUID) object;
Permanent selectedCreature = game.getPermanent(targetId);
if (!creature.getId().equals(selectedCreature.getId())) {
if (CardUtil.shareSubtypes(creature, selectedCreature, game)) {
if (creature.shareSubtypes(selectedCreature, game)) {
return false;
}
}

View file

@ -35,10 +35,8 @@ import mage.abilities.ActivatedAbility;
import mage.abilities.SpellAbility;
import mage.abilities.costs.VariableCost;
import mage.abilities.costs.mana.*;
import mage.abilities.keyword.ChangelingAbility;
import mage.cards.Card;
import mage.cards.SplitCard;
import mage.constants.CardType;
import mage.filter.FilterMana;
import mage.game.Game;
import mage.game.permanent.Permanent;
@ -84,57 +82,9 @@ public final class CardUtil {
"Trap", "Arcane"};
public static final Set<String> NON_CREATURE_SUBTYPES = new HashSet<>(Arrays.asList(NON_CHANGELING_SUBTYPES_VALUES));
/**
* Checks whether two cards share card types.
*
* @param card1
* @param card2
* @return
*/
public static boolean shareTypes(Card card1, Card card2) {
if (card1 == null || card2 == null) {
throw new IllegalArgumentException("Params can't be null");
}
for (CardType type : card1.getCardType()) {
if (card2.getCardType().contains(type)) {
return true;
}
}
return false;
}
/**
* Checks whether two cards share card subtypes.
*
* @param card1
* @param card2
* @return
*/
public static boolean shareSubtypes(Card card1, Card card2, Game game) {
if (card1 == null || card2 == null) {
throw new IllegalArgumentException("Params can't be null");
}
if (card1.isCreature() && card2.isCreature()) {
if (card1.getAbilities().contains(ChangelingAbility.getInstance())
|| card1.getSubtype(game).contains(ChangelingAbility.ALL_CREATURE_TYPE)
|| card2.getAbilities().contains(ChangelingAbility.getInstance())
|| card2.getSubtype(game).contains(ChangelingAbility.ALL_CREATURE_TYPE)) {
return true;
}
}
for (String subtype : card1.getSubtype(game)) {
if (card2.getSubtype(game).contains(subtype)) {
return true;
}
}
return false;
}
/**
* Increase spell or ability cost to be paid.