mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-15 18:28:00 +00:00
Merge branch 'master' of https://github.com/Card-Forge/forge into adventure
This commit is contained in:
16
README.md
16
README.md
@@ -1,8 +1,8 @@
|
||||
# Forge
|
||||
|
||||
[Official GitLab repo](https://git.cardforge.org/core-developers/forge).
|
||||
[Official repo](https://github.com/Card-Forge/forge.git).
|
||||
|
||||
Dev instructions here: [Getting Started](https://git.cardforge.org/core-developers/forge/-/wikis/(SM-autoconverted)-how-to-get-started-developing-forge) (Somewhat outdated)
|
||||
Dev instructions here: [Getting Started](https://github.com/Card-Forge/forge/wiki) (Somewhat outdated)
|
||||
|
||||
Discord channel [here](https://discord.gg/fWfNgCUNRq)
|
||||
|
||||
@@ -13,14 +13,14 @@ Discord channel [here](https://discord.gg/fWfNgCUNRq)
|
||||
- Git
|
||||
- Git client (optional)
|
||||
- Maven
|
||||
- Gitlab account
|
||||
- GitHub account
|
||||
- Libgdx (optional: familiarity with this library is helpful for mobile platform development)
|
||||
- Android SDK (optional: for Android releases)
|
||||
- RoboVM (optional: for iOS releases) (TBD: Current status of support by libgdx)
|
||||
|
||||
## Project Quick Setup
|
||||
|
||||
- Log in to gitlab with your user account and fork the project.
|
||||
- Login into GitHub with your user account and fork the project.
|
||||
|
||||
- Clone your forked project to your local machine
|
||||
|
||||
@@ -32,13 +32,13 @@ Eclipse includes Maven integration so a separate install is not necessary. For
|
||||
|
||||
### Project Setup
|
||||
|
||||
- Follow the instructions for cloning from Gitlab. You'll need a Gitlab account setup and an SSH key defined.
|
||||
- Follow the instructions for cloning from GitHub. You'll need to setup an account and your SSH key.
|
||||
|
||||
If you are on a Windows machine you can use Putty with TortoiseGit for SSH keys. Run puttygen.exe to generate the key -- save the private key and export
|
||||
the OpenSSH public key. If you just leave the dialog open, you can copy and paste the key from it to your Gitlab profile under
|
||||
"SSH keys". Run pageant.exe and add the private key generated earlier. TortoiseGit will use this for accessing Gitlab.
|
||||
the OpenSSH public key. If you just leave the dialog open, you can copy and paste the key from it to your GitHub profile under
|
||||
"SSH keys". Run pageant.exe and add the private key generated earlier. TortoiseGit will use this for accessing GitHub.
|
||||
|
||||
- Fork the Forge git repo to your Gitlab account.
|
||||
- Fork the Forge git repo to your GitHub account.
|
||||
|
||||
- Clone your forked repo to your local machine.
|
||||
|
||||
|
||||
4
forge-ai/src/test/java/.gitignore
vendored
4
forge-ai/src/test/java/.gitignore
vendored
@@ -1,4 +0,0 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
||||
4
forge-core/src/test/java/.gitignore
vendored
4
forge-core/src/test/java/.gitignore
vendored
@@ -1,4 +0,0 @@
|
||||
# Ignore everything in this directory
|
||||
*
|
||||
# Except this file
|
||||
!.gitignore
|
||||
@@ -22,6 +22,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.*;
|
||||
import forge.game.card.*;
|
||||
import forge.util.Aggregates;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import forge.card.MagicColor;
|
||||
@@ -30,17 +32,10 @@ import forge.card.mana.ManaCostParser;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardCollectionView;
|
||||
import forge.game.card.CardFactoryUtil;
|
||||
import forge.game.card.CardPlayOption;
|
||||
import forge.game.card.CardPlayOption.PayManaCost;
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.cost.Cost;
|
||||
import forge.game.keyword.Keyword;
|
||||
import forge.game.keyword.KeywordInterface;
|
||||
import forge.game.keyword.KeywordsChange;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerCollection;
|
||||
import forge.game.player.PlayerController;
|
||||
@@ -567,7 +562,11 @@ public final class GameActionUtil {
|
||||
if (tr != null) {
|
||||
String n = o.split(":")[1];
|
||||
if (host.wasCast() && n.equals("X")) {
|
||||
n = Integer.toString(pc.announceRequirements(sa, "X for Casualty"));
|
||||
CardCollectionView creatures = CardLists.filter(CardLists.filterControlledBy(game.getCardsIn
|
||||
(ZoneType.Battlefield), activator), CardPredicates.Presets.CREATURES);
|
||||
int max = Aggregates.max(creatures, CardPredicates.Accessors.fnGetNetPower);
|
||||
int min = Aggregates.min(creatures, CardPredicates.Accessors.fnGetNetPower);
|
||||
n = Integer.toString(pc.chooseNumber(sa, "Choose X for Casualty", min, max));
|
||||
}
|
||||
final String casualtyCost = "Sac<1/Creature.powerGE" + n + "/creature with power " + n +
|
||||
" or greater>";
|
||||
@@ -584,6 +583,8 @@ public final class GameActionUtil {
|
||||
result.getPayCosts().add(cost);
|
||||
tr.getOverridingAbility().setSVar("Casualty", n);
|
||||
reset = true;
|
||||
} else {
|
||||
tr.getOverridingAbility().setSVar("Casualty", "0");
|
||||
}
|
||||
}
|
||||
} else if (o.equals("Conspire")) {
|
||||
@@ -721,7 +722,7 @@ public final class GameActionUtil {
|
||||
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
||||
game.getAction().moveTo(ZoneType.Command, eff, null, null);
|
||||
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
||||
|
||||
|
||||
return eff;
|
||||
}
|
||||
|
||||
@@ -820,24 +821,8 @@ public final class GameActionUtil {
|
||||
}
|
||||
|
||||
public static void checkStaticAfterPaying(Card c) {
|
||||
Table<Long, Long, KeywordsChange> oldKW = TreeBasedTable.create((TreeBasedTable<Long, Long, KeywordsChange>) c.getChangedCardKeywords());
|
||||
// this should be the last time checkStaticAbilities is called before SpellCast triggers to
|
||||
// - setup Cascade dependent on high enough X (Imoti)
|
||||
// - remove Replicate if Djinn Illuminatus gets sacrificed as payment
|
||||
// because this will remove the payment SVars for Replicate we need to restore them
|
||||
c.getGame().getAction().checkStaticAbilities(false);
|
||||
|
||||
Table<Long, Long, KeywordsChange> updatedKW = c.getChangedCardKeywords();
|
||||
for (Table.Cell<Long, Long, KeywordsChange> entry : oldKW.cellSet()) {
|
||||
for (KeywordInterface ki : entry.getValue().getKeywords()) {
|
||||
// check if this keyword existed previously
|
||||
if ((ki.getOriginal().startsWith("Replicate") || ki.getOriginal().startsWith("Conspire")
|
||||
|| ki.getOriginal().startsWith("Casualty"))
|
||||
&& updatedKW.get(entry.getRowKey(), entry.getColumnKey()) != null) {
|
||||
updatedKW.put(entry.getRowKey(), entry.getColumnKey(), oldKW.get(entry.getRowKey(), entry.getColumnKey()));
|
||||
}
|
||||
}
|
||||
}
|
||||
c.updateKeywords();
|
||||
|
||||
c.getGame().getTriggerHandler().resetActiveTriggers();
|
||||
|
||||
@@ -252,6 +252,11 @@ public class StaticEffect {
|
||||
affectedCard.removeColor(getTimestamp(), ability.getId());
|
||||
}
|
||||
|
||||
// remove changed name
|
||||
if (hasParam("SetName") || hasParam("AddNames")) {
|
||||
affectedCard.removeChangedName(timestamp, ability.getId());
|
||||
}
|
||||
|
||||
// remove may look at
|
||||
if (hasParam("MayLookAt")) {
|
||||
affectedCard.removeMayLookAt(getTimestamp());
|
||||
|
||||
@@ -1822,6 +1822,12 @@ public class AbilityUtils {
|
||||
return root == null ? 0 : root.getTotalManaSpent();
|
||||
}
|
||||
|
||||
// Count$ManaColorsPaid
|
||||
if (sq[0].equals("ManaColorsPaid")) {
|
||||
final SpellAbility root = sa.getRootAbility();
|
||||
return doXMath(root == null ? 0 : root.getPayingColors().countColors(), expr, c, ctb);
|
||||
}
|
||||
|
||||
// Count$Adamant.<Color>.<True>.<False>
|
||||
if (sq[0].startsWith("Adamant")) {
|
||||
final String payingMana = StringUtils.join(sa.getRootAbility().getPayingMana());
|
||||
@@ -1981,9 +1987,9 @@ public class AbilityUtils {
|
||||
final int lifeTotal = calculateAmount(c, sq[1], ctb);
|
||||
int number = 0;
|
||||
for (final Player opp : player.getOpponents()) {
|
||||
if (opp.getLife() == lifeTotal) {
|
||||
number++;
|
||||
}
|
||||
if (opp.getLife() == lifeTotal) {
|
||||
number++;
|
||||
}
|
||||
}
|
||||
return doXMath(number, expr, c, ctb);
|
||||
}
|
||||
@@ -2828,23 +2834,6 @@ public class AbilityUtils {
|
||||
return doXMath(ColorSet.fromMask(n).countColors(), expr, c, ctb);
|
||||
}
|
||||
|
||||
if (sq[0].startsWith("CreatureType")) {
|
||||
String[] sqparts = l[0].split(" ", 2);
|
||||
final String[] rest = sqparts[1].split(",");
|
||||
|
||||
final CardCollectionView cardsInZones = sqparts[0].length() > 12
|
||||
? game.getCardsIn(ZoneType.listValueOf(sqparts[0].substring(12)))
|
||||
: game.getCardsIn(ZoneType.Battlefield);
|
||||
|
||||
CardCollection cards = CardLists.getValidCards(cardsInZones, rest, player, c, ctb);
|
||||
final Set<String> creatTypes = Sets.newHashSet();
|
||||
|
||||
for (Card card : cards) {
|
||||
Iterables.addAll(creatTypes, card.getType().getCreatureTypes());
|
||||
}
|
||||
return doXMath(creatTypes.size(), expr, c, ctb);
|
||||
}
|
||||
|
||||
// TODO move below to handlePaid
|
||||
if (sq[0].startsWith("SumPower")) {
|
||||
final String[] restrictions = l[0].split("_");
|
||||
|
||||
@@ -165,18 +165,23 @@ public abstract class SpellAbilityEffect {
|
||||
if ("}".equals(t)) { isPlainText = true; continue; }
|
||||
|
||||
if (!isPlainText) {
|
||||
final List<? extends GameObject> objs;
|
||||
if (t.startsWith("p:")) {
|
||||
objs = AbilityUtils.getDefinedPlayers(sa.getHostCard(), t.substring(2), sa);
|
||||
} else if (t.startsWith("s:")) {
|
||||
objs = AbilityUtils.getDefinedSpellAbilities(sa.getHostCard(), t.substring(2), sa);
|
||||
} else if (t.startsWith("c:")) {
|
||||
objs = AbilityUtils.getDefinedCards(sa.getHostCard(), t.substring(2), sa);
|
||||
if (t.startsWith("n:")) { // {n:<SVar> <noun(opt.)>}
|
||||
String parts[] = t.substring(2).split(" ", 2);
|
||||
int n = AbilityUtils.calculateAmount(sa.getHostCard(), parts[0], sa);
|
||||
sb.append(parts.length == 1 ? Lang.getNumeral(n) : Lang.nounWithNumeral(n, parts[1]));
|
||||
} else {
|
||||
objs = AbilityUtils.getDefinedObjects(sa.getHostCard(), t, sa);
|
||||
final List<? extends GameObject> objs;
|
||||
if (t.startsWith("p:")) {
|
||||
objs = AbilityUtils.getDefinedPlayers(sa.getHostCard(), t.substring(2), sa);
|
||||
} else if (t.startsWith("s:")) {
|
||||
objs = AbilityUtils.getDefinedSpellAbilities(sa.getHostCard(), t.substring(2), sa);
|
||||
} else if (t.startsWith("c:")) {
|
||||
objs = AbilityUtils.getDefinedCards(sa.getHostCard(), t.substring(2), sa);
|
||||
} else {
|
||||
objs = AbilityUtils.getDefinedObjects(sa.getHostCard(), t, sa);
|
||||
}
|
||||
sb.append(StringUtils.join(objs, ", "));
|
||||
}
|
||||
|
||||
sb.append(StringUtils.join(objs, ", "));
|
||||
} else {
|
||||
sb.append(t);
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
}
|
||||
final String cardTag = type.contains("card") ? "" : " card";
|
||||
sb.append(Lang.nounWithNumeralExceptOne(num, type + cardTag)).append(", ");
|
||||
if (!sa.hasParam("NoReveal") && !destination.equals("Battlefield")) {
|
||||
if (!sa.hasParam("NoReveal") && ZoneType.smartValueOf(destination).isHidden()) {
|
||||
if (choosers.size() == 1) {
|
||||
sb.append(num > 1 ? "reveals them, " : "reveals it, ");
|
||||
} else {
|
||||
@@ -359,6 +359,8 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
if (destination.equals(ZoneType.Hand)) {
|
||||
if (ZoneType.Graveyard.equals(origin)) {
|
||||
sb.append("Return").append(targetname).append(fromGraveyard).append(" to");
|
||||
} else if (ZoneType.Battlefield.equals(origin)) {
|
||||
sb.append("Return").append(targetname).append(" to");
|
||||
} else {
|
||||
sb.append("Put").append(targetname).append(" in");
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ public class DamageDealEffect extends DamageBaseEffect {
|
||||
break;
|
||||
}
|
||||
}
|
||||
stringBuilder.append(statement);
|
||||
stringBuilder.append(" ").append(statement);
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
@@ -269,6 +269,11 @@ public class ManaEffect extends SpellAbilityEffect {
|
||||
String mana = !sa.hasParam("Amount") || StringUtils.isNumeric(sa.getParam("Amount"))
|
||||
? GameActionUtil.generatedMana(sa) : "mana";
|
||||
sb.append("Add ").append(toManaString(mana)).append(".");
|
||||
if (sa.hasParam("RestrictValid")) {
|
||||
String desc = sa.getDescription();
|
||||
int i = desc.indexOf("Spend this");
|
||||
sb.append(" ").append(desc, i, desc.indexOf(".", i) + 1);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,6 @@ public class PumpAllEffect extends SpellAbilityEffect {
|
||||
|
||||
@Override
|
||||
public void resolve(final SpellAbility sa) {
|
||||
final PlayerCollection tgtPlayers = getTargetPlayers(sa);
|
||||
final List<ZoneType> affectedZones = Lists.newArrayList();
|
||||
final Game game = sa.getActivatingPlayer().getGame();
|
||||
|
||||
@@ -134,6 +133,7 @@ public class PumpAllEffect extends SpellAbilityEffect {
|
||||
if (!sa.usesTargeting() && !sa.hasParam("Defined")) {
|
||||
list = game.getCardsIn(affectedZones);
|
||||
} else {
|
||||
final PlayerCollection tgtPlayers = getTargetPlayers(sa);
|
||||
list = tgtPlayers.getCardsIn(affectedZones);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ import forge.game.player.Player;
|
||||
import forge.game.player.PlayerCollection;
|
||||
import forge.game.replacement.ReplaceMoved;
|
||||
import forge.game.replacement.ReplacementEffect;
|
||||
import forge.game.replacement.ReplacementHandler;
|
||||
import forge.game.replacement.ReplacementResult;
|
||||
import forge.game.replacement.ReplacementType;
|
||||
import forge.game.spellability.*;
|
||||
@@ -60,6 +61,7 @@ import forge.game.staticability.StaticAbilityCantSacrifice;
|
||||
import forge.game.staticability.StaticAbilityCantTarget;
|
||||
import forge.game.staticability.StaticAbilityCantTransform;
|
||||
import forge.game.trigger.Trigger;
|
||||
import forge.game.trigger.TriggerHandler;
|
||||
import forge.game.trigger.TriggerType;
|
||||
import forge.game.zone.Zone;
|
||||
import forge.game.zone.ZoneType;
|
||||
@@ -139,13 +141,22 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
|
||||
private final Table<Long, Long, CardChangedName> changedCardNames = TreeBasedTable.create(); // Layer 3
|
||||
private final Table<Long, Long, KeywordsChange> changedCardKeywordsByText = TreeBasedTable.create(); // Layer 3 by Text Change
|
||||
protected KeywordsChange changedCardKeywordsByWord = new KeywordsChange(ImmutableList.<String>of(), null, false); // Layer 3 by Word Change
|
||||
protected KeywordsChange changedCardKeywordsByWord = new KeywordsChange(ImmutableList.<KeywordInterface>of(), ImmutableList.<KeywordInterface>of(), false); // Layer 3 by Word Change
|
||||
private final Table<Long, Long, KeywordsChange> changedCardKeywords = TreeBasedTable.create(); // Layer 6
|
||||
|
||||
// stores the keywords created by static abilities
|
||||
private final Table<Long, String, KeywordInterface> storedKeywords = TreeBasedTable.create();
|
||||
|
||||
// x=timestamp y=StaticAbility id
|
||||
private final Table<Long, Long, CardTraitChanges> changedCardTraitsByText = TreeBasedTable.create(); // Layer 3 by Text Change
|
||||
private final Table<Long, Long, CardTraitChanges> changedCardTraits = TreeBasedTable.create(); // Layer 6
|
||||
|
||||
// stores the card traits created by static abilities
|
||||
private final Table<StaticAbility, String, SpellAbility> storedSpellAbilility = TreeBasedTable.create();
|
||||
private final Table<StaticAbility, String, Trigger> storedTrigger = TreeBasedTable.create();
|
||||
private final Table<StaticAbility, String, ReplacementEffect> storedReplacementEffect = TreeBasedTable.create();
|
||||
private final Table<StaticAbility, String, StaticAbility> storedStaticAbility = TreeBasedTable.create();
|
||||
|
||||
// x=timestamp y=StaticAbility id
|
||||
private final Table<Long, Long, CardColor> changedCardColorsByText = TreeBasedTable.create(); // Layer 3 by Text Change
|
||||
private final Table<Long, Long, CardColor> changedCardColorsCharacterDefining = TreeBasedTable.create(); // Layer 5 CDA
|
||||
@@ -179,7 +190,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
|
||||
private List<Pair<Card, Integer>> receivedDamageFromThisTurn = Lists.newArrayList();
|
||||
private Map<Player, Integer> receivedDamageFromPlayerThisTurn = Maps.newHashMap();
|
||||
|
||||
|
||||
private final Map<Card, Integer> assignedDamageMap = Maps.newTreeMap();
|
||||
|
||||
private boolean isCommander = false;
|
||||
@@ -3680,7 +3691,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
public Iterable<KeywordsChange> getChangedCardKeywordsList() {
|
||||
return Iterables.concat(
|
||||
changedCardKeywordsByText.values(), // Layer 3
|
||||
ImmutableList.of(new KeywordsChange(ImmutableList.<String>of(), null, this.hasRemoveIntrinsic())), // Layer 4
|
||||
ImmutableList.of(new KeywordsChange(ImmutableList.<KeywordInterface>of(), ImmutableList.<KeywordInterface>of(), this.hasRemoveIntrinsic())), // Layer 4
|
||||
changedCardKeywords.values() // Layer 6
|
||||
);
|
||||
}
|
||||
@@ -4260,6 +4271,45 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
updateAbilityTextForView();
|
||||
}
|
||||
|
||||
public final SpellAbility getSpellAbilityForStaticAbility(final String str, final StaticAbility stAb) {
|
||||
SpellAbility result = storedSpellAbilility.get(stAb, str);
|
||||
if (result == null) {
|
||||
result = AbilityFactory.getAbility(str, this, stAb);
|
||||
result.setIntrinsic(false);
|
||||
result.setGrantorStatic(stAb);
|
||||
storedSpellAbilility.put(stAb, str, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public final Trigger getTriggerForStaticAbility(final String str, final StaticAbility stAb) {
|
||||
Trigger result = storedTrigger.get(stAb, str);
|
||||
if (result == null) {
|
||||
result = TriggerHandler.parseTrigger(str, this, false, stAb);
|
||||
storedTrigger.put(stAb, str, result);
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
public final ReplacementEffect getReplacementEffectForStaticAbility(final String str, final StaticAbility stAb) {
|
||||
ReplacementEffect result = storedReplacementEffect.get(stAb, str);
|
||||
if (result == null) {
|
||||
result = ReplacementHandler.parseReplacement(str, this, false, stAb);
|
||||
storedReplacementEffect.put(stAb, str, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public final StaticAbility getStaticAbilityForStaticAbility(final String str, final StaticAbility stAb) {
|
||||
StaticAbility result = storedStaticAbility.get(stAb, str);
|
||||
if (result == null) {
|
||||
result = StaticAbility.create(str, this, stAb.getCardState(), false);
|
||||
storedStaticAbility.put(stAb, str, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public final void addChangedCardTraits(Collection<SpellAbility> spells, Collection<SpellAbility> removedAbilities,
|
||||
Collection<Trigger> trigger, Collection<ReplacementEffect> replacements, Collection<StaticAbility> statics,
|
||||
boolean removeAll, boolean removeNonMana, long timestamp, long staticId) {
|
||||
@@ -4367,8 +4417,14 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
}
|
||||
public final void addChangedCardKeywords(final List<String> keywords, final List<String> removeKeywords,
|
||||
final boolean removeAllKeywords, final long timestamp, final long staticId, final boolean updateView) {
|
||||
final KeywordsChange newCks = new KeywordsChange(keywords, removeKeywords, removeAllKeywords);
|
||||
newCks.addKeywordsToCard(this);
|
||||
List<KeywordInterface> kws = Lists.newArrayList();
|
||||
if (keywords != null) {
|
||||
for(String kw : keywords) {
|
||||
kws.add(getKeywordForStaticAbility(kw, staticId));
|
||||
}
|
||||
}
|
||||
|
||||
final KeywordsChange newCks = new KeywordsChange(kws, removeKeywords, removeAllKeywords);
|
||||
changedCardKeywords.put(timestamp, staticId, newCks);
|
||||
|
||||
if (updateView) {
|
||||
@@ -4378,10 +4434,24 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
}
|
||||
}
|
||||
|
||||
public final KeywordInterface getKeywordForStaticAbility(String kw, final long staticId) {
|
||||
KeywordInterface result;
|
||||
if (staticId < 1 || !storedKeywords.contains(staticId, kw)) {
|
||||
result = Keyword.getInstance(kw);
|
||||
result.createTraits(this, false);
|
||||
if (staticId > 0) {
|
||||
storedKeywords.put(staticId, kw, result);
|
||||
}
|
||||
} else {
|
||||
result = storedKeywords.get(staticId, kw);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public final void addChangedCardKeywordsByText(final List<KeywordInterface> keywords, final long timestamp, final long staticId, final boolean updateView) {
|
||||
// keywords should already created for Card, so no addKeywordsToCard
|
||||
// this one is done for Volrath's Shapeshifter which replaces all the card text
|
||||
changedCardKeywordsByText.put(timestamp, staticId, new KeywordsChange(keywords, null, true));
|
||||
changedCardKeywordsByText.put(timestamp, staticId, new KeywordsChange(keywords, ImmutableList.<KeywordInterface>of(), true));
|
||||
|
||||
if (updateView) {
|
||||
updateKeywords();
|
||||
@@ -4394,7 +4464,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
final long timestamp, final long staticId, final boolean updateView) {
|
||||
|
||||
final KeywordsChange newCks = new KeywordsChange(keywords, removeKeywords, removeAllKeywords);
|
||||
newCks.addKeywordsToCard(this);
|
||||
changedCardKeywords.put(timestamp, staticId, newCks);
|
||||
|
||||
if (updateView) {
|
||||
|
||||
@@ -202,12 +202,12 @@ public class CardFactory {
|
||||
copySA = getCopiedTriggeredAbility((WrappedAbility)targetSA, c, controller);
|
||||
} else {
|
||||
copySA = targetSA.copy(c, controller, false);
|
||||
c.setCastSA(copySA);
|
||||
}
|
||||
|
||||
copySA.setCopied(true);
|
||||
// 707.10b
|
||||
copySA.setOriginalAbility(targetSA);
|
||||
c.setCastSA(copySA);
|
||||
|
||||
if (targetSA.usesTargeting()) {
|
||||
// do for SubAbilities too?
|
||||
|
||||
@@ -1417,8 +1417,8 @@ public class CardProperty {
|
||||
if (card.getCMC() != source.getChosenNumber()) {
|
||||
return false;
|
||||
}
|
||||
} else if (property.startsWith("power") || property.startsWith("toughness")
|
||||
|| property.startsWith("cmc") || property.startsWith("totalPT")) {
|
||||
} else if (property.startsWith("power") || property.startsWith("toughness") || property.startsWith("cmc")
|
||||
|| property.startsWith("totalPT") || property.startsWith("numColors")) {
|
||||
int x;
|
||||
int y = 0;
|
||||
String rhs = "";
|
||||
@@ -1435,6 +1435,9 @@ public class CardProperty {
|
||||
} else if (property.startsWith("totalPT")) {
|
||||
rhs = property.substring(10);
|
||||
y = card.getNetPower() + card.getNetToughness();
|
||||
} else if (property.startsWith("numColors")) {
|
||||
rhs = property.substring(11);
|
||||
y = card.getColor().countColors();
|
||||
}
|
||||
x = AbilityUtils.calculateAmount(source, rhs, spellAbility);
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ import java.util.List;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.game.card.Card;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.replacement.ReplacementEffect;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.staticability.StaticAbility;
|
||||
@@ -51,11 +50,11 @@ public class KeywordsChange implements Cloneable {
|
||||
* @param removeAll whether to remove all keywords.
|
||||
*/
|
||||
public KeywordsChange(
|
||||
final Iterable<String> keywordList,
|
||||
final Iterable<KeywordInterface> keywordList,
|
||||
final Collection<String> removeKeywordList,
|
||||
final boolean removeAll) {
|
||||
if (keywordList != null) {
|
||||
this.keywords.addAll(keywordList);
|
||||
this.keywords.insertAll(keywordList);
|
||||
}
|
||||
|
||||
if (removeKeywordList != null) {
|
||||
@@ -64,7 +63,6 @@ public class KeywordsChange implements Cloneable {
|
||||
|
||||
this.removeAllKeywords = removeAll;
|
||||
}
|
||||
|
||||
public KeywordsChange(
|
||||
final Collection<KeywordInterface> keywordList,
|
||||
final Collection<KeywordInterface> removeKeywordInterfaces,
|
||||
@@ -122,18 +120,6 @@ public class KeywordsChange implements Cloneable {
|
||||
&& this.removeKeywords.isEmpty();
|
||||
}
|
||||
|
||||
public final void addKeywordsToCard(final Card host) {
|
||||
for (KeywordInterface inst : keywords.getValues()) {
|
||||
inst.createTraits(host, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
public final void addKeywordsToPlayer(final Player player) {
|
||||
for (KeywordInterface inst : keywords.getValues()) {
|
||||
inst.createTraits(player, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void setHostCard(final Card host) {
|
||||
keywords.setHostCard(host);
|
||||
for (KeywordInterface k : removeKeywordInterfaces) {
|
||||
|
||||
@@ -441,9 +441,6 @@ public class PhaseHandler implements java.io.Serializable {
|
||||
|
||||
// Rule 514.3a - state-based actions
|
||||
game.getAction().checkStateEffects(true);
|
||||
|
||||
// done this after check state effects, so it only has effect next check
|
||||
game.getCleanup().executeUntil(getNextTurn());
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -529,6 +526,10 @@ public class PhaseHandler implements java.io.Serializable {
|
||||
// set previous player
|
||||
playerPreviousTurn = this.getPlayerTurn();
|
||||
setPlayerTurn(handleNextTurn());
|
||||
|
||||
// done this after check state effects, so it only has effect next check
|
||||
game.getCleanup().executeUntil(playerTurn);
|
||||
|
||||
// "Trigger" for begin turn to get around a phase skipping
|
||||
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
|
||||
runParams.put(AbilityKey.Player, playerTurn);
|
||||
|
||||
@@ -196,6 +196,8 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
private CardCollection inboundTokens = new CardCollection();
|
||||
|
||||
private KeywordCollection keywords = new KeywordCollection();
|
||||
// stores the keywords created by static abilities
|
||||
private final Table<Long, String, KeywordInterface> storedKeywords = TreeBasedTable.create();
|
||||
|
||||
private Map<Card, DetachedCardEffect> staticAbilities = Maps.newHashMap();
|
||||
|
||||
@@ -991,9 +993,13 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
}
|
||||
// ================ POISON Merged =================================
|
||||
public final void addChangedKeywords(final List<String> addKeywords, final List<String> removeKeywords, final Long timestamp, final long staticId) {
|
||||
// if the key already exists - merge entries
|
||||
KeywordsChange cks = new KeywordsChange(addKeywords, removeKeywords, false);
|
||||
cks.addKeywordsToPlayer(this);
|
||||
List<KeywordInterface> kws = Lists.newArrayList();
|
||||
if (addKeywords != null) {
|
||||
for(String kw : addKeywords) {
|
||||
kws.add(getKeywordForStaticAbility(kw, staticId));
|
||||
}
|
||||
}
|
||||
KeywordsChange cks = new KeywordsChange(kws, removeKeywords, false);
|
||||
if (!cks.getAbilities().isEmpty() || !cks.getTriggers().isEmpty() || !cks.getReplacements().isEmpty() || !cks.getStaticAbilities().isEmpty()) {
|
||||
getKeywordCard().addChangedCardTraits(
|
||||
cks.getAbilities(), null, cks.getTriggers(), cks.getReplacements(), cks.getStaticAbilities(), false, false, timestamp, staticId);
|
||||
@@ -1003,6 +1009,17 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
game.fireEvent(new GameEventPlayerStatsChanged(this, true));
|
||||
}
|
||||
|
||||
public final KeywordInterface getKeywordForStaticAbility(String kw, final long staticId) {
|
||||
KeywordInterface result;
|
||||
if (staticId < 1 || !storedKeywords.contains(staticId, kw)) {
|
||||
result = Keyword.getInstance(kw);
|
||||
result.createTraits(this, false);
|
||||
} else {
|
||||
result = storedKeywords.get(staticId, kw);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public final KeywordsChange removeChangedKeywords(final Long timestamp, final long staticId) {
|
||||
KeywordsChange change = changedKeywords.remove(timestamp, staticId);
|
||||
if (change != null) {
|
||||
@@ -1179,7 +1196,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
public final boolean canDraw() {
|
||||
return canDrawAmount(1);
|
||||
}
|
||||
|
||||
|
||||
public final boolean canDrawAmount(int amount) {
|
||||
return StaticAbilityCantDraw.canDrawThisAmount(this, amount);
|
||||
}
|
||||
|
||||
@@ -142,7 +142,8 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone
|
||||
layers.add(StaticAbilityLayer.CONTROL);
|
||||
}
|
||||
|
||||
if (hasParam("ChangeColorWordsTo") || hasParam("GainTextOf") || hasParam("AddNames")) {
|
||||
if (hasParam("ChangeColorWordsTo") || hasParam("GainTextOf") || hasParam("AddNames") ||
|
||||
hasParam("SetName")) {
|
||||
layers.add(StaticAbilityLayer.TEXT);
|
||||
}
|
||||
|
||||
|
||||
@@ -56,11 +56,9 @@ import forge.game.keyword.Keyword;
|
||||
import forge.game.keyword.KeywordInterface;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.replacement.ReplacementEffect;
|
||||
import forge.game.replacement.ReplacementHandler;
|
||||
import forge.game.spellability.AbilityStatic;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.trigger.Trigger;
|
||||
import forge.game.trigger.TriggerHandler;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.TextUtil;
|
||||
|
||||
@@ -675,6 +673,10 @@ public final class StaticAbilityContinuous {
|
||||
if (stAb.hasParam("AddNames")) { // currently only for AllNonLegendaryCreatureNames
|
||||
affectedCard.addChangedName(null, true, se.getTimestamp(), stAb.getId());
|
||||
}
|
||||
if (stAb.hasParam("SetName")) {
|
||||
affectedCard.addChangedName(stAb.getParam("SetName"), false,
|
||||
se.getTimestamp(), stAb.getId());
|
||||
}
|
||||
|
||||
// Change color words
|
||||
if (params.containsKey("ChangeColorWordsTo")) {
|
||||
@@ -724,8 +726,6 @@ public final class StaticAbilityContinuous {
|
||||
}
|
||||
|
||||
// add keywords
|
||||
// TODO regular keywords currently don't try to use keyword multiplier
|
||||
// (Although nothing uses it at this time)
|
||||
if (addKeywords != null || removeKeywords != null || removeAllAbilities) {
|
||||
List<String> newKeywords = null;
|
||||
if (addKeywords != null) {
|
||||
@@ -806,10 +806,7 @@ public final class StaticAbilityContinuous {
|
||||
abilty = TextUtil.fastReplace(abilty, "ConvertedManaCost", costcmc);
|
||||
}
|
||||
if (abilty.startsWith("AB") || abilty.startsWith("ST")) { // grant the ability
|
||||
final SpellAbility sa = AbilityFactory.getAbility(abilty, affectedCard, stAb);
|
||||
sa.setIntrinsic(false);
|
||||
sa.setGrantorStatic(stAb);
|
||||
addedAbilities.add(sa);
|
||||
addedAbilities.add(affectedCard.getSpellAbilityForStaticAbility(abilty, stAb));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -855,15 +852,14 @@ public final class StaticAbilityContinuous {
|
||||
// add Replacement effects
|
||||
if (addReplacements != null) {
|
||||
for (String rep : addReplacements) {
|
||||
final ReplacementEffect actualRep = ReplacementHandler.parseReplacement(rep, affectedCard, false, stAb);
|
||||
addedReplacementEffects.add(actualRep);
|
||||
addedReplacementEffects.add(affectedCard.getReplacementEffectForStaticAbility(rep, stAb));
|
||||
}
|
||||
}
|
||||
|
||||
// add triggers
|
||||
if (addTriggers != null) {
|
||||
for (final String trigger : addTriggers) {
|
||||
final Trigger actualTrigger = TriggerHandler.parseTrigger(trigger, affectedCard, false, stAb);
|
||||
final Trigger actualTrigger = affectedCard.getTriggerForStaticAbility(trigger, stAb);
|
||||
// if the trigger has Execute param, which most trigger gained by Static Abilties should have
|
||||
// turn them into SpellAbility object before adding to card
|
||||
// with that the TargetedCard does not need the Svars added to them anymore
|
||||
@@ -888,7 +884,7 @@ public final class StaticAbilityContinuous {
|
||||
s = TextUtil.fastReplace(s, "ConvertedManaCost", costcmc);
|
||||
}
|
||||
|
||||
addedStaticAbility.add(StaticAbility.create(s, affectedCard, stAb.getCardState(), false));
|
||||
addedStaticAbility.add(affectedCard.getStaticAbilityForStaticAbility(s, stAb));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -937,7 +933,7 @@ public final class StaticAbilityContinuous {
|
||||
|
||||
if (controllerMayPlay && (mayPlayLimit == null || stAb.getMayPlayTurn() < mayPlayLimit)) {
|
||||
String mayPlayAltCost = mayPlayAltManaCost;
|
||||
boolean additional = mayPlayAltCost.contains("RegularCost");
|
||||
boolean additional = mayPlayAltCost != null && mayPlayAltCost.contains("RegularCost");
|
||||
|
||||
if (mayPlayAltCost != null) {
|
||||
if (mayPlayAltCost.contains("ConvertedManaCost")) {
|
||||
|
||||
@@ -2,8 +2,11 @@ package forge;
|
||||
|
||||
import java.awt.Desktop;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.datatransfer.StringSelection;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -334,4 +337,18 @@ public class GuiDesktop implements IGuiBase {
|
||||
public void preventSystemSleep(boolean preventSleep) {
|
||||
OperatingSystem.preventSystemSleep(preventSleep);
|
||||
}
|
||||
|
||||
private static float initializeScreenScale() {
|
||||
GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
|
||||
AffineTransform at = gc.getDefaultTransform();
|
||||
double scaleX = at.getScaleX();
|
||||
double scaleY = at.getScaleY();
|
||||
return (float) Math.min(scaleX, scaleY);
|
||||
}
|
||||
static float screenScale = initializeScreenScale();
|
||||
|
||||
@Override
|
||||
public float getScreenScale() {
|
||||
return screenScale;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ import forge.game.card.Card;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.player.PlayerView;
|
||||
import forge.gui.FThreads;
|
||||
import forge.gui.GuiBase;
|
||||
import forge.item.IPaperCard;
|
||||
import forge.item.InventoryItem;
|
||||
import forge.item.PaperCard;
|
||||
@@ -259,7 +260,8 @@ public class ImageCache {
|
||||
// as otherwise it's problematic to update if the real image gets fetched.
|
||||
if (original == null || useArtCrop) {
|
||||
if ((ipc != null || cardView != null) && !originalKey.equals(ImageKeys.getTokenKey(ImageKeys.HIDDEN_CARD))) {
|
||||
int width = 488, height = 680;
|
||||
float screenScale = GuiBase.getInterface().getScreenScale();
|
||||
int width = Math.round(488 * screenScale), height = Math.round(680 * screenScale);
|
||||
BufferedImage art = original;
|
||||
CardView card = ipc != null ? Card.getCardForUi(ipc).getView() : cardView;
|
||||
String legalString = null;
|
||||
|
||||
@@ -8,6 +8,7 @@ import javax.swing.JPanel;
|
||||
|
||||
import com.google.common.base.Predicates;
|
||||
|
||||
import forge.gui.GuiBase;
|
||||
import forge.gui.UiCommand;
|
||||
import forge.item.InventoryItem;
|
||||
import forge.item.ItemPredicate;
|
||||
@@ -43,7 +44,8 @@ public abstract class StatTypeFilter<T extends InventoryItem> extends ToggleButt
|
||||
}
|
||||
tooltip.append(")");
|
||||
|
||||
final FLabel button = addToggleButton(widget, FSkin.getImage(st.skinProp, 18, 18), tooltip.toString());
|
||||
int imageSize = Math.round(18 * GuiBase.getInterface().getScreenScale());
|
||||
final FLabel button = addToggleButton(widget, FSkin.getImage(st.skinProp, imageSize, imageSize), tooltip.toString());
|
||||
buttonMap.put(st, button);
|
||||
|
||||
//hook so right-clicking a button toggles itself on and toggles off all other buttons
|
||||
|
||||
@@ -7,6 +7,7 @@ import forge.deck.io.DeckPreferences;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardView;
|
||||
import forge.gamemodes.limited.CardRanker;
|
||||
import forge.gui.GuiBase;
|
||||
import forge.gui.framework.ILocalRepaint;
|
||||
import forge.item.IPaperCard;
|
||||
import forge.item.InventoryItem;
|
||||
@@ -1164,10 +1165,17 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
||||
g.setColor(Color.black);
|
||||
g.fillRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, cornerSize, cornerSize);
|
||||
|
||||
BufferedImage img = ImageCache.getImage(item, bounds.width - 2 * borderSize, bounds.height - 2 * borderSize, itemInfo.alt);
|
||||
final float screenScale = GuiBase.getInterface().getScreenScale();
|
||||
final int drawX = bounds.x + borderSize;
|
||||
final int drawY = bounds.y + borderSize;
|
||||
final int drawWidth = bounds.width - 2 * borderSize;
|
||||
final int drawHeight = bounds.height - 2 * borderSize;
|
||||
final int imageWidth = Math.round(drawWidth * screenScale);
|
||||
final int imageHeight = Math.round(drawHeight * screenScale);
|
||||
BufferedImage img = ImageCache.getImage(item, imageWidth, imageHeight, itemInfo.alt);
|
||||
|
||||
if (img != null) {
|
||||
g.drawImage(img, null, bounds.x + borderSize, bounds.y + borderSize);
|
||||
g.drawImage(img, drawX, drawY, drawX + drawWidth, drawY + drawHeight, 0, 0, imageWidth, imageHeight, null);
|
||||
}
|
||||
else {
|
||||
if (deckSelectMode) {
|
||||
|
||||
@@ -43,6 +43,7 @@ import forge.deck.CardPool;
|
||||
import forge.deck.Deck;
|
||||
import forge.deck.DeckProxy;
|
||||
import forge.deck.DeckgenUtil;
|
||||
import forge.gui.GuiBase;
|
||||
import forge.gui.UiCommand;
|
||||
import forge.item.PaperCard;
|
||||
import forge.localinstance.skin.FSkinProp;
|
||||
@@ -436,12 +437,15 @@ public class AddBasicLandsDialog {
|
||||
|
||||
final Graphics2D g2d = (Graphics2D) g;
|
||||
|
||||
int width = getWidth();
|
||||
int height = getHeight();
|
||||
final float screenScale = GuiBase.getInterface().getScreenScale();
|
||||
final int drawWidth = getWidth();
|
||||
final int drawHeight = getHeight();
|
||||
final int imageWidth = Math.round(drawWidth * screenScale);
|
||||
final int imageHeight = Math.round(drawHeight * screenScale);
|
||||
|
||||
final BufferedImage img = ImageCache.getImage(card, width, height);
|
||||
final BufferedImage img = ImageCache.getImage(card, imageWidth, imageHeight);
|
||||
if (img != null) {
|
||||
g2d.drawImage(img, null, (width - img.getWidth()) / 2, (height - img.getHeight()) / 2);
|
||||
g2d.drawImage(img, 0, 0, drawWidth, drawHeight, 0, 0, imageWidth, imageHeight, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import forge.deck.DeckBase;
|
||||
import forge.deck.DeckFormat;
|
||||
import forge.deck.DeckSection;
|
||||
import forge.game.GameType;
|
||||
import forge.gui.GuiBase;
|
||||
import forge.gui.GuiChoose;
|
||||
import forge.gui.GuiUtils;
|
||||
import forge.gui.UiCommand;
|
||||
@@ -126,7 +127,9 @@ public abstract class ACEditorBase<TItem extends InventoryItem, TModel extends D
|
||||
.fontSize(14)
|
||||
.text(localizer.getMessage("lblAddBasicLands"))
|
||||
.tooltip(localizer.getMessage("ttAddBasicLands"))
|
||||
.icon(FSkin.getImage(FSkinProp.IMG_LAND, 18, 18))
|
||||
.icon(FSkin.getImage(FSkinProp.IMG_LAND,
|
||||
Math.round(18 * GuiBase.getInterface().getScreenScale()),
|
||||
Math.round(18 * GuiBase.getInterface().getScreenScale())))
|
||||
.iconScaleAuto(false).hoverable().build();
|
||||
|
||||
protected ACEditorBase(final FScreen screen0, final CDetailPicture cDetailPicture0, final GameType gameType0) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import forge.gui.framework.DragCell;
|
||||
import forge.gui.framework.DragTab;
|
||||
import forge.gui.framework.EDocID;
|
||||
import forge.gui.framework.IVDoc;
|
||||
import forge.gui.GuiBase;
|
||||
import forge.itemmanager.SItemManagerUtil.StatTypes;
|
||||
import forge.screens.deckeditor.controllers.CStatistics;
|
||||
import forge.toolbox.FLabel;
|
||||
@@ -309,6 +310,7 @@ public enum VStatistics implements IVDoc<CStatistics> {
|
||||
}
|
||||
|
||||
private static FLabel buildLabel(final StatTypes statType, final boolean zebra) {
|
||||
return buildLabel(FSkin.getImage(statType.skinProp, 18, 18), zebra);
|
||||
int imageSize = Math.round(18 * GuiBase.getInterface().getScreenScale());
|
||||
return buildLabel(FSkin.getImage(statType.skinProp, imageSize, imageSize), zebra);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.esotericsoftware.minlog.Log;
|
||||
import forge.card.ColorSet;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.card.mana.ManaCostShard;
|
||||
import forge.gui.GuiBase;
|
||||
import forge.localinstance.skin.FSkinProp;
|
||||
import forge.toolbox.FSkin.SkinImage;
|
||||
|
||||
@@ -295,13 +296,23 @@ public class CardFaceSymbols {
|
||||
FSkin.drawImage(g, MANA_IMAGES.get(imageName), x, y);
|
||||
}
|
||||
public static void drawManaSymbol(final String imageName, final Graphics g, final int x, final int y) {
|
||||
FSkin.drawImage(g, MANA_IMAGES.get(imageName).resize(manaImageSize, manaImageSize), x, y);
|
||||
drawSymbol(imageName, g, x, y, manaImageSize);
|
||||
}
|
||||
public static void drawSymbol(final String imageName, final Graphics g, final int x, final int y, final int size) {
|
||||
FSkin.drawImage(g, MANA_IMAGES.get(imageName).resize(size, size), x, y);
|
||||
// Obtain screen DPI scale
|
||||
float screenScale = GuiBase.getInterface().getScreenScale();
|
||||
int imageSize = Math.round(size * screenScale);
|
||||
|
||||
FSkin.drawImage(g, MANA_IMAGES.get(imageName).resize(imageSize, imageSize),
|
||||
x, y, x + size, y + size, 0, 0, imageSize, imageSize);
|
||||
}
|
||||
public static void drawWatermark(final String imageName, final Graphics g, final int x, final int y, final int size) {
|
||||
FSkin.drawImage(g, WATERMARKS.get(imageName).resize(size, size), x, y);
|
||||
// Obtain screen DPI scale
|
||||
float screenScale = GuiBase.getInterface().getScreenScale();
|
||||
int imageSize = Math.round(size * screenScale);
|
||||
|
||||
FSkin.drawImage(g, WATERMARKS.get(imageName).resize(imageSize, imageSize),
|
||||
x, y, x + size, y + size, 0, 0, imageSize, imageSize);
|
||||
}
|
||||
public static void drawAbilitySymbol(final String imageName, final Graphics g, final int x, final int y, final int w, final int h) {
|
||||
FSkin.drawImage(g, MANA_IMAGES.get(imageName), x, y, w, h);
|
||||
|
||||
@@ -39,6 +39,7 @@ import java.awt.Window;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.image.BaseMultiResolutionImage;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -103,6 +104,7 @@ import javax.swing.text.JTextComponent;
|
||||
|
||||
import forge.Singletons;
|
||||
import forge.gui.FThreads;
|
||||
import forge.gui.GuiBase;
|
||||
import forge.gui.GuiUtils;
|
||||
import forge.gui.framework.ILocalRepaint;
|
||||
import forge.localinstance.properties.ForgeConstants;
|
||||
@@ -688,7 +690,14 @@ public class FSkin {
|
||||
|
||||
protected ImageIcon getIcon() {
|
||||
if (this.imageIcon == null) {
|
||||
this.imageIcon = new ImageIcon(this.image);
|
||||
float screenScale = GuiBase.getInterface().getScreenScale();
|
||||
int iconWidth = Math.round(image.getWidth(null) / screenScale);
|
||||
int iconHeight = Math.round(image.getHeight(null) / screenScale);
|
||||
Image [] iconImages = new Image[2];
|
||||
iconImages[0] = image.getScaledInstance(iconWidth, iconHeight, Image.SCALE_SMOOTH);
|
||||
iconImages[1] = image;
|
||||
BaseMultiResolutionImage multiImage = new BaseMultiResolutionImage(iconImages);
|
||||
this.imageIcon = new ImageIcon(multiImage);
|
||||
}
|
||||
return this.imageIcon;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import forge.card.CardRarity;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.game.card.CardView;
|
||||
import forge.game.card.CardView.CardStateView;
|
||||
import forge.gui.GuiBase;
|
||||
import forge.gui.card.CardDetailUtil;
|
||||
import forge.gui.card.CardDetailUtil.DetailColors;
|
||||
import forge.localinstance.properties.ForgePreferences.FPref;
|
||||
@@ -82,12 +83,15 @@ public class FCardImageRenderer {
|
||||
PT_FONT = NAME_FONT;
|
||||
ARTIST_FONT = new Font(Font.SERIF, Font.BOLD, 20);
|
||||
|
||||
float screenScale = GuiBase.getInterface().getScreenScale();
|
||||
int arrayMultiplier = Math.round(2 * screenScale);
|
||||
|
||||
cachedFonts = new HashMap<>();
|
||||
cachedFonts.put(NAME_FONT, new Font[NAME_FONT.getSize() * 2]);
|
||||
cachedFonts.put(TYPE_FONT, new Font[TYPE_FONT.getSize() * 2]);
|
||||
cachedFonts.put(TEXT_FONT, new Font[TEXT_FONT.getSize() * 2]);
|
||||
cachedFonts.put(REMINDER_FONT, new Font[REMINDER_FONT.getSize() * 2]);
|
||||
cachedFonts.put(ARTIST_FONT, new Font[ARTIST_FONT.getSize() * 2]);
|
||||
cachedFonts.put(NAME_FONT, new Font[NAME_FONT.getSize() * arrayMultiplier]);
|
||||
cachedFonts.put(TYPE_FONT, new Font[TYPE_FONT.getSize() * arrayMultiplier]);
|
||||
cachedFonts.put(TEXT_FONT, new Font[TEXT_FONT.getSize() * arrayMultiplier]);
|
||||
cachedFonts.put(REMINDER_FONT, new Font[REMINDER_FONT.getSize() * arrayMultiplier]);
|
||||
cachedFonts.put(ARTIST_FONT, new Font[ARTIST_FONT.getSize() * arrayMultiplier]);
|
||||
|
||||
isInitialed = true;
|
||||
}
|
||||
@@ -620,10 +624,12 @@ public class FCardImageRenderer {
|
||||
float halfWidth = w / 2;
|
||||
GradientPaint gradient1 = new GradientPaint(x, y, colors[0], x + halfWidth, y, colors[1]);
|
||||
g.setPaint(gradient1);
|
||||
g.fillRoundRect(Math.round(x), Math.round(y), Math.round(halfWidth + arcWidth), Math.round(h), Math.round(arcWidth), Math.round(arcHeight));
|
||||
g.fillRoundRect(Math.round(x), Math.round(y), Math.round(halfWidth), Math.round(h), Math.round(arcWidth), Math.round(arcHeight));
|
||||
g.fillRect(Math.round(x + halfWidth - arcWidth), Math.round(y), Math.round(arcWidth), Math.round(h));
|
||||
GradientPaint gradient2 = new GradientPaint(x + halfWidth, y, colors[1], x + w, y, colors[2]);
|
||||
g.setPaint(gradient2);
|
||||
g.fillRoundRect(Math.round(x + halfWidth - arcWidth), Math.round(y), Math.round(halfWidth + arcWidth), Math.round(h), Math.round(arcWidth), Math.round(arcHeight));
|
||||
g.fillRoundRect(Math.round(x + halfWidth), Math.round(y), Math.round(halfWidth), Math.round(h), Math.round(arcWidth), Math.round(arcHeight));
|
||||
g.fillRect(Math.round(x + halfWidth), Math.round(y), Math.round(arcWidth), Math.round(h));
|
||||
break;
|
||||
}
|
||||
g.setPaint(oldPaint);
|
||||
|
||||
@@ -33,6 +33,8 @@ import javax.swing.Timer;
|
||||
import com.mortennobel.imagescaling.DimensionConstrain;
|
||||
import com.mortennobel.imagescaling.ResampleOp;
|
||||
|
||||
import forge.gui.GuiBase;
|
||||
|
||||
/**
|
||||
* Displays a {@code BufferedImage} at its center.
|
||||
* <p>
|
||||
@@ -295,8 +297,11 @@ public class FImagePanel extends JPanel {
|
||||
at.rotate(Math.toRadians(degreesOfRotation));
|
||||
|
||||
// 2. scale image.
|
||||
float screenScale = GuiBase.getInterface().getScreenScale();
|
||||
if (createScaleTransform) {
|
||||
at.scale(this.imageScale, this.imageScale);
|
||||
at.scale(this.imageScale / screenScale, this.imageScale / screenScale);
|
||||
} else {
|
||||
at.scale(1 / screenScale, 1 / screenScale);
|
||||
}
|
||||
|
||||
// 1. move the image so that its center is at (0,0).
|
||||
@@ -334,6 +339,8 @@ public class FImagePanel extends JPanel {
|
||||
if (this.sourceImage != null) {
|
||||
if (this.autoSizeMode != AutoSizeImageMode.OFF) {
|
||||
Double newScale = FImageUtil.getBestFitScale(getSourceImageSize(), this.getSize());
|
||||
// apply DPI based scale
|
||||
newScale *= GuiBase.getInterface().getScreenScale();
|
||||
if (newScale != this.imageScale) {
|
||||
isResampleEnabled = true;
|
||||
this.imageScale = newScale;
|
||||
|
||||
@@ -56,6 +56,7 @@ import forge.game.keyword.Keyword;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.gui.CardContainer;
|
||||
import forge.gui.FThreads;
|
||||
import forge.gui.GuiBase;
|
||||
import forge.item.PaperCard;
|
||||
import forge.localinstance.properties.ForgeConstants;
|
||||
import forge.localinstance.properties.ForgeConstants.CounterDisplayType;
|
||||
@@ -215,7 +216,11 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl
|
||||
return;
|
||||
}
|
||||
|
||||
cachedImage = new CachedCardImage(card, matchUI.getLocalPlayers(), imagePanel.getWidth(), imagePanel.getHeight()) {
|
||||
// Obtain screen DPI scale and apply them
|
||||
final float screenScale = GuiBase.getInterface().getScreenScale();
|
||||
int imageWidth = Math.round(imagePanel.getWidth() * screenScale);
|
||||
int imageHeight = Math.round(imagePanel.getHeight() * screenScale);
|
||||
cachedImage = new CachedCardImage(card, matchUI.getLocalPlayers(), imageWidth, imageHeight) {
|
||||
@Override
|
||||
public void onImageFetched() {
|
||||
if (cachedImage != null) {
|
||||
|
||||
@@ -23,6 +23,8 @@ import java.awt.image.BufferedImage;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import forge.gui.GuiBase;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* ScaledImagePanel class.
|
||||
@@ -107,24 +109,25 @@ public class ScaledImagePanel extends JPanel {
|
||||
//ResampleOp resizer = new ResampleOp(DimensionConstrain.createMaxDimension(this.getWidth(), this.getHeight(), !scaleLarger));
|
||||
//resizer.setUnsharpenMask(UnsharpenMask.Soft);
|
||||
BufferedImage img = getSrcImage(); //resizer.filter(getSrcImage(), null);
|
||||
float screenScale = GuiBase.getInterface().getScreenScale();
|
||||
|
||||
boolean needsScale = img.getWidth() < sz.width;
|
||||
float scaleFactor = ((float)img.getWidth()) / sz.width;
|
||||
if (needsScale && ( scaleFactor < 0.95 || scaleFactor > 1.05 )) { // This should very low-quality scaling to draw during animation
|
||||
float maxZoomX = ((float)sz.width) / img.getWidth();
|
||||
float maxZoomY = ((float)sz.height) / img.getHeight();
|
||||
boolean needsScale = Math.round(img.getWidth() / screenScale) < sz.width;
|
||||
float scaleFactor = ((float)img.getWidth() / screenScale) / sz.width;
|
||||
if (needsScale && ( scaleFactor < 0.95 || scaleFactor > 1.05 )) { // This should very low-quality scaling to draw during animation
|
||||
float maxZoomX = ((float)sz.width) / (img.getWidth() / screenScale);
|
||||
float maxZoomY = ((float)sz.height) / (img.getHeight() / screenScale);
|
||||
float zoom = Math.min(maxZoomX, maxZoomY);
|
||||
|
||||
int zoomedWidth = (int) (img.getWidth() * zoom);
|
||||
int zoomedHeight = (int) (img.getHeight() * zoom);
|
||||
int zoomedWidth = (int) (img.getWidth() / screenScale * zoom);
|
||||
int zoomedHeight = (int) (img.getHeight() / screenScale * zoom);
|
||||
int x = (sz.width - zoomedWidth) / 2;
|
||||
int y = (sz.height - zoomedHeight) / 2;
|
||||
|
||||
g.drawImage(img, x, y, zoomedWidth, zoomedHeight, null);
|
||||
} else {
|
||||
int x = (sz.width / 2) - (img.getWidth() / 2);
|
||||
int y = (sz.height / 2) - (img.getHeight() / 2);
|
||||
g.drawImage(img, x, y, null);
|
||||
g.drawImage(img, x, y, x + zoomedWidth, y + zoomedHeight, 0, 0, img.getWidth(), img.getHeight(), null);
|
||||
} else {
|
||||
int x = Math.round((sz.width / 2) - (img.getWidth() / screenScale / 2));
|
||||
int y = Math.round((sz.height / 2) - (img.getHeight() / screenScale / 2));
|
||||
g.drawImage(img, x, y, x + sz.width, y + sz.height, 0, 0, img.getWidth(), img.getHeight(), null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -322,4 +322,9 @@ public class GuiMobile implements IGuiBase {
|
||||
public void preventSystemSleep(boolean preventSleep) {
|
||||
Forge.getDeviceAdapter().preventSystemSleep(preventSleep);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getScreenScale() {
|
||||
return 1f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,9 @@ public class DialogData {
|
||||
public EffectData[] effect; //List of effects to cause when the dialog shows.
|
||||
public ConditionData[] condition; //List of conditions for the action to show.
|
||||
public String name; //Text to display when action is listed as a button.
|
||||
public String locname; //References a localized string for the button labels.
|
||||
public String text; //The text body.
|
||||
public String loctext; //References a localized string.
|
||||
public String loctext; //References a localized string for the text body.
|
||||
public DialogData[] options; //
|
||||
|
||||
static public class EffectData {
|
||||
|
||||
@@ -144,8 +144,12 @@ public class GameHUD extends Stage {
|
||||
|
||||
float x=(c.x-miniMap.getX())/miniMap.getWidth();
|
||||
float y=(c.y-miniMap.getY())/miniMap.getHeight();
|
||||
float mMapX = ui.findActor("map").getX();
|
||||
float mMapY = ui.findActor("map").getY();
|
||||
float mMapT = ui.findActor("map").getTop();
|
||||
float mMapR = ui.findActor("map").getRight();
|
||||
//map bounds
|
||||
if (Controls.actorContainsVector(miniMap,c)) {
|
||||
if (c.x>=mMapX&&c.x<=mMapR&&c.y>=mMapY&&c.y<=mMapT) {
|
||||
touchpad.setVisible(false);
|
||||
if (MapStage.getInstance().isInMap())
|
||||
return true;
|
||||
@@ -158,7 +162,12 @@ public class GameHUD extends Stage {
|
||||
|
||||
@Override
|
||||
public boolean touchDown(int screenX, int screenY, int pointer, int button)
|
||||
{Vector2 c=new Vector2();
|
||||
{
|
||||
return setPosition(screenX, screenY, pointer, button);
|
||||
}
|
||||
|
||||
boolean setPosition(int screenX, int screenY, int pointer, int button) {
|
||||
Vector2 c=new Vector2();
|
||||
Vector2 touch =new Vector2();
|
||||
screenToStageCoordinates(touch.set(screenX, screenY));
|
||||
screenToStageCoordinates(c.set(screenX, screenY));
|
||||
@@ -167,32 +176,46 @@ public class GameHUD extends Stage {
|
||||
float y=(c.y-miniMap.getY())/miniMap.getHeight();
|
||||
|
||||
|
||||
float uiX = gamehud.getX();
|
||||
float uiY = gamehud.getY();
|
||||
float uiTop = gamehud.getTop();
|
||||
float uiRight = gamehud.getRight();
|
||||
//gamehud bounds
|
||||
if (c.x>=uiX&&c.x<=uiRight&&c.y>=uiY&&c.y<=uiTop) {
|
||||
super.touchDown(screenX, screenY, pointer, button);
|
||||
return true;
|
||||
}
|
||||
|
||||
float mMapX = miniMap.getX();
|
||||
float mMapY = miniMap.getY();
|
||||
float mMapT = miniMap.getTop();
|
||||
float mMapR = miniMap.getRight();
|
||||
//map bounds
|
||||
if (Controls.actorContainsVector(miniMap,c)) {
|
||||
if (c.x>=mMapX&&c.x<=mMapR&&c.y>=mMapY&&c.y<=mMapT) {
|
||||
if (MapStage.getInstance().isInMap())
|
||||
return true;
|
||||
if(Current.isInDebug())
|
||||
WorldStage.getInstance().GetPlayer().setPosition(x*WorldSave.getCurrentSave().getWorld().getWidthInPixels(),y*WorldSave.getCurrentSave().getWorld().getHeightInPixels());
|
||||
return true;
|
||||
}
|
||||
//gamehud bounds
|
||||
for(Actor child:ui.getChildren())
|
||||
{
|
||||
if(child==touchpad)
|
||||
continue;
|
||||
if (Controls.actorContainsVector(child,c)) {
|
||||
super.touchDown(screenX, screenY, pointer, button);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//display bounds
|
||||
float displayX = ui.getX();
|
||||
float displayY = ui.getY();
|
||||
float displayT = ui.getTop();
|
||||
float displayR = ui.getRight();
|
||||
//menu Y bounds
|
||||
float menuY = menuActor.getY();
|
||||
//auto follow touchpad
|
||||
if (GuiBase.isAndroid()) {
|
||||
if ( (Controls.actorContainsVector(ui,touch)) //inside display bounds
|
||||
if (!(touch.x>=mMapX&&touch.x<=mMapR&&touch.y>=mMapY&&touch.y<=mMapT) // not inside map bounds
|
||||
&& !(touch.x>=uiX&&touch.x<=uiRight&&touch.y>=menuY&&touch.y<=uiTop) //not inside gamehud bounds and menu Y bounds
|
||||
&& (touch.x>=displayX&&touch.x<=displayR&&touch.y>=displayY&&touch.y<=displayT) //inside display bounds
|
||||
&& pointer < 1) { //not more than 1 pointer
|
||||
touchpad.setBounds(touch.x-TOUCHPAD_SCALE/2, touch.y-TOUCHPAD_SCALE/2, TOUCHPAD_SCALE, TOUCHPAD_SCALE);
|
||||
touchpad.setVisible(true);
|
||||
touchpad.setResetOnTouchUp(true);
|
||||
if (!Forge.isLandscapeMode())
|
||||
hideButtons();
|
||||
return super.touchDown(screenX, screenY, pointer, button);
|
||||
}
|
||||
}
|
||||
@@ -268,6 +291,20 @@ public class GameHUD extends Stage {
|
||||
|
||||
return true;
|
||||
}
|
||||
if (keycode == Input.Keys.BACK) {
|
||||
if (!Forge.isLandscapeMode()) {
|
||||
menuActor.setVisible(!menuActor.isVisible());
|
||||
statsActor.setVisible(!statsActor.isVisible());
|
||||
inventoryActor.setVisible(!inventoryActor.isVisible());
|
||||
deckActor.setVisible(!deckActor.isVisible());
|
||||
}
|
||||
}
|
||||
return super.keyDown(keycode);
|
||||
}
|
||||
public void hideButtons() {
|
||||
menuActor.setVisible(false);
|
||||
deckActor.setVisible(false);
|
||||
inventoryActor.setVisible(false);
|
||||
statsActor.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
package forge.adventure.util;
|
||||
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
|
||||
import com.badlogic.gdx.math.Rectangle;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.scenes.scene2d.Actor;
|
||||
@@ -126,26 +123,14 @@ public class Controls {
|
||||
FileHandle atlasFile = skinFile.sibling(skinFile.nameWithoutExtension() + ".atlas");
|
||||
TextureAtlas atlas = new TextureAtlas(atlasFile);
|
||||
//font
|
||||
FreeTypeFontGenerator generateFonts=new FreeTypeFontGenerator(Config.instance().getFile(Paths.SKIN_FONT));
|
||||
FreeTypeFontGenerator.FreeTypeFontParameter parameter = new FreeTypeFontGenerator.FreeTypeFontParameter();
|
||||
parameter.borderWidth=0;
|
||||
parameter.incremental = true;
|
||||
parameter.mono=true;
|
||||
parameter.size=11;
|
||||
parameter.minFilter = Texture.TextureFilter.Nearest;
|
||||
parameter.magFilter = Texture.TextureFilter.Nearest;
|
||||
parameter.color= Color.WHITE;
|
||||
|
||||
defaultfont = generateFonts.generateFont(parameter);
|
||||
|
||||
|
||||
parameter.size=22;
|
||||
parameter.color= Color.WHITE;
|
||||
bigfont = generateFonts.generateFont(parameter);
|
||||
SelectedSkin.add("default",defaultfont);
|
||||
SelectedSkin.add("big",bigfont);
|
||||
defaultfont = new BitmapFont(Config.instance().getFile(Paths.SKIN).sibling("LanaPixel.fnt"));
|
||||
bigfont = new BitmapFont(Config.instance().getFile(Paths.SKIN).sibling("LanaPixel.fnt"));
|
||||
bigfont.getData().setScale(2, 2);
|
||||
SelectedSkin.add("default", defaultfont);
|
||||
SelectedSkin.add("big", bigfont);
|
||||
SelectedSkin.addRegions(atlas);
|
||||
SelectedSkin.load(skinFile);
|
||||
|
||||
}
|
||||
return SelectedSkin;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package forge.adventure.util;
|
||||
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.*;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.Json;
|
||||
import com.badlogic.gdx.utils.SerializationException;
|
||||
import forge.Forge;
|
||||
import forge.adventure.data.DialogData;
|
||||
import forge.adventure.stage.MapStage;
|
||||
import forge.util.Localizer;
|
||||
|
||||
/**
|
||||
* MapDialog
|
||||
* Implements a dialogue/event tree for dialogs.
|
||||
@@ -15,7 +18,7 @@ public class MapDialog {
|
||||
private final MapStage stage;
|
||||
private Array<DialogData> data;
|
||||
private final int parentID;
|
||||
|
||||
private final float WIDTH = 260f;
|
||||
static private final String defaultJSON = "[\n" +
|
||||
" {\n" +
|
||||
" \"effect\":[],\n" +
|
||||
@@ -46,30 +49,27 @@ public class MapDialog {
|
||||
}
|
||||
}
|
||||
|
||||
private void loadDialog(DialogData dialog) {
|
||||
private void loadDialog(DialogData dialog) { //Displays a dialog with dialogue and possible choices.
|
||||
setEffects(dialog.effect);
|
||||
stage.getDialog().getContentTable().clear();
|
||||
stage.getDialog().getButtonTable().clear();
|
||||
String text;
|
||||
if(dialog.loctext != null && !dialog.loctext.isEmpty()){ //Check for localized string, otherwise print text.
|
||||
text = Forge.getLocalizer().getMessage(dialog.loctext);
|
||||
} else {
|
||||
text = dialog.text;
|
||||
}
|
||||
|
||||
int charCount = 0;
|
||||
|
||||
stage.getDialog().text(text);
|
||||
Dialog D = stage.getDialog();
|
||||
Localizer L = Forge.getLocalizer();
|
||||
D.getContentTable().clear(); D.getButtonTable().clear(); //Clear tables to start fresh.
|
||||
String text; //Check for localized string (locname), otherwise print text.
|
||||
if(dialog.loctext != null && !dialog.loctext.isEmpty()) text = L.getMessage(dialog.loctext);
|
||||
else text = dialog.text;
|
||||
Label A = Controls.newLabel(text);
|
||||
A.setWrap(true);
|
||||
D.getContentTable().add(A).width(WIDTH); //Add() returns a Cell, which is what the width is being applied to.
|
||||
if(dialog.options != null) {
|
||||
for(DialogData option:dialog.options) {
|
||||
if( isConditionOk(option.condition) ) {
|
||||
charCount += option.name.length();
|
||||
if(charCount > 35){ //Gross hack.
|
||||
stage.getDialog().getButtonTable().row();
|
||||
charCount = 0;
|
||||
}
|
||||
stage.getDialog().getButtonTable().add(Controls.newTextButton(option.name,() -> loadDialog(option)));
|
||||
|
||||
String name; //Get localized label if present.
|
||||
if(option.locname != null && !option.locname.isEmpty()) name = L.getMessage(option.locname);
|
||||
else name = option.name;
|
||||
TextButton B = Controls.newTextButton(name,() -> loadDialog(option));
|
||||
B.getLabel().setWrap(true); //We want this to wrap in case it's a wordy choice.
|
||||
D.getButtonTable().add(B).width(WIDTH - 10); //The button table also returns a Cell when adding.
|
||||
D.getButtonTable().row(); //Add a row. Tried to allow a few per row but it was a bit erratic.
|
||||
}
|
||||
}
|
||||
stage.showDialog();
|
||||
@@ -90,23 +90,23 @@ public class MapDialog {
|
||||
void setEffects(DialogData.EffectData[] data) {
|
||||
if(data==null) return;
|
||||
for(DialogData.EffectData E:data) {
|
||||
if (E.removeItem != null){
|
||||
if (E.removeItem != null){ //Removes an item from the player's inventory.
|
||||
Current.player().removeItem(E.removeItem);
|
||||
}
|
||||
if (E.addItem != null){
|
||||
if (E.addItem != null){ //Gives an item to the player.
|
||||
Current.player().addItem(E.addItem);
|
||||
}
|
||||
if (E.deleteMapObject != 0){
|
||||
if (E.deleteMapObject != 0){ //Removes a dummy object from the map.
|
||||
if(E.deleteMapObject < 0) stage.deleteObject(parentID);
|
||||
else stage.deleteObject(E.deleteMapObject);
|
||||
}
|
||||
if (E.battleWithActorID != 0){
|
||||
if (E.battleWithActorID != 0){ //Starts a battle with the given enemy ID.
|
||||
if(E.battleWithActorID < 0) stage.beginDuel(stage.getEnemyByID(parentID));
|
||||
else stage.beginDuel(stage.getEnemyByID(E.battleWithActorID));
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Create map object.
|
||||
//Check for quest flags, local.
|
||||
//Check for quest flags, global.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
21846
forge-gui/res/adventure/Shandalar/skin/LanaPixel.fnt
Normal file
21846
forge-gui/res/adventure/Shandalar/skin/LanaPixel.fnt
Normal file
File diff suppressed because it is too large
Load Diff
BIN
forge-gui/res/adventure/Shandalar/skin/LanaPixel.png
Normal file
BIN
forge-gui/res/adventure/Shandalar/skin/LanaPixel.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 172 KiB |
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
Before Width: | Height: | Size: 151 KiB |
@@ -1,4 +1,18 @@
|
||||
{
|
||||
"com.badlogic.gdx.graphics.g2d.BitmapFont": {
|
||||
"big": {
|
||||
"file": "LanaPixel.fnt"
|
||||
},
|
||||
"black": {
|
||||
"file": "LanaPixel.fnt"
|
||||
},
|
||||
"blackbig": {
|
||||
"file": "LanaPixel.fnt"
|
||||
},
|
||||
"default": {
|
||||
"file": "LanaPixel.fnt"
|
||||
}
|
||||
},
|
||||
"com.badlogic.gdx.graphics.Color": {
|
||||
"RGBA_0_0_0_255": {
|
||||
"r": 0,
|
||||
|
||||
@@ -102,3 +102,4 @@ Innistrad: Midnight Hunt, 3/6/MID, MID
|
||||
Innistrad: Crimson Vow, 3/6/VOW, VOW
|
||||
Innistrad: Double Feature, 3/6/MID, DBL
|
||||
Kamigawa: Neon Dynasty, 3/6/NEO, NEO
|
||||
Streets of New Capenna, 3/6/SNC, SNC
|
||||
|
||||
@@ -3,10 +3,10 @@ ManaCost:W U B R
|
||||
Types:Legendary Artifact Creature Human
|
||||
PT:4/4
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME enters the battlefield, create two 1/1 blue Thopter artifact creature tokens with flying.
|
||||
SVar:TrigToken:DB$ Token | TokenAmount$ 2 | TokenScript$ u_1_1_a_thopter_flying | TokenOwner$ You
|
||||
A:AB$ Charm | Cost$ 2 Sac<2/Artifact> | Choices$ DBDealDamage,DBPump,DBGainLife | Defined$ You
|
||||
SVar:DBDealDamage:DB$ DealDamage | ValidTgts$ Player,Planeswalker | TgtPrompt$ Select target player or planeswalker | NumDmg$ 3 | SpellDescription$ CARDNAME deals 3 damage to target player or planeswalker.
|
||||
SVar:DBPump:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ -4 | NumDef$ -4 | IsCurse$ True | SpellDescription$ Target creature gets -4/-4 until end of turn
|
||||
SVar:TrigToken:DB$ Token | TokenAmount$ 2 | TokenScript$ u_1_1_a_thopter_flying
|
||||
A:AB$ Charm | Cost$ 2 Sac<2/Artifact> | Choices$ DBDealDamage,DBPump,DBGainLife
|
||||
SVar:DBDealDamage:DB$ DealDamage | ValidTgts$ Player,Planeswalker | TgtPrompt$ Select target player or planeswalker | NumDmg$ 3 | SpellDescription$ NICKNAME deals 3 damage to target player or planeswalker.
|
||||
SVar:DBPump:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ -4 | NumDef$ -4 | IsCurse$ True | SpellDescription$ Target creature gets -4/-4 until end of turn.
|
||||
SVar:DBGainLife:DB$ GainLife | LifeAmount$ 5 | Defined$ You | SpellDescription$ You gain 5 life.
|
||||
DeckHas:Ability$Token|LifeGain
|
||||
DeckHas:Ability$Token|LifeGain|Sacrifice & Type$Thopter
|
||||
Oracle:When Breya, Etherium Shaper enters the battlefield, create two 1/1 blue Thopter artifact creature tokens with flying.\n{2}, Sacrifice two artifacts: Choose one —\n• Breya deals 3 damage to target player or planeswalker.\n• Target creature gets -4/-4 until end of turn.\n• You gain 5 life.
|
||||
|
||||
@@ -2,8 +2,9 @@ Name:Grand Master of Flowers
|
||||
ManaCost:2 W W
|
||||
Types:Legendary Planeswalker Bahamut
|
||||
Loyalty:3
|
||||
S:Mode$ Continuous | Affected$ Card.Self | CheckSVar$ X | SVarCompare$ GE7 | AddKeyword$ Flying & Indestructible | AddType$ Creature & Dragon & God | SetPower$ 7 | SetToughness$ 7 | RemoveCardTypes$ True | CharacteristicDefining$ True | Description$ As long as CARDNAME has seven or more loyalty counters on him, he's a 7/7 Dragon God creature with flying and indestructible.
|
||||
SVar:X:Count$CardCounters.LOYALTY
|
||||
A:AB$ Pump | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | ValidTgts$ Creature.withoutFirst Strike+withoutDouble Strike+withoutVigilance | KW$ HIDDEN CARDNAME can't attack or block. | IsCurse$ True | Duration$ UntilYourNextTurn | AILogic$ DetainNonLand | SpellDescription$ Target creature without first strike, double strike, or vigilance can't attack or block until your next turn.
|
||||
S:Mode$ Continuous | Affected$ Card.Self | IsPresent$ Card.Self+counters_GE7_LOYALTY | AddKeyword$ Flying & Indestructible | AddType$ Creature & Dragon & God | SetPower$ 7 | SetToughness$ 7 | RemoveCardTypes$ True | CharacteristicDefining$ True | Description$ As long as CARDNAME has seven or more loyalty counters on him, he's a 7/7 Dragon God creature with flying and indestructible.
|
||||
A:AB$ Pump | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | ValidTgts$ Creature.withoutFirst Strike+withoutDouble Strike+withoutVigilance | TgtPrompt$ Target creature without first strike, double strike, or vigilance | Select KW$ HIDDEN CARDNAME can't attack or block. | IsCurse$ True | Duration$ UntilYourNextTurn | AILogic$ DetainNonLand | SpellDescription$ Target creature without first strike, double strike, or vigilance can't attack or block until your next turn.
|
||||
A:AB$ ChangeZone | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | Origin$ Library | OriginChoice$ True | OriginAlternative$ Graveyard | AlternativeMessage$ Would you like to search your library with this ability? If you do, your library will be shuffled. | Destination$ Hand | ChangeType$ Card.namedMonk of the Open Hand | ChangeNum$ 1 | Optional$ True | SpellDescription$ Search your library and/or graveyard for a card named Monk of the Open Hand, reveal it, and put it into your hand. If you search your library this way, shuffle.
|
||||
DeckHas:Type$Dragon|God
|
||||
DeckHints:Name$Monk of the Open Hand
|
||||
Oracle:As long as Grand Master of Flowers has seven or more loyalty counters on him, he's a 7/7 Dragon God creature with flying and indestructible.\n[+1]: Target creature without first strike, double strike, or vigilance can't attack or block until your next turn.\n[+1]: Search your library and/or graveyard for a card named Monk of the Open Hand, reveal it, and put it into your hand. If you search your library this way, shuffle.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
Name:Shoulder to Shoulder
|
||||
ManaCost:2 W
|
||||
Types:Sorcery
|
||||
A:SP$ PutCounter | Cost$ 2 W | ValidTgts$ Creature | TargetMin$ 0 | TargetMax$ 2 | TgtPrompt$ Select target creature other than CARDNAME | CounterType$ P1P1 | CounterNum$ 1 | SubAbility$ DBDraw | SpellDescription$ Support 2. (Put a +1/+1 counter on each of up to two target creatures.)
|
||||
A:SP$ PutCounter | ValidTgts$ Creature | TargetMin$ 0 | TargetMax$ 2 | TgtPrompt$ Select up to two target creatures | TargetUnique$ True | CounterType$ P1P1 | SubAbility$ DBDraw | SpellDescription$ Support 2. (Put a +1/+1 counter on each of up to two target creatures.)
|
||||
SVar:DBDraw:DB$ Draw | NumCards$ 1 | SpellDescription$ Draw a card.
|
||||
DeckHas:Ability$Counters
|
||||
Oracle:Support 2. (Put a +1/+1 counter on each of up to two target creatures.)\nDraw a card.
|
||||
|
||||
10
forge-gui/res/cardsfolder/upcoming/angel_of_suffering.txt
Normal file
10
forge-gui/res/cardsfolder/upcoming/angel_of_suffering.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Name:Angel of Suffering
|
||||
ManaCost:3 B B
|
||||
Types:Creature Nightmare Angel
|
||||
PT:5/3
|
||||
K:Flying
|
||||
R:Event$ DamageDone | ActiveZones$ Battlefield | ValidTarget$ You | ReplaceWith$ DoubleMill | PreventionEffect$ True | Description$ If damage would be dealt to you, prevent that damage and mill twice that many cards.
|
||||
SVar:DoubleMill:DB$ Mill | Defined$ ReplacedTarget | NumCards$ X
|
||||
SVar:X:ReplaceCount$DamageAmount/Twice
|
||||
DeckHas:Ability$Mill
|
||||
Oracle:Flying\nIf damage would be dealt to you, prevent that damage and mill twice that many cards.
|
||||
9
forge-gui/res/cardsfolder/upcoming/angelic_observer.txt
Normal file
9
forge-gui/res/cardsfolder/upcoming/angelic_observer.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
Name:Angelic Observer
|
||||
ManaCost:5 W
|
||||
Types:Creature Angel Advisor
|
||||
PT:3/3
|
||||
K:Flying
|
||||
S:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ X | EffectZone$ All | Description$ This spell costs {1} less to cast for each Citizen you control.
|
||||
SVar:X:Count$TypeYouCtrl.Citizen
|
||||
DeckHints:Type$Citizen
|
||||
Oracle:This spell costs {1} less to cast for each Citizen you control.\nFlying
|
||||
@@ -0,0 +1,8 @@
|
||||
Name:Attended Socialite
|
||||
ManaCost:1 G
|
||||
Types:Creature Elf Druid
|
||||
PT:2/1
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ Alliance — Whenever another creature enters the battlefield under your control, CARDNAME gets +1/+1 until end of turn.
|
||||
SVar:TrigPump:DB$ Pump | Defined$ Self | NumAtt$ 1 | NumDef$ 1
|
||||
SVar:BuffedBy:Creature
|
||||
Oracle:Alliance — Whenever another creature enters the battlefield under your control, Attended Socialite gets +1/+1 until end of turn.
|
||||
12
forge-gui/res/cardsfolder/upcoming/aven_heartstabber.txt
Normal file
12
forge-gui/res/cardsfolder/upcoming/aven_heartstabber.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
Name:Aven Heartstabber
|
||||
ManaCost:U B
|
||||
Types:Creature Bird Assassin
|
||||
PT:1/1
|
||||
K:Flying
|
||||
S:Mode$ Continuous | Affected$ Card.Self | AddPower$ 2 | AddToughness$ 2 | AddKeyword$ Deathtouch | CheckSVar$ X | SVarCompare$ GE5 | Description$ As long as there are five or more mana values among cards in your graveyard, CARDNAME gets +2/+2 and has deathtouch.
|
||||
SVar:X:Count$ValidGraveyard Card.YouOwn$DifferentCMC
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigMill | TriggerDescription$ When CARDNAME dies, mill two cards, then draw a card.
|
||||
SVar:TrigMill:DB$ Mill | NumCards$ 2 | Defined$ You | SubAbility$ TrigDraw
|
||||
SVar:TrigDraw:DB$ Draw | NumCards$ 1 | Defined$ You
|
||||
DeckHas:Ability$Graveyard|Mill
|
||||
Oracle:Flying\nAs long as there are five or more mana values among cards in your graveyard, Aven Heartstabber gets +2/+2 and has deathtouch.\nWhen Aven Heartstabber dies, mill two cards, then draw a card.
|
||||
@@ -3,7 +3,7 @@ ManaCost:3 W W
|
||||
Types:Creature Human Warrior
|
||||
PT:3/5
|
||||
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigSelectTargetCreature | TriggerDescription$ Whenever CARDNAME attacks, CARDNAME and up to one other target creature you control both gain your choice of first strike or lifelink until end of turn.
|
||||
SVar:TrigSelectTargetCreature:DB$ Pump | ValidTgts$ Creature.YouCtrl+Other | TargetMin$ 0 | TargetMax$ 1 | TgtPrompt$ Select up to one other target creature | SubAbility$ DBKeywordChoice | SpellDescription$ CARDNAME and up to one other target creature you control both gain your choice of first strike or lifelink until end of turn.
|
||||
SVar:TrigSelectTargetCreature:DB$ Pump | ValidTgts$ Creature.Other+YouCtrl | TargetMin$ 0 | TargetMax$ 1 | TgtPrompt$ Select up to one other target creature | SubAbility$ DBKeywordChoice | SpellDescription$ CARDNAME and up to one other target creature you control both gain your choice of first strike or lifelink until end of turn.
|
||||
SVar:DBKeywordChoice:DB$ GenericChoice | Defined$ You | Choices$ DBFirstStrike,DBLifelink
|
||||
SVar:DBFirstStrike:DB$ Pump | Defined$ Self | KW$ First Strike | SubAbility$ DBFirstStrike2 | SpellDescription$ First strike
|
||||
SVar:DBFirstStrike2:DB$ Pump | Defined$ Targeted | KW$ First Strike
|
||||
|
||||
10
forge-gui/res/cardsfolder/upcoming/bouncers_beatdown.txt
Normal file
10
forge-gui/res/cardsfolder/upcoming/bouncers_beatdown.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Name:Bouncer's Beatdown
|
||||
ManaCost:2 G
|
||||
Types:Instant
|
||||
S:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ CostReduction | Relative$ True | EffectZone$ All | Description$ This spell costs {2} less to cast if it targets a a black permanent.
|
||||
SVar:CostReduction:Count$Compare CheckTgt GE1.2.0
|
||||
SVar:CheckTgt:Targeted$Valid Permanent.Black
|
||||
A:SP$ DealDamage | ValidTgts$ Creature,Planeswalker | TgtPrompt$ Select target creature or planeswalker | NumDmg$ X | ReplaceDyingDefined$ Targeted | SpellDescription$ CARDNAME deals X damage to target creature or planeswalker, where X is the greatest power among creatures you control. If that creature or planeswalker would die this turn, exile it instead.
|
||||
SVar:X:Count$Valid Creature.YouCtrl$GreatestPower
|
||||
SVar:NeedsToPlayVar:X GE3
|
||||
Oracle:This spell costs {2} less to cast if it targets a black permanent.\nBouncer's Beatdown deals X damage to target creature or planeswalker, where X is the greatest power among creatures you control. If that creature or planeswalker would die this turn, exile it instead.
|
||||
7
forge-gui/res/cardsfolder/upcoming/buy_your_silence.txt
Normal file
7
forge-gui/res/cardsfolder/upcoming/buy_your_silence.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
Name:Buy Your Silence
|
||||
ManaCost:4 W
|
||||
Types:Sorcery
|
||||
A:SP$ ChangeZone | Cost$ 4 W | Origin$ Battlefield | Destination$ Exile | ValidTgts$ Permanent.nonLand | TgtPromt$ Select target nonland permanant | SubAbility$ DBTreasure | StackDescription$ SpellDescription | SpellDescription$ Exile target nonland permanent. Its controller creates a Treasure token. (It's an artifact with "{T}, Sacrifice this artifact: Add one mana of any color.")
|
||||
SVar:DBTreasure:DB$ Token | TokenAmount$ 1 | TokenScript$ c_a_treasure_sac | TokenOwner$ TargetedController
|
||||
DeckHas:Ability$Sacrifice|Token & Type$Treasure|Artifact
|
||||
Oracle:Exile target nonland permanent. Its controller creates a Treasure token. (It's an artifact with "{T}, Sacrifice this artifact: Add one mana of any color.")
|
||||
10
forge-gui/res/cardsfolder/upcoming/caldaia_strongarm.txt
Normal file
10
forge-gui/res/cardsfolder/upcoming/caldaia_strongarm.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Name:Caldaia Strongarm
|
||||
ManaCost:4 G
|
||||
Types:Creature Human Warrior
|
||||
PT:2/3
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPutCounter | TriggerDescription$ When CARDNAME enters the battlefield, put two +1/+1 counters on target creature.
|
||||
SVar:TrigPutCounter:DB$ PutCounter | ValidTgts$ Creature | TgtPrompt$ Select target creature | CounterType$ P1P1 | CounterNum$ 2
|
||||
K:Blitz:3 G
|
||||
SVar:PlayMain1:TRUE
|
||||
DeckHas:Ability$Counters|Sacrifice
|
||||
Oracle:When Caldaia Strongarm enters the battlefield, put two +1/+1 counters on target creature.\nBlitz {3}{G} (If you cast this spell for its blitz cost, it gains haste and "When this creature dies, draw a card." Sacrifice it at the beginning of the next end step.)
|
||||
9
forge-gui/res/cardsfolder/upcoming/celebrity_fencer.txt
Normal file
9
forge-gui/res/cardsfolder/upcoming/celebrity_fencer.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
Name:Celebrity Fencer
|
||||
ManaCost:3 W
|
||||
Types:Creature Elf Druid
|
||||
PT:3/2
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Alliance — Whenever another creature enters the battlefield under your control, put a +1/+1 counter on CARDNAME.
|
||||
SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1
|
||||
SVar:BuffedBy:Creature
|
||||
DeckHas:Ability$Counters
|
||||
Oracle:Alliance — Whenever another creature enters the battlefield under your control, put a +1/+1 counter on Celebrity Fencer.
|
||||
@@ -4,7 +4,7 @@ Types:Enchantment
|
||||
K:Hideaway:5
|
||||
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | Execute$ TrigMill | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of your upkeep, you may mill three cards. Then if there are twenty or more cards in your graveyard, you may play the exiled card without paying its mana cost.
|
||||
SVar:TrigMill:DB$ Mill | NumCards$ 3 | Optional$ True | SubAbility$ DBPlay
|
||||
SVar:DBPlay:DB$ Play | ConditionPresent$ Card.IsRemembered | ConditionZone$ Exile | ConditionCheckSVar$ X | ConditionSVarCompare$ GE20 | ConditionZone$ Graveyard | Defined$ Remembered | Amount$ All | Controller$ You | WithoutManaCost$ True | Optional$ True
|
||||
SVar:DBPlay:DB$ Play | ConditionPresent$ Card.IsRemembered | ConditionZone$ Exile | ConditionCheckSVar$ X | ConditionSVarCompare$ GE20 | Defined$ Remembered | Amount$ All | Controller$ You | WithoutManaCost$ True | Optional$ True
|
||||
SVar:X:Count$ValidGraveyard Card.YouOwn
|
||||
DeckHas:Ability$Mill
|
||||
Oracle:Hideaway 5 (When this enchantment enters the battlefield, look at the top five cards of your library, exile one face down, then put the rest on the bottom in a random order.)\nAt the beginning of your upkeep, you may mill three cards. Then if there are twenty or more cards in your graveyard, you may play the exiled card without paying its mana cost.
|
||||
|
||||
@@ -4,4 +4,5 @@ Types:Creature Human Citizen
|
||||
PT:2/2
|
||||
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigUntap | TriggerDescription$ Whenever CARDNAME attacks, untap target creature or land.
|
||||
SVar:TrigUntap:DB$ Untap | ValidTgts$ Creature,Land | TgtPrompt$ Select target creature or land
|
||||
SVar:HasAttackEffect:True
|
||||
Oracle:Whenever Civic Gardener attacks, untap target creature or land.
|
||||
|
||||
10
forge-gui/res/cardsfolder/upcoming/corpse_appraiser.txt
Normal file
10
forge-gui/res/cardsfolder/upcoming/corpse_appraiser.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Name:Corpse Appraiser
|
||||
ManaCost:U B R
|
||||
Types:Creature Vampire Rogue
|
||||
PT:3/3
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigChangeZone | TriggerDescription$ When CARDNAME enters the battlefield, you may exile up to one target creature from a graveyard. If a card is put into exile this way, look at the top three cards of your library, then put one of those cards into your hand and the rest into your graveyard.
|
||||
SVar:TrigChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Exile | ValidTgts$ Creature | TargetMin$ 0 | TargetMax$ 1 | SubAbility$ DBDig | TgtPrompt$ Select up to one target creature card from a graveyard | RememberChanged$ True
|
||||
SVar:DBDig:DB$ Dig | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionZone$ Exile | DigNum$ 3 | DestinationZone2$ Graveyard | SubAbility$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
DeckHas:Ability$Graveyard
|
||||
Oracle: When Corpse Appraiser enters the battlefield, exile up to one target creature card from a graveyard. If a card is put into exile this way, look at the top three cards of your library, then put one of those cards into your hand and the rest into your graveyard.
|
||||
@@ -7,4 +7,5 @@ K:Haste
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ Alliance — Whenever another creature enters the battlefield under your control, double CARDNAME's power until end of turn.
|
||||
SVar:TrigPump:DB$ Pump | Defined$ Self | NumAtt$ +X | Double$ True
|
||||
SVar:X:Count$CardPower
|
||||
SVar:BuffedBy:Creature
|
||||
Oracle:Trample, haste\nAlliance — Whenever another creature enters the battlefield under your control, double Devilish Valet's power until end of turn.
|
||||
|
||||
9
forge-gui/res/cardsfolder/upcoming/elegant_entourage.txt
Normal file
9
forge-gui/res/cardsfolder/upcoming/elegant_entourage.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
Name:Elegant Entourage
|
||||
ManaCost:3 G
|
||||
Types:Creature Elf Druid
|
||||
PT:4/4
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ Alliance — Whenever another creature enters the battlefield under your control, target creature other than CARDNAME gets +1/+1 and gains trample until end of turn.
|
||||
SVar:TrigPump:DB$ Pump | ValidTgts$ Creature.Other | TgtPrompt$ Select target creature other than CARDNAME | NumAtt$ +1 | NumDef$ +1 | KW$ Trample
|
||||
SVar:PlayMain1:TRUE
|
||||
SVar:BuffedBy:Creature
|
||||
Oracle:Alliance — Whenever another creature enters the battlefield under your control, target creature other than Elegant Entourage gets +1/+1 and gains trample until end of turn.
|
||||
10
forge-gui/res/cardsfolder/upcoming/evolving_door.txt
Normal file
10
forge-gui/res/cardsfolder/upcoming/evolving_door.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Name:Evolving Door
|
||||
ManaCost:2 G
|
||||
Types:Artifact
|
||||
A:AB$ ChangeZone | Cost$ 1 T Sac<1/Creature> | Origin$ Library | Destination$ Exile | ChangeType$ Creature.numColorsEQX | ChangeTypeDesc$ creature card that's {n:X color} | SorcerySpeed$ True | RememberChanged$ True | SubAbility$ DBPlay | SpellDescription$ Count the colors of the sacrificed creature, then search your library for a creature card that's exactly that many colors plus one. Exile that card, then shuffle.
|
||||
SVar:DBPlay:DB$ Play | Defined$ Remembered | ValidSA$ Spell | Amount$ All | Controller$ You | Optional$ True | SubAbility$ DBCleanup | DefinedDesc$ the exiled card | SpellDescription$ You may cast the exiled card. Activate only as a sorcery.
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:X:Sacrificed$CardNumColors/Plus.1
|
||||
DeckHas:Ability$Sacrifice
|
||||
AI:RemoveDeck:Random
|
||||
Oracle:{1}, {T}, Sacrifice a creature: Count the colors of the sacrificed creature, then search your library for a creature card that's exactly that many colors plus one. Exile that card, then shuffle. You may cast the exiled card. Activate only as a sorcery.
|
||||
11
forge-gui/res/cardsfolder/upcoming/extraction_specialist.txt
Normal file
11
forge-gui/res/cardsfolder/upcoming/extraction_specialist.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
Name:Extraction Specialist
|
||||
ManaCost:2 W
|
||||
Types:Creature Human Rogue
|
||||
PT:3/2
|
||||
K:Lifelink
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigChangeZone | TriggerDescription$ When CARDNAME enters the battlefield, return target creature card with mana value 2 or less from your graveyard to the battlefield. That creature can't attack or block for as long as you control CARDNAME.
|
||||
SVar:TrigChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ValidTgts$ Creature.YouCtrl+cmcLE2 | TgtPrompt$ Select target creature with mana value 2 or less from your graveyard | SubAbility$ DBAnimate
|
||||
SVar:DBAnimate:DB$ Animate | Defined$ Targeted | HiddenKeywords$ CARDNAME can't attack or block. | Duration$ UntilHostLeavesPlay
|
||||
SVar:PlayMain1:TRUE
|
||||
DeckHas:Ability$LifeGain|Graveyard
|
||||
Oracle:Lifelink\nWhen Extraction Specialist enters the battlefield, return target creature card with mana value 2 or less from your graveyard to the battlefield. That creature can't attack or block for as long as you control Extraction Specialist.
|
||||
@@ -2,7 +2,7 @@ Name:Forge Boss
|
||||
ManaCost:2 B R
|
||||
Types:Creature Human Warrior
|
||||
PT:3/4
|
||||
T:Mode$ Sacrificed | ValidCard$ Creature.YouCtrl+Other | TriggerZones$ Battlefield | Execute$ TrigDamage | ActivationLimit$ 1 | TriggerDescription$ Whenever you sacrifice one or more other creatures, CARDNAME deals 2 damage to each opponent. This ability triggers only once each turn.
|
||||
T:Mode$ Sacrificed | ValidCard$ Creature.Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigDamage | ActivationLimit$ 1 | TriggerDescription$ Whenever you sacrifice one or more other creatures, CARDNAME deals 2 damage to each opponent. This ability triggers only once each turn.
|
||||
SVar:TrigDamage:DB$ DealDamage | Defined$ Opponent | NumDmg$ 2
|
||||
DeckNeeds:Ability$Sacrifice
|
||||
Oracle:Whenever you sacrifice one or more other creatures, Forge Boss deals 2 damage to each opponent. This ability triggers only once each turn.
|
||||
|
||||
@@ -7,5 +7,6 @@ SVar:TrigCharm:DB$ Charm | Choices$ DBPutCounter,DBToken,DBGainLife | ChoiceRest
|
||||
SVar:DBPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1 | SpellDescription$ Put a +1/+1 counter on CARDNAME.
|
||||
SVar:DBToken:DB$ Token | TokenScript$ c_a_treasure_sac | TokenTapped$ True | SpellDescription$ Create a tapped Treasure token.
|
||||
SVar:DBGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 2 | SpellDescription$ You gain 2 life.
|
||||
SVar:BuffedBy:Creature
|
||||
DeckHas:Ability$Counters|Token|LifeGain|Sacrifice & Type$Treasure
|
||||
Oracle:Alliance — Whenever another creature enters the battlefield under your control, choose one that hasn't been chosen this turn —\n• Put a +1/+1 counter on Gala Greeters.\n• Create a tapped Treasure token.\n• You gain 2 life.
|
||||
|
||||
13
forge-gui/res/cardsfolder/upcoming/giada_font_of_hope.txt
Normal file
13
forge-gui/res/cardsfolder/upcoming/giada_font_of_hope.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
Name:Giada, Font of Hope
|
||||
ManaCost:1 W
|
||||
Types:Legendary Creature Angel
|
||||
PT:2/2
|
||||
K:Flying
|
||||
K:Vigilance
|
||||
K:ETBReplacement:Other:AddExtraCounter:Mandatory:Battlefield:Creature.Angel+YouCtrl+Other
|
||||
SVar:AddExtraCounter:DB$ PutCounter | ETB$ True | Defined$ ReplacedCard | CounterType$ P1P1 | CounterNum$ X | SpellDescription$ Each other Angel you control enters the battlefield with an additional +1/+1 counter on it for each Angel you already control.
|
||||
SVar:X:Count$Valid Angel.YouCtrl
|
||||
A:AB$ Mana | Cost$ T | Produced$ W | RestrictValid$ Spell.Angel | SpellDescription$ Add {W}. Spend this mana only to cast an Angel spell.
|
||||
DeckHas:Ability$Counters
|
||||
DeckNeeds:Type$Angel
|
||||
Oracle:Flying, vigilance\nEach other Angel you control enters the battlefield with an additional +1/+1 counter on it for each Angel you already control.\n{T}: Add {W}. Spend this mana only to cast an Angel spell.
|
||||
9
forge-gui/res/cardsfolder/upcoming/girder_goons.txt
Normal file
9
forge-gui/res/cardsfolder/upcoming/girder_goons.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
Name:Girder Goons
|
||||
ManaCost:4 B
|
||||
Types:Creature Ogre Warrior
|
||||
PT:4/4
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ When CARDNAME dies, create a tapped 2/2 black Rogue creature token.
|
||||
SVar:TrigToken:DB$ Token | TokenScript$ b_2_2_rogue | TokenTapped$ True
|
||||
K:Blitz:3 B
|
||||
DeckHas:Ability$Token|Sacrifice & Type$Rogue
|
||||
Oracle:When Girder Goons dies, create a tapped 2/2 black Rogue creature token.\nBlitz {3}{B} (If you cast this spell for its blitz cost, it gains haste and "When this creature dies, draw a card." Sacrifice it at the beginning of the next end step.)
|
||||
14
forge-gui/res/cardsfolder/upcoming/glamorous_outlaw.txt
Normal file
14
forge-gui/res/cardsfolder/upcoming/glamorous_outlaw.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
Name:Glamorous Outlaw
|
||||
ManaCost:3 U B R
|
||||
Types:Creature Vampire Rogue
|
||||
PT:4/5
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDealDamage | TriggerDescription$ When CARDNAME enters the battlefield, it deals 2 damage to each opponent and you scry 2.
|
||||
SVar:TrigDealDamage:DB$ DealDamage | NumDmg$ 2 | Defined$ Opponent | SubAbility$ DBScry
|
||||
SVar:DBScry:DB$ Scry | ScryNum$ 2
|
||||
A:AB$ Effect | Cost$ 2 ExileFromHand<1/CARDNAME> | ActivationZone$ Hand | ValidTgts$ Land | TgtPrompt$ Select target land | RememberObjects$ Targeted,Self | StaticAbilities$ Land,MayPlay | Triggers$ Cast | ImprintCards$ Self | Duration$ Permanent | ForgetOnMoved$ Exile | SpellDescription$ Target land gains "{T}: Add {U}, {B}, or {R}" until CARDNAME is cast from exile. You may cast CARDNAME for as long as it remains exiled.
|
||||
SVar:Land:Mode$ Continuous | EffectZone$ Command | AffectedZone$ Battlefield | Affected$ Card.IsRemembered+IsNotImprinted | AddAbility$ Mana | Description$ Target land gains "{T}: Add {U}, {B}, or {R}" until EFFECTSOURCE is cast from exile. You may cast EFFECTSOURCE for as long as it remains exiled.
|
||||
SVar:Mana:AB$ Mana | Cost$ T | Produced$ Combo U B R | Amount$ 1 | SpellDescription$ Add {U}, {B}, or {R}
|
||||
SVar:MayPlay:Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsImprinted+IsRemembered | AffectedZone$ Exile | Secondary$ True | Description$ You may cast EFFECTSOURCE for as long as it remains exiled.
|
||||
SVar:Cast:Mode$ SpellCast | ValidCard$ Card.IsImprinted+IsRemembered+wasCastFromExile | Execute$ ExileSelf | Static$ True
|
||||
SVar:ExileSelf:DB$ ChangeZone | Origin$ Command | Destination$ Exile | Defined$ Self
|
||||
Oracle:When Glamorous Outlaw enters the battlefield, it deals 2 damage to each opponent and you scry 2.\n{2}, Exile Glamorous Outlaw from your hand: Target land gains "{T}: Add {U}, {B}, or {R}" until Glamorous Outlaw is cast from exile. You may cast Glamorous Outlaw for as long as it remains exiled.
|
||||
9
forge-gui/res/cardsfolder/upcoming/graveyard_shift.txt
Normal file
9
forge-gui/res/cardsfolder/upcoming/graveyard_shift.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
Name:Graveyard Shift
|
||||
ManaCost:4 B
|
||||
Types:Sorcery
|
||||
S:Mode$ Continuous | CharacteristicDefining$ True | Affected$ Card.Self | AddKeyword$ Flash | CheckSVar$ X | SVarCompare$ GE5 | Description$ This spell has flash as long as there are five or more mana values among cards in your graveyard.
|
||||
SVar:X:Count$ValidGraveyard Card.YouOwn$DifferentCMC
|
||||
A:SP$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ValidTgts$ Creature.YouOwn | TgtPrompt$ Select target creature card in your graveyard | SpellDescription$ Return target creature card from your graveyard to the battlefield.
|
||||
DeckHas:Ability$Graveyard
|
||||
DeckHints:Ability$Discard|Mill
|
||||
Oracle:This spell has flash as long as there are five or more mana values among cards in your graveyard.\nReturn target creature card from your graveyard to the battlefield.
|
||||
5
forge-gui/res/cardsfolder/upcoming/incandescent_aria.txt
Normal file
5
forge-gui/res/cardsfolder/upcoming/incandescent_aria.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
Name:Incandescent Aria
|
||||
ManaCost:R G W
|
||||
Types:Sorcery
|
||||
A:SP$ DamageAll | ValidCards$ Creature.nonToken | NumDmg$ 3 | SpellDescription$ CARDNAME deals 3 damage to each nontoken creature.
|
||||
Oracle:Incandescent Aria deals 3 damage to each nontoken creature.
|
||||
@@ -6,4 +6,5 @@ A:AB$ CopyPermanent | Cost$ R T Discard<1/Card> | ValidTgts$ Creature.Other+YouC
|
||||
SVar:Dies:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigDraw | TriggerDescription$ When this creature dies, draw a card.
|
||||
SVar:TrigDraw:DB$ Draw | NumCards$ 1
|
||||
K:Blitz:1 R
|
||||
DeckHas:Ability$Discard|Token|Sacrifice
|
||||
Oracle:{R}, {T}, Discard a card: Create a token that's a copy of another target creature you control. It gains haste and "When this creature dies, draw a card." Sacrifice it at the beginning of the next end step. Activate only as a sorcery.\nBlitz {1}{R} (If you cast this spell for its blitz cost, it gains haste and "When this creature dies, draw a card." Sacrifice it at the beginning of the next end step.)
|
||||
|
||||
10
forge-gui/res/cardsfolder/upcoming/knockout_blow.txt
Normal file
10
forge-gui/res/cardsfolder/upcoming/knockout_blow.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Name:Knockout Blow
|
||||
ManaCost:2 W
|
||||
Types:Instant
|
||||
S:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ CostReduction | Relative$ True | EffectZone$ All | Description$ This spell costs {2} less to cast if it targets a red creature.
|
||||
SVar:CostReduction:Count$Compare CheckTgt GE1.2.0
|
||||
SVar:CheckTgt:Targeted$Valid Creature.Red
|
||||
A:SP$ DealDamage | ValidTgts$ Creature.attacking,Creature.blocking | TgtPrompt$ Select target attacking or blocking creature | NumDmg$ 4 | SubAbility$ GainLife | SpellDescription$ CARDNAME deals 4 damage to target attacking or blocking creature and you gain 2 life.
|
||||
SVar:GainLife:DB$ GainLife | LifeAmount$ 2 | Defined$ You
|
||||
DeckHas:Ability$LifeGain
|
||||
Oracle:This spell costs {2} less to cast if it targets a red creature.\nKnockout Blow deals 4 damage to target attacking or blocking creature and you gain 2 life.
|
||||
@@ -5,4 +5,5 @@ PT:3/1
|
||||
A:AB$ Draw | Cost$ 4 UR ExileFromGrave<1/CARDNAME> | ActivationZone$ Graveyard | NumCards$ 2 | SubAbility$ DBDiscard | SpellDescription$ Draw two cards, then discard a card.
|
||||
SVar:DBDiscard:DB$ Discard | Mode$ TgtChoose
|
||||
DeckHas:Ability$Discard
|
||||
DeckHints:Color$Blue|Red
|
||||
Oracle:{4}{U/R}, Exile Maestros Initiate from your graveyard: Draw two cards, then discard a card.
|
||||
|
||||
13
forge-gui/res/cardsfolder/upcoming/masked_bandits.txt
Normal file
13
forge-gui/res/cardsfolder/upcoming/masked_bandits.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
Name:Masked Bandits
|
||||
ManaCost:3 B R G
|
||||
Types:Creature Raccoon Rogue
|
||||
PT:5/5
|
||||
K:Vigilance
|
||||
K:Menace
|
||||
A:AB$ Effect | Cost$ 2 ExileFromHand<1/CARDNAME> | ActivationZone$ Hand | ValidTgts$ Land | TgtPrompt$ Select target land | RememberObjects$ Targeted,Self | StaticAbilities$ Land,MayPlay | Triggers$ Cast | ImprintCards$ Self | Duration$ Permanent | ForgetOnMoved$ Exile | SpellDescription$ Target land gains "{T}: Add {B}, {R}, or {G}" until CARDNAME is cast from exile. You may cast CARDNAME for as long as it remains exiled.
|
||||
SVar:Land:Mode$ Continuous | EffectZone$ Command | AffectedZone$ Battlefield | Affected$ Card.IsRemembered+IsNotImprinted | AddAbility$ Mana | Description$ Target land gains "{T}: Add {B}, {R}, or {G}" until EFFECTSOURCE is cast from exile. You may cast EFFECTSOURCE for as long as it remains exiled.
|
||||
SVar:Mana:AB$ Mana | Cost$ T | Produced$ Combo B R G | Amount$ 1 | SpellDescription$ Add {B}, {R}, or {G}
|
||||
SVar:MayPlay:Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsImprinted+IsRemembered | AffectedZone$ Exile | Secondary$ True | Description$ You may cast EFFECTSOURCE for as long as it remains exiled.
|
||||
SVar:Cast:Mode$ SpellCast | ValidCard$ Card.IsImprinted+IsRemembered+wasCastFromExile | Execute$ ExileSelf | Static$ True
|
||||
SVar:ExileSelf:DB$ ChangeZone | Origin$ Command | Destination$ Exile | Defined$ Self
|
||||
Oracle:Vigilance\nMenace (This creature can't be blocked except by two or more creatures.)\n{2}, Exile Masked Bandits from your hand: Target land gains "{T}: Add {B}, {R}, or {G}" until Masked Bandits is cast from exile. You may cast Masked Bandits for as long as it remains exiled.
|
||||
11
forge-gui/res/cardsfolder/upcoming/mayhem_patrol.txt
Normal file
11
forge-gui/res/cardsfolder/upcoming/mayhem_patrol.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
Name:Mayhem Patrol
|
||||
ManaCost:1 R
|
||||
Types:Creature Devil Warrior
|
||||
PT:1/2
|
||||
K:Menace
|
||||
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigPump | TriggerDescription$ Whenever CARDNAME attacks, target creature gets +1/+0 until end of turn.
|
||||
SVar:TrigPump:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ 1
|
||||
K:Blitz:1 R
|
||||
SVar:HasAttackEffect:True
|
||||
DeckHas:Ability$Sacrifice
|
||||
Oracle:Menace (This creature can't be blocked except by two or more creatures.)\nWhenever Mayhem Patrol attacks, target creature gets +1/+0 until end of turn.\nBlitz {1}{R} (If you cast this spell for its blitz cost, it gains haste and "When this creature dies, draw a card." Sacrifice it at the beginning of the next end step.)
|
||||
10
forge-gui/res/cardsfolder/upcoming/meeting_of_the_five.txt
Normal file
10
forge-gui/res/cardsfolder/upcoming/meeting_of_the_five.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Name:Meeting of the Five
|
||||
ManaCost:3 W U B R G
|
||||
Types:Sorcery
|
||||
A:SP$ Dig | DigNum$ 10 | ChangeNum$ All | DestinationZone$ Exile | RememberChanged$ True | SubAbility$ DBEffect | SpellDescription$ Exile the top ten cards of your library.
|
||||
SVar:DBEffect:DB$ Effect | StaticAbilities$ EffSModeContinuous | ExileOnMoved$ Exile | RememberObjects$ Remembered | SubAbility$ DBCleanup | SpellDescription$ You may cast spells with exactly three colors from among them this turn.
|
||||
SVar:EffSModeContinuous:Mode$ Continuous | EffectZone$ Command | Affected$ Card.IsRemembered+numColorsEQ3 | MayPlay$ True | AffectedZone$ Exile | Description$ You may cast spells with exactly three colors from among them this turn.
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | SubAbility$ DBMana
|
||||
SVar:DBMana:DB$ Mana | Produced$ W W U U B B R R G G | RestrictValid$ Spell.numColorsEQ3 | SpellDescription$ Add {W}{W}{U}{U}{B}{B}{R}{R}{G}{G}. Spend this mana only to cast spells with exactly three colors.
|
||||
AI:RemoveDeck:Random
|
||||
Oracle:Exile the top ten cards of your library. You may cast spells with exactly three colors from among them this turn. Add {W}{W}{U}{U}{B}{B}{R}{R}{G}{G}. Spend this mana only to cast spells with exactly three colors.
|
||||
9
forge-gui/res/cardsfolder/upcoming/metropolis_angel.txt
Normal file
9
forge-gui/res/cardsfolder/upcoming/metropolis_angel.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
Name:Metropolis Angel
|
||||
ManaCost:2 W U
|
||||
Types:Creature Angel Soldier
|
||||
PT:3/1
|
||||
K:Flying
|
||||
T:Mode$ AttackersDeclared | ValidAttackers$ Creature.YouCtrl+HasCounters | TriggerZones$ Battlefield | Execute$ TrigDraw | TriggerDescription$ Whenever you attack with one or more creatures with counters on them, draw a card.
|
||||
SVar:TrigDraw:DB$ Draw
|
||||
DeckHints:Ability$Counters
|
||||
Oracle:Flying\nWhenever you attack with one or more creatures with counters on them, draw a card.
|
||||
10
forge-gui/res/cardsfolder/upcoming/night_clubber.txt
Normal file
10
forge-gui/res/cardsfolder/upcoming/night_clubber.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Name:Night Clubber
|
||||
ManaCost:1 B B
|
||||
Types:Creature Human Warrior
|
||||
PT:2/2
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPumpAll | TriggerDescription$ When CARDNAME enters the battlefield, creatures your opponents control get -1/-1 until end of turn.
|
||||
SVar:TrigPumpAll:DB$ PumpAll | NumAtt$ -1 | NumDef$ -1 | ValidCards$ Creature.OppCtrl | IsCurse$ True
|
||||
K:Blitz:2 B
|
||||
SVar:PlayMain1:TRUE
|
||||
DeckHas:Ability$Sacrifice
|
||||
Oracle:When Night Clubber enters the battlefield, creatures your opponents control get -1/-1 until end of turn.\nBlitz {2}{B} (If you cast this spell for its blitz cost, it gains haste and "When this creature dies, draw a card." Sacrifice it at the beginning of the next end step.)
|
||||
9
forge-gui/res/cardsfolder/upcoming/out_of_the_way.txt
Normal file
9
forge-gui/res/cardsfolder/upcoming/out_of_the_way.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
Name:Out of the Way
|
||||
ManaCost:3 U
|
||||
Types:Instant
|
||||
S:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ CostReduction | Relative$ True | EffectZone$ All | Description$ This spell costs {2} less to cast if it targets a a green permanent.
|
||||
SVar:CostReduction:Count$Compare CheckTgt GE1.2.0
|
||||
SVar:CheckTgt:Targeted$Valid Permanent.Green
|
||||
A:SP$ ChangeZone | ValidTgts$ Permanent.nonLand+OppCtrl | TgtPrompt$ Select target nonland permanent an opponent controls | Origin$ Battlefield | Destination$ Hand | SubAbility$ DBDraw | SpellDescription$ Return target nonland permanent an opponent controls to its owner's hand.
|
||||
SVar:DBDraw:DB$ Draw
|
||||
Oracle:This spell costs {2} less to cast if it targets a green permanent.\nReturn target nonland permanent an opponent controls to its owner's hand.\nDraw a card.
|
||||
11
forge-gui/res/cardsfolder/upcoming/paragon_of_modernity.txt
Normal file
11
forge-gui/res/cardsfolder/upcoming/paragon_of_modernity.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
Name:Paragon of Modernity
|
||||
ManaCost:4
|
||||
Types:Artifact Creature Angel Warrior
|
||||
PT:2/2
|
||||
K:Flying
|
||||
A:AB$ Branch | Cost$ 3 | BranchConditionSVar$ X | BranchConditionSVarCompare$ EQ3 | FalseSubAbility$ DBPump | TrueSubAbility$ DBPutCounter | SpellDescription$ CARDNAME gets +1/+1 until end of turn. If exactly three colors of mana were spent to activate this ability, put a +1/+1 counter on it instead.
|
||||
SVar:DBPump:DB$ Pump | Defined$ Self | NumAtt$ 1 | NumDef$ 1
|
||||
SVar:DBPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1
|
||||
SVar:X:Count$ManaColorsPaid
|
||||
DeckHas:Ability$Counters
|
||||
Oracle:Flying\n{3}: Paragon of Modernity gets +1/+1 until end of turn. If exactly three colors of mana were spent to activate this ability, put a +1/+1 counter on it instead.
|
||||
10
forge-gui/res/cardsfolder/upcoming/plasma_jockey.txt
Normal file
10
forge-gui/res/cardsfolder/upcoming/plasma_jockey.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Name:Plasma Jockey
|
||||
ManaCost:3 R
|
||||
Types:Creature Viashino Warrior
|
||||
PT:3/1
|
||||
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigPump | TriggerDescription$ Whenever CARDNAME attacks, target creature an opponent controls can't block this turn.
|
||||
SVar:TrigPump:DB$ Pump | ValidTgts$ Creature.OppCtrl | KW$ HIDDEN CARDNAME can't block. | TgtPrompt$ Select target creature an opponent controls | IsCurse$ True
|
||||
K:Blitz:2 R
|
||||
SVar:HasAttackEffect:True
|
||||
DeckHas:Ability$Sacrifice
|
||||
Oracle:Whenever Plasma Jockey attacks, target creature an opponent controls can't block this turn.\nBlitz {2}{R} (If you cast this spell for its blitz cost, it gains haste and "When this creature dies, draw a card." Sacrifice it at the beginning of the next end step.)
|
||||
10
forge-gui/res/cardsfolder/upcoming/pugnacious_pugilist.txt
Normal file
10
forge-gui/res/cardsfolder/upcoming/pugnacious_pugilist.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Name:Pugnacious Pugilist
|
||||
ManaCost:3 R R
|
||||
Types:Creature Ogre Warrior
|
||||
PT:4/4
|
||||
T:Mode$ Attacks | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerDescription$ Whenever CARDNAME attacks, create a tapped and attacking 1/1 red Devil creature token with "When this creature dies, it deals 1 damage to any target."
|
||||
SVar:TrigToken:DB$ Token | TokenScript$ r_1_1_devil_burn | TokenTapped$ True | TokenAttacking$ True
|
||||
K:Blitz:3 R
|
||||
DeckHas:Ability$Token|Sacrifice & Type$Devil
|
||||
SVar:HasAttackEffect:True
|
||||
Oracle:Whenever Pugnacious Pugilist attacks, create a tapped and attacking 1/1 red Devil creature token with "When this creature dies, it deals 1 damage to any target."\nBlitz {3}{R} (If you cast this spell for its blitz cost, it gains haste and "When this creature dies, draw a card." Sacrifice it at the beginning of the next end step.)
|
||||
9
forge-gui/res/cardsfolder/upcoming/raffines_guidance.txt
Normal file
9
forge-gui/res/cardsfolder/upcoming/raffines_guidance.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
Name:Raffine's Guidance
|
||||
ManaCost:W
|
||||
Types:Enchantment Aura
|
||||
K:Enchant creature
|
||||
A:SP$ Attach | ValidTgts$ Creature | AILogic$ Pump
|
||||
S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddPower$ 1 | AddToughness$ 1 | Description$ Enchanted creature gets +1/+1.
|
||||
SVar:AltCost:Cost$ 2 W | ActivationZone$ Graveyard | Description$ You may cast CARDNAME from your graveyard by paying {2}{W} rather than paying its mana cost.
|
||||
DeckHas:Ability$Graveyard
|
||||
Oracle:Enchant creature\nEnchanted creature gets +1/+1.\nYou may cast Raffine's Guidance from your graveyard by paying {2}{W} instead of its mana cost.
|
||||
14
forge-gui/res/cardsfolder/upcoming/rakish_revelers.txt
Normal file
14
forge-gui/res/cardsfolder/upcoming/rakish_revelers.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
Name:Rakish Revelers
|
||||
ManaCost:2 R G W
|
||||
Types:Creature Elf Druid Rogue
|
||||
PT:5/3
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME enters the battlefield, create a 1/1 green and white Citizen creature token.
|
||||
SVar:TrigToken:DB$ Token | TokenScript$ gw_1_1_citizen
|
||||
A:AB$ Effect | Cost$ 2 ExileFromHand<1/CARDNAME> | ActivationZone$ Hand | ValidTgts$ Land | TgtPrompt$ Select target land | RememberObjects$ Targeted,Self | StaticAbilities$ Land,MayPlay | Triggers$ Cast | ImprintCards$ Self | Duration$ Permanent | ForgetOnMoved$ Exile | SpellDescription$ Target land gains "{T}: Add {R}, {G}, or {W}" until CARDNAME is cast from exile. You may cast CARDNAME for as long as it remains exiled.
|
||||
SVar:Land:Mode$ Continuous | EffectZone$ Command | AffectedZone$ Battlefield | Affected$ Card.IsRemembered+IsNotImprinted | AddAbility$ Mana | Description$ Target land gains "{T}: Add {R}, {G}, or {W}" until EFFECTSOURCE is cast from exile. You may cast EFFECTSOURCE for as long as it remains exiled.
|
||||
SVar:Mana:AB$ Mana | Cost$ T | Produced$ Combo R G W | Amount$ 1 | SpellDescription$ Add {R}, {G}, or {W}
|
||||
SVar:MayPlay:Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsImprinted+IsRemembered | AffectedZone$ Exile | Secondary$ True | Description$ You may cast EFFECTSOURCE for as long as it remains exiled.
|
||||
SVar:Cast:Mode$ SpellCast | ValidCard$ Card.IsImprinted+IsRemembered+wasCastFromExile | Execute$ ExileSelf | Static$ True
|
||||
SVar:ExileSelf:DB$ ChangeZone | Origin$ Command | Destination$ Exile | Defined$ Self
|
||||
DeckHas:Ability$Token & Type$Citizen
|
||||
Oracle:When Rakish Revelers enters the battlefield, create a 1/1 green and white Citizen creature token.\n{2}, Exile Rakish Revelers from your hand: Target land gains "{T}: Add {R}, {G}, or {W}" until Rakish Revelers is cast from exile. You may cast Rakish Revelers for as long as it remains exiled.
|
||||
6
forge-gui/res/cardsfolder/upcoming/refuse_to_yield.txt
Normal file
6
forge-gui/res/cardsfolder/upcoming/refuse_to_yield.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
Name:Refuse to Yield
|
||||
ManaCost:1 W
|
||||
Types:Instant
|
||||
A:SP$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ +2 | NumDef$ +7 | SubAbility$ DBUntap | SpellDescription$ Target creature gets +2/+7 until end of turn. Untap it.
|
||||
SVar:DBUntap:DB$ Untap | Defined$ Targeted
|
||||
Oracle:Target creature gets +2/+7 until end of turn. Untap it.
|
||||
8
forge-gui/res/cardsfolder/upcoming/riveteers_decoy.txt
Normal file
8
forge-gui/res/cardsfolder/upcoming/riveteers_decoy.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
Name:Riveteers Decoy
|
||||
ManaCost:1 G
|
||||
Types:Creature Human Warrior
|
||||
PT:3/1
|
||||
K:CARDNAME must be blocked if able.
|
||||
K:Blitz:3 G
|
||||
DeckHas:Ability$Sacrifice
|
||||
Oracle:Riveteers Decoy must be blocked if able.\nBlitz {3}{G} (If you cast this spell for its blitz cost, it gains haste and "When this creature dies, draw a card." Sacrifice it at the beginning of the next end step.)
|
||||
@@ -0,0 +1,9 @@
|
||||
Name:Riveteers Requisitioner
|
||||
ManaCost:1 R
|
||||
Types:Creature Viashino Rogue
|
||||
PT:3/1
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME dies, create a Treasure token. (It's an artifact with "{T}, Sacrifice this artifact: Add one mana of any color.")
|
||||
SVar:TrigToken:DB$ Token | TokenScript$ c_a_treasure_sac
|
||||
DeckHas:Ability$Token|Sacrifice & Type$Treasure|Artifact
|
||||
K:Blitz:2 R
|
||||
Oracle:When Riveteers Requisitioner dies, create a Treasure token. (It's an artifact with "{T}, Sacrifice this artifact: Add one mana of any color.")\nBlitz {2}{R} (If you cast this spell for its blitz cost, it gains haste and "When this creature dies, draw a card." Sacrifice it at the beginning of the next end step.)
|
||||
@@ -7,4 +7,5 @@ T:Mode$ Attacks | ValidCard$ Card.Self | OptionalDecider$ DefendingPlayer | Exec
|
||||
SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ 1 | SubAbility$ TrigUntap
|
||||
SVar:TrigUntap:DB$ Untap | Defined$ Self | SubAbility$ RemCombat
|
||||
SVar:RemCombat:DB$ RemoveFromCombat | Defined$ Self
|
||||
SVar:HasAttackEffect:True
|
||||
Oracle:Menace\nWhenever Shakedown Heavy attacks, defending player may have you draw a card. If they do, untap Shakedown Heavy and remove it from combat.
|
||||
15
forge-gui/res/cardsfolder/upcoming/shattered_seraph.txt
Normal file
15
forge-gui/res/cardsfolder/upcoming/shattered_seraph.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
Name:Shattered Seraph
|
||||
ManaCost:4 W U B
|
||||
Types:Creature Angel Rogue
|
||||
PT:4/4
|
||||
K:Flying
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigGainLife | TriggerDescription$ When CARDNAME enters the battlefield, you gain 3 life.
|
||||
SVar:TrigGainLife:DB$ GainLife | LifeAmount$ 3
|
||||
A:AB$ Effect | Cost$ 2 ExileFromHand<1/CARDNAME> | ActivationZone$ Hand | ValidTgts$ Land | TgtPrompt$ Select target land | RememberObjects$ Targeted,Self | StaticAbilities$ Land,MayPlay | Triggers$ Cast | ImprintCards$ Self | Duration$ Permanent | ForgetOnMoved$ Exile | SpellDescription$ Target land gains "{T}: Add {W}, {U}, or {B}" until CARDNAME is cast from exile. You may cast CARDNAME for as long as it remains exiled.
|
||||
SVar:Land:Mode$ Continuous | EffectZone$ Command | AffectedZone$ Battlefield | Affected$ Card.IsRemembered+IsNotImprinted | AddAbility$ Mana | Description$ Target land gains "{T}: Add {W}, {U}, or {B}" until EFFECTSOURCE is cast from exile. You may cast EFFECTSOURCE for as long as it remains exiled.
|
||||
SVar:Mana:AB$ Mana | Cost$ T | Produced$ Combo W U B | Amount$ 1 | SpellDescription$ Add {W}, {U}, or {B}
|
||||
SVar:MayPlay:Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsImprinted+IsRemembered | AffectedZone$ Exile | Secondary$ True | Description$ You may cast EFFECTSOURCE for as long as it remains exiled.
|
||||
SVar:Cast:Mode$ SpellCast | ValidCard$ Card.IsImprinted+IsRemembered+wasCastFromExile | Execute$ ExileSelf | Static$ True
|
||||
SVar:ExileSelf:DB$ ChangeZone | Origin$ Command | Destination$ Exile | Defined$ Self
|
||||
DeckHas:Ability$LifeGain
|
||||
Oracle:Flying\nWhen Shattered Seraph enters the battlefield, you gain 3 life.\n{2}, Exile Shattered Seraph from your hand: Target land gains "{T}: Add {W}, {U}, or {B}" until Shattered Seraph is cast from exile. You may cast Shattered Seraph for as long as it remains exiled.
|
||||
9
forge-gui/res/cardsfolder/upcoming/social_climber.txt
Normal file
9
forge-gui/res/cardsfolder/upcoming/social_climber.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
Name:Social Climber
|
||||
ManaCost:2 G
|
||||
Types:Creature Human Druid
|
||||
PT:3/2
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigGainLife | TriggerDescription$ Alliance — Whenever another creature enters the battlefield under your control, you gain 1 life.
|
||||
SVar:TrigGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 1
|
||||
SVar:BuffedBy:Creature
|
||||
DeckHas:Ability$LifeGain
|
||||
Oracle:Alliance — Whenever another creature enters the battlefield under your control, you gain 1 life.
|
||||
13
forge-gui/res/cardsfolder/upcoming/sparas_adjudicators.txt
Normal file
13
forge-gui/res/cardsfolder/upcoming/sparas_adjudicators.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
Name:Spara's Adjudicators
|
||||
ManaCost:2 G W U
|
||||
Types:Creature Cat Citizen
|
||||
PT:4/4
|
||||
T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefield | Execute$ TrigPump | TriggerDescription$ When CARDNAME enters the battlefield, target creature an opponent controls can't attack or block until your next turn.
|
||||
SVar:TrigPump:DB$ Pump | ValidTgts$ Creature.OpponentCtrl | TgtPrompt$ Select target creature an opponent controls | KW$ HIDDEN CARDNAME can't attack or block. | IsCurse$ True | Duration$ UntilYourNextTurn
|
||||
A:AB$ Effect | Cost$ 2 ExileFromHand<1/CARDNAME> | ActivationZone$ Hand | ValidTgts$ Land | TgtPrompt$ Select target land | RememberObjects$ Targeted,Self | StaticAbilities$ Land,MayPlay | Triggers$ Cast | ImprintCards$ Self | Duration$ Permanent | ForgetOnMoved$ Exile | SpellDescription$ Target land gains "{T}: Add {G}, {W}, or {U}" until CARDNAME is cast from exile. You may cast CARDNAME for as long as it remains exiled.
|
||||
SVar:Land:Mode$ Continuous | EffectZone$ Command | AffectedZone$ Battlefield | Affected$ Card.IsRemembered+IsNotImprinted | AddAbility$ Mana | Description$ Target land gains "{T}: Add {G}, {W}, or {U}" until EFFECTSOURCE is cast from exile. You may cast EFFECTSOURCE for as long as it remains exiled.
|
||||
SVar:Mana:AB$ Mana | Cost$ T | Produced$ Combo G W U | Amount$ 1 | SpellDescription$ Add {G}, {W}, or {U}
|
||||
SVar:MayPlay:Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsImprinted+IsRemembered | AffectedZone$ Exile | Secondary$ True | Description$ You may cast EFFECTSOURCE for as long as it remains exiled.
|
||||
SVar:Cast:Mode$ SpellCast | ValidCard$ Card.IsImprinted+IsRemembered+wasCastFromExile | Execute$ ExileSelf | Static$ True
|
||||
SVar:ExileSelf:DB$ ChangeZone | Origin$ Command | Destination$ Exile | Defined$ Self
|
||||
Oracle:When Spara's Adjudicators enters the battlefield, target creature an opponent controls can't attack or block until your next turn.\n{2}, Exile Spara's Adjudicators from your hand: Target land gains "{T}: Add {G}, {W}, or {U}" until Spara's Adjudicators is cast from exile. You may cast Spara's Adjudicators for as long as it remains exiled.
|
||||
@@ -0,0 +1,8 @@
|
||||
Name:Tainted Indulgence
|
||||
ManaCost:U B
|
||||
Types:Instant
|
||||
A:SP$ Draw | NumCards$ 2 | SubAbility$ DBDiscard | SpellDescription$ Draw two cards. Then discard a card unless there are five or more mana values among cards in your graveyard.
|
||||
SVar:DBDiscard:DB$ Discard | NumCards$ 1 | Mode$ TgtChoose | ConditionCheckSVar$ X | ConditionSVarCompare$ LE4
|
||||
SVar:X:Count$ValidGraveyard Card.YouOwn$DifferentCMC
|
||||
DeckHas:Ability$Discard|Graveyard
|
||||
Oracle:Draw two cards. Then discard a card unless there are five or more mana values among cards in your graveyard.
|
||||
@@ -0,0 +1,8 @@
|
||||
Name:Tenacious Underdog
|
||||
ManaCost:1 B
|
||||
Types:Creature Human Warrior
|
||||
PT:3/2
|
||||
K:Blitz:2 B B PayLife<2>
|
||||
S:Mode$ Continuous | Affected$ Card.Self | MayPlay$ True | ValidSA$ Spell.Blitz | AffectedZone$ Graveyard | EffectZone$ Graveyard | Description$ You may cast CARDNAME from your graveyard using its blitz ability.
|
||||
DeckHas:Ability$Sacrifice|Graveyard
|
||||
Oracle:Blitz—{2}{B}{B}, Pay 2 life. (If you cast this spell for its blitz cost, it gains haste and "When this creature dies, draw a card." Sacrifice it at the beginning of the next end step.)\nYou may cast Tenacious Underdog from your graveyard using its blitz ability.
|
||||
10
forge-gui/res/cardsfolder/upcoming/torch_breath.txt
Normal file
10
forge-gui/res/cardsfolder/upcoming/torch_breath.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Name:Torch Breath
|
||||
ManaCost:X R
|
||||
Types:Instant
|
||||
S:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ CostReduction | Relative$ True | EffectZone$ All | Description$ This spell costs {2} less to cast if it targets a a blue permanent.
|
||||
SVar:CostReduction:Count$Compare CheckTgt GE1.2.0
|
||||
SVar:CheckTgt:Targeted$Valid Permanent.Blue
|
||||
K:This spell can't be countered.
|
||||
A:SP$ DealDamage | ValidTgts$ Creature,Planeswalker | TgtPrompt$ Select target creature or planeswalker | NumDmg$ X | SpellDescription$ CARDNAME deals X damage to target creature or planeswalker.
|
||||
SVar:X:Count$xPaid
|
||||
Oracle:This spell costs {2} less to cast if it targets a blue permanent.\nThis spell can't be countered.\nTorch Breath deals X damage to target creature or planeswalker.
|
||||
10
forge-gui/res/cardsfolder/upcoming/venom_connoisseur.txt
Normal file
10
forge-gui/res/cardsfolder/upcoming/venom_connoisseur.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Name:Venom Connoisseur
|
||||
ManaCost:1 G
|
||||
Types:Creature Human Druid
|
||||
PT:2/2
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ Alliance — Whenever another creature enters the battlefield under your control, Venom Connoisseur gains deathtouch until end of turn. If this is the second time this ability has resolved this turn, all creatures you control gain deathtouch until end of turn.
|
||||
SVar:TrigPump:DB$ Pump | Defined$ Self | KW$ Deathtouch | SubAbility$ DBPumpAll
|
||||
SVar:DBPumpAll:DB$ PumpAll | ValidCards$ Creature.YouCtrl | KW$ Deathtouch | ConditionCheckSVar$ CreatureETBAmount | ConditionSVarCompare$ EQ2
|
||||
SVar:CreatureETBAmount:Count$ResolvedThisTurn
|
||||
SVar:BuffedBy:Creature
|
||||
Oracle:Alliance — Whenever another creature enters the battlefield under your control, Venom Connoisseur gains deathtouch until end of turn. If this is the second time this ability has resolved this turn, all creatures you control gain deathtouch until end of turn.
|
||||
6
forge-gui/res/cardsfolder/upcoming/void_rend.txt
Normal file
6
forge-gui/res/cardsfolder/upcoming/void_rend.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
Name:Void Rend
|
||||
ManaCost:W U B
|
||||
Types:Instant
|
||||
K:This spell can't be countered.
|
||||
A:SP$ Destroy | ValidTgts$ Permanent.nonLand | TgtPrompt$ Select target nonland permanent | SpellDescription$ Destroy target nonland permanent.
|
||||
Oracle:This spell can't be countered.\nDestroy target nonland permanent.
|
||||
8
forge-gui/res/cardsfolder/upcoming/whack.txt
Normal file
8
forge-gui/res/cardsfolder/upcoming/whack.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
Name:Whack
|
||||
ManaCost:3 B
|
||||
Types:Sorcery
|
||||
S:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ CostReduction | Relative$ True | EffectZone$ All | Description$ This spell costs {3} less to cast if it targets a a white creature.
|
||||
SVar:CostReduction:Count$Compare CheckTgt GE1.3.0
|
||||
SVar:CheckTgt:Targeted$Valid Creature.White
|
||||
A:SP$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ -4 | NumDef$ -4 | IsCurse$ True | SpellDescription$ Target creature gets -4/-4 until end of turn.
|
||||
Oracle:This spell costs {3} less to cast if it targets a white creature.\nTarget creature gets -4/-4 until end of turn.
|
||||
11
forge-gui/res/cardsfolder/upcoming/widespread_thieving.txt
Normal file
11
forge-gui/res/cardsfolder/upcoming/widespread_thieving.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
Name:Widespread Thieving
|
||||
ManaCost:2 R
|
||||
Types:Enchantment
|
||||
K:Hideaway:5
|
||||
T:Mode$ SpellCast | ValidCard$ Card.MultiColor | ValidActivatingPlayer$ You | Execute$ TrigToken | TriggerZones$ Battlefield | TriggerDescription$ Whenever you cast a multicolored spell, create a Treasure token. Then, you may pay {W}{U}{B}{R}{G}. If you do, you may play the exiled card without paying its mana cost.
|
||||
SVar:TrigToken:DB$ Token | TokenScript$ c_a_treasure_sac | SubAbility$ DBPlay
|
||||
SVar:DBPlay:DB$ Play | UnlessCost$ W U B R G | UnlessSwitched$ True | UnlessPayer$ You | ConditionPresent$ Card.IsRemembered | ConditionZone$ Exile | Defined$ Remembered | Amount$ All | Controller$ You | WithoutManaCost$ True | Optional$ True
|
||||
AI:RemoveDeck:Random
|
||||
SVar:BuffedBy:Card.MultiColor
|
||||
DeckHas:Ability$Token|Sacrifice & Type$Treasure|Artifact
|
||||
Oracle:Hideaway 5 (When this enchantment enters the battlefield, look at the top five cards of your library, exile one face down, then put the rest on the bottom in a random order.)\nWhenever you cast a multicolored spell, create a Treasure token. Then, you may pay {W}{U}{B}{R}{G}. If you do, you may play the exiled card without paying its mana cost.
|
||||
@@ -0,0 +1,8 @@
|
||||
Name:Witness Protection
|
||||
ManaCost:U
|
||||
Types:Enchantment Aura
|
||||
K:Enchant creature
|
||||
A:SP$ Attach | ValidTgts$ Creature | AILogic$ Curse
|
||||
S:Mode$ Continuous | Affected$ Creature.EnchantedBy | SetPower$ 1 | SetToughness$ 1 | SetColor$ Green & White | RemoveAllAbilities$ True | AddType$ Creature & Citizen | SetName$ Legitimate Businessperson | RemoveCardTypes$ True | RemoveCreatureTypes$ True | Description$ Enchanted creature loses all abilities and is a green and white Citizen creature with base power and toughness 1/1 named Legitimate Businessperson. (It loses all other colors, card types, creature types, and names.)
|
||||
SVar:NonStackingAttachEffect:True
|
||||
Oracle:Enchant creature\nEnchanted creature loses all abilities and is a green and white Citizen creature with base power and toughness 1/1 named Legitimate Businessperson. (It loses all other colors, card types, creature types, and names.)
|
||||
8
forge-gui/res/cardsfolder/upcoming/witty_roastmaster.txt
Normal file
8
forge-gui/res/cardsfolder/upcoming/witty_roastmaster.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
Name:Witty Roastmaster
|
||||
ManaCost:2 R
|
||||
Types:Creature Devil Citizen
|
||||
PT:3/2
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.Other+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigDmg | TriggerDescription$ Alliance — Whenever another creature enters the battlefield under your control, CARDNAME deals 1 damage to each opponent.
|
||||
SVar:TrigDmg:DB$ DealDamage | Defined$ Player.Opponent | NumDmg$ 1
|
||||
SVar:BuffedBy:Creature
|
||||
Oracle:Alliance — Whenever another creature enters the battlefield under your control, Witty Roastmaster deals 1 damage to each opponent.
|
||||
12
forge-gui/res/cardsfolder/upcoming/workshop_warchief.txt
Normal file
12
forge-gui/res/cardsfolder/upcoming/workshop_warchief.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
Name:Workshop Warchief
|
||||
ManaCost:3 G G
|
||||
Types:Creature Rhino Warrior
|
||||
PT:5/3
|
||||
K:Trample
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigGainLife | TriggerDescription$ When CARDNAME enters the battlefield, you gain 3 life.
|
||||
SVar:TrigGainLife:DB$ GainLife | LifeAmount$ 3
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME dies, create a 4/4 green Rhino Warrior creature token.
|
||||
SVar:TrigToken:DB$ Token | TokenScript$ g_4_4_rhino_warrior
|
||||
K:Blitz:4 G G
|
||||
DeckHas:Ability$LifeGain|Token|Sacrifice
|
||||
Oracle:Trample\nWhen Workshop Warchief enters the battlefield, you gain 3 life.\nWhen Workshop Warchief dies, create a 4/4 green Rhino Warrior creature token.\nBlitz {4}{G}{G} (If you cast this spell for its blitz cost, it gains haste and "When this creature dies, draw a card." Sacrifice it at the beginning of the next end step.)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user