mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 12:18:00 +00:00
Merge branch 'master' into Attractions
# Conflicts: # forge-core/src/main/java/forge/deck/DeckFormat.java
This commit is contained in:
@@ -52,6 +52,7 @@ public final class CardRules implements ICardCharacteristics {
|
|||||||
private ColorSet deckbuildingColors;
|
private ColorSet deckbuildingColors;
|
||||||
private String meldWith;
|
private String meldWith;
|
||||||
private String partnerWith;
|
private String partnerWith;
|
||||||
|
private boolean addsWildCardColor;
|
||||||
private boolean custom;
|
private boolean custom;
|
||||||
|
|
||||||
public CardRules(ICardFace[] faces, CardSplitType altMode, CardAiHints cah) {
|
public CardRules(ICardFace[] faces, CardSplitType altMode, CardAiHints cah) {
|
||||||
@@ -70,6 +71,7 @@ public final class CardRules implements ICardCharacteristics {
|
|||||||
aiHints = cah;
|
aiHints = cah;
|
||||||
meldWith = "";
|
meldWith = "";
|
||||||
partnerWith = "";
|
partnerWith = "";
|
||||||
|
addsWildCardColor = false;
|
||||||
|
|
||||||
//calculate color identity
|
//calculate color identity
|
||||||
byte colMask = calculateColorIdentity(mainPart);
|
byte colMask = calculateColorIdentity(mainPart);
|
||||||
@@ -92,6 +94,8 @@ public final class CardRules implements ICardCharacteristics {
|
|||||||
colorIdentity = newRules.colorIdentity;
|
colorIdentity = newRules.colorIdentity;
|
||||||
meldWith = newRules.meldWith;
|
meldWith = newRules.meldWith;
|
||||||
partnerWith = newRules.partnerWith;
|
partnerWith = newRules.partnerWith;
|
||||||
|
addsWildCardColor = newRules.addsWildCardColor;
|
||||||
|
tokens = newRules.tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte calculateColorIdentity(final ICardFace face) {
|
private static byte calculateColorIdentity(final ICardFace face) {
|
||||||
@@ -203,20 +207,20 @@ public final class CardRules implements ICardCharacteristics {
|
|||||||
@Override
|
@Override
|
||||||
public ManaCost getManaCost() {
|
public ManaCost getManaCost() {
|
||||||
switch (splitType.getAggregationMethod()) {
|
switch (splitType.getAggregationMethod()) {
|
||||||
case COMBINE:
|
case COMBINE:
|
||||||
return ManaCost.combine(mainPart.getManaCost(), otherPart.getManaCost());
|
return ManaCost.combine(mainPart.getManaCost(), otherPart.getManaCost());
|
||||||
default:
|
default:
|
||||||
return mainPart.getManaCost();
|
return mainPart.getManaCost();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ColorSet getColor() {
|
public ColorSet getColor() {
|
||||||
switch (splitType.getAggregationMethod()) {
|
switch (splitType.getAggregationMethod()) {
|
||||||
case COMBINE:
|
case COMBINE:
|
||||||
return ColorSet.fromMask(mainPart.getColor().getColor() | otherPart.getColor().getColor());
|
return ColorSet.fromMask(mainPart.getColor().getColor() | otherPart.getColor().getColor());
|
||||||
default:
|
default:
|
||||||
return mainPart.getColor();
|
return mainPart.getColor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,10 +234,10 @@ public final class CardRules implements ICardCharacteristics {
|
|||||||
|
|
||||||
public boolean canCastWithAvailable(byte colorCode) {
|
public boolean canCastWithAvailable(byte colorCode) {
|
||||||
switch (splitType.getAggregationMethod()) {
|
switch (splitType.getAggregationMethod()) {
|
||||||
case COMBINE:
|
case COMBINE:
|
||||||
return canCastFace(mainPart, colorCode) || canCastFace(otherPart, colorCode);
|
return canCastFace(mainPart, colorCode) || canCastFace(otherPart, colorCode);
|
||||||
default:
|
default:
|
||||||
return canCastFace(mainPart, colorCode);
|
return canCastFace(mainPart, colorCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,10 +257,10 @@ public final class CardRules implements ICardCharacteristics {
|
|||||||
@Override
|
@Override
|
||||||
public String getOracleText() {
|
public String getOracleText() {
|
||||||
switch (splitType.getAggregationMethod()) {
|
switch (splitType.getAggregationMethod()) {
|
||||||
case COMBINE:
|
case COMBINE:
|
||||||
return mainPart.getOracleText() + "\r\n\r\n" + otherPart.getOracleText();
|
return mainPart.getOracleText() + "\r\n\r\n" + otherPart.getOracleText();
|
||||||
default:
|
default:
|
||||||
return mainPart.getOracleText();
|
return mainPart.getOracleText();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,6 +272,9 @@ public final class CardRules implements ICardCharacteristics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean canBeCommander() {
|
public boolean canBeCommander() {
|
||||||
|
if (mainPart.getOracleText().contains(" is your commander, choose a color before the game begins.")) {
|
||||||
|
addsWildCardColor = true;
|
||||||
|
}
|
||||||
if (mainPart.getOracleText().contains("can be your commander") || canBeBackground()) {
|
if (mainPart.getOracleText().contains("can be your commander") || canBeBackground()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -385,11 +392,15 @@ public final class CardRules implements ICardCharacteristics {
|
|||||||
return partnerWith;
|
return partnerWith;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean getAddsWildCardColor() {
|
||||||
|
return addsWildCardColor;
|
||||||
|
}
|
||||||
|
|
||||||
// vanguard card fields, they don't use sides.
|
// vanguard card fields, they don't use sides.
|
||||||
private int deltaHand;
|
private int deltaHand;
|
||||||
private int deltaLife;
|
private int deltaLife;
|
||||||
|
|
||||||
private List<String> tokens;
|
private List<String> tokens = Collections.emptyList();
|
||||||
|
|
||||||
public List<String> getTokens() {
|
public List<String> getTokens() {
|
||||||
return tokens;
|
return tokens;
|
||||||
@@ -435,6 +446,7 @@ public final class CardRules implements ICardCharacteristics {
|
|||||||
private CardSplitType altMode = CardSplitType.None;
|
private CardSplitType altMode = CardSplitType.None;
|
||||||
private String meldWith = "";
|
private String meldWith = "";
|
||||||
private String partnerWith = "";
|
private String partnerWith = "";
|
||||||
|
private boolean addsWildCardColor = false;
|
||||||
private String handLife = null;
|
private String handLife = null;
|
||||||
private String normalizedName = "";
|
private String normalizedName = "";
|
||||||
private Set<String> supportedFunctionalVariants = null;
|
private Set<String> supportedFunctionalVariants = null;
|
||||||
@@ -473,6 +485,7 @@ public final class CardRules implements ICardCharacteristics {
|
|||||||
this.has = null;
|
this.has = null;
|
||||||
this.meldWith = "";
|
this.meldWith = "";
|
||||||
this.partnerWith = "";
|
this.partnerWith = "";
|
||||||
|
this.addsWildCardColor = false;
|
||||||
this.normalizedName = "";
|
this.normalizedName = "";
|
||||||
this.supportedFunctionalVariants = null;
|
this.supportedFunctionalVariants = null;
|
||||||
this.tokens = Lists.newArrayList();
|
this.tokens = Lists.newArrayList();
|
||||||
@@ -497,7 +510,10 @@ public final class CardRules implements ICardCharacteristics {
|
|||||||
result.setNormalizedName(this.normalizedName);
|
result.setNormalizedName(this.normalizedName);
|
||||||
result.meldWith = this.meldWith;
|
result.meldWith = this.meldWith;
|
||||||
result.partnerWith = this.partnerWith;
|
result.partnerWith = this.partnerWith;
|
||||||
result.tokens = tokens.isEmpty() ? Collections.emptyList() : tokens;
|
result.addsWildCardColor = this.addsWildCardColor;
|
||||||
|
if (!tokens.isEmpty()) {
|
||||||
|
result.tokens = tokens;
|
||||||
|
}
|
||||||
if (StringUtils.isNotBlank(handLife))
|
if (StringUtils.isNotBlank(handLife))
|
||||||
result.setVanguardProperties(handLife);
|
result.setVanguardProperties(handLife);
|
||||||
result.supportedFunctionalVariants = this.supportedFunctionalVariants;
|
result.supportedFunctionalVariants = this.supportedFunctionalVariants;
|
||||||
@@ -567,7 +583,7 @@ public final class CardRules implements ICardCharacteristics {
|
|||||||
} else if ("AltName".equals(key)) {
|
} else if ("AltName".equals(key)) {
|
||||||
face.setAltName(value);
|
face.setAltName(value);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'C':
|
case 'C':
|
||||||
if ("Colors".equals(key)) {
|
if ("Colors".equals(key)) {
|
||||||
@@ -777,7 +793,10 @@ public final class CardRules implements ICardCharacteristics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasStartOfKeyword(final String k) {
|
public boolean hasStartOfKeyword(final String k) {
|
||||||
for (final String inst : mainPart.getKeywords()) {
|
return hasStartOfKeyword(k, mainPart);
|
||||||
|
}
|
||||||
|
public boolean hasStartOfKeyword(final String k, ICardFace cf) {
|
||||||
|
for (final String inst : cf.getKeywords()) {
|
||||||
final String[] parts = inst.split(":");
|
final String[] parts = inst.split(":");
|
||||||
if (parts[0].equals(k)) {
|
if (parts[0].equals(k)) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.base.Predicates;
|
import com.google.common.base.Predicates;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
import forge.util.CardTranslation;
|
import forge.util.CardTranslation;
|
||||||
import forge.util.ComparableOp;
|
import forge.util.ComparableOp;
|
||||||
@@ -186,7 +187,7 @@ public final class CardRulesPredicates {
|
|||||||
return new Predicate<CardRules>() {
|
return new Predicate<CardRules>() {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(final CardRules card) {
|
public boolean apply(final CardRules card) {
|
||||||
return card.hasStartOfKeyword(keyword);
|
return Iterables.any(card.getAllFaces(), cf -> cf != null && card.hasStartOfKeyword(keyword, cf));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,6 +131,11 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
|
|||||||
return (this.myColor & ~colormask) == 0;
|
return (this.myColor & ~colormask) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** This returns the colors that colormask contains that are not in color */
|
||||||
|
public ColorSet getMissingColors(final byte colormask) {
|
||||||
|
return fromMask(this.myColor & ~colormask);
|
||||||
|
}
|
||||||
|
|
||||||
/** Operand has no other colors except defined by this. */
|
/** Operand has no other colors except defined by this. */
|
||||||
public boolean containsAllColorsFrom(final int colorProfile) {
|
public boolean containsAllColorsFrom(final int colorProfile) {
|
||||||
return (~this.myColor & colorProfile) == 0;
|
return (~this.myColor & colorProfile) == 0;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import forge.StaticData;
|
|||||||
import forge.card.CardRules;
|
import forge.card.CardRules;
|
||||||
import forge.card.CardRulesPredicates;
|
import forge.card.CardRulesPredicates;
|
||||||
import forge.card.CardType;
|
import forge.card.CardType;
|
||||||
|
import forge.card.ColorSet;
|
||||||
import forge.card.ICardFace;
|
import forge.card.ICardFace;
|
||||||
import forge.deck.generation.DeckGenPool;
|
import forge.deck.generation.DeckGenPool;
|
||||||
import forge.deck.generation.DeckGeneratorBase.FilterCMC;
|
import forge.deck.generation.DeckGeneratorBase.FilterCMC;
|
||||||
@@ -126,7 +127,7 @@ public enum DeckFormat {
|
|||||||
private final Predicate<CardRules> cardPoolFilter;
|
private final Predicate<CardRules> cardPoolFilter;
|
||||||
private final Predicate<PaperCard> paperCardPoolFilter;
|
private final Predicate<PaperCard> paperCardPoolFilter;
|
||||||
private final static String ADVPROCLAMATION = "Advantageous Proclamation";
|
private final static String ADVPROCLAMATION = "Advantageous Proclamation";
|
||||||
private final static String SOVREALM = "Sovereign's Realm";
|
// private final static String SOVREALM = "Sovereign's Realm";
|
||||||
|
|
||||||
DeckFormat(Range<Integer> mainRange0, Range<Integer> sideRange0, int maxCardCopies0, Predicate<CardRules> cardPoolFilter0, Predicate<PaperCard> paperCardPoolFilter0) {
|
DeckFormat(Range<Integer> mainRange0, Range<Integer> sideRange0, int maxCardCopies0, Predicate<CardRules> cardPoolFilter0, Predicate<PaperCard> paperCardPoolFilter0) {
|
||||||
mainRange = mainRange0;
|
mainRange = mainRange0;
|
||||||
@@ -212,17 +213,19 @@ public enum DeckFormat {
|
|||||||
|
|
||||||
int min = getMainRange().getMinimum();
|
int min = getMainRange().getMinimum();
|
||||||
int max = getMainRange().getMaximum();
|
int max = getMainRange().getMaximum();
|
||||||
boolean noBasicLands = false;
|
// boolean noBasicLands = false;
|
||||||
|
|
||||||
// Adjust minimum base on number of Advantageous Proclamation or similar cards
|
// Adjust minimum base on number of Advantageous Proclamation or similar cards
|
||||||
CardPool conspiracies = deck.get(DeckSection.Conspiracy);
|
CardPool conspiracies = deck.get(DeckSection.Conspiracy);
|
||||||
if (conspiracies != null) {
|
if (conspiracies != null) {
|
||||||
min -= (5 * conspiracies.countByName(ADVPROCLAMATION));
|
min -= (5 * conspiracies.countByName(ADVPROCLAMATION));
|
||||||
noBasicLands = conspiracies.countByName(SOVREALM) > 0;
|
// Commented out to remove warnings from the code.
|
||||||
|
// noBasicLands = conspiracies.countByName(SOVREALM) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasCommander()) {
|
if (hasCommander()) {
|
||||||
byte cmdCI = 0;
|
byte cmdCI = 0;
|
||||||
|
int wildColors = 0;
|
||||||
if (equals(DeckFormat.Oathbreaker)) { // 1 Oathbreaker and 1 Signature Spell
|
if (equals(DeckFormat.Oathbreaker)) { // 1 Oathbreaker and 1 Signature Spell
|
||||||
PaperCard oathbreaker = deck.getOathbreaker();
|
PaperCard oathbreaker = deck.getOathbreaker();
|
||||||
if (oathbreaker == null) {
|
if (oathbreaker == null) {
|
||||||
@@ -235,8 +238,7 @@ public enum DeckFormat {
|
|||||||
return "has too many commanders";
|
return "has too many commanders";
|
||||||
}
|
}
|
||||||
cmdCI = oathbreaker.getRules().getColorIdentity().getColor();
|
cmdCI = oathbreaker.getRules().getColorIdentity().getColor();
|
||||||
}
|
} else { // 1 Commander or 2 Partner Commanders
|
||||||
else { // 1 Commander or 2 Partner Commanders
|
|
||||||
final List<PaperCard> commanders = deck.getCommanders();
|
final List<PaperCard> commanders = deck.getCommanders();
|
||||||
|
|
||||||
if (commanders.isEmpty()) {
|
if (commanders.isEmpty()) {
|
||||||
@@ -252,6 +254,7 @@ public enum DeckFormat {
|
|||||||
return "has an illegal commander";
|
return "has an illegal commander";
|
||||||
}
|
}
|
||||||
cmdCI |= pc.getRules().getColorIdentity().getColor();
|
cmdCI |= pc.getRules().getColorIdentity().getColor();
|
||||||
|
wildColors += pc.getRules().getAddsWildCardColor() ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// special check for Partner
|
// special check for Partner
|
||||||
@@ -280,8 +283,14 @@ public enum DeckFormat {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!cp.getKey().getRules().getColorIdentity().hasNoColorsExcept(cmdCI)) {
|
ColorSet missingColors = cp.getKey().getRules().getColorIdentity().getMissingColors(cmdCI);
|
||||||
erroneousCI.add(cp.getKey());
|
if (missingColors.countColors() > 0) {
|
||||||
|
if (missingColors.countColors() <= wildColors) {
|
||||||
|
wildColors -= missingColors.countColors();
|
||||||
|
cmdCI |= missingColors.getColor();
|
||||||
|
} else {
|
||||||
|
erroneousCI.add(cp.getKey());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (deck.has(DeckSection.Sideboard)) {
|
if (deck.has(DeckSection.Sideboard)) {
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A lightweight version of a card that matches real-world cards, to use outside of games (eg. inventory, decks, trade).
|
* A lightweight version of a card that matches real-world cards, to use outside of games (eg. inventory, decks, trade).
|
||||||
@@ -38,7 +37,7 @@ import java.io.Serializable;
|
|||||||
*
|
*
|
||||||
* @author Forge
|
* @author Forge
|
||||||
*/
|
*/
|
||||||
public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet, IPaperCard, Serializable {
|
public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet, IPaperCard {
|
||||||
private static final long serialVersionUID = 2942081982620691205L;
|
private static final long serialVersionUID = 2942081982620691205L;
|
||||||
|
|
||||||
// Reference to rules
|
// Reference to rules
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ import forge.util.Aggregates;
|
|||||||
import forge.util.MyRandom;
|
import forge.util.MyRandom;
|
||||||
import forge.util.Visitor;
|
import forge.util.Visitor;
|
||||||
import forge.util.collect.FCollection;
|
import forge.util.collect.FCollection;
|
||||||
|
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
@@ -327,7 +326,9 @@ public class Game {
|
|||||||
int plId = 0;
|
int plId = 0;
|
||||||
for (RegisteredPlayer psc : players0) {
|
for (RegisteredPlayer psc : players0) {
|
||||||
IGameEntitiesFactory factory = (IGameEntitiesFactory)psc.getPlayer();
|
IGameEntitiesFactory factory = (IGameEntitiesFactory)psc.getPlayer();
|
||||||
Player pl = factory.createIngamePlayer(this, plId++);
|
// If the Registered Player already has a pre-assigned ID, use that. Otherwise, assign a new one.
|
||||||
|
Integer id = psc.getId();
|
||||||
|
Player pl = factory.createIngamePlayer(this, id == null ? plId++ : id);
|
||||||
allPlayers.add(pl);
|
allPlayers.add(pl);
|
||||||
ingamePlayers.add(pl);
|
ingamePlayers.add(pl);
|
||||||
|
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ public final class GameActionUtil {
|
|||||||
// do only non intrinsic
|
// do only non intrinsic
|
||||||
if (iSa.isSpell() && !iSa.isIntrinsic()) {
|
if (iSa.isSpell() && !iSa.isIntrinsic()) {
|
||||||
alternatives.add(iSa);
|
alternatives.add(iSa);
|
||||||
alternatives.addAll(getMayPlaySpellOptions(iSa, source, activator, altCostOnly));
|
alternatives.addAll(getMayPlaySpellOptions(iSa, stackCopy, activator, altCostOnly));
|
||||||
// currently only AltCost get added this way
|
// currently only AltCost get added this way
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,9 +84,11 @@ public abstract class SpellAbilityEffect {
|
|||||||
String spellDesc = CardTranslation.translateSingleDescriptionText(rawSDesc,
|
String spellDesc = CardTranslation.translateSingleDescriptionText(rawSDesc,
|
||||||
sa.getHostCard().getName());
|
sa.getHostCard().getName());
|
||||||
|
|
||||||
int idx = spellDesc.indexOf("(");
|
//trim reminder text from StackDesc
|
||||||
if (idx > 0) { //trim reminder text from StackDesc
|
int idxL = spellDesc.indexOf(" (");
|
||||||
spellDesc = spellDesc.substring(0, spellDesc.indexOf("(") - 1);
|
int idxR = spellDesc.indexOf(")");
|
||||||
|
if (idxL > 0 && idxR > idxL) {
|
||||||
|
spellDesc = spellDesc.replace(spellDesc.substring(idxL, idxR + 1), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reps != null) {
|
if (reps != null) {
|
||||||
|
|||||||
@@ -26,9 +26,10 @@ public class ChooseGenericEffect extends SpellAbilityEffect {
|
|||||||
@Override
|
@Override
|
||||||
protected String getStackDescription(SpellAbility sa) {
|
protected String getStackDescription(SpellAbility sa) {
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
final List<Player> players = getDefinedPlayersOrTargeted(sa);
|
||||||
|
|
||||||
sb.append(Lang.joinHomogenous(getDefinedPlayersOrTargeted(sa)));
|
sb.append(Lang.joinHomogenous(players));
|
||||||
sb.append("chooses from a list.");
|
sb.append(players.size() == 1 ? " chooses" : " choose").append(" from a list.");
|
||||||
|
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,8 +120,8 @@ public class DebuffEffect extends SpellAbilityEffect {
|
|||||||
ProtectionFromColor = true;
|
ProtectionFromColor = true;
|
||||||
}
|
}
|
||||||
if (ProtectionFromColor) {
|
if (ProtectionFromColor) {
|
||||||
// Split "Protection from all colors" into extra Protection from <color>
|
// Split "Protection from each color" into extra Protection from <color>
|
||||||
String allColors = "Protection from all colors";
|
String allColors = "Protection from each color";
|
||||||
if (tgtC.hasKeyword(allColors)) {
|
if (tgtC.hasKeyword(allColors)) {
|
||||||
final List<String> allColorsProtect = Lists.newArrayList();
|
final List<String> allColorsProtect = Lists.newArrayList();
|
||||||
|
|
||||||
@@ -134,7 +134,7 @@ public class DebuffEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Extra for Spectra Ward
|
// Extra for Spectra Ward
|
||||||
allColors = "Protection:Card.nonColorless:all colors:Aura";
|
allColors = "Protection:Card.nonColorless:each color:Aura";
|
||||||
if (tgtC.hasKeyword(allColors)) {
|
if (tgtC.hasKeyword(allColors)) {
|
||||||
final List<String> allColorsProtect = Lists.newArrayList();
|
final List<String> allColorsProtect = Lists.newArrayList();
|
||||||
|
|
||||||
|
|||||||
@@ -180,12 +180,8 @@ public class RepeatEachEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (final Player p : repeatPlayers) {
|
for (final Player p : repeatPlayers) {
|
||||||
if (optional) {
|
if (optional && !p.getController().confirmAction(repeat, null, sa.getParam("RepeatOptionalMessage"), null)) {
|
||||||
if (!p.getController().confirmAction(repeat, null, sa.getParam("RepeatOptionalMessage"), null)) {
|
continue;
|
||||||
continue;
|
|
||||||
} else if (sa.hasParam("RememberDeciders")) {
|
|
||||||
source.addRemembered(p);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (nextTurn) {
|
if (nextTurn) {
|
||||||
game.getCleanup().addUntil(p, new GameCommand() {
|
game.getCleanup().addUntil(p, new GameCommand() {
|
||||||
|
|||||||
@@ -2258,7 +2258,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
// If no colon exists in Madness keyword, it must have been granted and assumed the cost from host
|
// If no colon exists in Madness keyword, it must have been granted and assumed the cost from host
|
||||||
sbLong.append("Madness ").append(this.getManaCost()).append(" (").append(inst.getReminderText());
|
sbLong.append("Madness ").append(this.getManaCost()).append(" (").append(inst.getReminderText());
|
||||||
sbLong.append(")").append("\r\n");
|
sbLong.append(")").append("\r\n");
|
||||||
} else if (keyword.startsWith("Emerge") || keyword.startsWith("Reflect")) {
|
} else if (keyword.startsWith("Reflect")) {
|
||||||
final String[] k = keyword.split(":");
|
final String[] k = keyword.split(":");
|
||||||
sbLong.append(k[0]).append(" ").append(ManaCostParser.parse(k[1]));
|
sbLong.append(k[0]).append(" ").append(ManaCostParser.parse(k[1]));
|
||||||
sbLong.append(" (").append(inst.getReminderText()).append(")");
|
sbLong.append(" (").append(inst.getReminderText()).append(")");
|
||||||
@@ -2325,6 +2325,16 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
sbLong.append("\r\n");
|
sbLong.append("\r\n");
|
||||||
|
} else if (keyword.startsWith("Emerge")) {
|
||||||
|
final String[] k = keyword.split(":");
|
||||||
|
sbLong.append(k[0]);
|
||||||
|
if (k.length > 2) {
|
||||||
|
sbLong.append(" from ").append(k[2].toLowerCase());
|
||||||
|
}
|
||||||
|
sbLong.append(" ").append(ManaCostParser.parse(k[1]));
|
||||||
|
sbLong.append(" (").append(inst.getReminderText()).append(")");
|
||||||
|
sbLong.append("\r\n");
|
||||||
|
|
||||||
} else if (inst.getKeyword().equals(Keyword.COMPANION)) {
|
} else if (inst.getKeyword().equals(Keyword.COMPANION)) {
|
||||||
sbLong.append("Companion — ");
|
sbLong.append("Companion — ");
|
||||||
sbLong.append(((Companion)inst).getDescription());
|
sbLong.append(((Companion)inst).getDescription());
|
||||||
@@ -2484,7 +2494,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
|| keyword.equals("Undaunted") || keyword.startsWith("Monstrosity")
|
|| keyword.equals("Undaunted") || keyword.startsWith("Monstrosity")
|
||||||
|| keyword.startsWith("Embalm") || keyword.equals("Prowess")
|
|| keyword.startsWith("Embalm") || keyword.equals("Prowess")
|
||||||
|| keyword.startsWith("Eternalize") || keyword.startsWith("Reinforce")
|
|| keyword.startsWith("Eternalize") || keyword.startsWith("Reinforce")
|
||||||
|| keyword.startsWith("Champion") || keyword.startsWith("Prowl") || keyword.startsWith("Adapt")
|
|| keyword.startsWith("Champion") || keyword.startsWith("Freerunning") || keyword.startsWith("Prowl") || keyword.startsWith("Adapt")
|
||||||
|| keyword.startsWith("Amplify") || keyword.startsWith("Ninjutsu") || keyword.startsWith("Chapter")
|
|| keyword.startsWith("Amplify") || keyword.startsWith("Ninjutsu") || keyword.startsWith("Chapter")
|
||||||
|| keyword.startsWith("Transfigure") || keyword.startsWith("Aura swap")
|
|| keyword.startsWith("Transfigure") || keyword.startsWith("Aura swap")
|
||||||
|| keyword.startsWith("Cycling") || keyword.startsWith("TypeCycling")
|
|| keyword.startsWith("Cycling") || keyword.startsWith("TypeCycling")
|
||||||
@@ -3002,7 +3012,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
} else if (keyword.startsWith("Starting intensity")) {
|
} else if (keyword.startsWith("Starting intensity")) {
|
||||||
sbAfter.append(TextUtil.fastReplace(keyword, ":", " ")).append("\r\n");
|
sbAfter.append(TextUtil.fastReplace(keyword, ":", " ")).append("\r\n");
|
||||||
} else if (keyword.startsWith("Escalate") || keyword.startsWith("Buyback")
|
} else if (keyword.startsWith("Escalate") || keyword.startsWith("Buyback")
|
||||||
|| keyword.startsWith("Prowl")) {
|
|| keyword.startsWith("Freerunning") || keyword.startsWith("Prowl")) {
|
||||||
final String[] k = keyword.split(":");
|
final String[] k = keyword.split(":");
|
||||||
final String manacost = k[1];
|
final String manacost = k[1];
|
||||||
final Cost cost = new Cost(manacost, false);
|
final Cost cost = new Cost(manacost, false);
|
||||||
@@ -6757,7 +6767,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
pW = true;
|
pW = true;
|
||||||
protectKey += "W";
|
protectKey += "W";
|
||||||
}
|
}
|
||||||
} else if (kw.contains("all colors")) {
|
} else if (kw.contains("each color")) {
|
||||||
protectKey += "allcolors:";
|
protectKey += "allcolors:";
|
||||||
} else if (kw.equals("Protection from everything")) {
|
} else if (kw.equals("Protection from everything")) {
|
||||||
protectKey += "everything:";
|
protectKey += "everything:";
|
||||||
|
|||||||
@@ -676,7 +676,7 @@ public class CardFactoryUtil {
|
|||||||
validSource = "Green" + (damage ? "Source" : "");
|
validSource = "Green" + (damage ? "Source" : "");
|
||||||
} else if (protectType.equals("colorless")) {
|
} else if (protectType.equals("colorless")) {
|
||||||
validSource = "Colorless" + (damage ? "Source" : "");
|
validSource = "Colorless" + (damage ? "Source" : "");
|
||||||
} else if (protectType.equals("all colors")) {
|
} else if (protectType.equals("each color")) {
|
||||||
validSource = "nonColorless" + (damage ? "Source" : "");
|
validSource = "nonColorless" + (damage ? "Source" : "");
|
||||||
} else if (protectType.equals("everything")) {
|
} else if (protectType.equals("everything")) {
|
||||||
return "";
|
return "";
|
||||||
@@ -2830,16 +2830,22 @@ public class CardFactoryUtil {
|
|||||||
} else if (keyword.startsWith("Emerge")) {
|
} else if (keyword.startsWith("Emerge")) {
|
||||||
final String[] kw = keyword.split(":");
|
final String[] kw = keyword.split(":");
|
||||||
String costStr = kw[1];
|
String costStr = kw[1];
|
||||||
final SpellAbility sa = card.getFirstSpellAbility();
|
String validStr = kw.length > 2 ? kw[2] : "Creature";
|
||||||
|
String desc = "(Emerge";
|
||||||
|
if (kw.length > 2) {
|
||||||
|
desc += " from " + kw[2].toLowerCase();
|
||||||
|
}
|
||||||
|
desc += ")";
|
||||||
|
|
||||||
|
final SpellAbility sa = card.getFirstSpellAbility();
|
||||||
final SpellAbility newSA = sa.copyWithDefinedCost(new Cost(costStr, false));
|
final SpellAbility newSA = sa.copyWithDefinedCost(new Cost(costStr, false));
|
||||||
|
|
||||||
newSA.getRestrictions().setIsPresent("Creature.YouCtrl+CanBeSacrificedBy");
|
newSA.getRestrictions().setIsPresent(validStr + ".YouCtrl+CanBeSacrificedBy");
|
||||||
newSA.putParam("Secondary", "True");
|
newSA.putParam("Secondary", "True");
|
||||||
newSA.setAlternativeCost(AlternativeCost.Emerge);
|
newSA.setAlternativeCost(AlternativeCost.Emerge);
|
||||||
|
|
||||||
newSA.setDescription(sa.getDescription() + " (Emerge)");
|
newSA.setDescription(sa.getDescription() + " " + desc);
|
||||||
newSA.putParam("AfterDescription", "(Emerge)");
|
newSA.putParam("AfterDescription", desc);
|
||||||
newSA.setIntrinsic(intrinsic);
|
newSA.setIntrinsic(intrinsic);
|
||||||
inst.addSpellAbility(newSA);
|
inst.addSpellAbility(newSA);
|
||||||
} else if (keyword.startsWith("Embalm")) {
|
} else if (keyword.startsWith("Embalm")) {
|
||||||
@@ -3105,6 +3111,27 @@ public class CardFactoryUtil {
|
|||||||
// instantiate attach ability
|
// instantiate attach ability
|
||||||
final SpellAbility sa = AbilityFactory.getAbility(abilityStr.toString(), card);
|
final SpellAbility sa = AbilityFactory.getAbility(abilityStr.toString(), card);
|
||||||
inst.addSpellAbility(sa);
|
inst.addSpellAbility(sa);
|
||||||
|
} else if (keyword.startsWith("Freerunning")) {
|
||||||
|
final String[] k = keyword.split(":");
|
||||||
|
final Cost freerunningCost = new Cost(k[1], false);
|
||||||
|
final SpellAbility newSA = card.getFirstSpellAbility().copyWithDefinedCost(freerunningCost);
|
||||||
|
|
||||||
|
if (host.isInstant() || host.isSorcery()) {
|
||||||
|
newSA.putParam("Secondary", "True");
|
||||||
|
}
|
||||||
|
newSA.putParam("PrecostDesc", "Freerunning");
|
||||||
|
newSA.putParam("CostDesc", ManaCostParser.parse(k[1]));
|
||||||
|
|
||||||
|
// makes new SpellDescription
|
||||||
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(newSA.getCostDescription());
|
||||||
|
sb.append("(").append(inst.getReminderText()).append(")");
|
||||||
|
newSA.setDescription(sb.toString());
|
||||||
|
|
||||||
|
newSA.setAlternativeCost(AlternativeCost.Freerunning);
|
||||||
|
|
||||||
|
newSA.setIntrinsic(intrinsic);
|
||||||
|
inst.addSpellAbility(newSA);
|
||||||
} else if (keyword.startsWith("Fuse") && card.getStateName().equals(CardStateName.Original)) {
|
} else if (keyword.startsWith("Fuse") && card.getStateName().equals(CardStateName.Original)) {
|
||||||
final SpellAbility sa = AbilityFactory.buildFusedAbility(card.getCard());
|
final SpellAbility sa = AbilityFactory.buildFusedAbility(card.getCard());
|
||||||
card.addSpellAbility(sa);
|
card.addSpellAbility(sa);
|
||||||
@@ -3900,7 +3927,8 @@ public class CardFactoryUtil {
|
|||||||
final String[] k = keyword.split(":");
|
final String[] k = keyword.split(":");
|
||||||
|
|
||||||
sbDesc.append(" from ").append(k[2]);
|
sbDesc.append(" from ").append(k[2]);
|
||||||
sbValid.append("| ValidSource$ ").append(k[1]);
|
final String param = k[2].contains("abilities") ? "ValidSA$ " : "ValidSource$ ";
|
||||||
|
sbValid.append("| ").append(param).append(k[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
String effect = "Mode$ CantTarget | ValidCard$ Card.Self | Secondary$ True"
|
String effect = "Mode$ CantTarget | ValidCard$ Card.Self | Secondary$ True"
|
||||||
|
|||||||
@@ -2120,6 +2120,14 @@ public class CardProperty {
|
|||||||
}
|
}
|
||||||
List<String> nameList = Lists.newArrayList(names.split(";"));
|
List<String> nameList = Lists.newArrayList(names.split(";"));
|
||||||
|
|
||||||
|
return nameList.contains(card.getName());
|
||||||
|
} else if (property.equals("NotedNameAetherSearcher")) {
|
||||||
|
String names = sourceController.getDraftNotes().get("Aether Searcher");
|
||||||
|
if (names == null || names.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
List<String> nameList = Lists.newArrayList(names.split(";"));
|
||||||
|
|
||||||
return nameList.contains(card.getName());
|
return nameList.contains(card.getName());
|
||||||
} else if (property.equals("NotedTypes")) {
|
} else if (property.equals("NotedTypes")) {
|
||||||
// Should Paliano Vanguard be hardcoded here or part of the property?
|
// Should Paliano Vanguard be hardcoded here or part of the property?
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ public final class CardUtil {
|
|||||||
"Cycling", "Echo", "Kicker", "Flashback", "Madness", "Morph",
|
"Cycling", "Echo", "Kicker", "Flashback", "Madness", "Morph",
|
||||||
"Affinity", "Entwine", "Splice", "Ninjutsu",
|
"Affinity", "Entwine", "Splice", "Ninjutsu",
|
||||||
"Transmute", "Replicate", "Recover", "Squad", "Suspend", "Aura swap",
|
"Transmute", "Replicate", "Recover", "Squad", "Suspend", "Aura swap",
|
||||||
"Fortify", "Transfigure", "Champion", "Evoke", "Prowl",
|
"Fortify", "Transfigure", "Champion", "Evoke", "Prowl", "Freerunning",
|
||||||
"Reinforce", "Unearth", "Level up", "Miracle", "Overload", "Cleave",
|
"Reinforce", "Unearth", "Level up", "Miracle", "Overload", "Cleave",
|
||||||
"Scavenge", "Encore", "Bestow", "Outlast", "Dash", "Surge", "Emerge", "Hexproof:",
|
"Scavenge", "Encore", "Bestow", "Outlast", "Dash", "Surge", "Emerge", "Hexproof:",
|
||||||
"etbCounter", "Reflect", "Ward").build();
|
"etbCounter", "Reflect", "Ward").build();
|
||||||
|
|||||||
@@ -326,8 +326,28 @@ public class CardView extends GameEntityView {
|
|||||||
void updateDamage(Card c) {
|
void updateDamage(Card c) {
|
||||||
set(TrackableProperty.Damage, c.getDamage());
|
set(TrackableProperty.Damage, c.getDamage());
|
||||||
updateLethalDamage(c);
|
updateLethalDamage(c);
|
||||||
//update CrackOverlay (currently 16 overlays)
|
//get crackoverlay by level of damage light 0, medium 1, heavy 2, max 3
|
||||||
set(TrackableProperty.CrackOverlay, c.getDamage() > 0 ? MyRandom.getRandom().nextInt(16) : 0);
|
int randCrackLevel = 0;
|
||||||
|
if (c.getDamage() > 0) {
|
||||||
|
switch (c.getDamage()) {
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
randCrackLevel = 0;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
randCrackLevel = 1;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
randCrackLevel = 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
randCrackLevel = 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set(TrackableProperty.CrackOverlay, randCrackLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getAssignedDamage() {
|
public int getAssignedDamage() {
|
||||||
@@ -1466,6 +1486,7 @@ public class CardView extends GameEntityView {
|
|||||||
public String getKeywordKey() { return get(TrackableProperty.KeywordKey); }
|
public String getKeywordKey() { return get(TrackableProperty.KeywordKey); }
|
||||||
public String getProtectionKey() { return get(TrackableProperty.ProtectionKey); }
|
public String getProtectionKey() { return get(TrackableProperty.ProtectionKey); }
|
||||||
public String getHexproofKey() { return get(TrackableProperty.HexproofKey); }
|
public String getHexproofKey() { return get(TrackableProperty.HexproofKey); }
|
||||||
|
public boolean hasAnnihilator() { return get(TrackableProperty.HasAnnihilator); }
|
||||||
public boolean hasDeathtouch() { return get(TrackableProperty.HasDeathtouch); }
|
public boolean hasDeathtouch() { return get(TrackableProperty.HasDeathtouch); }
|
||||||
public boolean hasToxic() { return get(TrackableProperty.HasToxic); }
|
public boolean hasToxic() { return get(TrackableProperty.HasToxic); }
|
||||||
public boolean hasDevoid() { return get(TrackableProperty.HasDevoid); }
|
public boolean hasDevoid() { return get(TrackableProperty.HasDevoid); }
|
||||||
@@ -1473,6 +1494,7 @@ public class CardView extends GameEntityView {
|
|||||||
public boolean hasDivideDamage() { return get(TrackableProperty.HasDivideDamage); }
|
public boolean hasDivideDamage() { return get(TrackableProperty.HasDivideDamage); }
|
||||||
public boolean hasDoubleStrike() { return get(TrackableProperty.HasDoubleStrike); }
|
public boolean hasDoubleStrike() { return get(TrackableProperty.HasDoubleStrike); }
|
||||||
public boolean hasDoubleTeam() { return get(TrackableProperty.HasDoubleTeam); }
|
public boolean hasDoubleTeam() { return get(TrackableProperty.HasDoubleTeam); }
|
||||||
|
public boolean hasExalted() { return get(TrackableProperty.HasExalted); }
|
||||||
public boolean hasFirstStrike() { return get(TrackableProperty.HasFirstStrike); }
|
public boolean hasFirstStrike() { return get(TrackableProperty.HasFirstStrike); }
|
||||||
public boolean hasFlying() { return get(TrackableProperty.HasFlying); }
|
public boolean hasFlying() { return get(TrackableProperty.HasFlying); }
|
||||||
public boolean hasFear() { return get(TrackableProperty.HasFear); }
|
public boolean hasFear() { return get(TrackableProperty.HasFear); }
|
||||||
@@ -1542,6 +1564,7 @@ public class CardView extends GameEntityView {
|
|||||||
}
|
}
|
||||||
void updateKeywords(Card c, CardState state) {
|
void updateKeywords(Card c, CardState state) {
|
||||||
c.updateKeywordsCache(state);
|
c.updateKeywordsCache(state);
|
||||||
|
set(TrackableProperty.HasAnnihilator, c.hasKeyword(Keyword.ANNIHILATOR, state));
|
||||||
set(TrackableProperty.HasDeathtouch, c.hasKeyword(Keyword.DEATHTOUCH, state));
|
set(TrackableProperty.HasDeathtouch, c.hasKeyword(Keyword.DEATHTOUCH, state));
|
||||||
set(TrackableProperty.HasToxic, c.hasKeyword(Keyword.TOXIC, state));
|
set(TrackableProperty.HasToxic, c.hasKeyword(Keyword.TOXIC, state));
|
||||||
set(TrackableProperty.HasDevoid, c.hasKeyword(Keyword.DEVOID, state));
|
set(TrackableProperty.HasDevoid, c.hasKeyword(Keyword.DEVOID, state));
|
||||||
@@ -1549,6 +1572,7 @@ public class CardView extends GameEntityView {
|
|||||||
set(TrackableProperty.HasDivideDamage, c.hasKeyword("You may assign CARDNAME's combat damage divided as " +
|
set(TrackableProperty.HasDivideDamage, c.hasKeyword("You may assign CARDNAME's combat damage divided as " +
|
||||||
"you choose among defending player and/or any number of creatures they control."));
|
"you choose among defending player and/or any number of creatures they control."));
|
||||||
set(TrackableProperty.HasDoubleStrike, c.hasKeyword(Keyword.DOUBLE_STRIKE, state));
|
set(TrackableProperty.HasDoubleStrike, c.hasKeyword(Keyword.DOUBLE_STRIKE, state));
|
||||||
|
set(TrackableProperty.HasExalted, c.hasKeyword(Keyword.EXALTED, state));
|
||||||
set(TrackableProperty.HasFirstStrike, c.hasKeyword(Keyword.FIRST_STRIKE, state));
|
set(TrackableProperty.HasFirstStrike, c.hasKeyword(Keyword.FIRST_STRIKE, state));
|
||||||
set(TrackableProperty.HasFlying, c.hasKeyword(Keyword.FLYING, state));
|
set(TrackableProperty.HasFlying, c.hasKeyword(Keyword.FLYING, state));
|
||||||
set(TrackableProperty.HasFear, c.hasKeyword(Keyword.FEAR, state));
|
set(TrackableProperty.HasFear, c.hasKeyword(Keyword.FEAR, state));
|
||||||
|
|||||||
@@ -223,7 +223,15 @@ public class CostAdjustment {
|
|||||||
// Reduce cost
|
// Reduce cost
|
||||||
int sumGeneric = 0;
|
int sumGeneric = 0;
|
||||||
if (sa.hasParam("ReduceCost")) {
|
if (sa.hasParam("ReduceCost")) {
|
||||||
sumGeneric += AbilityUtils.calculateAmount(originalCard, sa.getParam("ReduceCost"), sa);
|
String cst = sa.getParam("ReduceCost");
|
||||||
|
String amt = sa.getParamOrDefault("ReduceAmount", cst);
|
||||||
|
int num = AbilityUtils.calculateAmount(originalCard, amt, sa);
|
||||||
|
|
||||||
|
if (sa.hasParam("ReduceAmount") && num > 0) {
|
||||||
|
cost.subtractManaCost(new ManaCost(new ManaCostParser(Strings.repeat(cst + " ", num))));
|
||||||
|
} else {
|
||||||
|
sumGeneric += num;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!reduceAbilities.isEmpty()) {
|
while (!reduceAbilities.isEmpty()) {
|
||||||
@@ -379,9 +387,15 @@ public class CostAdjustment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void adjustCostByEmerge(final ManaCostBeingPaid cost, final SpellAbility sa) {
|
private static void adjustCostByEmerge(final ManaCostBeingPaid cost, final SpellAbility sa) {
|
||||||
CardCollectionView canEmerge = CardLists.filter(sa.getActivatingPlayer().getCreaturesInPlay(), CardPredicates.canBeSacrificedBy(sa, false));
|
String kw = sa.getKeyword().getOriginal();
|
||||||
|
String k[] = kw.split(":");
|
||||||
|
String validStr = k.length > 2 ? k[2] : "Creature";
|
||||||
|
Player p = sa.getActivatingPlayer();
|
||||||
|
CardCollectionView canEmerge = CardLists.filter(p.getCardsIn(ZoneType.Battlefield),
|
||||||
|
CardPredicates.restriction(validStr, p, sa.getHostCard(), sa),
|
||||||
|
CardPredicates.canBeSacrificedBy(sa, false));
|
||||||
|
|
||||||
final CardCollectionView toSacList = sa.getHostCard().getController().getController().choosePermanentsToSacrifice(sa, 0, 1, canEmerge, "Creature");
|
final CardCollectionView toSacList = p.getController().choosePermanentsToSacrifice(sa, 0, 1, canEmerge, validStr);
|
||||||
|
|
||||||
if (toSacList.isEmpty()) {
|
if (toSacList.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
13
forge-game/src/main/java/forge/game/keyword/Emerge.java
Normal file
13
forge-game/src/main/java/forge/game/keyword/Emerge.java
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package forge.game.keyword;
|
||||||
|
|
||||||
|
public class Emerge extends KeywordWithCostAndType {
|
||||||
|
protected void parse(String details) {
|
||||||
|
final String[] k = details.split(":");
|
||||||
|
if (k.length < 2) {
|
||||||
|
super.parse("Creature:" + k[0]);
|
||||||
|
} else {
|
||||||
|
// Flip parameters
|
||||||
|
super.parse(k[1] + ":" + k[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -69,7 +69,7 @@ public enum Keyword {
|
|||||||
DREDGE("Dredge", KeywordWithAmount.class, false, "If you would draw a card, instead you may put exactly {%d:card} from the top of your library into your graveyard. If you do, return this card from your graveyard to your hand. Otherwise, draw a card."),
|
DREDGE("Dredge", KeywordWithAmount.class, false, "If you would draw a card, instead you may put exactly {%d:card} from the top of your library into your graveyard. If you do, return this card from your graveyard to your hand. Otherwise, draw a card."),
|
||||||
ECHO("Echo", KeywordWithCost.class, false, "At the beginning of your upkeep, if this permanent came under your control since the beginning of your last upkeep, sacrifice it unless you pay %s."),
|
ECHO("Echo", KeywordWithCost.class, false, "At the beginning of your upkeep, if this permanent came under your control since the beginning of your last upkeep, sacrifice it unless you pay %s."),
|
||||||
EMBALM("Embalm", KeywordWithCost.class, false, "%s, Exile this card from your graveyard: Create a token that's a copy of this card, except it's white, it has no mana cost, and it's a Zombie in addition to its other types. Embalm only as a sorcery."),
|
EMBALM("Embalm", KeywordWithCost.class, false, "%s, Exile this card from your graveyard: Create a token that's a copy of this card, except it's white, it has no mana cost, and it's a Zombie in addition to its other types. Embalm only as a sorcery."),
|
||||||
EMERGE("Emerge", KeywordWithCost.class, false, "You may cast this spell by sacrificing a creature and paying the emerge cost reduced by that creature's mana value."),
|
EMERGE("Emerge", Emerge.class, false, "You may cast this spell by sacrificing {1:%2$s} and paying the emerge cost reduced by that %2$s's mana value."),
|
||||||
ENCHANT("Enchant", KeywordWithType.class, false, "Target a %s as you cast this. This card enters the battlefield attached to that %s."),
|
ENCHANT("Enchant", KeywordWithType.class, false, "Target a %s as you cast this. This card enters the battlefield attached to that %s."),
|
||||||
ENCORE("Encore", KeywordWithCost.class, false, "%s, Exile this card from your graveyard: For each opponent, create a token copy that attacks that opponent this turn if able. They gain haste. Sacrifice them at the beginning of the next end step. Activate only as a sorcery."),
|
ENCORE("Encore", KeywordWithCost.class, false, "%s, Exile this card from your graveyard: For each opponent, create a token copy that attacks that opponent this turn if able. They gain haste. Sacrifice them at the beginning of the next end step. Activate only as a sorcery."),
|
||||||
ENLIST("Enlist", SimpleKeyword.class, false, "As this creature attacks, you may tap a nonattacking creature you control without summoning sickness. When you do, add its power to this creature’s until end of turn."),
|
ENLIST("Enlist", SimpleKeyword.class, false, "As this creature attacks, you may tap a nonattacking creature you control without summoning sickness. When you do, add its power to this creature’s until end of turn."),
|
||||||
@@ -95,6 +95,7 @@ public enum Keyword {
|
|||||||
FOR_MIRRODIN("For Mirrodin", SimpleKeyword.class, false, "When this Equipment enters the battlefield, create a 2/2 red Rebel creature token, then attach this to it."),
|
FOR_MIRRODIN("For Mirrodin", SimpleKeyword.class, false, "When this Equipment enters the battlefield, create a 2/2 red Rebel creature token, then attach this to it."),
|
||||||
FORETELL("Foretell", KeywordWithCost.class, false, "During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost."),
|
FORETELL("Foretell", KeywordWithCost.class, false, "During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost."),
|
||||||
FORTIFY("Fortify", KeywordWithCost.class, false, "%s: Attach to target land you control. Fortify only as a sorcery."),
|
FORTIFY("Fortify", KeywordWithCost.class, false, "%s: Attach to target land you control. Fortify only as a sorcery."),
|
||||||
|
FREERUNNING("Freerunning", KeywordWithCost.class, false, "You may cast this spell for its freerunning cost if you dealt combat damage to a player this turn with an Assassin or commander."),
|
||||||
FRENZY("Frenzy", KeywordWithAmount.class, false, "Whenever this creature attacks and isn't blocked, it gets +%d/+0 until end of turn."),
|
FRENZY("Frenzy", KeywordWithAmount.class, false, "Whenever this creature attacks and isn't blocked, it gets +%d/+0 until end of turn."),
|
||||||
FRIENDS_FOREVER("Friends forever", Partner.class, true, "You can have two commanders if both have friends forever."),
|
FRIENDS_FOREVER("Friends forever", Partner.class, true, "You can have two commanders if both have friends forever."),
|
||||||
FUSE("Fuse", SimpleKeyword.class, true, "You may cast one or both halves of this card from your hand."),
|
FUSE("Fuse", SimpleKeyword.class, true, "You may cast one or both halves of this card from your hand."),
|
||||||
|
|||||||
@@ -2150,6 +2150,10 @@ public class Player extends GameEntity implements Comparable<Player> {
|
|||||||
return !game.getDamageDoneThisTurn(true, true, sb.toString(), "Player", null, this, null).isEmpty();
|
return !game.getDamageDoneThisTurn(true, true, sb.toString(), "Player", null, this, null).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final boolean hasFreerunning() {
|
||||||
|
return !game.getDamageDoneThisTurn(true, true, "Card.Assassin+YouCtrl,Card.IsCommander+YouCtrl", "Player", null, this, null).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
public final void setLibrarySearched(final int l) {
|
public final void setLibrarySearched(final int l) {
|
||||||
numLibrarySearchedOwn = l;
|
numLibrarySearchedOwn = l;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package forge.game.player;
|
|||||||
|
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import forge.game.CardTraitBase;
|
import forge.game.CardTraitBase;
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
@@ -15,6 +14,7 @@ import forge.util.Expressions;
|
|||||||
import forge.util.TextUtil;
|
import forge.util.TextUtil;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
@@ -264,6 +264,10 @@ public class PlayerProperty {
|
|||||||
if (source.getChosenPlayer() == null || !source.getChosenPlayer().equals(player)) {
|
if (source.getChosenPlayer() == null || !source.getChosenPlayer().equals(player)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
} else if (property.equals("NotedDefender")) {
|
||||||
|
String tracker = player.getDraftNotes().getOrDefault("Cogwork Tracker", "");
|
||||||
|
|
||||||
|
return Iterables.contains(Arrays.asList(tracker.split(",")), String.valueOf(player));
|
||||||
} else if (property.startsWith("life")) {
|
} else if (property.startsWith("life")) {
|
||||||
int life = player.getLife();
|
int life = player.getLife();
|
||||||
int amount = AbilityUtils.calculateAmount(source, property.substring(6), spellAbility);
|
int amount = AbilityUtils.calculateAmount(source, property.substring(6), spellAbility);
|
||||||
|
|||||||
@@ -1,13 +1,7 @@
|
|||||||
package forge.game.player;
|
package forge.game.player;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import forge.LobbyPlayer;
|
import forge.LobbyPlayer;
|
||||||
import forge.deck.CardPool;
|
import forge.deck.CardPool;
|
||||||
import forge.deck.Deck;
|
import forge.deck.Deck;
|
||||||
@@ -16,6 +10,11 @@ import forge.game.GameType;
|
|||||||
import forge.item.IPaperCard;
|
import forge.item.IPaperCard;
|
||||||
import forge.item.PaperCard;
|
import forge.item.PaperCard;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
public class RegisteredPlayer {
|
public class RegisteredPlayer {
|
||||||
private final Deck originalDeck; // never return or modify this instance (it's a reference to game resources)
|
private final Deck originalDeck; // never return or modify this instance (it's a reference to game resources)
|
||||||
private Deck currentDeck;
|
private Deck currentDeck;
|
||||||
@@ -38,6 +37,7 @@ public class RegisteredPlayer {
|
|||||||
private List<PaperCard> vanguardAvatars = null;
|
private List<PaperCard> vanguardAvatars = null;
|
||||||
private PaperCard planeswalker = null;
|
private PaperCard planeswalker = null;
|
||||||
private int teamNumber = -1; // members of teams with negative id will play FFA.
|
private int teamNumber = -1; // members of teams with negative id will play FFA.
|
||||||
|
private Integer id = null;
|
||||||
private boolean randomFoil = false;
|
private boolean randomFoil = false;
|
||||||
private boolean enableETBCountersEffect = false;
|
private boolean enableETBCountersEffect = false;
|
||||||
|
|
||||||
@@ -46,6 +46,14 @@ public class RegisteredPlayer {
|
|||||||
restoreDeck();
|
restoreDeck();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setId(Integer id0) {
|
||||||
|
id = id0;
|
||||||
|
}
|
||||||
|
|
||||||
public final Deck getDeck() {
|
public final Deck getDeck() {
|
||||||
return currentDeck;
|
return currentDeck;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ public enum AlternativeCost {
|
|||||||
Evoke,
|
Evoke,
|
||||||
Flashback,
|
Flashback,
|
||||||
Foretold,
|
Foretold,
|
||||||
|
Freerunning,
|
||||||
Madness,
|
Madness,
|
||||||
MTMtE, // More Than Meets the Eye (Transformers Universes Beyond)
|
MTMtE, // More Than Meets the Eye (Transformers Universes Beyond)
|
||||||
Mutate,
|
Mutate,
|
||||||
|
|||||||
@@ -1549,6 +1549,10 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
return isAlternativeCost(AlternativeCost.Evoke);
|
return isAlternativeCost(AlternativeCost.Evoke);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final boolean isFreerunning() {
|
||||||
|
return isAlternativeCost(AlternativeCost.Freerunning);
|
||||||
|
}
|
||||||
|
|
||||||
public final boolean isMadness() {
|
public final boolean isMadness() {
|
||||||
return isAlternativeCost(AlternativeCost.Madness);
|
return isAlternativeCost(AlternativeCost.Madness);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -444,6 +444,11 @@ public class SpellAbilityRestriction extends SpellAbilityVariables {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (sa.isFreerunning()) {
|
||||||
|
if (!activator.hasFreerunning()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (this.getIsPresent() != null) {
|
if (this.getIsPresent() != null) {
|
||||||
FCollection<GameObject> list;
|
FCollection<GameObject> list;
|
||||||
if (getPresentDefined() != null) {
|
if (getPresentDefined() != null) {
|
||||||
|
|||||||
@@ -70,7 +70,8 @@ public class TriggerSpellAbilityCastOrCopy extends Trigger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc}
|
/** {@inheritDoc}
|
||||||
* @param runParams*/
|
* @param runParams
|
||||||
|
**/
|
||||||
@Override
|
@Override
|
||||||
public final boolean performTest(final Map<AbilityKey, Object> runParams) {
|
public final boolean performTest(final Map<AbilityKey, Object> runParams) {
|
||||||
final SpellAbility spellAbility = (SpellAbility) runParams.get(AbilityKey.SpellAbility);
|
final SpellAbility spellAbility = (SpellAbility) runParams.get(AbilityKey.SpellAbility);
|
||||||
|
|||||||
@@ -144,6 +144,7 @@ public enum TrackableProperty {
|
|||||||
CountBasicLandTypes(TrackableTypes.IntegerType),
|
CountBasicLandTypes(TrackableTypes.IntegerType),
|
||||||
|
|
||||||
KeywordKey(TrackableTypes.StringType),
|
KeywordKey(TrackableTypes.StringType),
|
||||||
|
HasAnnihilator(TrackableTypes.BooleanType),
|
||||||
HasDeathtouch(TrackableTypes.BooleanType),
|
HasDeathtouch(TrackableTypes.BooleanType),
|
||||||
HasToxic(TrackableTypes.BooleanType),
|
HasToxic(TrackableTypes.BooleanType),
|
||||||
HasDevoid(TrackableTypes.BooleanType),
|
HasDevoid(TrackableTypes.BooleanType),
|
||||||
@@ -151,6 +152,7 @@ public enum TrackableProperty {
|
|||||||
HasDivideDamage(TrackableTypes.BooleanType),
|
HasDivideDamage(TrackableTypes.BooleanType),
|
||||||
HasDoubleStrike(TrackableTypes.BooleanType),
|
HasDoubleStrike(TrackableTypes.BooleanType),
|
||||||
HasDoubleTeam(TrackableTypes.BooleanType),
|
HasDoubleTeam(TrackableTypes.BooleanType),
|
||||||
|
HasExalted(TrackableTypes.BooleanType),
|
||||||
HasFirstStrike(TrackableTypes.BooleanType),
|
HasFirstStrike(TrackableTypes.BooleanType),
|
||||||
HasFlying(TrackableTypes.BooleanType),
|
HasFlying(TrackableTypes.BooleanType),
|
||||||
HasFear(TrackableTypes.BooleanType),
|
HasFear(TrackableTypes.BooleanType),
|
||||||
|
|||||||
@@ -1,17 +1,7 @@
|
|||||||
package forge.screens.home.sanctioned;
|
package forge.screens.home.sanctioned;
|
||||||
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.swing.JButton;
|
|
||||||
import javax.swing.JComboBox;
|
|
||||||
import javax.swing.SwingUtilities;
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
import forge.Singletons;
|
import forge.Singletons;
|
||||||
import forge.deck.Deck;
|
import forge.deck.Deck;
|
||||||
import forge.deck.DeckGroup;
|
import forge.deck.DeckGroup;
|
||||||
@@ -38,6 +28,14 @@ import forge.screens.deckeditor.views.VStatistics;
|
|||||||
import forge.toolbox.FOptionPane;
|
import forge.toolbox.FOptionPane;
|
||||||
import forge.util.Localizer;
|
import forge.util.Localizer;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controls the draft submenu in the home UI.
|
* Controls the draft submenu in the home UI.
|
||||||
*
|
*
|
||||||
@@ -142,6 +140,12 @@ public enum CSubmenuDraft implements ICDoc {
|
|||||||
|
|
||||||
FModel.getGauntletMini().resetGauntletDraft();
|
FModel.getGauntletMini().resetGauntletDraft();
|
||||||
String duelType = (String)VSubmenuDraft.SINGLETON_INSTANCE.getCbOpponent().getSelectedItem();
|
String duelType = (String)VSubmenuDraft.SINGLETON_INSTANCE.getCbOpponent().getSelectedItem();
|
||||||
|
|
||||||
|
if (duelType == null) {
|
||||||
|
FOptionPane.showErrorDialog("Please select duel types for the draft match.", "Missing opponent items");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final DeckGroup opponentDecks = FModel.getDecks().getDraft().get(humanDeck.getName());
|
final DeckGroup opponentDecks = FModel.getDecks().getDraft().get(humanDeck.getName());
|
||||||
if (gauntlet) {
|
if (gauntlet) {
|
||||||
if ("Gauntlet".equals(duelType)) {
|
if ("Gauntlet".equals(duelType)) {
|
||||||
@@ -161,7 +165,7 @@ public enum CSubmenuDraft implements ICDoc {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
List<Deck> aiDecks = Lists.newArrayList();
|
Map<Integer, Deck> aiMap = Maps.newHashMap();
|
||||||
if (VSubmenuDraft.SINGLETON_INSTANCE.isSingleSelected()) {
|
if (VSubmenuDraft.SINGLETON_INSTANCE.isSingleSelected()) {
|
||||||
// Restore Zero Indexing
|
// Restore Zero Indexing
|
||||||
final int aiIndex = Integer.parseInt(duelType)-1;
|
final int aiIndex = Integer.parseInt(duelType)-1;
|
||||||
@@ -169,28 +173,43 @@ public enum CSubmenuDraft implements ICDoc {
|
|||||||
if (aiDeck == null) {
|
if (aiDeck == null) {
|
||||||
throw new IllegalStateException("Draft: Computer deck is null!");
|
throw new IllegalStateException("Draft: Computer deck is null!");
|
||||||
}
|
}
|
||||||
aiDecks.add(aiDeck);
|
|
||||||
|
aiMap.put(aiIndex, aiDeck);
|
||||||
} else {
|
} else {
|
||||||
final int numOpponents = Integer.parseInt(duelType);
|
final int numOpponents = Integer.parseInt(duelType);
|
||||||
|
|
||||||
List<Deck> randomOpponents = Lists.newArrayList(opponentDecks.getAiDecks());
|
int maxDecks = opponentDecks.getAiDecks().size();
|
||||||
Collections.shuffle(randomOpponents);
|
if (numOpponents > maxDecks) {
|
||||||
aiDecks = randomOpponents.subList(0, numOpponents);
|
throw new IllegalStateException("Draft: Not enough decks for the number of opponents!");
|
||||||
for(Deck d : aiDecks) {
|
}
|
||||||
if (d == null) {
|
|
||||||
|
List<Integer> aiIndices = Lists.newArrayList();
|
||||||
|
for(int i = 0; i < maxDecks; i++) {
|
||||||
|
aiIndices.add(i);
|
||||||
|
}
|
||||||
|
Collections.shuffle(aiIndices);
|
||||||
|
aiIndices = aiIndices.subList(0, numOpponents);
|
||||||
|
|
||||||
|
for(int i : aiIndices) {
|
||||||
|
final Deck aiDeck = opponentDecks.getAiDecks().get(i);
|
||||||
|
if (aiDeck == null) {
|
||||||
throw new IllegalStateException("Draft: Computer deck is null!");
|
throw new IllegalStateException("Draft: Computer deck is null!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
aiMap.put(i + 1, aiDeck);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<RegisteredPlayer> starter = new ArrayList<>();
|
final List<RegisteredPlayer> starter = new ArrayList<>();
|
||||||
|
// Human is 0
|
||||||
final RegisteredPlayer human = new RegisteredPlayer(humanDeck.getDeck()).setPlayer(GamePlayerUtil.getGuiPlayer());
|
final RegisteredPlayer human = new RegisteredPlayer(humanDeck.getDeck()).setPlayer(GamePlayerUtil.getGuiPlayer());
|
||||||
starter.add(human);
|
starter.add(human);
|
||||||
for(Deck aiDeck : aiDecks) {
|
human.setId(0);
|
||||||
starter.add(new RegisteredPlayer(aiDeck).setPlayer(GamePlayerUtil.createAiPlayer()));
|
for(Map.Entry<Integer, Deck> aiDeck : aiMap.entrySet()) {
|
||||||
}
|
RegisteredPlayer aiPlayer = new RegisteredPlayer(aiDeck.getValue()).setPlayer(GamePlayerUtil.createAiPlayer());
|
||||||
for (final RegisteredPlayer pl : starter) {
|
aiPlayer.setId(aiDeck.getKey());
|
||||||
pl.assignConspiracies();
|
starter.add(aiPlayer);
|
||||||
|
aiPlayer.assignConspiracies();
|
||||||
}
|
}
|
||||||
|
|
||||||
final HostedMatch hostedMatch = GuiBase.getInterface().hostMatch();
|
final HostedMatch hostedMatch = GuiBase.getInterface().hostMatch();
|
||||||
|
|||||||
@@ -94,10 +94,12 @@ public class CardFaceSymbols {
|
|||||||
//ability icons
|
//ability icons
|
||||||
MANA_IMAGES.put("commander", FSkin.getImage(FSkinProp.IMG_ABILITY_COMMANDER));
|
MANA_IMAGES.put("commander", FSkin.getImage(FSkinProp.IMG_ABILITY_COMMANDER));
|
||||||
MANA_IMAGES.put("ringbearer", FSkin.getImage(FSkinProp.IMG_ABILITY_RINGBEARER));
|
MANA_IMAGES.put("ringbearer", FSkin.getImage(FSkinProp.IMG_ABILITY_RINGBEARER));
|
||||||
|
MANA_IMAGES.put("annihilator", FSkin.getImage(FSkinProp.IMG_ABILITY_ANNIHILATOR));
|
||||||
MANA_IMAGES.put("toxic", FSkin.getImage(FSkinProp.IMG_ABILITY_TOXIC));
|
MANA_IMAGES.put("toxic", FSkin.getImage(FSkinProp.IMG_ABILITY_TOXIC));
|
||||||
MANA_IMAGES.put("deathtouch", FSkin.getImage(FSkinProp.IMG_ABILITY_DEATHTOUCH));
|
MANA_IMAGES.put("deathtouch", FSkin.getImage(FSkinProp.IMG_ABILITY_DEATHTOUCH));
|
||||||
MANA_IMAGES.put("defender", FSkin.getImage(FSkinProp.IMG_ABILITY_DEFENDER));
|
MANA_IMAGES.put("defender", FSkin.getImage(FSkinProp.IMG_ABILITY_DEFENDER));
|
||||||
MANA_IMAGES.put("doublestrike", FSkin.getImage(FSkinProp.IMG_ABILITY_DOUBLE_STRIKE));
|
MANA_IMAGES.put("doublestrike", FSkin.getImage(FSkinProp.IMG_ABILITY_DOUBLE_STRIKE));
|
||||||
|
MANA_IMAGES.put("exalted", FSkin.getImage(FSkinProp.IMG_ABILITY_EXALTED));
|
||||||
MANA_IMAGES.put("firststrike", FSkin.getImage(FSkinProp.IMG_ABILITY_FIRST_STRIKE));
|
MANA_IMAGES.put("firststrike", FSkin.getImage(FSkinProp.IMG_ABILITY_FIRST_STRIKE));
|
||||||
MANA_IMAGES.put("fear", FSkin.getImage(FSkinProp.IMG_ABILITY_FEAR));
|
MANA_IMAGES.put("fear", FSkin.getImage(FSkinProp.IMG_ABILITY_FEAR));
|
||||||
MANA_IMAGES.put("flash", FSkin.getImage(FSkinProp.IMG_ABILITY_FLASH));
|
MANA_IMAGES.put("flash", FSkin.getImage(FSkinProp.IMG_ABILITY_FLASH));
|
||||||
|
|||||||
@@ -575,6 +575,14 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl
|
|||||||
CardFaceSymbols.drawAbilitySymbol("firststrike", g, abiX, abiY, abiScale, abiScale);
|
CardFaceSymbols.drawAbilitySymbol("firststrike", g, abiX, abiY, abiScale, abiScale);
|
||||||
abiY += abiSpace;
|
abiY += abiSpace;
|
||||||
}
|
}
|
||||||
|
if (card.getCurrentState().hasAnnihilator()) {
|
||||||
|
CardFaceSymbols.drawAbilitySymbol("annihilator", g, abiX, abiY, abiScale, abiScale);
|
||||||
|
abiY += abiSpace;
|
||||||
|
}
|
||||||
|
if (card.getCurrentState().hasExalted()) {
|
||||||
|
CardFaceSymbols.drawAbilitySymbol("exalted", g, abiX, abiY, abiScale, abiScale);
|
||||||
|
abiY += abiSpace;
|
||||||
|
}
|
||||||
if (card.getCurrentState().hasDeathtouch()) {
|
if (card.getCurrentState().hasDeathtouch()) {
|
||||||
CardFaceSymbols.drawAbilitySymbol("deathtouch", g, abiX, abiY, abiScale, abiScale);
|
CardFaceSymbols.drawAbilitySymbol("deathtouch", g, abiX, abiY, abiScale, abiScale);
|
||||||
abiY += abiSpace;
|
abiY += abiSpace;
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import java.util.List;
|
|||||||
public class BoosterDraftTest implements IBoosterDraft {
|
public class BoosterDraftTest implements IBoosterDraft {
|
||||||
|
|
||||||
private int n = 3;
|
private int n = 3;
|
||||||
|
private int round = 1;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Test(timeOut = 1000)
|
@Test(timeOut = 1000)
|
||||||
@@ -43,6 +44,11 @@ public class BoosterDraftTest implements IBoosterDraft {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRound() {
|
||||||
|
return round;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CardPool nextChoice() {
|
public CardPool nextChoice() {
|
||||||
this.n--;
|
this.n--;
|
||||||
@@ -95,4 +101,9 @@ public class BoosterDraftTest implements IBoosterDraft {
|
|||||||
public LimitedPlayer getNeighbor(LimitedPlayer p, boolean left) {
|
public LimitedPlayer getNeighbor(LimitedPlayer p, boolean left) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LimitedPlayer getPlayer(int i) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public class RewardSprite extends CharacterSprite {
|
|||||||
if (data != null) {
|
if (data != null) {
|
||||||
rewards = JSONStringLoader.parse(RewardData[].class, data, default_reward);
|
rewards = JSONStringLoader.parse(RewardData[].class, data, default_reward);
|
||||||
} else { //Shouldn't happen, but make sure it doesn't fly by.
|
} else { //Shouldn't happen, but make sure it doesn't fly by.
|
||||||
System.err.printf("Reward data is null. Using a default reward.");
|
System.err.print("Reward data is null. Using a default reward.");
|
||||||
rewards = JSONStringLoader.parse(RewardData[].class, default_reward, default_reward);
|
rewards = JSONStringLoader.parse(RewardData[].class, default_reward, default_reward);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -599,7 +599,7 @@ public class AdventureEventData implements Serializable {
|
|||||||
} else {
|
} else {
|
||||||
description += "\n";
|
description += "\n";
|
||||||
}
|
}
|
||||||
description += String.format("Prizes\n3 round wins: 500 gold\n2 round wins: 200 gold\n1 round win: 100 gold\n");
|
description += "Prizes\n3 round wins: 500 gold\n2 round wins: 200 gold\n1 round win: 100 gold\n";
|
||||||
description += "Finishing event will award an unsellable copy of each card in your Jumpstart deck.";
|
description += "Finishing event will award an unsellable copy of each card in your Jumpstart deck.";
|
||||||
}
|
}
|
||||||
return description;
|
return description;
|
||||||
|
|||||||
@@ -1106,10 +1106,13 @@ public class AdventureDeckEditor extends TabPageScreen<AdventureDeckEditor> {
|
|||||||
if (canOnlyBePartnerCommander(card)) {
|
if (canOnlyBePartnerCommander(card)) {
|
||||||
return; //don't auto-change commander unexpectedly
|
return; //don't auto-change commander unexpectedly
|
||||||
}
|
}
|
||||||
|
DeckSectionPage main = getMainDeckPage();
|
||||||
|
if (main == null)
|
||||||
|
return;
|
||||||
if (!cardManager.isInfinite()) {
|
if (!cardManager.isInfinite()) {
|
||||||
removeCard(card);
|
removeCard(card);
|
||||||
}
|
}
|
||||||
getMainDeckPage().addCard(card);
|
main.addCard(card);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -238,12 +238,18 @@ public class ArenaScene extends UIScene implements IAfterMatch {
|
|||||||
arenaPlane.addActor(lost);
|
arenaPlane.addActor(lost);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean started = false;
|
||||||
|
|
||||||
private void startRound() {
|
private void startRound() {
|
||||||
|
if (started)
|
||||||
|
return;
|
||||||
|
started = true;
|
||||||
DuelScene duelScene = DuelScene.instance();
|
DuelScene duelScene = DuelScene.instance();
|
||||||
EnemySprite enemy = enemies.get(enemies.size - 1);
|
EnemySprite enemy = enemies.get(enemies.size - 1);
|
||||||
FThreads.invokeInEdtNowOrLater(() -> {
|
FThreads.invokeInEdtNowOrLater(() -> {
|
||||||
Forge.setTransitionScreen(new TransitionScreen(() -> {
|
Forge.setTransitionScreen(new TransitionScreen(() -> {
|
||||||
duelScene.initDuels(WorldStage.getInstance().getPlayerSprite(), enemy);
|
started = false;
|
||||||
|
duelScene.initDuels(WorldStage.getInstance().getPlayerSprite(), enemy, true, null);
|
||||||
Forge.switchScene(duelScene);
|
Forge.switchScene(duelScene);
|
||||||
}, Forge.takeScreenshot(), true, false, false, false, "", Current.player().avatar(), enemy.getAtlasPath(), Current.player().getName(), enemy.getName()));
|
}, Forge.takeScreenshot(), true, false, false, false, "", Current.player().avatar(), enemy.getAtlasPath(), Current.player().getName(), enemy.getName()));
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ public class NewGameScene extends MenuScene {
|
|||||||
modeNames[i] = modes.get(i).getName();
|
modeNames[i] = modes.get(i).getName();
|
||||||
mode.setTextList(modeNames);
|
mode.setTextList(modeNames);
|
||||||
|
|
||||||
gender.setTextList(new String[]{Forge.getLocalizer().getInstance().getMessage("lblMale"), Forge.getLocalizer().getInstance().getMessage("lblFemale")});
|
gender.setTextList(new String[]{Forge.getLocalizer().getMessage("lblMale"), Forge.getLocalizer().getMessage("lblFemale")});
|
||||||
gender.addListener(new ClickListener() {
|
gender.addListener(new ClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void clicked(InputEvent event, float x, float y) {
|
public void clicked(InputEvent event, float x, float y) {
|
||||||
@@ -217,7 +217,7 @@ public class NewGameScene extends MenuScene {
|
|||||||
}
|
}
|
||||||
Forge.switchScene(GameScene.instance());
|
Forge.switchScene(GameScene.instance());
|
||||||
};
|
};
|
||||||
Forge.setTransitionScreen(new TransitionScreen(runnable, null, false, true, "Generating World..."));
|
Forge.setTransitionScreen(new TransitionScreen(runnable, null, false, true, Forge.getLocalizer().getMessage("lblGeneratingWorld")));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -273,6 +273,7 @@ public class PlayerStatisticScene extends UIScene {
|
|||||||
if (g != null) //skip variants
|
if (g != null) //skip variants
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
a.updateTrophyImage();
|
||||||
TextureRegion textureRegion = new TextureRegion(((FBufferedImage) a.getImage()).getTexture());
|
TextureRegion textureRegion = new TextureRegion(((FBufferedImage) a.getImage()).getTexture());
|
||||||
textureRegion.flip(false, true);
|
textureRegion.flip(false, true);
|
||||||
Image image = new Image(textureRegion);
|
Image image = new Image(textureRegion);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package forge.adventure.scene;
|
package forge.adventure.scene;
|
||||||
|
|
||||||
import com.badlogic.gdx.graphics.Color;
|
|
||||||
import com.badlogic.gdx.graphics.Texture;
|
import com.badlogic.gdx.graphics.Texture;
|
||||||
import com.badlogic.gdx.scenes.scene2d.InputEvent;
|
import com.badlogic.gdx.scenes.scene2d.InputEvent;
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.*;
|
import com.badlogic.gdx.scenes.scene2d.ui.*;
|
||||||
@@ -99,7 +98,6 @@ public class SaveLoadScene extends UIScene {
|
|||||||
ui.onButtonPress("return", SaveLoadScene.this::back);
|
ui.onButtonPress("return", SaveLoadScene.this::back);
|
||||||
difficulty.setSelectedIndex(1);
|
difficulty.setSelectedIndex(1);
|
||||||
difficulty.setAlignment(Align.center);
|
difficulty.setAlignment(Align.center);
|
||||||
difficulty.getStyle().fontColor = Color.GOLD;
|
|
||||||
difficulty.setX(scrollPane.getWidth() - difficulty.getWidth() + 5);
|
difficulty.setX(scrollPane.getWidth() - difficulty.getWidth() + 5);
|
||||||
difficulty.setY(scrollPane.getTop() - difficulty.getHeight() - 5);
|
difficulty.setY(scrollPane.getTop() - difficulty.getHeight() - 5);
|
||||||
}
|
}
|
||||||
@@ -196,14 +194,19 @@ public class SaveLoadScene extends UIScene {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean loaded = false;
|
||||||
|
|
||||||
public void loadSave() {
|
public void loadSave() {
|
||||||
|
if (loaded)
|
||||||
|
return;
|
||||||
|
loaded = true;
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case Save:
|
case Save:
|
||||||
if (TileMapScene.instance().currentMap().isInMap()) {
|
if (TileMapScene.instance().currentMap().isInMap()) {
|
||||||
//Access to screen should be disabled, but stop the process just in case.
|
//Access to screen should be disabled, but stop the process just in case.
|
||||||
//Saving needs to be disabled inside maps until we can capture and load exact map state
|
//Saving needs to be disabled inside maps until we can capture and load exact map state
|
||||||
//Otherwise location based events for quests can be skipped by saving and then loading outside the map
|
//Otherwise location based events for quests can be skipped by saving and then loading outside the map
|
||||||
Dialog noSave = createGenericDialog("", "!!GAME NOT SAVED!!\nManual saving is only available on the world map","OK",null, null, null);
|
Dialog noSave = createGenericDialog("", Forge.getLocalizer().getMessage("lblGameNotSaved"), Forge.getLocalizer().getMessage("lblOK"),null, null, null);
|
||||||
showDialog(noSave);
|
showDialog(noSave);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -226,17 +229,19 @@ public class SaveLoadScene extends UIScene {
|
|||||||
showDialog(saveDialog);
|
showDialog(saveDialog);
|
||||||
stage.setKeyboardFocus(textInput);
|
stage.setKeyboardFocus(textInput);
|
||||||
}
|
}
|
||||||
|
loaded = false;
|
||||||
break;
|
break;
|
||||||
case Load:
|
case Load:
|
||||||
try {
|
try {
|
||||||
Forge.setTransitionScreen(new TransitionScreen(() -> {
|
Forge.setTransitionScreen(new TransitionScreen(() -> {
|
||||||
|
loaded = false;
|
||||||
if (WorldSave.load(currentSlot)) {
|
if (WorldSave.load(currentSlot)) {
|
||||||
SoundSystem.instance.changeBackgroundTrack();
|
SoundSystem.instance.changeBackgroundTrack();
|
||||||
Forge.switchScene(GameScene.instance());
|
Forge.switchScene(GameScene.instance());
|
||||||
} else {
|
} else {
|
||||||
Forge.clearTransitionScreen();
|
Forge.clearTransitionScreen();
|
||||||
}
|
}
|
||||||
}, null, false, true, "Loading World..."));
|
}, null, false, true, Forge.getLocalizer().getMessage("lblLoadingWorld")));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Forge.clearTransitionScreen();
|
Forge.clearTransitionScreen();
|
||||||
}
|
}
|
||||||
@@ -244,6 +249,7 @@ public class SaveLoadScene extends UIScene {
|
|||||||
case NewGamePlus:
|
case NewGamePlus:
|
||||||
try {
|
try {
|
||||||
Forge.setTransitionScreen(new TransitionScreen(() -> {
|
Forge.setTransitionScreen(new TransitionScreen(() -> {
|
||||||
|
loaded = false;
|
||||||
if (WorldSave.load(currentSlot)) {
|
if (WorldSave.load(currentSlot)) {
|
||||||
WorldSave.getCurrentSave().clearChanges();
|
WorldSave.getCurrentSave().clearChanges();
|
||||||
WorldSave.getCurrentSave().getWorld().generateNew(0);
|
WorldSave.getCurrentSave().getWorld().generateNew(0);
|
||||||
@@ -261,8 +267,9 @@ public class SaveLoadScene extends UIScene {
|
|||||||
} else {
|
} else {
|
||||||
Forge.clearTransitionScreen();
|
Forge.clearTransitionScreen();
|
||||||
}
|
}
|
||||||
}, null, false, true, "Generating World..."));
|
}, null, false, true, Forge.getLocalizer().getMessage("lblGeneratingWorld")));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
loaded = false;
|
||||||
Forge.clearTransitionScreen();
|
Forge.clearTransitionScreen();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,24 +1,33 @@
|
|||||||
package forge.adventure.scene;
|
package forge.adventure.scene;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.files.FileHandle;
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Dialog;
|
import com.badlogic.gdx.scenes.scene2d.ui.Dialog;
|
||||||
|
import com.badlogic.gdx.utils.Timer;
|
||||||
import com.github.tommyettinger.textra.TextraButton;
|
import com.github.tommyettinger.textra.TextraButton;
|
||||||
|
import com.github.tommyettinger.textra.TypingLabel;
|
||||||
import forge.Forge;
|
import forge.Forge;
|
||||||
import forge.adventure.stage.GameHUD;
|
import forge.adventure.stage.GameHUD;
|
||||||
import forge.adventure.stage.GameStage;
|
import forge.adventure.stage.GameStage;
|
||||||
import forge.adventure.stage.MapStage;
|
import forge.adventure.stage.MapStage;
|
||||||
import forge.adventure.util.Config;
|
import forge.adventure.util.Config;
|
||||||
|
import forge.adventure.util.Controls;
|
||||||
import forge.adventure.world.WorldSave;
|
import forge.adventure.world.WorldSave;
|
||||||
|
import forge.localinstance.properties.ForgeProfileProperties;
|
||||||
import forge.screens.TransitionScreen;
|
import forge.screens.TransitionScreen;
|
||||||
import forge.sound.SoundSystem;
|
import forge.sound.SoundSystem;
|
||||||
|
import forge.util.ZipUtil;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* First scene after the splash screen
|
* First scene after the splash screen
|
||||||
*/
|
*/
|
||||||
public class StartScene extends UIScene {
|
public class StartScene extends UIScene {
|
||||||
|
|
||||||
private static StartScene object;
|
private static StartScene object;
|
||||||
Dialog exitDialog;
|
Dialog exitDialog, backupDialog, zipDialog, unzipDialog;
|
||||||
TextraButton saveButton, resumeButton, continueButton;
|
TextraButton saveButton, resumeButton, continueButton;
|
||||||
|
TypingLabel version = Controls.newTypingLabel("{GRADIENT}[%80]" + Forge.CURRENT_VERSION + "{ENDGRADIENT}");
|
||||||
|
|
||||||
|
|
||||||
public StartScene() {
|
public StartScene() {
|
||||||
@@ -30,6 +39,7 @@ public class StartScene extends UIScene {
|
|||||||
ui.onButtonPress("Resume", StartScene.this::Resume);
|
ui.onButtonPress("Resume", StartScene.this::Resume);
|
||||||
ui.onButtonPress("Continue", StartScene.this::Continue);
|
ui.onButtonPress("Continue", StartScene.this::Continue);
|
||||||
ui.onButtonPress("Settings", StartScene.this::settings);
|
ui.onButtonPress("Settings", StartScene.this::settings);
|
||||||
|
ui.onButtonPress("Backup", StartScene.this::backup);
|
||||||
ui.onButtonPress("Exit", StartScene.this::Exit);
|
ui.onButtonPress("Exit", StartScene.this::Exit);
|
||||||
ui.onButtonPress("Switch", StartScene.this::switchToClassic);
|
ui.onButtonPress("Switch", StartScene.this::switchToClassic);
|
||||||
|
|
||||||
@@ -40,6 +50,9 @@ public class StartScene extends UIScene {
|
|||||||
|
|
||||||
saveButton.setVisible(false);
|
saveButton.setVisible(false);
|
||||||
resumeButton.setVisible(false);
|
resumeButton.setVisible(false);
|
||||||
|
version.setHeight(5);
|
||||||
|
version.skipToTheEnd();
|
||||||
|
ui.addActor(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static StartScene instance() {
|
public static StartScene instance() {
|
||||||
@@ -55,7 +68,7 @@ public class StartScene extends UIScene {
|
|||||||
|
|
||||||
public boolean Save() {
|
public boolean Save() {
|
||||||
if (TileMapScene.instance().currentMap().isInMap()) {
|
if (TileMapScene.instance().currentMap().isInMap()) {
|
||||||
Dialog noSave = createGenericDialog("", "!!GAME NOT SAVED!!\nManual saving is only available on the world map","OK",null, null, null);
|
Dialog noSave = createGenericDialog("", Forge.getLocalizer().getMessage("lblGameNotSaved"), Forge.getLocalizer().getMessage("lblOK"),null, null, null);
|
||||||
showDialog(noSave);
|
showDialog(noSave);
|
||||||
} else {
|
} else {
|
||||||
SaveLoadScene.instance().setMode(SaveLoadScene.Modes.Save);
|
SaveLoadScene.instance().setMode(SaveLoadScene.Modes.Save);
|
||||||
@@ -79,20 +92,27 @@ public class StartScene extends UIScene {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean loaded = false;
|
||||||
|
|
||||||
public boolean Continue() {
|
public boolean Continue() {
|
||||||
final String lastActiveSave = Config.instance().getSettingData().lastActiveSave;
|
final String lastActiveSave = Config.instance().getSettingData().lastActiveSave;
|
||||||
|
|
||||||
if (WorldSave.isSafeFile(lastActiveSave)) {
|
if (WorldSave.isSafeFile(lastActiveSave)) {
|
||||||
|
if (loaded)
|
||||||
|
return true;
|
||||||
|
loaded = true;
|
||||||
try {
|
try {
|
||||||
Forge.setTransitionScreen(new TransitionScreen(() -> {
|
Forge.setTransitionScreen(new TransitionScreen(() -> {
|
||||||
|
loaded = false;
|
||||||
if (WorldSave.load(WorldSave.filenameToSlot(lastActiveSave))) {
|
if (WorldSave.load(WorldSave.filenameToSlot(lastActiveSave))) {
|
||||||
SoundSystem.instance.changeBackgroundTrack();
|
SoundSystem.instance.changeBackgroundTrack();
|
||||||
Forge.switchScene(GameScene.instance());
|
Forge.switchScene(GameScene.instance());
|
||||||
} else {
|
} else {
|
||||||
Forge.clearTransitionScreen();
|
Forge.clearTransitionScreen();
|
||||||
}
|
}
|
||||||
}, null, false, true, "Loading World..."));
|
}, null, false, true, Forge.getLocalizer().getMessage("lblLoadingWorld")));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
loaded = false;
|
||||||
Forge.clearTransitionScreen();
|
Forge.clearTransitionScreen();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -105,6 +125,86 @@ public class StartScene extends UIScene {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean backup() {
|
||||||
|
if (backupDialog == null) {
|
||||||
|
backupDialog = createGenericDialog(Forge.getLocalizer().getMessage("lblData"),
|
||||||
|
null, Forge.getLocalizer().getMessage("lblBackup"),
|
||||||
|
Forge.getLocalizer().getMessage("lblRestore"),
|
||||||
|
() -> {
|
||||||
|
removeDialog();
|
||||||
|
Timer.schedule(new Timer.Task() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
generateBackup();
|
||||||
|
}
|
||||||
|
}, 0.2f);
|
||||||
|
},
|
||||||
|
() -> {
|
||||||
|
removeDialog();
|
||||||
|
Timer.schedule(new Timer.Task() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
restoreBackup();
|
||||||
|
}
|
||||||
|
}, 0.2f);
|
||||||
|
}, true, Forge.getLocalizer().getMessage("lblCancel"));
|
||||||
|
}
|
||||||
|
showDialog(backupDialog);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public boolean generateBackup() {
|
||||||
|
try {
|
||||||
|
File source = new FileHandle(ForgeProfileProperties.getUserDir() + "/adventure/Shandalar").file();
|
||||||
|
File target = new FileHandle(Forge.getDeviceAdapter().getDownloadsDir()).file();
|
||||||
|
ZipUtil.zip(source, target, ZipUtil.backupAdvFile);
|
||||||
|
zipDialog = createGenericDialog("",
|
||||||
|
Forge.getLocalizer().getMessage("lblSaveLocation") + "\n" + target.getAbsolutePath() + File.separator + ZipUtil.backupAdvFile,
|
||||||
|
Forge.getLocalizer().getMessage("lblOK"), null, this::removeDialog, null);
|
||||||
|
} catch (IOException e) {
|
||||||
|
zipDialog = createGenericDialog("",
|
||||||
|
Forge.getLocalizer().getMessage("lblErrorSavingFile") + "\n\n" + e.getMessage(),
|
||||||
|
Forge.getLocalizer().getMessage("lblOK"), null, this::removeDialog, null);
|
||||||
|
} finally {
|
||||||
|
showDialog(zipDialog);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public boolean restoreBackup() {
|
||||||
|
File source = new FileHandle(Forge.getDeviceAdapter().getDownloadsDir() + ZipUtil.backupAdvFile).file();
|
||||||
|
File target = new FileHandle(ForgeProfileProperties.getUserDir() + "/adventure/Shandalar").file().getParentFile();
|
||||||
|
if (unzipDialog == null) {
|
||||||
|
unzipDialog = createGenericDialog("",
|
||||||
|
Forge.getLocalizer().getMessage("lblDoYouWantToRestoreBackup"),
|
||||||
|
Forge.getLocalizer().getMessage("lblYes"), Forge.getLocalizer().getMessage("lblNo"),
|
||||||
|
() -> {
|
||||||
|
removeDialog();
|
||||||
|
Timer.schedule(new Timer.Task() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
extract(source, target);
|
||||||
|
}
|
||||||
|
}, 0.2f);
|
||||||
|
}, this::removeDialog);
|
||||||
|
}
|
||||||
|
showDialog(unzipDialog);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public boolean extract(File source, File target) {
|
||||||
|
String title = "", val = "";
|
||||||
|
try {
|
||||||
|
val = Forge.getLocalizer().getMessage("lblFiles") + ":\n" + ZipUtil.unzip(source, target);
|
||||||
|
} catch (IOException e) {
|
||||||
|
title = Forge.getLocalizer().getMessage("lblError");
|
||||||
|
val = e.getMessage();
|
||||||
|
} finally {
|
||||||
|
Config.instance().getSettingData().lastActiveSave = null;
|
||||||
|
Config.instance().saveSettings();
|
||||||
|
showDialog(createGenericDialog(title, val,
|
||||||
|
Forge.getLocalizer().getMessage("lblOK"), null, this::removeDialog, null));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean Exit() {
|
public boolean Exit() {
|
||||||
if (exitDialog == null) {
|
if (exitDialog == null) {
|
||||||
exitDialog = createGenericDialog(Forge.getLocalizer().getMessage("lblExitForge"),
|
exitDialog = createGenericDialog(Forge.getLocalizer().getMessage("lblExitForge"),
|
||||||
@@ -123,16 +223,7 @@ public class StartScene extends UIScene {
|
|||||||
Forge.switchToClassic();
|
Forge.switchToClassic();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void updateResumeContinue() {
|
||||||
public void enter() {
|
|
||||||
boolean hasSaveButton = WorldSave.getCurrentSave().getWorld().getData() != null;
|
|
||||||
if (hasSaveButton) {
|
|
||||||
TileMapScene scene = TileMapScene.instance();
|
|
||||||
hasSaveButton = !scene.currentMap().isInMap() || scene.isAutoHealLocation();
|
|
||||||
}
|
|
||||||
saveButton.setVisible(hasSaveButton);
|
|
||||||
saveButton.setDisabled(TileMapScene.instance().currentMap().isInMap());
|
|
||||||
|
|
||||||
boolean hasResumeButton = WorldSave.getCurrentSave().getWorld().getData() != null;
|
boolean hasResumeButton = WorldSave.getCurrentSave().getWorld().getData() != null;
|
||||||
resumeButton.setVisible(hasResumeButton);
|
resumeButton.setVisible(hasResumeButton);
|
||||||
|
|
||||||
@@ -146,7 +237,18 @@ public class StartScene extends UIScene {
|
|||||||
} else {
|
} else {
|
||||||
continueButton.setVisible(false);
|
continueButton.setVisible(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void enter() {
|
||||||
|
boolean hasSaveButton = WorldSave.getCurrentSave().getWorld().getData() != null;
|
||||||
|
if (hasSaveButton) {
|
||||||
|
TileMapScene scene = TileMapScene.instance();
|
||||||
|
hasSaveButton = !scene.currentMap().isInMap() || scene.isAutoHealLocation();
|
||||||
|
}
|
||||||
|
saveButton.setVisible(hasSaveButton);
|
||||||
|
saveButton.setDisabled(TileMapScene.instance().currentMap().isInMap());
|
||||||
|
updateResumeContinue();
|
||||||
|
|
||||||
if (Forge.createNewAdventureMap) {
|
if (Forge.createNewAdventureMap) {
|
||||||
this.NewGame();
|
this.NewGame();
|
||||||
|
|||||||
@@ -239,6 +239,9 @@ public class UIScene extends Scene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Dialog createGenericDialog(String title, String label, String stringYes, String stringNo, Runnable runnableYes, Runnable runnableNo) {
|
public Dialog createGenericDialog(String title, String label, String stringYes, String stringNo, Runnable runnableYes, Runnable runnableNo) {
|
||||||
|
return createGenericDialog(title, label, stringYes, stringNo, runnableYes, runnableNo, false, "");
|
||||||
|
}
|
||||||
|
public Dialog createGenericDialog(String title, String label, String stringYes, String stringNo, Runnable runnableYes, Runnable runnableNo, boolean cancelButton, String stringCancel) {
|
||||||
Dialog dialog = new Dialog(title == null ? "" : title, Controls.getSkin());
|
Dialog dialog = new Dialog(title == null ? "" : title, Controls.getSkin());
|
||||||
if (label != null)
|
if (label != null)
|
||||||
dialog.text(label);
|
dialog.text(label);
|
||||||
@@ -248,6 +251,10 @@ public class UIScene extends Scene {
|
|||||||
TextraButton no = Controls.newTextButton(stringNo, runnableNo);
|
TextraButton no = Controls.newTextButton(stringNo, runnableNo);
|
||||||
dialog.button(no);
|
dialog.button(no);
|
||||||
}
|
}
|
||||||
|
if (cancelButton) {
|
||||||
|
TextraButton cancel = Controls.newTextButton(stringCancel, this::removeDialog);
|
||||||
|
dialog.button(cancel);
|
||||||
|
}
|
||||||
return dialog;
|
return dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public class ConsoleCommandInterpreter {
|
|||||||
public String complete(String text) {
|
public String complete(String text) {
|
||||||
String[] words = splitOnSpace(text);
|
String[] words = splitOnSpace(text);
|
||||||
Command currentCommand = root;
|
Command currentCommand = root;
|
||||||
String completionString = "";
|
StringBuilder completionString = new StringBuilder();
|
||||||
for (String name : words) {
|
for (String name : words) {
|
||||||
if (!currentCommand.children.containsKey(name)) {
|
if (!currentCommand.children.containsKey(name)) {
|
||||||
for (String key : currentCommand.children.keySet()) {
|
for (String key : currentCommand.children.keySet()) {
|
||||||
@@ -49,7 +49,7 @@ public class ConsoleCommandInterpreter {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
completionString += name + " ";
|
completionString.append(name).append(" ");
|
||||||
currentCommand = currentCommand.children.get(name);
|
currentCommand = currentCommand.children.get(name);
|
||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
|
|||||||
@@ -1039,6 +1039,7 @@ public class MapStage extends GameStage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean started = false;
|
||||||
public void beginDuel(EnemySprite mob) {
|
public void beginDuel(EnemySprite mob) {
|
||||||
if (mob == null) return;
|
if (mob == null) return;
|
||||||
mob.clearCollisionHeight();
|
mob.clearCollisionHeight();
|
||||||
@@ -1054,6 +1055,9 @@ public class MapStage extends GameStage {
|
|||||||
Forge.restrictAdvMenus = true;
|
Forge.restrictAdvMenus = true;
|
||||||
player.clearCollisionHeight();
|
player.clearCollisionHeight();
|
||||||
startPause(0.8f, () -> {
|
startPause(0.8f, () -> {
|
||||||
|
if (started)
|
||||||
|
return;
|
||||||
|
started = true;
|
||||||
Forge.setCursor(null, Forge.magnifyToggle ? "1" : "2");
|
Forge.setCursor(null, Forge.magnifyToggle ? "1" : "2");
|
||||||
SoundSystem.instance.play(SoundEffectType.ManaBurn, false);
|
SoundSystem.instance.play(SoundEffectType.ManaBurn, false);
|
||||||
DuelScene duelScene = DuelScene.instance();
|
DuelScene duelScene = DuelScene.instance();
|
||||||
@@ -1061,6 +1065,7 @@ public class MapStage extends GameStage {
|
|||||||
if (!isLoadingMatch) {
|
if (!isLoadingMatch) {
|
||||||
isLoadingMatch = true;
|
isLoadingMatch = true;
|
||||||
Forge.setTransitionScreen(new TransitionScreen(() -> {
|
Forge.setTransitionScreen(new TransitionScreen(() -> {
|
||||||
|
started = false;
|
||||||
duelScene.initDuels(player, mob);
|
duelScene.initDuels(player, mob);
|
||||||
if (isInMap && effect != null && !mob.ignoreDungeonEffect)
|
if (isInMap && effect != null && !mob.ignoreDungeonEffect)
|
||||||
duelScene.setDungeonEffect(effect);
|
duelScene.setDungeonEffect(effect);
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ public class WorldStage extends GameStage implements SaveFileContent {
|
|||||||
final Rectangle tempBoundingRect = new Rectangle();
|
final Rectangle tempBoundingRect = new Rectangle();
|
||||||
final Vector2 enemyMoveVector = new Vector2();
|
final Vector2 enemyMoveVector = new Vector2();
|
||||||
|
|
||||||
|
boolean collided = false;
|
||||||
@Override
|
@Override
|
||||||
protected void onActing(float delta) {
|
protected void onActing(float delta) {
|
||||||
if (isPaused() || MapStage.getInstance().isDialogOnlyInput())
|
if (isPaused() || MapStage.getInstance().isDialogOnlyInput())
|
||||||
@@ -110,6 +111,9 @@ public class WorldStage extends GameStage implements SaveFileContent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (player.collideWith(mob)) {
|
if (player.collideWith(mob)) {
|
||||||
|
if (collided)
|
||||||
|
return;
|
||||||
|
collided = true;
|
||||||
player.setAnimation(CharacterSprite.AnimationTypes.Attack);
|
player.setAnimation(CharacterSprite.AnimationTypes.Attack);
|
||||||
player.playEffect(Paths.EFFECT_SPARKS, 0.5f);
|
player.playEffect(Paths.EFFECT_SPARKS, 0.5f);
|
||||||
mob.setAnimation(CharacterSprite.AnimationTypes.Attack);
|
mob.setAnimation(CharacterSprite.AnimationTypes.Attack);
|
||||||
@@ -126,6 +130,7 @@ public class WorldStage extends GameStage implements SaveFileContent {
|
|||||||
DuelScene duelScene = DuelScene.instance();
|
DuelScene duelScene = DuelScene.instance();
|
||||||
FThreads.invokeInEdtNowOrLater(() -> {
|
FThreads.invokeInEdtNowOrLater(() -> {
|
||||||
Forge.setTransitionScreen(new TransitionScreen(() -> {
|
Forge.setTransitionScreen(new TransitionScreen(() -> {
|
||||||
|
collided = false;
|
||||||
duelScene.initDuels(player, mob);
|
duelScene.initDuels(player, mob);
|
||||||
Forge.switchScene(duelScene);
|
Forge.switchScene(duelScene);
|
||||||
}, Forge.takeScreenshot(), true, false, false, false, "", Current.player().avatar(), mob.getAtlasPath(), Current.player().getName(), mob.getName()));
|
}, Forge.takeScreenshot(), true, false, false, false, "", Current.player().avatar(), mob.getAtlasPath(), Current.player().getName(), mob.getName()));
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import com.badlogic.gdx.utils.Timer;
|
|||||||
import com.github.tommyettinger.textra.Font;
|
import com.github.tommyettinger.textra.Font;
|
||||||
import com.github.tommyettinger.textra.TextraButton;
|
import com.github.tommyettinger.textra.TextraButton;
|
||||||
import com.github.tommyettinger.textra.TextraLabel;
|
import com.github.tommyettinger.textra.TextraLabel;
|
||||||
|
import com.github.tommyettinger.textra.TypingButton;
|
||||||
import com.github.tommyettinger.textra.TypingLabel;
|
import com.github.tommyettinger.textra.TypingLabel;
|
||||||
import forge.Forge;
|
import forge.Forge;
|
||||||
import forge.adventure.player.AdventurePlayer;
|
import forge.adventure.player.AdventurePlayer;
|
||||||
@@ -84,12 +85,53 @@ public class Controls {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class TypingButtonFix extends TypingButton {
|
||||||
|
public TypingButtonFix(@Null String text) {
|
||||||
|
super(text == null ? "NULL" : text, Controls.getSkin(), Controls.getTextraFont());
|
||||||
|
addListener(new ClickListener(){
|
||||||
|
@Override
|
||||||
|
public void clicked(InputEvent event, float x, float y) {
|
||||||
|
super.clicked(event, x, y);
|
||||||
|
SoundSystem.instance.play(SoundEffectType.ButtonPress, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setStyle(Button.ButtonStyle style, boolean makeGridGlyphs) {
|
||||||
|
super.setStyle(style, makeGridGlyphs);
|
||||||
|
this.getTextraLabel().setFont(Controls.getTextraFont());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getText() {
|
||||||
|
return this.getTextraLabel().storedText;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setText(@Null String text) {
|
||||||
|
getTextraLabel().storedText = text;
|
||||||
|
getTextraLabel().layout.setTargetWidth(getTextraLabel().getMaxWidth());
|
||||||
|
getTextraLabel().getFont().markup(text, getTextraLabel().layout.clear());
|
||||||
|
getTextraLabel().setWidth(getTextraLabel().layout.getWidth() + (getTextraLabel().style != null && getTextraLabel().style.background != null ? getTextraLabel().style.background.getLeftWidth() + getTextraLabel().style.background.getRightWidth() : 0.0F));
|
||||||
|
layout();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static public TextraButton newTextButton(String text) {
|
static public TextraButton newTextButton(String text) {
|
||||||
TextraButton button = new TextButtonFix(text);
|
TextraButton button = new TextButtonFix(text);
|
||||||
button.getTextraLabel().setWrap(false);
|
button.getTextraLabel().setWrap(false);
|
||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static public TypingButton newTypingButton(String text) {
|
||||||
|
TypingButton button = new TypingButtonFix(text);
|
||||||
|
button.getTextraLabel().setWrap(false);
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
static public Rectangle getBoundingRect(Actor actor) {
|
static public Rectangle getBoundingRect(Actor actor) {
|
||||||
return new Rectangle(actor.getX(), actor.getY(), actor.getWidth(), actor.getHeight());
|
return new Rectangle(actor.getX(), actor.getY(), actor.getWidth(), actor.getHeight());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -354,11 +354,10 @@ public class SaveFileData extends HashMap<String,byte[]>
|
|||||||
final long localSUID = localClassDescriptor.getSerialVersionUID();
|
final long localSUID = localClassDescriptor.getSerialVersionUID();
|
||||||
final long streamSUID = resultClassDescriptor.getSerialVersionUID();
|
final long streamSUID = resultClassDescriptor.getSerialVersionUID();
|
||||||
if (streamSUID != localSUID) { // check for serialVersionUID mismatch.
|
if (streamSUID != localSUID) { // check for serialVersionUID mismatch.
|
||||||
final StringBuffer s = new StringBuffer("Overriding serialized class version mismatch: ");
|
String s = "Overriding serialized class version mismatch: " + "local serialVersionUID = " + localSUID +
|
||||||
s.append("local serialVersionUID = ").append(localSUID);
|
" stream serialVersionUID = " + streamSUID;
|
||||||
s.append(" stream serialVersionUID = ").append(streamSUID);
|
|
||||||
|
|
||||||
System.err.println("[Invalid Class Exception]\n"+s);
|
System.err.println("[Invalid Class Exception]\n"+ s);
|
||||||
resultClassDescriptor = localClassDescriptor; // Use local class descriptor for deserialization
|
resultClassDescriptor = localClassDescriptor; // Use local class descriptor for deserialization
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ public class TemplateTmxMapLoader extends TmxMapLoader {
|
|||||||
|
|
||||||
this.root = xml.parse(tmxFile);
|
this.root = xml.parse(tmxFile);
|
||||||
parameter.generateMipMaps=true;
|
parameter.generateMipMaps=true;
|
||||||
|
parameter.textureMinFilter = Texture.TextureFilter.Nearest;
|
||||||
|
parameter.textureMagFilter = Texture.TextureFilter.Nearest;
|
||||||
final Array<FileHandle> textureFiles = getDependencyFileHandles(tmxFile);
|
final Array<FileHandle> textureFiles = getDependencyFileHandles(tmxFile);
|
||||||
for (FileHandle textureFile : textureFiles) {
|
for (FileHandle textureFile : textureFiles) {
|
||||||
Texture texture = new Texture(textureFile, parameter.generateMipMaps);
|
Texture texture = new Texture(textureFile, parameter.generateMipMaps);
|
||||||
|
|||||||
@@ -23,13 +23,10 @@ public class NavigationMap {
|
|||||||
this.half = spriteSize / 2;
|
this.half = spriteSize / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
RayCastCallback callback = new RayCastCallback() {
|
RayCastCallback callback = (fixture, vector2, vector21, v) -> {
|
||||||
@Override
|
if (v < 1.0)
|
||||||
public float reportRayFixture(Fixture fixture, Vector2 vector2, Vector2 vector21, float v) {
|
rayCollided = true;
|
||||||
if (v < 1.0)
|
return 0;
|
||||||
rayCollided = true;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// public void initializeOverworldGeometryGraph() {
|
// public void initializeOverworldGeometryGraph() {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import java.util.ArrayList;
|
|||||||
public class BiomeTexture implements Serializable {
|
public class BiomeTexture implements Serializable {
|
||||||
private final BiomeData data;
|
private final BiomeData data;
|
||||||
private final int tileSize;
|
private final int tileSize;
|
||||||
public static Pixmap emptyPixmap = null;
|
public Pixmap emptyPixmap = null;
|
||||||
ArrayList<ArrayList<Pixmap>> images = new ArrayList<>();
|
ArrayList<ArrayList<Pixmap>> images = new ArrayList<>();
|
||||||
ArrayList<ArrayList<Pixmap>> smallImages = new ArrayList<>();
|
ArrayList<ArrayList<Pixmap>> smallImages = new ArrayList<>();
|
||||||
ArrayList<IntMap<Pixmap>> edgeImages = new ArrayList<>();
|
ArrayList<IntMap<Pixmap>> edgeImages = new ArrayList<>();
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ public enum AbilityEffect {
|
|||||||
if (soundClip == null) {
|
if (soundClip == null) {
|
||||||
soundClip = AudioClip.createClip(ForgeConstants.EFFECTS_DIR + wav);
|
soundClip = AudioClip.createClip(ForgeConstants.EFFECTS_DIR + wav);
|
||||||
}
|
}
|
||||||
soundClip.play(FModel.getPreferences().getPrefInt(ForgePreferences.FPref.UI_VOL_SOUNDS)/100f);
|
if (soundClip != null)
|
||||||
|
soundClip.play(FModel.getPreferences().getPrefInt(ForgePreferences.FPref.UI_VOL_SOUNDS)/100f);
|
||||||
animation.start();
|
animation.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -446,10 +446,7 @@ public class FSkin {
|
|||||||
int crackCount = 0;
|
int crackCount = 0;
|
||||||
for (int j = 0; j < 4; j++) {
|
for (int j = 0; j < 4; j++) {
|
||||||
int x = j * 200;
|
int x = j * 200;
|
||||||
for(int i = 0; i < 4; i++) {
|
Forge.getAssets().cracks().put(crackCount++, new TextureRegion(Forge.getAssets().getTexture(f17), x, 0, 200, 279));
|
||||||
int y = i * 279;
|
|
||||||
Forge.getAssets().cracks().put(crackCount++, new TextureRegion(Forge.getAssets().getTexture(f17), x, y, 200, 279));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//borders
|
//borders
|
||||||
|
|||||||
@@ -350,13 +350,15 @@ public enum FSkinImage implements FSkinImageInterface {
|
|||||||
//COMMANDER
|
//COMMANDER
|
||||||
IMG_ABILITY_COMMANDER (FSkinProp.IMG_ABILITY_COMMANDER),
|
IMG_ABILITY_COMMANDER (FSkinProp.IMG_ABILITY_COMMANDER),
|
||||||
IMG_ABILITY_RINGBEARER (FSkinProp.IMG_ABILITY_RINGBEARER),
|
IMG_ABILITY_RINGBEARER (FSkinProp.IMG_ABILITY_RINGBEARER),
|
||||||
|
//ANNIHILATOR
|
||||||
|
IMG_ABILITY_ANNIHILATOR (FSkinProp.IMG_ABILITY_ANNIHILATOR),
|
||||||
//TOXIC
|
//TOXIC
|
||||||
IMG_ABILITY_TOXIC (FSkinProp.IMG_ABILITY_TOXIC),
|
IMG_ABILITY_TOXIC (FSkinProp.IMG_ABILITY_TOXIC),
|
||||||
//ABILITY ICONS
|
//ABILITY ICONS
|
||||||
IMG_ABILITY_DEATHTOUCH (FSkinProp.IMG_ABILITY_DEATHTOUCH),
|
IMG_ABILITY_DEATHTOUCH (FSkinProp.IMG_ABILITY_DEATHTOUCH),
|
||||||
IMG_ABILITY_DEFENDER (FSkinProp.IMG_ABILITY_DEFENDER),
|
IMG_ABILITY_DEFENDER (FSkinProp.IMG_ABILITY_DEFENDER),
|
||||||
IMG_ABILITY_DOUBLE_STRIKE (FSkinProp.IMG_ABILITY_DOUBLE_STRIKE),
|
IMG_ABILITY_DOUBLE_STRIKE (FSkinProp.IMG_ABILITY_DOUBLE_STRIKE),
|
||||||
|
IMG_ABILITY_EXALTED (FSkinProp.IMG_ABILITY_EXALTED),
|
||||||
IMG_ABILITY_FIRST_STRIKE (FSkinProp.IMG_ABILITY_FIRST_STRIKE),
|
IMG_ABILITY_FIRST_STRIKE (FSkinProp.IMG_ABILITY_FIRST_STRIKE),
|
||||||
IMG_ABILITY_FEAR (FSkinProp.IMG_ABILITY_FEAR),
|
IMG_ABILITY_FEAR (FSkinProp.IMG_ABILITY_FEAR),
|
||||||
IMG_ABILITY_FLASH (FSkinProp.IMG_ABILITY_FLASH),
|
IMG_ABILITY_FLASH (FSkinProp.IMG_ABILITY_FLASH),
|
||||||
|
|||||||
@@ -75,10 +75,12 @@ public class CardFaceSymbols {
|
|||||||
|
|
||||||
Forge.getAssets().manaImages().put("commander", FSkinImage.IMG_ABILITY_COMMANDER);
|
Forge.getAssets().manaImages().put("commander", FSkinImage.IMG_ABILITY_COMMANDER);
|
||||||
Forge.getAssets().manaImages().put("ringbearer", FSkinImage.IMG_ABILITY_RINGBEARER);
|
Forge.getAssets().manaImages().put("ringbearer", FSkinImage.IMG_ABILITY_RINGBEARER);
|
||||||
|
Forge.getAssets().manaImages().put("annihilator", FSkinImage.IMG_ABILITY_ANNIHILATOR);
|
||||||
Forge.getAssets().manaImages().put("toxic", FSkinImage.IMG_ABILITY_TOXIC);
|
Forge.getAssets().manaImages().put("toxic", FSkinImage.IMG_ABILITY_TOXIC);
|
||||||
Forge.getAssets().manaImages().put("deathtouch", FSkinImage.IMG_ABILITY_DEATHTOUCH);
|
Forge.getAssets().manaImages().put("deathtouch", FSkinImage.IMG_ABILITY_DEATHTOUCH);
|
||||||
Forge.getAssets().manaImages().put("defender", FSkinImage.IMG_ABILITY_DEFENDER);
|
Forge.getAssets().manaImages().put("defender", FSkinImage.IMG_ABILITY_DEFENDER);
|
||||||
Forge.getAssets().manaImages().put("doublestrike", FSkinImage.IMG_ABILITY_DOUBLE_STRIKE);
|
Forge.getAssets().manaImages().put("doublestrike", FSkinImage.IMG_ABILITY_DOUBLE_STRIKE);
|
||||||
|
Forge.getAssets().manaImages().put("exalted", FSkinImage.IMG_ABILITY_EXALTED);
|
||||||
Forge.getAssets().manaImages().put("firststrike", FSkinImage.IMG_ABILITY_FIRST_STRIKE);
|
Forge.getAssets().manaImages().put("firststrike", FSkinImage.IMG_ABILITY_FIRST_STRIKE);
|
||||||
Forge.getAssets().manaImages().put("fear", FSkinImage.IMG_ABILITY_FEAR);
|
Forge.getAssets().manaImages().put("fear", FSkinImage.IMG_ABILITY_FEAR);
|
||||||
Forge.getAssets().manaImages().put("flash", FSkinImage.IMG_ABILITY_FLASH);
|
Forge.getAssets().manaImages().put("flash", FSkinImage.IMG_ABILITY_FLASH);
|
||||||
|
|||||||
@@ -910,6 +910,24 @@ public class CardRenderer {
|
|||||||
abiY += abiSpace;
|
abiY += abiSpace;
|
||||||
abiCount += 1;
|
abiCount += 1;
|
||||||
}
|
}
|
||||||
|
if (card.getCurrentState().hasAnnihilator()) {
|
||||||
|
if (abiCount > 5) {
|
||||||
|
abiY = cy + (abiSpace * (abiCount - 6));
|
||||||
|
abiX = cx + ((cw * 2) / 1.92f);
|
||||||
|
}
|
||||||
|
CardFaceSymbols.drawSymbol("annihilator", g, abiX, abiY, abiScale, abiScale);
|
||||||
|
abiY += abiSpace;
|
||||||
|
abiCount += 1;
|
||||||
|
}
|
||||||
|
if (card.getCurrentState().hasExalted()) {
|
||||||
|
if (abiCount > 5) {
|
||||||
|
abiY = cy + (abiSpace * (abiCount - 6));
|
||||||
|
abiX = cx + ((cw * 2) / 1.92f);
|
||||||
|
}
|
||||||
|
CardFaceSymbols.drawSymbol("exalted", g, abiX, abiY, abiScale, abiScale);
|
||||||
|
abiY += abiSpace;
|
||||||
|
abiCount += 1;
|
||||||
|
}
|
||||||
if (card.getCurrentState().hasDeathtouch()) {
|
if (card.getCurrentState().hasDeathtouch()) {
|
||||||
if (abiCount > 5) {
|
if (abiCount > 5) {
|
||||||
abiY = cy + (abiSpace * (abiCount - 6));
|
abiY = cy + (abiSpace * (abiCount - 6));
|
||||||
|
|||||||
@@ -35,7 +35,21 @@
|
|||||||
"Stinging Study",
|
"Stinging Study",
|
||||||
"Study Hall",
|
"Study Hall",
|
||||||
"Witch's Clinic",
|
"Witch's Clinic",
|
||||||
"Time Vault"
|
"Time Vault",
|
||||||
|
"Sol Ring",
|
||||||
|
"Mana Crypt",
|
||||||
|
"Tolarian Academy",
|
||||||
|
"Tinker",
|
||||||
|
"Demonic Tutor",
|
||||||
|
"Vampiric Tutor",
|
||||||
|
"Bazaar of Baghdad",
|
||||||
|
"Library of Alexandria",
|
||||||
|
"Mana Vault",
|
||||||
|
"Fastbond",
|
||||||
|
"Mishra's Workshop",
|
||||||
|
"Yawgmoth's Bargain",
|
||||||
|
"Gaea's Cradle",
|
||||||
|
"Commander's Sphere"
|
||||||
],
|
],
|
||||||
"restrictedEditions": [
|
"restrictedEditions": [
|
||||||
"HTR",
|
"HTR",
|
||||||
@@ -47,12 +61,12 @@
|
|||||||
"DS0",
|
"DS0",
|
||||||
"HHO",
|
"HHO",
|
||||||
"CMB1",
|
"CMB1",
|
||||||
"UNF",
|
"UST",
|
||||||
"UGL",
|
"UGL",
|
||||||
"UNH",
|
"UNH",
|
||||||
|
"PPC1",
|
||||||
"UND",
|
"UND",
|
||||||
"PUST",
|
"PUST"
|
||||||
"UST"
|
|
||||||
],
|
],
|
||||||
"difficulties": [
|
"difficulties": [
|
||||||
{
|
{
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 120 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 122 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 111 KiB |
@@ -1,12 +1,13 @@
|
|||||||
Name:Fifth Head of the Hydra
|
Name:Fifth Head of the Hydra
|
||||||
ManaCost:no cost
|
ManaCost:no cost
|
||||||
Types:Creature Hydra
|
Types:Creature Hydra
|
||||||
|
Colors:green,blue
|
||||||
PT:1/4
|
PT:1/4
|
||||||
K:Defender
|
K:Defender
|
||||||
S:Mode$ Continuous | Affected$ You | AddKeyword$ You can't lose the game. | Description$ You can't lose the game and your opponents can't win the game.
|
S:Mode$ Continuous | Affected$ You | AddKeyword$ You can't lose the game. | Description$ You can't lose the game and your opponents can't win the game.
|
||||||
S:Mode$ Continuous | Affected$ Opponent | AddKeyword$ You can't win the game. | Secondary$ True | Description$ You can't lose the game and your opponents can't win the game.
|
S:Mode$ Continuous | Affected$ Opponent | AddKeyword$ You can't win the game. | Secondary$ True | Description$ You can't lose the game and your opponents can't win the game.
|
||||||
T:Mode$ Phase | Phase$ End Of Turn | ValidPlayer$ Opponent | TriggerZones$ Battlefield | Execute$ TrigDig | TriggerDescription$ At the beginning of each opponents end step, that player exiles 4 cards.
|
T:Mode$ Phase | Phase$ End Of Turn | ValidPlayer$ Opponent | TriggerZones$ Battlefield | Execute$ TrigDig | TriggerDescription$ At the beginning of each opponents end step, that player exiles the top 4 cards from their library
|
||||||
SVar:TrigDig:DB$ Dig | Defined$ TriggeredPlayer | DigNum$ 4 | DestinationZone$ Exile
|
SVar:TrigDig:DB$ Dig | Defined$ ActivePlayer | DigNum$ 4 | DestinationZone$ Exile | ChangeNum$ All
|
||||||
R:Event$ Moved | ActiveZones$ Battlefield | Origin$ Battlefield | ValidCard$ Card.Self | ReplaceWith$ Exile | Description$ If CARDNAME would leave the battlefield, instead exile it with three time counters on it. It gains suspend.
|
R:Event$ Moved | ActiveZones$ Battlefield | Origin$ Battlefield | ValidCard$ Card.Self | ReplaceWith$ Exile | Description$ If CARDNAME would leave the battlefield, instead exile it with three time counters on it. It gains suspend.
|
||||||
SVar:Exile:DB$ ChangeZone | Hidden$ True | WithCountersType$ TIME | WithCountersAmount$ 3 | Origin$ All | Destination$ Exile | Defined$ ReplacedCard | SubAbility$ GiveSuspend
|
SVar:Exile:DB$ ChangeZone | Hidden$ True | WithCountersType$ TIME | WithCountersAmount$ 3 | Origin$ All | Destination$ Exile | Defined$ ReplacedCard | SubAbility$ GiveSuspend
|
||||||
SVar:GiveSuspend:DB$ PumpAll | ValidCards$ Card.withoutSuspend+YouOwn | KW$ Suspend | PumpZone$ Exile | Duration$ Permanent
|
SVar:GiveSuspend:DB$ PumpAll | ValidCards$ Card.withoutSuspend+YouOwn | KW$ Suspend | PumpZone$ Exile | Duration$ Permanent
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
Name:First Head of the Hydra
|
Name:First Head of the Hydra
|
||||||
ManaCost:no cost
|
ManaCost:no cost
|
||||||
Types:Creature Hydra
|
Types:Creature Hydra
|
||||||
|
Colors:green,blue
|
||||||
PT:1/4
|
PT:1/4
|
||||||
K:Defender
|
K:Defender
|
||||||
S:Mode$ Continuous | Affected$ You | AddKeyword$ You can't lose the game. | Description$ You can't lose the game and your opponents can't win the game.
|
S:Mode$ Continuous | Affected$ You | AddKeyword$ You can't lose the game. | Description$ You can't lose the game and your opponents can't win the game.
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
Name:Fourth Head of the Hydra
|
Name:Fourth Head of the Hydra
|
||||||
ManaCost:no cost
|
ManaCost:no cost
|
||||||
Types:Creature Hydra
|
Types:Creature Hydra
|
||||||
|
Colors:green,blue
|
||||||
PT:1/4
|
PT:1/4
|
||||||
K:Defender
|
K:Defender
|
||||||
S:Mode$ Continuous | Affected$ You | AddKeyword$ You can't lose the game. | Description$ You can't lose the game and your opponents can't win the game.
|
S:Mode$ Continuous | Affected$ You | AddKeyword$ You can't lose the game. | Description$ You can't lose the game and your opponents can't win the game.
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ Name:Fungus of Slimefoot's Boss Effect
|
|||||||
ManaCost:no cost
|
ManaCost:no cost
|
||||||
Colors:black,green
|
Colors:black,green
|
||||||
Types:Enchantment
|
Types:Enchantment
|
||||||
S:Mode$ Continuous | Affected$ Saproling | EffectZone$ Command | AddType$ Land & Forest | SetColor$ Green | Description$ Saprolings you control are Forest lands in addition to their other types.
|
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Command | Execute$ TrigAnimateAll | TriggerDescription$ At the beginning of your upkeep, Saprolings you control perpetually become Forest lands in addition to their other types.
|
||||||
|
SVar:TrigAnimateAll:DB$ AnimateAll | Duration$ Perpetual | Abilities$ ABMana | Types$ Land,Forest | SetColor$ Green | ValidCards$ Saproling.YouCtrl+nonForest
|
||||||
|
SVar:ABMana:AB$Mana | Cost$ T | Produced$ G | SpellDescription$ Add {G}.
|
||||||
T:Mode$ Phase | Phase$ End of Turn | TriggerZones$ Command | CheckSVar$ X | SVarCompare$ GE2 | Execute$ TrigConjure | TriggerDescription$ At the beginning of each end step, if two or more creatures died this turn, conjure a random Fungus onto the battlefield.
|
T:Mode$ Phase | Phase$ End of Turn | TriggerZones$ Command | CheckSVar$ X | SVarCompare$ GE2 | Execute$ TrigConjure | TriggerDescription$ At the beginning of each end step, if two or more creatures died this turn, conjure a random Fungus onto the battlefield.
|
||||||
SVar:TrigConjure:DB$ MakeCard | Conjure$ True | AtRandom$ True | Spellbook$ Cankerbloom,Corpsejack Menace,Undercellar Myconid,Utopia Mycon,Sporemound,Deathspore Thallid,Sporoloth Ancient,Thallid Shell-Dweller,Psychotrope Thallid,Sporecrown Thallid,Sporesower Thallid,Thallid | Zone$ Battlefield
|
SVar:TrigConjure:DB$ MakeCard | Conjure$ True | AtRandom$ True | Spellbook$ Cankerbloom,Corpsejack Menace,Undercellar Myconid,Utopia Mycon,Sporemound,Deathspore Thallid,Sporoloth Ancient,Thallid Shell-Dweller,Psychotrope Thallid,Sporecrown Thallid,Sporesower Thallid,Thallid | Zone$ Battlefield
|
||||||
SVar:X:Count$ThisTurnEntered_Graveyard_from_Battlefield_Creature.YouCtrl
|
SVar:X:Count$ThisTurnEntered_Graveyard_from_Battlefield_Creature.YouCtrl
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
Name:Second Head of the Hydra
|
Name:Second Head of the Hydra
|
||||||
ManaCost:no cost
|
ManaCost:no cost
|
||||||
Types:Creature Hydra
|
Types:Creature Hydra
|
||||||
|
Colors:green,blue
|
||||||
PT:1/4
|
PT:1/4
|
||||||
K:Defender
|
K:Defender
|
||||||
S:Mode$ Continuous | Affected$ You | AddKeyword$ You can't lose the game. | Description$ You can't lose the game and your opponents can't win the game.
|
S:Mode$ Continuous | Affected$ You | AddKeyword$ You can't lose the game. | Description$ You can't lose the game and your opponents can't win the game.
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
Name:Sixth Head of the Hydra
|
Name:Sixth Head of the Hydra
|
||||||
ManaCost:no cost
|
ManaCost:no cost
|
||||||
Types:Creature Hydra
|
Types:Creature Hydra
|
||||||
|
Colors:green,blue
|
||||||
PT:1/4
|
PT:1/4
|
||||||
K:Defender
|
K:Defender
|
||||||
S:Mode$ Continuous | Affected$ You | AddKeyword$ You can't lose the game. | Description$ You can't lose the game and your opponents can't win the game.
|
S:Mode$ Continuous | Affected$ You | AddKeyword$ You can't lose the game. | Description$ You can't lose the game and your opponents can't win the game.
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
Name:Sorin's Amulet
|
||||||
|
ManaCost:no cost
|
||||||
|
Types:Enchantment
|
||||||
|
A:AB$ MakeCard | Cost$ B B PayShards<4> PayLife<4> | IsPresent$ Vampire.YouCtrl | PresentZone$ Library | PresentCompare$ GE20 | ActivationZone$ Command | GameActivationLimit$ 1 | Conjure$ True | AtRandom$ True | Spellbook$ Sorin; Grim Nemesis,Sorin; Imperious Bloodlord,Sorin; Lord of Innistrad,Sorin Markov,Sorin; Solemn Visitor,Sorin the Mirthless,Sorin; Vampire Lord,Sorin; Vengeful Bloodlord,| WithCounter$ TIME | WithCounterNum$ 3 | Zone$ Exile | RememberMade$ True | SubAbility$ GiveSuspend | SpellDescription$ Conjure a Sorin planeswalker into exile with three time counters, it gains suspend. Activate this ability only if your library contains 20 or more vampires and only once each game.
|
||||||
|
SVar:GiveSuspend:DB$ Pump | Defined$ Remembered | KW$ Suspend | PumpZone$ Exile | Duration$ Permanent | SubAbility$ DBCleanup
|
||||||
|
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||||
|
S:Mode$ Continuous | EffectZone$ Command | Affected$ Vampire.YouCtrl | AddPower$ 1 | AddToughness$ 1 | CheckSVar$ YourLife | SVarCompare$ LT10 | AddKeyword$ Lifelink | Description$ As long as your life total is lower than 10, Vampires you control have +1/+1 and have lifelink.
|
||||||
|
SVar:YourLife:Count$YourLifeTotal
|
||||||
|
Oracle:{B}{B},{M}{M}{M}{M},Pay 4 life: Conjure a Sorin planeswalker into exile with three time counters, it gains suspend. Activate this ability only if your library contains 20 or more vampires and only once each game. \nAs long as your life total is lower than 10, Vampires you control have +1/+1 and have lifelink.
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
Name:Sorin's Boss Effect
|
||||||
|
ManaCost:no cost
|
||||||
|
Types:Enchantment
|
||||||
|
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Command | CheckSVar$ YourLife | SVarCompare$ GE40 | Execute$ TrigSeek | TriggerDescription$ As long as Sorin's life total is 40 or more, Sorin seeks two nonland cards every upkeep and can't lose the game and his opponents can't win the game.
|
||||||
|
SVar:TrigSeek:DB$ Seek | Num$ 2 | Type$ Card.nonLand
|
||||||
|
S:Mode$ Continuous | Affected$ You | AddKeyword$ You can't lose the game. | CheckSVar$ YourLife | EffectZone$ Command | SVarCompare$ GE40 | Secondary$ True | Description$ You can't lose the game and your opponents can't win the game.
|
||||||
|
S:Mode$ Continuous | Affected$ Opponent | AddKeyword$ You can't win the game. | Secondary$ True | EffectZone$ Command | CheckSVar$ YourLife | Secondary$ True | SVarCompare$ GE40 | Description$ You can't lose the game and your opponents can't win the game.
|
||||||
|
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Command | CheckSVar$ YourLifeCompare | SVarCompare$ EQ2 | Execute$ TrigConjure | TriggerDescription$ As long as Sorin's life total is between 20 and 40, at Sorin's upkeep, conjure a card from Sorin's Spellbook into exile with 2 time counters on it, it gains suspend.
|
||||||
|
SVar:TrigConjure:DB$ MakeCard | Conjure$ True | AtRandom$ True | Spellbook$ Sorin; Grim Nemesis,Sorin; Imperious Bloodlord,Sorin; Lord of Innistrad,Sorin Markov,Sorin; Solemn Visitor,Sorin the Mirthless,Sorin; Vampire Lord,Sorin; Vengeful Bloodlord,Timothar; Baron of Bats,Olivia Voldaren,Patriarch's Bidding,Licia; Sanguine Tribune,Astarion; the Decadent,Strefan; Maurer Progenitor,Evelyn; the Covetous,Anje; Maid of Dishonor,Edgar Markov | WithCounter$ TIME | WithCounterNum$ 2 | Zone$ Exile | RememberMade$ True | SubAbility$ GiveSuspend
|
||||||
|
SVar:GiveSuspend:DB$ Pump | Defined$ Remembered | KW$ Suspend | PumpZone$ Exile | Duration$ Permanent | SubAbility$ DBCleanup
|
||||||
|
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||||
|
S:Mode$ Continuous | EffectZone$ Command | Affected$ Vampire.YouCtrl | AddPower$ 2 | AddToughness$ 2 | CheckSVar$ YourLife | SVarCompare$ LT20 | AddKeyword$ Lifelink | Description$ As long as Sorin's life total is lower than 20, Sorin's Vampires get +2/+2 and have lifelink.
|
||||||
|
SVar:Y:Count$Compare YourLife GE20.1.0
|
||||||
|
SVar:X:Count$Compare YourLife LE40.1.0
|
||||||
|
SVar:YourLifeCompare:SVar$X/Plus.Y
|
||||||
|
SVar:YourLife:Count$YourLifeTotal
|
||||||
|
Oracle:As long as Sorin's life total is 40 or more, Sorin seeks two nonland cards every upkeep and can't lose the game and his opponents can't win the game. \nAs long as Sorin's life total is between 20 and 40, at Sorin's upkeep, conjure a card from Sorin's Spellbook into exile with 2 time counters on it, it gains suspend.\nAs long as Sorin's life total is lower than 20, Sorin's Vampires get +2/+2 and have lifelink.
|
||||||
@@ -2,6 +2,7 @@ Name:Third Head of the Hydra
|
|||||||
ManaCost:no cost
|
ManaCost:no cost
|
||||||
Types:Creature Hydra
|
Types:Creature Hydra
|
||||||
PT:1/4
|
PT:1/4
|
||||||
|
Colors:green,blue
|
||||||
K:Defender
|
K:Defender
|
||||||
S:Mode$ Continuous | Affected$ You | AddKeyword$ You can't lose the game. | Description$ You can't lose the game and your opponents can't win the game.
|
S:Mode$ Continuous | Affected$ You | AddKeyword$ You can't lose the game. | Description$ You can't lose the game and your opponents can't win the game.
|
||||||
S:Mode$ Continuous | Affected$ Opponent | AddKeyword$ You can't win the game. | Secondary$ True | Description$ You can't lose the game and your opponents can't win the game.
|
S:Mode$ Continuous | Affected$ Opponent | AddKeyword$ You can't win the game. | Secondary$ True | Description$ You can't lose the game and your opponents can't win the game.
|
||||||
|
|||||||
@@ -4,55 +4,79 @@ Name=slimefoot
|
|||||||
|
|
||||||
[Main]
|
[Main]
|
||||||
4 Abrupt Decay|GK1|1
|
4 Abrupt Decay|GK1|1
|
||||||
|
3 Akawalli, the Seething Tower|LCI|1
|
||||||
4 Bayou|30A|1
|
4 Bayou|30A|1
|
||||||
|
2 Binding the Old Gods|KHM|1
|
||||||
2 Blood Artist|J22|1
|
2 Blood Artist|J22|1
|
||||||
|
4 Bojuka Bog|WOC|1
|
||||||
|
2 Casualties of War|KHC|1
|
||||||
4 Corpsejack Menace|CM2|1
|
4 Corpsejack Menace|CM2|1
|
||||||
4 Cultivate|AFC|1
|
4 Cultivate|AFC|1
|
||||||
1 Damnation|TSR|1
|
1 Damnation|TSR|1
|
||||||
2 Deathbloom Thallid|J22|1
|
2 Deathbloom Thallid|J22|1
|
||||||
4 Deathbonnet Sprout|MID|1
|
4 Deathbonnet Sprout|MID|1
|
||||||
4 Deathcap Glade|VOW|1
|
4 Deathcap Glade|VOW|1
|
||||||
|
4 Deathcap Marionette|LCI|1
|
||||||
3 Deathsprout|C20|1
|
3 Deathsprout|C20|1
|
||||||
|
2 Doubling Season|CMM|1
|
||||||
|
2 Fists of Ironwood|RVR|1
|
||||||
11 Forest|DMU|1
|
11 Forest|DMU|1
|
||||||
2 Forest|DMU|2
|
2 Forest|DMU|2
|
||||||
3 Forest|DMU|3
|
3 Forest|DMU|3
|
||||||
|
4 Fungal Infection|J22|1
|
||||||
2 Ghave, Guru of Spores|PLIST|1
|
2 Ghave, Guru of Spores|PLIST|1
|
||||||
3 Golgari Germination|DDJ|1
|
2 Golgari Germination|DDJ|1
|
||||||
|
4 Golgari Rot Farm|C20|1
|
||||||
|
2 Grave Pact|8ED|1
|
||||||
|
2 Grim Backwoods|C18|1
|
||||||
|
2 Growing Rites of Itlimoc|P22|1
|
||||||
4 Haunted Mire|DMU|1
|
4 Haunted Mire|DMU|1
|
||||||
4 Indatha Triome|IKO|1
|
4 Indatha Triome|IKO|1
|
||||||
2 Llanowar Wastes|BRO|1
|
2 Llanowar Wastes|BRO|1
|
||||||
4 Mold Shambler|DDM|1
|
4 Mold Shambler|DDM|1
|
||||||
3 Moldervine Reclamation|KHC|1
|
3 Moldervine Reclamation|KHC|1
|
||||||
4 Mortality Spear|STX|1
|
4 Mortality Spear|STX|1
|
||||||
4 Mycoid Shepherd|PM10|1
|
2 Mycoid Shepherd|ARB|1
|
||||||
4 Mycoloth|MB1|1
|
2 Mycoloth|MB1|1
|
||||||
4 Myconid Spore Tender|CLB|1
|
4 Myconid Spore Tender|CLB|1
|
||||||
4 Nature's Lore|DMR|1
|
4 Nature's Lore|DMR|1
|
||||||
|
2 Nemata, Grove Guardian|CMM|1
|
||||||
2 Nemata, Primeval Warden|DMU|1
|
2 Nemata, Primeval Warden|DMU|1
|
||||||
4 Overgrown Tomb|GRN|1
|
4 Overgrown Tomb|GRN|1
|
||||||
2 Pallid Mycoderm|MMA|1
|
2 Pallid Mycoderm|MMA|1
|
||||||
3 Plains|DMU|1
|
3 Plains|DMU|1
|
||||||
|
4 Propagator Primordium|YLCI|1
|
||||||
|
2 Restless Cottage|WOE|1
|
||||||
2 Rot Shambler|BFZ|1
|
2 Rot Shambler|BFZ|1
|
||||||
2 Rot Shambler|CMM|1
|
2 Rot Shambler|CMM|1
|
||||||
|
2 Saproling Symbiosis|DMR|1
|
||||||
4 Savannah|30A|1
|
4 Savannah|30A|1
|
||||||
1 Slimefoot's Survey|DMU|1
|
1 Slimefoot's Survey|DMU|1
|
||||||
4 Slimefoot, Thallid Transplant|YDMU|1
|
4 Slimefoot, Thallid Transplant|YDMU|1
|
||||||
4 Slimefoot, the Stowaway|DOM|1
|
4 Slimefoot, the Stowaway|DOM|1
|
||||||
3 Sporecrown Thallid|DOM|1
|
3 Sporecrown Thallid|DOM|1
|
||||||
4 Sproutback Trudge|C21|1
|
3 Sporemound|SCD|1
|
||||||
|
2 Sproutback Trudge|C21|1
|
||||||
4 Swamp|DMU|1
|
4 Swamp|DMU|1
|
||||||
1 Swamp|DMU|2
|
1 Swamp|DMU|2
|
||||||
1 Swamp|DMU|3
|
1 Swamp|DMU|3
|
||||||
4 Swarm Shambler|J22|1
|
4 Swarm Shambler|J22|1
|
||||||
4 Tendershoot Dryad|RIX|1
|
2 Tendershoot Dryad|RIX|1
|
||||||
|
2 Tendril of the Mycotyrant|LCI|1
|
||||||
4 Thallid|MMA|1
|
4 Thallid|MMA|1
|
||||||
|
4 The Mycotyrant|LCI|1
|
||||||
|
3 The Skullspore Nexus|LCI|1
|
||||||
2 Thelon of Havenwood|TSR|1
|
2 Thelon of Havenwood|TSR|1
|
||||||
4 Trudge Garden|C21|1
|
4 Trudge Garden|C21|1
|
||||||
|
4 Underground Mortuary|MKM|1
|
||||||
|
1 Urborg, Tomb of Yawgmoth|M15|1
|
||||||
4 Verdant Catacombs|MM3|1
|
4 Verdant Catacombs|MM3|1
|
||||||
4 Verdant Force|C15|1
|
2 Verdant Force|C15|1
|
||||||
|
2 Verdeloth the Ancient|CMM|1
|
||||||
4 Village Rites|GN3|1
|
4 Village Rites|GN3|1
|
||||||
4 Woodland Cemetery|DOM|1
|
4 Woodland Cemetery|DOM|1
|
||||||
1 Yavimaya Sapherd|DOM|1
|
1 Yavimaya Sapherd|DOM|1
|
||||||
|
1 Yavimaya, Cradle of Growth|MH2|1
|
||||||
[Sideboard]
|
[Sideboard]
|
||||||
|
|
||||||
[Planes]
|
[Planes]
|
||||||
|
|||||||
75
forge-gui/res/adventure/common/decks/miniboss/sorin.dck
Normal file
75
forge-gui/res/adventure/common/decks/miniboss/sorin.dck
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
[metadata]
|
||||||
|
Name=sorin
|
||||||
|
[Avatar]
|
||||||
|
|
||||||
|
[Main]
|
||||||
|
4 Ancient Tomb|UMA|1
|
||||||
|
4 Anguished Unmaking|SOI|1
|
||||||
|
2 Anowon, the Ruin Sage|VOC|1
|
||||||
|
4 Blood Artist|J21|1
|
||||||
|
4 Bloodline Keeper|V17|1
|
||||||
|
2 Bloodlord of Vaasgoth|VOC|1
|
||||||
|
4 Bojuka Bog|WOC|1
|
||||||
|
2 Butcher of Malakir|VOC|1
|
||||||
|
2 Call the Bloodline|F16|1
|
||||||
|
2 Champion of Dusk|VOC|1
|
||||||
|
2 Charismatic Conqueror|LCC|2
|
||||||
|
4 Clavileño, First of the Blessed|LCC|3
|
||||||
|
4 Cordial Vampire|MH1|1
|
||||||
|
4 Cruel Celebrant|LCC|1
|
||||||
|
4 Dark Ritual|A25|1
|
||||||
|
2 Echo of Dusk|LCI|1
|
||||||
|
2 Edgar, Charmed Groom|VOW|1
|
||||||
|
4 Feast of Blood|PIDW|1
|
||||||
|
3 Gifted Aetherborn|AER|1
|
||||||
|
4 Godless Shrine|RVR|1
|
||||||
|
4 Guul Draz Assassin|PLIST|1
|
||||||
|
4 Indulgent Aristocrat|VOC|1
|
||||||
|
4 Isolated Chapel|LCC|1
|
||||||
|
2 Legion's Landing|XLN|1
|
||||||
|
4 Marsh Flats|MH2|1
|
||||||
|
4 Mortify|E02|1
|
||||||
|
2 Nullpriest of Oblivion|J21|1
|
||||||
|
4 Olivia's Wrath|VOC|1
|
||||||
|
4 Orzhov Basilica|2X2|1
|
||||||
|
5 Plains|XLN|1
|
||||||
|
3 Plains|XLN|2
|
||||||
|
4 Plains|XLN|3
|
||||||
|
2 Plains|XLN|4
|
||||||
|
4 Quag Vampires|CNS|1
|
||||||
|
4 Sanctum Seeker|LCC|1
|
||||||
|
4 Scrubland|VMA|1
|
||||||
|
4 Shattered Sanctum|VOW|1
|
||||||
|
4 Shineshadow Snarl|STX|1
|
||||||
|
3 Sorin Markov|PLIST|1
|
||||||
|
2 Sorin of House Markov|MH3|1
|
||||||
|
3 Sorin the Mirthless|VOW|1
|
||||||
|
4 Sorin's Thirst|M20|1
|
||||||
|
4 Sorin's Vengeance|PLIST|1
|
||||||
|
2 Sorin, Grim Nemesis|SOI|1
|
||||||
|
3 Sorin, Imperious Bloodlord|M20|1
|
||||||
|
2 Sorin, Lord of Innistrad|LCC|1
|
||||||
|
4 Sorin, Solemn Visitor|KTK|1
|
||||||
|
1 Sorin, Vampire Lord|M20|1
|
||||||
|
2 Sorin, Vengeful Bloodlord|WAR|1
|
||||||
|
4 Sunlit Marsh|DMU|1
|
||||||
|
21 Swamp|XLN|1
|
||||||
|
4 Swords to Plowshares|CMM|1
|
||||||
|
2 Tithe Drinker|C17|1
|
||||||
|
2 Vampire Nocturnus|PDP13|1
|
||||||
|
4 Vampire of the Dire Moon|M20|1
|
||||||
|
2 Vanquisher's Banner|XLN|1
|
||||||
|
4 Vindicate|EMA|1
|
||||||
|
4 Vito, Thorn of the Dusk Rose|M21|1
|
||||||
|
2 Vona, Butcher of Magan|MOC|1
|
||||||
|
4 Welcoming Vampire|LCC|1
|
||||||
|
[Sideboard]
|
||||||
|
|
||||||
|
[Planes]
|
||||||
|
|
||||||
|
[Schemes]
|
||||||
|
|
||||||
|
[Conspiracy]
|
||||||
|
|
||||||
|
[Dungeon]
|
||||||
|
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
Name=aerie_guard
|
Name=aerie_guard
|
||||||
[Avatar]
|
|
||||||
|
|
||||||
[Main]
|
[Main]
|
||||||
2 Battlefield Raptor|KHM|1
|
2 Battlefield Raptor|KHM|1
|
||||||
2 Bident of Thassa|A25|1
|
2 Bident of Thassa|A25|1
|
||||||
@@ -41,13 +39,3 @@ Name=aerie_guard
|
|||||||
2 Welcoming Vampire|VOW|1
|
2 Welcoming Vampire|VOW|1
|
||||||
1 Winged Words|J21|1
|
1 Winged Words|J21|1
|
||||||
1 Wrath of God|PZ1|1
|
1 Wrath of God|PZ1|1
|
||||||
[Sideboard]
|
|
||||||
|
|
||||||
[Planes]
|
|
||||||
|
|
||||||
[Schemes]
|
|
||||||
|
|
||||||
[Conspiracy]
|
|
||||||
|
|
||||||
[Dungeon]
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
Name=Amonkhet - Aven U1
|
Name=Amonkhet - Aven U1
|
||||||
[Avatar]
|
|
||||||
|
|
||||||
[Main]
|
[Main]
|
||||||
1 Alrund's Epiphany|KHM|1
|
1 Alrund's Epiphany|KHM|1
|
||||||
2 Aven Eternal|WAR|1
|
2 Aven Eternal|WAR|1
|
||||||
@@ -17,13 +15,3 @@ Name=Amonkhet - Aven U1
|
|||||||
4 Silent Departure|EMA|1
|
4 Silent Departure|EMA|1
|
||||||
4 Silver Raven|AFR|1
|
4 Silver Raven|AFR|1
|
||||||
4 Winged Words|M20|1
|
4 Winged Words|M20|1
|
||||||
[Sideboard]
|
|
||||||
|
|
||||||
[Planes]
|
|
||||||
|
|
||||||
[Schemes]
|
|
||||||
|
|
||||||
[Conspiracy]
|
|
||||||
|
|
||||||
[Dungeon]
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
Name=Amonkhet - Aven W1
|
Name=Amonkhet - Aven W1
|
||||||
[Avatar]
|
|
||||||
|
|
||||||
[Main]
|
[Main]
|
||||||
4 Aven Battle Priest|ORI|1
|
4 Aven Battle Priest|ORI|1
|
||||||
1 Aven Brigadier|ONS|1
|
1 Aven Brigadier|ONS|1
|
||||||
@@ -16,12 +14,4 @@ Name=Amonkhet - Aven W1
|
|||||||
3 Union of the Third Path|BRO|1
|
3 Union of the Third Path|BRO|1
|
||||||
1 Windbrisk Raptor|SHM|1
|
1 Windbrisk Raptor|SHM|1
|
||||||
[Sideboard]
|
[Sideboard]
|
||||||
|
|
||||||
[Planes]
|
|
||||||
|
|
||||||
[Schemes]
|
[Schemes]
|
||||||
|
|
||||||
[Conspiracy]
|
|
||||||
|
|
||||||
[Dungeon]
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
Name=amonkhet_minotaur
|
Name=amonkhet_minotaur
|
||||||
[Avatar]
|
|
||||||
|
|
||||||
[Main]
|
[Main]
|
||||||
1 Ahn-Crop Crasher|AKH|1
|
1 Ahn-Crop Crasher|AKH|1
|
||||||
2 Bloodrage Brawler|AKH|1
|
2 Bloodrage Brawler|AKH|1
|
||||||
@@ -42,13 +40,3 @@ Name=amonkhet_minotaur
|
|||||||
1 Trial of Zeal|AKH|1
|
1 Trial of Zeal|AKH|1
|
||||||
2 Warfire Javelineer|AKH|1
|
2 Warfire Javelineer|AKH|1
|
||||||
2 Zealot of the God-Pharaoh|HOU|1
|
2 Zealot of the God-Pharaoh|HOU|1
|
||||||
[Sideboard]
|
|
||||||
|
|
||||||
[Planes]
|
|
||||||
|
|
||||||
[Schemes]
|
|
||||||
|
|
||||||
[Conspiracy]
|
|
||||||
|
|
||||||
[Dungeon]
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
Name=salamander
|
Name=salamander
|
||||||
[Avatar]
|
|
||||||
|
|
||||||
[Main]
|
[Main]
|
||||||
1 Aetherspouts|C21|1
|
1 Aetherspouts|C21|1
|
||||||
4 Amphin Cutthroat|M12|1
|
4 Amphin Cutthroat|M12|1
|
||||||
@@ -26,13 +24,3 @@ Name=salamander
|
|||||||
3 Vineglimmer Snarl|LTC|1
|
3 Vineglimmer Snarl|LTC|1
|
||||||
1 Vronos, Masked Inquisitor|CMM|1
|
1 Vronos, Masked Inquisitor|CMM|1
|
||||||
1 Wormfang Newt|JUD|1
|
1 Wormfang Newt|JUD|1
|
||||||
[Sideboard]
|
|
||||||
|
|
||||||
[Planes]
|
|
||||||
|
|
||||||
[Schemes]
|
|
||||||
|
|
||||||
[Conspiracy]
|
|
||||||
|
|
||||||
[Dungeon]
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
Name=ancientvampire
|
Name=ancientvampire
|
||||||
[Avatar]
|
|
||||||
|
|
||||||
[Main]
|
[Main]
|
||||||
1 Bloodline Keeper|V17|1
|
1 Bloodline Keeper|V17|1
|
||||||
1 Bloodlord of Vaasgoth|C17|1
|
1 Bloodlord of Vaasgoth|C17|1
|
||||||
@@ -30,13 +28,3 @@ Name=ancientvampire
|
|||||||
2 Vito, Thorn of the Dusk Rose|PRES|1
|
2 Vito, Thorn of the Dusk Rose|PRES|1
|
||||||
1 Vraan, Executioner Thane|ONE|1
|
1 Vraan, Executioner Thane|ONE|1
|
||||||
1 Westgate Regent|AFR|1
|
1 Westgate Regent|AFR|1
|
||||||
[Sideboard]
|
|
||||||
|
|
||||||
[Planes]
|
|
||||||
|
|
||||||
[Schemes]
|
|
||||||
|
|
||||||
[Conspiracy]
|
|
||||||
|
|
||||||
[Dungeon]
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
Name=angelwarrior
|
Name=angelwarrior
|
||||||
[Avatar]
|
|
||||||
|
|
||||||
[Main]
|
[Main]
|
||||||
1 Admonition Angel|ZNC|1
|
1 Admonition Angel|ZNC|1
|
||||||
1 Akroma, Angel of Wrath|V15|1
|
1 Akroma, Angel of Wrath|V15|1
|
||||||
@@ -26,13 +24,3 @@ Name=angelwarrior
|
|||||||
1 Serra's Emissary|MH2|1
|
1 Serra's Emissary|MH2|1
|
||||||
4 Starnheim Aspirant|KHM|1
|
4 Starnheim Aspirant|KHM|1
|
||||||
4 Take Vengeance|M20|1
|
4 Take Vengeance|M20|1
|
||||||
[Sideboard]
|
|
||||||
|
|
||||||
[Planes]
|
|
||||||
|
|
||||||
[Schemes]
|
|
||||||
|
|
||||||
[Conspiracy]
|
|
||||||
|
|
||||||
[Dungeon]
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
Name=archaeologist
|
Name=archaeologist
|
||||||
[Avatar]
|
|
||||||
|
|
||||||
[Main]
|
[Main]
|
||||||
4 Ancient Den|C21|1
|
4 Ancient Den|C21|1
|
||||||
2 Angel of the Ruins|MOC|1
|
2 Angel of the Ruins|MOC|1
|
||||||
@@ -27,13 +25,3 @@ Name=archaeologist
|
|||||||
2 Tempered Steel|2XM|1
|
2 Tempered Steel|2XM|1
|
||||||
2 Teshar, Ancestor's Apostle|DOM|1
|
2 Teshar, Ancestor's Apostle|DOM|1
|
||||||
1 Traxos, Scourge of Kroog|DMC|1
|
1 Traxos, Scourge of Kroog|DMC|1
|
||||||
[Sideboard]
|
|
||||||
|
|
||||||
[Planes]
|
|
||||||
|
|
||||||
[Schemes]
|
|
||||||
|
|
||||||
[Conspiracy]
|
|
||||||
|
|
||||||
[Dungeon]
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
Name=archerelite
|
Name=archerelite
|
||||||
[Avatar]
|
|
||||||
|
|
||||||
[Main]
|
[Main]
|
||||||
2 Arbalest Elite|M12|1
|
2 Arbalest Elite|M12|1
|
||||||
2 Arcus Acolyte|J21|1
|
2 Arcus Acolyte|J21|1
|
||||||
@@ -25,13 +23,3 @@ Name=archerelite
|
|||||||
2 Tadeas, Juniper Ascendant|SLX|1
|
2 Tadeas, Juniper Ascendant|SLX|1
|
||||||
1 Titania's Chosen|C14|1
|
1 Titania's Chosen|C14|1
|
||||||
2 Titania's Chosen|CMA|1
|
2 Titania's Chosen|CMA|1
|
||||||
[Sideboard]
|
|
||||||
|
|
||||||
[Planes]
|
|
||||||
|
|
||||||
[Schemes]
|
|
||||||
|
|
||||||
[Conspiracy]
|
|
||||||
|
|
||||||
[Dungeon]
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
Name=archmage
|
Name=archmage
|
||||||
[Avatar]
|
|
||||||
|
|
||||||
[Main]
|
[Main]
|
||||||
4 Aether Channeler|DMU|1
|
4 Aether Channeler|DMU|1
|
||||||
1 Azami, Lady of Scrolls|C17|1
|
1 Azami, Lady of Scrolls|C17|1
|
||||||
@@ -19,13 +17,3 @@ Name=archmage
|
|||||||
2 Time Warp|E02|1
|
2 Time Warp|E02|1
|
||||||
2 Venser, Shaper Savant|TSR|1
|
2 Venser, Shaper Savant|TSR|1
|
||||||
4 Wizard Class|PLIST|1
|
4 Wizard Class|PLIST|1
|
||||||
[Sideboard]
|
|
||||||
|
|
||||||
[Planes]
|
|
||||||
|
|
||||||
[Schemes]
|
|
||||||
|
|
||||||
[Conspiracy]
|
|
||||||
|
|
||||||
[Dungeon]
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
[duel]
|
|
||||||
[metadata]
|
[metadata]
|
||||||
Name=Prince Valiant 3
|
Name=Prince Valiant 3
|
||||||
Title=Prince Valiant
|
|
||||||
Difficulty=hard
|
|
||||||
Description=GW Knight of the Reliquary deck with Terravore and Worm Harvest
|
|
||||||
Icon=Prince Valiant.jpg
|
|
||||||
Deck Type=constructed
|
|
||||||
[main]
|
[main]
|
||||||
4 Savannah
|
4 Savannah
|
||||||
2 Forest
|
2 Forest
|
||||||
@@ -34,4 +28,3 @@ Deck Type=constructed
|
|||||||
1 Courser of Kruphix
|
1 Courser of Kruphix
|
||||||
2 Valorous Stance
|
2 Valorous Stance
|
||||||
1 Naturalize
|
1 Naturalize
|
||||||
[sideboard]
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
Name=armored_knight
|
Name=armored_knight
|
||||||
[Avatar]
|
|
||||||
|
|
||||||
[Main]
|
[Main]
|
||||||
1 Acclaimed Contender|ELD|1
|
1 Acclaimed Contender|ELD|1
|
||||||
1 Adeline, Resplendent Cathar|MID|1
|
1 Adeline, Resplendent Cathar|MID|1
|
||||||
@@ -39,13 +37,3 @@ Name=armored_knight
|
|||||||
1 Trailblazer's Boots|ONC|1
|
1 Trailblazer's Boots|ONC|1
|
||||||
1 Valiant Endeavor|AFC|1
|
1 Valiant Endeavor|AFC|1
|
||||||
1 Varchild, Betrayer of Kjeldor|C18|1
|
1 Varchild, Betrayer of Kjeldor|C18|1
|
||||||
[Sideboard]
|
|
||||||
|
|
||||||
[Planes]
|
|
||||||
|
|
||||||
[Schemes]
|
|
||||||
|
|
||||||
[Conspiracy]
|
|
||||||
|
|
||||||
[Dungeon]
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
Name=Karn
|
Name=Karn
|
||||||
[Avatar]
|
|
||||||
|
|
||||||
[Main]
|
[Main]
|
||||||
4 Ancient Tomb|UMA|1
|
4 Ancient Tomb|UMA|1
|
||||||
2 Automatic Librarian|DMU|1
|
2 Automatic Librarian|DMU|1
|
||||||
@@ -22,13 +20,3 @@ Name=Karn
|
|||||||
4 Voltaic Servant|DOM|1
|
4 Voltaic Servant|DOM|1
|
||||||
4 Wasteland|SLD|1
|
4 Wasteland|SLD|1
|
||||||
2 Weatherlight|DOM|1
|
2 Weatherlight|DOM|1
|
||||||
[Sideboard]
|
|
||||||
|
|
||||||
[Planes]
|
|
||||||
|
|
||||||
[Schemes]
|
|
||||||
|
|
||||||
[Conspiracy]
|
|
||||||
|
|
||||||
[Dungeon]
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
Name=artificer
|
Name=artificer
|
||||||
[Avatar]
|
|
||||||
|
|
||||||
[Main]
|
[Main]
|
||||||
1 Aether Chaser|KLR|1
|
1 Aether Chaser|KLR|1
|
||||||
2 Aether Hub|KLD|1
|
2 Aether Hub|KLD|1
|
||||||
@@ -38,13 +36,3 @@ Name=artificer
|
|||||||
4 Welder Automaton|GNT|1
|
4 Welder Automaton|GNT|1
|
||||||
1 Whirler Virtuoso|KLR|1
|
1 Whirler Virtuoso|KLR|1
|
||||||
2 Whirlermaker|KLR|1
|
2 Whirlermaker|KLR|1
|
||||||
[Sideboard]
|
|
||||||
|
|
||||||
[Planes]
|
|
||||||
|
|
||||||
[Schemes]
|
|
||||||
|
|
||||||
[Conspiracy]
|
|
||||||
|
|
||||||
[Dungeon]
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
Name=axgard_dwarf
|
Name=axgard_dwarf
|
||||||
[Avatar]
|
|
||||||
|
|
||||||
[Main]
|
[Main]
|
||||||
4 Alpine Meadow|KHM|1
|
4 Alpine Meadow|KHM|1
|
||||||
2 Axgard Armory|KHM|1
|
2 Axgard Armory|KHM|1
|
||||||
@@ -30,13 +28,3 @@ Name=axgard_dwarf
|
|||||||
2 Vault Robber|KHM|1
|
2 Vault Robber|KHM|1
|
||||||
2 Warchanter Skald|KHM|1
|
2 Warchanter Skald|KHM|1
|
||||||
1 Warhorn Blast|KHM|1
|
1 Warhorn Blast|KHM|1
|
||||||
[Sideboard]
|
|
||||||
|
|
||||||
[Planes]
|
|
||||||
|
|
||||||
[Schemes]
|
|
||||||
|
|
||||||
[Conspiracy]
|
|
||||||
|
|
||||||
[Dungeon]
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
[metadata]
|
||||||
|
Name=azoriusangel
|
||||||
|
[Main]
|
||||||
|
4 Adarkar Wastes|DMU|1
|
||||||
|
2 Angel of Mercy|JMP|1
|
||||||
|
2 Benevolent Bodyguard|EMA|1
|
||||||
|
2 Celestial Regulator|SNC|1
|
||||||
|
2 Condemn|RVR|1
|
||||||
|
1 Errant and Giada|MOM|1
|
||||||
|
4 Faithful Disciple|YMID|1
|
||||||
|
2 Firemane Commando|MOC|1
|
||||||
|
2 Fragment Reality|YNEO|1
|
||||||
|
1 Geist of Saint Traft|PRM|1
|
||||||
|
2 Glacial Fortress|XLN|1
|
||||||
|
2 Holy Armor|30A|1
|
||||||
|
3 Holy Strength|30A|1
|
||||||
|
2 Invasion of Xerex|MOM|1
|
||||||
|
2 Invocation of Saint Traft|SOI|1
|
||||||
|
2 Iridescent Angel|V15|1
|
||||||
|
1 Island|SOI|1
|
||||||
|
2 Island|SOI|2
|
||||||
|
1 Island|SOI|3
|
||||||
|
2 Migratory Route|KHC|1
|
||||||
|
1 Plains|SOI|1
|
||||||
|
4 Plains|SOI|2
|
||||||
|
7 Plains|SOI|3
|
||||||
|
2 Port Town|WHO|4
|
||||||
|
3 Revitalize|M19|1
|
||||||
|
2 Seraph of Dawn|J21|1
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
Name=badger
|
Name=badger
|
||||||
[Avatar]
|
|
||||||
|
|
||||||
[Main]
|
[Main]
|
||||||
4 Beast Within|DMC|1
|
4 Beast Within|DMC|1
|
||||||
4 Charging Badger|ANB|1
|
4 Charging Badger|ANB|1
|
||||||
@@ -15,13 +13,3 @@ Name=badger
|
|||||||
4 Nimble Mongoose|MB1|1
|
4 Nimble Mongoose|MB1|1
|
||||||
4 Prismatic Vista|MH1|1
|
4 Prismatic Vista|MH1|1
|
||||||
4 Rysorian Badger|HML|1
|
4 Rysorian Badger|HML|1
|
||||||
[Sideboard]
|
|
||||||
|
|
||||||
[Planes]
|
|
||||||
|
|
||||||
[Schemes]
|
|
||||||
|
|
||||||
[Conspiracy]
|
|
||||||
|
|
||||||
[Dungeon]
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
[duel]
|
|
||||||
[metadata]
|
[metadata]
|
||||||
Name=Carnage 2
|
Name=Carnage 2
|
||||||
Title=Carnage
|
|
||||||
Difficulty=medium
|
|
||||||
Description=Mono R Grand Melee deck with Circle of Flame
|
|
||||||
Icon=Carnage.jpg
|
|
||||||
Deck Type=constructed
|
|
||||||
[main]
|
[main]
|
||||||
23 Mountain
|
23 Mountain
|
||||||
4 Grand Melee
|
4 Grand Melee
|
||||||
@@ -32,4 +26,3 @@ Deck Type=constructed
|
|||||||
1 Thran War Machine
|
1 Thran War Machine
|
||||||
1 Ulamog's Crusher
|
1 Ulamog's Crusher
|
||||||
1 Utvara Scalper
|
1 Utvara Scalper
|
||||||
[sideboard]
|
|
||||||
|
|||||||
@@ -1,11 +1,4 @@
|
|||||||
[duel]
|
|
||||||
[metadata]
|
[metadata]
|
||||||
Name=Freddy's Nightmares 2
|
|
||||||
Title=Freddy Krueger
|
|
||||||
Difficulty=medium
|
|
||||||
Description=RB nightmare creature theme with mutate abilities, life drain, and some burn
|
|
||||||
Icon=Freddy Krueger 2.jpg
|
|
||||||
Deck Type=constructed
|
|
||||||
[Main]
|
[Main]
|
||||||
2 Banefire
|
2 Banefire
|
||||||
3 Blood Crypt
|
3 Blood Crypt
|
||||||
|
|||||||
@@ -1,12 +1,5 @@
|
|||||||
[duel]
|
|
||||||
[metadata]
|
[metadata]
|
||||||
Name=Frodo 2
|
Name=Frodo 2
|
||||||
Title=Frodo
|
|
||||||
Difficulty=medium
|
|
||||||
Description=WRG Zoo deck
|
|
||||||
Icon=Frodo.jpg
|
|
||||||
Deck Type=constructed
|
|
||||||
Profile=Reckless
|
|
||||||
[main]
|
[main]
|
||||||
3 Plateau
|
3 Plateau
|
||||||
3 Taiga
|
3 Taiga
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
[duel]
|
|
||||||
[metadata]
|
[metadata]
|
||||||
Name=Cuthbert's Ka-tet 2
|
Name=Cuthbert's Ka-tet 2
|
||||||
Title=Cuthbert Allgood of Roland's Ka-tet
|
|
||||||
Difficulty=medium
|
|
||||||
Description=WGR flicker and direct damage theme deck
|
|
||||||
Icon=Cuthbert Allgood 2.jpg
|
|
||||||
Deck Type=constructed
|
|
||||||
[Main]
|
[Main]
|
||||||
2 Acidic Slime
|
2 Acidic Slime
|
||||||
2 Ajani's Welcome
|
2 Ajani's Welcome
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
[duel]
|
|
||||||
[metadata]
|
[metadata]
|
||||||
Name=Hellboy 2
|
Name=Hellboy 2
|
||||||
Title=Hellboy
|
|
||||||
Difficulty=medium
|
|
||||||
Description=BR direct damage deck
|
|
||||||
Icon=Hellboy.jpg
|
|
||||||
Deck Type=constructed
|
|
||||||
[main]
|
[main]
|
||||||
5 Swamp
|
5 Swamp
|
||||||
7 Mountain
|
7 Mountain
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
[duel]
|
|
||||||
[metadata]
|
[metadata]
|
||||||
Name=Bolas's Infernal Reign 3
|
Name=Bolas's Infernal Reign 3
|
||||||
Title=Nicol Bolas, the Deceiver
|
|
||||||
Difficulty=hard
|
|
||||||
Description=URB dragons, counter, burn, and reanimate theme with Bolas planeswalkers and legends
|
|
||||||
Icon=Nicol Bolas, the Deceiver 3.jpg
|
|
||||||
Deck Type=constructed
|
|
||||||
[Main]
|
[Main]
|
||||||
1 Ancient Brass Dragon
|
1 Ancient Brass Dragon
|
||||||
2 Avatar of Discord
|
2 Avatar of Discord
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
[duel]
|
|
||||||
[metadata]
|
[metadata]
|
||||||
Name=Diablo 3
|
Name=Diablo 3
|
||||||
Title=Diablo
|
|
||||||
Difficulty=hard
|
|
||||||
Description=BR Hellbent deck
|
|
||||||
Icon=Diablo.jpg
|
|
||||||
Deck Type=constructed
|
|
||||||
[main]
|
[main]
|
||||||
4 Badlands
|
4 Badlands
|
||||||
4 Bloodstained Mire
|
4 Bloodstained Mire
|
||||||
|
|||||||
@@ -1,12 +1,5 @@
|
|||||||
[duel]
|
|
||||||
[metadata]
|
[metadata]
|
||||||
Name=Deadpool 2
|
Name=Deadpool 2
|
||||||
Title=Deadpool
|
|
||||||
Difficulty=medium
|
|
||||||
Description=BR deck with Ashenmoor Liege and Grixis Grimblade
|
|
||||||
Icon=Deadpool.jpg
|
|
||||||
Deck Type=constructed
|
|
||||||
Profile=Reckless
|
|
||||||
[main]
|
[main]
|
||||||
2 Vicious Kavu
|
2 Vicious Kavu
|
||||||
2 Ashenmoor Gouger
|
2 Ashenmoor Gouger
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
[duel]
|
|
||||||
[metadata]
|
[metadata]
|
||||||
Name=Abraham Lincoln 2
|
Name=Abraham Lincoln 2
|
||||||
Title=Abraham Lincoln
|
|
||||||
Difficulty=medium
|
|
||||||
Description=WUR flying creatures deck with Flamebreak and Earthquake
|
|
||||||
Icon=Abraham Lincoln.jpg
|
|
||||||
Deck Type=constructed
|
|
||||||
[main]
|
[main]
|
||||||
1 Plateau
|
1 Plateau
|
||||||
1 Flooded Strand
|
1 Flooded Strand
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
[duel]
|
|
||||||
[metadata]
|
[metadata]
|
||||||
Name=Blaine the Pain 2
|
Name=Blaine the Pain 2
|
||||||
Title=Blaine the Pain
|
|
||||||
Difficulty=medium
|
|
||||||
Description=RB vehicles strategic aggro theme deck
|
|
||||||
Icon=Blaine the Pain 2.jpg
|
|
||||||
Deck Type=constructed
|
|
||||||
[Main]
|
[Main]
|
||||||
2 Aradara Express
|
2 Aradara Express
|
||||||
1 Beacon of Unrest
|
1 Beacon of Unrest
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
Name=bandittrapper_hazezon
|
Name=bandittrapper_hazezon
|
||||||
[Avatar]
|
|
||||||
|
|
||||||
[Main]
|
[Main]
|
||||||
2 Ancient Greenwarden|ZNR|1
|
2 Ancient Greenwarden|ZNR|1
|
||||||
2 Argoth, Sanctum of Nature|BRO|1
|
2 Argoth, Sanctum of Nature|BRO|1
|
||||||
@@ -30,13 +28,3 @@ Name=bandittrapper_hazezon
|
|||||||
1 Titania, Voice of Gaea|BRO|1
|
1 Titania, Voice of Gaea|BRO|1
|
||||||
2 Wayward Swordtooth|RIX|1
|
2 Wayward Swordtooth|RIX|1
|
||||||
2 Wooded Foothills|KTK|1
|
2 Wooded Foothills|KTK|1
|
||||||
[Sideboard]
|
|
||||||
|
|
||||||
[Planes]
|
|
||||||
|
|
||||||
[Schemes]
|
|
||||||
|
|
||||||
[Conspiracy]
|
|
||||||
|
|
||||||
[Dungeon]
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
Name=barbarian
|
Name=barbarian
|
||||||
[Avatar]
|
|
||||||
|
|
||||||
[Main]
|
[Main]
|
||||||
4 Balduvian Horde|A25|1
|
4 Balduvian Horde|A25|1
|
||||||
2 Balthor the Stout|TOR|1
|
2 Balthor the Stout|TOR|1
|
||||||
@@ -20,13 +18,3 @@ Name=barbarian
|
|||||||
4 Plundering Barbarian|AFR|1
|
4 Plundering Barbarian|AFR|1
|
||||||
4 Sardian Cliffstomper|BRO|1
|
4 Sardian Cliffstomper|BRO|1
|
||||||
1 Zalto, Fire Giant Duke|AFR|1
|
1 Zalto, Fire Giant Duke|AFR|1
|
||||||
[Sideboard]
|
|
||||||
|
|
||||||
[Planes]
|
|
||||||
|
|
||||||
[Schemes]
|
|
||||||
|
|
||||||
[Conspiracy]
|
|
||||||
|
|
||||||
[Dungeon]
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
[duel]
|
|
||||||
[metadata]
|
[metadata]
|
||||||
Name=Baltrice's Burning Light 3
|
Name=Baltrice's Burning Light 3
|
||||||
Title=Baltrice
|
|
||||||
Difficulty=hard
|
|
||||||
Description=RW burn and lifegain themed deck with Spitemare and Boros Reckoner
|
|
||||||
Icon=Baltrice 3.jpg
|
|
||||||
Deck Type=constructed
|
|
||||||
[Main]
|
[Main]
|
||||||
2 Akroma's Memorial
|
2 Akroma's Memorial
|
||||||
2 Archaeomancer's Map
|
2 Archaeomancer's Map
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
Name=barronlevilain
|
Name=barronlevilain
|
||||||
[Avatar]
|
|
||||||
|
|
||||||
[Main]
|
[Main]
|
||||||
4 Archon of Coronation|CMR|1
|
4 Archon of Coronation|CMR|1
|
||||||
4 Beloved Princess|ELD|1
|
4 Beloved Princess|ELD|1
|
||||||
@@ -23,12 +21,3 @@ Name=barronlevilain
|
|||||||
4 Throne of the High City|CN2|1
|
4 Throne of the High City|CN2|1
|
||||||
4 Throne Warden|PZ2|1
|
4 Throne Warden|PZ2|1
|
||||||
[Sideboard]
|
[Sideboard]
|
||||||
|
|
||||||
[Planes]
|
|
||||||
|
|
||||||
[Schemes]
|
|
||||||
|
|
||||||
[Conspiracy]
|
|
||||||
|
|
||||||
[Dungeon]
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
Name=bat
|
Name=bat
|
||||||
[Avatar]
|
|
||||||
|
|
||||||
[Main]
|
[Main]
|
||||||
4 Basilica Screecher|GTC|1
|
4 Basilica Screecher|GTC|1
|
||||||
4 Blight Keeper|J22|1
|
4 Blight Keeper|J22|1
|
||||||
@@ -15,13 +13,3 @@ Name=bat
|
|||||||
8 Swamp|J22|2
|
8 Swamp|J22|2
|
||||||
10 Swamp|J22|3
|
10 Swamp|J22|3
|
||||||
4 Unholy Strength|30A|1
|
4 Unholy Strength|30A|1
|
||||||
[Sideboard]
|
|
||||||
|
|
||||||
[Planes]
|
|
||||||
|
|
||||||
[Schemes]
|
|
||||||
|
|
||||||
[Conspiracy]
|
|
||||||
|
|
||||||
[Dungeon]
|
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user