mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-14 01:38:13 +00:00
Merge branch 'master' of git.cardforge.org:core-developers/forge into agetian-master
This commit is contained in:
@@ -1354,7 +1354,7 @@ public class AiController {
|
||||
|
||||
public AiPlayDecision canPlayFromEffectAI(Spell spell, boolean mandatory, boolean withoutPayingManaCost) {
|
||||
int damage = ComputerUtil.getDamageForPlaying(player, spell);
|
||||
if (damage >= player.getLife() && !player.cantLoseForZeroOrLessLife() && player.canLoseLife()) {
|
||||
if (!mandatory && damage >= player.getLife() && !player.cantLoseForZeroOrLessLife() && player.canLoseLife()) {
|
||||
return AiPlayDecision.CurseEffects;
|
||||
}
|
||||
|
||||
|
||||
@@ -2636,7 +2636,7 @@ public class ComputerUtil {
|
||||
continue;
|
||||
}
|
||||
if (trigger.hasParam("ValidCard")) {
|
||||
if (!card.isValid(trigger.getParam("ValidCard"), source.getController(), source, sa)) {
|
||||
if (!card.isValid(trigger.getParam("ValidCard").split(","), source.getController(), source, sa)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,7 +297,7 @@ public class PermanentAi extends SpellAbilityAi {
|
||||
if (!checkPhaseRestrictions(ai, sa, ai.getGame().getPhaseHandler())) {
|
||||
return false;
|
||||
}
|
||||
return mandatory || checkApiLogic(ai, sa);
|
||||
return checkApiLogic(ai, sa) || mandatory;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ public class PlayAi extends SpellAbilityAi {
|
||||
|
||||
spell = (Spell) spell.copyWithDefinedCost(abCost);
|
||||
}
|
||||
if( AiPlayDecision.WillPlay == ((PlayerControllerAi)ai.getController()).getAi().canPlayFromEffectAI(spell, !isOptional, true)) {
|
||||
if (AiPlayDecision.WillPlay == ((PlayerControllerAi)ai.getController()).getAi().canPlayFromEffectAI(spell, !isOptional, true)) {
|
||||
// Before accepting, see if the spell has a valid number of targets (it should at this point).
|
||||
// Proceeding past this point if the spell is not correctly targeted will result
|
||||
// in "Failed to add to stack" error and the card disappearing from the game completely.
|
||||
|
||||
@@ -70,7 +70,9 @@ import forge.util.storage.StorageReaderFolder;
|
||||
* @author Forge
|
||||
* @version $Id: CardSet.java 9708 2011-08-09 19:34:12Z jendave $
|
||||
*/
|
||||
public final class CardEdition implements Comparable<CardEdition> { // immutable
|
||||
public final class CardEdition implements Comparable<CardEdition> {
|
||||
|
||||
// immutable
|
||||
public enum Type {
|
||||
UNKNOWN,
|
||||
|
||||
@@ -234,6 +236,8 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
|
||||
private String code;
|
||||
private String code2;
|
||||
private String mciCode;
|
||||
private String scryfallCode;
|
||||
private String cardsLanguage;
|
||||
private Type type;
|
||||
private String name;
|
||||
private String alias = null;
|
||||
@@ -323,6 +327,8 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
|
||||
public String getCode() { return code; }
|
||||
public String getCode2() { return code2; }
|
||||
public String getMciCode() { return mciCode; }
|
||||
public String getScryfallCode() { return scryfallCode.toLowerCase(); }
|
||||
public String getCardsLangCode() { return cardsLanguage.toLowerCase(); }
|
||||
public Type getType() { return type; }
|
||||
public String getName() { return name; }
|
||||
public String getAlias() { return alias; }
|
||||
@@ -475,7 +481,8 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
|
||||
* rarity - grouping #4
|
||||
* name - grouping #5
|
||||
*/
|
||||
"(^([0-9A-Z]+.?) )?(([SCURML]) )?(.*)$"
|
||||
// "(^(.?[0-9A-Z]+.?))?(([SCURML]) )?(.*)$"
|
||||
"(^(.?[0-9A-Z]+\\S?[A-Z]*)\\s)?(([SCURML])\\s)?(.*)$"
|
||||
);
|
||||
|
||||
ListMultimap<String, CardInSet> cardMap = ArrayListMultimap.create();
|
||||
@@ -541,6 +548,14 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
|
||||
if (res.mciCode == null) {
|
||||
res.mciCode = res.code2.toLowerCase();
|
||||
}
|
||||
res.scryfallCode = section.get("ScryfallCode");
|
||||
if (res.scryfallCode == null){
|
||||
res.scryfallCode = res.code;
|
||||
}
|
||||
res.cardsLanguage = section.get("CardLang");
|
||||
if (res.cardsLanguage == null){
|
||||
res.cardsLanguage = "en";
|
||||
}
|
||||
|
||||
res.boosterArts = section.getInt("BoosterCovers", 1);
|
||||
String boosterDesc = section.get("Booster");
|
||||
|
||||
@@ -118,10 +118,6 @@ public class ImageUtil {
|
||||
return getImageRelativePath(cp, backFace, true, true);
|
||||
}
|
||||
|
||||
public static String getScryfallDownloadUrl(PaperCard cp, boolean backFace, String setCode){
|
||||
return getScryfallDownloadUrl(cp, backFace, setCode, "en");
|
||||
}
|
||||
|
||||
public static String getScryfallDownloadUrl(PaperCard cp, boolean backFace, String setCode, String langCode){
|
||||
String editionCode;
|
||||
if ((setCode != null) && (setCode.length() > 0))
|
||||
|
||||
@@ -807,6 +807,8 @@ public class AbilityUtils {
|
||||
final SpellAbility root = sa.getRootAbility();
|
||||
list = new CardCollection((Card) root.getReplacingObject(AbilityKey.fromString(calcX[0].substring(8))));
|
||||
}
|
||||
// there could be null inside!
|
||||
list = Iterables.filter(list, Card.class);
|
||||
if (list != null) {
|
||||
val = handlePaid(list, calcX[1], card, ability);
|
||||
}
|
||||
@@ -3424,7 +3426,6 @@ public class AbilityUtils {
|
||||
} else {
|
||||
return size;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (string.startsWith("DifferentCMC")) {
|
||||
@@ -3437,14 +3438,13 @@ public class AbilityUtils {
|
||||
|
||||
if (string.startsWith("SumCMC")) {
|
||||
int sumCMC = 0;
|
||||
for(Card c : paidList) {
|
||||
for (Card c : paidList) {
|
||||
sumCMC += c.getCMC();
|
||||
}
|
||||
return sumCMC;
|
||||
}
|
||||
|
||||
if (string.startsWith("Valid")) {
|
||||
|
||||
final String[] splitString = string.split("/", 2);
|
||||
String valid = splitString[0].substring(6);
|
||||
final List<Card> list = CardLists.getValidCardsAsList(paidList, valid, source.getController(), source, ctb);
|
||||
@@ -3464,6 +3464,7 @@ public class AbilityUtils {
|
||||
}
|
||||
|
||||
int tot = 0;
|
||||
|
||||
for (final Card c : filteredList) {
|
||||
tot += xCount(c, filteredString, ctb);
|
||||
}
|
||||
|
||||
@@ -704,8 +704,8 @@ public abstract class SpellAbilityEffect {
|
||||
Card host = sa.getHostCard();
|
||||
final Game game = host.getGame();
|
||||
final String duration = sa.getParam("Duration");
|
||||
// in case host was LKI
|
||||
if (host.isLKI()) {
|
||||
// in case host was LKI or still resolving
|
||||
if (host.isLKI() || host.getZone().is(ZoneType.Stack)) {
|
||||
host = game.getCardState(host);
|
||||
}
|
||||
|
||||
|
||||
@@ -243,5 +243,4 @@ public class CharmEffect extends SpellAbilityEffect {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package forge.game.ability.effects;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -62,6 +63,7 @@ public class ChooseCardNameEffect extends SpellAbilityEffect {
|
||||
|
||||
boolean randomChoice = sa.hasParam("AtRandom");
|
||||
boolean chooseFromDefined = sa.hasParam("ChooseFromDefinedCards");
|
||||
boolean chooseFromOneTimeList = sa.hasParam("ChooseFromOneTimeList");
|
||||
|
||||
if (!randomChoice) {
|
||||
if (sa.hasParam("SelectPrompt")) {
|
||||
@@ -100,7 +102,7 @@ public class ChooseCardNameEffect extends SpellAbilityEffect {
|
||||
} else if (chooseFromDefined) {
|
||||
CardCollection choices = AbilityUtils.getDefinedCards(host, sa.getParam("ChooseFromDefinedCards"), sa);
|
||||
choices = CardLists.getValidCards(choices, valid, host.getController(), host, sa);
|
||||
List<ICardFace> faces = Lists.newArrayList();
|
||||
List<ICardFace> faces = new ArrayList<>();
|
||||
// get Card
|
||||
for (final Card c : choices) {
|
||||
final CardRules rules = c.getRules();
|
||||
@@ -114,6 +116,22 @@ public class ChooseCardNameEffect extends SpellAbilityEffect {
|
||||
}
|
||||
Collections.sort(faces);
|
||||
chosen = p.getController().chooseCardName(sa, faces, message);
|
||||
} else if (chooseFromOneTimeList) {
|
||||
String [] names = sa.getParam("ChooseFromOneTimeList").split(",");
|
||||
List<ICardFace> faces = new ArrayList<>();
|
||||
for (String name : names) {
|
||||
faces.add(StaticData.instance().getCommonCards().getFaceByName(name));
|
||||
}
|
||||
chosen = p.getController().chooseCardName(sa, faces, message);
|
||||
|
||||
// Remove chosen Name from List
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String name : names) {
|
||||
if (chosen.equals(name)) continue;
|
||||
if (sb.length() > 0) sb.append(',');
|
||||
sb.append(name);
|
||||
}
|
||||
sa.putParam("ChooseFromOneTimeList", sb.toString());
|
||||
} else {
|
||||
// use CardFace because you might name a alternate names
|
||||
Predicate<ICardFace> cpp = Predicates.alwaysTrue();
|
||||
|
||||
@@ -99,9 +99,9 @@ public class CopyPermanentEffect extends TokenEffectBase {
|
||||
if (sa.hasParam("RandomCopied")) {
|
||||
List<PaperCard> copysource = Lists.newArrayList(cards);
|
||||
List<Card> choice = Lists.newArrayList();
|
||||
final String num = sa.hasParam("RandomNum") ? sa.getParam("RandomNum") : "1";
|
||||
final String num = sa.getParamOrDefault("RandomNum","1");
|
||||
int ncopied = AbilityUtils.calculateAmount(host, num, sa);
|
||||
while(ncopied > 0 && !copysource.isEmpty()) {
|
||||
while (ncopied > 0 && !copysource.isEmpty()) {
|
||||
final PaperCard cp = Aggregates.random(copysource);
|
||||
Card possibleCard = Card.fromPaperCard(cp, activator); // Need to temporarily set the Owner so the Game is set
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ public class MustAttackEffect extends SpellAbilityEffect {
|
||||
final Card host = sa.getHostCard();
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
|
||||
// end standard pre-
|
||||
|
||||
final List<Player> tgtPlayers = getTargetPlayers(sa);
|
||||
@@ -67,7 +66,6 @@ public class MustAttackEffect extends SpellAbilityEffect {
|
||||
entity = defPWs.getFirst();
|
||||
}
|
||||
}
|
||||
//System.out.println("Setting mustAttackEntity to: "+entity);
|
||||
|
||||
for (final Player p : tgtPlayers) {
|
||||
if ((tgt == null) || p.canBeTargetedBy(sa)) {
|
||||
|
||||
@@ -35,6 +35,7 @@ import forge.game.zone.Zone;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.item.PaperCard;
|
||||
import forge.util.Aggregates;
|
||||
import forge.util.CardTranslation;
|
||||
import forge.util.Lang;
|
||||
import forge.util.Localizer;
|
||||
|
||||
@@ -93,8 +94,7 @@ public class PlayEffect extends SpellAbilityEffect {
|
||||
if (sa.hasParam("ShowCards")) {
|
||||
showCards = new CardCollection(AbilityUtils.filterListByType(game.getCardsIn(zones), sa.getParam("ShowCards"), sa));
|
||||
}
|
||||
}
|
||||
else if (sa.hasParam("AnySupportedCard")) {
|
||||
} else if (sa.hasParam("AnySupportedCard")) {
|
||||
final String valid = sa.getParam("AnySupportedCard");
|
||||
List<PaperCard> cards = null;
|
||||
if (valid.startsWith("Names:")){
|
||||
@@ -139,8 +139,14 @@ public class PlayEffect extends SpellAbilityEffect {
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else if (sa.hasParam("CopyFromChosenName")) {
|
||||
String name = source.getChosenName();
|
||||
if (name.trim().isEmpty()) return;
|
||||
Card card = Card.fromPaperCard(StaticData.instance().getCommonCards().getUniqueByName(name), controller);
|
||||
card.setToken(true);
|
||||
tgtCards = new CardCollection();
|
||||
tgtCards.add(card);
|
||||
} else {
|
||||
tgtCards = new CardCollection();
|
||||
// filter only cards that didn't changed zones
|
||||
for (Card c : getTargetCards(sa)) {
|
||||
@@ -179,7 +185,16 @@ public class PlayEffect extends SpellAbilityEffect {
|
||||
|
||||
while (!tgtCards.isEmpty() && amount > 0) {
|
||||
activator.getController().tempShowCards(showCards);
|
||||
Card tgtCard = controller.getController().chooseSingleEntityForEffect(tgtCards, sa, Localizer.getInstance().getMessage("lblSelectCardToPlay"), optional, null);
|
||||
Card tgtCard = null;
|
||||
if (tgtCards.size() == 1 && amount == 1 && optional) {
|
||||
tgtCard = tgtCards.get(0);
|
||||
if (!controller.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWantPlayCard", CardTranslation.getTranslatedName(tgtCard.getName())))) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
tgtCard = controller.getController().chooseSingleEntityForEffect(tgtCards, sa, Localizer.getInstance().getMessage("lblSelectCardToPlay"), optional, null);
|
||||
}
|
||||
|
||||
activator.getController().endTempShowCards();
|
||||
if (tgtCard == null) {
|
||||
break;
|
||||
|
||||
@@ -3,6 +3,7 @@ package forge.game.ability.effects;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.GameCommand;
|
||||
@@ -154,20 +155,27 @@ public class RepeatEachEffect extends SpellAbilityEffect {
|
||||
game.getUntap().addUntil(p, new GameCommand() {
|
||||
@Override
|
||||
public void run() {
|
||||
List<Object> tempRemembered = Lists.newArrayList(Iterables.filter(source.getRemembered(), Player.class));
|
||||
source.removeRemembered(tempRemembered);
|
||||
source.addRemembered(p);
|
||||
AbilityUtils.resolve(repeat);
|
||||
source.removeRemembered(p);
|
||||
source.addRemembered(tempRemembered);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// to avoid risk of collision with other abilities swap out other Remembered Player while resolving
|
||||
List<Object> tempRemembered = Lists.newArrayList(Iterables.filter(source.getRemembered(), Player.class));
|
||||
source.removeRemembered(tempRemembered);
|
||||
source.addRemembered(p);
|
||||
AbilityUtils.resolve(repeat);
|
||||
source.removeRemembered(p);
|
||||
source.addRemembered(tempRemembered);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(sa.hasParam("DamageMap")) {
|
||||
if (sa.hasParam("DamageMap")) {
|
||||
game.getAction().dealDamage(false, sa.getDamageMap(), sa.getPreventMap(), sa.getCounterTable(), sa);
|
||||
}
|
||||
if (sa.hasParam("ChangeZoneTable")) {
|
||||
|
||||
@@ -82,7 +82,7 @@ public class ReplaceManaEffect extends SpellAbilityEffect {
|
||||
|
||||
// need to log Updated events there, or the log is wrong order
|
||||
String message = sa.getReplacementEffect().toString();
|
||||
if ( !StringUtils.isEmpty(message)) {
|
||||
if (!StringUtils.isEmpty(message)) {
|
||||
message = TextUtil.fastReplace(message, "CARDNAME", card.getName());
|
||||
game.getGameLog().add(GameLogEntryType.EFFECT_REPLACED, message);
|
||||
}
|
||||
|
||||
@@ -1708,6 +1708,9 @@ public class CardProperty {
|
||||
}
|
||||
} else if (property.startsWith("set")) {
|
||||
final String setCode = property.substring(3, 6);
|
||||
if (card.getName().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
final PaperCard setCard = StaticData.instance().getCommonCards().getCardFromEdition(card.getName(), CardDb.SetPreference.Earliest);
|
||||
if (setCard != null && !setCard.getEdition().equals(setCode)) {
|
||||
return false;
|
||||
|
||||
@@ -1086,7 +1086,7 @@ public class CardView extends GameEntityView {
|
||||
}
|
||||
|
||||
public CardTypeView getType() {
|
||||
if (isFaceDown() && !isInZone(EnumSet.of(ZoneType.Battlefield, ZoneType.Stack))) {
|
||||
if (getState() != CardStateName.Original && isFaceDown() && !isInZone(EnumSet.of(ZoneType.Battlefield, ZoneType.Stack))) {
|
||||
return CardType.EMPTY;
|
||||
}
|
||||
return get(TrackableProperty.Type);
|
||||
|
||||
@@ -31,6 +31,7 @@ import forge.card.mana.ManaCost;
|
||||
import forge.card.mana.ManaCostParser;
|
||||
import forge.game.CardTraitBase;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CounterEnumType;
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.mana.ManaCostBeingPaid;
|
||||
import forge.game.player.Player;
|
||||
@@ -876,15 +877,30 @@ public class Cost implements Serializable {
|
||||
costParts.add(0, new CostPartMana(oldManaCost.toManaCost(), r));
|
||||
}
|
||||
} else if (part instanceof CostDiscard || part instanceof CostTapType ||
|
||||
part instanceof CostAddMana || part instanceof CostPayLife) {
|
||||
part instanceof CostAddMana || part instanceof CostPayLife
|
||||
|| part instanceof CostPutCounter) {
|
||||
boolean alreadyAdded = false;
|
||||
for (final CostPart other : costParts) {
|
||||
if (other.getClass().equals(part.getClass()) &&
|
||||
if ((other.getClass().equals(part.getClass()) || (part instanceof CostPutCounter && ((CostPutCounter)part).getCounter().is(CounterEnumType.LOYALTY))) &&
|
||||
part.getType().equals(other.getType()) &&
|
||||
StringUtils.isNumeric(part.getAmount()) &&
|
||||
StringUtils.isNumeric(other.getAmount())) {
|
||||
final String amount = String.valueOf(Integer.parseInt(part.getAmount()) + Integer.parseInt(other.getAmount()));
|
||||
if (part instanceof CostDiscard) {
|
||||
String amount = String.valueOf(Integer.parseInt(part.getAmount()) + Integer.parseInt(other.getAmount()));
|
||||
if (part instanceof CostPutCounter) { // path for Carth
|
||||
if (other instanceof CostPutCounter && ((CostPutCounter)other).getCounter().is(CounterEnumType.LOYALTY)) {
|
||||
costParts.add(new CostPutCounter(amount, CounterType.get(CounterEnumType.LOYALTY), part.getType(), part.getTypeDescription()));
|
||||
} else if (other instanceof CostRemoveCounter && ((CostRemoveCounter)other).counter.is(CounterEnumType.LOYALTY)) {
|
||||
Integer counters = Integer.parseInt(other.getAmount()) - Integer.parseInt(part.getAmount());
|
||||
// the cost can turn positive if multiple Carth raise it
|
||||
if (counters < 0) {
|
||||
costParts.add(new CostPutCounter(String.valueOf(counters *-1), CounterType.get(CounterEnumType.LOYALTY), part.getType(), part.getTypeDescription()));
|
||||
} else {
|
||||
costParts.add(new CostRemoveCounter(String.valueOf(counters), CounterType.get(CounterEnumType.LOYALTY), part.getType(), part.getTypeDescription(), ZoneType.Battlefield));
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else if (part instanceof CostDiscard) {
|
||||
costParts.add(new CostDiscard(amount, part.getType(), part.getTypeDescription()));
|
||||
} else if (part instanceof CostTapType) {
|
||||
CostTapType tappart = (CostTapType)part;
|
||||
|
||||
@@ -86,11 +86,12 @@ public class CostPayment extends ManaConversionMatrix {
|
||||
* a {@link forge.game.spellability.SpellAbility} object.
|
||||
* @return a boolean.
|
||||
*/
|
||||
public static boolean canPayAdditionalCosts(final Cost cost, final SpellAbility ability) {
|
||||
public static boolean canPayAdditionalCosts(Cost cost, final SpellAbility ability) {
|
||||
if (cost == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
cost = CostAdjustment.adjust(cost, ability);
|
||||
return cost.canPay(ability);
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ public class CostPutCounter extends CostPartWithList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int paymentOrder() { return 8; }
|
||||
public int paymentOrder() { return 6; }
|
||||
|
||||
@Override
|
||||
public boolean isReusable() {
|
||||
|
||||
@@ -1762,7 +1762,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
public final boolean playLand(final Card land, final boolean ignoreZoneAndTiming) {
|
||||
// Dakkon Blackblade Avatar will use a similar effect
|
||||
if (canPlayLand(land, ignoreZoneAndTiming)) {
|
||||
this.playLandNoCheck(land);
|
||||
playLandNoCheck(land);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1775,8 +1775,8 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
if (land.isFaceDown()) {
|
||||
land.turnFaceUp(null);
|
||||
}
|
||||
final Card c = game.getAction().moveTo(getZone(ZoneType.Battlefield), land, null);
|
||||
game.copyLastState();
|
||||
final Card c = game.getAction().moveTo(getZone(ZoneType.Battlefield), land, null);
|
||||
game.updateLastStateForCard(c);
|
||||
|
||||
// play a sound
|
||||
|
||||
@@ -31,7 +31,6 @@ public class ReplaceProduceMana extends ReplacementEffect {
|
||||
*/
|
||||
@Override
|
||||
public boolean canReplace(Map<AbilityKey, Object> runParams) {
|
||||
|
||||
if (!matchesValidParam("ValidCard", runParams.get(AbilityKey.Affected))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -765,6 +765,10 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
resetTriggeringObjects();
|
||||
resetTriggerRemembered();
|
||||
|
||||
if (isActivatedAbility()) {
|
||||
setXManaCostPaid(null);
|
||||
}
|
||||
|
||||
// reset last state when finished resolving
|
||||
setLastStateBattlefield(CardCollection.EMPTY);
|
||||
setLastStateGraveyard(CardCollection.EMPTY);
|
||||
|
||||
@@ -195,7 +195,6 @@ public class SpellAbilityRestriction extends SpellAbilityVariables {
|
||||
* @return a boolean.
|
||||
*/
|
||||
public final boolean checkZoneRestrictions(final Card c, final SpellAbility sa) {
|
||||
|
||||
final Player activator = sa.getActivatingPlayer();
|
||||
final Zone cardZone = c.getLastKnownZone();
|
||||
Card cp = c;
|
||||
|
||||
@@ -366,7 +366,6 @@ public class TargetRestrictions {
|
||||
return this.saValidTargeting;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* canOnlyTgtOpponent.
|
||||
|
||||
@@ -57,6 +57,9 @@ public class StaticAbilityCantBeCast {
|
||||
}
|
||||
|
||||
public static boolean cantBeActivatedAbility(final SpellAbility spell, final Card card, final Player activator) {
|
||||
if (spell.isTrigger()) {
|
||||
return false;
|
||||
}
|
||||
final Game game = activator.getGame();
|
||||
for (final Card ca : game.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) {
|
||||
for (final StaticAbility stAb : ca.getStaticAbilities()) {
|
||||
@@ -98,7 +101,6 @@ public class StaticAbilityCantBeCast {
|
||||
* @return true, if successful
|
||||
*/
|
||||
public static boolean applyCantBeCastAbility(final StaticAbility stAb, final SpellAbility spell, final Card card, final Player activator) {
|
||||
|
||||
if (!stAb.matchesValidParam("ValidCard", card)) {
|
||||
return false;
|
||||
}
|
||||
@@ -153,7 +155,6 @@ public class StaticAbilityCantBeCast {
|
||||
* @return true, if successful
|
||||
*/
|
||||
public static boolean applyCantBeActivatedAbility(final StaticAbility stAb, final SpellAbility spellAbility, final Card card, final Player activator) {
|
||||
|
||||
if (!stAb.matchesValidParam("ValidCard", card)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -543,7 +543,6 @@ public class MagicStack /* extends MyObservable */ implements Iterable<SpellAbil
|
||||
}
|
||||
|
||||
private final void finishResolving(final SpellAbility sa, final boolean fizzle) {
|
||||
|
||||
// SpellAbility is removed from the stack here
|
||||
// temporarily removed removing SA after resolution
|
||||
final SpellAbilityStackInstance si = getInstanceFromSpellAbility(sa);
|
||||
|
||||
@@ -5,8 +5,8 @@ PT:0/0
|
||||
K:Menace
|
||||
K:Modular:2
|
||||
T:Mode$ SpellCast | ValidCard$ Card.YouCtrl | TriggerZones$ Battlefield | Execute$ TrigPutCounter | CheckSVar$ YouCastThisTurn | SVarCompare$ GT1 | NoResolvingCheck$ True | TriggerDescription$ Whenever you cast a spell other than your first spell each turn, put a +1/+1 counter on CARDNAME.
|
||||
SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1 | SubAbility$ DBDealDamage
|
||||
SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1
|
||||
SVar:YouCastThisTurn:Count$ThisTurnCast_Card.YouCtrl
|
||||
DeckHas:Ability$Counters
|
||||
DeckHints:Type$Artifact & Ability$Counters
|
||||
DeckHints:Type$Artifact
|
||||
Oracle:Menace\nModular 2 (This creature enters the battlefield with two +1/+1 counters on it. When it dies, you may put its +1/+1 counters on target artifact creature.)\nWhenever you cast a spell other than your first spell each turn, put a +1/+1 counter on Arcbound Tracker.
|
||||
@@ -4,7 +4,7 @@ Types:Legendary Planeswalker Basri
|
||||
Loyalty:4
|
||||
A:AB$ PutCounter | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | CounterNum$ 1 | CounterType$ P1P1 | TargetMin$ 0 | TargetMax$ 1 | TgtPrompt$ Choose target creature | ValidTgts$ Creature | SubAbility$ DBPump | SpellDescription$ Put a +1/+1 counter on up to one target creature. It gains vigilance until end of turn.
|
||||
SVar:DBPump:DB$ Pump | Defined$ Targeted | KW$ Vigilance
|
||||
A:AB$ Effect | Cost$ SubCounter<1/LOYALTY> | Triggers$ TrigAttack | SpellDescription$ Whenever a creature attacks this turn, put a +1/+1 counter on it.
|
||||
A:AB$ Effect | Cost$ SubCounter<1/LOYALTY> | Planeswalker$ True | Triggers$ TrigAttack | SpellDescription$ Whenever a creature attacks this turn, put a +1/+1 counter on it.
|
||||
SVar:TrigAttack:Mode$ Attacks | ValidCard$ Creature | Execute$ TrigPutCounter | TriggerDescription$ Whenever a creature attacks this turn, put a +1/+1 counter on it.
|
||||
SVar:TrigPutCounter:DB$ PutCounter | Defined$ TriggeredAttackerLKICopy | CounterType$ P1P1 | CounterNum$ 1
|
||||
A:AB$ PumpAll | Cost$ SubCounter<6/LOYALTY> | Planeswalker$ True | Ultimate$ True | ValidCards$ Creature.YouCtrl | NumAtt$ +2 | NumDef$ +2 | KW$ Flying | SpellDescription$ Creatures you control get +2/+2 and gain flying until end of turn.
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
Name:Burning Rootwalla
|
||||
Name:Blazing Rootwalla
|
||||
ManaCost:R
|
||||
Types:Creature Lizard
|
||||
PT:1/1
|
||||
A:AB$ Pump | Cost$ R | NumAtt$ +2 | ActivationLimit$ 1 | SpellDescription$ CARDNAME gets +2/+0 until end of turn. Activate only once per turn.
|
||||
K:Madness:0
|
||||
Oracle:{R}: Burning Rootwalla gets +2/+0 until end of turn. Activate only once per turn.\nMadness {0} (If you discard this card, discard it into exile. When you do, cast it for its madness cost or put it into your graveyard.)
|
||||
DeckHints:Ability$Discard
|
||||
Oracle:{R}: Blazing Rootwalla gets +2/+0 until end of turn. Activate only once per turn.\nMadness {0} (If you discard this card, discard it into exile. When you do, cast it for its madness cost or put it into your graveyard.)
|
||||
@@ -1,5 +1,6 @@
|
||||
Name:Bog Rats
|
||||
ManaCost:B
|
||||
Types:Creature Rat
|
||||
PT:1/1
|
||||
S:Mode$ CantBlockBy | ValidAttacker$ Creature.Self | ValidBlocker$ Creature.Wall | Description$ CARDNAME can't be blocked by Walls.
|
||||
Oracle:Bog Rats can't be blocked by Walls.
|
||||
13
forge-gui/res/cardsfolder/b/breathless_knight.txt
Normal file
13
forge-gui/res/cardsfolder/b/breathless_knight.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
Name:Breathless Knight
|
||||
ManaCost:1 W B
|
||||
Types:Creature Spirit Knight
|
||||
PT:2/2
|
||||
K:Flying
|
||||
K:Lifelink
|
||||
T:Mode$ ChangesZone | Origin$ Graveyard | Destination$ Battlefield | TriggerZones$ Battlefield | ValidCard$ Creature.YouOwn+Other | Execute$ TrigPutCounter | TriggerDescription$ Whenever CARDNAME or another creature enters the battlefield under your control, if it entered from a graveyard or you cast it from a graveyard, put a +1/+1 counter on CARDNAME.
|
||||
T:Mode$ ChangesZone | Destination$ Battlefield | TriggerZones$ Battlefield | ValidCard$ Creature.YouOwn+Other+wasCastFromGraveyard | Execute$ TrigPutCounter | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another creature enters the battlefield under your control, if it entered from a graveyard or you cast it from a graveyard, put a +1/+1 counter on CARDNAME.
|
||||
T:Mode$ ChangesZone | Origin$ Graveyard | Destination$ Battlefield | ValidCard$ Creature.Self | Execute$ TrigPutCounter | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another creature enters the battlefield under your control, if it entered from a graveyard or you cast it from a graveyard, put a +1/+1 counter on CARDNAME.
|
||||
T:Mode$ ChangesZone | Destination$ Battlefield | ValidCard$ Creature.Self+wasCastFromGraveyard | Execute$ TrigPutCounter | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another creature enters the battlefield under your control, if it entered from a graveyard or you cast it from a graveyard, put a +1/+1 counter on CARDNAME.
|
||||
SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterNum$ 1 | CounterType$ P1P1
|
||||
DeckHas:Ability$Counters
|
||||
Oracle:Flying, lifelink\nWhenever Breathless Knight or another creature enters the battlefield under your control, if it entered from a graveyard or you cast it from a graveyard, put a +1/+1 counter on Breathless Knight.
|
||||
10
forge-gui/res/cardsfolder/c/carth_the_lion.txt
Normal file
10
forge-gui/res/cardsfolder/c/carth_the_lion.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Name:Carth the Lion
|
||||
ManaCost:2 B G
|
||||
Types:Legendary Creature Human Warrior
|
||||
PT:3/5
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDig | TriggerDescription$ Whenever CARDNAME enters the battlefield or a planeswalker you control dies, look at the top seven cards of your library. You may reveal a planeswalker card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Planeswalker.YouCtrl | TriggerZones$ Battlefield | Execute$ TrigDig | Secondary$ True | TriggerDescription$ Whenever CARDNAME enters the battlefield or a planeswalker you control dies, look at the top seven cards of your library. You may reveal a planeswalker card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.
|
||||
SVar:TrigDig:DB$ Dig | DigNum$ 7 | ChangeNum$ 1 | Optional$ True | ChangeValid$ Planeswalker | RestRandomOrder$ True | Reveal$ True
|
||||
S:Mode$ RaiseCost | ValidCard$ Planeswalker.YouCtrl | Type$ Loyalty | Cost$ AddCounter<1/LOYALTY> | Description$ Planeswalkers' loyalty abilities you activate cost an additional [+1] to activate.
|
||||
DeckNeeds:Type$Planeswalker
|
||||
Oracle:Whenever Carth the Lion enters the battlefield or a planeswalker you control dies, look at the top seven cards of your library. You may reveal a planeswalker card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.\nPlaneswalkers' loyalty abilities you activate cost an additional [+1] to activate.
|
||||
@@ -2,6 +2,6 @@ Name:Diamond Lion
|
||||
ManaCost:2
|
||||
Types:Artifact Creature Lion
|
||||
PT:2/2
|
||||
A:AB$ Mana | Cost$ Discard<0/Hand> Sac<1/CARDNAME> | Produced$ Any | Amount$ 3 | InstantSpeed$ True | SpellDescription$ Add three mana of any one color. Activate only as an instant.
|
||||
A:AB$ Mana | Cost$ T Discard<0/Hand> Sac<1/CARDNAME> | Produced$ Any | Amount$ 3 | InstantSpeed$ True | SpellDescription$ Add three mana of any one color. Activate only as an instant.
|
||||
AI:RemoveDeck:All
|
||||
Oracle:{T}, Discard your hand, Sacrifice Diamond Lion: Add three mana of any one color. Activate only as an instant.
|
||||
@@ -1,5 +1,5 @@
|
||||
Name:Drake Stone
|
||||
ManaCost:U
|
||||
ManaCost:3 U B
|
||||
Types:Planeswalker Stone
|
||||
Loyalty:4
|
||||
A:AB$ Draw | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | NumCards$ 1 | SubAbility$ DBDiscard | SpellDescription$ Draw a card, then each player discards a card.
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
Name:Emergent Growth
|
||||
ManaCost:3 G
|
||||
Types:Sorcery
|
||||
A:SP$ Pump | Cost$ 3 G | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ +5 | NumDef$ +5 | KW$ HIDDEN CARDNAME must be blocked if able. | AILogic$ Pump | SpellDescription$ Target creature gets +5/+5 until end of turn and must be blocked this turn if able.
|
||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/emergent_growth.jpg
|
||||
Oracle:Target creature gets +5/+5 until end of turn and must be blocked this turn if able.
|
||||
A:SP$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ +5 | NumDef$ +5 | KW$ HIDDEN CARDNAME must be blocked if able. | AILogic$ Pump | StackDescription$ {c:Targeted} gets +5/+5 until end of turn and must be blocked this turn if able. | SpellDescription$ Target creature gets +5/+5 until end of turn and must be blocked this turn if able.
|
||||
Oracle:Target creature gets +5/+5 until end of turn and must be blocked this turn if able.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user