forked from External/mage
Merge branch 'External-master'
All checks were successful
/ example-docker-compose (push) Successful in 25m30s
All checks were successful
/ example-docker-compose (push) Successful in 25m30s
This commit is contained in:
commit
9e6e731a9e
110 changed files with 5687 additions and 591 deletions
|
|
@ -5,10 +5,7 @@ import mage.constants.ColoredManaSymbol;
|
|||
import mage.util.Copyable;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
|
||||
public class ObjectColor implements Serializable, Copyable<ObjectColor>, Comparable<ObjectColor> {
|
||||
|
||||
|
|
@ -19,17 +16,13 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
|
|||
public static final ObjectColor GREEN = new ObjectColor("G");
|
||||
|
||||
public static final ObjectColor COLORLESS = new ObjectColor();
|
||||
|
||||
public static final ObjectColor GOLD = new ObjectColor("O"); // Not multicolored - Sword of Dungeons & Dragons
|
||||
|
||||
private static final List<ObjectColor>allColors= Arrays.asList(WHITE,BLUE,BLACK,RED,GREEN);
|
||||
private boolean white;
|
||||
private boolean blue;
|
||||
private boolean black;
|
||||
private boolean red;
|
||||
private boolean green;
|
||||
|
||||
private boolean gold;
|
||||
|
||||
public ObjectColor() {
|
||||
}
|
||||
|
||||
|
|
@ -51,10 +44,6 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
|
|||
case 'G':
|
||||
green = true;
|
||||
break;
|
||||
|
||||
case 'O':
|
||||
gold = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -65,8 +54,6 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
|
|||
black = color.black;
|
||||
red = color.red;
|
||||
green = color.green;
|
||||
|
||||
gold = color.gold;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -83,8 +70,6 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
|
|||
newColor.black = black || other.black;
|
||||
newColor.red = red || other.red;
|
||||
newColor.green = green || other.green;
|
||||
|
||||
newColor.gold = gold || other.gold;
|
||||
return newColor;
|
||||
}
|
||||
|
||||
|
|
@ -102,8 +87,6 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
|
|||
newColor.black = black && other.black;
|
||||
newColor.red = red && other.red;
|
||||
newColor.green = green && other.green;
|
||||
|
||||
newColor.gold = gold && other.gold;
|
||||
return newColor;
|
||||
}
|
||||
|
||||
|
|
@ -124,10 +107,6 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
|
|||
if (red) {
|
||||
count++;
|
||||
}
|
||||
|
||||
if (gold) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
|
@ -176,10 +155,6 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
|
|||
if (colors.size() >= 2 && secondColor - firstColor >= 3) {
|
||||
Collections.swap(colors, 0, 1);
|
||||
}
|
||||
|
||||
if (this.isGold()) {
|
||||
colors.add(ObjectColor.GOLD);
|
||||
}
|
||||
return colors;
|
||||
}
|
||||
|
||||
|
|
@ -189,8 +164,6 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
|
|||
this.setGreen(color != null && color.isGreen());
|
||||
this.setRed(color != null && color.isRed());
|
||||
this.setWhite(color != null && color.isWhite());
|
||||
|
||||
this.setGold(color != null && color.isGold());
|
||||
}
|
||||
|
||||
public void addColor(ObjectColor color) {
|
||||
|
|
@ -209,10 +182,6 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
|
|||
if (color.isGreen()) {
|
||||
setGreen(true);
|
||||
}
|
||||
|
||||
if (color.isGold()) {
|
||||
setGold(true);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isColorless() {
|
||||
|
|
@ -220,32 +189,26 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
|
|||
}
|
||||
|
||||
public boolean hasColor() {
|
||||
return white || blue || black || red || green
|
||||
|| gold;
|
||||
return white || blue || black || red || green;
|
||||
}
|
||||
|
||||
public boolean isMulticolored() {
|
||||
if (isColorless()) {
|
||||
return false;
|
||||
}
|
||||
if (white && (blue || black || red || green
|
||||
|| gold)) {
|
||||
return true;
|
||||
if (white) {
|
||||
return blue || black || red || green;
|
||||
}
|
||||
if (blue && (black || red || green
|
||||
|| gold)) {
|
||||
return true;
|
||||
if (blue) {
|
||||
return black || red || green;
|
||||
}
|
||||
if (black && (red || green
|
||||
|| gold)) {
|
||||
return true;
|
||||
if (black) {
|
||||
return red || green;
|
||||
}
|
||||
if (red && (green
|
||||
|| gold)) {
|
||||
return true;
|
||||
if (red) {
|
||||
return green;
|
||||
}
|
||||
return green
|
||||
&& gold;
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isWhite() {
|
||||
|
|
@ -288,14 +251,6 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
|
|||
this.green = green;
|
||||
}
|
||||
|
||||
public boolean isGold() {
|
||||
return gold;
|
||||
}
|
||||
|
||||
public void setGold(boolean gold) {
|
||||
this.gold = gold;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(5);
|
||||
|
|
@ -314,36 +269,27 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
|
|||
if (green) {
|
||||
sb.append('G');
|
||||
}
|
||||
|
||||
if (gold) {
|
||||
sb.append('O');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
if (getColorCount() > 1) {
|
||||
if (isMulticolored()) {
|
||||
return "multicolored";
|
||||
} else {
|
||||
if (white) {
|
||||
return "white";
|
||||
}
|
||||
if (blue) {
|
||||
return "blue";
|
||||
}
|
||||
if (black) {
|
||||
return "black";
|
||||
}
|
||||
if (red) {
|
||||
return "red";
|
||||
}
|
||||
if (green) {
|
||||
return "green";
|
||||
}
|
||||
|
||||
if (gold) {
|
||||
return "gold";
|
||||
}
|
||||
}
|
||||
if (white) {
|
||||
return "white";
|
||||
}
|
||||
if (blue) {
|
||||
return "blue";
|
||||
}
|
||||
if (black) {
|
||||
return "black";
|
||||
}
|
||||
if (red) {
|
||||
return "red";
|
||||
}
|
||||
if (green) {
|
||||
return "green";
|
||||
}
|
||||
return "colorless";
|
||||
}
|
||||
|
|
@ -372,10 +318,6 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
|
|||
if (test.green != this.green) {
|
||||
return false;
|
||||
}
|
||||
if (test.gold != this.gold) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -387,8 +329,6 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
|
|||
hash = 23 * hash + (this.black ? 1 : 0);
|
||||
hash = 23 * hash + (this.red ? 1 : 0);
|
||||
hash = 23 * hash + (this.green ? 1 : 0);
|
||||
|
||||
hash = 23 * hash + (this.gold ? 1 : 0);
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
|
@ -411,10 +351,6 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
|
|||
if (color.green && this.green) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (color.gold && this.gold) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -422,8 +358,7 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
|
|||
// 105.4. [...] “Multicolored” is not a color. Neither is “colorless.”
|
||||
return !color.isColorless()
|
||||
&& (color.white && white || color.blue && blue || color.black && black
|
||||
|| color.red && red || color.green && green
|
||||
|| color.gold && gold);
|
||||
|| color.red && red || color.green && green);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -450,8 +385,6 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
|
|||
o1 = 4;
|
||||
} else if (this.isWhite()) {
|
||||
o1 = 5;
|
||||
} else if (this.isGold()) {
|
||||
o1 = 6;
|
||||
}
|
||||
|
||||
if (o.isMulticolored()) {
|
||||
|
|
@ -468,8 +401,6 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
|
|||
o2 = 4;
|
||||
} else if (o.isWhite()) {
|
||||
o2 = 5;
|
||||
} else if (o.isGold()) {
|
||||
o2 = 6;
|
||||
}
|
||||
|
||||
return o1 - o2;
|
||||
|
|
@ -482,7 +413,6 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
|
|||
* @return null or
|
||||
*/
|
||||
public ColoredManaSymbol getOneColoredManaSymbol() {
|
||||
|
||||
if (isMulticolored()) {
|
||||
throw new IllegalStateException("Found multicolor object, but was waiting for simple color.");
|
||||
}
|
||||
|
|
@ -503,21 +433,10 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
|
|||
return ColoredManaSymbol.W;
|
||||
}
|
||||
|
||||
if (isGold()) {
|
||||
return ColoredManaSymbol.O;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<ObjectColor> getAllColors() {
|
||||
List<ObjectColor> colors = new ArrayList<>();
|
||||
colors.add(ObjectColor.WHITE);
|
||||
colors.add(ObjectColor.BLUE);
|
||||
colors.add(ObjectColor.BLACK);
|
||||
colors.add(ObjectColor.RED);
|
||||
colors.add(ObjectColor.GREEN);
|
||||
|
||||
colors.add(ObjectColor.GOLD);
|
||||
return colors;
|
||||
return allColors;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,20 +18,27 @@ import java.util.Objects;
|
|||
public class CardsLeaveGraveyardTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private final FilterCard filter;
|
||||
private final boolean yourTurn;
|
||||
|
||||
public CardsLeaveGraveyardTriggeredAbility(Effect effect) {
|
||||
this(effect, StaticFilters.FILTER_CARD_CARDS);
|
||||
}
|
||||
|
||||
public CardsLeaveGraveyardTriggeredAbility(Effect effect, FilterCard filter) {
|
||||
this(effect, filter, false);
|
||||
}
|
||||
|
||||
public CardsLeaveGraveyardTriggeredAbility(Effect effect, FilterCard filter, boolean yourTurn) {
|
||||
super(Zone.BATTLEFIELD, effect, false);
|
||||
this.filter = filter;
|
||||
setTriggerPhrase("Whenever one or more " + filter + " leave your graveyard, ");
|
||||
this.yourTurn = yourTurn;
|
||||
setTriggerPhrase("Whenever one or more " + filter + " leave your graveyard" + (yourTurn ? " during your turn" : "") + ", ");
|
||||
}
|
||||
|
||||
private CardsLeaveGraveyardTriggeredAbility(final CardsLeaveGraveyardTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.filter = ability.filter;
|
||||
this.yourTurn = ability.yourTurn;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -41,6 +48,9 @@ public class CardsLeaveGraveyardTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (yourTurn && !isControlledBy(game.getActivePlayerId())) {
|
||||
return false;
|
||||
}
|
||||
ZoneChangeGroupEvent zEvent = (ZoneChangeGroupEvent) event;
|
||||
return zEvent != null
|
||||
&& Zone.GRAVEYARD == zEvent.getFromZone()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.keyword.BeholdDragonAbility;
|
||||
import mage.game.Game;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
* Checks if the spell was cast with the alternate behold a Dragon cost
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public enum BeheldDragonCondition implements Condition {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return CardUtil.checkSourceCostsTagExists(game, source, BeholdDragonAbility.BEHOLD_DRAGON_ACTIVATION_VALUE_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Dragon was beheld";
|
||||
}
|
||||
}
|
||||
|
|
@ -4,72 +4,65 @@ import mage.ObjectColor;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.predicate.Predicate;
|
||||
import mage.filter.predicate.mageobject.ColorPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class MostCommonColorCondition implements Condition {
|
||||
|
||||
protected final ObjectColor compareColor;
|
||||
protected final boolean isMono;
|
||||
protected final Predicate predicate;
|
||||
protected final FilterPermanent filter;
|
||||
|
||||
public MostCommonColorCondition(ObjectColor color) {
|
||||
this(color, false, null);
|
||||
}
|
||||
|
||||
//Use this one if you don't want a tie for most common and want to restrict to a player (literally only Call to Arms)
|
||||
// Use this one if you don't want a tie for most common and want to restrict to a player (literally only Call to Arms)
|
||||
public MostCommonColorCondition(ObjectColor color, boolean isMono, Predicate predicate) {
|
||||
this.compareColor = color;
|
||||
this.isMono = isMono;
|
||||
this.predicate = predicate;
|
||||
if (predicate == null) {
|
||||
this.filter = StaticFilters.FILTER_PERMANENT;
|
||||
} else {
|
||||
this.filter = new FilterPermanent();
|
||||
this.filter.add(predicate);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
FilterPermanent[] colorFilters = new FilterPermanent[6];
|
||||
int i = 0;
|
||||
for (ObjectColor color : ObjectColor.getAllColors()) {
|
||||
colorFilters[i] = new FilterPermanent();
|
||||
colorFilters[i].add(new ColorPredicate(color));
|
||||
if (predicate != null) {
|
||||
colorFilters[i].add(predicate);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
int[] colorCounts = new int[6];
|
||||
i = 0;
|
||||
for (ObjectColor color : ObjectColor.getAllColors()) {
|
||||
colorFilters[i].add(new ColorPredicate(color));
|
||||
colorCounts[i] = game.getBattlefield().count(colorFilters[i], source.getControllerId(), source, game);
|
||||
i++;
|
||||
}
|
||||
int max = 0;
|
||||
for (i = 0; i < 5; i++) {
|
||||
if (colorCounts[i] > max) {
|
||||
max = colorCounts[i] * 1;
|
||||
Map<String, Integer> colorMap = new HashMap<>();
|
||||
for (Permanent permanent : game
|
||||
.getBattlefield()
|
||||
.getActivePermanents(filter, source.getControllerId(), source, game)) {
|
||||
for (char c : permanent.getColor(game).toString().toCharArray()) {
|
||||
colorMap.compute("" + c, CardUtil::setOrIncrementValue);
|
||||
}
|
||||
}
|
||||
i = 0;
|
||||
ObjectColor commonest = new ObjectColor();
|
||||
for (ObjectColor color : ObjectColor.getAllColors()) {
|
||||
if (colorCounts[i] == max) {
|
||||
commonest.addColor(color);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (compareColor.shares(commonest)) {
|
||||
if (isMono) {
|
||||
return !commonest.isMulticolored();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
int most = colorMap
|
||||
.values()
|
||||
.stream()
|
||||
.mapToInt(x -> x)
|
||||
.max()
|
||||
.orElse(0);
|
||||
ObjectColor common = new ObjectColor(
|
||||
colorMap.entrySet()
|
||||
.stream()
|
||||
.filter(e -> e.getValue() == most)
|
||||
.map(Map.Entry::getKey)
|
||||
.collect(Collectors.joining())
|
||||
);
|
||||
return common.shares(compareColor) && (!isMono || common.getColorCount() == 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,27 +1,37 @@
|
|||
package mage.abilities.effects.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.token.Token;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author weirddan455
|
||||
*/
|
||||
public class CreateTokenAttachSourceEffect extends CreateTokenEffect {
|
||||
|
||||
private final boolean optional;
|
||||
|
||||
public CreateTokenAttachSourceEffect(Token token) {
|
||||
this(token, ", then");
|
||||
}
|
||||
|
||||
public CreateTokenAttachSourceEffect(Token token, String innerConcat) {
|
||||
this(token, innerConcat, false);
|
||||
}
|
||||
|
||||
public CreateTokenAttachSourceEffect(Token token, String innerConcat, boolean optional) {
|
||||
super(token);
|
||||
staticText = staticText.concat(innerConcat + " attach {this} to it");
|
||||
this.optional = optional;
|
||||
staticText = staticText.concat(innerConcat + (optional ? " you may" : "") + " attach {this} to it");
|
||||
}
|
||||
|
||||
private CreateTokenAttachSourceEffect(final CreateTokenAttachSourceEffect effect) {
|
||||
super(effect);
|
||||
this.optional = effect.optional;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -32,11 +42,22 @@ public class CreateTokenAttachSourceEffect extends CreateTokenEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
super.apply(game, source);
|
||||
Permanent token = game.getPermanent(this.getLastAddedTokenIds().stream().findFirst().orElse(null));
|
||||
if (token != null) {
|
||||
token.addAttachment(source.getSourceId(), source, game);
|
||||
return true;
|
||||
Permanent token = this
|
||||
.getLastAddedTokenIds()
|
||||
.stream()
|
||||
.findFirst()
|
||||
.map(game::getPermanent)
|
||||
.orElse(null);
|
||||
if (token == null || optional
|
||||
&& !Optional
|
||||
.ofNullable(game.getPlayer(source.getControllerId()))
|
||||
.map(player -> player.chooseUse(
|
||||
Outcome.BoostCreature, "Attach the equipment to the token?", source, game
|
||||
))
|
||||
.orElse(false)) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
token.addAttachment(source.getSourceId(), source, game);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
package mage.abilities.effects.mana;
|
||||
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.choices.Choice;
|
||||
import mage.constants.ManaType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class AddManaFromColorChoicesEffect extends ManaEffect {
|
||||
|
||||
private final List<ManaType> manaTypes = new ArrayList<>();
|
||||
private final List<Mana> netMana = new ArrayList<>();
|
||||
|
||||
public AddManaFromColorChoicesEffect(ManaType... manaTypes) {
|
||||
super();
|
||||
for (ManaType manaType : manaTypes) {
|
||||
this.manaTypes.add(manaType);
|
||||
}
|
||||
this.manaTypes
|
||||
.stream()
|
||||
.map(CardUtil::manaTypeToColoredManaSymbol)
|
||||
.map(Mana::new)
|
||||
.forEach(netMana::add);
|
||||
staticText = "add " + CardUtil
|
||||
.concatWithOr(this.netMana.stream().map(s -> "{" + s + '}').collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
private AddManaFromColorChoicesEffect(final AddManaFromColorChoicesEffect effect) {
|
||||
super(effect);
|
||||
this.manaTypes.addAll(effect.manaTypes);
|
||||
effect.netMana.stream().map(Mana::copy).forEach(this.netMana::add);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddManaFromColorChoicesEffect copy() {
|
||||
return new AddManaFromColorChoicesEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Mana> getNetMana(Game game, Ability source) {
|
||||
return netMana;
|
||||
}
|
||||
|
||||
public List<Mana> getNetMana() {
|
||||
return netMana;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mana produceMana(Game game, Ability source) {
|
||||
if (game == null || manaTypes.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
Choice choice = ManaType.getChoiceOfManaTypes(manaTypes, false);
|
||||
if (choice.getChoices().size() <= 1) {
|
||||
choice.setChoice(choice.getChoices().iterator().next());
|
||||
} else {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (player == null || !player.choose(Outcome.PutManaInPool, choice, game)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
ManaType chosenType = ManaType.findByName(choice.getChoice());
|
||||
return chosenType == null ? null : new Mana(chosenType);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.StaticAbility;
|
||||
import mage.abilities.costs.*;
|
||||
import mage.abilities.costs.common.BeholdDragonCost;
|
||||
import mage.abilities.costs.common.CollectEvidenceCost;
|
||||
import mage.abilities.hint.common.EvidenceHint;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class BeholdDragonAbility extends StaticAbility implements OptionalAdditionalSourceCosts {
|
||||
|
||||
private static final String promptString = "Behold a Dragon";
|
||||
private static final String keywordText = "As an additional cost to cast this spell, you may behold a Dragon";
|
||||
private static final String reminderText = "Choose a Dragon you control or reveal a Dragon card from your hand.";
|
||||
private final String rule;
|
||||
|
||||
public static final String BEHOLD_DRAGON_ACTIVATION_VALUE_KEY = "beholdDragonActivation";
|
||||
|
||||
protected OptionalAdditionalCost additionalCost;
|
||||
|
||||
public static OptionalAdditionalCost makeCost() {
|
||||
OptionalAdditionalCost cost = new OptionalAdditionalCostImpl(keywordText , reminderText, new BeholdDragonCost());
|
||||
cost.setRepeatable(false);
|
||||
return cost;
|
||||
}
|
||||
public BeholdDragonAbility( ) {
|
||||
super(Zone.STACK, null);
|
||||
this.additionalCost = makeCost();
|
||||
this.rule = additionalCost.getName() + ". " + additionalCost.getReminderText();
|
||||
this.setRuleAtTheTop(true);
|
||||
}
|
||||
|
||||
private BeholdDragonAbility(final BeholdDragonAbility ability) {
|
||||
super(ability);
|
||||
this.rule = ability.rule;
|
||||
this.additionalCost = ability.additionalCost.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeholdDragonAbility copy() {
|
||||
return new BeholdDragonAbility(this);
|
||||
}
|
||||
|
||||
public void resetCost() {
|
||||
if (additionalCost != null) {
|
||||
additionalCost.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOptionalAdditionalCosts(Ability ability, Game game) {
|
||||
if (!(ability instanceof SpellAbility)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = game.getPlayer(ability.getControllerId());
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.resetCost();
|
||||
boolean canPay = additionalCost.canPay(ability, this, ability.getControllerId(), game);
|
||||
if (!canPay || !player.chooseUse(Outcome.Exile, promptString + '?', ability, game)) {
|
||||
return;
|
||||
}
|
||||
|
||||
additionalCost.activate();
|
||||
for (Cost cost : ((Costs<Cost>) additionalCost)) {
|
||||
ability.getCosts().add(cost.copy());
|
||||
}
|
||||
ability.setCostsTag(BEHOLD_DRAGON_ACTIVATION_VALUE_KEY, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCastMessageSuffix() {
|
||||
return additionalCost.getCastSuffixMessage(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return rule;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Zone;
|
||||
|
||||
/**
|
||||
* TODO: Implement this
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class HarmonizeAbility extends SpellAbility {
|
||||
|
||||
public HarmonizeAbility(Card card, String manaString) {
|
||||
super(new ManaCostsImpl<>(manaString), card.getName(), Zone.GRAVEYARD);
|
||||
}
|
||||
|
||||
private HarmonizeAbility(final HarmonizeAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HarmonizeAbility copy() {
|
||||
return new HarmonizeAbility(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,12 +2,13 @@ package mage.abilities.keyword;
|
|||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.AttacksTriggeredAbility;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.dynamicvalue.common.StaticValue;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.CreateTokenEffect;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.token.RedWarriorToken;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
|
|
@ -16,10 +17,11 @@ import mage.util.CardUtil;
|
|||
public class MobilizeAbility extends AttacksTriggeredAbility {
|
||||
|
||||
public MobilizeAbility(int count) {
|
||||
super(new MobilizeEffect(count), false, "Mobilize " + count + " <i>(Whenever this creature attacks, create "
|
||||
+ (count == 1 ? "a" : CardUtil.numberToText(count)) + " tapped and attacking 1/1 red Warrior creature "
|
||||
+ (count == 1 ? "token" : "tokens") + ". Sacrifice " + (count == 1 ? "it" : "them")
|
||||
+ " at the beginning of the next end step.)");
|
||||
this(StaticValue.get(count));
|
||||
}
|
||||
|
||||
public MobilizeAbility(DynamicValue count) {
|
||||
super(new MobilizeEffect(count), false, makeText(count));
|
||||
}
|
||||
|
||||
protected MobilizeAbility(final MobilizeAbility ability) {
|
||||
|
|
@ -30,13 +32,33 @@ public class MobilizeAbility extends AttacksTriggeredAbility {
|
|||
public MobilizeAbility copy() {
|
||||
return new MobilizeAbility(this);
|
||||
}
|
||||
|
||||
private static String makeText(DynamicValue amount) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String message;
|
||||
String numToText;
|
||||
boolean plural;
|
||||
if (amount instanceof StaticValue) {
|
||||
int count = ((StaticValue) amount).getValue();
|
||||
message = "" + count;
|
||||
numToText = CardUtil.numberToText(count, "a");
|
||||
plural = count > 1;
|
||||
} else {
|
||||
message = "X, where X is " + amount.getMessage() + '.';
|
||||
numToText = "X";
|
||||
plural = true;
|
||||
}
|
||||
return "Mobilize " + message + " <i>(Whenever this creature attacks, create " +
|
||||
numToText + " tapped and attacking 1/1 red Warrior creature token" + (plural ? "s" : "") +
|
||||
". Sacrifice " + (plural ? "them" : "it") + " at the beginning of the next end step.)</i>";
|
||||
}
|
||||
}
|
||||
|
||||
class MobilizeEffect extends OneShotEffect {
|
||||
|
||||
private final int count;
|
||||
private final DynamicValue count;
|
||||
|
||||
MobilizeEffect(int count) {
|
||||
MobilizeEffect(DynamicValue count) {
|
||||
super(Outcome.Benefit);
|
||||
this.count = count;
|
||||
}
|
||||
|
|
@ -53,13 +75,9 @@ class MobilizeEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
CreateTokenEffect effect = new CreateTokenEffect(new RedWarriorToken(), this.count, true, true);
|
||||
effect.apply(game, source);
|
||||
effect.sacrificeTokensCreatedAtNextEndStep(game, source);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package mage.abilities.mana;
|
|||
import mage.MageIdentifier;
|
||||
import mage.Mana;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.effects.mana.AddManaFromColorChoicesEffect;
|
||||
import mage.abilities.effects.mana.AddManaOfAnyColorEffect;
|
||||
import mage.abilities.effects.mana.BasicManaEffect;
|
||||
import mage.abilities.effects.mana.ManaEffect;
|
||||
|
|
@ -37,6 +38,14 @@ public class LimitedTimesPerTurnActivatedManaAbility extends ActivatedManaAbilit
|
|||
new Mana(0, 0, 0, 0, 0, 0, effect.getAmount(), 0));
|
||||
}
|
||||
|
||||
public LimitedTimesPerTurnActivatedManaAbility(AddManaFromColorChoicesEffect effect, Cost cost) {
|
||||
this(effect, cost, 1);
|
||||
}
|
||||
|
||||
public LimitedTimesPerTurnActivatedManaAbility(AddManaFromColorChoicesEffect effect, Cost cost, int maxActivationPerTurn) {
|
||||
this(Zone.BATTLEFIELD, effect, cost, maxActivationPerTurn, effect.getNetMana());
|
||||
}
|
||||
|
||||
public LimitedTimesPerTurnActivatedManaAbility(Zone zone, ManaEffect effect, Cost cost, int maxActivationPerTurn, Mana mana) {
|
||||
this(zone, effect, cost, maxActivationPerTurn, Arrays.asList(mana));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,12 @@
|
|||
package mage.constants;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import mage.Mana;
|
||||
import mage.choices.Choice;
|
||||
import mage.choices.ChoiceColor;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author North
|
||||
*/
|
||||
public enum ManaType {
|
||||
|
|
@ -34,7 +30,7 @@ public enum ManaType {
|
|||
return text;
|
||||
}
|
||||
|
||||
public static Choice getChoiceOfManaTypes(Set<ManaType> types, boolean onlyColors) {
|
||||
public static Choice getChoiceOfManaTypes(Collection<ManaType> types, boolean onlyColors) {
|
||||
Choice choice = new ChoiceColor(true);
|
||||
choice.getChoices().clear();
|
||||
choice.setMessage("Pick a mana " + (onlyColors ? "color" : "type"));
|
||||
|
|
@ -124,8 +120,8 @@ public enum ManaType {
|
|||
* <p>
|
||||
* Used for things like mapping back to a ManaType after the user chose from several of them.
|
||||
*
|
||||
* @param name The name of the mana to find
|
||||
* @return The ManaType representing that mana (or null)
|
||||
* @param name The name of the mana to find
|
||||
* @return The ManaType representing that mana (or null)
|
||||
*/
|
||||
public static ManaType findByName(String name) {
|
||||
switch (name) {
|
||||
|
|
@ -153,6 +149,7 @@ public enum ManaType {
|
|||
}
|
||||
return manaTypes;
|
||||
}
|
||||
|
||||
public static Set<ManaType> getTrueManaTypes() {
|
||||
return EnumSet.of(BLACK, BLUE, GREEN, RED, WHITE, COLORLESS);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import mage.constants.CardType;
|
|||
import mage.constants.SubType;
|
||||
|
||||
/**
|
||||
* This token is supposed to be "gold" but the game rules don't support gold as a color in black border
|
||||
*
|
||||
* @author Saga
|
||||
*/
|
||||
public final class DragonTokenGold extends TokenImpl {
|
||||
|
|
@ -13,7 +15,11 @@ public final class DragonTokenGold extends TokenImpl {
|
|||
public DragonTokenGold() {
|
||||
super("Dragon Token", "4/4 gold Dragon creature token with flying");
|
||||
cardType.add(CardType.CREATURE);
|
||||
color.setGold(true);
|
||||
color.setWhite(true);
|
||||
color.setBlue(true);
|
||||
color.setBlack(true);
|
||||
color.setRed(true);
|
||||
color.setGreen(true);
|
||||
subtype.add(SubType.DRAGON);
|
||||
power = new MageInt(4);
|
||||
toughness = new MageInt(4);
|
||||
|
|
@ -27,4 +33,4 @@ public final class DragonTokenGold extends TokenImpl {
|
|||
public DragonTokenGold copy() {
|
||||
return new DragonTokenGold(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class Elephant55Token extends TokenImpl {
|
||||
|
||||
public Elephant55Token() {
|
||||
super("Elephant Token", "5/5 green Elephant creature token");
|
||||
cardType.add(CardType.CREATURE);
|
||||
color.setGreen(true);
|
||||
subtype.add(SubType.ELEPHANT);
|
||||
power = new MageInt(5);
|
||||
toughness = new MageInt(5);
|
||||
}
|
||||
|
||||
private Elephant55Token(final Elephant55Token token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public Elephant55Token copy() {
|
||||
return new Elephant55Token(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package mage.game.permanent.token;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.effects.common.DamageTargetEffect;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.abilities.keyword.LifelinkAbility;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.target.common.TargetAnyTarget;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public final class ReliquaryDragonToken extends TokenImpl {
|
||||
|
||||
public ReliquaryDragonToken() {
|
||||
super("Reliquary Dragon", "4/4 Dragon creature token named Reliquary Dragon that's all colors. It has flying, lifelink, and \"When this token enters, it deals 3 damage to any target.\"");
|
||||
cardType.add(CardType.CREATURE);
|
||||
color.setWhite(true);
|
||||
color.setBlue(true);
|
||||
color.setBlack(true);
|
||||
color.setRed(true);
|
||||
color.setGreen(true);
|
||||
subtype.add(SubType.DRAGON);
|
||||
power = new MageInt(4);
|
||||
toughness = new MageInt(4);
|
||||
addAbility(FlyingAbility.getInstance());
|
||||
addAbility(LifelinkAbility.getInstance());
|
||||
|
||||
Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(3, "it"));
|
||||
ability.addTarget(new TargetAnyTarget());
|
||||
addAbility(ability);
|
||||
}
|
||||
|
||||
private ReliquaryDragonToken(final ReliquaryDragonToken token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
public ReliquaryDragonToken copy() {
|
||||
return new ReliquaryDragonToken(this);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue