Merge branch 'master' of https://github.com/Card-Forge/forge into adventure

This commit is contained in:
Grimm
2022-08-22 14:46:49 +02:00
469 changed files with 960 additions and 225 deletions

View File

@@ -2809,7 +2809,7 @@ public class ComputerUtil {
|| type.is(CounterEnumType.GOLD) || type.is(CounterEnumType.MUSIC) || type.is(CounterEnumType.PUPA) || type.is(CounterEnumType.GOLD) || type.is(CounterEnumType.MUSIC) || type.is(CounterEnumType.PUPA)
|| type.is(CounterEnumType.PARALYZATION) || type.is(CounterEnumType.SHELL) || type.is(CounterEnumType.SLEEP) || type.is(CounterEnumType.PARALYZATION) || type.is(CounterEnumType.SHELL) || type.is(CounterEnumType.SLEEP)
|| type.is(CounterEnumType.SLUMBER) || type.is(CounterEnumType.SLEIGHT) || type.is(CounterEnumType.WAGE) || type.is(CounterEnumType.SLUMBER) || type.is(CounterEnumType.SLEIGHT) || type.is(CounterEnumType.WAGE)
|| type.is(CounterEnumType.INCARNATION) || type.is(CounterEnumType.RUST); || type.is(CounterEnumType.INCARNATION) || type.is(CounterEnumType.RUST) || type.is(CounterEnumType.STUN);
} }
// this countertypes has no effect // this countertypes has no effect

View File

@@ -190,6 +190,15 @@ public final class ColorSet implements Comparable<ColorSet>, Iterable<Byte>, Ser
return this.countColors() > 1; return this.countColors() > 1;
} }
/**
* Checks if is all colors.
*
* @return true, if is all colors
*/
public boolean isAllColors() {
return this == ALL_COLORS;
}
/** /**
* Checks if is mono color. * Checks if is mono color.
* *

View File

@@ -59,6 +59,11 @@ public class ForgeScript {
return false; return false;
return property.startsWith("non") != colors.isMulticolor(); return property.startsWith("non") != colors.isMulticolor();
} else if (property.contains("AllColors")) {
if (property.endsWith("Source") && isColorlessSource)
return false;
return property.startsWith("non") != colors.isAllColors();
} else if (property.contains("MonoColor")) { // ... Card is monocolored } else if (property.contains("MonoColor")) { // ... Card is monocolored
if (property.endsWith("Source") && isColorlessSource) if (property.endsWith("Source") && isColorlessSource)
return false; return false;

View File

@@ -366,7 +366,9 @@ public class GameAction {
} }
} }
if (zoneFrom == null) { // in addition to actual tokens, cards "made" by digital-only mechanics
// are also added to inbound tokens so their etb replacements will work
if (zoneFrom == null || zoneFrom.is(ZoneType.None)) {
copied.getOwner().addInboundToken(copied); copied.getOwner().addInboundToken(copied);
} }

View File

@@ -3478,8 +3478,8 @@ public class AbilityUtils {
} }
if (value.equals("OpponentsAttackedThisTurn")) { if (value.equals("OpponentsAttackedThisTurn")) {
final List<Player> opps = player.getAttackedPlayersMyTurn(); final Iterable<Player> opps = player.getAttackedPlayersMyTurn();
return doXMath(opps == null ? 0 : opps.size(), m, source, ctb); return doXMath(opps == null ? 0 : Iterables.size(opps), m, source, ctb);
} }
if (value.equals("OpponentsAttackedThisCombat")) { if (value.equals("OpponentsAttackedThisCombat")) {

View File

@@ -596,7 +596,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
} }
if (sa.hasParam("GainControl")) { if (sa.hasParam("GainControl")) {
final String g = sa.getParam("GainControl"); final String g = sa.getParam("GainControl");
Player newController = g.equals("True") ? sa.getActivatingPlayer() : Player newController = g.equals("True") ? player :
AbilityUtils.getDefinedPlayers(sa.getHostCard(), g, sa).get(0); AbilityUtils.getDefinedPlayers(sa.getHostCard(), g, sa).get(0);
if (newController != null) { if (newController != null) {
if (newController != gameCard.getController()) { if (newController != gameCard.getController()) {
@@ -764,7 +764,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
movedCard.setForetoldThisTurn(true); movedCard.setForetoldThisTurn(true);
movedCard.setForetoldByEffect(true); movedCard.setForetoldByEffect(true);
// look at the exiled card // look at the exiled card
movedCard.addMayLookTemp(sa.getActivatingPlayer()); movedCard.addMayLookTemp(player);
} }
if (sa.hasParam("TrackDiscarded")) { if (sa.hasParam("TrackDiscarded")) {

View File

@@ -439,6 +439,9 @@ public class CountersPutEffect extends SpellAbilityEffect {
} }
if (obj instanceof Card) { if (obj instanceof Card) {
if (sa.hasParam("CounterNumPerDefined")) {
counterAmount = AbilityUtils.calculateAmount(gameCard, sa.getParam("CounterNumPerDefined"), sa);
}
counterAmount = sa.usesTargeting() && sa.isDividedAsYouChoose() ? sa.getDividedValue(gameCard) counterAmount = sa.usesTargeting() && sa.isDividedAsYouChoose() ? sa.getDividedValue(gameCard)
: counterAmount; : counterAmount;
if (!sa.usesTargeting() || gameCard.canBeTargetedBy(sa)) { if (!sa.usesTargeting() || gameCard.canBeTargetedBy(sa)) {

View File

@@ -1,8 +1,12 @@
package forge.game.ability.effects; package forge.game.ability.effects;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map; import java.util.Map;
import forge.StaticData; import forge.StaticData;
import forge.card.ICardFace;
import forge.game.Game; import forge.game.Game;
import forge.game.ability.AbilityKey; import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
@@ -14,6 +18,9 @@ import forge.game.player.Player;
import forge.game.player.PlayerCollection; import forge.game.player.PlayerCollection;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.Aggregates;
import forge.util.CardTranslation;
import forge.util.Localizer;
public class MakeCardEffect extends SpellAbilityEffect { public class MakeCardEffect extends SpellAbilityEffect {
@Override @Override
@@ -40,6 +47,20 @@ public class MakeCardEffect extends SpellAbilityEffect {
if (def.size() > 0) { if (def.size() > 0) {
name = def.getFirst().getName(); name = def.getFirst().getName();
} }
} else if (sa.hasParam("Spellbook")) {
List<String> spellbook = Arrays.asList(sa.getParam("Spellbook").split(","));
List<ICardFace> faces = new ArrayList<>();
for (String s : spellbook) {
// Cardnames that include "," must use ";" instead in Spellbook$ (i.e. Tovolar; Dire Overlord)
s = s.replace(";", ",");
faces.add(StaticData.instance().getCommonCards().getFaceByName(s));
}
if (sa.hasParam("AtRandom")) {
name = Aggregates.random(faces).getName();
} else {
name = player.getController().chooseCardName(sa, faces,
Localizer.getInstance().getMessage("lblChooseFromSpellbook", CardTranslation.getTranslatedName(source.getName())));
}
} }
final ZoneType zone = ZoneType.smartValueOf(sa.getParamOrDefault("Zone", "Library")); final ZoneType zone = ZoneType.smartValueOf(sa.getParamOrDefault("Zone", "Library"));
int amount = sa.hasParam("Amount") ? int amount = sa.hasParam("Amount") ?
@@ -50,12 +71,7 @@ public class MakeCardEffect extends SpellAbilityEffect {
if (!name.equals("")) { if (!name.equals("")) {
while (amount > 0) { while (amount > 0) {
Card card = Card.fromPaperCard(StaticData.instance().getCommonCards().getUniqueByName(name), player); Card card = Card.fromPaperCard(StaticData.instance().getCommonCards().getUniqueByName(name), player);
if (sa.hasParam("IsToken")) {
card.setToken(true);
}
if (!sa.hasParam("NotToken")) {
card.setTokenCard(true); card.setTokenCard(true);
}
game.getAction().moveTo(ZoneType.None, card, sa, moveParams); game.getAction().moveTo(ZoneType.None, card, sa, moveParams);
cards.add(card); cards.add(card);
amount--; amount--;

View File

@@ -334,6 +334,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
private ReplacementEffect shieldCounterReplaceDamage = null; private ReplacementEffect shieldCounterReplaceDamage = null;
private ReplacementEffect shieldCounterReplaceDestroy = null; private ReplacementEffect shieldCounterReplaceDestroy = null;
private ReplacementEffect stunCounterReplaceUntap = null;
// Enumeration for CMC request types // Enumeration for CMC request types
public enum SplitCMCMode { public enum SplitCMCMode {
@@ -6100,16 +6101,16 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
} }
// Shield Counter aren't affected by Changed Card Traits // Shield Counter aren't affected by Changed Card Traits
if (this.getCounters(CounterEnumType.SHIELD) > 0) { if (getCounters(CounterEnumType.SHIELD) > 0) {
String sa = "DB$ RemoveCounter | Defined$ Self | CounterType$ Shield | CounterNum$ 1"; String sa = "DB$ RemoveCounter | Defined$ Self | CounterType$ Shield | CounterNum$ 1";
if (shieldCounterReplaceDamage == null) { if (shieldCounterReplaceDamage == null) {
String reStr = "Event$ DamageDone | ActiveZones$ Battlefield | ValidTarget$ Card.Self | PreventionEffect$ True | AlwaysReplace$ True " String reStr = "Event$ DamageDone | ActiveZones$ Battlefield | ValidTarget$ Card.Self | PreventionEffect$ True | AlwaysReplace$ True | Secondary$ True "
+ "| Description$ If damage would be dealt to this permanent, prevent that damage and remove a shield counter from it."; + "| Description$ If damage would be dealt to this permanent, prevent that damage and remove a shield counter from it.";
shieldCounterReplaceDamage = ReplacementHandler.parseReplacement(reStr, this, false, null); shieldCounterReplaceDamage = ReplacementHandler.parseReplacement(reStr, this, false, null);
shieldCounterReplaceDamage.setOverridingAbility(AbilityFactory.getAbility(sa, this)); shieldCounterReplaceDamage.setOverridingAbility(AbilityFactory.getAbility(sa, this));
} }
if (shieldCounterReplaceDestroy == null) { if (shieldCounterReplaceDestroy == null) {
String reStr = "Event$ Destroy | ActiveZones$ Battlefield | ValidCard$ Card.Self | ValidSource$ SpellAbility " String reStr = "Event$ Destroy | ActiveZones$ Battlefield | ValidCard$ Card.Self | ValidSource$ SpellAbility | Secondary$ True "
+ "| Description$ If this permanent would be destroyed as the result of an effect, instead remove a shield counter from it."; + "| Description$ If this permanent would be destroyed as the result of an effect, instead remove a shield counter from it.";
shieldCounterReplaceDestroy = ReplacementHandler.parseReplacement(reStr, this, false, null); shieldCounterReplaceDestroy = ReplacementHandler.parseReplacement(reStr, this, false, null);
shieldCounterReplaceDestroy.setOverridingAbility(AbilityFactory.getAbility(sa, this)); shieldCounterReplaceDestroy.setOverridingAbility(AbilityFactory.getAbility(sa, this));
@@ -6118,6 +6119,17 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
list.add(shieldCounterReplaceDamage); list.add(shieldCounterReplaceDamage);
list.add(shieldCounterReplaceDestroy); list.add(shieldCounterReplaceDestroy);
} }
if (getCounters(CounterEnumType.STUN) > 0) {
String sa = "DB$ RemoveCounter | Defined$ Self | CounterType$ Stun | CounterNum$ 1";
if (stunCounterReplaceUntap == null) {
String reStr = "Event$ Untap | ActiveZones$ Battlefield | ValidCard$ Card.Self | Secondary$ True "
+ "| Description$ If this permanent would become untapped, instead remove a stun counter from it.";
stunCounterReplaceUntap = ReplacementHandler.parseReplacement(reStr, this, false, null);
stunCounterReplaceUntap.setOverridingAbility(AbilityFactory.getAbility(sa, this));
}
list.add(stunCounterReplaceUntap);
}
} }
public boolean hasReplacementEffect(final ReplacementEffect re) { public boolean hasReplacementEffect(final ReplacementEffect re) {

View File

@@ -1391,6 +1391,10 @@ public class CardProperty {
if (card.getNetPower() <= card.getNetToughness()) { if (card.getNetPower() <= card.getNetToughness()) {
return false; return false;
} }
} else if (property.equals("powerGTbasePower")) {
if (card.getNetPower() <= card.getCurrentPower()) {
return false;
}
} else if (property.equals("powerLTtoughness")) { } else if (property.equals("powerLTtoughness")) {
if (card.getNetPower() >= card.getNetToughness()) { if (card.getNetPower() >= card.getNetToughness()) {
return false; return false;

View File

@@ -329,6 +329,8 @@ public enum CounterEnumType {
STUDY("STUDY", 226, 192, 165), STUDY("STUDY", 226, 192, 165),
STUN("STUN", 226, 192, 165),
TASK("TASK", 191, 63, 49), TASK("TASK", 191, 63, 49),
THEFT("THEFT", 255, 176, 125), THEFT("THEFT", 255, 176, 125),

View File

@@ -407,10 +407,7 @@ public class CombatUtil {
c.getDamageHistory().setCreatureAttackedThisCombat(defender); c.getDamageHistory().setCreatureAttackedThisCombat(defender);
c.getDamageHistory().clearNotAttackedSinceLastUpkeepOf(); c.getDamageHistory().clearNotAttackedSinceLastUpkeepOf();
c.getController().addCreaturesAttackedThisTurn(CardUtil.getLKICopy(c)); c.getController().addCreaturesAttackedThisTurn(CardUtil.getLKICopy(c), defender);
if (defender instanceof Player) {
c.getController().addAttackedPlayersMyTurn(combat.getDefenderPlayerByAttacker(c));
}
} }
/** /**

View File

@@ -24,6 +24,7 @@ import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Deque; import java.util.Deque;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -202,8 +203,7 @@ public class Player extends GameEntity implements Comparable<Player> {
private Table<Long, Long, KeywordsChange> changedKeywords = TreeBasedTable.create(); private Table<Long, Long, KeywordsChange> changedKeywords = TreeBasedTable.create();
private ManaPool manaPool = new ManaPool(this); private ManaPool manaPool = new ManaPool(this);
private List<Card> creatureAttackedThisTurn = new ArrayList<>(); private Map<GameEntity, List<Card>> attackedThisTurn = new HashMap<>();
private List<Player> attackedPlayersThisTurn = new ArrayList<>();
private List<Player> attackedPlayersLastTurn = new ArrayList<>(); private List<Player> attackedPlayersLastTurn = new ArrayList<>();
private List<Player> attackedPlayersThisCombat = new ArrayList<>(); private List<Player> attackedPlayersThisCombat = new ArrayList<>();
@@ -1826,37 +1826,37 @@ public class Player extends GameEntity implements Comparable<Player> {
} }
public final List<Card> getCreaturesAttackedThisTurn() { public final List<Card> getCreaturesAttackedThisTurn() {
return creatureAttackedThisTurn; List<Card> result = Lists.newArrayList(Iterables.concat(attackedThisTurn.values()));
return result;
} }
public final void addCreaturesAttackedThisTurn(final Card c) { public final List<Card> getCreaturesAttackedThisTurn(final GameEntity e) {
creatureAttackedThisTurn.add(c); return attackedThisTurn.getOrDefault(e, Lists.newArrayList());
}
public final void addCreaturesAttackedThisTurn(final Card c, final GameEntity e) {
final List<Card> creatures = attackedThisTurn.getOrDefault(e, Lists.newArrayList());
creatures.add(c);
attackedThisTurn.putIfAbsent(e, creatures);
if (e instanceof Player && !attackedPlayersThisCombat.contains(e)) {
attackedPlayersThisCombat.add((Player) e);
} }
public final void clearCreaturesAttackedThisTurn() {
creatureAttackedThisTurn.clear();
} }
public final void addAttackedPlayersMyTurn(final Player p) { public final Iterable<Player> getAttackedPlayersMyTurn() {
if (!attackedPlayersThisTurn.contains(p)) { return Iterables.filter(attackedThisTurn.keySet(), Player.class);
attackedPlayersThisCombat.add(p);
attackedPlayersThisTurn.add(p);
}
}
public final List<Player> getAttackedPlayersMyTurn() {
return attackedPlayersThisTurn;
} }
public final List<Player> getAttackedPlayersMyLastTurn() { public final List<Player> getAttackedPlayersMyLastTurn() {
return attackedPlayersLastTurn; return attackedPlayersLastTurn;
} }
public final void clearAttackedPlayersMyTurn() { public final void clearAttackedMyTurn() {
attackedPlayersThisTurn.clear(); attackedThisTurn.clear();
} }
public final void setAttackedPlayersMyLastTurn(List<Player> players) { public final void setAttackedPlayersMyLastTurn(Iterable<Player> players) {
attackedPlayersLastTurn.clear(); attackedPlayersLastTurn.clear();
attackedPlayersLastTurn.addAll(players); Iterables.addAll(attackedPlayersLastTurn, players);
} }
public final List<Player> getAttackedPlayersMyCombat() { public final List<Player> getAttackedPlayersMyCombat() {
return attackedPlayersThisTurn; return attackedPlayersThisCombat;
} }
public final void clearAttackedPlayersMyCombat() { public final void clearAttackedPlayersMyCombat() {
attackedPlayersThisCombat.clear(); attackedPlayersThisCombat.clear();
@@ -2390,7 +2390,6 @@ public class Player extends GameEntity implements Comparable<Player> {
resetNumForetoldThisTurn(); resetNumForetoldThisTurn();
resetNumTokenCreatedThisTurn(); resetNumTokenCreatedThisTurn();
setNumCardsInHandStartedThisTurnWith(getCardsIn(ZoneType.Hand).size()); setNumCardsInHandStartedThisTurnWith(getCardsIn(ZoneType.Hand).size());
clearCreaturesAttackedThisTurn();
setActivateLoyaltyAbilityThisTurn(false); setActivateLoyaltyAbilityThisTurn(false);
setTappedLandForManaThisTurn(false); setTappedLandForManaThisTurn(false);
setLandsPlayedLastTurn(getLandsPlayedThisTurn()); setLandsPlayedLastTurn(getLandsPlayedThisTurn());
@@ -2417,8 +2416,8 @@ public class Player extends GameEntity implements Comparable<Player> {
// set last turn nr // set last turn nr
if (game.getPhaseHandler().isPlayerTurn(this)) { if (game.getPhaseHandler().isPlayerTurn(this)) {
setAttackedPlayersMyLastTurn(attackedPlayersThisTurn); setAttackedPlayersMyLastTurn(getAttackedPlayersMyTurn());
clearAttackedPlayersMyTurn(); clearAttackedMyTurn();
this.lastTurnNr = game.getPhaseHandler().getTurn(); this.lastTurnNr = game.getPhaseHandler().getTurn();
} }
} }

View File

@@ -381,6 +381,14 @@ public class PlayerProperty {
if (player.getCreaturesAttackedThisTurn().isEmpty()) { if (player.getCreaturesAttackedThisTurn().isEmpty()) {
return false; return false;
} }
} else if (property.startsWith("wasAttackedThisTurnBy")) {
String restriction = property.split(" ")[1];
for (Card c : sourceController.getCreaturesAttackedThisTurn(player)) {
if (c.isValid(restriction, sourceController, source, spellAbility)) {
return true;
}
}
return false;
} else if (property.equals("attackedYouTheirLastTurn")) { } else if (property.equals("attackedYouTheirLastTurn")) {
if (!player.getAttackedPlayersMyLastTurn().contains(sourceController)) { if (!player.getAttackedPlayersMyLastTurn().contains(sourceController)) {
return false; return false;

View File

@@ -361,6 +361,10 @@ public class AbilityManaPart implements java.io.Serializable {
} }
} }
if (restriction.equals("CantCastNonArtifactSpells")) {
return !sa.isSpell() || sa.getHostCard().isArtifact();
}
// the payment is for a resolving SA, currently no other restrictions would allow that // the payment is for a resolving SA, currently no other restrictions would allow that
if (getSourceCard().getGame().getStack().getInstanceFromSpellAbility(sa.getRootAbility()) != null) { if (getSourceCard().getGame().getStack().getInstanceFromSpellAbility(sa.getRootAbility()) != null) {
return false; return false;

View File

@@ -41,7 +41,7 @@ public class CardEditionCollectionCardMockTestCase extends CardMockTestCase {
CardDb cardDb = FModel.getMagicDb().getCommonCards(); CardDb cardDb = FModel.getMagicDb().getCommonCards();
String[] cardNames = { "Shivan Dragon", "Animate Wall", "Balance", "Blessing", "Force of Will" }; String[] cardNames = { "Shivan Dragon", "Animate Wall", "Balance", "Blessing", "Force of Will" };
String[] expectedSets = { "M20", "MED", "SLD", "M14", "2XM" }; String[] expectedSets = { "M20", "MED", "SLD", "M14", "DMR" };
List<PaperCard> cards = new ArrayList<>(); List<PaperCard> cards = new ArrayList<>();
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
String cardName = cardNames[i]; String cardName = cardNames[i];

View File

@@ -60,6 +60,8 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
// Fantasy/Chaos mode settings. // Fantasy/Chaos mode settings.
private boolean fantasyMode = false; private boolean fantasyMode = false;
private boolean announceFantasy = false; private boolean announceFantasy = false;
private boolean usingCustomDeck = false;
private boolean announceCustom = false;
// Signals // Signals
SignalList onLifeTotalChangeList = new SignalList(); SignalList onLifeTotalChangeList = new SignalList();
@@ -83,6 +85,7 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
//Reset all properties HERE. //Reset all properties HERE.
fantasyMode = false; fantasyMode = false;
announceFantasy = false; announceFantasy = false;
usingCustomDeck = false;
blessing = null; blessing = null;
gold = 0; gold = 0;
maxLife = 20; maxLife = 20;
@@ -104,9 +107,10 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
private final CardPool cards=new CardPool(); private final CardPool cards=new CardPool();
private final ItemPool<InventoryItem> newCards=new ItemPool<>(InventoryItem.class); private final ItemPool<InventoryItem> newCards=new ItemPool<>(InventoryItem.class);
public void create(String n, Deck startingDeck, boolean male, int race, int avatar, boolean isFantasy, DifficultyData difficultyData) { public void create(String n, Deck startingDeck, boolean male, int race, int avatar, boolean isFantasy, boolean isUsingCustomDeck, DifficultyData difficultyData) {
clear(); clear();
announceFantasy = fantasyMode = isFantasy; //Set Chaos mode first. announceFantasy = fantasyMode = isFantasy; //Set Chaos mode first.
announceCustom = usingCustomDeck = isUsingCustomDeck;
deck = startingDeck; deck = startingDeck;
decks[0] = deck; decks[0] = deck;
@@ -289,6 +293,8 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
fantasyMode = data.containsKey("fantasyMode") ? data.readBool("fantasyMode") : false; fantasyMode = data.containsKey("fantasyMode") ? data.readBool("fantasyMode") : false;
announceFantasy = data.containsKey("announceFantasy") ? data.readBool("announceFantasy") : false; announceFantasy = data.containsKey("announceFantasy") ? data.readBool("announceFantasy") : false;
usingCustomDeck = data.containsKey("usingCustomDeck") ? data.readBool("usingCustomDeck") : false;
announceCustom = data.containsKey("announceCustom") ? data.readBool("announceCustom") : false;
onLifeTotalChangeList.emit(); onLifeTotalChangeList.emit();
onGoldChangeList.emit(); onGoldChangeList.emit();
@@ -315,6 +321,8 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
data.store("fantasyMode",fantasyMode); data.store("fantasyMode",fantasyMode);
data.store("announceFantasy",announceFantasy); data.store("announceFantasy",announceFantasy);
data.store("usingCustomDeck", usingCustomDeck);
data.store("announceCustom", announceCustom);
data.store("worldPosX",worldPosX); data.store("worldPosX",worldPosX);
data.store("worldPosY",worldPosY); data.store("worldPosY",worldPosY);
@@ -493,6 +501,9 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
public boolean isFantasyMode(){ public boolean isFantasyMode(){
return fantasyMode; return fantasyMode;
} }
public boolean isUsingCustomDeck(){
return usingCustomDeck;
}
public boolean hasAnnounceFantasy(){ public boolean hasAnnounceFantasy(){
return announceFantasy; return announceFantasy;
@@ -501,6 +512,12 @@ public class AdventurePlayer implements Serializable, SaveFileContent {
public void clearAnnounceFantasy(){ public void clearAnnounceFantasy(){
announceFantasy = false; announceFantasy = false;
} }
public boolean hasAnnounceCustom(){
return announceCustom;
}
public void clearAnnounceCustom(){
announceCustom = false;
}
public boolean hasColorView() { public boolean hasColorView() {
for(String name:equippedItems.values()) { for(String name:equippedItems.values()) {

View File

@@ -73,8 +73,9 @@ public class DuelScene extends ForgeScene {
public void GameEnd() { public void GameEnd() {
boolean winner = humanPlayer == hostedMatch.getGame().getMatch().getWinner(); boolean winner = humanPlayer == hostedMatch.getGame().getMatch().getWinner();
String enemyName = (enemy.nameOverride.isEmpty() ? enemy.getData().name : enemy.nameOverride); String enemyName = (enemy.nameOverride.isEmpty() ? enemy.getData().name : enemy.nameOverride);
boolean showMessages = enemy.getData().copyPlayerDeck && Current.player().isUsingCustomDeck();
Current.player().clearBlessing(); Current.player().clearBlessing();
if (chaosBattle && !winner) { if ((chaosBattle||showMessages) && !winner) {
callbackExit = true; callbackExit = true;
List<String> insult = Lists.newArrayList("I'm sorry...", "... ....", "Learn from your defeat.", List<String> insult = Lists.newArrayList("I'm sorry...", "... ....", "Learn from your defeat.",
"I haven't begun to use my full power.", "No matter how much you try, you still won't beat me.", "I haven't begun to use my full power.", "No matter how much you try, you still won't beat me.",
@@ -233,7 +234,7 @@ public class DuelScene extends ForgeScene {
this.AIExtras = aiCards; this.AIExtras = aiCards;
deck = deckProxy.getDeck(); deck = deckProxy.getDeck();
} else { } else {
deck = currentEnemy.copyPlayerDeck ? this.playerDeck : currentEnemy.generateDeck(Current.player().isFantasyMode(), Current.player().getDifficulty().name.equalsIgnoreCase("Hard")); deck = currentEnemy.copyPlayerDeck ? this.playerDeck : currentEnemy.generateDeck(Current.player().isFantasyMode(), Current.player().isUsingCustomDeck()||Current.player().getDifficulty().name.equalsIgnoreCase("Hard"));
} }
RegisteredPlayer aiPlayer = RegisteredPlayer.forVariants(playerCount, appliedVariants, deck, null, false, null, null); RegisteredPlayer aiPlayer = RegisteredPlayer.forVariants(playerCount, appliedVariants, deck, null, false, null, null);
@@ -285,7 +286,8 @@ public class DuelScene extends ForgeScene {
hostedMatch.setEndGameHook(() -> DuelScene.this.GameEnd()); hostedMatch.setEndGameHook(() -> DuelScene.this.GameEnd());
hostedMatch.startMatch(rules, appliedVariants, players, guiMap); hostedMatch.startMatch(rules, appliedVariants, players, guiMap);
MatchController.instance.setGameView(hostedMatch.getGameView()); MatchController.instance.setGameView(hostedMatch.getGameView());
if (chaosBattle) { boolean showMessages = enemy.getData().copyPlayerDeck && Current.player().isUsingCustomDeck();
if (chaosBattle||showMessages) {
List<String> list = Lists.newArrayList("It all depends on your skill!", "It's showtime!", "Let's party!", List<String> list = Lists.newArrayList("It all depends on your skill!", "It's showtime!", "Let's party!",
"You've proved yourself!", "Are you ready? Go!", "Prepare to strike, now!", "Let's go!", "What's next?", "You've proved yourself!", "Are you ready? Go!", "Prepare to strike, now!", "Let's go!", "What's next?",
"Yeah, I've been waitin' for this!", "The stage of battle is set!", "And the battle begins!", "Let's get started!", "Yeah, I've been waitin' for this!", "The stage of battle is set!", "And the battle begins!", "Let's get started!",

View File

@@ -15,6 +15,7 @@ import forge.adventure.util.Selector;
import forge.adventure.util.UIActor; import forge.adventure.util.UIActor;
import forge.adventure.world.WorldSave; import forge.adventure.world.WorldSave;
import forge.card.ColorSet; import forge.card.ColorSet;
import forge.deck.DeckProxy;
import forge.localinstance.properties.ForgePreferences; import forge.localinstance.properties.ForgePreferences;
import forge.model.FModel; import forge.model.FModel;
import forge.player.GamePlayerUtil; import forge.player.GamePlayerUtil;
@@ -36,7 +37,8 @@ public class NewGameScene extends UIScene {
private Selector gender; private Selector gender;
private Selector mode; private Selector mode;
private Selector difficulty; private Selector difficulty;
private Array<String> stringList, random; private Array<String> stringList, random, custom;
private Label colorLabel;
public NewGameScene() { public NewGameScene() {
super(Forge.isLandscapeMode() ? "ui/new_game.json" : "ui/new_game_portrait.json"); super(Forge.isLandscapeMode() ? "ui/new_game.json" : "ui/new_game_portrait.json");
@@ -54,7 +56,7 @@ public class NewGameScene extends UIScene {
avatarIndex, avatarIndex,
colorIds[colorId.getCurrentIndex()], colorIds[colorId.getCurrentIndex()],
Config.instance().getConfigData().difficulties[difficulty.getCurrentIndex()], Config.instance().getConfigData().difficulties[difficulty.getCurrentIndex()],
mode.getCurrentIndex()==2, mode.getCurrentIndex()==1, 0);//maybe replace with enum mode.getCurrentIndex() == 2, mode.getCurrentIndex() == 1, mode.getCurrentIndex() == 3, colorId.getCurrentIndex(), 0);//maybe replace with enum
GamePlayerUtil.getGuiPlayer().setName(selectedName.getText()); GamePlayerUtil.getGuiPlayer().setName(selectedName.getText());
Forge.switchScene(SceneType.GameScene.instance); Forge.switchScene(SceneType.GameScene.instance);
}; };
@@ -75,7 +77,12 @@ public class NewGameScene extends UIScene {
avatarImage = ui.findActor("avatarPreview"); avatarImage = ui.findActor("avatarPreview");
gender = ui.findActor("gender"); gender = ui.findActor("gender");
mode = ui.findActor("mode"); mode = ui.findActor("mode");
mode.setTextList(new String[]{"Standard", "Constructed","Chaos"}); colorLabel = ui.findActor("colorIdL");
String colorIdLabel = colorLabel.getText().toString();
custom = new Array<>();
for (DeckProxy deckProxy : DeckProxy.getAllCustomStarterDecks())
custom.add(deckProxy.getName());
mode.setTextList(custom.isEmpty() ? new String[]{"Standard", "Constructed", "Chaos"} : new String[]{"Standard", "Constructed", "Chaos", "Custom"});
gender.setTextList(new String[]{"Male", "Female"}); gender.setTextList(new String[]{"Male", "Female"});
gender.addListener(event -> NewGameScene.this.updateAvatar()); gender.addListener(event -> NewGameScene.this.updateAvatar());
Random rand = new Random(); Random rand = new Random();
@@ -94,9 +101,12 @@ public class NewGameScene extends UIScene {
mode.addListener(new ChangeListener() { mode.addListener(new ChangeListener() {
@Override @Override
public void changed(ChangeEvent changeEvent, Actor actor) { public void changed(ChangeEvent changeEvent, Actor actor) {
colorLabel.setText(mode.getCurrentIndex() < 2 ? colorIdLabel : Forge.getLocalizer().getMessage("lblDeck")+":");
if (mode.getCurrentIndex() == 3)
colorId.setTextList(custom);
if (mode.getCurrentIndex() == 2) if (mode.getCurrentIndex() == 2)
colorId.setTextList(random); colorId.setTextList(random);
else if (mode.getCurrentIndex() < 2)
colorId.setTextList(stringList); colorId.setTextList(stringList);
} }
}); });
@@ -125,9 +135,6 @@ public class NewGameScene extends UIScene {
ui.onButtonPress("start", () -> NewGameScene.this.start()); ui.onButtonPress("start", () -> NewGameScene.this.start());
ui.onButtonPress("leftAvatar", () -> NewGameScene.this.leftAvatar()); ui.onButtonPress("leftAvatar", () -> NewGameScene.this.leftAvatar());
ui.onButtonPress("rightAvatar", () -> NewGameScene.this.rightAvatar()); ui.onButtonPress("rightAvatar", () -> NewGameScene.this.rightAvatar());
} }
private void rightAvatar() { private void rightAvatar() {
@@ -156,8 +163,7 @@ public class NewGameScene extends UIScene {
updateAvatar(); updateAvatar();
Gdx.input.setInputProcessor(stage); //Start taking input from the ui Gdx.input.setInputProcessor(stage); //Start taking input from the ui
if(Forge.createNewAdventureMap) if (Forge.createNewAdventureMap) {
{
FModel.getPreferences().setPref(ForgePreferences.FPref.UI_ENABLE_MUSIC, false); FModel.getPreferences().setPref(ForgePreferences.FPref.UI_ENABLE_MUSIC, false);
WorldSave.generateNewWorld(selectedName.getText(), WorldSave.generateNewWorld(selectedName.getText(),
gender.getCurrentIndex() == 0, gender.getCurrentIndex() == 0,
@@ -165,7 +171,7 @@ public class NewGameScene extends UIScene {
avatarIndex, avatarIndex,
colorIds[colorId.getCurrentIndex()], colorIds[colorId.getCurrentIndex()],
Config.instance().getConfigData().difficulties[difficulty.getCurrentIndex()], Config.instance().getConfigData().difficulties[difficulty.getCurrentIndex()],
mode.getCurrentIndex()==2, mode.getCurrentIndex()==1, 0);//maybe replace with enum mode.getCurrentIndex() == 2, mode.getCurrentIndex() == 1, mode.getCurrentIndex() == 3, colorId.getCurrentIndex(), 0);//maybe replace with enum
GamePlayerUtil.getGuiPlayer().setName(selectedName.getText()); GamePlayerUtil.getGuiPlayer().setName(selectedName.getText());
Forge.switchScene(SceneType.GameScene.instance); Forge.switchScene(SceneType.GameScene.instance);
} }

View File

@@ -195,7 +195,7 @@ public static ConsoleCommandInterpreter getInstance()
}); });
registerCommand(new String[]{"dumpEnemyDeckColors"}, s -> { registerCommand(new String[]{"dumpEnemyDeckColors"}, s -> {
for(EnemyData E : new Array.ArrayIterator<>(WorldData.getAllEnemies())){ for(EnemyData E : new Array.ArrayIterator<>(WorldData.getAllEnemies())){
Deck D = E.generateDeck(Current.player().isFantasyMode(), Current.player().getDifficulty().name.equalsIgnoreCase("Hard")); Deck D = E.generateDeck(Current.player().isFantasyMode(), Current.player().isUsingCustomDeck()||Current.player().getDifficulty().name.equalsIgnoreCase("Hard"));
DeckProxy DP = new DeckProxy(D, "Constructed", GameType.Constructed, null); DeckProxy DP = new DeckProxy(D, "Constructed", GameType.Constructed, null);
ColorSet colorSet = DP.getColor(); ColorSet colorSet = DP.getColor();
System.out.printf("%s: Colors: %s (%s%s%s%s%s%s)\n", D.getName(), DP.getColor(), System.out.printf("%s: Colors: %s (%s%s%s%s%s%s)\n", D.getName(), DP.getColor(),
@@ -211,7 +211,7 @@ public static ConsoleCommandInterpreter getInstance()
}); });
registerCommand(new String[]{"dumpEnemyDeckList"}, s -> { registerCommand(new String[]{"dumpEnemyDeckList"}, s -> {
for(EnemyData E : new Array.ArrayIterator<>(WorldData.getAllEnemies())){ for(EnemyData E : new Array.ArrayIterator<>(WorldData.getAllEnemies())){
Deck D = E.generateDeck(Current.player().isFantasyMode(), Current.player().getDifficulty().name.equalsIgnoreCase("Hard")); Deck D = E.generateDeck(Current.player().isFantasyMode(), Current.player().isUsingCustomDeck()||Current.player().getDifficulty().name.equalsIgnoreCase("Hard"));
DeckProxy DP = new DeckProxy(D, "Constructed", GameType.Constructed, null); DeckProxy DP = new DeckProxy(D, "Constructed", GameType.Constructed, null);
ColorSet colorSet = DP.getColor(); ColorSet colorSet = DP.getColor();
System.out.printf("Deck: %s\n%s\n\n", D.getName(), DP.getDeck().getMain().toCardList("\n") System.out.printf("Deck: %s\n%s\n\n", D.getName(), DP.getDeck().getMain().toCardList("\n")
@@ -221,7 +221,7 @@ public static ConsoleCommandInterpreter getInstance()
}); });
registerCommand(new String[]{"dumpEnemyColorIdentity"}, s -> { registerCommand(new String[]{"dumpEnemyColorIdentity"}, s -> {
for(EnemyData E : new Array.ArrayIterator<>(WorldData.getAllEnemies())){ for(EnemyData E : new Array.ArrayIterator<>(WorldData.getAllEnemies())){
Deck D = E.generateDeck(Current.player().isFantasyMode(), Current.player().getDifficulty().name.equalsIgnoreCase("Hard")); Deck D = E.generateDeck(Current.player().isFantasyMode(), Current.player().isUsingCustomDeck()||Current.player().getDifficulty().name.equalsIgnoreCase("Hard"));
DeckProxy DP = new DeckProxy(D, "Constructed", GameType.Constructed, null); DeckProxy DP = new DeckProxy(D, "Constructed", GameType.Constructed, null);
ColorSet colorSet = DP.getColor(); ColorSet colorSet = DP.getColor();
System.out.printf("%s Colors: %s | Deck Colors: %s (%s)\n", E.name, E.colors, DP.getColorIdentity().toEnumSet().toString(), DP.getName() System.out.printf("%s Colors: %s | Deck Colors: %s (%s)\n", E.name, E.colors, DP.getColorIdentity().toEnumSet().toString(), DP.getName()

View File

@@ -153,25 +153,19 @@ public class WorldStage extends GameStage implements SaveFileContent {
if (playerIsWinner) { if (playerIsWinner) {
player.setAnimation(CharacterSprite.AnimationTypes.Attack); player.setAnimation(CharacterSprite.AnimationTypes.Attack);
currentMob.setAnimation(CharacterSprite.AnimationTypes.Death); currentMob.setAnimation(CharacterSprite.AnimationTypes.Death);
startPause(0.5f, new Runnable() { startPause(0.5f, () -> {
@Override
public void run() {
((RewardScene) SceneType.RewardScene.instance).loadRewards(currentMob.getRewards(), RewardScene.Type.Loot, null); ((RewardScene) SceneType.RewardScene.instance).loadRewards(currentMob.getRewards(), RewardScene.Type.Loot, null);
WorldStage.this.removeEnemy(currentMob); WorldStage.this.removeEnemy(currentMob);
currentMob = null; currentMob = null;
Forge.switchScene(SceneType.RewardScene.instance); Forge.switchScene(SceneType.RewardScene.instance);
}
}); });
} else { } else {
player.setAnimation(CharacterSprite.AnimationTypes.Hit); player.setAnimation(CharacterSprite.AnimationTypes.Hit);
currentMob.setAnimation(CharacterSprite.AnimationTypes.Attack); currentMob.setAnimation(CharacterSprite.AnimationTypes.Attack);
startPause(0.5f, new Runnable() { startPause(0.5f, () -> {
@Override
public void run() {
Current.player().defeated(); Current.player().defeated();
WorldStage.this.removeEnemy(currentMob); WorldStage.this.removeEnemy(currentMob);
currentMob = null; currentMob = null;
}
}); });
} }
@@ -269,6 +263,11 @@ public class WorldStage extends GameStage implements SaveFileContent {
WorldSave.getCurrentSave().getPlayer().getSelectedDeck().getName()+ WorldSave.getCurrentSave().getPlayer().getSelectedDeck().getName()+
"\nEnemy will use Preconstructed or Random Generated Decks. Genetic AI Decks will be available to some enemies on Hard difficulty.", WorldSave.getCurrentSave().getPlayer().getSelectedDeck()); "\nEnemy will use Preconstructed or Random Generated Decks. Genetic AI Decks will be available to some enemies on Hard difficulty.", WorldSave.getCurrentSave().getPlayer().getSelectedDeck());
WorldSave.getCurrentSave().getPlayer().clearAnnounceFantasy(); WorldSave.getCurrentSave().getPlayer().clearAnnounceFantasy();
} else if (WorldSave.getCurrentSave().getPlayer().hasAnnounceCustom()) {
MapStage.getInstance().showDeckAwardDialog("{GRADIENT}Custom Deck Mode!{ENDGRADIENT}\n"+ WorldSave.getCurrentSave().getPlayer().getName()+ "'s Deck: "+
WorldSave.getCurrentSave().getPlayer().getSelectedDeck().getName()+
"\nSome enemies will use Genetic AI Decks randomly.", WorldSave.getCurrentSave().getPlayer().getSelectedDeck());
WorldSave.getCurrentSave().getPlayer().clearAnnounceCustom();
} }
} }

View File

@@ -535,7 +535,7 @@ public class CardUtil {
if(path.endsWith(".dck")) if(path.endsWith(".dck"))
return DeckSerializer.fromFile(new File(Config.instance().getFilePath(path))); return DeckSerializer.fromFile(new File(Config.instance().getFilePath(path)));
if(forAI && isFantasyMode) { if(forAI && (isFantasyMode||useGeneticAI)) {
Deck deck = DeckgenUtil.getRandomOrPreconOrThemeDeck(colors, forAI, isTheme, useGeneticAI); Deck deck = DeckgenUtil.getRandomOrPreconOrThemeDeck(colors, forAI, isTheme, useGeneticAI);
if (deck != null) if (deck != null)
return deck; return deck;

View File

@@ -9,6 +9,7 @@ import forge.adventure.util.SaveFileData;
import forge.adventure.util.SignalList; import forge.adventure.util.SignalList;
import forge.card.ColorSet; import forge.card.ColorSet;
import forge.deck.Deck; import forge.deck.Deck;
import forge.deck.DeckProxy;
import forge.deck.DeckgenUtil; import forge.deck.DeckgenUtil;
import forge.localinstance.properties.ForgeConstants; import forge.localinstance.properties.ForgeConstants;
import forge.player.GamePlayerUtil; import forge.player.GamePlayerUtil;
@@ -122,20 +123,15 @@ public class WorldSave {
return currentSave; return currentSave;
} }
public static WorldSave generateNewWorld(String name, boolean male, int race, int avatarIndex, ColorSet startingColorIdentity, DifficultyData diff, boolean chaos, boolean constructed, long seed) { public static WorldSave generateNewWorld(String name, boolean male, int race, int avatarIndex, ColorSet startingColorIdentity, DifficultyData diff, boolean chaos, boolean constructed, boolean custom, int customDeckIndex, long seed) {
currentSave.world.generateNew(seed); currentSave.world.generateNew(seed);
currentSave.pointOfInterestChanges.clear(); currentSave.pointOfInterestChanges.clear();
Deck starterDeck = chaos ? DeckgenUtil.getRandomOrPreconOrThemeDeck("", false, false, false) : Config.instance().starterDeck(startingColorIdentity,diff,constructed); Deck starterDeck = chaos ? DeckgenUtil.getRandomOrPreconOrThemeDeck("", false, false, false) : custom ? DeckProxy.getAllCustomStarterDecks().get(customDeckIndex).getDeck() : Config.instance().starterDeck(startingColorIdentity,diff,constructed);
currentSave.player.create(name, starterDeck, male, race, avatarIndex, chaos, custom, diff);
currentSave.player.create(name, starterDeck, male, race, avatarIndex, chaos, diff);
currentSave.player.setWorldPosY((int) (currentSave.world.getData().playerStartPosY * currentSave.world.getData().height * currentSave.world.getTileSize())); currentSave.player.setWorldPosY((int) (currentSave.world.getData().playerStartPosY * currentSave.world.getData().height * currentSave.world.getTileSize()));
currentSave.player.setWorldPosX((int) (currentSave.world.getData().playerStartPosX * currentSave.world.getData().width * currentSave.world.getTileSize())); currentSave.player.setWorldPosX((int) (currentSave.world.getData().playerStartPosX * currentSave.world.getData().width * currentSave.world.getTileSize()));
//after getting deck override starting color identity to match
//if (identity != startingColorIdentity)
// currentSave.player.setColorIdentity(identity);
currentSave.onLoadList.emit(); currentSave.onLoadList.emit();
return currentSave; return currentSave;
//return currentSave = ret;
} }
public boolean autoSave() { public boolean autoSave() {

View File

@@ -43,7 +43,7 @@
<dependency> <dependency>
<groupId>com.github.tommyettinger</groupId> <groupId>com.github.tommyettinger</groupId>
<artifactId>textratypist</artifactId> <artifactId>textratypist</artifactId>
<version>2f773002a8</version> <version>0.7.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.github.tommyettinger</groupId> <groupId>com.github.tommyettinger</groupId>

View File

@@ -3,8 +3,8 @@ ManaCost:4 U U
Types:Creature Shapeshifter Types:Creature Shapeshifter
PT:4/5 PT:4/5
A:AB$ ChangeZone | Cost$ U | Defined$ Self | Origin$ Battlefield | Destination$ Exile | SubAbility$ DelTrig | RememberChanged$ True | SpellDescription$ Exile CARDNAME. Return it to the battlefield under its owner's control at the beginning of the next end step. A:AB$ ChangeZone | Cost$ U | Defined$ Self | Origin$ Battlefield | Destination$ Exile | SubAbility$ DelTrig | RememberChanged$ True | SpellDescription$ Exile CARDNAME. Return it to the battlefield under its owner's control at the beginning of the next end step.
SVar:DelTrig:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | Execute$ TrigReturn | ConditionDefined$ Remembered | ConditionPresent$ Card | TriggerDescription$ Return CARDNAME to the battlefield. SVar:DelTrig:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | Execute$ TrigReturn | ConditionDefined$ Remembered | ConditionPresent$ Card | RememberObjects$ Remembered | TriggerDescription$ Return CARDNAME to the battlefield.
SVar:TrigReturn:DB$ ChangeZone | Defined$ Self | Origin$ Exile | Destination$ Battlefield SVar:TrigReturn:DB$ ChangeZone | Defined$ DelayTriggerRememberedLKI | Origin$ Exile | Destination$ Battlefield
A:AB$ Pump | Cost$ U | Defined$ Self | KW$ HIDDEN Unblockable | SpellDescription$ CARDNAME can't be blocked this turn. A:AB$ Pump | Cost$ U | Defined$ Self | KW$ HIDDEN Unblockable | SpellDescription$ CARDNAME can't be blocked this turn.
A:AB$ Pump | Cost$ 1 | Defined$ Self | NumAtt$ +1 | NumDef$ -1 | SpellDescription$ CARDNAME gets +1/-1 until end of turn. A:AB$ Pump | Cost$ 1 | Defined$ Self | NumAtt$ +1 | NumDef$ -1 | SpellDescription$ CARDNAME gets +1/-1 until end of turn.
A:AB$ Pump | Cost$ 1 | Defined$ Self | NumAtt$ -1 | NumDef$ +1 | SpellDescription$ CARDNAME gets -1/+1 until end of turn. A:AB$ Pump | Cost$ 1 | Defined$ Self | NumAtt$ -1 | NumDef$ +1 | SpellDescription$ CARDNAME gets -1/+1 until end of turn.

View File

@@ -3,7 +3,7 @@ ManaCost:1 G W
Types:Creature Frog Beast Types:Creature Frog Beast
PT:3/4 PT:3/4
A:AB$ ChangeZone | Cost$ Discard<2/Card> | Defined$ Self | Origin$ Battlefield | Destination$ Exile | SubAbility$ DelTrig | RememberChanged$ True | SpellDescription$ Exile CARDNAME. Return it to the battlefield under its owner's control at the beginning of the next end step. A:AB$ ChangeZone | Cost$ Discard<2/Card> | Defined$ Self | Origin$ Battlefield | Destination$ Exile | SubAbility$ DelTrig | RememberChanged$ True | SpellDescription$ Exile CARDNAME. Return it to the battlefield under its owner's control at the beginning of the next end step.
SVar:DelTrig:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | Execute$ TrigReturn | ConditionDefined$ Remembered | ConditionPresent$ Card | TriggerDescription$ Return CARDNAME to the battlefield. SVar:DelTrig:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | Execute$ TrigReturn | ConditionDefined$ Remembered | ConditionPresent$ Card | RememberObjects$ Remembered | TriggerDescription$ Return CARDNAME to the battlefield.
SVar:TrigReturn:DB$ ChangeZone | Origin$ Exile | Destination$ Battlefield | Defined$ Self SVar:TrigReturn:DB$ ChangeZone | Origin$ Exile | Destination$ Battlefield | Defined$ DelayTriggerRememberedLKI
AI:RemoveDeck:All AI:RemoveDeck:All
Oracle:Discard two cards: Exile Anurid Brushhopper. Return it to the battlefield under its owner's control at the beginning of the next end step. Oracle:Discard two cards: Exile Anurid Brushhopper. Return it to the battlefield under its owner's control at the beginning of the next end step.

View File

@@ -0,0 +1,9 @@
Name:Baird, Argivian Recruiter
ManaCost:R W
Types:Legendary Creature Human Soldier
PT:2/2
T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigToken | IsPresent$ Creature.YouCtrl+powerGTbasePower | TriggerDescription$ At the beginning of your end step, if you control a creature with power greater than its base power, create a 1/1 white Soldier creature token.
SVar:TrigToken:DB$ Token | TokenScript$ w_1_1_soldier
DeckHas:Ability$Token
AI:RemoveDeck:Random
Oracle:At the beginning of your end step, if you control a creature with power greater than its base power, create a 1/1 white Soldier creature token.

Some files were not shown because too many files have changed in this diff Show More