Resolve "Daybound & Nightbound"

This commit is contained in:
Hans Mackowiak
2021-10-15 13:20:36 +00:00
committed by Sol
parent fa09c3fa7b
commit 997e566af0
104 changed files with 1581 additions and 189 deletions

View File

@@ -306,7 +306,7 @@ public class CountersPutAi extends CountersAi {
}
} else if (logic.equals("CheckDFC")) {
// for cards like Ludevic's Test Subject
if (!source.canTransform()) {
if (!source.canTransform(null)) {
return false;
}
} else if (logic.startsWith("MoveCounter")) {

View File

@@ -1,18 +1,20 @@
package forge.ai.ability;
import java.util.List;
import com.google.common.base.Predicate;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCost;
import forge.ai.SpellAbilityAi;
import forge.card.CardStateName;
import forge.game.Game;
import forge.game.GlobalRuleChange;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates.Presets;
import forge.game.card.CardPredicates;
import forge.game.card.CardState;
import forge.game.card.CardUtil;
import forge.game.card.CounterEnumType;
@@ -67,12 +69,11 @@ public class SetStateAi extends SpellAbilityAi {
final String mode = sa.getParam("Mode");
final Card source = sa.getHostCard();
final String logic = sa.getParamOrDefault("AILogic", "");
final Game game = source.getGame();
if ("Transform".equals(mode)) {
if (!sa.usesTargeting()) {
// no Transform with Defined which is not Self
if (!source.canTransform()) {
if (!source.canTransform(sa)) {
return false;
}
return shouldTransformCard(source, ai, ph) || "Always".equals(logic);
@@ -80,15 +81,13 @@ public class SetStateAi extends SpellAbilityAi {
final TargetRestrictions tgt = sa.getTargetRestrictions();
sa.resetTargets();
CardCollection list = CardLists.getValidCards(CardLists.filter(game.getCardsIn(ZoneType.Battlefield), Presets.CREATURES), tgt.getValidTgts(), ai, source, sa);
// select only the ones that can transform
list = CardLists.filter(list, new Predicate<Card>() {
CardCollection list = CardLists.filter(CardUtil.getValidCardsToTarget(tgt, sa), CardPredicates.Presets.CREATURES, new Predicate<Card>() {
@Override
public boolean apply(Card c) {
return c.canTransform();
return c.canTransform(sa);
}
});
list = CardLists.getTargetableCards(list, sa);
if (list.isEmpty()) {
return false;
@@ -116,8 +115,7 @@ public class SetStateAi extends SpellAbilityAi {
final TargetRestrictions tgt = sa.getTargetRestrictions();
sa.resetTargets();
CardCollection list = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), tgt.getValidTgts(), ai, source, sa);
list = CardLists.getTargetableCards(list, sa);
List<Card> list = CardUtil.getValidCardsToTarget(tgt, sa);
if (list.isEmpty()) {
return false;
@@ -126,13 +124,13 @@ public class SetStateAi extends SpellAbilityAi {
for (final Card c : list) {
if (shouldTurnFace(c, ai, ph) || "Always".equals(logic)) {
sa.getTargets().add(c);
if (sa.getTargets().size() == tgt.getMaxTargets(source, sa)) {
if (!sa.canAddMoreTarget()) {
break;
}
}
}
return sa.getTargets().size() >= tgt.getMinTargets(source, sa);
return sa.isTargetNumberValid();
}
}
return true;

View File

@@ -7,6 +7,7 @@ import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import forge.card.CardStateName;
@@ -16,8 +17,8 @@ import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardState;
import forge.game.card.CardUtil;
import forge.game.card.CardView;
import forge.game.card.IHasCardView;
import forge.game.player.Player;
@@ -264,6 +265,22 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView,
if ("True".equalsIgnoreCase(params.get("Blessing")) != hostController.hasBlessing()) return false;
}
if (params.containsKey("DayTime")) {
if ("Day".equalsIgnoreCase(params.get("DayTime"))) {
if (!game.isDay()) {
return false;
}
} else if ("Night".equalsIgnoreCase(params.get("DayTime"))) {
if (!game.isNight()) {
return false;
}
} else if ("Neither".equalsIgnoreCase(params.get("DayTime"))) {
if (!game.isNeitherDayNorNight()) {
return false;
}
}
}
if (params.containsKey("Adamant")) {
if (hostCard.getCastSA() == null) {
return false;
@@ -450,7 +467,7 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView,
}
if (params.containsKey("WerewolfTransformCondition")) {
if (!CardUtil.getLastTurnCast("Card", this.getHostCard(), this).isEmpty()) {
if (!game.getStack().getSpellsCastLastTurn().isEmpty()) {
return false;
}
}
@@ -459,7 +476,10 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView,
List<Card> casted = game.getStack().getSpellsCastLastTurn();
boolean conditionMet = false;
for (Player p : game.getPlayers()) {
conditionMet |= CardLists.filterControlledBy(casted, p).size() > 1;
if (Iterables.size(Iterables.filter(casted, CardPredicates.isController(p))) > 1) {
conditionMet = true;
break;
}
}
if (!conditionMet) {
return false;

View File

@@ -167,6 +167,10 @@ public class ForgeScript {
return sa.isForetold();
} else if (property.equals("ClassLevelUp")) {
return sa.getApi() == ApiType.ClassLevelUp;
} else if (property.equals("Daybound")) {
return sa.hasParam("Daybound");
} else if (property.equals("Nightbound")) {
return sa.hasParam("Nightbound");
} else if (property.equals("MayPlaySource")) {
StaticAbility m = sa.getMayPlay();
if (m == null) {

View File

@@ -26,6 +26,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import forge.game.event.GameEventDayTimeChanged;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Predicate;
@@ -129,6 +130,8 @@ public class Game {
private Direction turnOrder = Direction.getDefaultDirection();
private Boolean daytime = null;
private long timestamp = 0;
public final GameAction action;
private final Match match;
@@ -1164,4 +1167,29 @@ public class Game {
public void addFacedownWhileCasting(Card c, int numDrawn) {
facedownWhileCasting.put(c, Integer.valueOf(numDrawn));
}
public boolean isDay() {
return this.daytime != null && this.daytime == false;
}
public boolean isNight() {
return this.daytime != null && this.daytime == true;
}
public boolean isNeitherDayNorNight() {
return this.daytime == null;
}
public Boolean getDayTime() {
return this.daytime;
}
public void setDayTime(Boolean value) {
Boolean previous = this.daytime;
this.daytime = value;
if (previous != null && value != null && previous != value) {
Map<AbilityKey, Object> params = AbilityKey.newMap();
this.getTriggerHandler().runTrigger(TriggerType.DayTimeChanges, params, false);
}
if (!isNeitherDayNorNight())
fireEvent(new GameEventDayTimeChanged(isDay()));
}
}

View File

@@ -126,7 +126,6 @@ public enum AbilityKey {
TgtSA("TgtSA"),
Token("Token"),
TokenNum("TokenNum"),
Transformer("Transformer"),
TriggeredParams("TriggeredParams"),
Vehicle("Vehicle"),
Won("Won");

View File

@@ -2275,6 +2275,10 @@ public class AbilityUtils {
return doXMath(player.getSpellsCastThisGame(), expr, c, ctb);
}
if (sq[0].equals("Night")) {
return doXMath(calculateAmount(c, sq[game.isNight() ? 1 : 2], ctb), expr, c, ctb);
}
if (sq[0].contains("CardControllerTypes")) {
return doXMath(getCardTypesFromList(player.getCardsIn(ZoneType.listValueOf(sq[1]))), expr, c, ctb);
}

View File

@@ -58,6 +58,7 @@ public enum ApiType {
Counter (CounterEffect.class),
DamageAll (DamageAllEffect.class),
DealDamage (DamageDealEffect.class),
DayTime (DayTimeEffect.class),
Debuff (DebuffEffect.class),
DeclareCombatants (DeclareCombatantsEffect.class),
DelayedTrigger (DelayedTriggerEffect.class),

View File

@@ -71,23 +71,38 @@ public class AttachEffect extends SpellAbilityEffect {
GameEntity attachTo;
if (sa.hasParam("Object") && sa.hasParam("Choices")) {
if (sa.hasParam("Object") && (sa.hasParam("Choices") || sa.hasParam("PlayerChoices"))) {
ZoneType choiceZone = ZoneType.Battlefield;
if (sa.hasParam("ChoiceZone")) {
choiceZone = ZoneType.smartValueOf(sa.getParam("ChoiceZone"));
}
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChoose") + " ";
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") :
Localizer.getInstance().getMessage("lblChoose") + " ";
CardCollection choices = CardLists.getValidCards(game.getCardsIn(choiceZone), sa.getParam("Choices"), p, source, sa);
// Object + Choices means Attach Aura/Equipment onto new another card it can attach
// if multiple attachments, all of them need to be able to attach to new card
for (final Card attachment : attachments) {
if (sa.hasParam("Move")) {
Card e = attachment.getAttachedTo();
if (e != null)
choices.remove(e);
FCollection<GameEntity> choices = new FCollection<>();
if (sa.hasParam("PlayerChoices")) {
choices = AbilityUtils.getDefinedEntities(source, sa.getParam("PlayerChoices"), sa);
for (final Card attachment : attachments) {
for (GameEntity g : choices) {
if (!g.canBeAttached(attachment)) {
choices.remove(g);
}
}
}
choices = CardLists.filter(choices, CardPredicates.canBeAttached(attachment));
} else {
CardCollection cardChoices = CardLists.getValidCards(game.getCardsIn(choiceZone),
sa.getParam("Choices"), p, source, sa);
// Object + Choices means Attach Aura/Equipment onto new another card it can attach
// if multiple attachments, all of them need to be able to attach to new card
for (final Card attachment : attachments) {
if (sa.hasParam("Move")) {
Card e = attachment.getAttachedTo();
if (e != null)
cardChoices.remove(e);
}
cardChoices = CardLists.filter(cardChoices, CardPredicates.canBeAttached(attachment));
}
choices.addAll(cardChoices);
}
Map<String, Object> params = Maps.newHashMap();

View File

@@ -0,0 +1,37 @@
package forge.game.ability.effects;
import forge.game.Game;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.spellability.SpellAbility;
public class DayTimeEffect extends SpellAbilityEffect {
@Override
protected String getStackDescription(SpellAbility sa) {
final StringBuilder sb = new StringBuilder();
sb.append("It becomes ").append(sa.getParam("Value").toLowerCase()).append(".");
return sb.toString();
}
@Override
public void resolve(SpellAbility sa) {
Card host = sa.getHostCard();
Game game = host.getGame();
String newValue = sa.getParam("Value");
if (newValue.equals("Day")) {
game.setDayTime(false);
} else if (newValue.equals("Night")) {
game.setDayTime(true);
} else if (newValue.equals("Switch")) {
// logic for the Celestus
Boolean oldValue = game.getDayTime();
if (oldValue == null) {
game.setDayTime(true); // if it was neither it becomes night
} else {
game.setDayTime(!oldValue);
}
}
}
}

View File

@@ -4,11 +4,9 @@ import forge.card.CardStateName;
import forge.game.Game;
import forge.game.GameEntityCounterTable;
import forge.game.GameLogEntryType;
import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardUtil;
import forge.game.card.CounterEnumType;
import forge.game.card.*;
import forge.game.event.GameEventCardStatsChanged;
import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode;
@@ -17,6 +15,7 @@ import forge.game.zone.ZoneType;
import forge.util.Lang;
import forge.util.Localizer;
import forge.util.TextUtil;
import org.apache.commons.lang3.StringUtils;
public class SetStateEffect extends SpellAbilityEffect {
@@ -47,9 +46,32 @@ public class SetStateEffect extends SpellAbilityEffect {
final boolean optional = sa.hasParam("Optional");
final CardCollection transformedCards = new CardCollection();
CardCollection cardsToTransform = new CardCollection();
if (sa.hasParam("Choices")) {
CardCollectionView choices = game.getCardsIn(ZoneType.Battlefield);
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), p, host, sa);
final String numericAmount = sa.getParamOrDefault("Amount", "1");
final int validAmount = StringUtils.isNumeric(numericAmount) ? Integer.parseInt(numericAmount) :
AbilityUtils.calculateAmount(host, numericAmount, sa);
final int minAmount = sa.hasParam("MinAmount") ? Integer.parseInt(sa.getParam("MinAmount")) :
validAmount;
if (validAmount <= 0) {
return;
}
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") :
Localizer.getInstance().getMessage("lblChooseaCard") + " ";
cardsToTransform.addAll(p.getController().chooseCardsForEffect(choices, sa, title, minAmount, validAmount,
!sa.hasParam("Mandatory"), null));
} else {
cardsToTransform = getTargetCards(sa);
}
GameEntityCounterTable table = new GameEntityCounterTable();
for (final Card tgtCard : getTargetCards(sa)) {
for (final Card tgtCard : cardsToTransform) {
// check if the object is still in game or if it was moved
Card gameCard = game.getCardState(tgtCard, null);
// gameCard is LKI in that case, the card is not in game anymore
@@ -65,7 +87,7 @@ public class SetStateEffect extends SpellAbilityEffect {
// Cards which are not on the battlefield should not be able to transform.
// TurnFace should be allowed in other zones like Exile too
if (!"TurnFace".equals(mode) && !gameCard.isInZone(ZoneType.Battlefield)) {
if (!"TurnFace".equals(mode) && !gameCard.isInZone(ZoneType.Battlefield) && !sa.hasParam("ETB")) {
continue;
}
@@ -112,7 +134,7 @@ public class SetStateEffect extends SpellAbilityEffect {
}
// for reasons it can't transform, skip
if ("Transform".equals(mode) && !gameCard.canTransform()) {
if ("Transform".equals(mode) && !gameCard.canTransform(sa)) {
continue;
}

View File

@@ -56,6 +56,7 @@ import forge.game.replacement.ReplacementType;
import forge.game.spellability.*;
import forge.game.staticability.StaticAbility;
import forge.game.staticability.StaticAbilityCantAttackBlock;
import forge.game.staticability.StaticAbilityCantTransform;
import forge.game.trigger.Trigger;
import forge.game.trigger.TriggerType;
import forge.game.zone.Zone;
@@ -576,7 +577,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
// Proof: Morph cards never have ability that makes them flip, Ixidron does not suppose cards to be turned face up again,
// Illusionary Mask affects cards in hand.
if (mode.equals("Transform") && (isDoubleFaced() || hasMergedCard())) {
if (!canTransform()) {
if (!canTransform(cause)) {
return false;
}
@@ -606,9 +607,11 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
// Clear old dfc trigger from the trigger handler
getGame().getTriggerHandler().clearActiveTriggers(this, null);
getGame().getTriggerHandler().registerActiveTrigger(this, false);
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
runParams.put(AbilityKey.Transformer, this);
getGame().getTriggerHandler().runTrigger(TriggerType.Transformed, runParams, false);
if (cause == null || !cause.hasParam("ETB")) {
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(this);
getGame().getTriggerHandler().runTrigger(TriggerType.Transformed, runParams, false);
}
incrementTransformedTimestamp();
return retResult;
@@ -761,7 +764,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
return false;
}
public boolean canTransform() {
public boolean canTransform(SpellAbility cause) {
if (isFaceDown()) {
return false;
}
@@ -794,7 +797,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
return false;
}
return !hasKeyword("CARDNAME can't transform");
return !StaticAbilityCantTransform.cantTransform(this, cause);
}
public int getHiddenId() {
@@ -2082,7 +2085,8 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|| keyword.equals("Suspend") // for the ones without amount
|| keyword.equals("Foretell") // for the ones without cost
|| keyword.equals("Hideaway") || keyword.equals("Ascend") || keyword.equals("Totem armor")
|| keyword.equals("Battle cry") || keyword.equals("Devoid") || keyword.equals("Riot")) {
|| keyword.equals("Battle cry") || keyword.equals("Devoid") || keyword.equals("Riot")
|| keyword.equals("Daybound") || keyword.equals("Nightbound")) {
sbLong.append(keyword).append(" (").append(inst.getReminderText()).append(")");
} else if (keyword.startsWith("Partner:")) {
final String[] k = keyword.split(":");

View File

@@ -978,6 +978,24 @@ public class CardFactoryUtil {
trigger.setOverridingAbility(AbilityFactory.getAbility(effect, card));
inst.addTrigger(trigger);
} else if (keyword.equals("Daybound")) {
// Set Day when it's Neither
final String setDayTrig = "Mode$ Always | TriggerZones$ Battlefield | Static$ True | DayTime$ Neither | Secondary$ True | TriggerDescription$ Any time a player controls a permanent with daybound, if its neither day nor night, it becomes day.";
String setDayEff = "DB$ DayTime | Value$ Day";
Trigger trigger = TriggerHandler.parseTrigger(setDayTrig, card, intrinsic);
trigger.setOverridingAbility(AbilityFactory.getAbility(setDayEff, card));
inst.addTrigger(trigger);
final String transformTrig = "Mode$ Always | TriggerZones$ Battlefield | Static$ True | DayTime$ Night | IsPresent$ Card.Self+FrontSide | Secondary$ True | TriggerDescription$ As it becomes night, if this permanent is front face up, transform it.";
String transformEff = "DB$ SetState | Mode$ Transform | Daybound$ True";
trigger = TriggerHandler.parseTrigger(transformTrig, card, intrinsic);
trigger.setOverridingAbility(AbilityFactory.getAbility(transformEff, card));
inst.addTrigger(trigger);
} else if (keyword.equals("Decayed")) {
final String attackTrig = "Mode$ Attacks | ValidCard$ Card.Self | Secondary$ True | TriggerDescription$ " +
"When a creature with decayed attacks, sacrifice it at end of combat.";
@@ -1507,6 +1525,24 @@ public class CardFactoryUtil {
parsedTrigger.setOverridingAbility(repeatSA);
inst.addTrigger(parsedTrigger);
} else if (keyword.equals("Nightbound")) {
// Set Night when it's Neither
final String setDayTrig = "Mode$ Always | TriggerZones$ Battlefield | Static$ True | DayTime$ Neither | IsPresent$ Card.Daybound | PresentCompare$ EQ0 | Secondary$ True | TriggerDescription$ Any time a player controls a permanent with nightbound, if its neither day nor night and there are no permanents with daybound on the battlefield, it becomes night.";
String setDayEff = "DB$ DayTime | Value$ Night";
Trigger trigger = TriggerHandler.parseTrigger(setDayTrig, card, intrinsic);
trigger.setOverridingAbility(AbilityFactory.getAbility(setDayEff, card));
inst.addTrigger(trigger);
final String transformTrig = "Mode$ Always | TriggerZones$ Battlefield | Static$ True | DayTime$ Day | IsPresent$ Card.Self+BackSide | Secondary$ True | TriggerDescription$ As it becomes day, if this permanent is back face up, transform it";
String transformEff = "DB$ SetState | Mode$ Transform | Nightbound$ True";
trigger = TriggerHandler.parseTrigger(transformTrig, card, intrinsic);
trigger.setOverridingAbility(AbilityFactory.getAbility(transformEff, card));
inst.addTrigger(trigger);
} else if (keyword.startsWith("Partner:")) {
// Partner With
final String[] k = keyword.split(":");
@@ -2124,6 +2160,17 @@ public class CardFactoryUtil {
re.setSVar("DredgeCheckLib", "Count$ValidLibrary Card.YouOwn");
inst.addReplacement(re);
} else if (keyword.equals("Daybound")) {
final String actualRep = "Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | DayTime$ Night | Secondary$ True | Description$ If it is night, this permanent enters the battlefield transformed.";
final String abTransform = "DB$ SetState | Defined$ ReplacedCard | Mode$ Transform | ETB$ True | Daybound$ True";
ReplacementEffect re = ReplacementHandler.parseReplacement(actualRep, host, intrinsic, card);
SpellAbility saTransform = AbilityFactory.getAbility(abTransform, card);
setupETBReplacementAbility(saTransform);
re.setOverridingAbility(saTransform);
inst.addReplacement(re);
} else if (keyword.startsWith("Devour")) {
final String[] k = keyword.split(":");
@@ -3438,6 +3485,8 @@ public class CardFactoryUtil {
}
} else if (keyword.startsWith("Dash")) {
effect = "Mode$ Continuous | Affected$ Card.Self+dashed | AddKeyword$ Haste";
} else if (keyword.equals("Daybound")) {
effect = "Mode$ CantTransform | ValidCard$ Creature.Self | ExceptCause$ SpellAbility.Daybound | Secondary$ True | Description$ This permanent cant be transformed except by its daybound ability.";
} else if (keyword.equals("Decayed")) {
effect = "Mode$ Continuous | Affected$ Card.Self | AddHiddenKeyword$ CARDNAME can't block. | " +
"Secondary$ True";
@@ -3490,6 +3539,8 @@ public class CardFactoryUtil {
} else if (keyword.equals("Intimidate")) {
effect = "Mode$ CantBlockBy | ValidAttacker$ Creature.Self | ValidBlocker$ Creature.nonArtifact+notSharesColorWith | Secondary$ True " +
" | Description$ Intimidate ( " + inst.getReminderText() + ")";
} else if (keyword.equals("Nightbound")) {
effect = "Mode$ CantTransform | ValidCard$ Creature.Self | ExceptCause$ SpellAbility.Nightbound | Secondary$ True | Description$ This permanent cant be transformed except by its nightbound ability.";
} else if (keyword.startsWith("Protection")) {
String valid = getProtectionValid(keyword, false);
effect = "Mode$ CantBlockBy | ValidAttacker$ Creature.Self ";

View File

@@ -114,6 +114,14 @@ public class CardProperty {
if (!card.isDoubleFaced()) {
return false;
}
} else if (property.equals("FrontSide")) {
if (card.isBackSide()) {
return false;
}
} else if (property.equals("BackSide")) {
if (!card.isBackSide()) {
return false;
}
} else if (property.equals("Flip")) {
if (!card.isFlipCard()) {
return false;

View File

@@ -0,0 +1,14 @@
package forge.game.event;
public class GameEventDayTimeChanged extends GameEvent {
public final boolean daytime;
public GameEventDayTimeChanged(final boolean daytime) {
this.daytime = daytime;
}
@Override
public <T> T visit(IGameEventVisitor<T> visitor) {
return visitor.visit(this);
}
}

View File

@@ -54,7 +54,7 @@ public interface IGameEventVisitor<T> {
T visit(GameEventTurnPhase event);
T visit(GameEventZone event);
T visit(GameEventCardForetold gameEventCardForetold);
T visit(GameEventDayTimeChanged gameEventDayTimeChanged);
// This is base class for all visitors.
class Base<T> implements IGameEventVisitor<T>{
@@ -109,5 +109,8 @@ public interface IGameEventVisitor<T> {
public T visit(GameEventCardForetold gameEventCardForetold) {
return null;
}
public T visit(GameEventDayTimeChanged gameEventDayTimeChanged) {
return null;
}
}
}

View File

@@ -45,6 +45,7 @@ public enum Keyword {
CUMULATIVE_UPKEEP("Cumulative upkeep", KeywordWithCost.class, false, "At the beginning of your upkeep, put an age counter on this permanent, then sacrifice it unless you pay its upkeep cost for each age counter on it."),
CYCLING("Cycling", KeywordWithCost.class, false, "%s, Discard this card: Draw a card."), //Typecycling reminder text handled by Cycling class
DASH("Dash", KeywordWithCost.class, false, "You may cast this spell for its dash cost. If you do, it gains haste, and it's returned from the battlefield to its owner's hand at the beginning of the next end step."),
DAYBOUND("Daybound", SimpleKeyword.class, true, "If a player casts no spells during their own turn, it becomes night next turn."),
DEATHTOUCH("Deathtouch", SimpleKeyword.class, true, "Any amount of damage this deals to a creature is enough to destroy it."),
DECAYED("Decayed", SimpleKeyword.class, true, "This creature can't block. When it attacks, sacrifice it at end of combat."),
DEFENDER("Defender", SimpleKeyword.class, true, "This creature can't attack."),
@@ -116,6 +117,7 @@ public enum Keyword {
MULTIKICKER("Multikicker", KeywordWithCost.class, false, "You may pay an additional %s any number of times as you cast this spell."),
MUTATE("Mutate", KeywordWithCost.class, true, "If you cast this spell for its mutate cost, put it over or under target non-Human creature you own. They mutate into the creature on top plus all abilities from under it."),
MYRIAD("Myriad", SimpleKeyword.class, false, "Whenever this creature attacks, for each opponent other than defending player, you may create a token that's a copy of this creature that's tapped and attacking that player or a planeswalker they control. Exile the tokens at end of combat."),
NIGHTBOUND("Nightbound", SimpleKeyword.class, true, "If a player casts at least two spells during their own turn, it becomes day next turn."),
NINJUTSU("Ninjutsu", Ninjutsu.class, false, "%s, Return an unblocked attacker you control to hand: Put this card onto the battlefield from your %s tapped and attacking."),
OUTLAST("Outlast", KeywordWithCost.class, false, "%s, {T}: Put a +1/+1 counter on this creature. Outlast only as a sorcery."),
OFFERING("Offering", KeywordWithType.class, false, "You may cast this card any time you could cast an instant by sacrificing a %1$s and paying the difference in mana costs between this and the sacrificed %1$s. Mana cost includes color."),

View File

@@ -14,7 +14,16 @@ public class KeywordWithCost extends KeywordInstance<KeywordWithCost> {
protected String formatReminderText(String reminderText) {
// some reminder does not contain cost
if (reminderText.contains("%")) {
return String.format(reminderText, cost.toSimpleString());
String costString = cost.toSimpleString();
if (reminderText.contains("pays %")) {
if (costString.startsWith("Pay ")) {
costString = costString.substring(4);
} else if (costString.startsWith("Discard ")) {
reminderText = reminderText.replace("pays", "");
costString = costString.replace("Discard", "discards");
}
}
return String.format(reminderText, costString);
} else {
return reminderText;
}

View File

@@ -95,6 +95,7 @@ public class PhaseHandler implements java.io.Serializable {
private int planarDiceRolledthisTurn = 0;
private transient Player playerTurn = null;
private transient Player playerPreviousTurn = null;
// priority player
@@ -142,6 +143,10 @@ public class PhaseHandler implements java.io.Serializable {
setPriority(playerTurn);
}
public final Player getPreviousPlayerTurn() {
return playerPreviousTurn;
}
public final Player getPriorityPlayer() {
return pPlayerPriority;
}
@@ -523,6 +528,8 @@ public class PhaseHandler implements java.io.Serializable {
if (!bRepeatCleanup) {
// only call onCleanupPhase when Cleanup is not repeated
game.onCleanupPhase();
// set previous player
playerPreviousTurn = this.getPlayerTurn();
setPlayerTurn(handleNextTurn());
// "Trigger" for begin turn to get around a phase skipping
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();

View File

@@ -24,6 +24,7 @@ import java.util.Map.Entry;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -33,6 +34,7 @@ import forge.game.ability.ApiType;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardPredicates.Presets;
import forge.game.keyword.Keyword;
import forge.game.keyword.KeywordInterface;
@@ -69,9 +71,9 @@ public class Untap extends Phase {
public void executeAt() {
this.execute(this.at);
final Player turn = game.getPhaseHandler().getPlayerTurn();
Untap.doPhasing(turn);
doPhasing(game.getPhaseHandler().getPlayerTurn());
doDayTime(game.getPhaseHandler().getPreviousPlayerTurn());
game.getAction().checkStaticAbilities();
doUntap();
@@ -273,19 +275,28 @@ public class Untap extends Phase {
} else if (c.hasKeyword(Keyword.PHASING)) {
// 702.23g If an object would simultaneously phase out directly
// and indirectly, it just phases out indirectly.
if (c.isAura() || c.isFortification()) {
if (c.isAttachment()) {
final Card ent = c.getAttachedTo();
if (ent != null && list.contains(ent)) {
continue;
}
} else if (c.isEquipment() && c.isEquipping()) {
if (list.contains(c.getEquipping())) {
continue;
}
}
c.phase(true);
}
}
}
private static void doDayTime(final Player previous) {
if (previous == null) {
return;
}
final Game game = previous.getGame();
List<Card> casted = game.getStack().getSpellsCastLastTurn();
if (game.isDay() && !Iterables.any(casted, CardPredicates.isController(previous))) {
game.setDayTime(true);
} else if (game.isNight() && Iterables.size(Iterables.filter(casted, CardPredicates.isController(previous))) > 1) {
game.setDayTime(false);
}
}
} //end class Untap

View File

@@ -484,6 +484,7 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone
if (condition.equals("Desert") && !controller.hasDesert()) return false;
if (condition.equals("Blessing") && !controller.hasBlessing()) return false;
if (condition.equals("Monarch") & !controller.isMonarch()) return false;
if (condition.equals("Night") & !game.isNight()) return false;
if (condition.equals("PlayerTurn")) {
if (!ph.isPlayerTurn(controller)) {

View File

@@ -0,0 +1,38 @@
package forge.game.staticability;
import forge.game.CardTraitBase;
import forge.game.Game;
import forge.game.card.Card;
import forge.game.zone.ZoneType;
public class StaticAbilityCantTransform {
static String MODE = "CantTransform";
static public boolean cantTransform(Card card, CardTraitBase cause) {
final Game game = card.getGame();
for (final Card ca : game.getCardsIn(ZoneType.STATIC_ABILITIES_SOURCE_ZONES)) {
for (final StaticAbility stAb : ca.getStaticAbilities()) {
if (!stAb.getParam("Mode").equals(MODE) || stAb.isSuppressed() || !stAb.checkConditions()) {
continue;
}
if (applyCantTransformAbility(stAb, card, cause)) {
return true;
}
}
}
return false;
}
static public boolean applyCantTransformAbility(StaticAbility stAb, Card card, CardTraitBase cause) {
if (!stAb.matchesValidParam("ValidCard", card)) {
return false;
}
if (stAb.hasParam("ExceptCause")) {
if (stAb.matchesValidParam("ExceptCause", cause)) {
return false;
}
}
return true;
}
}

View File

@@ -0,0 +1,29 @@
package forge.game.trigger;
import java.util.Map;
import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.spellability.SpellAbility;
public class TriggerDayTimeChanges extends Trigger {
public TriggerDayTimeChanges(Map<String, String> params, Card host, boolean intrinsic) {
super(params, host, intrinsic);
}
@Override
public boolean performTest(Map<AbilityKey, Object> runParams) {
return true;
}
@Override
public void setTriggeringObjects(SpellAbility sa, Map<AbilityKey, Object> runParams) {
}
@Override
public String getImportantStackObjects(SpellAbility sa) {
return "";
}
}

View File

@@ -46,7 +46,7 @@ public class TriggerTransformed extends Trigger {
*/
@Override
public boolean performTest(Map<AbilityKey, Object> runParams) {
if (!matchesValidParam("ValidCard", runParams.get(AbilityKey.Transformer))) {
if (!matchesValidParam("ValidCard", runParams.get(AbilityKey.Card))) {
return false;
}
@@ -55,13 +55,13 @@ public class TriggerTransformed extends Trigger {
@Override
public void setTriggeringObjects(SpellAbility sa, Map<AbilityKey, Object> runParams) {
sa.setTriggeringObjectsFrom(runParams, AbilityKey.Transformer);
sa.setTriggeringObjectsFrom(runParams, AbilityKey.Card);
}
@Override
public String getImportantStackObjects(SpellAbility sa) {
StringBuilder sb = new StringBuilder();
sb.append(Localizer.getInstance().getMessage("lblTransformed")).append(": ").append(sa.getTriggeringObject(AbilityKey.Transformer));
sb.append(Localizer.getInstance().getMessage("lblTransformed")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card));
return sb.toString();
}

View File

@@ -54,6 +54,7 @@ public enum TriggerType {
DamageDoneOnce(TriggerDamageDoneOnce.class),
DamagePrevented(TriggerDamagePrevented.class),
DamagePreventedOnce(TriggerDamagePreventedOnce.class),
DayTimeChanges (TriggerDayTimeChanges.class),
Destroyed(TriggerDestroyed.class),
Devoured(TriggerDevoured.class),
Discarded(TriggerDiscarded.class),

View File

@@ -0,0 +1,15 @@
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_color;
varying vec2 v_texCoords;
uniform sampler2D u_texture;
uniform float u_grayness;
void main() {
vec4 c = v_color * texture2D(u_texture, v_texCoords);
float grey = dot( c.rgb, vec3(0.22, 0.707, 0.071) );
vec3 blendedColor = mix(c.rgb, vec3(grey), u_grayness);
gl_FragColor = vec4(blendedColor.rgb, c.a);
}

View File

@@ -0,0 +1,14 @@
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord0;
uniform mat4 u_projTrans;
varying vec4 v_color;
varying vec2 v_texCoords;
void main() {
v_color = a_color;
v_texCoords = a_texCoord0;
gl_Position = u_projTrans * a_position;
}

View File

@@ -0,0 +1,40 @@
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
uniform sampler2D u_texture;
uniform vec2 u_viewportInverse;
uniform vec3 u_color;
uniform float u_offset;
uniform float u_step;
varying vec4 v_color;
varying vec2 v_texCoord;
#define ALPHA_VALUE_BORDER 0.5
void main() {
vec2 T = v_texCoord.xy;
float alpha = 0.0;
bool allin = true;
for( float ix = -u_offset; ix < u_offset; ix += u_step )
{
for( float iy = -u_offset; iy < u_offset; iy += u_step )
{
float newAlpha = texture2D(u_texture, T + vec2(ix, iy) * u_viewportInverse).a;
allin = allin && newAlpha > ALPHA_VALUE_BORDER;
if (newAlpha > ALPHA_VALUE_BORDER && newAlpha >= alpha)
{
alpha = newAlpha;
}
}
}
if (allin)
{
alpha = 0.0;
}
gl_FragColor = vec4(u_color,alpha);
}

View File

@@ -0,0 +1,16 @@
uniform mat4 u_projTrans;
attribute vec4 a_position;
attribute vec2 a_texCoord0;
attribute vec4 a_color;
varying vec4 v_color;
varying vec2 v_texCoord;
uniform vec2 u_viewportInverse;
void main() {
gl_Position = u_projTrans * a_position;
v_texCoord = a_texCoord0;
v_color = a_color;
}

View File

@@ -0,0 +1,23 @@
#ifdef GL_ES
#define PRECISION mediump
precision PRECISION float;
precision PRECISION int;
#else
#define PRECISION
#endif
varying vec2 v_texCoords;
uniform sampler2D u_texture;
uniform float u_amount;
uniform float u_speed;
uniform float u_time;
void main () {
vec2 uv = v_texCoords;
uv.y += (cos((uv.y + (u_time * 0.04 * u_speed)) * 45.0) * 0.0019 * u_amount) + (cos((uv.y + (u_time * 0.1 * u_speed)) * 10.0) * 0.002 * u_amount);
uv.x += (sin((uv.y + (u_time * 0.07 * u_speed)) * 15.0) * 0.0029 * u_amount) + (sin((uv.y + (u_time * 0.1 * u_speed)) * 15.0) * 0.002 * u_amount);
gl_FragColor = texture2D(u_texture, uv);
}

View File

@@ -0,0 +1,57 @@
#ifdef GL_ES
precision mediump float;
#endif
varying vec2 v_texCoords;
uniform sampler2D u_texture;
uniform float u_time;
uniform float u_speed;
uniform float u_amount;
uniform vec2 u_viewport;
uniform vec2 u_position;
float random2d(vec2 n) {
return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);
}
float randomRange (in vec2 seed, in float min, in float max) {
return min + random2d(seed) * (max - min);
}
float insideRange(float v, float bottom, float top) {
return step(bottom, v) - step(top, v);
}
void main()
{
float time = floor(u_time * u_speed * 60.0);
vec3 outCol = texture2D(u_texture, v_texCoords).rgb;
float maxOffset = u_amount/2.0;
for (float i = 0.0; i < 2.0; i += 1.0) {
float sliceY = random2d(vec2(time, 2345.0 + float(i)));
float sliceH = random2d(vec2(time, 9035.0 + float(i))) * 0.25;
float hOffset = randomRange(vec2(time, 9625.0 + float(i)), -maxOffset, maxOffset);
vec2 uvOff = v_texCoords;
uvOff.x += hOffset;
if (insideRange(v_texCoords.y, sliceY, fract(sliceY+sliceH)) == 1.0){
outCol = texture2D(u_texture, uvOff).rgb;
}
}
float maxColOffset = u_amount / 6.0;
float rnd = random2d(vec2(time , 9545.0));
vec2 colOffset = vec2(randomRange(vec2(time , 9545.0), -maxColOffset, maxColOffset),
randomRange(vec2(time , 7205.0), -maxColOffset, maxColOffset));
if (rnd < 0.33) {
outCol.r = texture2D(u_texture, v_texCoords + colOffset).r;
} else if (rnd < 0.66) {
outCol.g = texture2D(u_texture, v_texCoords + colOffset).g;
} else {
outCol.b = texture2D(u_texture, v_texCoords + colOffset).b;
}
gl_FragColor = vec4(outCol, 1.0);
}

View File

@@ -17,10 +17,7 @@
*/
package forge.control;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.InputEvent;
@@ -333,9 +330,20 @@ public enum FControl implements KeyEventDispatcher {
if (screen.isMatchScreen()) {
if (isMatchBackgroundImageVisible()) {
FView.SINGLETON_INSTANCE.getPnlInsets().setForegroundImage(FSkin.getIcon(FSkinProp.BG_MATCH));
if (screen.getDaytime() == null)
FView.SINGLETON_INSTANCE.getPnlInsets().setForegroundImage(FSkin.getIcon(FSkinProp.BG_MATCH), true);
else {
if ("Day".equals(screen.getDaytime()))
FView.SINGLETON_INSTANCE.getPnlInsets().setForegroundImage(FSkin.getIcon(FSkinProp.BG_DAY), true);
else
FView.SINGLETON_INSTANCE.getPnlInsets().setForegroundImage(FSkin.getIcon(FSkinProp.BG_NIGHT), true);
}
} else {
FView.SINGLETON_INSTANCE.getPnlInsets().setForegroundImage((Image)null);
}
//SOverlayUtils.showTargetingOverlay();
} else {
FView.SINGLETON_INSTANCE.getPnlInsets().setForegroundImage((Image)null);
}
Singletons.getView().getNavigationBar().updateSelectedTab();

View File

@@ -188,6 +188,7 @@ public class FScreen {
private final boolean allowTabClose;
private final FileLocation layoutFile;
private final boolean isMatch;
private String daytime = null;
private FScreen(final IVTopLevelUI view0, final ICDoc controller0,
final String tabCaption0, final SkinImage tabIcon0,
@@ -230,6 +231,12 @@ public class FScreen {
this.tabCaption = caption;
FView.SINGLETON_INSTANCE.getNavigationBar().updateTitle(this);
}
public String getDaytime() {
return daytime;
}
public void setDaytime(final String daytime) {
this.daytime = daytime;
}
public SkinImage getTabIcon() {
return tabIcon;

View File

@@ -14,6 +14,7 @@ import javax.swing.JRadioButtonMenuItem;
import javax.swing.KeyStroke;
import forge.Singletons;
import forge.control.FControl;
import forge.gui.GuiChoose;
import forge.gui.MouseUtil;
import forge.gui.framework.FScreen;
@@ -119,7 +120,14 @@ public final class LayoutMenu {
final boolean isVisible = menuItem.getState();
prefs.setPref(FPref.UI_MATCH_IMAGE_VISIBLE, isVisible);
if (isVisible) {
FView.SINGLETON_INSTANCE.getPnlInsets().setForegroundImage(FSkin.getIcon(FSkinProp.BG_MATCH));
if (FControl.instance.getCurrentScreen().getDaytime() == null)
FView.SINGLETON_INSTANCE.getPnlInsets().setForegroundImage(FSkin.getIcon(FSkinProp.BG_MATCH), true);
else {
if ("Day".equals(FControl.instance.getCurrentScreen().getDaytime()))
FView.SINGLETON_INSTANCE.getPnlInsets().setForegroundImage(FSkin.getIcon(FSkinProp.BG_DAY), true);
else
FView.SINGLETON_INSTANCE.getPnlInsets().setForegroundImage(FSkin.getIcon(FSkinProp.BG_NIGHT), true);
}
} else {
FView.SINGLETON_INSTANCE.getPnlInsets().setForegroundImage((Image)null);
}

View File

@@ -17,8 +17,7 @@
*/
package forge.screens.match;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
@@ -415,6 +414,19 @@ public final class CMatchUI
cCombat.update();
} // showCombat(CombatView)
@Override
public void updateDayTime(String daytime) {
super.updateDayTime(daytime);
if ("Day".equals(daytime)) {
FView.SINGLETON_INSTANCE.getPnlInsets().setForegroundImage(FSkin.getIcon(FSkinProp.BG_DAY), true);
getScreen().setDaytime("Day");
} else {
FView.SINGLETON_INSTANCE.getPnlInsets().setForegroundImage(FSkin.getIcon(FSkinProp.BG_NIGHT), true);
getScreen().setDaytime("Night");
}
FView.SINGLETON_INSTANCE.getPnlInsets().repaint();
}
@Override
public void updateZones(final Iterable<PlayerZoneUpdate> zonesToUpdate) {
for (final PlayerZoneUpdate update : zonesToUpdate) {
@@ -1064,6 +1076,12 @@ public final class CMatchUI
SDisplayUtil.showTab(EDocID.REPORT_LOG.getDoc());
SOverlayUtils.hideOverlay();
//reset every match
getScreen().setDaytime(null);
if (FModel.getPreferences().getPrefBoolean(FPref.UI_MATCH_IMAGE_VISIBLE))
FView.SINGLETON_INSTANCE.getPnlInsets().setForegroundImage(FSkin.getIcon(FSkinProp.BG_MATCH), true);
else
FView.SINGLETON_INSTANCE.getPnlInsets().setForegroundImage((Image)null);
}
@Override

View File

@@ -32,6 +32,7 @@ import java.beans.PropertyChangeListener;
import javax.swing.JButton;
import forge.control.FControl;
import forge.game.GameView;
import forge.game.card.CardView;
import forge.gui.FThreads;
@@ -42,6 +43,7 @@ import forge.model.FModel;
import forge.screens.match.CMatchUI;
import forge.screens.match.views.VPrompt;
import forge.toolbox.FSkin;
import forge.util.Localizer;
/**
* Controls the prompt panel in the match UI.
@@ -156,7 +158,9 @@ public class CPrompt implements ICDoc {
}
public void setMessage(final String s0) {
view.getTarMessage().setText(FSkin.encodeSymbols(s0, false));
String header = FControl.instance.getCurrentScreen().getDaytime() != null ? "[" + Localizer.getInstance().getMessage("lbl"+FControl.instance.getCurrentScreen().getDaytime()) + "]\n\n" : "[---]\n\n";
header += s0;
view.getTarMessage().setText(FSkin.encodeSymbols(header, false));
view.setCardView(null);
}
public void setMessage(final String s0, final CardView card) {

View File

@@ -149,7 +149,7 @@ public class FPanel extends FPanelBase implements ILocalRepaint {
/** @param img0 &emsp; {@link java.awt.Image} */
@Override
protected void onSetForegroundImage(final Image img0) {
protected void onSetForegroundImage(final Image img0, boolean stretch) {
if (img0 == null) {
this.foregroundImage = null;
return;
@@ -159,6 +159,7 @@ public class FPanel extends FPanelBase implements ILocalRepaint {
this.imgW = img0.getWidth(null);
this.imgH = img0.getHeight(null);
this.iar = (double) imgW / (double) imgH;
this.foregroundStretch = stretch;
}
/** Aligns NON-STRETCHED foreground image.

View File

@@ -1305,6 +1305,9 @@ public class FSkin {
// Exceptions handled inside method.
SkinIcon.setIcon(FSkinProp.BG_TEXTURE, preferredDir + ForgeConstants.TEXTURE_BG_FILE);
SkinIcon.setIcon(FSkinProp.BG_MATCH, preferredDir + ForgeConstants.MATCH_BG_FILE);
//daynight bg
SkinIcon.setIcon(FSkinProp.BG_DAY, defaultDir + ForgeConstants.MATCH_BG_DAY_FILE);
SkinIcon.setIcon(FSkinProp.BG_NIGHT, defaultDir + ForgeConstants.MATCH_BG_NIGHT_FILE);
// Run through enums and load their coords.
Colors.updateAll();
@@ -2258,10 +2261,11 @@ public class FSkin {
protected FPanelBase() { super(); }
public FPanelBase(final LayoutManager layoutManager) { super(layoutManager); }
protected abstract void onSetForegroundImage(final Image image);
public final void setForegroundImage(final SkinImage skinImage) { onSetForegroundImage(skinImage.image); this.foregroundImage = skinImage; }
public final void setForegroundImage(final Image image) { onSetForegroundImage(image); this.foregroundImage = null; }
public final void setForegroundImage(final ImageIcon imageIcon) { onSetForegroundImage(imageIcon.getImage()); this.foregroundImage = null; }
protected abstract void onSetForegroundImage(final Image image, boolean stretch);
public final void setForegroundImage(final SkinImage skinImage, final boolean stretch) { onSetForegroundImage(skinImage.image, stretch); this.foregroundImage = skinImage; }
public final void setForegroundImage(final SkinImage skinImage) { onSetForegroundImage(skinImage.image, false); this.foregroundImage = skinImage; }
public final void setForegroundImage(final Image image) { onSetForegroundImage(image, false); this.foregroundImage = null; }
public final void setForegroundImage(final ImageIcon imageIcon) { onSetForegroundImage(imageIcon.getImage(), false); this.foregroundImage = null; }
protected abstract void onSetBackgroundTexture(final Image image);
public final void setBackgroundTexture(final SkinImage skinImage) { onSetBackgroundTexture(skinImage.image); this.backgroundTexture = skinImage; }

View File

@@ -1720,11 +1720,11 @@ public class GameSimulatorTest extends SimulationTestCase {
assertFalse(outlaw.isCloned());
assertTrue(outlaw.isDoubleFaced());
assertTrue(outlaw.hasState(CardStateName.Transformed));
assertTrue(outlaw.canTransform());
assertTrue(outlaw.canTransform(null));
assertFalse(outlaw.isBackSide());
assertFalse(giant.isDoubleFaced());
assertFalse(giant.canTransform());
assertFalse(giant.canTransform(null));
addCard("Forest", p);
addCard("Forest", p);
@@ -1756,7 +1756,7 @@ public class GameSimulatorTest extends SimulationTestCase {
assertTrue(clonedOutLaw.isCloned());
assertTrue(clonedOutLaw.isDoubleFaced());
assertFalse(clonedOutLaw.hasState(CardStateName.Transformed));
assertTrue(clonedOutLaw.canTransform());
assertTrue(clonedOutLaw.canTransform(null));
assertFalse(clonedOutLaw.isBackSide());
assertEquals(clonedOutLaw.getName(), hillGiantName);
@@ -1777,7 +1777,7 @@ public class GameSimulatorTest extends SimulationTestCase {
assertTrue(transformOutLaw.isCloned());
assertTrue(transformOutLaw.isDoubleFaced());
assertFalse(transformOutLaw.hasState(CardStateName.Transformed));
assertTrue(transformOutLaw.canTransform());
assertTrue(transformOutLaw.canTransform(null));
assertTrue(transformOutLaw.isBackSide());
assertEquals(transformOutLaw.getName(), hillGiantName);
@@ -1792,7 +1792,7 @@ public class GameSimulatorTest extends SimulationTestCase {
assertFalse(transformOutLaw.isCloned());
assertTrue(transformOutLaw.isDoubleFaced());
assertTrue(transformOutLaw.hasState(CardStateName.Transformed));
assertTrue(transformOutLaw.canTransform());
assertTrue(transformOutLaw.canTransform(null));
assertTrue(transformOutLaw.isBackSide());
assertEquals(transformOutLaw.getName(), terrorName);

View File

@@ -13,6 +13,15 @@
<build>
<sourceDirectory>src</sourceDirectory>
<resources>
<resource>
<directory>${project.basedir}</directory>
<includes>
<include>**/*.vert</include>
<include>**/*.frag</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>

View File

@@ -0,0 +1,15 @@
#ifdef GL_ES
precision mediump float;
#endif
varying vec4 v_color;
varying vec2 v_texCoords;
uniform sampler2D u_texture;
uniform float u_grayness;
void main() {
vec4 c = v_color * texture2D(u_texture, v_texCoords);
float grey = dot( c.rgb, vec3(0.22, 0.707, 0.071) );
vec3 blendedColor = mix(c.rgb, vec3(grey), u_grayness);
gl_FragColor = vec4(blendedColor.rgb, c.a);
}

View File

@@ -0,0 +1,14 @@
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord0;
uniform mat4 u_projTrans;
varying vec4 v_color;
varying vec2 v_texCoords;
void main() {
v_color = a_color;
v_texCoords = a_texCoord0;
gl_Position = u_projTrans * a_position;
}

View File

@@ -0,0 +1,40 @@
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
uniform sampler2D u_texture;
uniform vec2 u_viewportInverse;
uniform vec3 u_color;
uniform float u_offset;
uniform float u_step;
varying vec4 v_color;
varying vec2 v_texCoord;
#define ALPHA_VALUE_BORDER 0.5
void main() {
vec2 T = v_texCoord.xy;
float alpha = 0.0;
bool allin = true;
for( float ix = -u_offset; ix < u_offset; ix += u_step )
{
for( float iy = -u_offset; iy < u_offset; iy += u_step )
{
float newAlpha = texture2D(u_texture, T + vec2(ix, iy) * u_viewportInverse).a;
allin = allin && newAlpha > ALPHA_VALUE_BORDER;
if (newAlpha > ALPHA_VALUE_BORDER && newAlpha >= alpha)
{
alpha = newAlpha;
}
}
}
if (allin)
{
alpha = 0.0;
}
gl_FragColor = vec4(u_color,alpha);
}

View File

@@ -0,0 +1,16 @@
uniform mat4 u_projTrans;
attribute vec4 a_position;
attribute vec2 a_texCoord0;
attribute vec4 a_color;
varying vec4 v_color;
varying vec2 v_texCoord;
uniform vec2 u_viewportInverse;
void main() {
gl_Position = u_projTrans * a_position;
v_texCoord = a_texCoord0;
v_color = a_color;
}

View File

@@ -0,0 +1,23 @@
#ifdef GL_ES
#define PRECISION mediump
precision PRECISION float;
precision PRECISION int;
#else
#define PRECISION
#endif
varying vec2 v_texCoords;
uniform sampler2D u_texture;
uniform float u_amount;
uniform float u_speed;
uniform float u_time;
void main () {
vec2 uv = v_texCoords;
uv.y += (cos((uv.y + (u_time * 0.04 * u_speed)) * 45.0) * 0.0019 * u_amount) + (cos((uv.y + (u_time * 0.1 * u_speed)) * 10.0) * 0.002 * u_amount);
uv.x += (sin((uv.y + (u_time * 0.07 * u_speed)) * 15.0) * 0.0029 * u_amount) + (sin((uv.y + (u_time * 0.1 * u_speed)) * 15.0) * 0.002 * u_amount);
gl_FragColor = texture2D(u_texture, uv);
}

View File

@@ -0,0 +1,57 @@
#ifdef GL_ES
precision mediump float;
#endif
varying vec2 v_texCoords;
uniform sampler2D u_texture;
uniform float u_time;
uniform float u_speed;
uniform float u_amount;
uniform vec2 u_viewport;
uniform vec2 u_position;
float random2d(vec2 n) {
return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);
}
float randomRange (in vec2 seed, in float min, in float max) {
return min + random2d(seed) * (max - min);
}
float insideRange(float v, float bottom, float top) {
return step(bottom, v) - step(top, v);
}
void main()
{
float time = floor(u_time * u_speed * 60.0);
vec3 outCol = texture2D(u_texture, v_texCoords).rgb;
float maxOffset = u_amount/2.0;
for (float i = 0.0; i < 2.0; i += 1.0) {
float sliceY = random2d(vec2(time, 2345.0 + float(i)));
float sliceH = random2d(vec2(time, 9035.0 + float(i))) * 0.25;
float hOffset = randomRange(vec2(time, 9625.0 + float(i)), -maxOffset, maxOffset);
vec2 uvOff = v_texCoords;
uvOff.x += hOffset;
if (insideRange(v_texCoords.y, sliceY, fract(sliceY+sliceH)) == 1.0){
outCol = texture2D(u_texture, uvOff).rgb;
}
}
float maxColOffset = u_amount / 6.0;
float rnd = random2d(vec2(time , 9545.0));
vec2 colOffset = vec2(randomRange(vec2(time , 9545.0), -maxColOffset, maxColOffset),
randomRange(vec2(time , 7205.0), -maxColOffset, maxColOffset));
if (rnd < 0.33) {
outCol.r = texture2D(u_texture, v_texCoords + colOffset).r;
} else if (rnd < 0.66) {
outCol.g = texture2D(u_texture, v_texCoords + colOffset).g;
} else {
outCol.b = texture2D(u_texture, v_texCoords + colOffset).b;
}
gl_FragColor = vec4(outCol, 1.0);
}

View File

@@ -39,102 +39,10 @@ public class Graphics {
private int failedClipCount;
private float alphaComposite = 1;
private int transformCount = 0;
private final String sVertex = "uniform mat4 u_projTrans;\n" +
"\n" +
"attribute vec4 a_position;\n" +
"attribute vec2 a_texCoord0;\n" +
"attribute vec4 a_color;\n" +
"\n" +
"varying vec4 v_color;\n" +
"varying vec2 v_texCoord;\n" +
"\n" +
"uniform vec2 u_viewportInverse;\n" +
"\n" +
"void main() {\n" +
" gl_Position = u_projTrans * a_position;\n" +
" v_texCoord = a_texCoord0;\n" +
" v_color = a_color;\n" +
"}";
private final String sFragment = "#ifdef GL_ES\n" +
"precision mediump float;\n" +
"precision mediump int;\n" +
"#endif\n" +
"\n" +
"uniform sampler2D u_texture;\n" +
"\n" +
"// The inverse of the viewport dimensions along X and Y\n" +
"uniform vec2 u_viewportInverse;\n" +
"\n" +
"// Color of the outline\n" +
"uniform vec3 u_color;\n" +
"\n" +
"// Thickness of the outline\n" +
"uniform float u_offset;\n" +
"\n" +
"// Step to check for neighbors\n" +
"uniform float u_step;\n" +
"\n" +
"varying vec4 v_color;\n" +
"varying vec2 v_texCoord;\n" +
"\n" +
"#define ALPHA_VALUE_BORDER 0.5\n" +
"\n" +
"void main() {\n" +
" vec2 T = v_texCoord.xy;\n" +
"\n" +
" float alpha = 0.0;\n" +
" bool allin = true;\n" +
" for( float ix = -u_offset; ix < u_offset; ix += u_step )\n" +
" {\n" +
" for( float iy = -u_offset; iy < u_offset; iy += u_step )\n" +
" {\n" +
" float newAlpha = texture2D(u_texture, T + vec2(ix, iy) * u_viewportInverse).a;\n" +
" allin = allin && newAlpha > ALPHA_VALUE_BORDER;\n" +
" if (newAlpha > ALPHA_VALUE_BORDER && newAlpha >= alpha)\n" +
" {\n" +
" alpha = newAlpha;\n" +
" }\n" +
" }\n" +
" }\n" +
" if (allin)\n" +
" {\n" +
" alpha = 0.0;\n" +
" }\n" +
"\n" +
" gl_FragColor = vec4(u_color,alpha);\n" +
"}";
private final String vertexShaderGray = "attribute vec4 a_position;\n" +
"attribute vec4 a_color;\n" +
"attribute vec2 a_texCoord0;\n" +
"\n" +
"uniform mat4 u_projTrans;\n" +
"\n" +
"varying vec4 v_color;\n" +
"varying vec2 v_texCoords;\n" +
"\n" +
"void main() {\n" +
" v_color = a_color;\n" +
" v_texCoords = a_texCoord0;\n" +
" gl_Position = u_projTrans * a_position;\n" +
"}";
private final String fragmentShaderGray = "#ifdef GL_ES\n" +
" precision mediump float;\n" +
"#endif\n" +
"\n" +
"varying vec4 v_color;\n" +
"varying vec2 v_texCoords;\n" +
"uniform sampler2D u_texture;\n" +
"uniform float u_grayness;\n" +
"\n" +
"void main() {\n" +
" vec4 c = v_color * texture2D(u_texture, v_texCoords);\n" +
" float grey = dot( c.rgb, vec3(0.22, 0.707, 0.071) );\n" +
" vec3 blendedColor = mix(c.rgb, vec3(grey), u_grayness);\n" +
" gl_FragColor = vec4(blendedColor.rgb, c.a);\n" +
"}";
private final ShaderProgram shaderOutline = new ShaderProgram(sVertex, sFragment);
private final ShaderProgram shaderGrayscale = new ShaderProgram(vertexShaderGray, fragmentShaderGray);
private final ShaderProgram shaderOutline = new ShaderProgram(Gdx.files.internal("shaders").child("outline.vert"), Gdx.files.internal("shaders").child("outline.frag"));
private final ShaderProgram shaderGrayscale = new ShaderProgram(Gdx.files.internal("shaders").child("grayscale.vert"), Gdx.files.internal("shaders").child("grayscale.frag"));
private final ShaderProgram shaderWarp = new ShaderProgram(Gdx.files.internal("shaders").child("grayscale.vert"), Gdx.files.internal("shaders").child("warp.frag"));
private final ShaderProgram shaderUnderwater = new ShaderProgram(Gdx.files.internal("shaders").child("grayscale.vert"), Gdx.files.internal("shaders").child("underwater.frag"));
public Graphics() {
ShaderProgram.pedantic = false;
@@ -160,6 +68,9 @@ public class Graphics {
batch.dispose();
shapeRenderer.dispose();
shaderOutline.dispose();
shaderGrayscale.dispose();
shaderUnderwater.dispose();
shaderWarp.dispose();
}
public SpriteBatch getBatch() {
@@ -842,6 +753,87 @@ public class Graphics {
setAlphaComposite(oldalpha);
}
}
public void drawWarpImage(Texture image, float x, float y, float w, float h, float time) {
batch.end();
shaderWarp.bind();
shaderWarp.setUniformf("u_amount", 0.2f);
shaderWarp.setUniformf("u_speed", 0.6f);
shaderWarp.setUniformf("u_time", time);
batch.setShader(shaderWarp);
batch.begin();
//draw
batch.draw(image, adjustX(x), adjustY(y, h), w, h);
//reset
batch.end();
batch.setShader(null);
batch.begin();
}
public void drawWarpImage(TextureRegion image, float x, float y, float w, float h, float time) {
batch.end();
shaderWarp.bind();
shaderWarp.setUniformf("u_amount", 0.2f);
shaderWarp.setUniformf("u_speed", 0.6f);
shaderWarp.setUniformf("u_time", time);
batch.setShader(shaderWarp);
batch.begin();
//draw
batch.draw(image, adjustX(x), adjustY(y, h), w, h);
//reset
batch.end();
batch.setShader(null);
batch.begin();
}
public void drawWarpImage(FImage image, float x, float y, float w, float h, float time) {
batch.end();
shaderWarp.bind();
shaderWarp.setUniformf("u_amount", 0.2f);
shaderWarp.setUniformf("u_speed", 0.6f);
shaderWarp.setUniformf("u_time", time);
batch.setShader(shaderWarp);
batch.begin();
//draw
image.draw(this, x, y, w, h);
//reset
batch.end();
batch.setShader(null);
batch.begin();
}
public void drawUnderWaterImage(FImage image, float x, float y, float w, float h, float time, boolean withDarkOverlay) {
batch.end();
shaderUnderwater.bind();
shaderUnderwater.setUniformf("u_amount", 10f*time);
shaderUnderwater.setUniformf("u_speed", 0.5f*time);
shaderUnderwater.setUniformf("u_time", time);
batch.setShader(shaderUnderwater);
batch.begin();
//draw
image.draw(this, x, y, w, h);
//reset
batch.end();
batch.setShader(null);
batch.begin();
if(withDarkOverlay){
float oldalpha = alphaComposite;
setAlphaComposite(0.4f);
fillRect(Color.BLACK, x, y, w, h);
setAlphaComposite(oldalpha);
}
}
public void drawUnderWaterImage(TextureRegion image, float x, float y, float w, float h, float time) {
batch.end();
shaderUnderwater.bind();
shaderUnderwater.setUniformf("u_amount", 10f);
shaderUnderwater.setUniformf("u_speed", 0.5f);
shaderUnderwater.setUniformf("u_time", time);
batch.setShader(shaderUnderwater);
batch.begin();
//draw
batch.draw(image, adjustX(x), adjustY(y, h), w, h);
//reset
batch.end();
batch.setShader(null);
batch.begin();
}
public void drawImage(FImage image, float x, float y, float w, float h) {
drawImage(image, x, y, w, h, false);
}

View File

@@ -14,6 +14,8 @@ import forge.localinstance.properties.ForgeConstants;
public enum FSkinTexture implements FImage {
BG_TEXTURE(ForgeConstants.TEXTURE_BG_FILE, true, false),
BG_MATCH(ForgeConstants.MATCH_BG_FILE, false, false),
BG_MATCH_DAY(ForgeConstants.MATCH_BG_DAY_FILE, false, false),
BG_MATCH_NIGHT(ForgeConstants.MATCH_BG_NIGHT_FILE, false, false),
BG_SPACE(ForgeConstants.SPACE_BG_FILE, false, false),
BG_CHAOS_WHEEL(ForgeConstants.CHAOS_WHEEL_IMG_FILE, false, false),
Academy_at_Tolaria_West(ForgeConstants.BG_1, false, true),

View File

@@ -177,7 +177,8 @@ public class MatchController extends AbstractGuiGame {
}
actuateMatchPreferences();
//reset daytime every match
updateDayTime(null);
Forge.openScreen(view);
}

View File

@@ -667,7 +667,7 @@ public class MatchScreen extends FScreen {
private float progress = 0;
private boolean finished;
private void drawBackground(Graphics g, FImage image, float x, float y, float w, float h, boolean darkoverlay) {
private void drawBackground(Graphics g, FImage image, float x, float y, float w, float h, boolean darkoverlay, boolean daynightTransition) {
float percentage = progress / DURATION;
float oldAlpha = g.getfloatAlphaComposite();
if (percentage < 0) {
@@ -676,7 +676,10 @@ public class MatchScreen extends FScreen {
percentage = 1;
}
g.setAlphaComposite(percentage);
g.drawGrayTransitionImage(image, x, y, w, h, darkoverlay, 1-(percentage*1));
if (!daynightTransition)
g.drawGrayTransitionImage(image, x, y, w, h, darkoverlay, 1-(percentage*1));
else
g.drawUnderWaterImage(image, x, y, w, h, 1-(percentage*1), darkoverlay);
g.setAlphaComposite(oldAlpha);
}
@@ -694,20 +697,42 @@ public class MatchScreen extends FScreen {
private class FieldScroller extends FScrollPane {
private float extraHeight = 0;
private String plane = "";
private String daytime = "";
@Override
public void drawBackground(Graphics g) {
super.drawBackground(g);
if (FModel.getPreferences().getPrefBoolean(FPref.UI_MATCH_IMAGE_VISIBLE)) {
boolean isGameFast = MatchController.instance.isGameFast();
float midField = topPlayerPanel.getBottom();
float x = topPlayerPanel.getField().getLeft();
float y = midField - topPlayerPanel.getField().getHeight();
float w = getWidth() - x;
float bgFullWidth, scaledbgHeight;
int multiplier = playerPanels.keySet().size() - 1; //fix scaling of background when zoomed in multiplayer
float bgHeight = (midField + bottomPlayerPanel.getField().getHeight() * multiplier) - y;
boolean isGameFast = MatchController.instance.isGameFast();
float midField = topPlayerPanel.getBottom();
float x = topPlayerPanel.getField().getLeft();
float y = midField - topPlayerPanel.getField().getHeight();
float w = getWidth() - x;
float bgFullWidth, scaledbgHeight;
int multiplier = playerPanels.keySet().size() - 1; //fix scaling of background when zoomed in multiplayer
float bgHeight = (midField + bottomPlayerPanel.getField().getHeight() * multiplier) - y;
if (MatchController.instance.getDayTime() != null) {
//override BG
String dayTime = MatchController.instance.getDayTime();
if (!daytime.equals(dayTime)) {
bgAnimation = new BGAnimation();
bgAnimation.start();
daytime = dayTime;
}
FSkinTexture matchBG = MatchController.instance.getGameView().getGame().isDay() ? FSkinTexture.BG_MATCH_DAY : FSkinTexture.BG_MATCH_NIGHT;
bgFullWidth = bgHeight * matchBG.getWidth() / matchBG.getHeight();
if (bgFullWidth < w) {
scaledbgHeight = w * (bgHeight / bgFullWidth);
bgFullWidth = w;
bgHeight = scaledbgHeight;
}
if (bgAnimation != null && !isGameFast && !MatchController.instance.getGameView().isMatchOver()) {
bgAnimation.drawBackground(g, matchBG, x + (w - bgFullWidth) / 2, y, bgFullWidth, bgHeight, true, true);
} else {
g.drawImage(matchBG, x + (w - bgFullWidth) / 2, y, bgFullWidth, bgHeight, true);
}
} else if (FModel.getPreferences().getPrefBoolean(FPref.UI_MATCH_IMAGE_VISIBLE)) {
if(FModel.getPreferences().getPrefBoolean(FPref.UI_DYNAMIC_PLANECHASE_BG)
&& hasActivePlane()) {
String imageName = getPlaneName()
@@ -727,7 +752,7 @@ public class MatchScreen extends FScreen {
bgHeight = scaledbgHeight;
}
if (bgAnimation != null && !isGameFast && !MatchController.instance.getGameView().isMatchOver()) {
bgAnimation.drawBackground(g, FSkinTexture.valueOf(imageName), x + (w - bgFullWidth) / 2, y, bgFullWidth, bgHeight, true);
bgAnimation.drawBackground(g, FSkinTexture.valueOf(imageName), x + (w - bgFullWidth) / 2, y, bgFullWidth, bgHeight, true, false);
} else {
g.drawImage(FSkinTexture.valueOf(imageName), x + (w - bgFullWidth) / 2, y, bgFullWidth, bgHeight, true);
}

View File

@@ -3,8 +3,8 @@ ManaCost:2 W
Types:Enchantment Aura
K:Enchant creature
A:SP$ Attach | Cost$ 2 W | ValidTgts$ Creature | AILogic$ Curse
S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddHiddenKeyword$ CARDNAME can't attack or block. & CARDNAME can't transform | Description$ Enchanted creature can't attack, block, or transform.
S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddHiddenKeyword$ CARDNAME can't attack or block. | Description$ Enchanted creature can't attack, block, or transform.
S:Mode$ CantTransform | ValidCard$ Creature.EnchantedBy | Secondary$ True | Description$ Enchanted creature can't transform.
A:AB$ Attach | Cost$ Sac<1/Permanent.Other/another permanent> | ValidTgts$ Creature | TgtPrompt$ Select target creature | AILogic$ Curse | SorcerySpeed$ True | ActivationLimit$ 1 | SpellDescription$ Attach CARDNAME to target creature. Activate only as a sorcery and only once each turn.
SVar:AIPreference:SacCost$Card.token,Permanent.nonLand+cmcLE2,Land.Basic
SVar:Picture:http://www.wizards.com/global/images/magic/general/bound_by_moonsilver.jpg
Oracle:Enchant creature\nEnchanted creature can't attack, block, or transform.\nSacrifice another permanent: Attach Bound by Moonsilver to target creature. Activate only as a sorcery and only once each turn.

View File

@@ -4,7 +4,6 @@ Types:Creature Wolf
PT:2/2
K:Intimidate
S:Mode$ Continuous | Affected$ Creature.Wolf+Other+YouCtrl,Creature.Werewolf+Other+YouCtrl | AddPower$ 1 | AddToughness$ 1 | Description$ Each other creature you control that's a Wolf or a Werewolf gets +1/+1.
S:Mode$ Continuous | Affected$ Creature.Werewolf+nonHuman+YouCtrl | AddHiddenKeyword$ CARDNAME can't transform | Description$ Non-Human Werewolf creatures you control can't transform.
S:Mode$ CantTransform | ValidCard$ Creature.Werewolf+nonHuman+YouCtrl | Description$ Non-Human Werewolves you control can't transform.
SVar:PlayMain1:TRUE
SVar:Picture:http://www.wizards.com/global/images/magic/general/immerwolf.jpg
Oracle:Intimidate (This creature can't be blocked except by artifact creatures and/or creatures that share a color with it.)\nEach other creature you control that's a Wolf or a Werewolf gets +1/+1.\nNon-Human Werewolves you control can't transform.

View File

@@ -0,0 +1,26 @@
Name:Arlinn, the Pack's Hope
ManaCost:2 R G
Types:Legendary Planeswalker Arlinn
Loyalty:4
K:Daybound
A:AB$ Effect | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | Duration$ UntilYourNextTurn | StaticAbilities$ WithFlash | ReplacementEffects$ ExtraETBCounter | SpellDescription$ Until your next turn, you may cast creature spells as though they had flash, and each creature you control enters the battlefield with an additional +1/+1 counter on it.
SVar:WithFlash:Mode$ CastWithFlash | ValidCard$ Creature | ValidSA$ Spell | EffectZone$ Command | Caster$ You | Description$ Until your next turn, you may cast creature spells as though they had flash, and each creature you control enters the battlefield with an additional +1/+1 counter on it.
SVar:ExtraETBCounter:Event$ Moved | ActiveZones$ Command | Destination$ Battlefield | ValidCard$ Creature.YouCtrl | ReplaceWith$ AddExtraCounter | Secondary$ True | Description$ Until your next turn, you may cast creature spells as though they had flash, and each creature you control enters the battlefield with an additional +1/+1 counter on it.
SVar:AddExtraCounter:DB$ PutCounter | ETB$ True | Defined$ ReplacedCard | CounterType$ P1P1 | CounterNum$ 1 | SubAbility$ MoveToBattlefield
SVar:MoveToBattlefield:DB$ ChangeZone | Origin$ All | Destination$ Battlefield | Defined$ ReplacedCard
A:AB$ Token | Cost$ SubCounter<3/LOYALTY> | Planeswalker$ True | TokenAmount$ 2 | TokenScript$ g_2_2_wolf | SpellDescription$ Create two 2/2 green Wolf creature tokens.
AlternateMode:DoubleFaced
DeckHas:Ability$Token & Ability$Counters & Type$Wolf
Oracle:Daybound (If a player casts no spells during their own turn, it becomes night next turn.)\n[+1]: Until your next turn, you may cast creature spells as though they had flash, and each creature you control enters the battlefield with an additional +1/+1 counter on it.\n[3]: Create two 2/2 green Wolf creature tokens.
ALTERNATE
Name:Arlinn, the Moon's Fury
ManaCost:no cost
Colors:red,green
Types:Legendary Planeswalker Arlinn
Loyalty:4
K:Nightbound
A:AB$ Mana | Cost$ AddCounter<2/LOYALTY> | Planeswalker$ True | Produced$ R G | SpellDescription$ Add {R}{G}.
A:AB$ Animate | Cost$ AddCounter<0/LOYALTY> | Planeswalker$ True | Defined$ Self | Power$ 5 | Toughness$ 5 | Keywords$ Trample & Indestructible & Haste | Types$ Creature,Werewolf | StackDescription$ SpellDescription | SpellDescription$ Until end of turn, CARDNAME becomes a 5/5 Werewolf creature with trample, indestructible, and haste.
Oracle:Nightbound (If a player casts at least two spells during their own turn, it becomes day next turn.)\n[+2]: Add {R}{G}.\n[0]: Until end of turn, Arlinn, the Moon's Fury becomes a 5/5 Werewolf creature with trample, indestructible, and haste.

View File

@@ -0,0 +1,23 @@
Name:Baneblade Scoundrel
ManaCost:3 B
Types:Creature Human Rogue Werewolf
PT:4/3
T:Mode$ AttackerBlocked | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ Whenever CARDNAME becomes blocked, each creature blocking it gets -1/-1 until end of turn.
SVar:TrigPump:DB$ PumpAll | ValidCards$ Creature.blockingSource+DefenderCtrl | NumAtt$ -1 | NumDef$ -1
K:Daybound
AlternateMode:DoubleFaced
Oracle:Whenever Baneblade Scoundrel becomes blocked, each creature blocking it gets -1/-1 until end of turn.\nDaybound (If a player casts no spells during their own turn, it becomes night next turn.)
ALTERNATE
Name:Baneclaw Marauder
ManaCost:no cost
Colors:black
Types:Creature Werewolf
PT:5/4
T:Mode$ AttackerBlocked | ValidCard$ Card.Self | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ Whenever CARDNAME becomes blocked, each creature blocking it gets -1/-1 until end of turn.
SVar:TrigPump:DB$ PumpAll | ValidCards$ Creature.blockingSource+DefenderCtrl | NumAtt$ -1 | NumDef$ -1
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.blockingSource+DefenderCtrl | Execute$ TrigLoseLife | TriggerZones$ Battlefield | TriggerDescription$ Whenever a creature blocking CARDNAME dies, that creature's controller loses 1 life.
SVar:TrigLoseLife:DB$ LoseLife | Defined$ TriggeredCardController | LifeAmount$ 1
K:Nightbound
Oracle:Whenever Baneclaw Marauder becomes blocked, each creature blocking it gets -1/-1 until end of turn.\nWhenever a creature blocking Baneclaw Marauder dies, that creature's controller loses 1 life.\nNightbound (If a player casts at least two spells during their own turn, it becomes day next turn.)

View File

@@ -0,0 +1,19 @@
Name:Bird Admirer
ManaCost:2 G
Types:Creature Human Archer Werewolf
PT:1/4
K:Reach
K:Daybound
AlternateMode:DoubleFaced
Oracle:Reach\nDaybound (If a player casts no spells during their own turn, it becomes night next turn.)
ALTERNATE
Name:Wing Shredder
ManaCost:no cost
Colors:green
Types:Creature Werewolf
PT:3/5
K:Reach
K:Nightbound
Oracle:Reach\nNightbound (If a player casts at least two spells during their own turn, it becomes day next turn.)

View File

@@ -0,0 +1,11 @@
Name:Brimstone Vandal
ManaCost:2 R
Types:Creature Devil
PT:2/3
K:Menace
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | DayTime$ Neither | ReplaceWith$ DoDay | Description$ If it's neither day nor night, it becomes day as CARDNAME enters the battlefield.
SVar:DoDay:DB$ DayTime | Value$ Day | SubAbility$ ETB
SVar:ETB:DB$ InternalEtbReplacement
T:Mode$ DayTimeChanges | Execute$ TrigDamage | TriggerZones$ Battlefield | TriggerDescription$ Whenever day becomes night or night becomes day, CARDNAME deals 1 damage to each opponent.
SVar:TrigDamage:DB$ DealDamage | Defined$ Player.Opponent | NumDmg$ 1
Oracle:Menace (This creature cant be blocked except by two or more creatures.)\nIf it's neither day nor night, it becomes day as Brimstone Vandal enters the battlefield.\nWhenever day becomes night or night becomes day, Brimstone Vandal deals 1 damage to each opponent.

View File

@@ -0,0 +1,24 @@
Name:Brutal Cathar
ManaCost:2 W
Types:Creature Human Soldier Werewolf
PT:2/2
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ When this creature enters the battlefield or transforms into CARDNAME, exile target creature an opponent controls until this creature leaves the battlefield.
T:Mode$ Transformed | ValidCard$ Card.Self | Execute$ TrigExile | Secondary$ True | TriggerDescription$ When this creature enters the battlefield or transforms into CARDNAME, exile target creature an opponent controls until this creature leaves the battlefield.
SVar:TrigExile:DB$ ChangeZone | Origin$ Battlefield | Destination$ Exile | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Select target creature an opponent controls | Duration$ UntilHostLeavesPlay
K:Daybound
AlternateMode:DoubleFaced
SVar:PlayMain1:TRUE
SVar:OblivionRing:TRUE
Oracle:When this creature enters the battlefield or transforms into Brutal Cathar, exile target creature an opponent controls until this creature leaves the battlefield.\nDaybound (If a player casts no spells during their own turn, it becomes night next turn.)
ALTERNATE
Name:Moonrage Brute
ManaCost:no cost
Colors:red
Types:Creature Werewolf
PT:3/3
K:First strike
K:Ward:PayLife<3>
K:Nightbound
Oracle:First strike\nWard—Pay 3 life.\nNightbound (If a player casts at least two spells during their own turn, it becomes day next turn.)

View File

@@ -0,0 +1,19 @@
Name:Burly Breaker
ManaCost:3 G G
Types:Creature Human Werewolf
PT:6/5
K:Ward:1
K:Daybound
AlternateMode:DoubleFaced
Oracle:Ward {1} (Whenever this creature becomes the target of a spell or ability an opponent controls, counter it unless that player pays {1}.)\nDaybound (If a player casts no spells during their own turn, it becomes night next turn.)
ALTERNATE
Name:Dire-Strain Demolisher
ManaCost:no cost
Colors:green
Types:Creature Werewolf
PT:8/7
K:Ward:3
K:Nightbound
Oracle:Ward {3} (Whenever this creature becomes the target of a spell or ability an opponent controls, counter it unless that player pays {3}.)\nNightbound (If a player casts at least two spells during their own turn, it becomes day next turn.)

View File

@@ -0,0 +1,11 @@
Name:Celestus Sanctifier
ManaCost:2 W
Types:Creature Human Cleric
PT:3/2
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | DayTime$ Neither | ReplaceWith$ DoDay | Description$ If it's neither day nor night, it becomes day as CARDNAME enters the battlefield.
SVar:DoDay:DB$ DayTime | Value$ Day | SubAbility$ ETB
SVar:ETB:DB$ InternalEtbReplacement
T:Mode$ DayTimeChanges | Execute$ DBDig | TriggerZones$ Battlefield | TriggerDescription$ Whenever day becomes night or night becomes day, look at the top two cards of your library. Put one of them into your graveyard.
SVar:DBDig:DB$ Dig | DigNum$ 2 | DestinationZone$ Graveyard | LibraryPosition2$ 0
DeckHas:Ability$Graveyard
Oracle:If it's neither day nor night, it becomes day as Celestus Sanctifier enters the battlefield.\nWhenever day becomes night or night becomes day, look at the top two cards of your library. Put one of them into your graveyard.

View File

@@ -0,0 +1,10 @@
Name:Component Collector
ManaCost:2 U
Types:Creature Homunculus
PT:1/4
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | DayTime$ Neither | ReplaceWith$ DoDay | Description$ If it's neither day nor night, it becomes day as CARDNAME enters the battlefield.
SVar:DoDay:DB$ DayTime | Value$ Day | SubAbility$ ETB
SVar:ETB:DB$ InternalEtbReplacement
T:Mode$ DayTimeChanges | Execute$ TrigTapOrUntap | TriggerZones$ Battlefield | TriggerDescription$ Whenever day becomes night or night becomes day, you may tap or untap target nonland permanent.
SVar:TrigTapOrUntap:DB$ TapOrUntap | ValidTgts$ Permanent.nonLand | TgtPrompt$ Select target nonland permanent
Oracle:If it's neither day nor night, it becomes day as Component Collector enters the battlefield.\nWhenever day becomes night or night becomes day, you may tap or untap target nonland permanent.

View File

@@ -0,0 +1,26 @@
Name:Curse of Leeches
ManaCost:2 B
Types:Enchantment Aura Curse
K:Enchant player
A:SP$ Attach | ValidTgts$ Player | TgtPrompt$ Select target player to curse | AILogic$ Curse
R:Event$ Transform | ValidCard$ Card.Self | ReplaceWith$ Attach | Description$ As this permanent transforms into CARDNAME, attach it to a player.
SVar:Attach:DB$ Attach | Object$ Self | Chooser$ You | PlayerChoices$ Player | ChoiceTitle$ Select player to curse | AILogic$ Curse
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ Player.EnchantedBy | TriggerZones$ Battlefield | Execute$ TrigDrain | TriggerDescription$ At the beginning of enchanted player's upkeep, they lose 1 life and you gain 1 life.
SVar:TrigDrain:DB$ LoseLife | Defined$ TriggeredPlayer | LifeAmount$ 1 | SubAbility$ DBGainLife
SVar:DBGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 1
K:Daybound
AlternateMode:DoubleFaced
DeckHas:Ability$LifeGain
Oracle:Enchant player\nAs this permanent transforms into Curse of Leeches, attach it to a player.\nAt the beginning of enchanted player's upkeep, they lose 1 life and you gain 1 life.\nDaybound (If a player casts no spells during their own turn, it becomes night next turn.)
ALTERNATE
Name:Leeching Lurker
ManaCost:no cost
Colors:black
Types:Creature Leech Horror
PT:4/4
K:Lifelink
K:Nightbound
DeckHas:Ability$LifeGain
Oracle:Lifelink\nNightbound (If a player casts at least two spells during their own turn, it becomes day next turn.)

View File

@@ -0,0 +1,20 @@
Name:Fangblade Brigand
ManaCost:3 R
Types:Creature Human Werewolf
PT:3/4
A:AB$ Pump | Cost$ 1 R | Defined$ Self | NumAtt$ +1 | KW$ First Strike | SpellDescription$ CARDNAME gets +1/+0 and gains first strike until end of turn.
K:Daybound
AlternateMode:DoubleFaced
Oracle:{1}{R}: Fangblade Brigand gets +1/+0 and gains first strike until end of turn.\nDaybound (If a player casts no spells during their own turn, it becomes night next turn.)
ALTERNATE
Name:Fangblade Eviscerator
ManaCost:no cost
Colors:red
Types:Creature Werewolf
PT:4/5
A:AB$ Pump | Cost$ 1 R | Defined$ Self | NumAtt$ +1 | KW$ First Strike | SpellDescription$ CARDNAME gets +1/+0 and gains first strike until end of turn.
A:AB$ PumpAll | Cost$ 4 R | ValidCards$ Creature.YouCtrl | NumAtt$ +2 | SpellDescription$ Creatures you control get +2/+0 until end of turn.
K:Nightbound
Oracle:{1}{R}: Fangblade Eviscerator gets +1/+0 and gains first strike until end of turn.\n{4}{R}: Creatures you control get +2/+0 until end of turn.\nNightbound (If a player casts at least two spells during their own turn, it becomes day next turn.)

View File

@@ -0,0 +1,10 @@
Name:Firmament Sage
ManaCost:3 U
Types:Creature Human Wizard
PT:2/3
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | DayTime$ Neither | ReplaceWith$ DoDay | Description$ If it's neither day nor night, it becomes day as CARDNAME enters the battlefield.
SVar:DoDay:DB$ DayTime | Value$ Day | SubAbility$ ETB
SVar:ETB:DB$ InternalEtbReplacement
T:Mode$ DayTimeChanges | Execute$ DBDraw | TriggerZones$ Battlefield | TriggerDescription$ Whenever day becomes night or night becomes day, draw a card.
SVar:DBDraw:DB$ Draw | Defined$ You | NumCards$ 1
Oracle:If it's neither day nor night, it becomes day as Firmament Sage enters the battlefield.\nWhenever day becomes night or night becomes day, draw a card.

View File

@@ -0,0 +1,11 @@
Name:Gavony Dawnguard
ManaCost:1 W W
Types:Creature Human Soldier
PT:3/3
K:Ward:1
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | DayTime$ Neither | ReplaceWith$ DoDay | Description$ If it's neither day nor night, it becomes day as CARDNAME enters the battlefield.
SVar:DoDay:DB$ DayTime | Value$ Day | SubAbility$ ETB
SVar:ETB:DB$ InternalEtbReplacement
T:Mode$ DayTimeChanges | Execute$ TrigDig | TriggerZones$ Battlefield | TriggerDescription$ Whenever day becomes night or night becomes day, look at the top four cards of your library. You may reveal a creature card with mana value 3 or less from among them and put it into your hand. Put the rest on the bottom of your library in any order.
SVar:TrigDig:DB$ Dig | ForceRevealToController$ True | DigNum$ 4 | ChangeNum$ 1 | Optional$ True | ChangeValid$ Creature.cmcLE3
Oracle:Ward {1}\nIf it's neither day nor night, it becomes day as Gavony Dawnguard enters the battlefield.\nWhenever day becomes night or night becomes day, look at the top four cards of your library. You may reveal a creature card with mana value 3 or less from among them and put it into your hand. Put the rest on the bottom of your library in any order.

View File

@@ -0,0 +1,34 @@
Name:Graveyard Trespasser
ManaCost:2 B
Types:Creature Human Werewolf
PT:3/3
K:Ward:Discard<1/Card>
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ Whenever CARDNAME enters the battlefield or attacks, exile up to one target card from a graveyard. If a creature card was exiled this way, each opponent loses 1 life and you gain 1 life.
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigExile | Secondary$ True | TriggerDescription$ Whenever CARDNAME enters the battlefield or attacks, exile up to one target card from a graveyard. If a creature card was exiled this way, each opponent loses 1 life and you gain 1 life.
SVar:TrigExile:DB$ ChangeZone | Origin$ Graveyard | Destination$ Exile | TargetMin$ 0 | TargetMax$ 1 | ValidTgts$ Card | TgtPrompt$ Select up to one target card from a graveyard | RememberChanged$ True | SubAbility$ DBDrain
SVar:DBDrain:DB$ LoseLife | ConditionDefined$ Remembered | ConditionPresent$ Creature | Defined$ Player.Opponent | LifeAmount$ 1 | SubAbility$ DBGainLife
SVar:DBGainLife:DB$ GainLife | ConditionDefined$ Remembered | ConditionPresent$ Creature | Defined$ You | LifeAmount$ 1 | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
K:Daybound
AlternateMode:DoubleFaced
DeckHas:Ability$Graveyard & Ability$LifeGain
Oracle:Ward—Discard a card.\nWhenever Graveyard Trespasser enters the battlefield or attacks, exile up to one target card from a graveyard. If a creature card was exiled this way, each opponent loses 1 life and you gain 1 life.\nDaybound (If a player casts no spells during their own turn, it becomes night next turn.)
ALTERNATE
Name:Graveyard Glutton
ManaCost:no cost
Colors:black
Types:Creature Werewolf
PT:4/4
K:Ward:Discard<1/Card>
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExileN | TriggerDescription$ Whenever CARDNAME enters the battlefield or attacks, exile up to two target cards from graveyards. For each creature card exiled this way, each opponent loses 1 life and you gain 1 life.
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigExileN | Secondary$ True | TriggerDescription$ Whenever CARDNAME enters the battlefield or attacks, exile up to two target cards from graveyards. For each creature card exiled this way, each opponent loses 1 life and you gain 1 life.
SVar:TrigExileN:DB$ ChangeZone | Origin$ Graveyard | Destination$ Exile | TargetMin$ 0 | TargetMax$ 2 | ValidTgts$ Card | TgtPrompt$ Select up to two target cards from graveyards | RememberChanged$ True | SubAbility$ DBDrainN
SVar:DBDrainN:DB$ LoseLife | ConditionDefined$ Remembered | ConditionPresent$ Creature | Defined$ Player.Opponent | LifeAmount$ X | SubAbility$ DBGainLifeN
SVar:DBGainLifeN:DB$ GainLife | ConditionDefined$ Remembered | ConditionPresent$ Creature | Defined$ You | LifeAmount$ X | SubAbility$ DBCleanupN
SVar:X:Remembered$Valid Creature
SVar:DBCleanupN:DB$ Cleanup | ClearRemembered$ True
K:Nightbound
DeckHas:Ability$Graveyard & Ability$LifeGain
Oracle:Ward—Discard a card.\nWhenever Graveyard Glutton enters the battlefield or attacks, exile up to two target cards from graveyards. For each creature card exiled this way, each opponent loses 1 life and you gain 1 life.\nNightbound (If a player casts at least two spells during their own turn, it becomes day next turn.)

View File

@@ -0,0 +1,19 @@
Name:Harvesttide Infiltrator
ManaCost:2 R
Types:Creature Human Werewolf
PT:3/2
K:Trample
K:Daybound
AlternateMode:DoubleFaced
Oracle:Trample\nDaybound (If a player casts no spells during their own turn, it becomes night next turn.)
ALTERNATE
Name:Harvesttide Assailant
ManaCost:no cost
Colors:red
Types:Creature Werewolf
PT:4/4
K:Trample
K:Nightbound
Oracle:Trample\nNightbound (If a player casts at least two spells during their own turn, it becomes day next turn.)

View File

@@ -0,0 +1,23 @@
Name:Hound Tamer
ManaCost:2 G
Types:Creature Human Werewolf
PT:3/3
K:Trample
A:AB$ PutCounter | Cost$ 3 G | ValidTgts$ Creature | TgtPrompt$ Select target creature | CounterType$ P1P1 | CounterNum$ 1 | SpellDescription$ Put a +1/+1 counter on target creature.
K:Daybound
AlternateMode:DoubleFaced
Oracle:Trample\n{3}{G}: Put a +1/+1 counter on target creature.\nDaybound (If a player casts no spells during their own turn, it becomes night next turn.)
ALTERNATE
Name:Untamed Pup
ManaCost:no cost
Colors:green
Types:Creature Werewolf
PT:4/4
K:Trample
S:Mode$ Continuous | Affected$ Wolf.Other+YouCtrl,Werewolf.Other+YouCtrl | AddKeyword$ Trample | Description$ Other Wolves and Werewolves you control have trample.
A:AB$ PutCounter | Cost$ 3 G | ValidTgts$ Creature | TgtPrompt$ Select target creature | CounterType$ P1P1 | CounterNum$ 1 | SpellDescription$ Put a +1/+1 counter on target creature.
K:Nightbound
DeckHints:Type$Wolf & Type$Werewolf
Oracle:Trample\nOther Wolves and Werewolves you control have trample.\n{3}{G}: Put a +1/+1 counter on target creature.\nNightbound (If a player casts at least two spells during their own turn, it becomes day next turn.)

View File

@@ -0,0 +1,24 @@
Name:Kessig Naturalist
ManaCost:R G
Types:Creature Human Werewolf
PT:2/2
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigMana | TriggerDescription$ Whenever CARDNAME attacks, add {R} or {G}. Until end of turn, you don't lose this mana as steps and phases end.
SVar:TrigMana:DB$ Mana | Amount$ 1 | Produced$ Combo R G | PersistentMana$ True
K:Daybound
AlternateMode:DoubleFaced
Oracle:Whenever Kessig Naturalist attacks, add {R} or {G}. Until end of turn, you don't lose this mana as steps and phases end.\nDaybound (If a player casts no spells during their own turn, it becomes night next turn.)
ALTERNATE
Name:Lord of the Ulvenwald
ManaCost:no cost
Colors:red,green
Types:Creature Werewolf
PT:3/3
S:Mode$ Continuous | Affected$ Wolf.Other+YouCtrl,Werewolf.Other+YouCtrl | AddPower$ 1 | AddToughness$ 1 | Description$ Other Wolves and Werewolves you control get +1/+1.
SVar:PlayMain1:TRUE
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigMana | TriggerDescription$ Whenever CARDNAME attacks, add {R} or {G}. Until end of turn, you don't lose this mana as steps and phases end.
SVar:TrigMana:DB$ Mana | Amount$ 1 | Produced$ Combo R G | PersistentMana$ True
K:Nightbound
DeckHints:Type$Wolf & Type$Werewolf
Oracle:Other Wolves and Werewolves you control get +1/+1.\nWhenever Lord of the Ulvenwald attacks, add {R} or {G}. Until end of turn, you don't lose this mana as steps and phases end.\nNightbound (If a player casts at least two spells during their own turn, it becomes day next turn.)

View File

@@ -0,0 +1,6 @@
Name:Moonrager's Slash
ManaCost:2 R
Types:Instant
S:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ 2 | EffectZone$ All | Condition$ Night | Description$ This spell costs {2} less to cast if it's night.
A:SP$ DealDamage | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | NumDmg$ 3 | SpellDescription$ CARDNAME deals 3 damage to any target.
Oracle:This spell costs {2} less to cast if it's night.\nMoonrager's Slash deals 3 damage to any target.

View File

@@ -0,0 +1,14 @@
Name:Obsessive Astronomer
ManaCost:1 R
Types:Creature Human Wizard
PT:2/2
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | DayTime$ Neither | ReplaceWith$ DoDay | Description$ If it's neither day nor night, it becomes day as CARDNAME enters the battlefield.
SVar:DoDay:DB$ DayTime | Value$ Day | SubAbility$ ETB
SVar:ETB:DB$ InternalEtbReplacement
T:Mode$ DayTimeChanges | Execute$ TrigDiscard | TriggerZones$ Battlefield | TriggerDescription$ Whenever day becomes night or night becomes day, discard up to two cards, then draw that many cards.
SVar:TrigDiscard:DB$ Discard | Defined$ You | NumCards$ 2 | Optional$ True | Mode$ TgtChoose | RememberDiscarded$ True | SubAbility$ DBDraw
SVar:DBDraw:DB$ Draw | NumCards$ Y | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:Y:Remembered$Amount
DeckHas:Ability$Discard
Oracle:If it's neither day nor night, it becomes day as Obsessive Astronomer enters the battlefield.\nWhenever day becomes night or night becomes day, discard up to two cards, then draw that many cards.

View File

@@ -0,0 +1,6 @@
Name:Olivia's Midnight Ambush
ManaCost:1 B
Types:Instant
A:SP$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ -X | NumDef$ -X | SpellDescription$ Target creature gets -2/-2 until end of turn. If it's night, that creature gets -13/-13 until end of turn instead.
SVar:X:Count$Night.13.2
Oracle:Target creature gets -2/-2 until end of turn. If it's night, that creature gets -13/-13 until end of turn instead.

View File

@@ -0,0 +1,23 @@
Name:Outland Liberator
ManaCost:1 G
Types:Creature Human Werewolf
PT:2/2
A:AB$ Destroy | Cost$ 1 Sac<1/CARDNAME> | ValidTgts$ Artifact,Enchantment | TgtPrompt$ Select target artifact or enchantment | SpellDescription$ Destroy target artifact or enchantment.
K:Daybound
AlternateMode:DoubleFaced
Oracle:{1}, Sacrifice Outland Liberator: Destroy target artifact or enchantment.\nDaybound (If a player casts no spells during their own turn, it becomes night next turn.)
ALTERNATE
Name:Frenzied Trapbreaker
ManaCost:no cost
Colors:green
Types:Creature Werewolf
PT:3/3
A:AB$ Destroy | Cost$ 1 Sac<1/CARDNAME> | ValidTgts$ Artifact,Enchantment | TgtPrompt$ Select target artifact or enchantment | SpellDescription$ Destroy target artifact or enchantment.
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigDestroy | TriggerDescription$ Whenever CARDNAME attacks, destroy target artifact or enchantment defending player controls.
SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact.ControlledBy TriggeredDefendingPlayer,Enchantment.ControlledBy TriggeredDefendingPlayer | TgtPrompt$ Select target artifact or enchantment defending player controls
K:Nightbound
SVar:HasAttackEffect:TRUE
Oracle:{1}, Sacrifice Frenzied Trapbreaker: Destroy target artifact or enchantment.
Whenever Frenzied Trapbreaker attacks, destroy target artifact or enchantment defending player controls.\nNightbound (If a player casts at least two spells during their own turn, it becomes day next turn.)

View File

@@ -0,0 +1,21 @@
Name:Reckless Stormseeker
ManaCost:2 R
Types:Creature Human Werewolf
PT:2/3
T:Mode$ Phase | Phase$ BeginCombat | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ At the beginning of combat on your turn, target creature you control gets +1/+0 and gains haste until end of turn.
SVar:TrigPump:DB$ Pump | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | NumAtt$ 1 | KW$ Haste
K:Daybound
AlternateMode:DoubleFaced
Oracle:At the beginning of combat on your turn, target creature you control gets +1/+0 and gains haste until end of turn.\nDaybound (If a player casts no spells during their own turn, it becomes night next turn.)
ALTERNATE
Name:Storm-Charged Slasher
ManaCost:no cost
Colors:red
Types:Creature Werewolf
PT:3/4
T:Mode$ Phase | Phase$ BeginCombat | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ At the beginning of combat on your turn, target creature you control gets +2/+0 and gains trample and haste until end of turn.
SVar:TrigPump:DB$ Pump | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | NumAtt$ 2 | KW$ Trample & Haste
K:Nightbound
Oracle:At the beginning of combat on your turn, target creature you control gets +2/+0 and gains trample and haste until end of turn.\nNightbound (If a player casts at least two spells during their own turn, it becomes day next turn.)

View File

@@ -0,0 +1,19 @@
Name:Shady Traveler
ManaCost:2 B
Types:Creature Human Werewolf
PT:2/3
K:Menace
K:Daybound
AlternateMode:DoubleFaced
Oracle:Menace (This creature can't be blocked except by two or more creatures.)\nDaybound (If a player casts no spells during their own turn, it becomes night next turn.)
ALTERNATE
Name:Stalking Predator
ManaCost:no cost
Colors:black
Types:Creature Werewolf
PT:4/4
K:Menace
K:Nightbound
Oracle:Menace (This creature can't be blocked except by two or more creatures.)\nNightbound (If a player casts at least two spells during their own turn, it becomes day next turn.)

View File

@@ -0,0 +1,23 @@
Name:Spellrune Painter
ManaCost:2 R
Types:Creature Human Shaman Werewolf
PT:2/3
T:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ Whenever you cast an instant or sorcery spell, CARDNAME gets +1/+1 until end of turn.
SVar:TrigPump:DB$ Pump | Defined$ Self | ValidCard$ Card.Self | NumAtt$ 1 | NumDef$ 1
DeckHints:Type$Instant|Sorcery
K:Daybound
AlternateMode:DoubleFaced
Oracle:Whenever you cast an instant or sorcery spell, Spellrune Painter gets +1/+1 until end of turn.\nDaybound (If a player casts no spells during their own turn, it becomes night next turn.)
ALTERNATE
Name:Spellrune Howler
ManaCost:no cost
Colors:red
Types:Creature Werewolf
PT:3/4
T:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ Whenever you cast an instant or sorcery spell, CARDNAME gets +2/+2 until end of turn.
SVar:TrigPump:DB$ Pump | Defined$ Self | ValidCard$ Card.Self | NumAtt$ 2 | NumDef$ 2
DeckHints:Type$Instant|Sorcery
K:Nightbound
Oracle:Whenever you cast an instant or sorcery spell, Spellrune Howler gets +2/+2 until end of turn.\nNightbound (If a player casts at least two spells during their own turn, it becomes day next turn.)

View File

@@ -0,0 +1,13 @@
Name:Sunrise Cavalier
ManaCost:1 R W
Types:Creature Human Knight
PT:3/3
K:Trample
K:Haste
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | DayTime$ Neither | ReplaceWith$ DoDay | Description$ If it's neither day nor night, it becomes day as CARDNAME enters the battlefield.
SVar:DoDay:DB$ DayTime | Value$ Day | SubAbility$ ETB
SVar:ETB:DB$ InternalEtbReplacement
T:Mode$ DayTimeChanges | Execute$ TrigPutCounter | TriggerZones$ Battlefield | TriggerDescription$ Whenever day becomes night or night becomes day, put a +1/+1 counter on target creature you control.
SVar:TrigPutCounter:DB$ PutCounter | ValidTgts$ Creature | TgtPrompt$ Select target creature | CounterType$ P1P1 | CounterNum$ 1
DeckHas:Ability$Counters
Oracle:Trample, haste\nIf it's neither day nor night, it becomes day as Sunrise Cavalier enters the battlefield.\nWhenever day becomes night or night becomes day, put a +1/+1 counter on target creature you control.

View File

@@ -0,0 +1,12 @@
Name:Sunstreak Phoenix
ManaCost:2 R R
Types:Creature Phoenix
PT:4/2
K:Flying
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | DayTime$ Neither | ReplaceWith$ DoDay | Description$ If it's neither day nor night, it becomes day as CARDNAME enters the battlefield.
SVar:DoDay:DB$ DayTime | Value$ Day | SubAbility$ ETB
SVar:ETB:DB$ InternalEtbReplacement
T:Mode$ DayTimeChanges | Execute$ TrigReturn | TriggerZones$ Battlefield | TriggerDescription$ Whenever day becomes night or night becomes day, you may pay {1}{R}. If you do, return CARDNAME from your graveyard to the battlefield tapped.
SVar:TrigReturn:AB$ ChangeZone | Cost$ 1 R | Origin$ Graveyard | Destination$ Battlefield | Tapped$ True
DeckHas:Ability$Graveyard
Oracle:Flying\nIf it's neither day nor night, it becomes day as Sunstreak Phoenix enters the battlefield.\nWhenever day becomes night or night becomes day, you may pay {1}{R}. If you do, return Sunstreak Phoenix from your graveyard to the battlefield tapped.

View File

@@ -0,0 +1,26 @@
Name:Suspicious Stowaway
ManaCost:1 U
Types:Creature Human Rogue Werewolf
PT:1/1
K:Unblockable
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigDraw | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, draw a card, then discard a card.
SVar:TrigDraw:DB$ Draw | NumCards$ 1 | Defined$ You | SubAbility$ DBDiscard
SVar:DBDiscard:DB$ Discard | Defined$ You | Mode$ TgtChoose | NumCards$ 1
K:Daybound
AlternateMode:DoubleFaced
DeckHas:Ability$Discard
Oracle:Suspicious Stowaway can't be blocked.\nWhenever Suspicious Stowaway deals combat damage to a player, draw a card, then discard a card.\nDaybound (If a player casts no spells during their own turn, it becomes night next turn.)
ALTERNATE
Name:Seafaring Werewolf
ManaCost:no cost
Colors:green
Types:Creature Werewolf
PT:2/1
K:Unblockable
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigDrawN | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, draw a card, then discard a card.
SVar:TrigDrawN:DB$ Draw | NumCards$ 1 | Defined$ You | SubAbility$ DBDiscardN
SVar:DBDiscardN:DB$ Discard | Defined$ You | Mode$ TgtChoose | NumCards$ 1
K:Nightbound
Oracle:Seafaring Werewolf can't be blocked.\nWhenever Seafaring Werewolf deals combat damage to a player, draw a card.\nNightbound (If a player casts at least two spells during their own turn, it becomes day next turn.)

View File

@@ -0,0 +1,17 @@
Name:Tavern Ruffian
ManaCost:3 R
Types:Creature Human Warrior Werewolf
PT:2/5
K:Daybound
AlternateMode:DoubleFaced
Oracle:Daybound (If a player casts no spells during their own turn, it becomes night next turn.)
ALTERNATE
Name:Tavern Smasher
ManaCost:no cost
Colors:red
Types:Creature Werewolf
PT:6/5
K:Nightbound
Oracle:Nightbound (If a player casts at least two spells during their own turn, it becomes day next turn.)

View File

@@ -0,0 +1,15 @@
Name:The Celestus
ManaCost:3
Types:Legendary Artifact
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | DayTime$ Neither | ReplaceWith$ DoDay | Description$ If it's neither day nor night, it becomes day as CARDNAME enters the battlefield.
SVar:DoDay:DB$ DayTime | Value$ Day | SubAbility$ ETB
SVar:ETB:DB$ InternalEtbReplacement
A:AB$ Mana | Cost$ T | Produced$ Any | SpellDescription$ Add one mana of any color.
A:AB$ DayTime | Cost$ 3 T | Value$ Switch | SorcerySpeed$ True | SpellDescription$ If it's night, it becomes day. Otherwise, it becomes night. Activate only as a sorcery.
T:Mode$ DayTimeChanges | Execute$ DBGainLife | TriggerZones$ Battlefield | TriggerDescription$ Whenever day becomes night or night becomes day, you gain 1 life. You may draw a card. If you do, discard a card.
SVar:DBGainLife:DB$ GainLife | LifeAmount$ 1 | SubAbility$ DBDiscard | StackDescription$ {p:You} gain 1 life.
SVar:DBDiscard:DB$ Discard | Defined$ You | Mode$ TgtChoose | NumCards$ 1 | UnlessCost$ Draw<1/You> | UnlessPayer$ You | UnlessSwitched$ True
DeckHas:Ability$LifeGain
Oracle:If it's neither day nor night, it becomes day as The Celestus enters the battlefield.\n{T}: Add one mana of any color.\n{3}, {T}: If it's night, it becomes day. Otherwise, it becomes night. Activate only as a sorcery.\nWhenever day becomes night or night becomes day, you gain 1 life. You may draw a card. If you do, discard a card.

View File

@@ -0,0 +1,19 @@
Name:Tireless Hauler
ManaCost:4 G
Types:Creature Human Werewolf
PT:4/5
K:Vigilance
K:Daybound
AlternateMode:DoubleFaced
Oracle:Vigilance\nDaybound (If a player casts no spells during their own turn, it becomes night next turn.)
ALTERNATE
Name:Dire-Strain Brawler
ManaCost:no cost
Colors:green
Types:Creature Werewolf
PT:6/6
K:Vigilance
K:Nightbound
Oracle:Vigilance\nNightbound (If a player casts at least two spells during their own turn, it becomes day next turn.)

View File

@@ -0,0 +1,32 @@
Name:Tovolar, Dire Overlord
ManaCost:1 R G
Types:Legendary Creature Human Werewolf
PT:3/3
T:Mode$ DamageDone | ValidSource$ Wolf.YouCtrl,Werewolf.YouCtrl | ValidTarget$ Player | CombatDamage$ True | TriggerZones$ Battlefield | Execute$ TrigDrawD | TriggerDescription$ Whenever a Wolf or Werewolf you control deals combat damage to a player, draw a card.
SVar:TrigDrawD:DB$ Draw | Defined$ You | NumCards$ 1
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | CheckSVar$ X | SVarCompare$ GE3 | Execute$ TrigNight | TriggerDescription$ At the beginning of your upkeep, if you control three or more Wolves and/or Werewolves, it becomes night. Then transform any number of Human Werewolves you control.
SVar:TrigNight:DB$ DayTime | Value$ Night | SubAbility$ DBTransform
SVar:DBTransform:DB$ SetState | MinAmount$ 0 | Amount$ NumHumanWerewolves | Choices$ Human.Werewolf+YouCtrl+DoubleFaced | ChoiceTitle$ Choose any number of Human Werewolves you control | Mode$ Transform
K:Daybound
SVar:NumHumanWerewolves:Count$Valid Human.Werewolf+YouCtrl+DoubleFaced
SVar:Y:Count$Valid Wolf.YouCtrl
SVar:Z:Count$Valid Werewolf.YouCtrl
SVar:X:SVar$Y/Plus.Z
AlternateMode:DoubleFaced
DeckHints:Type$Wolf|Werewolf
Oracle:Whenever a Wolf or Werewolf you control deals combat damage to a player, draw a card.\nAt the beginning of your upkeep, if you control three or more Wolves and/or Werewolves, it becomes night. Then transform any number of Human Werewolves you control.\nDaybound
ALTERNATE
Name:Tovolar, the Midnight Scourge
ManaCost:no cost
Colors:red,green
Types:Legendary Creature Werewolf
PT:4/4
T:Mode$ DamageDone | ValidSource$ Wolf.YouCtrl,Werewolf.YouCtrl | ValidTarget$ Player | CombatDamage$ True | TriggerZones$ Battlefield | Execute$ TrigDrawN | TriggerDescription$ Whenever a Wolf or Werewolf you control deals combat damage to a player, draw a card.
SVar:TrigDrawN:DB$ Draw | Defined$ You | NumCards$ 1
A:AB$ Pump | Cost$ X R G | ValidTgts$ Wolf.YouCtrl,Werewolf.YouCtrl | TgtPrompt$ Select target Wolf or Werewolf you control | NumAtt$ X | KW$ Trample | SpellDescription$ Target Wolf or Werewolf you control gets +X/+0 and gains trample until end of turn.
K:Nightbound
SVar:X:Count$xPaid
DeckHints:Type$Wolf|Werewolf
Oracle:Whenever a Wolf or Werewolf you control deals combat damage to a player, draw a card.\n{X}{R}{G}: Target Wolf or Werewolf you control gets +X/+0 and gains trample until end of turn.\nNightbound

View File

@@ -0,0 +1,27 @@
Name:Tovolar's Huntmaster
ManaCost:4 G G
Types:Creature Human Werewolf
PT:6/6
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME enters the battlefield, create two 2/2 green Wolf creature tokens.
SVar:TrigToken:DB$ Token | TokenAmount$ 2 | TokenScript$ g_2_2_wolf
K:Daybound
AlternateMode:DoubleFaced
DeckHas:Ability$Token
Oracle:When Tovolar's Huntmaster enters the battlefield, create two 2/2 green Wolf creature tokens.\nDaybound (If a player casts no spells during their own turn, it becomes night next turn.)
ALTERNATE
Name:Tovolar's Packleader
ManaCost:no cost
Colors:green
Types:Creature Werewolf
PT:7/7
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ Whenever CARDNAME enters the battlefield or attacks, create two 2/2 green Wolf creature tokens.
T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ TrigToken | Secondary$ True | TriggerDescription$ Whenever CARDNAME enters the battlefield or attacks, create two 2/2 green Wolf creature tokens.
SVar:TrigToken:DB$ Token | TokenAmount$ 2 | TokenScript$ g_2_2_wolf
A:AB$ Pump | Cost$ 2 G G | ValidTgts$ Wolf.Other+YouCtrl,Werewolf.Other+YouCtrl | TgtPrompt$ Select another target Wolf or Werewolf you control | AILogic$ Fight | SubAbility$ DBFight | StackDescription$ {c:ThisTargetedCard} | SpellDescription$ Another target Wolf or Werewolf you control fights target creature you don't control.
SVar:DBFight:DB$ Fight | Defined$ ParentTarget | ValidTgts$ Creature.YouDontCtrl | TgtPrompt$ Choose target creature you don't control | StackDescription$ fights {c:ThisTargetedCard}.
K:Nightbound
DeckHas:Ability$Token
DeckHints:Type$Wolf|Werewolf
Oracle:Whenever Tovolar's Packleader enters the battlefield or attacks, create two 2/2 green Wolf creature tokens.\n{2}{G}{G}: Another target Wolf or Werewolf you control fights target creature you don't control.\nNightbound (If a player casts at least two spells during their own turn, it becomes day next turn.)

View File

@@ -0,0 +1,10 @@
Name:Unnatural Moonrise
ManaCost: R G
Types:Sorcery
A:SP$ DayTime | Value$ Night | SubAbility$ DBPump | SpellDescription$ It becomes night. Until end of turn, target creature gets +1/+0 and gains trample and "Whenever this creature deals combat damage to a player, draw a card."
SVar:DBPump:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ 1 | KW$ Trample | SubAbility$ DBAnimate | StackDescription$ Until end of turn, {c:Targeted} gets +1/+0 and gains trample and "Whenever this creature deals combat damage to a player, draw a card."
SVar:DBAnimate:DB$ Animate | Defined$ Targeted | Triggers$ DamageDraw | StackDescription$ None
SVar:DamageDraw:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | TriggerZones$ Battlefield | Execute$ TrigDraw | TriggerDescription$ Whenever this creature deals combat damage to a player, draw a card.
SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ 1
K:Flashback:2 R G
Oracle:It becomes night. Until end of turn, target creature gets +1/+0 and gains trample and "Whenever this creature deals combat damage to a player, draw a card."\nFlashback {2}{R}{G} (You may cast this card from your graveyard for its flashback cost. Then exile it.)

View File

@@ -0,0 +1,14 @@
Name:Vadrik, Astral Archmage
ManaCost:1 U R
Types:Legendary Creature Human Wizard
PT:1/2
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield | DayTime$ Neither | ReplaceWith$ DoDay | Description$ If it's neither day nor night, it becomes day as CARDNAME enters the battlefield.
SVar:DoDay:DB$ DayTime | Value$ Day | SubAbility$ ETB
SVar:ETB:DB$ InternalEtbReplacement
S:Mode$ ReduceCost | ValidCard$ Instant,Sorcery | Type$ Spell | Activator$ You | Amount$ X | Description$ Instant and sorcery spells you cast cost {X} less to cast, where X is NICKNAME's power.
SVar:X:Count$CardPower
T:Mode$ DayTimeChanges | Execute$ TrigPutCounter | TriggerZones$ Battlefield | TriggerDescription$ Whenever day becomes night or night becomes day, put a +1/+1 counter on NICKNAME.
SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ 1
DeckHints:Type$Instant|Sorcery
DeckHas:Ability$Counters
Oracle:If it's neither day nor night, it becomes day as Vadrik, Astral Archmage enters the battlefield.\nInstant and sorcery spells you cast cost {X} less to cast, where X is Vadriks power.\nWhenever day becomes night or night becomes day, put a +1/+1 counter on Vadrik.

View File

@@ -0,0 +1,20 @@
Name:Village Watch
ManaCost:4 R
Types:Creature Human Werewolf
PT:4/3
K:Haste
K:Daybound
AlternateMode:DoubleFaced
Oracle:Haste\nDaybound (If a player casts no spells during their own turn, it becomes night next turn.)
ALTERNATE
Name:Village Reavers
ManaCost:no cost
Colors:red
Types:Creature Werewolf
PT:5/4
S:Mode$ Continuous | Affected$ Wolf.YouCtrl,Werewolf.YouCtrl | AddKeyword$ Haste | Description$ Wolves and Werewolves you control have haste.
K:Nightbound
DeckHints:Type$Wolf|Werewolf
Oracle:Wolves and Werewolves you control have haste.\nNightbound (If a player casts at least two spells during their own turn, it becomes day next turn.)

View File

@@ -2714,3 +2714,6 @@ lblWildOpponentNumberError=Anzahl der Wild-Gegner kann nur 0 bis 3 sein
lblGauntletProgress=Spießrutenlauf-Fortschritt
#SpellAbility.java
lblInvalidTargetSpecification=Nicht alle Zielbedingungen sind erfüllt.
#CPrompt.java
lblDay=Tag
lblNight=Nacht

View File

@@ -2712,3 +2712,6 @@ lblWildOpponentNumberError=Wild Opponents can only be 0 to 3
lblGauntletProgress=Gauntlet Progress
#SpellAbility.java
lblInvalidTargetSpecification=Not all target requirements are met.
#CPrompt.java
lblDay=Day
lblNight=Night

View File

@@ -2712,3 +2712,6 @@ lblWildOpponentNumberError=Los oponentes salvajes sólo pueden ser de 0 a 3
lblGauntletProgress=Progreso del desafío
#SpellAbility.java
lblInvalidTargetSpecification=No se cumplen todos los requisitos de objetivos.
#CPrompt.java
lblDay=Día
lblNight=Noche

View File

@@ -2711,3 +2711,6 @@ lblWildOpponentNumberError=Gli avversari a sorpresa possono essere da 0 a 3
lblGauntletProgress=Avanzamento della Sfida
#SpellAbility.java
lblInvalidTargetSpecification=Bersagli non validi.
#CPrompt.java
lblDay=Giorno
lblNight=Notte

View File

@@ -2711,3 +2711,6 @@ lblWildOpponentNumberError=ワイルカード相手は 0~3 を設定してくだ
lblGauntletProgress=ガントレット進行状況
#SpellAbility.java
lblInvalidTargetSpecification=全ての対象制限を満たしていない。
#CPrompt.java
lblDay=
lblNight=

View File

@@ -2713,3 +2713,6 @@ lblWildOpponentNumberError=野外对手数只能在0-3之间
lblGauntletProgress=决斗进度
#SpellAbility.java
lblInvalidTargetSpecification=并非所有目标的要求都得到了满足。
#CPrompt.java
lblDay=
lblNight=夜晚

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

Binary file not shown.

View File

@@ -44,6 +44,7 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
private final Map<PlayerView, IGameController> originalGameControllers = Maps.newHashMap();
private boolean gamePause = false;
private boolean gameSpeed = false;
private String daytime = null;
private boolean ignoreConcedeChain = false;
public final boolean hasLocalPlayers() {
@@ -62,6 +63,17 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
public final PlayerView getCurrentPlayer() {
return currentPlayer;
}
@Override
public String getDayTime() {
return daytime;
}
@Override
public void updateDayTime(String daytime) {
this.daytime = daytime;
}
@Override
public final void setCurrentPlayer(PlayerView player) {
player = TrackableTypes.PlayerViewType.lookup(player); //ensure we use the correct player
@@ -772,6 +784,7 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
awaitNextInputTimer.cancel();
awaitNextInputTimer = null;
}
daytime = null;
}
// End of Choice code
}

View File

@@ -317,6 +317,7 @@ public class HostedMatch {
humanController.getGui().afterGameEnd();
else if (!GuiBase.getInterface().isLibgdxPort()||!isMatchOver)
humanController.getGui().afterGameEnd();
humanController.getGui().updateDayTime(null);
}
humanControllers.clear();
}

View File

@@ -465,6 +465,12 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base<Void> {
}
}
@Override
public Void visit(final GameEventDayTimeChanged event) {
matchController.updateDayTime(event.daytime ? "Day" : "Night");
return processEvent();
}
@Override
public Void visit(final GameEventManaPool event) {
return processPlayer(event.player, manaPoolUpdate);

View File

@@ -173,8 +173,10 @@ public interface IGuiGame {
void clearSelectables();
boolean isSelecting();
boolean isGamePaused();
public void setgamePause(boolean pause);
public void setGameSpeed(boolean gameSpeed);
void setgamePause(boolean pause);
void setGameSpeed(boolean gameSpeed);
String getDayTime();
void updateDayTime(String daytime);
void awaitNextInput();
void cancelAwaitNextInput();

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