mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 18:58:00 +00:00
Resolve "Daybound & Nightbound"
This commit is contained in:
@@ -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")) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,7 +126,6 @@ public enum AbilityKey {
|
||||
TgtSA("TgtSA"),
|
||||
Token("Token"),
|
||||
TokenNum("TokenNum"),
|
||||
Transformer("Transformer"),
|
||||
TriggeredParams("TriggeredParams"),
|
||||
Vehicle("Vehicle"),
|
||||
Won("Won");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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(":");
|
||||
|
||||
@@ -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 it’s 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 it’s 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 can’t 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 can’t be transformed except by its nightbound ability.";
|
||||
} else if (keyword.startsWith("Protection")) {
|
||||
String valid = getProtectionValid(keyword, false);
|
||||
effect = "Mode$ CantBlockBy | ValidAttacker$ Creature.Self ";
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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."),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 "";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
15
forge-gui-android/assets/shaders/grayscale.frag
Normal file
15
forge-gui-android/assets/shaders/grayscale.frag
Normal 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);
|
||||
}
|
||||
14
forge-gui-android/assets/shaders/grayscale.vert
Normal file
14
forge-gui-android/assets/shaders/grayscale.vert
Normal 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;
|
||||
}
|
||||
40
forge-gui-android/assets/shaders/outline.frag
Normal file
40
forge-gui-android/assets/shaders/outline.frag
Normal 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);
|
||||
}
|
||||
16
forge-gui-android/assets/shaders/outline.vert
Normal file
16
forge-gui-android/assets/shaders/outline.vert
Normal 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;
|
||||
}
|
||||
23
forge-gui-android/assets/shaders/underwater.frag
Normal file
23
forge-gui-android/assets/shaders/underwater.frag
Normal 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);
|
||||
}
|
||||
57
forge-gui-android/assets/shaders/warp.frag
Normal file
57
forge-gui-android/assets/shaders/warp.frag
Normal 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);
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -149,7 +149,7 @@ public class FPanel extends FPanelBase implements ILocalRepaint {
|
||||
|
||||
/** @param img0   {@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.
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
15
forge-gui-mobile-dev/shaders/grayscale.frag
Normal file
15
forge-gui-mobile-dev/shaders/grayscale.frag
Normal 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);
|
||||
}
|
||||
14
forge-gui-mobile-dev/shaders/grayscale.vert
Normal file
14
forge-gui-mobile-dev/shaders/grayscale.vert
Normal 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;
|
||||
}
|
||||
40
forge-gui-mobile-dev/shaders/outline.frag
Normal file
40
forge-gui-mobile-dev/shaders/outline.frag
Normal 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);
|
||||
}
|
||||
16
forge-gui-mobile-dev/shaders/outline.vert
Normal file
16
forge-gui-mobile-dev/shaders/outline.vert
Normal 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;
|
||||
}
|
||||
23
forge-gui-mobile-dev/shaders/underwater.frag
Normal file
23
forge-gui-mobile-dev/shaders/underwater.frag
Normal 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);
|
||||
}
|
||||
57
forge-gui-mobile-dev/shaders/warp.frag
Normal file
57
forge-gui-mobile-dev/shaders/warp.frag
Normal 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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -177,7 +177,8 @@ public class MatchController extends AbstractGuiGame {
|
||||
}
|
||||
|
||||
actuateMatchPreferences();
|
||||
|
||||
//reset daytime every match
|
||||
updateDayTime(null);
|
||||
Forge.openScreen(view);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
@@ -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.)
|
||||
@@ -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.)
|
||||
11
forge-gui/res/cardsfolder/upcoming/brimstone_vandal.txt
Normal file
11
forge-gui/res/cardsfolder/upcoming/brimstone_vandal.txt
Normal 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 can’t 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.
|
||||
@@ -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.)
|
||||
@@ -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.)
|
||||
11
forge-gui/res/cardsfolder/upcoming/celestus_sanctifier.txt
Normal file
11
forge-gui/res/cardsfolder/upcoming/celestus_sanctifier.txt
Normal 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.
|
||||
10
forge-gui/res/cardsfolder/upcoming/component_collector.txt
Normal file
10
forge-gui/res/cardsfolder/upcoming/component_collector.txt
Normal 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.
|
||||
@@ -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.)
|
||||
@@ -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.)
|
||||
10
forge-gui/res/cardsfolder/upcoming/firmament_sage.txt
Normal file
10
forge-gui/res/cardsfolder/upcoming/firmament_sage.txt
Normal 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.
|
||||
11
forge-gui/res/cardsfolder/upcoming/gavony_dawnguard.txt
Normal file
11
forge-gui/res/cardsfolder/upcoming/gavony_dawnguard.txt
Normal 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.
|
||||
@@ -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.)
|
||||
@@ -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.)
|
||||
@@ -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.)
|
||||
@@ -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.)
|
||||
6
forge-gui/res/cardsfolder/upcoming/moonragers_slash.txt
Normal file
6
forge-gui/res/cardsfolder/upcoming/moonragers_slash.txt
Normal 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.
|
||||
14
forge-gui/res/cardsfolder/upcoming/obsessive_astronomer.txt
Normal file
14
forge-gui/res/cardsfolder/upcoming/obsessive_astronomer.txt
Normal 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.
|
||||
@@ -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.
|
||||
@@ -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.)
|
||||
@@ -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.)
|
||||
@@ -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.)
|
||||
@@ -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.)
|
||||
13
forge-gui/res/cardsfolder/upcoming/sunrise_cavalier.txt
Normal file
13
forge-gui/res/cardsfolder/upcoming/sunrise_cavalier.txt
Normal 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.
|
||||
12
forge-gui/res/cardsfolder/upcoming/sunstreak_phoenix.txt
Normal file
12
forge-gui/res/cardsfolder/upcoming/sunstreak_phoenix.txt
Normal 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.
|
||||
@@ -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.)
|
||||
@@ -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.)
|
||||
15
forge-gui/res/cardsfolder/upcoming/the_celestus.txt
Normal file
15
forge-gui/res/cardsfolder/upcoming/the_celestus.txt
Normal 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.
|
||||
@@ -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.)
|
||||
@@ -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
|
||||
@@ -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.)
|
||||
10
forge-gui/res/cardsfolder/upcoming/unnatural_moonrise.txt
Normal file
10
forge-gui/res/cardsfolder/upcoming/unnatural_moonrise.txt
Normal 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.)
|
||||
@@ -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 Vadrik’s power.\nWhenever day becomes night or night becomes day, put a +1/+1 counter on Vadrik.
|
||||
@@ -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.)
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -2711,3 +2711,6 @@ lblWildOpponentNumberError=ワイルカード相手は 0~3 を設定してくだ
|
||||
lblGauntletProgress=ガントレット進行状況
|
||||
#SpellAbility.java
|
||||
lblInvalidTargetSpecification=全ての対象制限を満たしていない。
|
||||
#CPrompt.java
|
||||
lblDay=日
|
||||
lblNight=夜
|
||||
|
||||
@@ -2713,3 +2713,6 @@ lblWildOpponentNumberError=野外对手数只能在0-3之间
|
||||
lblGauntletProgress=决斗进度
|
||||
#SpellAbility.java
|
||||
lblInvalidTargetSpecification=并非所有目标的要求都得到了满足。
|
||||
#CPrompt.java
|
||||
lblDay=日
|
||||
lblNight=夜晚
|
||||
|
||||
BIN
forge-gui/res/skins/default/bg_day.jpg
Normal file
BIN
forge-gui/res/skins/default/bg_day.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 152 KiB |
BIN
forge-gui/res/skins/default/bg_night.jpg
Normal file
BIN
forge-gui/res/skins/default/bg_night.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 134 KiB |
BIN
forge-gui/res/sound/daytime.mp3
Normal file
BIN
forge-gui/res/sound/daytime.mp3
Normal file
Binary file not shown.
BIN
forge-gui/res/sound/nighttime.mp3
Normal file
BIN
forge-gui/res/sound/nighttime.mp3
Normal file
Binary file not shown.
@@ -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
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user