mirror of
https://github.com/magefree/mage.git
synced 2025-12-24 12:31:59 -08:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
83cf370cc6
59 changed files with 2566 additions and 373 deletions
|
|
@ -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 ");
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
27
Mage/src/main/java/mage/abilities/keyword/AdaptAbility.java
Normal file
27
Mage/src/main/java/mage/abilities/keyword/AdaptAbility.java
Normal 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue