mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 11:18:01 +00:00
Merge branch 'master' into 'm19'
This commit is contained in:
@@ -76,6 +76,51 @@ public final class CardFacePredicates {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class ValidPredicate implements Predicate<ICardFace> {
|
||||||
|
private String valid;
|
||||||
|
|
||||||
|
public ValidPredicate(final String valid) {
|
||||||
|
this.valid = valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(ICardFace input) {
|
||||||
|
String k[] = valid.split("\\.", 2);
|
||||||
|
|
||||||
|
if ("Card".equals(k[0])) {
|
||||||
|
// okay
|
||||||
|
} else if ("Permanent".equals(k[0])) {
|
||||||
|
if (input.getType().isInstant() || input.getType().isSorcery()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (!input.getType().hasStringType(k[0])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (k.length > 1) {
|
||||||
|
for (final String m : k[1].split("\\+")) {
|
||||||
|
if (!hasProperty(input, m)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static protected boolean hasProperty(ICardFace input, final String v) {
|
||||||
|
if (v.startsWith("non")) {
|
||||||
|
return !hasProperty(input, v.substring(3));
|
||||||
|
} else if (!input.getType().hasStringType(v)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Predicate<ICardFace> valid(final String val) {
|
||||||
|
return new ValidPredicate(val);
|
||||||
|
}
|
||||||
|
|
||||||
public static class Presets {
|
public static class Presets {
|
||||||
/** The Constant isBasicLand. */
|
/** The Constant isBasicLand. */
|
||||||
public static final Predicate<ICardFace> IS_BASIC_LAND = new Predicate<ICardFace>() {
|
public static final Predicate<ICardFace> IS_BASIC_LAND = new Predicate<ICardFace>() {
|
||||||
|
|||||||
@@ -368,6 +368,7 @@ public class GameAction {
|
|||||||
|
|
||||||
final Map<String, Object> runParams = Maps.newHashMap();
|
final Map<String, Object> runParams = Maps.newHashMap();
|
||||||
runParams.put("Card", lastKnownInfo);
|
runParams.put("Card", lastKnownInfo);
|
||||||
|
runParams.put("Cause", cause);
|
||||||
runParams.put("Origin", zoneFrom != null ? zoneFrom.getZoneType().name() : null);
|
runParams.put("Origin", zoneFrom != null ? zoneFrom.getZoneType().name() : null);
|
||||||
runParams.put("Destination", zoneTo.getZoneType().name());
|
runParams.put("Destination", zoneTo.getZoneType().name());
|
||||||
runParams.put("SpellAbilityStackInstance", game.stack.peek());
|
runParams.put("SpellAbilityStackInstance", game.stack.peek());
|
||||||
|
|||||||
@@ -105,17 +105,8 @@ public class ChooseCardNameEffect extends SpellAbilityEffect {
|
|||||||
final String message = validDesc.equals("card") ? "Name a card" : "Name a " + validDesc + " card.";
|
final String message = validDesc.equals("card") ? "Name a card" : "Name a " + validDesc + " card.";
|
||||||
|
|
||||||
Predicate<ICardFace> cpp = Predicates.alwaysTrue();
|
Predicate<ICardFace> cpp = Predicates.alwaysTrue();
|
||||||
if ( StringUtils.containsIgnoreCase(valid, "nonland") ) {
|
if (sa.hasParam("ValidCards")) {
|
||||||
cpp = CardFacePredicates.Presets.IS_NON_LAND;
|
cpp = CardFacePredicates.valid(valid);
|
||||||
}
|
|
||||||
if ( StringUtils.containsIgnoreCase(valid, "nonbasic") ) {
|
|
||||||
cpp = Predicates.not(CardFacePredicates.Presets.IS_BASIC_LAND);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( StringUtils.containsIgnoreCase(valid, "noncreature") ) {
|
|
||||||
cpp = Predicates.not(CardFacePredicates.Presets.IS_CREATURE);
|
|
||||||
} else if ( StringUtils.containsIgnoreCase(valid, "creature") ) {
|
|
||||||
cpp = CardFacePredicates.Presets.IS_CREATURE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
chosen = p.getController().chooseCardName(sa, cpp, valid, message);
|
chosen = p.getController().chooseCardName(sa, cpp, valid, message);
|
||||||
|
|||||||
@@ -65,57 +65,68 @@ public class TriggerChangesZone extends Trigger {
|
|||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public final boolean performTest(final java.util.Map<String, Object> runParams2) {
|
public final boolean performTest(final Map<String, Object> runParams2) {
|
||||||
if (this.mapParams.containsKey("Origin")) {
|
if (hasParam("Origin")) {
|
||||||
if (!this.mapParams.get("Origin").equals("Any")) {
|
if (!getParam("Origin").equals("Any")) {
|
||||||
if (this.mapParams.get("Origin") == null) {
|
if (getParam("Origin") == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!ArrayUtils.contains(
|
if (!ArrayUtils.contains(
|
||||||
this.mapParams.get("Origin").split(","), runParams2.get("Origin")
|
getParam("Origin").split(","), runParams2.get("Origin")
|
||||||
)) {
|
)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.mapParams.containsKey("Destination")) {
|
if (hasParam("Destination")) {
|
||||||
if (!this.mapParams.get("Destination").equals("Any")) {
|
if (!getParam("Destination").equals("Any")) {
|
||||||
if (!ArrayUtils.contains(
|
if (!ArrayUtils.contains(
|
||||||
this.mapParams.get("Destination").split(","), runParams2.get("Destination")
|
getParam("Destination").split(","), runParams2.get("Destination")
|
||||||
)) {
|
)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.mapParams.containsKey("ExcludedDestinations")) {
|
if (hasParam("ExcludedDestinations")) {
|
||||||
if (!ArrayUtils.contains(
|
if (!ArrayUtils.contains(
|
||||||
this.mapParams.get("ExcludedDestinations").split(","), runParams2.get("Destination")
|
getParam("ExcludedDestinations").split(","), runParams2.get("Destination")
|
||||||
)) {
|
)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.mapParams.containsKey("ValidCard")) {
|
if (hasParam("ValidCard")) {
|
||||||
Card moved = (Card) runParams2.get("Card");
|
Card moved = (Card) runParams2.get("Card");
|
||||||
final Game game = this.getHostCard().getGame();
|
final Game game = getHostCard().getGame();
|
||||||
boolean isDiesTrig = "Battlefield".equals(this.mapParams.get("Origin"))
|
boolean isDiesTrig = "Battlefield".equals(getParam("Origin"))
|
||||||
&& "Graveyard".equals(this.mapParams.get("Destination"));
|
&& "Graveyard".equals(getParam("Destination"));
|
||||||
|
|
||||||
if (isDiesTrig) {
|
if (isDiesTrig) {
|
||||||
moved = game.getChangeZoneLKIInfo(moved);
|
moved = game.getChangeZoneLKIInfo(moved);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!moved.isValid(this.mapParams.get("ValidCard").split(","), this.getHostCard().getController(),
|
if (!moved.isValid(getParam("ValidCard").split(","), getHostCard().getController(),
|
||||||
this.getHostCard(), null)) {
|
getHostCard(), null)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasParam("ValidCause")) {
|
||||||
|
if (!runParams2.containsKey("Cause") ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SpellAbility cause = (SpellAbility) runParams2.get("Cause");
|
||||||
|
if (!cause.getHostCard().isValid(getParam("ValidCause").split(","), getHostCard().getController(),
|
||||||
|
getHostCard(), null)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check number of lands ETB this turn on triggered card's controller
|
// Check number of lands ETB this turn on triggered card's controller
|
||||||
if (mapParams.containsKey("CheckOnTriggeredCard")) {
|
if (hasParam("CheckOnTriggeredCard")) {
|
||||||
final String[] condition = mapParams.get("CheckOnTriggeredCard").split(" ", 2);
|
final String[] condition = getParam("CheckOnTriggeredCard").split(" ", 2);
|
||||||
|
|
||||||
final Card host = hostCard.getGame().getCardState(hostCard);
|
final Card host = hostCard.getGame().getCardState(hostCard);
|
||||||
final String comparator = condition.length < 2 ? "GE1" : condition[1];
|
final String comparator = condition.length < 2 ? "GE1" : condition[1];
|
||||||
@@ -128,8 +139,8 @@ public class TriggerChangesZone extends Trigger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check amount of damage dealt to the triggered card
|
// Check amount of damage dealt to the triggered card
|
||||||
if (this.mapParams.containsKey("DamageReceivedCondition")) {
|
if (hasParam("DamageReceivedCondition")) {
|
||||||
final String cond = this.mapParams.get("DamageReceivedCondition");
|
final String cond = getParam("DamageReceivedCondition");
|
||||||
if (cond.length() < 3) {
|
if (cond.length() < 3) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -152,7 +163,7 @@ public class TriggerChangesZone extends Trigger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.mapParams.containsKey("OncePerEffect")) {
|
if (hasParam("OncePerEffect")) {
|
||||||
// A "once per effect" trigger will only trigger once regardless of how many things the effect caused
|
// A "once per effect" trigger will only trigger once regardless of how many things the effect caused
|
||||||
// to change zones.
|
// to change zones.
|
||||||
|
|
||||||
@@ -184,8 +195,8 @@ public class TriggerChangesZone extends Trigger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* this trigger can only be activated once per turn, verify it hasn't already run */
|
/* this trigger can only be activated once per turn, verify it hasn't already run */
|
||||||
if (this.mapParams.containsKey("ActivationLimit")) {
|
if (hasParam("ActivationLimit")) {
|
||||||
return this.getActivationsThisTurn() < Integer.parseInt(this.mapParams.get("ActivationLimit"));
|
return this.getActivationsThisTurn() < Integer.parseInt(getParam("ActivationLimit"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import javax.swing.WindowConstants;
|
|||||||
import javax.swing.event.ListSelectionEvent;
|
import javax.swing.event.ListSelectionEvent;
|
||||||
import javax.swing.event.ListSelectionListener;
|
import javax.swing.event.ListSelectionListener;
|
||||||
|
|
||||||
|
import forge.card.CardStateName;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
@@ -165,7 +166,25 @@ public class GuiChoose {
|
|||||||
if (paper == null) {
|
if (paper == null) {
|
||||||
paper = FModel.getMagicDb().getVariantCards().getUniqueByName(face.getName());
|
paper = FModel.getMagicDb().getVariantCards().getUniqueByName(face.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (paper != null && !paper.getName().equals(face.getName())) {
|
||||||
|
Card c = Card.getCardForUi(paper);
|
||||||
|
boolean foundState = false;
|
||||||
|
for (CardStateName cs : c.getStates()) {
|
||||||
|
if (c.getState(cs).getName().equals(face.getName())) {
|
||||||
|
foundState = true;
|
||||||
|
c.setState(cs, true);
|
||||||
|
matchUI.setCard(c.getView());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!foundState) {
|
||||||
matchUI.setCard(paper);
|
matchUI.setCard(paper);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
matchUI.setCard(paper);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
Name:Vivien's Invocation
|
Name:Vivien's Invocation
|
||||||
ManaCost:5 G G
|
ManaCost:5 G G
|
||||||
Types:Sorcery
|
Types:Sorcery
|
||||||
A:SP$ PeekAndReveal | Cost$ 4 G G | PeekAmount$ 7 | RememberPeeked$ True | SubAbility$ DBChangeZone | OptionalDecider$ You | Look at the top seven cards of your library. You may put a creature card from among them onto the battlefield. Put the rest on the bottom of your library in a random order. When a creature is put onto the battlefield this way, it deals damage equal to its power to target creature an opponent controls.
|
A:SP$ Dig | Cost$ 5 G G | DigNum$ 7 | ChangeNum$ 1 | ChangeValid$ Creature | Optional$ True | RestRandomOrder$ True | DestinationZone$ Battlefield | ForceRevealToController$ True | SpellDescription$ Look at the top seven cards of your library. You may put a creature card from among them onto the battlefield. Put the rest on the bottom of your library in a random order. When a creature is put onto the battlefield this way, it deals damage equals to its power to target creature an opponent controls.
|
||||||
SVar:DBEffect:DB$ Effect | Name$ Vivien's Invocation Effect | Triggers$ EffTModeChangesZone | RememberObjects$ Remembered.Creature | SVars$ EffTrigDealDamage,EffX | Description$ When a creature is put onto the battlefield this way, it deals damage equal to its power to target creature an opponent controls. | SubAbility$ DBChangeZone
|
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature | ValidCause$ Card.Self | Execute$ DBDealDamage | Secondary$ True | TriggerDescription$ When a creature is put onto the battlefield this way, it deals damage equals to its power to target creature an opponent controls.
|
||||||
SVar:DBChangeZone:DB$ ChangeZone | Origin$ Library | NoLooking$ True | Destination$ Battlefield | LimitSearchLibrary$ Creature.IsRemembered | ChangeValid$ Creature.IsRemembered | Controller$ You | WithoutManaCost$ True | Amount$ 1 | SubAbility$ DBRestRandomOrder
|
SVar:DBDealDamage:DB$ DealDamage | ValidTgts$ Creature.OppCtrl | AILogic$ PowerDmg | TgtPrompt$ Select target creature an opponent controls | NumDmg$ X | References$ X | DamageSource$ TriggeredCard
|
||||||
SVar:DBRestRandomOrder:DB$ ChangeZone | Defined$ Remembered | AtRandom$ True | Origin$ Library | Destination$ Library | LibraryPosition$ -1
|
SVar:X:TriggeredCard$CardPower
|
||||||
SVar:EffTModeChangesZone:Mode$ ChangesZone | ValidCard$ Remembered.Creature | TriggerZones$ Stack | Origin$ Library | Destination$ Battlefield | SubAbility$ EffTrigDealDamage | TriggerDescription$ When a creature is put onto the battlefield this way, it deals damage equal to its power to target creature an opponent controls.
|
Oracle:Look at the top seven cards of your library. You may put a creature card from among them onto the battlefield. Put the rest on the bottom of your library in a random order. When a creature is put onto the battlefield this way, it deals damage equals to its power to target creature an opponent controls.
|
||||||
SVar:EffTrigDealDamage:DB$ DealDamage | ValidSource$ Remembered+inZoneBattlefield | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Select target creature an opponent controls | NumDmg$ EffX | References$ EffX
|
|
||||||
SVar:EffX:RememberedCard$CardPower
|
|
||||||
Oracle:Look at the top seven cards of your library. You may put a creature card from among them onto the battlefield. Put the rest on the bottom of your library in a random order. When a creature is put onto the battlefield this way, it deals damage equal to its power to target creature an opponent controls.
|
|
||||||
Reference in New Issue
Block a user