Merge remote-tracking branch 'origin/master'

This commit is contained in:
Oleg Agafonov 2019-01-04 23:34:15 +04:00
commit 83cf370cc6
59 changed files with 2566 additions and 373 deletions

View file

@ -1,13 +1,6 @@
package mage.abilities;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import mage.abilities.costs.OptionalAdditionalModeSourceCosts;
import mage.cards.Card;
import mage.constants.Outcome;
@ -18,8 +11,9 @@ import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetOpponent;
import java.util.*;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class Modes extends LinkedHashMap<UUID, Mode> {
@ -340,7 +334,9 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
StringBuilder sb = new StringBuilder();
if (this.getMaxModesFilter() != null) {
sb.append("choose one or more. Each mode must target ").append(getMaxModesFilter().getMessage());
} else if (this.getMinModes() == 1 && this.getMaxModes() == 3) {
} else if (this.getMinModes() == 0 && this.getMaxModes() == 1) {
sb.append("choose up to one ");
} else if (this.getMinModes() == 1 && this.getMaxModes() > 2) {
sb.append("choose one or more ");
} else if (this.getMinModes() == 1 && this.getMaxModes() == 2) {
sb.append("choose one or both ");

View file

@ -494,7 +494,11 @@ public class ContinuousEffects implements Serializable {
if (affectedAbility != null && affectedAbility.getSourceObject(game) instanceof SplitCardHalf) {
idToCheck = ((SplitCardHalf) affectedAbility.getSourceObject(game)).getParentCard().getId();
} else {
idToCheck = objectId;
if (game.getObject(objectId) instanceof SplitCardHalf) {
idToCheck = ((SplitCardHalf) game.getObject(objectId)).getParentCard().getId();
} else {
idToCheck = objectId;
}
}
for (AsThoughEffect effect : asThoughEffectsList) {
Set<Ability> abilities = asThoughEffectsMap.get(type).getAbility(effect.getId());

View file

@ -3,10 +3,13 @@ package mage.abilities.effects.common.cost;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.constants.ComparisonType;
import mage.constants.Outcome;
import mage.filter.FilterCard;
import mage.filter.common.FilterNonlandCard;
import mage.filter.predicate.mageobject.ConvertedManaCostPredicate;
import mage.game.Game;
@ -25,23 +28,23 @@ import org.apache.log4j.Logger;
*/
public class CastWithoutPayingManaCostEffect extends OneShotEffect {
private final FilterNonlandCard filter;
private final int manaCost;
private final DynamicValue manaCost;
/**
* @param maxCost Maximum converted mana cost for this effect to apply to
*/
public CastWithoutPayingManaCostEffect(int maxCost) {
this(new StaticValue(maxCost));
}
public CastWithoutPayingManaCostEffect(DynamicValue maxCost) {
super(Outcome.PlayForFree);
filter = new FilterNonlandCard("card with converted mana cost " + maxCost + " or less from your hand");
filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, maxCost + 1));
this.manaCost = maxCost;
this.staticText = "you may cast a card with converted mana cost " + maxCost + " or less from your hand without paying its mana cost";
}
public CastWithoutPayingManaCostEffect(final CastWithoutPayingManaCostEffect effect) {
super(effect);
this.filter = effect.filter.copy();
this.manaCost = effect.manaCost;
}
@ -52,11 +55,14 @@ public class CastWithoutPayingManaCostEffect extends OneShotEffect {
if (controller == null) {
return false;
}
int cmc = manaCost.calculate(game, source, this);
FilterCard filter = new FilterNonlandCard("card with converted mana cost " + cmc + " or less from your hand");
filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, cmc + 1));
Target target = new TargetCardInHand(filter);
if (target.canChoose(source.getSourceId(), controller.getId(), game)
&& controller.chooseUse(outcome, "Cast a card with converted mana cost " + manaCost
+ " or less from your hand without paying its mana cost?", source, game)) {
&& controller.chooseUse(outcome, "Cast a card with converted mana cost " + cmc
+ " or less from your hand without paying its mana cost?", source, game)) {
Card cardToCast = null;
boolean cancel = false;
while (controller.canRespond() && !cancel) {

View file

@ -0,0 +1,62 @@
package mage.abilities.effects.common.ruleModifying;
import mage.abilities.Ability;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.constants.Duration;
import mage.constants.Layer;
import mage.constants.Outcome;
import mage.constants.SubLayer;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.game.Game;
/**
* @author TheElk801
*/
public class CombatDamageByToughnessEffect extends ContinuousEffectImpl {
private final FilterCreaturePermanent filter;
private final boolean onlyControlled;
public CombatDamageByToughnessEffect(FilterCreaturePermanent filter, boolean onlyControlled) {
super(Duration.WhileOnBattlefield, Outcome.Detriment);
this.filter = filter;
this.onlyControlled = onlyControlled;
staticText = "Each " + filter.getMessage() + (onlyControlled ? " you control" : "") +
" assigns combat damage equal to its toughness rather than its power";
}
public CombatDamageByToughnessEffect(final CombatDamageByToughnessEffect effect) {
super(effect);
this.filter = effect.filter;
this.onlyControlled = effect.onlyControlled;
}
@Override
public CombatDamageByToughnessEffect copy() {
return new CombatDamageByToughnessEffect(this);
}
@Override
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
// Change the rule
FilterCreaturePermanent filterPermanent = filter.copy();
if (onlyControlled) {
filterPermanent.add(new ControllerIdPredicate(source.getControllerId()));
}
game.getCombat().setUseToughnessForDamage(true);
game.getCombat().addUseToughnessForDamageFilter(filterPermanent);
return true;
}
@Override
public boolean apply(Game game, Ability source) {
return false;
}
@Override
public boolean hasLayer(Layer layer) {
return layer == Layer.RulesEffects;
}
}

View file

@ -5,6 +5,7 @@ import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.util.CardUtil;
@ -40,8 +41,15 @@ public class AdaptEffect extends OneShotEffect {
if (permanent == null) {
return false;
}
if (permanent.getCounters(game).getCount(CounterType.P1P1) == 0) {
permanent.addCounters(CounterType.P1P1.createInstance(adaptNumber), source, game);
GameEvent event = new GameEvent(
GameEvent.EventType.ADAPT, source.getSourceId(), source.getSourceId(),
source.getControllerId(), adaptNumber, false
);
if (game.replaceEvent(event)) {
return false;
}
if (permanent.getCounters(game).getCount(CounterType.P1P1) == 0 || event.getFlag()) {
permanent.addCounters(CounterType.P1P1.createInstance(event.getAmount()), source, game);
}
return true;
}

View file

@ -0,0 +1,27 @@
package mage.abilities.keyword;
import mage.abilities.ActivatedAbilityImpl;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.keyword.AdaptEffect;
import mage.constants.Zone;
/**
* @author TheElk801
*/
public class AdaptAbility extends ActivatedAbilityImpl {
public AdaptAbility(int adaptNumber, String manaCost) {
super(Zone.BATTLEFIELD, new AdaptEffect(adaptNumber), new ManaCostsImpl(manaCost));
}
public AdaptAbility(final AdaptAbility ability) {
super(ability);
}
@Override
public AdaptAbility copy() {
return new AdaptAbility(this);
}
}

View file

@ -1,14 +1,14 @@
package mage.game.events;
import mage.MageObjectReference;
import mage.constants.Zone;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.MageObjectReference;
import mage.constants.Zone;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class GameEvent implements Serializable {
@ -232,6 +232,7 @@ public class GameEvent implements Serializable {
FLIP, FLIPPED,
UNFLIP, UNFLIPPED,
TRANSFORM, TRANSFORMED,
ADAPT,
BECOMES_MONSTROUS,
BECOMES_EXERTED,
/* BECOMES_EXERTED
@ -383,12 +384,12 @@ public class GameEvent implements Serializable {
}
private GameEvent(EventType type, UUID customEventType,
UUID targetId, UUID sourceId, UUID playerId, int amount, boolean flag) {
UUID targetId, UUID sourceId, UUID playerId, int amount, boolean flag) {
this(type, customEventType, targetId, sourceId, playerId, amount, flag, null);
}
private GameEvent(EventType type, UUID customEventType,
UUID targetId, UUID sourceId, UUID playerId, int amount, boolean flag, MageObjectReference reference) {
UUID targetId, UUID sourceId, UUID playerId, int amount, boolean flag, MageObjectReference reference) {
this.type = type;
this.customEventType = customEventType;
this.targetId = targetId;
@ -466,7 +467,7 @@ public class GameEvent implements Serializable {
/**
* used to store which replacement effects were already applied to an event
* or or any modified events that may replace it
*
* <p>
* 614.5. A replacement effect doesn't invoke itself repeatedly; it gets
* only one opportunity to affect an event or any modified events that may
* replace it. Example: A player controls two permanents, each with an

View file

@ -1,9 +1,6 @@
package mage.game.permanent;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import mage.MageObject;
import mage.MageObjectReference;
import mage.abilities.Ability;
@ -14,6 +11,10 @@ import mage.game.Controllable;
import mage.game.Game;
import mage.game.GameState;
import java.util.List;
import java.util.Set;
import java.util.UUID;
public interface Permanent extends Card, Controllable {
void setControllerId(UUID controllerId);
@ -106,6 +107,8 @@ public interface Permanent extends Card, Controllable {
int getDamage();
int damage(int damage, UUID sourceId, Game game);
int damage(int damage, UUID sourceId, Game game, boolean combat, boolean preventable);
int damage(int damage, UUID sourceId, Game game, boolean combat, boolean preventable, List<UUID> appliedEffects);

View file

@ -711,6 +711,11 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
return this.damage;
}
@Override
public int damage(int damage, UUID sourceId, Game game) {
return damage(damage, sourceId, game, true, false, false, null);
}
@Override
public int damage(int damage, UUID sourceId, Game game, boolean combat, boolean preventable) {
return damage(damage, sourceId, game, preventable, combat, false, null);

View file

@ -1,7 +1,5 @@
package mage.players;
import java.io.Serializable;
import java.util.*;
import mage.MageItem;
import mage.MageObject;
import mage.MageObjectReference;
@ -39,6 +37,9 @@ import mage.target.TargetCard;
import mage.target.common.TargetCardInLibrary;
import mage.util.Copyable;
import java.io.Serializable;
import java.util.*;
/**
* @author BetaSteward_at_googlemail.com
*/
@ -84,6 +85,8 @@ public interface Player extends MageItem, Copyable<Player> {
int gainLife(int amount, Game game, UUID sourceId);
int damage(int damage, UUID sourceId, Game game);
int damage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable);
int damage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable, List<UUID> appliedEffects);

View file

@ -1919,6 +1919,11 @@ public abstract class PlayerImpl implements Player, Serializable {
return 0;
}
@Override
public int damage(int damage, UUID sourceId, Game game) {
return doDamage(damage, sourceId, game, true, false, null);
}
@Override
public int damage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable) {
return doDamage(damage, sourceId, game, combatDamage, preventable, null);
@ -2491,7 +2496,7 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override
public void lookAtAllLibraries(Ability source, Game game) {
for(UUID playerId : game.getState().getPlayersInRange(this.getId(), game)){
for (UUID playerId : game.getState().getPlayersInRange(this.getId(), game)) {
Player player = game.getPlayer(playerId);
String playerName = this.getName().equals(player.getName()) ? "Your " : player.getName() + "'s ";
playerName += "library";