diff --git a/forge-game/src/main/java/forge/game/CardTraitBase.java b/forge-game/src/main/java/forge/game/CardTraitBase.java index 822b185df46..6951c2be1bb 100644 --- a/forge-game/src/main/java/forge/game/CardTraitBase.java +++ b/forge-game/src/main/java/forge/game/CardTraitBase.java @@ -170,8 +170,8 @@ public abstract class CardTraitBase extends GameObject implements IHasCardView { * @return a boolean. */ public static boolean matchesValid(final Object o, final String[] valids, final Card srcCard) { - if (o instanceof GameEntity) { - final GameEntity c = (GameEntity) o; + if (o instanceof GameObject) { + final GameObject c = (GameObject) o; return c.isValid(valids, srcCard.getController(), srcCard, null); } diff --git a/forge-game/src/main/java/forge/game/ForgeScript.java b/forge-game/src/main/java/forge/game/ForgeScript.java index 7ba06ea9a79..8cc37fb3987 100644 --- a/forge-game/src/main/java/forge/game/ForgeScript.java +++ b/forge-game/src/main/java/forge/game/ForgeScript.java @@ -179,6 +179,18 @@ public class ForgeScript { if (!sa.hasParam("Equip")) { return false; } + } else if (property.startsWith("IsTargeting")) { + String k[] = property.split(" ", 2); + boolean found = false; + for (GameObject o : AbilityUtils.getDefinedObjects(source, k[1], spellAbility)) { + if (sa.isTargeting(o)) { + found = true; + break; + } + } + if (!found) { + return false; + } } return true; diff --git a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java index 3361436670b..cb8ae2e50e4 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -1205,7 +1205,7 @@ public class AbilityUtils { final SpellAbility sa) { final FCollection sas = new FCollection(); final String defined = (def == null) ? "Self" : applyAbilityTextChangeEffects(def, sa); // default to Self - final Game game = sa.getActivatingPlayer().getGame(); + final Game game = card.getGame(); SpellAbility s = null; diff --git a/forge-game/src/main/java/forge/game/ability/effects/ChooseGenericEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ChooseGenericEffect.java index 1d52dd622e4..7cb835542b6 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ChooseGenericEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ChooseGenericEffect.java @@ -7,7 +7,6 @@ import forge.game.card.Card; import forge.game.event.GameEventCardModeChosen; import forge.game.player.Player; import forge.game.spellability.SpellAbility; -import forge.game.spellability.TargetRestrictions; import forge.util.MyRandom; import java.util.List; @@ -34,14 +33,16 @@ public class ChooseGenericEffect extends SpellAbilityEffect { final SpellAbility fallback = sa.getAdditionalAbility("FallbackAbility"); final List tgtPlayers = getDefinedPlayersOrTargeted(sa); - final TargetRestrictions tgt = sa.getTargetRestrictions(); for (final Player p : tgtPlayers) { // determine if any of the choices are not valid List saToRemove = Lists.newArrayList(); for (SpellAbility saChoice : abilities) { - if ("Player.IsRemembered".equals(saChoice.getParam("Defined")) && saChoice.hasParam("UnlessCost")) { + if (!saChoice.getRestrictions().checkOtherRestrictions(host, saChoice, sa.getActivatingPlayer()) ) { + saToRemove.add(saChoice); + } else if (saChoice.hasParam("UnlessCost") && + "Player.IsRemembered".equals(saChoice.getParam("Defined"))) { String unlessCost = saChoice.getParam("UnlessCost"); // Sac a permanent in presence of Sigarda, Host of Herons // TODO: generalize this by testing if the unless cost can be paid @@ -55,7 +56,7 @@ public class ChooseGenericEffect extends SpellAbilityEffect { } abilities.removeAll(saToRemove); - if (tgt != null && sa.getTargets().isTargeting(p) && !p.canBeTargetedBy(sa)) { + if (sa.usesTargeting() && sa.getTargets().isTargeting(p) && !p.canBeTargetedBy(sa)) { continue; } diff --git a/forge-game/src/main/java/forge/game/ability/effects/CloneEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CloneEffect.java index d35ec37f7e6..977db72b19d 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/CloneEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/CloneEffect.java @@ -149,7 +149,7 @@ public class CloneEffect extends SpellAbilityEffect { // set the host card for copied spellabilities for (final SpellAbility newSa : tgtCard.getSpellAbilities()) { - newSa.setHostCard(cardToCopy); + newSa.setOriginalHost(cardToCopy); } // restore name if it should be unchanged diff --git a/forge-game/src/main/java/forge/game/ability/effects/RegenerateBaseEffect.java b/forge-game/src/main/java/forge/game/ability/effects/RegenerateBaseEffect.java index 5114885e70f..e84307bb801 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/RegenerateBaseEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/RegenerateBaseEffect.java @@ -22,7 +22,7 @@ public abstract class RegenerateBaseEffect extends SpellAbilityEffect { final Game game = hostCard.getGame(); // create Effect for Regeneration - Card eff = createEffect( + final Card eff = createEffect( hostCard, sa.getActivatingPlayer(), hostCard.getName() + "'s Regeneration", hostCard.getImageKey()); eff.addRemembered(list); diff --git a/forge-game/src/main/java/forge/game/ability/effects/SetStateEffect.java b/forge-game/src/main/java/forge/game/ability/effects/SetStateEffect.java index 4732a185cd9..91695cd6580 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/SetStateEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/SetStateEffect.java @@ -66,7 +66,7 @@ public class SetStateEffect extends SpellAbilityEffect { continue; } - if ("Transform".equals(mode) && tgt.equals(host)) { + if ("Transform".equals(mode) && tgt.equals(host) && sa.hasSVar("StoredTransform")) { // If want to Transform, and host is trying to transform self, skip if not in alignment boolean skip = tgt.getTransformedTimestamp() != Long.parseLong(sa.getSVar("StoredTransform")); // Clear SVar from SA so it doesn't get reused accidentally diff --git a/forge-game/src/main/java/forge/game/ability/effects/TokenEffect.java b/forge-game/src/main/java/forge/game/ability/effects/TokenEffect.java index ee15c6f7b2c..2181ed28ba6 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/TokenEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/TokenEffect.java @@ -18,9 +18,7 @@ package forge.game.ability.effects; import java.util.Arrays; -import java.util.HashSet; import java.util.List; -import java.util.Set; import forge.StaticData; import forge.card.MagicColor; @@ -281,10 +279,10 @@ public class TokenEffect extends SpellAbilityEffect { if (prototype == null) { tokens = tokenInfo.makeTokenWithMultiplier(controller, finalAmount, cause != null); grantHiddenKeywords(tokens); - grantSvars(tokens, root); - grantAbilities(tokens, root); - grantTriggers(tokens, root); - grantStatics(tokens, root); + grantSvars(tokens, sa); + grantAbilities(tokens, sa); + grantTriggers(tokens, sa); + grantStatics(tokens, sa); } else { tokens = TokenInfo.makeTokensFromPrototype(prototype, controller, finalAmount, cause != null); } @@ -352,7 +350,6 @@ public class TokenEffect extends SpellAbilityEffect { } private String determineTokenColor(Card host) { - Set colorSet = new HashSet<>(); final String[] substitutedColors = Arrays.copyOf(this.tokenColors, this.tokenColors.length); for (int i = 0; i < substitutedColors.length; i++) { if (substitutedColors[i].equals("ChosenColor")) { diff --git a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java index a090562c9a2..e0fe3eb7d13 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -2350,11 +2350,12 @@ public class CardFactoryUtil { final String name = StringUtils.join(k); final String trigStr = "Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield " - + " | Execute$ " + name + "Choose | ValidCard$ Card.Self | Secondary$ True" + + " | ValidCard$ Card.Self | Secondary$ True" + " | TriggerDescription$ Fabricate " + n + " (" + inst.getReminderText() + ")"; - final String choose = "DB$ GenericChoice | Choices$ DB" + name + "Counter,DB" + name + "Token | ConditionPresent$ Card.StrictlySelf | SubAbility$ DB" + name + "Token2 | AILogic$ " + name; - final String counter = "DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ " + n + " | SpellDescription$ Put " + final String choose = "DB$ GenericChoice | AILogic$ " + name; + final String counter = "DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ " + n + + " | IsPresent$ Card.StrictlySelf | SpellDescription$ Put " + Lang.nounWithNumeral(n, "+1/+1 counter") + " on it."; final String token = "DB$ Token | TokenAmount$ " + n + " | TokenName$ Servo | TokenTypes$ Artifact,Creature,Servo" + " | TokenOwner$ You | TokenColors$ Colorless | TokenPower$ 1 | TokenToughness$ 1" @@ -2363,10 +2364,15 @@ public class CardFactoryUtil { final Trigger trigger = TriggerHandler.parseTrigger(trigStr, card, intrinsic); - card.setSVar(name + "Choose", choose); - card.setSVar("DB" + name + "Counter", counter); - card.setSVar("DB" + name + "Token", token); - card.setSVar("DB" + name + "Token2", token + " | ConditionPresent$ Card.StrictlySelf | ConditionCompare$ EQ0"); + SpellAbility saChoose = AbilityFactory.getAbility(choose, card); + + List list = Lists.newArrayList(); + list.add((AbilitySub)AbilityFactory.getAbility(counter, card)); + list.add((AbilitySub)AbilityFactory.getAbility(token, card)); + saChoose.setAdditionalAbilityList("Choices", list); + saChoose.setIntrinsic(intrinsic); + + trigger.setOverridingAbility(saChoose); inst.addTrigger(trigger); } else if (keyword.startsWith("Fading")) { @@ -3367,6 +3373,8 @@ public class CardFactoryUtil { // extra part for the Damage Prevention keywords if (keyword.startsWith("Prevent all ")) { + // TODO add intrinsic warning + boolean isCombat = false; boolean from = false; boolean to = false; diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java index 4416815c7a7..a8a1e2b3cfd 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java @@ -816,6 +816,10 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit if (manaPart != null) { clone.manaPart = new AbilityManaPart(host, mapParams); } + + // clear maps for copy, the values will be added later + clone.additionalAbilities = Maps.newHashMap(); + clone.additionalAbilityLists = Maps.newHashMap(); // run special copy Ability to make a deep copy CardFactory.copySpellAbility(this, clone, host, lki); } catch (final CloneNotSupportedException e) { @@ -1486,24 +1490,33 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit return topSA.getHostCard().isValid(tgt.getValidTgts(), getActivatingPlayer(), getHostCard(), this); } + public boolean isTargeting(GameObject o) { + if (getTargets().isTargeting(o)) { + return true; + } + SpellAbility p = getParent(); + return p != null && p.isTargeting(o); + } + // Takes one argument like Permanent.Blue+withFlying @Override public final boolean isValid(final String restriction, final Player sourceController, final Card source, SpellAbility spellAbility) { // Inclusive restrictions are Card types final String[] incR = restriction.split("\\.", 2); + SpellAbility root = getRootAbility(); if (incR[0].equals("Spell")) { - if (!isSpell()) { + if (!root.isSpell()) { return false; } } else if (incR[0].equals("Triggered")) { - if (!isTrigger()) { + if (!root.isTrigger()) { return false; } } else if (incR[0].equals("Activated")) { - if (!(this instanceof AbilityActivated)) { + if (!(root instanceof AbilityActivated)) { return false; } } diff --git a/forge-gui-desktop/src/main/java/forge/view/SimulateMatch.java b/forge-gui-desktop/src/main/java/forge/view/SimulateMatch.java index 5b901753a8f..586e7c0231f 100644 --- a/forge-gui-desktop/src/main/java/forge/view/SimulateMatch.java +++ b/forge-gui-desktop/src/main/java/forge/view/SimulateMatch.java @@ -160,7 +160,7 @@ public class SimulateMatch { - private static void simulateSingleMatch(Match mc, int iGame, boolean outputGamelog) { + private static void simulateSingleMatch(final Match mc, int iGame, boolean outputGamelog) { final StopWatch sw = new StopWatch(); sw.start(); diff --git a/forge-gui/res/cardsfolder/t/treasure_map_treasure_cove.txt b/forge-gui/res/cardsfolder/t/treasure_map_treasure_cove.txt index 99f4383977e..f4193ed8f05 100644 --- a/forge-gui/res/cardsfolder/t/treasure_map_treasure_cove.txt +++ b/forge-gui/res/cardsfolder/t/treasure_map_treasure_cove.txt @@ -2,16 +2,13 @@ Name:Treasure Map ManaCost:2 Types:Artifact A:AB$ Scry | Cost$ 1 T | ScryNum$ 1 | SubAbility$ DBLandmark | SpellDescription$ Scry 1. Put a landmark counter on CARDNAME. Then if there are three or more landmark counters on it, remove those counters, transform CARDNAME, and create three colorless Treasure artifact tokens with "{T}, Sacrifice this artifact: Add one mana of any color to your mana pool." -SVar:DBLandmark:DB$ PutCounter | Defined$ Self | CounterType$ LANDMARK | CounterNum$ 1 | SubAbility$ DBStoreSVar -SVar:DBStoreSVar:DB$ StoreSVar | SVar$ FoundTreasure | Type$ Number | Expression$ 1 | ConditionCheckSVar$ XMarksTheSpot | ConditionSVarCompare$ GE1 | References$ XMarksTheSpot,FoundTreasure | SubAbility$ DBRemoveCtrs -SVar:DBRemoveCtrs:DB$ RemoveCounter | Defined$ Self | CounterType$ LANDMARK | CounterNum$ 3 | ConditionCheckSVar$ FoundTreasure | ConditionSVarCompare$ GE1 | References$ FoundTreasure | SubAbility$ DBTreasureTokens -SVar:DBTreasureTokens:DB$ Token | TokenAmount$ 3 | TokenName$ Treasure | TokenTypes$ Artifact,Treasure | TokenOwner$ You | TokenColors$ Colorless | TokenImage$ c treasure | TokenAbilities$ ABTreasureMana | TokenAltImages$ c_treasure2,c_treasure3,c_treasure4 | ConditionCheckSVar$ FoundTreasure | ConditionSVarCompare$ GE1 | SubAbility$ DBTransform | References$ FoundTreasure -SVar:DBTransform:DB$ SetState | Defined$ Self | Mode$ Transform | ConditionCheckSVar$ FoundTreasure | ConditionSVarCompare$ GE1 | References$ FoundTreasure +SVar:DBLandmark:DB$ PutCounter | Defined$ Self | CounterType$ LANDMARK | CounterNum$ 1 | SubAbility$ DBBranch +SVar:DBBranch:DB$ Branch | BranchConditionSVar$ XMarksTheSpot | References$ XMarksTheSpot | TrueSubAbility$ DBRemoveCtrs +SVar:DBRemoveCtrs:DB$ RemoveCounter | Defined$ Self | CounterType$ LANDMARK | CounterNum$ All | SubAbility$ DBTransform +SVar:DBTransform:DB$ SetState | Defined$ Self | Mode$ Transform | SubAbility$ DBTreasureTokens +SVar:DBTreasureTokens:DB$ Token | TokenAmount$ 3 | TokenName$ Treasure | TokenTypes$ Artifact,Treasure | TokenOwner$ You | TokenColors$ Colorless | TokenImage$ c treasure | TokenAbilities$ ABTreasureMana | TokenAltImages$ c_treasure2,c_treasure3,c_treasure4 | References$ ABTreasureMana SVar:ABTreasureMana:AB$ Mana | Cost$ T Sac<1/CARDNAME> | Produced$ Any | Amount$ 1 | SpellDescription$ Add one mana of any color to your mana pool. SVar:XMarksTheSpot:Count$Valid Card.Self+counters_GE3_LANDMARK -T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | Execute$ DBInitSVar | Static$ True -SVar:DBInitSVar:DB$ StoreSVar | SVar$ FoundTreasure | Type$ Number | Expression$ 0 | References$ FoundTreasure -SVar:FoundTreasure:Number$0 AlternateMode:DoubleFaced DeckHas:Ability$Token SVar:Picture:http://www.wizards.com/global/images/magic/general/treasure_map.jpg diff --git a/forge-gui/src/main/java/forge/deck/CommanderDeckGenerator.java b/forge-gui/src/main/java/forge/deck/CommanderDeckGenerator.java index 52af7d5b7d2..fc08fb0d616 100644 --- a/forge-gui/src/main/java/forge/deck/CommanderDeckGenerator.java +++ b/forge-gui/src/main/java/forge/deck/CommanderDeckGenerator.java @@ -22,7 +22,7 @@ import java.util.Map; * Created by maustin on 09/05/2017. */ public class CommanderDeckGenerator extends DeckProxy implements Comparable { - public static List getCommanderDecks(DeckFormat format, boolean isForAi, boolean isCardGen){ + public static List getCommanderDecks(final DeckFormat format, boolean isForAi, boolean isCardGen){ ItemPool uniqueCards; if(isCardGen){ uniqueCards = new ItemPool(PaperCard.class);