mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 19:28:01 +00:00
Compare commits
25 Commits
bestowStat
...
forge-2.0.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a29da54b2e | ||
|
|
ec63b230c8 | ||
|
|
e880a83df2 | ||
|
|
80cc7218a3 | ||
|
|
4809fb858a | ||
|
|
3af62888dc | ||
|
|
79e1d0a0f0 | ||
|
|
c447dfc888 | ||
|
|
8149966915 | ||
|
|
472f9481e8 | ||
|
|
2209ce3cee | ||
|
|
258c89e65d | ||
|
|
11913085ef | ||
|
|
53fca12a57 | ||
|
|
8e8a795f19 | ||
|
|
a4b27321ac | ||
|
|
ead83d932f | ||
|
|
900bd4327d | ||
|
|
1a2bb054f4 | ||
|
|
f908df46c8 | ||
|
|
f8c97842c4 | ||
|
|
c324b45025 | ||
|
|
5061ceda0e | ||
|
|
d1e677eb4f | ||
|
|
493a8f351b |
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>${revision}</version>
|
||||
<version>2.0.02</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>${revision}</version>
|
||||
<version>2.0.02</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-ai</artifactId>
|
||||
|
||||
@@ -22,7 +22,6 @@ import forge.game.player.Player;
|
||||
import forge.game.player.PlayerActionConfirmMode;
|
||||
import forge.game.spellability.AbilitySub;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.spellability.SpellAbilityStackInstance;
|
||||
import forge.game.spellability.TargetRestrictions;
|
||||
import forge.game.staticability.StaticAbilityMustTarget;
|
||||
import forge.game.zone.ZoneType;
|
||||
@@ -138,8 +137,6 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
if (aiLogic != null) {
|
||||
if (aiLogic.equals("Always")) {
|
||||
return true;
|
||||
} else if (aiLogic.startsWith("ExileSpell")) {
|
||||
return doExileSpellLogic(aiPlayer, sa);
|
||||
} else if (aiLogic.startsWith("SacAndUpgrade")) { // Birthing Pod, Natural Order, etc.
|
||||
return doSacAndUpgradeLogic(aiPlayer, sa);
|
||||
} else if (aiLogic.startsWith("SacAndRetFromGrave")) { // Recurring Nightmare, etc.
|
||||
@@ -878,6 +875,10 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
origin.addAll(ZoneType.listValueOf(sa.getParam("TgtZone")));
|
||||
}
|
||||
|
||||
if (origin.contains(ZoneType.Stack) && doExileSpellLogic(ai, sa, mandatory)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final ZoneType destination = ZoneType.smartValueOf(sa.getParam("Destination"));
|
||||
final Game game = ai.getGame();
|
||||
|
||||
@@ -902,7 +903,6 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
}
|
||||
CardCollection list = CardLists.getTargetableCards(game.getCardsIn(origin), sa);
|
||||
|
||||
// Filter AI-specific targets if provided
|
||||
list = ComputerUtil.filterAITgts(sa, ai, list, true);
|
||||
if (sa.hasParam("AITgtsOnlyBetterThanSelf")) {
|
||||
list = CardLists.filter(list, card -> ComputerUtilCard.evaluateCreature(card) > ComputerUtilCard.evaluateCreature(source) + 30);
|
||||
@@ -2061,33 +2061,26 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean doExileSpellLogic(final Player aiPlayer, final SpellAbility sa) {
|
||||
String aiLogic = sa.getParamOrDefault("AILogic", "");
|
||||
SpellAbilityStackInstance top = aiPlayer.getGame().getStack().peek();
|
||||
List<ApiType> dangerousApi = Arrays.asList(ApiType.DealDamage, ApiType.DamageAll, ApiType.Destroy, ApiType.DestroyAll, ApiType.Sacrifice, ApiType.SacrificeAll);
|
||||
int manaCost = 0;
|
||||
int minCost = 0;
|
||||
|
||||
if (aiLogic.contains(".")) {
|
||||
minCost = Integer.parseInt(aiLogic.substring(aiLogic.indexOf(".") + 1));
|
||||
private static boolean doExileSpellLogic(final Player ai, final SpellAbility sa, final boolean mandatory) {
|
||||
List<ApiType> dangerousApi = null;
|
||||
CardCollection spells = new CardCollection(ai.getGame().getStackZone().getCards());
|
||||
Collections.reverse(spells);
|
||||
if (!mandatory && !spells.isEmpty()) {
|
||||
spells = spells.subList(0, 1);
|
||||
spells = ComputerUtil.filterAITgts(sa, ai, spells, true);
|
||||
dangerousApi = Arrays.asList(ApiType.DealDamage, ApiType.DamageAll, ApiType.Destroy, ApiType.DestroyAll, ApiType.Sacrifice, ApiType.SacrificeAll);
|
||||
}
|
||||
|
||||
if (top != null) {
|
||||
SpellAbility topSA = top.getSpellAbility();
|
||||
if (topSA != null) {
|
||||
if (topSA.getPayCosts().hasManaCost()) {
|
||||
manaCost = topSA.getPayCosts().getTotalMana().getCMC();
|
||||
}
|
||||
|
||||
if ((manaCost >= minCost || dangerousApi.contains(topSA.getApi()))
|
||||
&& topSA.getActivatingPlayer().isOpponentOf(aiPlayer)
|
||||
&& sa.canTargetSpellAbility(topSA)) {
|
||||
for (Card c : spells) {
|
||||
SpellAbility topSA = ai.getGame().getStack().getSpellMatchingHost(c);
|
||||
if (topSA != null && (dangerousApi == null ||
|
||||
(dangerousApi.contains(topSA.getApi()) && topSA.getActivatingPlayer().isOpponentOf(ai)))
|
||||
&& sa.canTarget(topSA)) {
|
||||
sa.resetTargets();
|
||||
sa.getTargets().add(topSA);
|
||||
return sa.isTargetNumberValid();
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>${revision}</version>
|
||||
<version>2.0.02</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-core</artifactId>
|
||||
|
||||
@@ -222,7 +222,7 @@ final class CardFace implements ICardFace, Cloneable {
|
||||
else variant.replacements.addAll(0, this.replacements);
|
||||
|
||||
if(variant.variables == null) variant.variables = this.variables;
|
||||
else variant.variables.putAll(this.variables);
|
||||
else this.variables.forEach((k, v) -> variant.variables.putIfAbsent(k, v));
|
||||
|
||||
if(variant.nonAbilityText == null) variant.nonAbilityText = this.nonAbilityText;
|
||||
if(variant.draftActions == null) variant.draftActions = this.draftActions;
|
||||
|
||||
@@ -472,7 +472,8 @@ public class DeckRecognizer {
|
||||
"side", "sideboard", "sb",
|
||||
"main", "card", "mainboard",
|
||||
"avatar", "commander", "schemes",
|
||||
"conspiracy", "planes", "deck", "dungeon"};
|
||||
"conspiracy", "planes", "deck", "dungeon",
|
||||
"attractions", "contraptions"};
|
||||
|
||||
private static CharSequence[] allCardTypes(){
|
||||
List<String> cardTypesList = new ArrayList<>();
|
||||
@@ -670,6 +671,9 @@ public class DeckRecognizer {
|
||||
// ok so the card has been found - let's see if there's any restriction on the set
|
||||
return checkAndSetCardToken(pc, edition, cardCount, deckSecFromCardLine,
|
||||
currentDeckSection, true);
|
||||
// On the off chance we accidentally interpreted part of the card's name as a set code, e.g. "Tyrranax Rex"
|
||||
if (data.isMTGCard(cardName + " " + setCode))
|
||||
continue;
|
||||
// UNKNOWN card as in the Counterspell|FEM case
|
||||
return Token.UnknownCard(cardName, setCode, cardCount);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>${revision}</version>
|
||||
<version>2.0.02</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-game</artifactId>
|
||||
|
||||
@@ -705,7 +705,7 @@ public class GameAction {
|
||||
StaticAbility stAb = eff.addStaticAbility(AbilityUtils.getSVar(cause, cause.getParam("StaticEffect")));
|
||||
stAb.setActiveZone(EnumSet.of(ZoneType.Command));
|
||||
// needed for ETB lookahead like Bronzehide Lion
|
||||
stAb.putParam("AffectedZone", "Battlefield,Hand,Graveyard,Exile,Stack,Library,Command");
|
||||
stAb.putParam("AffectedZone", "All");
|
||||
SpellAbilityEffect.addForgetOnMovedTrigger(eff, "Battlefield");
|
||||
game.getAction().moveToCommand(eff, cause);
|
||||
}
|
||||
|
||||
@@ -3704,6 +3704,10 @@ public class AbilityUtils {
|
||||
return doXMath(amount, m, source, ctb);
|
||||
}
|
||||
|
||||
if (value.equals("AttractionsVisitedThisTurn")) {
|
||||
return doXMath(player.getAttractionsVisitedThisTurn(), m, source, ctb);
|
||||
}
|
||||
|
||||
if (value.startsWith("PlaneswalkedToThisTurn")) {
|
||||
int found = 0;
|
||||
String name = value.split(" ")[1];
|
||||
|
||||
@@ -107,11 +107,9 @@ public class ChangeZoneAllEffect extends SpellAbilityEffect {
|
||||
final Zone originZone = game.getZoneOf(c);
|
||||
|
||||
// Fizzle spells so that they are removed from stack (e.g. Summary Dismissal)
|
||||
if (sa.hasParam("Fizzle")) {
|
||||
if (originZone.is(ZoneType.Exile) || originZone.is(ZoneType.Hand) || originZone.is(ZoneType.Stack)) {
|
||||
if (originZone.is(ZoneType.Stack)) {
|
||||
game.getStack().remove(c);
|
||||
}
|
||||
}
|
||||
|
||||
if (remLKI) {
|
||||
source.addRemembered(CardCopyService.getLKICopy(c));
|
||||
|
||||
@@ -558,22 +558,15 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (originZone.is(ZoneType.Stack)) {
|
||||
game.getStack().remove(gameCard);
|
||||
}
|
||||
|
||||
Card movedCard = null;
|
||||
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
|
||||
AbilityKey.addCardZoneTableParams(moveParams, triggerList);
|
||||
|
||||
if (destination.equals(ZoneType.Library)) {
|
||||
// If a card is moved to library from the stack, remove its spells from the stack
|
||||
if (sa.hasParam("Fizzle")) {
|
||||
// TODO only AI still targets as card, try to remove it
|
||||
if (gameCard.isInZone(ZoneType.Exile) || gameCard.isInZone(ZoneType.Hand) || gameCard.isInZone(ZoneType.Stack)) {
|
||||
// This only fizzles spells, not anything else.
|
||||
game.getStack().remove(gameCard);
|
||||
}
|
||||
}
|
||||
|
||||
movedCard = game.getAction().moveToLibrary(gameCard, libraryPosition, sa, moveParams);
|
||||
} else if (destination.equals(ZoneType.Battlefield)) {
|
||||
if (destination.equals(ZoneType.Battlefield)) {
|
||||
moveParams.put(AbilityKey.SimultaneousETB, tgtCards);
|
||||
if (sa.isReplacementAbility()) {
|
||||
ReplacementEffect re = sa.getReplacementEffect();
|
||||
@@ -725,15 +718,6 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
||||
commandCards.add(movedCard); //add to list to reveal the commandzone cards
|
||||
}
|
||||
|
||||
// If a card is Exiled from the stack, remove its spells from the stack
|
||||
if (sa.hasParam("Fizzle")) {
|
||||
if (gameCard.isInZone(ZoneType.Exile) || gameCard.isInZone(ZoneType.Hand)
|
||||
|| gameCard.isInZone(ZoneType.Stack) || gameCard.isInZone(ZoneType.Command)) {
|
||||
// This only fizzles spells, not anything else.
|
||||
game.getStack().remove(gameCard);
|
||||
}
|
||||
}
|
||||
|
||||
if (sa.hasParam("WithCountersType")) {
|
||||
CounterType cType = CounterType.getType(sa.getParam("WithCountersType"));
|
||||
int cAmount = AbilityUtils.calculateAmount(hostCard, sa.getParamOrDefault("WithCountersAmount", "1"), sa);
|
||||
|
||||
@@ -257,7 +257,7 @@ public class CounterEffect extends SpellAbilityEffect {
|
||||
|
||||
params.put(AbilityKey.StackSa, tgtSA);
|
||||
|
||||
String destination = srcSA.hasParam("Destination") ? srcSA.getParam("Destination") : tgtSA.isAftermath() ? "Exile" : "Graveyard";
|
||||
String destination = srcSA.getParamOrDefault("Destination", "Graveyard");
|
||||
if (srcSA.hasParam("DestinationChoice")) { //Hinder
|
||||
List<String> pos = Arrays.asList(srcSA.getParam("DestinationChoice").split(","));
|
||||
destination = srcSA.getActivatingPlayer().getController().chooseSomeType(Localizer.getInstance().getMessage("lblRemoveDestination"), tgtSA, pos);
|
||||
|
||||
@@ -32,6 +32,7 @@ public class ManaEffect extends SpellAbilityEffect {
|
||||
@Override
|
||||
public void resolve(SpellAbility sa) {
|
||||
final Card card = sa.getHostCard();
|
||||
final Game game = card.getGame();
|
||||
final AbilityManaPart abMana = sa.getManaPart();
|
||||
final List<Player> tgtPlayers = getDefinedPlayersOrTargeted(sa);
|
||||
final Player activator = sa.getActivatingPlayer();
|
||||
@@ -39,10 +40,7 @@ public class ManaEffect extends SpellAbilityEffect {
|
||||
// Spells are not undoable
|
||||
sa.setUndoable(sa.isAbility() && sa.isUndoable() && tgtPlayers.size() < 2 && !sa.hasParam("ActivationLimit"));
|
||||
|
||||
final boolean optional = sa.hasParam("Optional");
|
||||
final Game game = activator.getGame();
|
||||
|
||||
if (optional && !activator.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWantAddMana"), null)) {
|
||||
if (sa.hasParam("Optional") && !activator.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoYouWantAddMana"), null)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -340,6 +340,8 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
||||
protected boolean renderForUi = true;
|
||||
private final CardView view;
|
||||
|
||||
private String overlayText = null;
|
||||
|
||||
private SpellAbility[] basicLandAbilities = new SpellAbility[MagicColor.WUBRG.length];
|
||||
|
||||
private int planeswalkerAbilityActivated;
|
||||
@@ -6826,6 +6828,17 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
|
||||
return getType().hasStringType("Class");
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a string as an overlay on top of this card (similar to the way counter text is shown).
|
||||
*/
|
||||
public void setOverlayText(String overlayText) {
|
||||
this.overlayText = overlayText;
|
||||
view.updateMarkerText(this);
|
||||
}
|
||||
public String getOverlayText() {
|
||||
return this.overlayText;
|
||||
}
|
||||
|
||||
public final void animateBestow() {
|
||||
animateBestow(true);
|
||||
}
|
||||
|
||||
@@ -214,8 +214,8 @@ public class CardCopyService {
|
||||
if (cachedCard != null) {
|
||||
return cachedCard;
|
||||
}
|
||||
String msg = "CardUtil:getLKICopy copy object";
|
||||
|
||||
String msg = "CardUtil:getLKICopy copy object";
|
||||
Breadcrumb bread = new Breadcrumb(msg);
|
||||
bread.setData("Card", copyFrom.getName());
|
||||
bread.setData("CardState", copyFrom.getCurrentStateName().toString());
|
||||
@@ -304,22 +304,20 @@ public class CardCopyService {
|
||||
|
||||
newCopy.setCounters(Maps.newHashMap(copyFrom.getCounters()));
|
||||
|
||||
newCopy.setColor(copyFrom.getColor().getColor());
|
||||
newCopy.setPhasedOut(copyFrom.getPhasedOut());
|
||||
newCopy.setTapped(copyFrom.isTapped());
|
||||
newCopy.setTributed(copyFrom.isTributed());
|
||||
newCopy.setMonstrous(copyFrom.isMonstrous());
|
||||
newCopy.setRenowned(copyFrom.isRenowned());
|
||||
newCopy.setSolved(copyFrom.isSolved());
|
||||
newCopy.setSaddled(copyFrom.isSaddled());
|
||||
newCopy.setPromisedGift(copyFrom.getPromisedGift());
|
||||
newCopy.setSaddled(copyFrom.isSaddled());
|
||||
if (newCopy.isSaddled()) newCopy.setSaddledByThisTurn(copyFrom.getSaddledByThisTurn());
|
||||
if (copyFrom.isSuspected()) {
|
||||
newCopy.setSuspectedEffect(getLKICopy(copyFrom.getSuspectedEffect(), cachedMap));
|
||||
}
|
||||
|
||||
newCopy.setColor(copyFrom.getColor().getColor());
|
||||
newCopy.setPhasedOut(copyFrom.getPhasedOut());
|
||||
|
||||
newCopy.setTapped(copyFrom.isTapped());
|
||||
|
||||
newCopy.setDamageHistory(copyFrom.getDamageHistory());
|
||||
newCopy.setDamageReceivedThisTurn(copyFrom.getDamageReceivedThisTurn());
|
||||
newCopy.setExcessDamageReceivedThisTurn(copyFrom.getExcessDamageThisTurn());
|
||||
@@ -354,8 +352,6 @@ public class CardCopyService {
|
||||
}
|
||||
newCopy.setChosenEvenOdd(copyFrom.getChosenEvenOdd());
|
||||
|
||||
//newCopy.getEtbCounters().putAll(copyFrom.getEtbCounters());
|
||||
|
||||
newCopy.setUnearthed(copyFrom.isUnearthed());
|
||||
|
||||
newCopy.copyFrom(copyFrom);
|
||||
|
||||
@@ -3764,6 +3764,8 @@ public class CardFactoryUtil {
|
||||
desc = "Basic land";
|
||||
} else if (type.equals("Land.Artifact")) {
|
||||
desc = "Artifact land";
|
||||
} else if (type.startsWith("Card.with")) {
|
||||
desc = type.substring(9);
|
||||
}
|
||||
|
||||
sb.append(" Discard<1/CARDNAME> | ActivationZone$ Hand | PrecostDesc$ ").append(desc).append("cycling ");
|
||||
@@ -3784,17 +3786,20 @@ public class CardFactoryUtil {
|
||||
if (keyword.startsWith("Affinity")) {
|
||||
final String[] k = keyword.split(":");
|
||||
final String t = k[1];
|
||||
String d = "";
|
||||
if (k.length > 2) {
|
||||
final StringBuilder s = new StringBuilder();
|
||||
s.append(k[2]).append("s");
|
||||
d = s.toString();
|
||||
}
|
||||
|
||||
String desc = "Artifact".equals(t) ? "artifacts" : CardType.getPluralType(t);
|
||||
if (!d.isEmpty()) {
|
||||
desc = d;
|
||||
String desc;
|
||||
if(k.length > 2) {
|
||||
String typeText = k[2];
|
||||
if(typeText.contains(" with "))
|
||||
desc = typeText.substring(typeText.indexOf(" with ") + 6);
|
||||
else
|
||||
desc = typeText + "s";
|
||||
}
|
||||
else if ("Artifact".equals(t))
|
||||
desc = "artifacts";
|
||||
else
|
||||
desc = CardType.getPluralType(t);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ AffinityX | EffectZone$ All");
|
||||
sb.append("| Description$ Affinity for ").append(desc);
|
||||
|
||||
@@ -491,6 +491,7 @@ public class CardView extends GameEntityView {
|
||||
}
|
||||
void updateCurrentRoom(Card c) {
|
||||
set(TrackableProperty.CurrentRoom, c.getCurrentRoom());
|
||||
updateMarkerText(c);
|
||||
}
|
||||
|
||||
public int getIntensity() {
|
||||
@@ -514,6 +515,7 @@ public class CardView extends GameEntityView {
|
||||
}
|
||||
void updateClassLevel(Card c) {
|
||||
set(TrackableProperty.ClassLevel, c.getClassLevel());
|
||||
updateMarkerText(c);
|
||||
}
|
||||
|
||||
public int getRingLevel() {
|
||||
@@ -525,6 +527,41 @@ public class CardView extends GameEntityView {
|
||||
set(TrackableProperty.RingLevel, p.getNumRingTemptedYou());
|
||||
}
|
||||
|
||||
public String getOverlayText() {
|
||||
return get(TrackableProperty.OverlayText);
|
||||
}
|
||||
public List<String> getMarkerText() {
|
||||
return get(TrackableProperty.MarkerText);
|
||||
}
|
||||
void updateMarkerText(Card c) {
|
||||
List<String> markerItems = new ArrayList<>();
|
||||
if(c.getCurrentRoom() != null && !c.getCurrentRoom().isEmpty()) {
|
||||
markerItems.add("In Room:");
|
||||
markerItems.add(c.getCurrentRoom());
|
||||
}
|
||||
if(c.isClassCard() && c.isInZone(ZoneType.Battlefield)) {
|
||||
markerItems.add("CL:" + c.getClassLevel());
|
||||
}
|
||||
if(getRingLevel() > 0) {
|
||||
markerItems.add("RL:" + getRingLevel());
|
||||
}
|
||||
|
||||
if(StringUtils.isNotEmpty(c.getOverlayText())) {
|
||||
set(TrackableProperty.OverlayText, c.getOverlayText());
|
||||
markerItems.add(c.getOverlayText());
|
||||
}
|
||||
else {
|
||||
//Overlay text is any custom string. It gets mixed in with the other marker lines, but it also needs its
|
||||
//own property so that it can display in the card detail text.
|
||||
set(TrackableProperty.OverlayText, null);
|
||||
}
|
||||
|
||||
if(markerItems.isEmpty())
|
||||
set(TrackableProperty.MarkerText, null);
|
||||
else
|
||||
set(TrackableProperty.MarkerText, markerItems);
|
||||
}
|
||||
|
||||
private String getRemembered() {
|
||||
return get(TrackableProperty.Remembered);
|
||||
}
|
||||
@@ -974,6 +1011,7 @@ public class CardView extends GameEntityView {
|
||||
updateDamage(c);
|
||||
updateSpecialize(c);
|
||||
updateRingLevel(c);
|
||||
updateMarkerText(c);
|
||||
|
||||
if (c.getIntensity(false) > 0) {
|
||||
updateIntensity(c);
|
||||
|
||||
@@ -95,8 +95,6 @@ public enum CounterEnumType {
|
||||
|
||||
CORRUPTION("CRPTN", 210, 121, 210),
|
||||
|
||||
CRANK("CRANK!", 181, 148, 15),
|
||||
|
||||
CROAK("CROAK", 155, 255, 5),
|
||||
|
||||
CREDIT("CRDIT", 188, 197, 234),
|
||||
|
||||
@@ -26,6 +26,8 @@ public class KeywordWithCostAndType extends KeywordInstance<KeywordWithCostAndTy
|
||||
n[i] = "basic land";
|
||||
} else if (n[i].equals("Land.Artifact")) {
|
||||
n[i] = "artifact land";
|
||||
} else if (n[i].startsWith("Card.with")) {
|
||||
n[i] = n[i].substring(9);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -112,6 +112,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
private int expentThisTurn;
|
||||
private int numLibrarySearchedOwn; //The number of times this player has searched his library
|
||||
private int venturedThisTurn;
|
||||
private int attractionsVisitedThisTurn;
|
||||
private int descended;
|
||||
private int numRingTemptedYou;
|
||||
private int devotionMod;
|
||||
@@ -189,7 +190,6 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
private final Map<Card, Integer> commanderCast = Maps.newHashMap();
|
||||
private final Map<Card, Integer> commanderDamage = Maps.newHashMap();
|
||||
private DetachedCardEffect commanderEffect = null;
|
||||
private DetachedCardEffect speedEffect;
|
||||
|
||||
private Card monarchEffect;
|
||||
private Card initiativeEffect;
|
||||
@@ -197,6 +197,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
private Card contraptionSprocketEffect;
|
||||
private Card radiationEffect;
|
||||
private Card keywordEffect;
|
||||
private Card speedEffect;
|
||||
|
||||
private Map<Long, Integer> additionalVotes = Maps.newHashMap();
|
||||
private Map<Long, Integer> additionalOptionalVotes = Maps.newHashMap();
|
||||
@@ -237,10 +238,6 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
return achievementTracker;
|
||||
}
|
||||
|
||||
public final PlayerOutcome getOutcome() {
|
||||
return stats.getOutcome();
|
||||
}
|
||||
|
||||
private String chooseName(String originalName) {
|
||||
String nameCandidate = originalName;
|
||||
for (int i = 2; i <= 8; i++) { // several tries, not matter how many
|
||||
@@ -1333,6 +1330,25 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
return drawn;
|
||||
}
|
||||
|
||||
public final void resetNumDrawnThisDrawStep() {
|
||||
numDrawnThisDrawStep = 0;
|
||||
}
|
||||
|
||||
public final void resetNumDrawnThisTurn() {
|
||||
numDrawnThisTurn = 0;
|
||||
view.updateNumDrawnThisTurn(this);
|
||||
}
|
||||
|
||||
public final int getNumDrawnThisTurn() {
|
||||
return numDrawnThisTurn;
|
||||
}
|
||||
public final int getNumDrawnLastTurn() {
|
||||
return numDrawnLastTurn;
|
||||
}
|
||||
public final int numDrawnThisDrawStep() {
|
||||
return numDrawnThisDrawStep;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns PlayerZone corresponding to the given zone of game.
|
||||
*/
|
||||
@@ -1360,7 +1376,6 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public final CardCollectionView getCardsIn(final ZoneType zoneType) {
|
||||
return getCardsIn(zoneType, true);
|
||||
}
|
||||
@@ -1448,35 +1463,12 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
return CardCollection.combine(getCardsIn(Player.ALL_ZONES), getCardsIn(ZoneType.Stack), inboundTokens);
|
||||
}
|
||||
|
||||
public final void resetNumDrawnThisDrawStep() {
|
||||
numDrawnThisDrawStep = 0;
|
||||
}
|
||||
|
||||
public final void resetNumDrawnThisTurn() {
|
||||
numDrawnThisTurn = 0;
|
||||
view.updateNumDrawnThisTurn(this);
|
||||
}
|
||||
|
||||
public final int getNumDrawnThisTurn() {
|
||||
return numDrawnThisTurn;
|
||||
}
|
||||
|
||||
public final int getNumDrawnLastTurn() {
|
||||
return numDrawnLastTurn;
|
||||
}
|
||||
|
||||
public final int numDrawnThisDrawStep() {
|
||||
return numDrawnThisDrawStep;
|
||||
}
|
||||
|
||||
public final void resetNumRollsThisTurn() {
|
||||
numRollsThisTurn = 0;
|
||||
}
|
||||
|
||||
public final int getNumRollsThisTurn() {
|
||||
return numRollsThisTurn;
|
||||
}
|
||||
|
||||
public void roll() {
|
||||
numRollsThisTurn++;
|
||||
}
|
||||
@@ -1954,37 +1946,23 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
completedDungeons.clear();
|
||||
}
|
||||
|
||||
public final int getNumRingTemptedYou() {
|
||||
return numRingTemptedYou;
|
||||
}
|
||||
public final void incrementRingTemptedYou() {
|
||||
numRingTemptedYou++;
|
||||
}
|
||||
public final void setNumRingTemptedYou(int value) {
|
||||
numRingTemptedYou = value;
|
||||
}
|
||||
public final void resetRingTemptedYou() {
|
||||
numRingTemptedYou = 0;
|
||||
}
|
||||
|
||||
public final int getSpeed() {
|
||||
return speed;
|
||||
}
|
||||
public final void increaseSpeed() {
|
||||
if (speedEffect == null) createSpeedEffect();
|
||||
if (!maxSpeed()) { // can't increase past 4
|
||||
int old = speed;
|
||||
speed++;
|
||||
view.updateSpeed(this);
|
||||
getGame().fireEvent(new GameEventSpeedChanged(this, old, speed)); //play sound effect
|
||||
updateSpeedEffect();
|
||||
}
|
||||
}
|
||||
public final void decreaseSpeed() {
|
||||
if (speed > 1) { // can't decrease speed below 1
|
||||
int old = speed;
|
||||
speed--;
|
||||
view.updateSpeed(this);
|
||||
game.fireEvent(new GameEventSpeedChanged(this, old, speed));
|
||||
updateSpeedEffect();
|
||||
}
|
||||
}
|
||||
public final boolean noSpeed() {
|
||||
@@ -1995,26 +1973,62 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
}
|
||||
public final void setSpeed(int i) { //just used for copy/save
|
||||
speed = i;
|
||||
if (speed > 0) view.updateSpeed(this);
|
||||
if(this.speedEffect != null)
|
||||
updateSpeedEffect();
|
||||
}
|
||||
public final void createSpeedEffect() {
|
||||
final PlayerZone com = getZone(ZoneType.Command);
|
||||
DetachedCardEffect eff = new DetachedCardEffect(this, "Speed Effect");
|
||||
if(this.speedEffect != null || this.noSpeed())
|
||||
return;
|
||||
|
||||
speedEffect = new Card(game.nextCardId(), null, game);
|
||||
speedEffect.setOwner(this);
|
||||
speedEffect.setGamePieceType(GamePieceType.EFFECT);
|
||||
|
||||
speedEffect.addAlternateState(CardStateName.Flipped, false);
|
||||
CardState speedFront = speedEffect.getState(CardStateName.Original);
|
||||
CardState speedBack = speedEffect.getState(CardStateName.Flipped);
|
||||
|
||||
speedFront.setImageKey("t:speed");
|
||||
speedFront.setName("Start Your Engines!");
|
||||
|
||||
speedBack.setImageKey("t:max_speed");
|
||||
speedBack.setName("Max Speed!");
|
||||
|
||||
String label = Localizer.getInstance().getMessage("lblSpeed", this.speed);
|
||||
speedEffect.setOverlayText(label);
|
||||
|
||||
// 702.179d There is an inherent triggered ability associated with a player having 1 or more speed. This ability has no source and is controlled by that player.
|
||||
// That ability is “Whenever one or more opponents lose life during your turn, if your speed is less than 4, your speed increases by 1. This ability triggers only once each turn.”
|
||||
String trigger = "Mode$ LifeLostAll | ValidPlayer$ Opponent | TriggerZones$ Command | ActivationLimit$ 1 | " +
|
||||
"PlayerTurn$ True | CheckSVar$ Count$YourSpeed | SVarCompare$ LT4 | "
|
||||
+ "TriggerDescription$ Whenever one or more opponents lose life during your turn, if your speed is less than 4, your speed increases by 1. This ability triggers only once each turn.";
|
||||
String speedUp = "DB$ ChangeSpeed";
|
||||
Trigger lifeLostTrigger = TriggerHandler.parseTrigger(trigger, eff, true);
|
||||
lifeLostTrigger.setOverridingAbility(AbilityFactory.getAbility(speedUp, eff));
|
||||
eff.addTrigger(lifeLostTrigger);
|
||||
this.speedEffect = eff;
|
||||
com.add(eff);
|
||||
}
|
||||
Trigger lifeLostTrigger = TriggerHandler.parseTrigger(trigger, speedEffect, true);
|
||||
lifeLostTrigger.setOverridingAbility(AbilityFactory.getAbility(speedUp, speedEffect));
|
||||
speedFront.addTrigger(lifeLostTrigger);
|
||||
|
||||
public final List<Card> getPlaneswalkedToThisTurn() {
|
||||
return planeswalkedToThisTurn;
|
||||
speedEffect.updateStateForView();
|
||||
|
||||
if(this.maxSpeed())
|
||||
speedEffect.setState(CardStateName.Flipped, true);
|
||||
|
||||
final PlayerZone com = getZone(ZoneType.Command);
|
||||
com.add(speedEffect);
|
||||
this.updateZoneForView(com);
|
||||
}
|
||||
protected void updateSpeedEffect() {
|
||||
if(this.speedEffect == null) {
|
||||
if(this.noSpeed())
|
||||
return;
|
||||
createSpeedEffect();
|
||||
}
|
||||
Localizer localizer = Localizer.getInstance();
|
||||
String label = this.maxSpeed() ? localizer.getMessage("lblMaxSpeed") : localizer.getMessage("lblSpeed", this.speed);
|
||||
speedEffect.setOverlayText(label);
|
||||
if(maxSpeed() && speedEffect.getCurrentStateName() == CardStateName.Original)
|
||||
speedEffect.setState(CardStateName.Flipped, true);
|
||||
else if(!maxSpeed() && speedEffect.getCurrentStateName() == CardStateName.Flipped)
|
||||
speedEffect.setState(CardStateName.Original, true);
|
||||
}
|
||||
|
||||
public final void altWinBySpellEffect(final String sourceName) {
|
||||
@@ -2477,6 +2491,9 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
return game.getMatch().getPlayers().get(game.getRegisteredPlayers().indexOf(this));
|
||||
}
|
||||
|
||||
public final PlayerOutcome getOutcome() {
|
||||
return stats.getOutcome();
|
||||
}
|
||||
private void setOutcome(PlayerOutcome outcome) {
|
||||
stats.setOutcome(outcome);
|
||||
}
|
||||
@@ -2573,6 +2590,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
setCommitedCrimeThisTurn(0);
|
||||
diceRollsThisTurn = Lists.newArrayList();
|
||||
setExpentThisTurn(0);
|
||||
attractionsVisitedThisTurn = 0;
|
||||
|
||||
damageReceivedThisTurn.clear();
|
||||
planeswalkedToThisTurn.clear();
|
||||
@@ -2705,6 +2723,10 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
return !isInGame();
|
||||
}
|
||||
|
||||
public final List<Card> getPlaneswalkedToThisTurn() {
|
||||
return planeswalkedToThisTurn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the top plane of the planar deck and put it face up in the command zone.
|
||||
* Then runs triggers.
|
||||
@@ -3391,6 +3413,19 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
getTheRing().updateStateForView();
|
||||
}
|
||||
|
||||
public final int getNumRingTemptedYou() {
|
||||
return numRingTemptedYou;
|
||||
}
|
||||
public final void incrementRingTemptedYou() {
|
||||
numRingTemptedYou++;
|
||||
}
|
||||
public final void setNumRingTemptedYou(int value) {
|
||||
numRingTemptedYou = value;
|
||||
}
|
||||
public final void resetRingTemptedYou() {
|
||||
numRingTemptedYou = 0;
|
||||
}
|
||||
|
||||
public void changeOwnership(Card card) {
|
||||
// If lost then gained, just clear out of lost.
|
||||
// If gained then lost, just clear out of gained.
|
||||
@@ -3615,6 +3650,26 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
return radiationEffect != null;
|
||||
}
|
||||
|
||||
public Card getKeywordCard() {
|
||||
if (keywordEffect != null) {
|
||||
return keywordEffect;
|
||||
}
|
||||
|
||||
final PlayerZone com = getZone(ZoneType.Command);
|
||||
|
||||
keywordEffect = new Card(game.nextCardId(), null, game);
|
||||
keywordEffect.setGamePieceType(GamePieceType.EFFECT);
|
||||
keywordEffect.setOwner(this);
|
||||
keywordEffect.setName("Keyword Effects");
|
||||
keywordEffect.setImageKey(ImageKeys.HIDDEN_CARD);
|
||||
|
||||
keywordEffect.updateStateForView();
|
||||
|
||||
com.add(keywordEffect);
|
||||
|
||||
this.updateZoneForView(com);
|
||||
return keywordEffect;
|
||||
}
|
||||
public void updateKeywordCardAbilityText() {
|
||||
if (getKeywordCard() == null)
|
||||
return;
|
||||
@@ -3739,27 +3794,6 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
|| !hasKeyword("Spells and abilities you control can't cause you to search your library.");
|
||||
}
|
||||
|
||||
public Card getKeywordCard() {
|
||||
if (keywordEffect != null) {
|
||||
return keywordEffect;
|
||||
}
|
||||
|
||||
final PlayerZone com = getZone(ZoneType.Command);
|
||||
|
||||
keywordEffect = new Card(game.nextCardId(), null, game);
|
||||
keywordEffect.setGamePieceType(GamePieceType.EFFECT);
|
||||
keywordEffect.setOwner(this);
|
||||
keywordEffect.setName("Keyword Effects");
|
||||
keywordEffect.setImageKey(ImageKeys.HIDDEN_CARD);
|
||||
|
||||
keywordEffect.updateStateForView();
|
||||
|
||||
com.add(keywordEffect);
|
||||
|
||||
this.updateZoneForView(com);
|
||||
return keywordEffect;
|
||||
}
|
||||
|
||||
public void addAdditionalVote(long timestamp, int value) {
|
||||
additionalVotes.put(timestamp, value);
|
||||
getView().updateAdditionalVote(this);
|
||||
@@ -3950,7 +3984,6 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
|
||||
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(this);
|
||||
game.getTriggerHandler().runTrigger(TriggerType.CommitCrime, runParams, false);
|
||||
|
||||
}
|
||||
|
||||
public int getCommittedCrimeThisTurn() {
|
||||
@@ -3977,12 +4010,17 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
public void visitAttractions(int light) {
|
||||
CardCollection attractions = CardLists.filter(getCardsIn(ZoneType.Battlefield), CardPredicates.isAttractionWithLight(light));
|
||||
for (Card c : attractions) {
|
||||
if(!c.wasVisitedThisTurn())
|
||||
this.attractionsVisitedThisTurn++;
|
||||
c.visitAttraction(this);
|
||||
}
|
||||
}
|
||||
public void rollToVisitAttractions() {
|
||||
this.visitAttractions(RollDiceEffect.rollDiceForPlayerToVisitAttractions(this));
|
||||
}
|
||||
public int getAttractionsVisitedThisTurn() {
|
||||
return this.attractionsVisitedThisTurn;
|
||||
}
|
||||
|
||||
public int getCrankCounter() {
|
||||
return this.crankCounter;
|
||||
@@ -3990,8 +4028,8 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
public void setCrankCounter(int counters) {
|
||||
this.crankCounter = counters;
|
||||
if (this.contraptionSprocketEffect != null) {
|
||||
Map<CounterType, Integer> counterMap = Map.of(CounterType.get(CounterEnumType.CRANK), this.crankCounter);
|
||||
contraptionSprocketEffect.setCounters(counterMap);
|
||||
String label = Localizer.getInstance().getMessage("lblCrank", this.crankCounter);
|
||||
contraptionSprocketEffect.setOverlayText(label);
|
||||
}
|
||||
else if (this.getCardsIn(ZoneType.Battlefield).anyMatch(CardPredicates.CONTRAPTIONS)) {
|
||||
this.createContraptionSprockets();
|
||||
@@ -4017,12 +4055,8 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
contraptionSprocketEffect.setName("Contraption Sprockets");
|
||||
contraptionSprocketEffect.setGamePieceType(GamePieceType.EFFECT);
|
||||
|
||||
//Add "counters" on the effect to represent the current CRANK counter position.
|
||||
//This and some other un-cards could benefit from a distinct system for positional counters or markers,
|
||||
//see for instance Baron von Count or B-I-N-G-O. For now this is sufficient to display the current sprocket
|
||||
//on the counter overlay, and I don't think any existing effect will notice it.
|
||||
Map<CounterType, Integer> counterMap = Map.of(CounterType.get(CounterEnumType.CRANK), this.crankCounter);
|
||||
contraptionSprocketEffect.setCounters(counterMap);
|
||||
String label = Localizer.getInstance().getMessage("lblCrank", this.crankCounter);
|
||||
contraptionSprocketEffect.setOverlayText(label);
|
||||
contraptionSprocketEffect.setText("At the beginning of your upkeep, if you control a Contraption, move the CRANK! counter to the next sprocket and crank any number of that sprocket's Contraptions.");
|
||||
|
||||
contraptionSprocketEffect.updateStateForView();
|
||||
|
||||
@@ -329,13 +329,6 @@ public class PlayerView extends GameEntityView {
|
||||
set(TrackableProperty.ControlVotes, val);
|
||||
}
|
||||
|
||||
public int getSpeed() {
|
||||
return get(TrackableProperty.Speed);
|
||||
}
|
||||
void updateSpeed(Player p) {
|
||||
set(TrackableProperty.Speed, p.getSpeed());
|
||||
}
|
||||
|
||||
public int getAdditionalVillainousChoices() {
|
||||
return get(TrackableProperty.AdditionalVillainousChoices);
|
||||
}
|
||||
@@ -604,10 +597,6 @@ public class PlayerView extends GameEntityView {
|
||||
}
|
||||
details.add(Localizer.getInstance().getMessage("lblExtraTurnCountHas", String.valueOf(getExtraTurnCount())));
|
||||
|
||||
if (getSpeed() > 0) {
|
||||
details.add(Localizer.getInstance().getMessage("lblSpeed", String.valueOf(getSpeed())));
|
||||
}
|
||||
|
||||
final String keywords = Lang.joinHomogenous(getDisplayableKeywords());
|
||||
if (!keywords.isEmpty()) {
|
||||
details.add(keywords);
|
||||
|
||||
@@ -344,12 +344,10 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone
|
||||
if (zone == null || !this.validHostZones.contains(zone.getZoneType())) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!getHostCard().isInPlay()) { // default
|
||||
} else if (!getHostCard().isInPlay()) { // default
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String condition = getParam("Condition");
|
||||
if (null != condition) {
|
||||
|
||||
@@ -917,12 +917,11 @@ public final class StaticAbilityContinuous {
|
||||
|
||||
private static ColorSet getColorsFromParam(StaticAbility stAb, final String colors) {
|
||||
final Card hostCard = stAb.getHostCard();
|
||||
ColorSet addColors;
|
||||
ColorSet addColors = null;
|
||||
if (colors.equals("ChosenColor")) {
|
||||
if (hostCard.hasChosenColor()) {
|
||||
addColors = ColorSet.fromNames(hostCard.getChosenColors());
|
||||
}
|
||||
return null;
|
||||
} else if (colors.equals("All")) {
|
||||
addColors = ColorSet.ALL_COLORS;
|
||||
} else {
|
||||
|
||||
@@ -384,17 +384,15 @@ public class TriggerHandler {
|
||||
return false; // It's not the right phase to go off.
|
||||
}
|
||||
|
||||
if (TriggerType.Always.equals(regtrig.getMode())) {
|
||||
if (game.getStack().hasStateTrigger(regtrig.getId())) {
|
||||
return false; // State triggers that are already on the stack
|
||||
// don't trigger again.
|
||||
}
|
||||
}
|
||||
|
||||
if (regtrig.isSuppressed()) {
|
||||
return false; // Trigger removed by effect
|
||||
}
|
||||
|
||||
if (TriggerType.Always.equals(regtrig.getMode()) && game.getStack().hasStateTrigger(regtrig.getId())) {
|
||||
return false; // State triggers that are already on the stack
|
||||
// don't trigger again.
|
||||
}
|
||||
|
||||
// do not check delayed
|
||||
if (regtrig.getSpawningAbility() == null && !regtrig.zonesCheck(game.getZoneOf(regtrig.getHostCard()))) {
|
||||
return false; // Host card isn't where it needs to be.
|
||||
@@ -415,6 +413,10 @@ public class TriggerHandler {
|
||||
return false; // Not the right mode.
|
||||
}
|
||||
|
||||
if (regtrig.isSuppressed()) {
|
||||
return false; // Trigger removed by effect
|
||||
}
|
||||
|
||||
/* this trigger can only be activated once per turn, verify it hasn't already run */
|
||||
if (!regtrig.checkActivationLimit()) {
|
||||
return false;
|
||||
@@ -431,21 +433,17 @@ public class TriggerHandler {
|
||||
if (!regtrig.performTest(runParams)) {
|
||||
return false; // Test failed.
|
||||
}
|
||||
if (regtrig.isSuppressed()) {
|
||||
return false; // Trigger removed by effect
|
||||
}
|
||||
|
||||
if (TriggerType.Always.equals(regtrig.getMode())) {
|
||||
if (game.getStack().hasStateTrigger(regtrig.getId())) {
|
||||
if (TriggerType.Always.equals(regtrig.getMode()) && game.getStack().hasStateTrigger(regtrig.getId())) {
|
||||
return false; // State triggers that are already on the stack
|
||||
// don't trigger again.
|
||||
}
|
||||
}
|
||||
|
||||
// check if any static abilities are disabling the trigger (Torpor Orb and the like)
|
||||
if (!regtrig.isStatic() && StaticAbilityDisableTriggers.disabled(game, regtrig, runParams)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -85,6 +85,8 @@ public enum TrackableProperty {
|
||||
RingLevel(TrackableTypes.IntegerType),
|
||||
CurrentRoom(TrackableTypes.StringType),
|
||||
Intensity(TrackableTypes.IntegerType),
|
||||
OverlayText(TrackableTypes.StringType),
|
||||
MarkerText(TrackableTypes.StringListType),
|
||||
Remembered(TrackableTypes.StringType),
|
||||
NamedCard(TrackableTypes.StringListType),
|
||||
PlayerMayLook(TrackableTypes.PlayerViewCollectionType, FreezeMode.IgnoresFreeze),
|
||||
@@ -217,7 +219,6 @@ public enum TrackableProperty {
|
||||
CommanderCast(TrackableTypes.IntegerMapType),
|
||||
CommanderDamage(TrackableTypes.IntegerMapType),
|
||||
MindSlaveMaster(TrackableTypes.PlayerViewType),
|
||||
Speed(TrackableTypes.IntegerType),
|
||||
|
||||
Ante(TrackableTypes.CardViewCollectionType, FreezeMode.IgnoresFreeze),
|
||||
Battlefield(TrackableTypes.CardViewCollectionType, FreezeMode.IgnoresFreeze), //zones can't respect freeze, otherwise cards that die from state based effects won't have that reflected in the UI
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>${revision}</version>
|
||||
<version>2.0.02</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-gui-android</artifactId>
|
||||
@@ -66,7 +66,7 @@
|
||||
<configuration>
|
||||
<!-- generate versionName from revision property to snapshot-version property -->
|
||||
<name>snapshot-version</name>
|
||||
<value>${revision}</value>
|
||||
<value>2.0.02-SNAPSHOT</value>
|
||||
<regex>-SNAPSHOT</regex>
|
||||
<replacement>-SNAPSHOT-${month.date}</replacement>
|
||||
<failIfNoMatch>false</failIfNoMatch>
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>${revision}</version>
|
||||
<version>2.0.02</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-gui-desktop</artifactId>
|
||||
@@ -50,7 +49,7 @@
|
||||
<configuration>
|
||||
<!-- generate versionName from revision property to snapshot-version property -->
|
||||
<name>snapshot-version</name>
|
||||
<value>${revision}</value>
|
||||
<value>2.0.02-SNAPSHOT</value>
|
||||
<regex>-SNAPSHOT</regex>
|
||||
<replacement>-SNAPSHOT-${month.date}</replacement>
|
||||
<failIfNoMatch>false</failIfNoMatch>
|
||||
@@ -489,31 +488,17 @@
|
||||
<mkdir dir="${project.build.directory}/${project.build.finalName}-osx" />
|
||||
<copy todir="${project.build.directory}/${project.build.finalName}-osx">
|
||||
<fileset dir="${basedir}/../forge-gui/" includes="LICENSE.txt" />
|
||||
<fileset dir="${basedir}/../forge-gui/release-files/"
|
||||
includes="CHANGES.txt"/>
|
||||
<fileset dir="${basedir}/../forge-gui/release-files/"
|
||||
includes="CONTRIBUTORS.txt"/>
|
||||
<fileset dir="${basedir}/../forge-gui/release-files/"
|
||||
includes="ISSUES.txt"/>
|
||||
<fileset dir="${basedir}/../forge-gui/release-files/"
|
||||
includes="INSTALLATION.txt"/>
|
||||
<fileset dir="${basedir}/../forge-gui/release-files/"
|
||||
includes="GAMEPAD_README.txt"/>
|
||||
<fileset dir="${basedir}/../forge-gui/release-files/" includes="CHANGES.txt" />
|
||||
<fileset dir="${basedir}/../forge-gui/release-files/" includes="CONTRIBUTORS.txt" />
|
||||
<fileset dir="${basedir}/../forge-gui/release-files/" includes="ISSUES.txt" />
|
||||
<fileset dir="${basedir}/../forge-gui/release-files/" includes="INSTALLATION.txt" />
|
||||
<fileset dir="${basedir}/../forge-gui/release-files/" includes="GAMEPAD_README.txt" />
|
||||
<fileset dir="${basedir}/../forge-gui/" includes="MANUAL.txt" />
|
||||
<fileset dir="${basedir}/" includes="sentry.properties" />
|
||||
</copy>
|
||||
<taskdef name="bundleapp"
|
||||
classpath="${basedir}/../forge-gui/${configSourceDirectory}/appbundler-1.0-custom.jar"
|
||||
classname="com.oracle.appbundler.AppBundlerTask"/>
|
||||
<bundleapp
|
||||
outputdirectory="${project.build.directory}/${project.build.finalName}-osx"
|
||||
name="${project.name}" displayname="${project.name}"
|
||||
shortversion="${project.version}" identifier="forge.view.Main"
|
||||
icon="${basedir}/${configSourceDirectory}/Forge.icns"
|
||||
applicationCategory="public.app-category.games"
|
||||
mainclassname="forge.view.Main">
|
||||
<classpath
|
||||
file="${project.build.directory}/${project.build.finalName}-jar-with-dependencies.jar"/>
|
||||
<taskdef name="bundleapp" classpath="${basedir}/../forge-gui/${configSourceDirectory}/appbundler-1.0-custom.jar" classname="com.oracle.appbundler.AppBundlerTask" />
|
||||
<bundleapp outputdirectory="${project.build.directory}/${project.build.finalName}-osx" name="${project.name}" displayname="${project.name}" shortversion="${project.version}" identifier="forge.view.Main" icon="${basedir}/${configSourceDirectory}/Forge.icns" applicationCategory="public.app-category.games" mainclassname="forge.view.Main">
|
||||
<classpath file="${project.build.directory}/${project.build.finalName}-jar-with-dependencies.jar" />
|
||||
<classpath file="${basedir}/../forge-gui/forge.profile.properties.example" />
|
||||
<option value="-Dapple.laf.useScreenMenuBar=true" />
|
||||
<option value="-Dcom.apple.macos.use-file-dialog-packages=true" />
|
||||
@@ -527,19 +512,12 @@
|
||||
<fileset dir="${basedir}/../forge-gui/res" excludes="**/cardsfolder/**" />
|
||||
</copy>
|
||||
<mkdir dir="${project.build.directory}/${project.build.finalName}-osx/Forge.app/Contents/Resources/res/cardsfolder" />
|
||||
<zip destfile="${project.build.directory}/${project.build.finalName}-osx/Forge.app/Contents/Resources/res/cardsfolder/cardsfolder.zip"
|
||||
basedir="${basedir}/../forge-gui/res/cardsfolder" level="1"/>
|
||||
<symlink
|
||||
link="${project.build.directory}/${project.build.finalName}-osx/Applications"
|
||||
resource="/Applications"/>
|
||||
<exec executable="${basedir}/../forge-gui/${configSourceDirectory}/create-dmg"
|
||||
failonerror="false">
|
||||
<zip destfile="${project.build.directory}/${project.build.finalName}-osx/Forge.app/Contents/Resources/res/cardsfolder/cardsfolder.zip" basedir="${basedir}/../forge-gui/res/cardsfolder" level="1" />
|
||||
<symlink link="${project.build.directory}/${project.build.finalName}-osx/Applications" resource="/Applications" />
|
||||
<exec executable="${basedir}/../forge-gui/${configSourceDirectory}/create-dmg" failonerror="false">
|
||||
<arg line="--volname ${project.name}-${project.version} --background ${basedir}/../forge-gui/${configSourceDirectory}/backgroundImage.jpg --window-size 700 419 --icon-size 64 --icon ${forge.file.name} 141 283 --icon ${applications.file.name} 452 283 --icon ${changes.file.name} 645 80 --icon ${license.file.name} 645 200 --icon ${readme.file.name} 645 320 ${project.build.directory}/${project.build.finalName}.dmg ${project.build.directory}/${project.build.finalName}-osx" />
|
||||
</exec>
|
||||
<tar basedir="${project.build.directory}"
|
||||
includes="${project.build.finalName}.dmg"
|
||||
destfile="${project.build.directory}/${project.build.finalName}-osx.tar.bz2"
|
||||
compression="bzip2"/>
|
||||
<tar basedir="${project.build.directory}" includes="${project.build.finalName}.dmg" destfile="${project.build.directory}/${project.build.finalName}-osx.tar.bz2" compression="bzip2" />
|
||||
<!--<symlink link="${project.build.directory}/${project.build.finalName}-osx/Applications" action="delete" /> -->
|
||||
<exec executable="rm" failonerror="false">
|
||||
<arg line="-f ${project.build.directory}/${project.build.finalName}-osx/Applications" />
|
||||
@@ -629,18 +607,9 @@
|
||||
<fileset dir="${basedir}/../forge-gui/" includes="MANUAL.txt" />
|
||||
<fileset dir="${basedir}/" includes="sentry.properties" />
|
||||
</copy>
|
||||
<taskdef name="bundleapp"
|
||||
classpath="${basedir}/../forge-gui/${configSourceDirectory}/appbundler-1.0-custom.jar"
|
||||
classname="com.oracle.appbundler.AppBundlerTask"/>
|
||||
<bundleapp
|
||||
outputdirectory="${project.build.directory}/${project.build.finalName}-osx"
|
||||
name="${project.name}" displayname="${project.name}"
|
||||
shortversion="${project.version}" identifier="forge.view.Main"
|
||||
icon="${basedir}/${configSourceDirectory}/Forge.icns"
|
||||
applicationCategory="public.app-category.games"
|
||||
mainclassname="forge.view.Main">
|
||||
<classpath
|
||||
file="${project.build.directory}/${project.build.finalName}-jar-with-dependencies.jar"/>
|
||||
<taskdef name="bundleapp" classpath="${basedir}/../forge-gui/${configSourceDirectory}/appbundler-1.0-custom.jar" classname="com.oracle.appbundler.AppBundlerTask" />
|
||||
<bundleapp outputdirectory="${project.build.directory}/${project.build.finalName}-osx" name="${project.name}" displayname="${project.name}" shortversion="${project.version}" identifier="forge.view.Main" icon="${basedir}/${configSourceDirectory}/Forge.icns" applicationCategory="public.app-category.games" mainclassname="forge.view.Main">
|
||||
<classpath file="${project.build.directory}/${project.build.finalName}-jar-with-dependencies.jar" />
|
||||
<classpath file="${basedir}/../forge-gui/forge.profile.properties.example" />
|
||||
<option value="-Dapple.laf.useScreenMenuBar=true" />
|
||||
<option value="-Dcom.apple.macos.use-file-dialog-packages=true" />
|
||||
@@ -654,19 +623,12 @@
|
||||
<fileset dir="${basedir}/../forge-gui/res" excludes="**/cardsfolder/**" />
|
||||
</copy>
|
||||
<mkdir dir="${project.build.directory}/${project.build.finalName}-osx/Forge.app/Contents/Resources/res/cardsfolder" />
|
||||
<zip destfile="${project.build.directory}/${project.build.finalName}-osx/Forge.app/Contents/Resources/res/cardsfolder/cardsfolder.zip"
|
||||
basedir="${basedir}/../forge-gui/res/cardsfolder" level="1"/>
|
||||
<symlink
|
||||
link="${project.build.directory}/${project.build.finalName}-osx/Applications"
|
||||
resource="/Applications"/>
|
||||
<exec executable="${basedir}/../forge-gui/${configSourceDirectory}/create-dmg"
|
||||
failonerror="false">
|
||||
<zip destfile="${project.build.directory}/${project.build.finalName}-osx/Forge.app/Contents/Resources/res/cardsfolder/cardsfolder.zip" basedir="${basedir}/../forge-gui/res/cardsfolder" level="1" />
|
||||
<symlink link="${project.build.directory}/${project.build.finalName}-osx/Applications" resource="/Applications" />
|
||||
<exec executable="${basedir}/../forge-gui/${configSourceDirectory}/create-dmg" failonerror="false">
|
||||
<arg line="--volname ${project.name}-${project.version} --background ${basedir}/../forge-gui/${configSourceDirectory}/backgroundImage.jpg --window-size 700 419 --icon-size 64 --icon ${forge.file.name} 141 283 --icon ${applications.file.name} 452 283 --icon ${changes.file.name} 645 80 --icon ${license.file.name} 645 200 --icon ${readme.file.name} 645 320 ${project.build.directory}/${project.build.finalName}.dmg ${project.build.directory}/${project.build.finalName}-osx" />
|
||||
</exec>
|
||||
<tar basedir="${project.build.directory}"
|
||||
includes="${project.build.finalName}.dmg"
|
||||
destfile="${project.build.directory}/${project.build.finalName}-osx.tar.bz2"
|
||||
compression="bzip2"/>
|
||||
<tar basedir="${project.build.directory}" includes="${project.build.finalName}.dmg" destfile="${project.build.directory}/${project.build.finalName}-osx.tar.bz2" compression="bzip2" />
|
||||
<!--<symlink link="${project.build.directory}/${project.build.finalName}-osx/Applications" action="delete" /> -->
|
||||
<exec executable="rm" failonerror="false">
|
||||
<arg line="-f ${project.build.directory}/${project.build.finalName}-osx/Applications" />
|
||||
|
||||
@@ -533,11 +533,8 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl
|
||||
|
||||
}
|
||||
|
||||
if (card.getCurrentRoom() != null && !card.getCurrentRoom().isEmpty()) {
|
||||
List<String> markers = new ArrayList<>();
|
||||
markers.add("In Room:");
|
||||
markers.add(card.getCurrentRoom());
|
||||
drawMarkersTabs(g, markers);
|
||||
if(card.getMarkerText() != null) {
|
||||
drawMarkersTabs(g, card.getMarkerText());
|
||||
}
|
||||
|
||||
final int combatXSymbols = (cardXOffset + (cardWidth / 4)) - 16;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>${revision}</version>
|
||||
<version>2.0.02</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-gui-ios</artifactId>
|
||||
@@ -35,7 +35,7 @@
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
<finalName>forge-ios-${revision}</finalName>
|
||||
<finalName>forge-ios-2.0.02-SNAPSHOT</finalName>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>${revision}</version>
|
||||
<version>2.0.02</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-gui-mobile-dev</artifactId>
|
||||
@@ -45,7 +45,7 @@
|
||||
<configuration>
|
||||
<!-- generate versionName from revision property to snapshot-version property -->
|
||||
<name>snapshot-version</name>
|
||||
<value>${revision}</value>
|
||||
<value>2.0.02-SNAPSHOT</value>
|
||||
<regex>-SNAPSHOT</regex>
|
||||
<replacement>-SNAPSHOT-${month.date}</replacement>
|
||||
<failIfNoMatch>false</failIfNoMatch>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>${revision}</version>
|
||||
<version>2.0.02</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-gui-mobile</artifactId>
|
||||
|
||||
@@ -781,22 +781,11 @@ public class CardRenderer {
|
||||
|
||||
}
|
||||
|
||||
if (card.getCurrentRoom() != null && !card.getCurrentRoom().isEmpty()) {
|
||||
List<String> markers = new ArrayList<>();
|
||||
markers.add("In Room:");
|
||||
markers.add(card.getCurrentRoom());
|
||||
if(card.getMarkerText() != null) {
|
||||
List<String> markers = card.getMarkerText();
|
||||
if(markers.size() > 1) //Use smaller text for multi-line strings.
|
||||
drawMarkersTabs(markers, g, x, y, w, h, false);
|
||||
}
|
||||
//Class level
|
||||
if (card.getCurrentState().getType().hasStringType("Class") && ZoneType.Battlefield.equals(card.getZone())) {
|
||||
List<String> markers = new ArrayList<>();
|
||||
markers.add("CL:" + card.getClassLevel());
|
||||
drawMarkersTabs(markers, g, x, y - markersHeight, w, h, true);
|
||||
}
|
||||
//Ring level
|
||||
if (card.getRingLevel() > 0) {
|
||||
List<String> markers = new ArrayList<>();
|
||||
markers.add("RL:" + card.getRingLevel());
|
||||
else
|
||||
drawMarkersTabs(markers, g, x, y - markersHeight, w, h, true);
|
||||
}
|
||||
|
||||
@@ -1528,7 +1517,7 @@ public class CardRenderer {
|
||||
int pageSize = 128;
|
||||
|
||||
//only generate images for characters that could be used by Forge
|
||||
String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890/-+:'";
|
||||
String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890/-+:'!—";
|
||||
|
||||
final PixmapPacker packer = new PixmapPacker(pageSize, pageSize, Pixmap.Format.RGBA8888, 2, false);
|
||||
final FreeTypeFontParameter parameter = new FreeTypeFontParameter();
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>${revision}</version>
|
||||
<version>2.0.02</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-gui</artifactId>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Name:Aether Gust
|
||||
ManaCost:1 U
|
||||
Types:Instant
|
||||
A:SP$ ChangeZone | ValidTgts$ Card.inZoneStack+Red,Card.inZoneStack+Green,Permanent.Red,Permanent.Green | TgtZone$ Battlefield,Stack | TgtPrompt$ Select target spell or permanent that's red or green | AlternativeDecider$ TargetedOwner | Origin$ Battlefield,Stack | Fizzle$ True | Destination$ Library | DestinationAlternative$ Library | LibraryPositionAlternative$ -1 | StackDescription$ {c:TargetedOwner} puts {c:Targeted} on the top or bottom of their library. | SpellDescription$ Choose target spell or permanent that's red or green. Its owner puts it on the top or bottom of their library.
|
||||
A:SP$ ChangeZone | ValidTgts$ Card.inZoneStack+Red,Card.inZoneStack+Green,Permanent.Red,Permanent.Green | TgtZone$ Battlefield,Stack | TgtPrompt$ Select target spell or permanent that's red or green | AlternativeDecider$ TargetedOwner | Origin$ Battlefield,Stack | Destination$ Library | DestinationAlternative$ Library | LibraryPositionAlternative$ -1 | StackDescription$ {c:TargetedOwner} puts {c:Targeted} on the top or bottom of their library. | SpellDescription$ Choose target spell or permanent that's red or green. Its owner puts it on the top or bottom of their library.
|
||||
AI:RemoveDeck:Random
|
||||
Oracle:Choose target spell or permanent that's red or green. Its owner puts it on the top or bottom of their library.
|
||||
|
||||
@@ -2,8 +2,8 @@ Name:Ahn-Crop Invader
|
||||
ManaCost:2 R
|
||||
Types:Creature Zombie Minotaur Warrior
|
||||
PT:2/2
|
||||
S:Mode$ Continuous | Affected$ Card.Self | AddKeyword$ First Strike | Condition$ PlayerTurn | Description$ As long as it's your turn, CARDNAME has first strike.
|
||||
S:Mode$ Continuous | Affected$ Card.Self | AddKeyword$ First Strike | Condition$ PlayerTurn | Description$ During your turn, CARDNAME has first strike.
|
||||
A:AB$ Pump | Cost$ 1 Sac<1/Creature.Other/another creature> | Defined$ Self | NumAtt$ +2 | AILogic$ Aristocrat | SpellDescription$ CARDNAME gets +2/+0 until end of turn.
|
||||
SVar:AIPreference:SacCost$Creature.Other
|
||||
DeckHas:Ability$Sacrifice
|
||||
Oracle:As long as it's your turn, Ahn-Crop Invader has first strike.\n{1}, Sacrifice another creature: Ahn-Crop Invader gets +2/+0 until end of turn.
|
||||
Oracle:During your turn, Ahn-Crop Invader has first strike.\n{1}, Sacrifice another creature: Ahn-Crop Invader gets +2/+0 until end of turn.
|
||||
|
||||
@@ -2,7 +2,7 @@ Name:Anara, Wolvid Familiar
|
||||
ManaCost:3 G
|
||||
Types:Legendary Creature Wolf Beast
|
||||
PT:4/4
|
||||
S:Mode$ Continuous | Affected$ Permanent.IsCommander+YouCtrl | AddKeyword$ Indestructible | Condition$ PlayerTurn | Description$ As long as it's your turn, commanders you control have indestructible. (Effects that say "destroy" don't destroy them. A creature with indestructible can't be destroyed by damage.)
|
||||
S:Mode$ Continuous | Affected$ Permanent.IsCommander+YouCtrl | AddKeyword$ Indestructible | Condition$ PlayerTurn | Description$ During your turn, commanders you control have indestructible. (Effects that say "destroy" don't destroy them. A creature with indestructible can't be destroyed by damage.)
|
||||
K:Partner
|
||||
AI:RemoveDeck:NonCommander
|
||||
Oracle:As long as it's your turn, commanders you control have indestructible. (Effects that say "destroy" don't destroy them. A creature with indestructible can't be destroyed by damage.)\nPartner (You can have two commanders if both have partner.)
|
||||
Oracle:During your turn, commanders you control have indestructible. (Effects that say "destroy" don't destroy them. A creature with indestructible can't be destroyed by damage.)\nPartner (You can have two commanders if both have partner.)
|
||||
|
||||
@@ -2,8 +2,7 @@ Name:Angelic Observer
|
||||
ManaCost:5 W
|
||||
Types:Creature Angel Advisor
|
||||
PT:3/3
|
||||
K:Affinity:Citizen
|
||||
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
|
||||
Oracle:Affinity for Citizens (This spell costs {1} less to cast for each Citizen you control.)\nFlying
|
||||
|
||||
@@ -3,9 +3,9 @@ ManaCost:2 W W
|
||||
Types:Creature Human
|
||||
PT:2+*/2+*
|
||||
K:Trample
|
||||
S:Mode$ Continuous | CharacteristicDefining$ True | SetPower$ X | SetToughness$ X | Condition$ PlayerTurn | Description$ As long as it's your turn, CARDNAME's power and toughness are each equal to 2 plus the number of Swamps your opponents control. As long as it's not your turn, CARDNAME's power and toughness are each 2.
|
||||
S:Mode$ Continuous | CharacteristicDefining$ True | SetPower$ X | SetToughness$ X | Condition$ PlayerTurn | Description$ During your turn, CARDNAME's power and toughness are each equal to 2 plus the number of Swamps your opponents control. During turns other than yours, CARDNAME's power and toughness are each 2.
|
||||
SVar:X:Count$Valid Swamp.OppCtrl/Plus.2
|
||||
S:Mode$ Continuous | CharacteristicDefining$ True | SetPower$ 2 | SetToughness$ 2 | Condition$ NotPlayerTurn
|
||||
AI:RemoveDeck:Random
|
||||
DeckHints:Name$Urborg, Tomb of Yawgmoth & Keyword$Swampwalk
|
||||
Oracle:Trample\nAs long as it's your turn, Angry Mob's power and toughness are each equal to 2 plus the number of Swamps your opponents control. As long as it's not your turn, Angry Mob's power and toughness are each 2.
|
||||
Oracle:Trample\nDuring your turn, Angry Mob's power and toughness are each equal to 2 plus the number of Swamps your opponents control. During turns other than yours, Angry Mob's power and toughness are each 2.
|
||||
|
||||
@@ -2,7 +2,6 @@ Name:Argivian Phalanx
|
||||
ManaCost:5 W
|
||||
Types:Creature Human Kor Soldier
|
||||
PT:4/4
|
||||
K:Affinity:Creature
|
||||
K:Vigilance
|
||||
S:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ X | EffectZone$ All | Description$ This spell costs {1} less to cast for each creature you control.
|
||||
SVar:X:Count$Valid Creature.YouCtrl
|
||||
Oracle:This spell costs {1} less to cast for each creature you control.\nVigilance
|
||||
Oracle:Affinity for creatures (This spell costs {1} less to cast for each creature you control.)\nVigilance
|
||||
|
||||
@@ -5,7 +5,7 @@ K:Flash
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ When CARDNAME enters, exile target spell.
|
||||
S:Mode$ CantBeCast | ValidCard$ Card.nonLand+sharesNameWith Remembered.ExiledWithSource | Caster$ Opponent | Description$ Your opponents can't cast spells with the same name as the card exiled by CARDNAME.
|
||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ TrigBounce | TriggerDescription$ When CARDNAME leaves the battlefield, return the exiled card to its owner's hand.
|
||||
SVar:TrigExile:DB$ ChangeZone | TargetType$ Spell | ValidTgts$ Card | TgtZone$ Stack | Origin$ Stack | Fizzle$ True | Destination$ Exile | IsCurse$ True | TgtPrompt$ Choose target spell | RememberChanged$ True
|
||||
SVar:TrigExile:DB$ ChangeZone | TargetType$ Spell | ValidTgts$ Card | TgtZone$ Stack | Origin$ Stack | Destination$ Exile | IsCurse$ True | TgtPrompt$ Choose target spell | RememberChanged$ True
|
||||
SVar:TrigBounce:DB$ ChangeZone | Origin$ Exile | Destination$ Hand | Defined$ Remembered | SubAbility$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
Oracle:Flash\nWhen Ashiok's Erasure enters, exile target spell.\nYour opponents can't cast spells with the same name as the exiled card.\nWhen Ashiok's Erasure leaves the battlefield, return the exiled card to its owner's hand.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
Name:At Knifepoint
|
||||
ManaCost:1 B R
|
||||
Types:Enchantment
|
||||
S:Mode$ Continuous | Affected$ Creature.Outlaw+YouCtrl | AddKeyword$ First Strike | Condition$ PlayerTurn | Description$ As long as it's your turn, outlaws you control have first strike. (Assassins, Mercenaries, Pirates, Rogues, and Warlocks are outlaws.)
|
||||
S:Mode$ Continuous | Affected$ Creature.Outlaw+YouCtrl | AddKeyword$ First Strike | Condition$ PlayerTurn | Description$ During your turn, outlaws you control have first strike. (Assassins, Mercenaries, Pirates, Rogues, and Warlocks are outlaws.)
|
||||
T:Mode$ CommitCrime | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigToken | ActivationLimit$ 1 | TriggerDescription$ Whenever you commit a crime, create a 1/1 red Mercenary creature token with "{T}: Target creature you control gets +1/+0 until end of turn. Activate only as a sorcery." This ability triggers only once each turn.
|
||||
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ r_1_1_mercenary_tappump | TokenOwner$ You
|
||||
DeckHas:Ability$Token & Type$Mercenary
|
||||
DeckHints:Type$Assassin|Mercenary|Pirate|Rogue|Warlock
|
||||
Oracle:As long as it's your turn, outlaws you control have first strike. (Assassins, Mercenaries, Pirates, Rogues, and Warlocks are outlaws.)\nWhenever you commit a crime, create a 1/1 red Mercenary creature token with "{T}: Target creature you control gets +1/+0 until end of turn. Activate only as a sorcery." This ability triggers only once each turn.
|
||||
Oracle:During your turn, outlaws you control have first strike. (Assassins, Mercenaries, Pirates, Rogues, and Warlocks are outlaws.)\nWhenever you commit a crime, create a 1/1 red Mercenary creature token with "{T}: Target creature you control gets +1/+0 until end of turn. Activate only as a sorcery." This ability triggers only once each turn.
|
||||
|
||||
@@ -5,7 +5,7 @@ PT:2/2
|
||||
K:Flash
|
||||
K:Flying
|
||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ When CARDNAME enters, exile target spell. It becomes plotted. (Its owner may cast it as a sorcery on a later turn without paying its mana cost.)
|
||||
SVar:TrigExile:DB$ ChangeZone | TargetType$ Spell | ValidTgts$ Card | TgtZone$ Stack | Origin$ Stack | Fizzle$ True | Mandatory$ True | Destination$ Exile | IsCurse$ True | TgtPrompt$ Choose target spell | RememberChanged$ True | SubAbility$ DBPlot
|
||||
SVar:TrigExile:DB$ ChangeZone | TargetType$ Spell | ValidTgts$ Card | TgtZone$ Stack | Origin$ Stack | Destination$ Exile | IsCurse$ True | TgtPrompt$ Choose target spell | RememberChanged$ True | SubAbility$ DBPlot
|
||||
SVar:DBPlot:DB$ AlterAttribute | Defined$ Remembered | Attributes$ Plotted | SubAbility$ DBCleanup
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
S:Mode$ RaiseCost | Activator$ Opponent | ValidCard$ Card.wasCastFromGraveyard,Card.wasCastFromExile | Type$ Spell | Amount$ 2 | Description$ Spells your opponents cast from graveyards or from exile cost {2} more to cast.
|
||||
|
||||
@@ -3,6 +3,6 @@ ManaCost:3 R W
|
||||
Types:Legendary Creature Human Assassin
|
||||
PT:3/4
|
||||
K:Double Strike
|
||||
S:Mode$ Continuous | Affected$ Creature.Historic+Other+YouCtrl | AddKeyword$ Double Strike | Condition$ PlayerTurn | Description$ As long as it's your turn, other historic creatures you control have double strike.
|
||||
S:Mode$ Continuous | Affected$ Creature.Historic+Other+YouCtrl | AddKeyword$ Double Strike | Condition$ PlayerTurn | Description$ During your turn, other historic creatures you control have double strike.
|
||||
K:Disguise:1 R W
|
||||
Oracle:Double strike\nAs long as it's your turn, other historic creatures you control have double strike.\nDisguise {1}{R}{W} (You may cast this card face down for {3} as a 2/2 creature with ward {2}. Turn it face up any time for its disguise cost.)
|
||||
Oracle:Double strike\nDuring your turn, other historic creatures you control have double strike.\nDisguise {1}{R}{W} (You may cast this card face down for {3} as a 2/2 creature with ward {2}. Turn it face up any time for its disguise cost.)
|
||||
|
||||
@@ -2,7 +2,7 @@ Name:Bedrock Tortoise
|
||||
ManaCost:3 G
|
||||
Types:Creature Turtle
|
||||
PT:0/6
|
||||
S:Mode$ Continuous | Affected$ Creature.YouCtrl | AddKeyword$ Hexproof | Condition$ PlayerTurn | Description$ As long as it's your turn, creatures you control have hexproof.
|
||||
S:Mode$ Continuous | Affected$ Creature.YouCtrl | AddKeyword$ Hexproof | Condition$ PlayerTurn | Description$ During your turn, creatures you control have hexproof.
|
||||
S:Mode$ CombatDamageToughness | ValidCard$ Creature.powerLTtoughness+YouCtrl | Description$ Each creature you control with toughness greater than its power assigns combat damage equal to its toughness rather than its power.
|
||||
DeckHints:Type$Turtle|Spider|Treefolk|Crab|Wall
|
||||
Oracle:As long as it's your turn, creatures you control have hexproof.\nEach creature you control with toughness greater than its power assigns combat damage equal to its toughness rather than its power.
|
||||
Oracle:During your turn, creatures you control have hexproof.\nEach creature you control with toughness greater than its power assigns combat damage equal to its toughness rather than its power.
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Name:Bilbo's Ring
|
||||
ManaCost:3
|
||||
Types:Legendary Artifact Equipment
|
||||
S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddKeyword$ Hexproof | Condition$ PlayerTurn | Description$ As long as it's your turn, equipped creature has hexproof and can't be blocked.
|
||||
S:Mode$ CantBlockBy | ValidAttacker$ Creature.EquippedBy | Secondary$ True | Condition$ PlayerTurn | Description$ As long as it's your turn, equipped creature has hexproof and can't be blocked.
|
||||
S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddKeyword$ Hexproof | Condition$ PlayerTurn | Description$ During your turn, equipped creature has hexproof and can't be blocked.
|
||||
S:Mode$ CantBlockBy | ValidAttacker$ Creature.EquippedBy | Secondary$ True | Condition$ PlayerTurn | Description$ During your turn, equipped creature has hexproof and can't be blocked.
|
||||
T:Mode$ Attacks | ValidCard$ Card.EquippedBy | Alone$ True | Execute$ TrigDraw | TriggerDescription$ Whenever equipped creature attacks alone, you draw a card and you lose 1 life.
|
||||
SVar:TrigDraw:DB$ Draw | SubAbility$ DBLoseLife
|
||||
SVar:DBLoseLife:DB$ LoseLife | LifeAmount$ 1
|
||||
K:Equip:4
|
||||
K:Equip:1:Halfling.YouCtrl:Halfling you control
|
||||
DeckHints:Type$Halfling
|
||||
Oracle:As long as it's your turn, equipped creature has hexproof and can't be blocked.\nWhenever equipped creature attacks alone, you draw a card and you lose 1 life.\nEquip Halfling {1} ({1}: Attach to target Halfling you control. Equip only as a sorcery.)\nEquip {4} ({4}: Attach to target creature you control. Equip only as a sorcery.)
|
||||
Oracle:During your turn, equipped creature has hexproof and can't be blocked.\nWhenever equipped creature attacks alone, you draw a card and you lose 1 life.\nEquip Halfling {1} ({1}: Attach to target Halfling you control. Equip only as a sorcery.)\nEquip {4} ({4}: Attach to target creature you control. Equip only as a sorcery.)
|
||||
|
||||
@@ -2,5 +2,5 @@ Name:Black Hole
|
||||
ManaCost:3 B
|
||||
Types:Sorcery
|
||||
A:SP$ Destroy | ValidTgts$ Creature | TgtPrompt$ Select target creature and up to X other target creatures, where X is the number of Attractions you're visited this turn | TargetMin$ 1 | TargetMax$ X | SpellDescription$ Destroy target creature and up to X other target creatures, where X is the number of Attractions you've visited this turn.
|
||||
SVar:X:Count$Valid Attraction.VisitedThisTurn/Plus.1
|
||||
SVar:X:PlayerCountPropertyYou$AttractionsVisitedThisTurn/Plus.1
|
||||
Oracle:Destroy target creature and up to X other target creatures, where X is the number of Attractions you've visited this turn.
|
||||
|
||||
@@ -2,6 +2,6 @@ Name:Blood Burglar
|
||||
ManaCost:1 B
|
||||
Types:Creature Vampire Rogue
|
||||
PT:2/2
|
||||
S:Mode$ Continuous | Affected$ Card.Self | AddKeyword$ Lifelink | Condition$ PlayerTurn | Description$ As long as it's your turn, CARDNAME has lifelink.
|
||||
S:Mode$ Continuous | Affected$ Card.Self | AddKeyword$ Lifelink | Condition$ PlayerTurn | Description$ During your turn, CARDNAME has lifelink.
|
||||
DeckHas:Ability$LifeGain
|
||||
Oracle:As long as it's your turn, Blood Burglar has lifelink. (Damage dealt by this creature also causes you to gain that much life.)
|
||||
Oracle:During your turn, Blood Burglar has lifelink. (Damage dealt by this creature also causes you to gain that much life.)
|
||||
|
||||
@@ -2,7 +2,6 @@ Name:Brine Giant
|
||||
ManaCost:6 U
|
||||
Types:Creature Giant
|
||||
PT:5/6
|
||||
S:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ X | EffectZone$ All | Description$ This spell costs {1} less to cast for each enchantment you control.
|
||||
SVar:X:Count$Valid Enchantment.YouCtrl
|
||||
K:Affinity:Enchantment
|
||||
DeckHints:Type$Enchantment
|
||||
Oracle:This spell costs {1} less to cast for each enchantment you control.
|
||||
Oracle:Affinity for enchantments (This spell costs {1} less to cast for each enchantment you control.)
|
||||
|
||||
@@ -3,6 +3,6 @@ ManaCost:2 U R
|
||||
Types:Instant
|
||||
K:Devoid
|
||||
A:SP$ Charm | MinCharmNum$ 1 | CharmNum$ 2 | Choices$ DBReturn,DBDmg
|
||||
SVar:DBReturn:DB$ ChangeZone | ValidTgts$ Creature,Card.inZoneStack | TgtZone$ Stack,Battlefield | Origin$ Battlefield,Stack | Fizzle$ True | Destination$ Hand | SpellDescription$ Return target spell or creature to its owner's hand.
|
||||
SVar:DBReturn:DB$ ChangeZone | ValidTgts$ Creature,Card.inZoneStack | TgtZone$ Stack,Battlefield | Origin$ Battlefield,Stack | Destination$ Hand | SpellDescription$ Return target spell or creature to its owner's hand.
|
||||
SVar:DBDmg:DB$ DealDamage | ValidTgts$ Creature,Planeswalker | TgtPrompt$ Select target creature or planeswalker | NumDmg$ 2 | ReplaceDyingDefined$ Targeted | SpellDescription$ CARDNAME deals 2 damage to target creature or planeswalker. If that creature or planeswalker would die this turn, exile it instead.
|
||||
Oracle:Devoid (This card has no color.)\nChoose one or both —\n• Return target spell or creature to its owner's hand.\n• Brutal Expulsion deals 2 damage to target creature or planeswalker. If that creature or planeswalker would die this turn, exile it instead.
|
||||
|
||||
@@ -2,7 +2,7 @@ Name:Cait, Cage Brawler
|
||||
ManaCost:R G
|
||||
Types:Legendary Creature Human Warrior
|
||||
PT:1/1
|
||||
S:Mode$ Continuous | Affected$ Card.Self | AddKeyword$ Indestructible | Condition$ PlayerTurn | Description$ As long as it's your turn, CARDNAME has indestructible.
|
||||
S:Mode$ Continuous | Affected$ Card.Self | AddKeyword$ Indestructible | Condition$ PlayerTurn | Description$ During your turn, CARDNAME has indestructible.
|
||||
T:Mode$ Attacks | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigDraw | TriggerDescription$ Whenever NICKNAME attacks, you and defending player each draw a card, then discard a card. Put two +1/+1 counters on NICKNAME if you discarded the card with the highest mana value among those cards or tied for highest.
|
||||
SVar:TrigDraw:DB$ Draw | Defined$ You & TriggeredDefendingPlayer | NumCards$ 1 | SubAbility$ DBDiscard
|
||||
SVar:DBDiscard:DB$ Discard | Mode$ TgtChoose | Defined$ TriggeredDefendingPlayerAndYou | RememberDiscarded$ True | SubAbility$ DBPutCounter
|
||||
@@ -10,4 +10,4 @@ SVar:DBPutCounter:DB$ PutCounter | ConditionDefined$ Remembered | ConditionPrese
|
||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||
SVar:HasAttackEffect:True
|
||||
DeckHas:Ability$Discard|Counters
|
||||
Oracle:As long as it's your turn, Cait, Cage Brawler has indestructible.\nWhenever Cait attacks, you and defending player each draw a card, then discard a card. Put two +1/+1 counters on Cait if you discarded the card with the highest mana value among those cards or tied for highest.
|
||||
Oracle:During your turn, Cait, Cage Brawler has indestructible.\nWhenever Cait attacks, you and defending player each draw a card, then discard a card. Put two +1/+1 counters on Cait if you discarded the card with the highest mana value among those cards or tied for highest.
|
||||
|
||||
@@ -2,5 +2,5 @@ Name:Circle of the Moon Druid
|
||||
ManaCost:2 G
|
||||
Types:Creature Human Elf Druid
|
||||
PT:2/4
|
||||
S:Mode$ Continuous | Affected$ Card.Self | Condition$ PlayerTurn | EffectZone$ Battlefield | SetPower$ 4 | SetToughness$ 2 | AddType$ Creature & Bear | RemoveCreatureTypes$ True | Description$ Bear Form — As long as it's your turn, CARDNAME is a Bear with base power and toughness 4/2. (It loses all other creature types.)
|
||||
Oracle:Bear Form — As long as it's your turn, Circle of the Moon Druid is a Bear with base power and toughness 4/2. (It loses all other creature types.)
|
||||
S:Mode$ Continuous | Affected$ Card.Self | Condition$ PlayerTurn | EffectZone$ Battlefield | SetPower$ 4 | SetToughness$ 2 | AddType$ Creature & Bear | RemoveCreatureTypes$ True | Description$ Bear Form — During your turn, CARDNAME is a Bear with base power and toughness 4/2. (It loses all other creature types.)
|
||||
Oracle:Bear Form — During your turn, Circle of the Moon Druid is a Bear with base power and toughness 4/2. (It loses all other creature types.)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user