mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-16 10:48:00 +00:00
Merge branch 'master' of git.cardforge.org:core-developers/forge into remove_some_build_warnings
# Conflicts: # forge-gui-mobile/src/forge/assets/FSkin.java
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>1.6.30-SNAPSHOT</version>
|
||||
<version>1.6.31-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-ai</artifactId>
|
||||
|
||||
@@ -1281,7 +1281,8 @@ public class AiBlockController {
|
||||
oppCreatureCount = ComputerUtil.countUsefulCreatures(attackersLeft.get(0).getController());
|
||||
}
|
||||
|
||||
if (attacker.getOwner().equals(ai) && "6".equals(attacker.getSVar("SacMe"))) {
|
||||
if (attacker != null && attacker.getOwner() != null)
|
||||
if (attacker.getOwner().equals(ai) && "6".equals(attacker.getSVar("SacMe"))) {
|
||||
// Temporarily controlled object - don't trade with it
|
||||
// TODO: find a more reliable way to figure out that control will be reestablished next turn
|
||||
return false;
|
||||
|
||||
@@ -59,6 +59,7 @@ import forge.item.PaperCard;
|
||||
import forge.util.Aggregates;
|
||||
import forge.util.Expressions;
|
||||
import forge.util.MyRandom;
|
||||
import forge.util.ComparatorUtil;
|
||||
import forge.util.collect.FCollectionView;
|
||||
import io.sentry.Sentry;
|
||||
import io.sentry.event.BreadcrumbBuilder;
|
||||
@@ -609,7 +610,15 @@ public class AiController {
|
||||
ComputerUtilAbility.getAvailableCards(game, player);
|
||||
|
||||
List<SpellAbility> all = ComputerUtilAbility.getSpellAbilities(cards, player);
|
||||
Collections.sort(all, saComparator); // put best spells first
|
||||
|
||||
try {
|
||||
Collections.sort(all, saComparator); // put best spells first
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
System.err.println(ex.getMessage());
|
||||
String assertex = ComparatorUtil.verifyTransitivity(saComparator, all);
|
||||
Sentry.capture(ex.getMessage() + "\nAssertionError [verifyTransitivity]: " + assertex);
|
||||
}
|
||||
|
||||
for (final SpellAbility sa : ComputerUtilAbility.getOriginalAndAltCostAbilities(all, player)) {
|
||||
ApiType saApi = sa.getApi();
|
||||
@@ -1572,8 +1581,15 @@ public class AiController {
|
||||
if (all == null || all.isEmpty())
|
||||
return null;
|
||||
|
||||
Collections.sort(all, saComparator); // put best spells first
|
||||
|
||||
try {
|
||||
Collections.sort(all, saComparator); // put best spells first
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
System.err.println(ex.getMessage());
|
||||
String assertex = ComparatorUtil.verifyTransitivity(saComparator, all);
|
||||
Sentry.capture(ex.getMessage() + "\nAssertionError [verifyTransitivity]: " + assertex);
|
||||
}
|
||||
|
||||
for (final SpellAbility sa : ComputerUtilAbility.getOriginalAndAltCostAbilities(all, player)) {
|
||||
// Don't add Counterspells to the "normal" playcard lookups
|
||||
if (skipCounter && sa.getApi() == ApiType.Counter) {
|
||||
@@ -1830,7 +1846,7 @@ public class AiController {
|
||||
// Special case for Bow to My Command which simulates a complex tap cost via ChooseCard
|
||||
// TODO: consider enhancing support for tapXType<Any/...> in UnlessCost to get rid of this hack
|
||||
if ("BowToMyCommand".equals(sa.getParam("AILogic"))) {
|
||||
if (!sa.getHostCard().getZone().is(ZoneType.Command)) {
|
||||
if (!sa.getHostCard().isInZone(ZoneType.Command)) {
|
||||
// Make sure that other opponents do not tap for an already abandoned scheme
|
||||
result.clear();
|
||||
break;
|
||||
@@ -2079,8 +2095,7 @@ public class AiController {
|
||||
return true;
|
||||
}
|
||||
|
||||
public ReplacementEffect chooseSingleReplacementEffect(List<ReplacementEffect> list,
|
||||
Map<String, Object> runParams) {
|
||||
public ReplacementEffect chooseSingleReplacementEffect(List<ReplacementEffect> list) {
|
||||
// no need to choose anything
|
||||
if (list.size() <= 1) {
|
||||
return Iterables.getFirst(list, null);
|
||||
|
||||
@@ -29,6 +29,7 @@ import forge.card.MagicColor;
|
||||
import forge.card.mana.ManaCostShard;
|
||||
import forge.game.*;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.ability.effects.CharmEffect;
|
||||
@@ -2402,7 +2403,7 @@ public class ComputerUtil {
|
||||
}
|
||||
// if source is not on the battlefield anymore, choose +1/+1
|
||||
// ones
|
||||
if (!game.getCardState(source).getZone().is(ZoneType.Battlefield)) {
|
||||
if (!game.getCardState(source).isInZone(ZoneType.Battlefield)) {
|
||||
return opponent ? "Feather" : "Quill";
|
||||
}
|
||||
// if no hand cards, try to mill opponent
|
||||
@@ -2434,7 +2435,7 @@ public class ComputerUtil {
|
||||
}
|
||||
|
||||
// if source is not on the battlefield anymore
|
||||
if (!game.getCardState(source).getZone().is(ZoneType.Battlefield)) {
|
||||
if (!game.getCardState(source).isInZone(ZoneType.Battlefield)) {
|
||||
return opponent ? "Strength" : "Numbers";
|
||||
}
|
||||
|
||||
@@ -2483,7 +2484,7 @@ public class ComputerUtil {
|
||||
}
|
||||
|
||||
// if source is not on the battlefield anymore
|
||||
if (!game.getCardState(source).getZone().is(ZoneType.Battlefield)) {
|
||||
if (!game.getCardState(source).isInZone(ZoneType.Battlefield)) {
|
||||
return opponent ? "Sprout" : "Harvest";
|
||||
}
|
||||
// TODO add Lifegain to +1/+1 counters trigger
|
||||
@@ -2849,10 +2850,9 @@ public class ComputerUtil {
|
||||
}
|
||||
|
||||
// Run any applicable replacement effects.
|
||||
final Map<String, Object> repParams = Maps.newHashMap();
|
||||
repParams.put("Affected", player);
|
||||
repParams.put("LifeGained", 1);
|
||||
repParams.put("Source", source);
|
||||
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(player);
|
||||
repParams.put(AbilityKey.LifeGained, 1);
|
||||
repParams.put(AbilityKey.Source, source);
|
||||
|
||||
List<ReplacementEffect> list = player.getGame().getReplacementHandler().getReplacementList(
|
||||
ReplacementType.GainLife,
|
||||
@@ -2880,15 +2880,15 @@ public class ComputerUtil {
|
||||
}
|
||||
|
||||
// Run any applicable replacement effects.
|
||||
final Map<String, Object> repParams = Maps.newHashMap();
|
||||
repParams.put("Affected", player);
|
||||
repParams.put("LifeGained", n);
|
||||
repParams.put("Source", source);
|
||||
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(player);
|
||||
repParams.put(AbilityKey.LifeGained, n);
|
||||
repParams.put(AbilityKey.Source, source);
|
||||
|
||||
List<ReplacementEffect> list = player.getGame().getReplacementHandler().getReplacementList(
|
||||
ReplacementType.GainLife,
|
||||
repParams,
|
||||
ReplacementLayer.Other);
|
||||
ReplacementType.GainLife,
|
||||
repParams,
|
||||
ReplacementLayer.Other
|
||||
);
|
||||
|
||||
if (Iterables.any(list, CardTraitPredicates.hasParam("AiLogic", "NoLife"))) {
|
||||
// no life gain is not negative
|
||||
|
||||
@@ -1294,7 +1294,7 @@ public class ComputerUtilCard {
|
||||
// cast it during Declare Blockers, thus ruining its attacker
|
||||
if (holdCombatTricks && sa.getApi() == ApiType.Pump
|
||||
&& sa.hasParam("NumAtt") && sa.getHostCard() != null
|
||||
&& sa.getHostCard().getZone() != null && sa.getHostCard().getZone().is(ZoneType.Hand)
|
||||
&& sa.getHostCard().isInZone(ZoneType.Hand)
|
||||
&& c.getNetPower() > 0 // too obvious if attacking with a 0-power creature
|
||||
&& sa.getHostCard().isInstant() // only do it for instant speed spells in hand
|
||||
&& ComputerUtilMana.hasEnoughManaSourcesToCast(sa, ai)) {
|
||||
|
||||
@@ -29,6 +29,7 @@ import forge.game.CardTraitBase;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.card.*;
|
||||
@@ -2580,13 +2581,11 @@ public class ComputerUtilCombat {
|
||||
final Game game = attacker.getGame();
|
||||
|
||||
// first try to replace the damage
|
||||
final Map<String, Object> repParams = Maps.newHashMap();
|
||||
repParams.put("Affected", target);
|
||||
repParams.put("DamageSource", attacker);
|
||||
repParams.put("DamageAmount", damage);
|
||||
repParams.put("IsCombat", true);
|
||||
repParams.put("Prevention", true);
|
||||
// repParams.put("PreventMap", preventMap);
|
||||
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(target);
|
||||
repParams.put(AbilityKey.DamageSource, attacker);
|
||||
repParams.put(AbilityKey.DamageAmount, damage);
|
||||
repParams.put(AbilityKey.IsCombat, true);
|
||||
repParams.put(AbilityKey.Prevention, true);
|
||||
|
||||
List<ReplacementEffect> list = game.getReplacementHandler().getReplacementList(
|
||||
ReplacementType.DamageDone, repParams, ReplacementLayer.Other);
|
||||
|
||||
@@ -13,6 +13,7 @@ import forge.card.mana.ManaCostParser;
|
||||
import forge.card.mana.ManaCostShard;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameActionUtil;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.card.*;
|
||||
@@ -1408,11 +1409,11 @@ public class ComputerUtilMana {
|
||||
AbilityManaPart mp = m.getManaPart();
|
||||
|
||||
// setup produce mana replacement effects
|
||||
final Map<String, Object> repParams = new HashMap<>();
|
||||
repParams.put("Mana", mp.getOrigProduced());
|
||||
repParams.put("Affected", sourceCard);
|
||||
repParams.put("Player", ai);
|
||||
repParams.put("AbilityMana", m);
|
||||
final Map<AbilityKey, Object> repParams = AbilityKey.newMap();
|
||||
repParams.put(AbilityKey.Mana, mp.getOrigProduced());
|
||||
repParams.put(AbilityKey.Affected, sourceCard);
|
||||
repParams.put(AbilityKey.Player, ai);
|
||||
repParams.put(AbilityKey.AbilityMana, m);
|
||||
|
||||
for (final ReplacementEffect replacementEffect : replacementEffects) {
|
||||
if (replacementEffect.canReplace(repParams)) {
|
||||
|
||||
@@ -11,10 +11,7 @@ import forge.game.Game;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.effects.DetachedCardEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardCollectionView;
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.card.*;
|
||||
import forge.game.card.token.TokenInfo;
|
||||
import forge.game.combat.Combat;
|
||||
import forge.game.combat.CombatUtil;
|
||||
@@ -24,6 +21,7 @@ import forge.game.mana.ManaPool;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.AbilityManaPart;
|
||||
import forge.game.spellability.AbilitySub;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.trigger.TriggerType;
|
||||
@@ -362,6 +360,12 @@ public abstract class GameState {
|
||||
if (c.isFaceDown()) {
|
||||
newText.append("|FaceDown"); // Exiled face down
|
||||
}
|
||||
if (c.isAdventureCard() && c.getZone().is(ZoneType.Exile)) {
|
||||
// TODO: this will basically default all exiled cards with Adventure to being "On Adventure".
|
||||
// Need to figure out a better way to detect if it's actually on adventure.
|
||||
newText.append("|OnAdventure");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (zoneType == ZoneType.Battlefield || zoneType == ZoneType.Exile) {
|
||||
@@ -1202,6 +1206,16 @@ public abstract class GameState {
|
||||
c.setState(CardStateName.Flipped, true);
|
||||
} else if (info.startsWith("Meld")) {
|
||||
c.setState(CardStateName.Meld, true);
|
||||
} else if (info.startsWith("OnAdventure")) {
|
||||
String abAdventure = "DB$ Effect | RememberObjects$ Self | StaticAbilities$ Play | ExileOnMoved$ Exile | Duration$ Permanent | ConditionDefined$ Self | ConditionPresent$ Card.nonCopiedSpell";
|
||||
AbilitySub saAdventure = (AbilitySub)AbilityFactory.getAbility(abAdventure, c);
|
||||
StringBuilder sbPlay = new StringBuilder();
|
||||
sbPlay.append("Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered+nonAdventure");
|
||||
sbPlay.append(" | AffectedZone$ Exile | Description$ You may cast the card.");
|
||||
saAdventure.setSVar("Play", sbPlay.toString());
|
||||
saAdventure.setActivatingPlayer(c.getOwner());
|
||||
saAdventure.resolve();
|
||||
c.setExiledWith(c); // This seems to be the way it's set up internally. Potentially not needed here?
|
||||
} else if (info.startsWith("IsCommander")) {
|
||||
// TODO: This doesn't seem to properly restore the ability to play the commander. Why?
|
||||
c.setCommander(true);
|
||||
|
||||
@@ -729,7 +729,7 @@ public class PlayerControllerAi extends PlayerController {
|
||||
return true;
|
||||
} else {
|
||||
Card rem = (Card) source.getFirstRemembered();
|
||||
if (!rem.getZone().is(ZoneType.Battlefield)) {
|
||||
if (!rem.isInZone(ZoneType.Battlefield)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -737,7 +737,7 @@ public class PlayerControllerAi extends PlayerController {
|
||||
case "BetterTgtThanRemembered":
|
||||
if (source.getRememberedCount() > 0) {
|
||||
Card rem = (Card) source.getFirstRemembered();
|
||||
if (!rem.getZone().is(ZoneType.Battlefield)) {
|
||||
if (!rem.isInZone(ZoneType.Battlefield)) {
|
||||
return true;
|
||||
}
|
||||
for (Card c : source.getController().getCreaturesInPlay()) {
|
||||
@@ -866,8 +866,8 @@ public class PlayerControllerAi extends PlayerController {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReplacementEffect chooseSingleReplacementEffect(String prompt, List<ReplacementEffect> possibleReplacers, Map<String, Object> runParams) {
|
||||
return brains.chooseSingleReplacementEffect(possibleReplacers, runParams);
|
||||
public ReplacementEffect chooseSingleReplacementEffect(String prompt, List<ReplacementEffect> possibleReplacers) {
|
||||
return brains.chooseSingleReplacementEffect(possibleReplacers);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -10,6 +10,7 @@ import forge.card.MagicColor;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameObject;
|
||||
import forge.game.GlobalRuleChange;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.card.*;
|
||||
@@ -1789,8 +1790,8 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
}
|
||||
|
||||
public boolean doReturnCommanderLogic(SpellAbility sa, Player aiPlayer) {
|
||||
Map<String, Object> originalParams = (Map<String, Object>)sa.getReplacingObject("OriginalParams");
|
||||
SpellAbility causeSa = (SpellAbility)originalParams.get("Cause");
|
||||
Map<AbilityKey, Object> originalParams = (Map<AbilityKey, Object>)sa.getReplacingObject(AbilityKey.OriginalParams);
|
||||
SpellAbility causeSa = (SpellAbility)originalParams.get(AbilityKey.Cause);
|
||||
SpellAbility causeSub = null;
|
||||
|
||||
// Squee, the Immortal: easier to recast it (the call below has to be "contains" since SA is an intrinsic effect)
|
||||
@@ -1813,7 +1814,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
||||
// A blink effect implemented using a delayed trigger
|
||||
return !"Exile".equals(exec.getParam("Origin")) || !"Battlefield".equals(exec.getParam("Destination"));
|
||||
}
|
||||
} else return causeSa.getHostCard() == null || !causeSa.getHostCard().equals(sa.getReplacingObject("Card"))
|
||||
} else return causeSa.getHostCard() == null || !causeSa.getHostCard().equals(sa.getReplacingObject(AbilityKey.Card))
|
||||
|| !causeSa.getActivatingPlayer().equals(aiPlayer);
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ public class DamageDealAi extends DamageAiBase {
|
||||
// Set PayX here to maximum value.
|
||||
dmg = ComputerUtilMana.determineLeftoverMana(sa, ai);
|
||||
source.setSVar("PayX", Integer.toString(dmg));
|
||||
} else if (sa.getSVar(damage).equals("Count$CardsInYourHand") && source.getZone().is(ZoneType.Hand)) {
|
||||
} else if (sa.getSVar(damage).equals("Count$CardsInYourHand") && source.isInZone(ZoneType.Hand)) {
|
||||
dmg--; // the card will be spent casting the spell, so actual damage is 1 less
|
||||
}
|
||||
}
|
||||
@@ -113,7 +113,7 @@ public class DamageDealAi extends DamageAiBase {
|
||||
|
||||
// Set PayX here to maximum value. It will be adjusted later depending on the target.
|
||||
source.setSVar("PayX", Integer.toString(dmg));
|
||||
} else if (sa.getSVar(damage).contains("InYourHand") && source.getZone().is(ZoneType.Hand)) {
|
||||
} else if (sa.getSVar(damage).contains("InYourHand") && source.isInZone(ZoneType.Hand)) {
|
||||
dmg = CardFactoryUtil.xCount(source, sa.getSVar(damage)) - 1; // the card will be spent casting the spell, so actual damage is 1 less
|
||||
} else if (sa.getSVar(damage).equals("TargetedPlayer$CardsInHand")) {
|
||||
// cards that deal damage by the number of cards in target player's hand, e.g. Sudden Impact
|
||||
|
||||
@@ -409,7 +409,7 @@ public class DrawAi extends SpellAbilityAi {
|
||||
if (computerHandSize + numCards > computerMaxHandSize && game.getPhaseHandler().isPlayerTurn(ai)) {
|
||||
if (xPaid) {
|
||||
numCards = computerMaxHandSize - computerHandSize;
|
||||
if (sa.getHostCard().getZone().is(ZoneType.Hand)) {
|
||||
if (sa.getHostCard().isInZone(ZoneType.Hand)) {
|
||||
numCards++; // the card will be spent
|
||||
}
|
||||
source.setSVar("PayX", Integer.toString(numCards));
|
||||
|
||||
@@ -45,6 +45,8 @@ public class FightAi extends SpellAbilityAi {
|
||||
aiCreatures = ComputerUtil.getSafeTargets(ai, sa, aiCreatures);
|
||||
List<Card> humCreatures = ai.getOpponents().getCreaturesInPlay();
|
||||
humCreatures = CardLists.getTargetableCards(humCreatures, sa);
|
||||
if (humCreatures.isEmpty())
|
||||
return false; //prevent IndexOutOfBoundsException on MOJHOSTO variant
|
||||
|
||||
// assumes the triggered card belongs to the ai
|
||||
if (sa.hasParam("Defined")) {
|
||||
|
||||
@@ -2,12 +2,12 @@ package forge.ai.ability;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Maps;
|
||||
import forge.ai.ComputerUtil;
|
||||
import forge.ai.ComputerUtilCard;
|
||||
import forge.ai.ComputerUtilMana;
|
||||
import forge.ai.SpellAbilityAi;
|
||||
import forge.game.Game;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardCollectionView;
|
||||
@@ -97,11 +97,10 @@ public class ManifestAi extends SpellAbilityAi {
|
||||
topCopy.turnFaceDownNoUpdate();
|
||||
topCopy.setManifested(true);
|
||||
|
||||
final Map<String, Object> repParams = Maps.newHashMap();
|
||||
repParams.put("Affected", topCopy);
|
||||
repParams.put("Origin", card.getZone().getZoneType());
|
||||
repParams.put("Destination", ZoneType.Battlefield);
|
||||
repParams.put("Source", sa.getHostCard());
|
||||
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(topCopy);
|
||||
repParams.put(AbilityKey.Origin, card.getZone().getZoneType());
|
||||
repParams.put(AbilityKey.Destination, ZoneType.Battlefield);
|
||||
repParams.put(AbilityKey.Source, sa.getHostCard());
|
||||
List<ReplacementEffect> list = game.getReplacementHandler().getReplacementList(ReplacementType.Moved, repParams, ReplacementLayer.Other);
|
||||
if (!list.isEmpty()) {
|
||||
return false;
|
||||
|
||||
@@ -309,7 +309,7 @@ public class PumpAi extends PumpAiBase {
|
||||
}
|
||||
} else {
|
||||
defense = AbilityUtils.calculateAmount(sa.getHostCard(), numDefense, sa);
|
||||
if (numDefense.contains("X") && sa.getSVar("X").equals("Count$CardsInYourHand") && source.getZone().is(ZoneType.Hand)) {
|
||||
if (numDefense.contains("X") && sa.getSVar("X").equals("Count$CardsInYourHand") && source.isInZone(ZoneType.Hand)) {
|
||||
defense--; // the card will be spent casting the spell, so actual toughness is 1 less
|
||||
}
|
||||
}
|
||||
@@ -328,7 +328,7 @@ public class PumpAi extends PumpAiBase {
|
||||
}
|
||||
} else {
|
||||
attack = AbilityUtils.calculateAmount(sa.getHostCard(), numAttack, sa);
|
||||
if (numAttack.contains("X") && sa.getSVar("X").equals("Count$CardsInYourHand") && source.getZone().is(ZoneType.Hand)) {
|
||||
if (numAttack.contains("X") && sa.getSVar("X").equals("Count$CardsInYourHand") && source.isInZone(ZoneType.Hand)) {
|
||||
attack--; // the card will be spent casting the spell, so actual power is 1 less
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ public class SacrificeAi extends SpellAbilityAi {
|
||||
final boolean destroy = sa.hasParam("Destroy");
|
||||
|
||||
Player opp = ai.getWeakestOpponent();
|
||||
|
||||
if (tgt != null) {
|
||||
sa.resetTargets();
|
||||
if (!opp.canBeTargetedBy(sa)) {
|
||||
@@ -74,8 +75,16 @@ public class SacrificeAi extends SpellAbilityAi {
|
||||
num = (num == null) ? "1" : num;
|
||||
final int amount = AbilityUtils.calculateAmount(sa.getHostCard(), num, sa);
|
||||
|
||||
List<Card> list =
|
||||
CardLists.getValidCards(opp.getCardsIn(ZoneType.Battlefield), valid.split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa);
|
||||
List<Card> list = null;
|
||||
try {
|
||||
list = CardLists.getValidCards(opp.getCardsIn(ZoneType.Battlefield), valid.split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa);
|
||||
} catch (NullPointerException e) {
|
||||
return false;
|
||||
} finally {
|
||||
if (list == null)
|
||||
return false;
|
||||
}//prevent NPE on MoJhoSto
|
||||
|
||||
for (Card c : list) {
|
||||
if (c.hasSVar("SacMe") && Integer.parseInt(c.getSVar("SacMe")) > 3) {
|
||||
return false;
|
||||
@@ -131,15 +140,31 @@ public class SacrificeAi extends SpellAbilityAi {
|
||||
amount = Math.min(ComputerUtilMana.determineLeftoverMana(sa, ai), amount);
|
||||
}
|
||||
|
||||
List<Card> humanList =
|
||||
CardLists.getValidCards(opp.getCardsIn(ZoneType.Battlefield), valid.split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa);
|
||||
List<Card> humanList = null;
|
||||
try {
|
||||
humanList = CardLists.getValidCards(opp.getCardsIn(ZoneType.Battlefield), valid.split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa);
|
||||
} catch (NullPointerException e) {
|
||||
return false;
|
||||
} finally {
|
||||
if (humanList == null)
|
||||
return false;
|
||||
}//prevent NPE on MoJhoSto
|
||||
|
||||
// Since all of the cards have AI:RemoveDeck:All, I enabled 1 for 1
|
||||
// (or X for X) trades for special decks
|
||||
return humanList.size() >= amount;
|
||||
} else if (defined.equals("You")) {
|
||||
List<Card> computerList =
|
||||
CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), valid.split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa);
|
||||
|
||||
List<Card> computerList = null;
|
||||
try {
|
||||
computerList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), valid.split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa);
|
||||
} catch (NullPointerException e) {
|
||||
return false;
|
||||
} finally {
|
||||
if (computerList == null)
|
||||
return false;
|
||||
}//prevent NPE on MoJhoSto
|
||||
|
||||
for (Card c : computerList) {
|
||||
if (c.hasSVar("SacMe") || ComputerUtilCard.evaluateCreature(c) <= 135) {
|
||||
return true;
|
||||
|
||||
@@ -148,7 +148,7 @@ public class SetStateAi extends SpellAbilityAi {
|
||||
if (card.isFaceDown()) {
|
||||
// hidden agenda
|
||||
if (card.getState(CardStateName.Original).hasIntrinsicKeyword("Hidden agenda")
|
||||
&& card.getZone().is(ZoneType.Command)) {
|
||||
&& card.isInZone(ZoneType.Command)) {
|
||||
String chosenName = card.getNamedCard();
|
||||
for (Card cast : ai.getGame().getStack().getSpellsCastThisTurn()) {
|
||||
if (cast.getController() == ai && cast.getName().equals(chosenName)) {
|
||||
|
||||
@@ -228,7 +228,7 @@ public class GameCopier {
|
||||
CardFactory.copyCopiableCharacteristics(c, result);
|
||||
return result;
|
||||
}
|
||||
if (USE_FROM_PAPER_CARD && !c.isEmblem()) {
|
||||
if (USE_FROM_PAPER_CARD && !c.isEmblem() && c.getPaperCard() != null) {
|
||||
Card newCard = Card.fromPaperCard(c.getPaperCard(), newOwner);
|
||||
newCard.setCommander(c.isCommander());
|
||||
return newCard;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>1.6.30-SNAPSHOT</version>
|
||||
<version>1.6.31-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-core</artifactId>
|
||||
@@ -21,7 +21,7 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.7</version>
|
||||
<version>3.8.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -111,7 +111,18 @@ public final class ImageKeys {
|
||||
file = findFile(dir, TextUtil.fastReplace(filename, "AE", "Ae"));
|
||||
if (file != null) { return file; }
|
||||
}
|
||||
|
||||
//try fullborder...
|
||||
if (filename.contains(".full")) {
|
||||
file = findFile(dir, TextUtil.fastReplace(filename, ".full", ".fullborder"));
|
||||
if (file != null) { return file; }
|
||||
}
|
||||
//if an image, like phenomenon or planes is missing .full in their filenames but you have an existing images that have .full/.fullborder
|
||||
if (!filename.contains(".full")) {
|
||||
file = findFile(dir, TextUtil.addSuffix(filename,".full"));
|
||||
if (file != null) { return file; }
|
||||
file = findFile(dir, TextUtil.addSuffix(filename,".fullborder"));
|
||||
if (file != null) { return file; }
|
||||
}
|
||||
// some S00 cards are really part of 6ED
|
||||
String s2kAlias = getSetFolder("S00");
|
||||
if (filename.startsWith(s2kAlias)) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.apache.commons.lang3.StringUtils;
|
||||
public abstract class LobbyPlayer {
|
||||
protected String name;
|
||||
private int avatarIndex = -1;
|
||||
private int sleeveIndex = -1;
|
||||
private String avatarCardImageKey;
|
||||
|
||||
public LobbyPlayer(String name) {
|
||||
@@ -59,9 +60,15 @@ public abstract class LobbyPlayer {
|
||||
public int getAvatarIndex() {
|
||||
return avatarIndex;
|
||||
}
|
||||
public int getSleeveIndex() {
|
||||
return sleeveIndex;
|
||||
}
|
||||
public void setAvatarIndex(int avatarIndex) {
|
||||
this.avatarIndex = avatarIndex;
|
||||
}
|
||||
public void setSleeveIndex(int sleeveIndex) {
|
||||
this.sleeveIndex = sleeveIndex;
|
||||
}
|
||||
|
||||
public String getAvatarCardImageKey() {
|
||||
return avatarCardImageKey;
|
||||
|
||||
@@ -35,6 +35,7 @@ public class StaticData {
|
||||
|
||||
private Predicate<PaperCard> standardPredicate;
|
||||
private Predicate<PaperCard> brawlPredicate;
|
||||
private Predicate<PaperCard> pioneerPredicate;
|
||||
private Predicate<PaperCard> modernPredicate;
|
||||
private Predicate<PaperCard> commanderPredicate;
|
||||
private Predicate<PaperCard> oathbreakerPredicate;
|
||||
@@ -197,13 +198,13 @@ public class StaticData {
|
||||
|
||||
public TokenDb getAllTokens() { return allTokens; }
|
||||
|
||||
public Predicate<PaperCard> getStandardPredicate() {
|
||||
return standardPredicate;
|
||||
}
|
||||
|
||||
|
||||
public void setStandardPredicate(Predicate<PaperCard> standardPredicate) { this.standardPredicate = standardPredicate; }
|
||||
|
||||
public void setModernPredicate(Predicate<PaperCard> modernPredicate) { this.modernPredicate = standardPredicate; }
|
||||
public void setPioneerPredicate(Predicate<PaperCard> pioneerPredicate) { this.pioneerPredicate = pioneerPredicate; }
|
||||
|
||||
public void setModernPredicate(Predicate<PaperCard> modernPredicate) { this.modernPredicate = modernPredicate; }
|
||||
|
||||
public void setCommanderPredicate(Predicate<PaperCard> commanderPredicate) { this.commanderPredicate = commanderPredicate; }
|
||||
|
||||
@@ -211,9 +212,11 @@ public class StaticData {
|
||||
|
||||
public void setBrawlPredicate(Predicate<PaperCard> brawlPredicate) { this.brawlPredicate = brawlPredicate; }
|
||||
|
||||
public Predicate<PaperCard> getModernPredicate() {
|
||||
return modernPredicate;
|
||||
}
|
||||
public Predicate<PaperCard> getStandardPredicate() { return standardPredicate; }
|
||||
|
||||
public Predicate<PaperCard> getPioneerPredicate() { return pioneerPredicate; }
|
||||
|
||||
public Predicate<PaperCard> getModernPredicate() { return modernPredicate; }
|
||||
|
||||
public Predicate<PaperCard> getCommanderPredicate() { return commanderPredicate; }
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
import forge.StaticData;
|
||||
import forge.card.CardRules;
|
||||
import forge.card.CardRulesPredicates;
|
||||
@@ -37,8 +36,11 @@ import forge.util.TextUtil;
|
||||
import org.apache.commons.lang3.Range;
|
||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* GameType is an enum to determine the type of current game. :)
|
||||
@@ -324,23 +326,32 @@ public enum DeckFormat {
|
||||
}
|
||||
|
||||
final int maxCopies = getMaxCardCopies();
|
||||
if (maxCopies < Integer.MAX_VALUE) {
|
||||
//Must contain no more than 4 of the same card
|
||||
//shared among the main deck and sideboard, except
|
||||
//basic lands, Shadowborn Apostle, Relentless Rats and Rat Colony
|
||||
//Must contain no more than 4 of the same card
|
||||
//shared among the main deck and sideboard, except
|
||||
//basic lands, Shadowborn Apostle, Relentless Rats and Rat Colony
|
||||
// Seven Dwarves can have 7 in the deck. More than 7 in deck + sb is ok in Limited
|
||||
|
||||
final CardPool allCards = deck.getAllCardsInASinglePool(hasCommander());
|
||||
final CardPool allCards = deck.getAllCardsInASinglePool(hasCommander());
|
||||
|
||||
// should group all cards by name, so that different editions of same card are really counted as the same card
|
||||
for (final Entry<String, Integer> cp : Aggregates.groupSumBy(allCards, PaperCard.FN_GET_NAME)) {
|
||||
final IPaperCard simpleCard = StaticData.instance().getCommonCards().getCard(cp.getKey());
|
||||
if (simpleCard == null) {
|
||||
return TextUtil.concatWithSpace("contains the nonexisting card", cp.getKey());
|
||||
}
|
||||
// should group all cards by name, so that different editions of same card are really counted as the same card
|
||||
for (final Entry<String, Integer> cp : Aggregates.groupSumBy(allCards, PaperCard.FN_GET_NAME)) {
|
||||
final IPaperCard simpleCard = StaticData.instance().getCommonCards().getCard(cp.getKey());
|
||||
// Might cause issues since it ignores "Special" Cards
|
||||
if (simpleCard == null) {
|
||||
return TextUtil.concatWithSpace("contains the nonexisting card", cp.getKey());
|
||||
}
|
||||
|
||||
if (!canHaveAnyNumberOf(simpleCard) && cp.getValue() > maxCopies) {
|
||||
return TextUtil.concatWithSpace("must not contain more than", String.valueOf(maxCopies), "copies of the card", cp.getKey());
|
||||
}
|
||||
if (canHaveAnyNumberOf(simpleCard)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Integer cardCopies = canHaveSpecificNumberInDeck(simpleCard);
|
||||
if (cardCopies != null && deck.getMain().countByName(cp.getKey(), true) > cardCopies) {
|
||||
return TextUtil.concatWithSpace("must not contain more than", String.valueOf(cardCopies), "copies of the card", cp.getKey());
|
||||
}
|
||||
|
||||
if (cardCopies == null && cp.getValue() > maxCopies) {
|
||||
return TextUtil.concatWithSpace("must not contain more than", String.valueOf(maxCopies), "copies of the card", cp.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,6 +373,16 @@ public enum DeckFormat {
|
||||
"A deck can have any number of cards named CARDNAME.");
|
||||
}
|
||||
|
||||
public static Integer canHaveSpecificNumberInDeck(final IPaperCard card) {
|
||||
// Ideally, this would be parsed during card parsing and set this value
|
||||
if (Iterables.contains(card.getRules().getMainPart().getKeywords(),
|
||||
"A deck can have up to seven cards named CARDNAME.")) {
|
||||
return 7;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getPlaneSectionConformanceProblem(final CardPool planes) {
|
||||
//Must contain at least 10 planes/phenomenons, but max 2 phenomenons. Singleton.
|
||||
if (planes == null || planes.countAll() < 10) {
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package forge.card;
|
||||
package forge.util;
|
||||
|
||||
import com.esotericsoftware.minlog.Log;
|
||||
import com.google.common.base.Charsets;
|
||||
import forge.properties.ForgeConstants;
|
||||
import forge.util.LineReader;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
@@ -15,12 +12,12 @@ public class CardTranslation {
|
||||
private static Map <String, String> translatednames;
|
||||
private static Map <String, String> translatedtypes;
|
||||
private static Map <String, String> translatedoracles;
|
||||
private static String languageSelected;
|
||||
private static String languageSelected = "en-US";
|
||||
|
||||
private static void readTranslationFile(String language) {
|
||||
private static void readTranslationFile(String language, String languagesDirectory) {
|
||||
String filename = "cardnames-" + language + ".txt";
|
||||
|
||||
try (LineReader translationFile = new LineReader(new FileInputStream(ForgeConstants.LANG_DIR + filename), Charsets.UTF_8)) {
|
||||
try (LineReader translationFile = new LineReader(new FileInputStream(languagesDirectory + filename), Charsets.UTF_8)) {
|
||||
for (String line : translationFile.readLines()) {
|
||||
String[] matches = line.split("\\|");
|
||||
if (matches.length >= 2) {
|
||||
@@ -34,7 +31,7 @@ public class CardTranslation {
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.error("Error reading translation file: cardnames-" + language + ".txt");
|
||||
System.err.println("Error reading translation file: cardnames-" + language + ".txt");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +63,7 @@ public class CardTranslation {
|
||||
}
|
||||
|
||||
public static HashMap<String, String> getTranslationTexts(String cardname, String altcardname) {
|
||||
HashMap<String, String> translations = new HashMap<String, String>();
|
||||
HashMap<String, String> translations = new HashMap<>();
|
||||
translations.put("name", getTranslatedName(cardname));
|
||||
translations.put("oracle", getTranslatedOracle(cardname));
|
||||
translations.put("altname", getTranslatedName(altcardname));
|
||||
@@ -78,14 +75,14 @@ public class CardTranslation {
|
||||
return !languageSelected.equals("en-US");
|
||||
}
|
||||
|
||||
public static void preloadTranslation(String language) {
|
||||
public static void preloadTranslation(String language, String languagesDirectory) {
|
||||
languageSelected = language;
|
||||
|
||||
if (needsTranslation()) {
|
||||
translatednames = new HashMap<>();
|
||||
translatedtypes = new HashMap<>();
|
||||
translatedoracles = new HashMap<>();
|
||||
readTranslationFile(languageSelected);
|
||||
readTranslationFile(languageSelected, languagesDirectory);
|
||||
}
|
||||
}
|
||||
}
|
||||
78
forge-core/src/main/java/forge/util/ComparatorUtil.java
Normal file
78
forge-core/src/main/java/forge/util/ComparatorUtil.java
Normal file
@@ -0,0 +1,78 @@
|
||||
package forge.util;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Gili Tzabari
|
||||
*/
|
||||
public final class ComparatorUtil
|
||||
{
|
||||
/**
|
||||
* Verify that a comparator is transitive.
|
||||
*
|
||||
* @param <T> the type being compared
|
||||
* @param comparator the comparator to test
|
||||
* @param elements the elements to test against
|
||||
* @throws AssertionError if the comparator is not transitive
|
||||
*/
|
||||
public static <T> String verifyTransitivity(Comparator<T> comparator, Collection<T> elements)
|
||||
{
|
||||
String exception = "";
|
||||
for (T first: elements)
|
||||
{
|
||||
for (T second: elements)
|
||||
{
|
||||
int result1 = comparator.compare(first, second);
|
||||
int result2 = comparator.compare(second, first);
|
||||
if (result1 != -result2)
|
||||
{
|
||||
// Uncomment the following line to step through the failed case
|
||||
//comparator.compare(first, second);
|
||||
/*throw new AssertionError("compare(" + first + ", " + second + ") == " + result1 +
|
||||
" but swapping the parameters returns " + result2);*/
|
||||
exception = "compare(" + first + ", " + second + ") == " + result1 +
|
||||
" but swapping the parameters returns " + result2;
|
||||
System.err.println(exception);
|
||||
return exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (T first: elements)
|
||||
{
|
||||
for (T second: elements)
|
||||
{
|
||||
int firstGreaterThanSecond = comparator.compare(first, second);
|
||||
if (firstGreaterThanSecond <= 0)
|
||||
continue;
|
||||
for (T third: elements)
|
||||
{
|
||||
int secondGreaterThanThird = comparator.compare(second, third);
|
||||
if (secondGreaterThanThird <= 0)
|
||||
continue;
|
||||
int firstGreaterThanThird = comparator.compare(first, third);
|
||||
if (firstGreaterThanThird <= 0)
|
||||
{
|
||||
// Uncomment the following line to step through the failed case
|
||||
//comparator.compare(first, third);
|
||||
/*throw new AssertionError("compare(" + first + ", " + second + ") > 0, " +
|
||||
"compare(" + second + ", " + third + ") > 0, but compare(" + first + ", " + third + ") == " +
|
||||
firstGreaterThanThird);*/
|
||||
exception = "compare(" + first + ", " + second + ") > 0, " +
|
||||
"compare(" + second + ", " + third + ") > 0, but compare(" + first + ", " + third + ") == " +
|
||||
firstGreaterThanThird;
|
||||
System.err.println(exception);
|
||||
return exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent construction.
|
||||
*/
|
||||
private ComparatorUtil()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<artifactId>forge</artifactId>
|
||||
<groupId>forge</groupId>
|
||||
<version>1.6.30-SNAPSHOT</version>
|
||||
<version>1.6.31-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>forge-game</artifactId>
|
||||
@@ -32,8 +32,8 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.sentry</groupId>
|
||||
<artifactId>sentry-log4j</artifactId>
|
||||
<version>1.7.5</version>
|
||||
<artifactId>sentry-log4j2</artifactId>
|
||||
<version>1.7.27</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -55,8 +55,6 @@ import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static forge.util.EnumMapUtil.toStringMap;
|
||||
|
||||
/**
|
||||
* Methods for common actions performed during a game.
|
||||
*
|
||||
@@ -147,11 +145,6 @@ public class GameAction {
|
||||
}
|
||||
}
|
||||
|
||||
// if an adventureCard is put from Stack somewhere else, need to reset to Original State
|
||||
if (c.isAdventureCard() && ((zoneFrom != null && zoneFrom.is(ZoneType.Stack)) || !zoneTo.is(ZoneType.Stack))) {
|
||||
c.setState(CardStateName.Original, true);
|
||||
}
|
||||
|
||||
// Clean up the temporary Dash SVar when the Dashed card leaves the battlefield
|
||||
// Clean up the temporary AtEOT SVar
|
||||
String endofTurn = c.getSVar("EndOfTurnLeavePlay");
|
||||
@@ -258,7 +251,7 @@ public class GameAction {
|
||||
}
|
||||
if(noLandLKI.isLand()) {
|
||||
// if it isn't on the Stack, it stays in that Zone
|
||||
if (!c.getZone().is(ZoneType.Stack)) {
|
||||
if (!c.isInZone(ZoneType.Stack)) {
|
||||
return c;
|
||||
}
|
||||
// if something would only be a land when entering the battlefield and not before
|
||||
@@ -292,8 +285,7 @@ public class GameAction {
|
||||
copied.getOwner().addInboundToken(copied);
|
||||
}
|
||||
|
||||
Map<AbilityKey, Object> repParams = AbilityKey.newMap();
|
||||
repParams.put(AbilityKey.Affected, copied);
|
||||
Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(copied);
|
||||
repParams.put(AbilityKey.CardLKI, lastKnownInfo);
|
||||
repParams.put(AbilityKey.Cause, cause);
|
||||
repParams.put(AbilityKey.Origin, zoneFrom != null ? zoneFrom.getZoneType() : null);
|
||||
@@ -303,7 +295,7 @@ public class GameAction {
|
||||
repParams.putAll(params);
|
||||
}
|
||||
|
||||
ReplacementResult repres = game.getReplacementHandler().run(ReplacementType.Moved, toStringMap(repParams));
|
||||
ReplacementResult repres = game.getReplacementHandler().run(ReplacementType.Moved, repParams);
|
||||
if (repres != ReplacementResult.NotReplaced) {
|
||||
// reset failed manifested Cards back to original
|
||||
if (c.isManifested()) {
|
||||
@@ -355,6 +347,11 @@ public class GameAction {
|
||||
}
|
||||
}
|
||||
|
||||
// if an adventureCard is put from Stack somewhere else, need to reset to Original State
|
||||
if (copied.isAdventureCard() && ((zoneFrom != null && zoneFrom.is(ZoneType.Stack)) || !zoneTo.is(ZoneType.Stack))) {
|
||||
copied.setState(CardStateName.Original, false);
|
||||
}
|
||||
|
||||
GameEntityCounterTable table = new GameEntityCounterTable();
|
||||
|
||||
// need to suspend cards own replacement effects
|
||||
@@ -704,7 +701,9 @@ public class GameAction {
|
||||
// Run triggers
|
||||
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromCard(c);
|
||||
runParams.put(AbilityKey.Cause, cause);
|
||||
runParams.put(AbilityKey.Origin, origin.getZoneType().name());
|
||||
if (origin != null) { // is generally null when adding via dev mode
|
||||
runParams.put(AbilityKey.Origin, origin.getZoneType().name());
|
||||
}
|
||||
if (params != null) {
|
||||
runParams.putAll(params);
|
||||
}
|
||||
@@ -1389,11 +1388,10 @@ public class GameAction {
|
||||
}
|
||||
|
||||
// Replacement effects
|
||||
final Map<String, Object> repRunParams = Maps.newHashMap();
|
||||
repRunParams.put("Source", sa);
|
||||
repRunParams.put("Card", c);
|
||||
repRunParams.put("Affected", c);
|
||||
repRunParams.put("Regeneration", regenerate);
|
||||
final Map<AbilityKey, Object> repRunParams = AbilityKey.mapFromCard(c);
|
||||
repRunParams.put(AbilityKey.Source, sa);
|
||||
repRunParams.put(AbilityKey.Affected, c);
|
||||
repRunParams.put(AbilityKey.Regeneration, regenerate);
|
||||
|
||||
if (game.getReplacementHandler().run(ReplacementType.Destroy, repRunParams) != ReplacementResult.NotReplaced) {
|
||||
return false;
|
||||
|
||||
@@ -300,12 +300,12 @@ public final class GameActionUtil {
|
||||
costs.add(new OptionalCostValue(type, cost));
|
||||
}
|
||||
} else if (keyword.equals("Retrace")) {
|
||||
if (source.getZone().is(ZoneType.Graveyard)) {
|
||||
if (source.isInZone(ZoneType.Graveyard)) {
|
||||
final Cost cost = new Cost("Discard<1/Land>", false);
|
||||
costs.add(new OptionalCostValue(OptionalCost.Retrace, cost));
|
||||
}
|
||||
} else if (keyword.equals("Jump-start")) {
|
||||
if (source.getZone().is(ZoneType.Graveyard)) {
|
||||
if (source.isInZone(ZoneType.Graveyard)) {
|
||||
final Cost cost = new Cost("Discard<1/Card>", false);
|
||||
costs.add(new OptionalCostValue(OptionalCost.Jumpstart, cost));
|
||||
}
|
||||
|
||||
@@ -115,25 +115,24 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
|
||||
public int replaceDamage(final int damage, final Card source, final boolean isCombat, final boolean prevention,
|
||||
final CardDamageMap damageMap, final CardDamageMap preventMap, GameEntityCounterTable counterTable, final SpellAbility cause) {
|
||||
// Replacement effects
|
||||
final Map<String, Object> repParams = Maps.newHashMap();
|
||||
repParams.put("Affected", this);
|
||||
repParams.put("DamageSource", source);
|
||||
repParams.put("DamageAmount", damage);
|
||||
repParams.put("IsCombat", isCombat);
|
||||
repParams.put("NoPreventDamage", !prevention);
|
||||
repParams.put("DamageMap", damageMap);
|
||||
repParams.put("PreventMap", preventMap);
|
||||
repParams.put("CounterTable", counterTable);
|
||||
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(this);
|
||||
repParams.put(AbilityKey.DamageSource, source);
|
||||
repParams.put(AbilityKey.DamageAmount, damage);
|
||||
repParams.put(AbilityKey.IsCombat, isCombat);
|
||||
repParams.put(AbilityKey.NoPreventDamage, !prevention);
|
||||
repParams.put(AbilityKey.DamageMap, damageMap);
|
||||
repParams.put(AbilityKey.PreventMap, preventMap);
|
||||
repParams.put(AbilityKey.CounterTable, counterTable);
|
||||
if (cause != null) {
|
||||
repParams.put("Cause", cause);
|
||||
repParams.put(AbilityKey.Cause, cause);
|
||||
}
|
||||
|
||||
switch (getGame().getReplacementHandler().run(ReplacementType.DamageDone, repParams)) {
|
||||
case NotReplaced:
|
||||
return damage;
|
||||
case Updated:
|
||||
int newDamage = (int) repParams.get("DamageAmount");
|
||||
GameEntity newTarget = (GameEntity) repParams.get("Affected");
|
||||
int newDamage = (int) repParams.get(AbilityKey.DamageAmount);
|
||||
GameEntity newTarget = (GameEntity) repParams.get(AbilityKey.Affected);
|
||||
// check if this is still the affected card or player
|
||||
if (this.equals(newTarget)) {
|
||||
return newDamage;
|
||||
@@ -169,15 +168,14 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
|
||||
int restDamage = damage;
|
||||
|
||||
// first try to replace the damage
|
||||
final Map<String, Object> repParams = Maps.newHashMap();
|
||||
repParams.put("Affected", this);
|
||||
repParams.put("DamageSource", source);
|
||||
repParams.put("DamageAmount", damage);
|
||||
repParams.put("IsCombat", isCombat);
|
||||
repParams.put("Prevention", true);
|
||||
repParams.put("PreventMap", preventMap);
|
||||
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(this);
|
||||
repParams.put(AbilityKey.DamageSource, source);
|
||||
repParams.put(AbilityKey.DamageAmount, damage);
|
||||
repParams.put(AbilityKey.IsCombat, isCombat);
|
||||
repParams.put(AbilityKey.Prevention, true);
|
||||
repParams.put(AbilityKey.PreventMap, preventMap);
|
||||
if (cause != null) {
|
||||
repParams.put("Cause", cause);
|
||||
repParams.put(AbilityKey.Cause, cause);
|
||||
}
|
||||
|
||||
switch (getGame().getReplacementHandler().run(ReplacementType.DamageDone, repParams)) {
|
||||
@@ -185,7 +183,7 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
|
||||
restDamage = damage;
|
||||
break;
|
||||
case Updated:
|
||||
restDamage = (int) repParams.get("DamageAmount");
|
||||
restDamage = (int) repParams.get(AbilityKey.DamageAmount);
|
||||
break;
|
||||
default:
|
||||
restDamage = 0;
|
||||
|
||||
@@ -47,7 +47,7 @@ import java.util.Map.Entry;
|
||||
public class GameFormat implements Comparable<GameFormat> {
|
||||
private final String name;
|
||||
public enum FormatType {Sanctioned, Casual, Historic, Digital, Custom}
|
||||
public enum FormatSubType {Block, Standard, Extended, Modern, Legacy, Vintage, Commander, Planechase, Videogame, MTGO, Custom}
|
||||
public enum FormatSubType {Block, Standard, Extended, Pioneer, Modern, Legacy, Vintage, Commander, Planechase, Videogame, MTGO, Custom}
|
||||
|
||||
// contains allowed sets, when empty allows all sets
|
||||
private FormatType formatType;
|
||||
@@ -290,6 +290,7 @@ public class GameFormat implements Comparable<GameFormat> {
|
||||
private List<String> coreFormats = new ArrayList<>();
|
||||
{
|
||||
coreFormats.add("Standard.txt");
|
||||
coreFormats.add("Pioneer.txt");
|
||||
coreFormats.add("Modern.txt");
|
||||
coreFormats.add("Legacy.txt");
|
||||
coreFormats.add("Vintage.txt");
|
||||
@@ -468,6 +469,10 @@ public class GameFormat implements Comparable<GameFormat> {
|
||||
return this.map.get("Extended");
|
||||
}
|
||||
|
||||
public GameFormat getPioneer() {
|
||||
return this.map.get("Pioneer");
|
||||
}
|
||||
|
||||
public GameFormat getModern() {
|
||||
return this.map.get("Modern");
|
||||
}
|
||||
|
||||
@@ -33,11 +33,11 @@ import forge.game.player.RegisteredPlayer;
|
||||
import forge.game.spellability.TargetChoices;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Lang;
|
||||
import forge.util.Localizer;
|
||||
import forge.util.maps.MapOfLists;
|
||||
|
||||
public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
|
||||
private final GameLog log;
|
||||
|
||||
public GameLogFormatter(GameLog gameLog) {
|
||||
log = gameLog;
|
||||
}
|
||||
@@ -52,16 +52,15 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventScry ev) {
|
||||
final Localizer localizer = Localizer.getInstance();
|
||||
String scryOutcome = "";
|
||||
String toTop = Lang.nounWithAmount(ev.toTop, "card") + " to the top of the library";
|
||||
String toBottom = Lang.nounWithAmount(ev.toBottom, "card") + " to the bottom of the library";
|
||||
|
||||
if (ev.toTop > 0 && ev.toBottom > 0) {
|
||||
scryOutcome = ev.player.toString() + " scried " + toTop + " and " + toBottom;
|
||||
scryOutcome = localizer.getMessage("lblLogScryTopBottomLibrary").replace("%s", ev.player.toString()).replace("%top", String.valueOf(ev.toTop)).replace("%bottom", String.valueOf(ev.toBottom));
|
||||
} else if (ev.toBottom == 0) {
|
||||
scryOutcome = ev.player.toString() + " scried " + toTop;
|
||||
scryOutcome = localizer.getMessage("lblLogScryTopLibrary").replace("%s", ev.player.toString()).replace("%top", String.valueOf(ev.toTop));
|
||||
} else {
|
||||
scryOutcome = ev.player.toString() + " scried " + toBottom;
|
||||
scryOutcome = localizer.getMessage("lblLogScryBottomLibrary").replace("%s", ev.player.toString()).replace("%bottom", String.valueOf(ev.toBottom));
|
||||
}
|
||||
|
||||
return new GameLogEntry(GameLogEntryType.STACK_RESOLVE, scryOutcome);
|
||||
@@ -218,6 +217,7 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
|
||||
@Override
|
||||
public GameLogEntry visit(final GameEventAttackersDeclared ev) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
final Localizer localizer = Localizer.getInstance();
|
||||
|
||||
// Loop through Defenders
|
||||
// Append Defending Player/Planeswalker
|
||||
@@ -233,7 +233,7 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
|
||||
sb.append(" to attack ").append(k).append(".");
|
||||
}
|
||||
if (sb.length() == 0) {
|
||||
sb.append(ev.player).append(" didn't attack this turn.");
|
||||
sb.append(localizer.getMessage("lblPlayerDidntAttackThisTurn").replace("%s", ev.player.toString()));
|
||||
}
|
||||
return new GameLogEntry(GameLogEntryType.COMBAT, sb.toString());
|
||||
}
|
||||
@@ -281,7 +281,7 @@ public class GameLogFormatter extends IGameEventVisitor.Base<GameLogEntry> {
|
||||
|
||||
@Override
|
||||
public GameLogEntry visit(GameEventMulligan ev) {
|
||||
String message = ev.player.toString() + " has mulliganed down to " + ev.player.getZone(ZoneType.Hand).size() + " cards.";
|
||||
String message = Localizer.getInstance().getMessage("lblPlayerHasMulliganedDownToNCards").replace("%d", String.valueOf(ev.player.getZone(ZoneType.Hand).size())).replace("%s", ev.player.toString());
|
||||
return new GameLogEntry(GameLogEntryType.MULLIGAN, message);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package forge.game.ability;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.card.Card;
|
||||
|
||||
/**
|
||||
@@ -37,12 +38,15 @@ public enum AbilityKey {
|
||||
CostStack("CostStack"),
|
||||
CounterAmount("CounterAmount"),
|
||||
CounteredSA("CounteredSA"),
|
||||
CounterNum("CounterNum"),
|
||||
CounterTable("CounterTable"),
|
||||
CounterType("CounterType"),
|
||||
Crew("Crew"),
|
||||
CumulativeUpkeepPaid("CumulativeUpkeepPaid"),
|
||||
CurrentCastSpells("CurrentCastSpells"),
|
||||
CurrentStormCount("CurrentStormCount"),
|
||||
DamageAmount("DamageAmount"),
|
||||
DamageMap("DamageMap"),
|
||||
DamageSource("DamageSource"),
|
||||
DamageSources("DamageSources"),
|
||||
DamageTarget("DamageTarget"),
|
||||
@@ -53,18 +57,23 @@ public enum AbilityKey {
|
||||
Destination("Destination"),
|
||||
Devoured("Devoured"),
|
||||
EchoPaid("EchoPaid"),
|
||||
EffectOnly("EffectOnly"),
|
||||
Exploited("Exploited"),
|
||||
Explorer("Explorer"),
|
||||
Event("Event"),
|
||||
Fighter("Fighter"),
|
||||
FirstTime("FirstTime"),
|
||||
Fizzle("Fizzle"),
|
||||
IsCombat("IsCombat"), // TODO confirm that this and IsCombatDamage can be merged
|
||||
IsCombatDamage("IsCombatDamage"),
|
||||
IndividualCostPaymentInstance("IndividualCostPaymentInstance"),
|
||||
IsMadness("IsMadness"),
|
||||
LifeAmount("LifeAmount"),
|
||||
LifeAmount("LifeAmount"), //TODO confirm that this and LifeGained can be merged
|
||||
LifeGained("LifeGained"),
|
||||
Mana("Mana"),
|
||||
MonstrosityAmount("MonstrosityAmount"),
|
||||
NewCounterAmount("NewCounterAmount"),
|
||||
NoPreventDamage("NoPreventDamage"),
|
||||
Num("Num"), // TODO confirm that this and NumThisTurn can be merged
|
||||
NumBlockers("NumBlockers"),
|
||||
NumThisTurn("NumThisTurn"),
|
||||
@@ -76,10 +85,15 @@ public enum AbilityKey {
|
||||
Origin("Origin"),
|
||||
OriginalController("OriginalController"),
|
||||
OriginalDefender("OriginalDefender"),
|
||||
OriginalParams("OriginalParams"),
|
||||
PayingMana("PayingMana"),
|
||||
Phase("Phase"),
|
||||
Player("Player"),
|
||||
PreventMap("PreventMap"),
|
||||
Prevention("Prevention"),
|
||||
Produced("Produced"),
|
||||
Regeneration("Regeneration"),
|
||||
ReplacementResult("ReplacementResult"),
|
||||
Result("Result"),
|
||||
Scheme("Scheme"),
|
||||
Source("Source"),
|
||||
@@ -91,8 +105,12 @@ public enum AbilityKey {
|
||||
StackInstance("StackInstance"),
|
||||
StackSa("StackSa"),
|
||||
StackSi("StackSi"),
|
||||
SurveilNum("SurveilNum"),
|
||||
Target("Target"),
|
||||
Targets("Targets"),
|
||||
TgtSA("TgtSA"),
|
||||
Token("Token"),
|
||||
TokenNum("TokenNum"),
|
||||
Transformer("Transformer"),
|
||||
Vehicle("Vehicle"),
|
||||
Won("Won");
|
||||
@@ -141,4 +159,11 @@ public enum AbilityKey {
|
||||
runParams.put(Card, card);
|
||||
return runParams;
|
||||
}
|
||||
|
||||
public static Map<AbilityKey, Object> mapFromAffected(GameEntity gameEntity) {
|
||||
final Map<AbilityKey, Object> runParams = newMap();
|
||||
|
||||
runParams.put(Affected, gameEntity);
|
||||
return runParams;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ public class AbilityUtils {
|
||||
public static CounterType getCounterType(String name, SpellAbility sa) throws Exception {
|
||||
CounterType counterType;
|
||||
if ("ReplacedCounterType".equals(name)) {
|
||||
name = (String) sa.getReplacingObject("CounterType");
|
||||
name = (String) sa.getReplacingObject(AbilityKey.CounterType);
|
||||
}
|
||||
try {
|
||||
counterType = CounterType.getType(name);
|
||||
@@ -157,7 +157,9 @@ public class AbilityUtils {
|
||||
}
|
||||
else if (defined.startsWith("Replaced") && (sa != null)) {
|
||||
final SpellAbility root = sa.getRootAbility();
|
||||
final Object crd = root.getReplacingObject(defined.substring(8));
|
||||
AbilityKey type = AbilityKey.fromString(defined.substring(8));
|
||||
final Object crd = root.getReplacingObject(type);
|
||||
|
||||
if (crd instanceof Card) {
|
||||
c = game.getCardState((Card) crd);
|
||||
} else if (crd instanceof List<?>) {
|
||||
@@ -712,7 +714,7 @@ public class AbilityUtils {
|
||||
}
|
||||
else if (calcX[0].startsWith("Replaced")) {
|
||||
final SpellAbility root = sa.getRootAbility();
|
||||
list = new CardCollection((Card) root.getReplacingObject(calcX[0].substring(8)));
|
||||
list = new CardCollection((Card) root.getReplacingObject(AbilityKey.fromString(calcX[0].substring(8))));
|
||||
}
|
||||
else if (calcX[0].startsWith("ReplaceCount")) {
|
||||
// ReplaceCount is similar to a regular Count, but just
|
||||
@@ -720,7 +722,7 @@ public class AbilityUtils {
|
||||
final SpellAbility root = sa.getRootAbility();
|
||||
final String[] l = calcX[1].split("/");
|
||||
final String m = CardFactoryUtil.extractOperators(calcX[1]);
|
||||
final int count = (Integer) root.getReplacingObject(l[0]);
|
||||
final int count = (Integer) root.getReplacingObject(AbilityKey.fromString(l[0]));
|
||||
|
||||
return CardFactoryUtil.doXMath(count, m, card) * multiplier;
|
||||
}
|
||||
@@ -1063,7 +1065,7 @@ public class AbilityUtils {
|
||||
if (defined.endsWith("Controller")) {
|
||||
String replacingType = defined.substring(8);
|
||||
replacingType = replacingType.substring(0, replacingType.length() - 10);
|
||||
final Object c = root.getReplacingObject(replacingType);
|
||||
final Object c = root.getReplacingObject(AbilityKey.fromString(replacingType));
|
||||
if (c instanceof Card) {
|
||||
o = ((Card) c).getController();
|
||||
}
|
||||
@@ -1074,14 +1076,14 @@ public class AbilityUtils {
|
||||
else if (defined.endsWith("Owner")) {
|
||||
String replacingType = defined.substring(8);
|
||||
replacingType = replacingType.substring(0, replacingType.length() - 5);
|
||||
final Object c = root.getReplacingObject(replacingType);
|
||||
final Object c = root.getReplacingObject(AbilityKey.fromString(replacingType));
|
||||
if (c instanceof Card) {
|
||||
o = ((Card) c).getOwner();
|
||||
}
|
||||
}
|
||||
else {
|
||||
final String replacingType = defined.substring(8);
|
||||
o = root.getReplacingObject(replacingType);
|
||||
o = root.getReplacingObject(AbilityKey.fromString(replacingType));
|
||||
}
|
||||
if (o != null) {
|
||||
if (o instanceof Player) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import forge.game.card.Card;
|
||||
import forge.game.card.CardCollectionView;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.card.CardPredicates;
|
||||
import forge.game.card.CardZoneTable;
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.card.token.TokenInfo;
|
||||
import forge.game.event.GameEventTokenCreated;
|
||||
@@ -44,6 +45,17 @@ public class AmassEffect extends SpellAbilityEffect {
|
||||
final int amount = AbilityUtils.calculateAmount(card, sa.getParamOrDefault("Num", "1"), sa);
|
||||
final boolean remember = sa.hasParam("RememberAmass");
|
||||
|
||||
boolean useZoneTable = true;
|
||||
CardZoneTable triggerList = sa.getChangeZoneTable();
|
||||
if (triggerList == null) {
|
||||
triggerList = new CardZoneTable();
|
||||
useZoneTable = false;
|
||||
}
|
||||
if (sa.hasParam("ChangeZoneTable")) {
|
||||
sa.setChangeZoneTable(triggerList);
|
||||
useZoneTable = true;
|
||||
}
|
||||
|
||||
// create army token if needed
|
||||
if (CardLists.count(activator.getCardsIn(ZoneType.Battlefield), CardPredicates.isType("Army")) == 0) {
|
||||
final String tokenScript = "b_0_0_zombie_army";
|
||||
@@ -54,9 +66,16 @@ public class AmassEffect extends SpellAbilityEffect {
|
||||
|
||||
// Should this be catching the Card that's returned?
|
||||
Card c = game.getAction().moveToPlay(tok, sa);
|
||||
if (c.getZone() != null) {
|
||||
triggerList.put(ZoneType.None, c.getZone().getZoneType(), c);
|
||||
}
|
||||
c.updateStateForView();
|
||||
}
|
||||
|
||||
if (!useZoneTable) {
|
||||
triggerList.triggerChangesZoneAll(game);
|
||||
triggerList.clear();
|
||||
}
|
||||
game.fireEvent(new GameEventTokenCreated());
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ import forge.game.spellability.SpellAbility;
|
||||
import forge.game.trigger.TriggerType;
|
||||
import forge.game.zone.ZoneType;
|
||||
|
||||
import forge.util.Lang;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class BlockEffect extends SpellAbilityEffect {
|
||||
@@ -106,7 +108,7 @@ public class BlockEffect extends SpellAbilityEffect {
|
||||
}
|
||||
}
|
||||
|
||||
sb.append(String.join(", ", blockers)).append(" block ").append(String.join(", ", attackers));
|
||||
sb.append(Lang.joinHomogenous(blockers)).append(" block ").append(Lang.joinHomogenous(attackers));
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ public class CloneEffect extends SpellAbilityEffect {
|
||||
}
|
||||
|
||||
if (sa.hasParam("CloneZone")) {
|
||||
if (!tgtCard.getZone().is(ZoneType.smartValueOf(sa.getParam("CloneZone")))) {
|
||||
if (!tgtCard.isInZone(ZoneType.smartValueOf(sa.getParam("CloneZone")))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -134,7 +134,7 @@ public class CloneEffect extends SpellAbilityEffect {
|
||||
tgtCard.clearImprintedCards();
|
||||
|
||||
// check if clone is now an Aura that needs to be attached
|
||||
if (tgtCard.isAura() && !tgtCard.getZone().is(ZoneType.Battlefield)) {
|
||||
if (tgtCard.isAura() && !tgtCard.isInZone(ZoneType.Battlefield)) {
|
||||
AttachEffect.attachAuraOnIndirectEnterBattlefield(tgtCard);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
public class CounterEffect extends SpellAbilityEffect {
|
||||
@Override
|
||||
@@ -155,10 +154,9 @@ public class CounterEffect extends SpellAbilityEffect {
|
||||
final SpellAbility srcSA, final SpellAbilityStackInstance si) {
|
||||
final Game game = tgtSA.getActivatingPlayer().getGame();
|
||||
// Run any applicable replacement effects.
|
||||
final Map<String, Object> repParams = Maps.newHashMap();
|
||||
repParams.put("TgtSA", tgtSA);
|
||||
repParams.put("Affected", tgtSA.getHostCard());
|
||||
repParams.put("Cause", srcSA.getHostCard());
|
||||
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(tgtSA.getHostCard());
|
||||
repParams.put(AbilityKey.TgtSA, tgtSA);
|
||||
repParams.put(AbilityKey.Cause, srcSA.getHostCard());
|
||||
if (game.getReplacementHandler().run(ReplacementType.Counter, repParams) != ReplacementResult.NotReplaced) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package forge.game.ability.effects;
|
||||
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
@@ -11,6 +12,6 @@ import forge.game.spellability.SpellAbility;
|
||||
public class ETBReplacementEffect extends SpellAbilityEffect {
|
||||
@Override
|
||||
public void resolve(SpellAbility sa) {
|
||||
sa.getActivatingPlayer().getGame().getAction().moveToPlay(((Card) sa.getReplacingObject("Card")), sa);
|
||||
sa.getActivatingPlayer().getGame().getAction().moveToPlay(((Card) sa.getReplacingObject(AbilityKey.Card)), sa);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package forge.game.ability.effects;
|
||||
|
||||
import forge.game.card.Card;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.Localizer;
|
||||
|
||||
/**
|
||||
* TODO: Write javadoc for this type.
|
||||
@@ -13,7 +14,7 @@ public class PermanentCreatureEffect extends PermanentEffect {
|
||||
public String getStackDescription(final SpellAbility sa) {
|
||||
final Card sourceCard = sa.getHostCard();
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append(sourceCard.getName()).append(" - Creature ").append(sourceCard.getNetPower());
|
||||
sb.append(sourceCard.getName()).append(" - ").append(Localizer.getInstance().getMessage("lblCreature")).append(" ").append(sourceCard.getNetPower());
|
||||
sb.append(" / ").append(sourceCard.getNetToughness());
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -120,7 +120,10 @@ public class PumpEffect extends SpellAbilityEffect {
|
||||
&& !(host.isInPlay() || host.isInZone(ZoneType.Stack))) {
|
||||
return;
|
||||
}
|
||||
p.addChangedKeywords(keywords, ImmutableList.of(), timestamp);
|
||||
|
||||
if (!keywords.isEmpty()) {
|
||||
p.addChangedKeywords(keywords, ImmutableList.of(), timestamp);
|
||||
}
|
||||
|
||||
if (!sa.hasParam("Permanent")) {
|
||||
// If not Permanent, remove Pumped at EOT
|
||||
@@ -129,12 +132,7 @@ public class PumpEffect extends SpellAbilityEffect {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
if (keywords.size() > 0) {
|
||||
for (int i = 0; i < keywords.size(); i++) {
|
||||
p.removeKeyword(keywords.get(i));
|
||||
}
|
||||
}
|
||||
p.removeChangedKeywords(timestamp);
|
||||
}
|
||||
};
|
||||
addUntilCommand(sa, untilEOT);
|
||||
|
||||
@@ -2,10 +2,9 @@ package forge.game.ability.effects;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import forge.game.ability.AbilityKey;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
@@ -31,10 +30,10 @@ public class ReplaceDamageEffect extends SpellAbilityEffect {
|
||||
String varValue = sa.getParamOrDefault("VarName", "1");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> originalParams = (Map<String, Object>) sa.getReplacingObject("OriginalParams");
|
||||
Map<String, Object> params = Maps.newHashMap(originalParams);
|
||||
Map<AbilityKey, Object> originalParams = (Map<AbilityKey, Object>) sa.getReplacingObject(AbilityKey.OriginalParams);
|
||||
Map<AbilityKey, Object> params = AbilityKey.newMap(originalParams);
|
||||
|
||||
Integer dmg = (Integer) sa.getReplacingObject("DamageAmount");
|
||||
Integer dmg = (Integer) sa.getReplacingObject(AbilityKey.DamageAmount);
|
||||
|
||||
int prevent = AbilityUtils.calculateAmount(card, varValue, sa);
|
||||
|
||||
@@ -54,10 +53,10 @@ public class ReplaceDamageEffect extends SpellAbilityEffect {
|
||||
|
||||
// no damage for original target anymore
|
||||
if (dmg <= 0) {
|
||||
originalParams.put("ReplacementResult", ReplacementResult.Replaced);
|
||||
originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Replaced);
|
||||
return;
|
||||
}
|
||||
params.put("DamageAmount", dmg);
|
||||
params.put(AbilityKey.DamageAmount, dmg);
|
||||
|
||||
|
||||
//try to call replacementHandler with new Params
|
||||
@@ -65,16 +64,16 @@ public class ReplaceDamageEffect extends SpellAbilityEffect {
|
||||
switch (result) {
|
||||
case NotReplaced:
|
||||
case Updated: {
|
||||
for (Map.Entry<String, Object> e : params.entrySet()) {
|
||||
for (Map.Entry<AbilityKey, Object> e : params.entrySet()) {
|
||||
originalParams.put(e.getKey(), e.getValue());
|
||||
}
|
||||
// effect was updated
|
||||
originalParams.put("ReplacementResult", ReplacementResult.Updated);
|
||||
originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Updated);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// effect was replaced with something else
|
||||
originalParams.put("ReplacementResult", result);
|
||||
originalParams.put(AbilityKey.ReplacementResult, result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.google.common.collect.Maps;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.game.GameObject;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
@@ -23,14 +24,14 @@ public class ReplaceEffect extends SpellAbilityEffect {
|
||||
final Card card = sa.getHostCard();
|
||||
final Game game = card.getGame();
|
||||
|
||||
final String varName = sa.getParam("VarName");
|
||||
final AbilityKey varName = AbilityKey.fromString(sa.getParam("VarName"));
|
||||
final String varValue = sa.getParam("VarValue");
|
||||
final String type = sa.getParamOrDefault("VarType", "amount");
|
||||
final ReplacementType retype = sa.getReplacementEffect().getMode();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> originalParams = (Map<String, Object>) sa.getReplacingObject("OriginalParams");
|
||||
Map<String, Object> params = Maps.newHashMap(originalParams);
|
||||
Map<AbilityKey, Object> originalParams = (Map<AbilityKey, Object>) sa.getReplacingObject(AbilityKey.OriginalParams);
|
||||
Map<AbilityKey, Object> params = Maps.newHashMap(originalParams);
|
||||
|
||||
if ("Card".equals(type)) {
|
||||
List<Card> list = AbilityUtils.getDefinedCards(card, varValue, sa);
|
||||
@@ -56,8 +57,8 @@ public class ReplaceEffect extends SpellAbilityEffect {
|
||||
params.put(varName, AbilityUtils.calculateAmount(card, varValue, sa));
|
||||
}
|
||||
|
||||
if (params.containsKey("EffectOnly")) {
|
||||
params.put("EffectOnly", true);
|
||||
if (params.containsKey(AbilityKey.EffectOnly)) {
|
||||
params.put(AbilityKey.EffectOnly, true);
|
||||
}
|
||||
|
||||
//try to call replacementHandler with new Params
|
||||
@@ -65,16 +66,16 @@ public class ReplaceEffect extends SpellAbilityEffect {
|
||||
switch (result) {
|
||||
case NotReplaced:
|
||||
case Updated: {
|
||||
for (Map.Entry<String, Object> e : params.entrySet()) {
|
||||
for (Map.Entry<AbilityKey, Object> e : params.entrySet()) {
|
||||
originalParams.put(e.getKey(), e.getValue());
|
||||
}
|
||||
// effect was updated
|
||||
originalParams.put("ReplacementResult", ReplacementResult.Updated);
|
||||
originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Updated);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// effect was replaced with something else
|
||||
originalParams.put("ReplacementResult", result);
|
||||
originalParams.put(AbilityKey.ReplacementResult, result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,9 @@ package forge.game.ability.effects;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import forge.game.ability.AbilityKey;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.game.GameEntity;
|
||||
import forge.game.GameEntityCounterTable;
|
||||
@@ -36,10 +35,10 @@ public class ReplaceSplitDamageEffect extends SpellAbilityEffect {
|
||||
String varValue = sa.getParamOrDefault("VarName", "1");
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> originalParams = (Map<String, Object>) sa.getReplacingObject("OriginalParams");
|
||||
Map<String, Object> params = Maps.newHashMap(originalParams);
|
||||
Map<AbilityKey, Object> originalParams = (Map<AbilityKey , Object>) sa.getReplacingObject(AbilityKey.OriginalParams);
|
||||
Map<AbilityKey, Object> params = AbilityKey.newMap(originalParams);
|
||||
|
||||
Integer dmg = (Integer) sa.getReplacingObject("DamageAmount");
|
||||
Integer dmg = (Integer) sa.getReplacingObject(AbilityKey.DamageAmount);
|
||||
|
||||
|
||||
int prevent = AbilityUtils.calculateAmount(card, varValue, sa);
|
||||
@@ -57,15 +56,15 @@ public class ReplaceSplitDamageEffect extends SpellAbilityEffect {
|
||||
card.setSVar(varValue, "Number$" + prevent);
|
||||
}
|
||||
|
||||
Card sourceLKI = (Card) sa.getReplacingObject("Source");
|
||||
Card sourceLKI = (Card) sa.getReplacingObject(AbilityKey.Source);
|
||||
|
||||
CardDamageMap damageMap = (CardDamageMap) originalParams.get("DamageMap");
|
||||
CardDamageMap preventMap = (CardDamageMap) originalParams.get("PreventMap");
|
||||
GameEntityCounterTable counterTable = (GameEntityCounterTable) originalParams.get("CounterTable");
|
||||
SpellAbility cause = (SpellAbility) originalParams.get("Cause");
|
||||
CardDamageMap damageMap = (CardDamageMap) originalParams.get(AbilityKey.DamageMap);
|
||||
CardDamageMap preventMap = (CardDamageMap) originalParams.get(AbilityKey.PreventMap);
|
||||
GameEntityCounterTable counterTable = (GameEntityCounterTable) originalParams.get(AbilityKey.CounterTable);
|
||||
SpellAbility cause = (SpellAbility) originalParams.get(AbilityKey.Cause);
|
||||
|
||||
boolean isCombat = (Boolean) originalParams.get("IsCombat");
|
||||
boolean noPrevention = (Boolean) originalParams.get("NoPreventDamage");
|
||||
boolean isCombat = (Boolean) originalParams.get(AbilityKey.IsCombat);
|
||||
boolean noPrevention = (Boolean) originalParams.get(AbilityKey.NoPreventDamage);
|
||||
|
||||
GameEntity obj = (GameEntity) list.get(0);
|
||||
|
||||
@@ -74,26 +73,26 @@ public class ReplaceSplitDamageEffect extends SpellAbilityEffect {
|
||||
|
||||
// no damage for original target anymore
|
||||
if (dmg <= 0) {
|
||||
originalParams.put("ReplacementResult", ReplacementResult.Replaced);
|
||||
originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Replaced);
|
||||
return;
|
||||
}
|
||||
params.put("DamageAmount", dmg);
|
||||
params.put(AbilityKey.DamageAmount, dmg);
|
||||
|
||||
//try to call replacementHandler with new Params
|
||||
ReplacementResult result = game.getReplacementHandler().run(event, params);
|
||||
switch (result) {
|
||||
case NotReplaced:
|
||||
case Updated: {
|
||||
for (Map.Entry<String, Object> e : params.entrySet()) {
|
||||
for (Map.Entry<AbilityKey, Object> e : params.entrySet()) {
|
||||
originalParams.put(e.getKey(), e.getValue());
|
||||
}
|
||||
// effect was updated
|
||||
originalParams.put("ReplacementResult", ReplacementResult.Updated);
|
||||
originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Updated);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// effect was replaced with something else
|
||||
originalParams.put("ReplacementResult", result);
|
||||
originalParams.put(AbilityKey.ReplacementResult, result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import forge.card.MagicColor;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.token.TokenInfo;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@@ -224,8 +225,11 @@ public class TokenEffect extends SpellAbilityEffect {
|
||||
// Cause of the Token Effect, in general it should be this
|
||||
// but if its a Replacement Effect, it might be something else or null
|
||||
SpellAbility cause = sa;
|
||||
if (root.isReplacementAbility() && root.hasReplacingObject("Cause")) {
|
||||
cause = (SpellAbility)root.getReplacingObject("Cause");
|
||||
if (root.isReplacementAbility()) {
|
||||
SpellAbility replacingObject = (SpellAbility) root.getReplacingObject(AbilityKey.Cause);
|
||||
if (replacingObject != null) {
|
||||
cause = replacingObject;
|
||||
}
|
||||
}
|
||||
|
||||
final boolean remember = sa.hasParam("RememberTokens");
|
||||
|
||||
@@ -689,9 +689,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
|
||||
if (result && runTriggers) {
|
||||
// Run replacement effects
|
||||
Map<String, Object> repParams = Maps.newHashMap();
|
||||
repParams.put("Affected", this);
|
||||
getGame().getReplacementHandler().run(ReplacementType.TurnFaceUp, repParams);
|
||||
getGame().getReplacementHandler().run(ReplacementType.TurnFaceUp, AbilityKey.mapFromAffected(this));
|
||||
|
||||
// Run triggers
|
||||
getGame().getTriggerHandler().registerActiveTrigger(this, false);
|
||||
@@ -1241,18 +1239,17 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
addAmount = 0; // As per rule 107.1b
|
||||
return 0;
|
||||
}
|
||||
final Map<String, Object> repParams = Maps.newHashMap();
|
||||
repParams.put("Affected", this);
|
||||
repParams.put("Source", source);
|
||||
repParams.put("CounterType", counterType);
|
||||
repParams.put("CounterNum", addAmount);
|
||||
repParams.put("EffectOnly", applyMultiplier);
|
||||
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(this);
|
||||
repParams.put(AbilityKey.Source, source);
|
||||
repParams.put(AbilityKey.CounterType, counterType);
|
||||
repParams.put(AbilityKey.CounterNum, addAmount);
|
||||
repParams.put(AbilityKey.EffectOnly, applyMultiplier);
|
||||
|
||||
switch (getGame().getReplacementHandler().run(ReplacementType.AddCounter, repParams)) {
|
||||
case NotReplaced:
|
||||
break;
|
||||
case Updated: {
|
||||
addAmount = (int) repParams.get("CounterNum");
|
||||
addAmount = (int) repParams.get(AbilityKey.CounterNum);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -3158,6 +3155,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
public final void addColor(final String s, final boolean addToColors, final long timestamp) {
|
||||
changedCardColors.put(timestamp, new CardColor(s, addToColors, timestamp));
|
||||
currentState.getView().updateColors(this);
|
||||
currentState.getView().updateHasChangeColors(!getChangedCardColors().isEmpty());
|
||||
}
|
||||
|
||||
public final void removeColor(final long timestampIn) {
|
||||
@@ -3165,6 +3163,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
|
||||
if (removeCol != null) {
|
||||
currentState.getView().updateColors(this);
|
||||
currentState.getView().updateHasChangeColors(!getChangedCardColors().isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3611,10 +3610,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
if (!tapped) { return; }
|
||||
|
||||
// Run Replacement effects
|
||||
final Map<String, Object> repRunParams = Maps.newHashMap();
|
||||
repRunParams.put("Affected", this);
|
||||
|
||||
if (getGame().getReplacementHandler().run(ReplacementType.Untap, repRunParams) != ReplacementResult.NotReplaced) {
|
||||
if (getGame().getReplacementHandler().run(ReplacementType.Untap, AbilityKey.mapFromAffected(this)) != ReplacementResult.NotReplaced) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5622,34 +5618,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
}
|
||||
|
||||
final Card source = sa.getHostCard();
|
||||
final MutableBoolean result = new MutableBoolean(true);
|
||||
visitKeywords(currentState, new Visitor<KeywordInterface>() {
|
||||
@Override
|
||||
public boolean visit(KeywordInterface kw) {
|
||||
switch (kw.getOriginal()) {
|
||||
case "Shroud":
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Can target CardUID_").append(getId());
|
||||
sb.append(" with spells and abilities as though it didn't have shroud.");
|
||||
if (sa.getActivatingPlayer() == null) {
|
||||
System.err.println("Unexpected behavior: SA activator was null when trying to determine if the activating player could target a card with Shroud. SA host card = " + source + ", SA = " + sa);
|
||||
result.setFalse(); // FIXME: maybe this should check by SA host card controller at this point instead?
|
||||
} else if (!sa.getActivatingPlayer().hasKeyword(sb.toString())) {
|
||||
result.setFalse();
|
||||
}
|
||||
break;
|
||||
case "CARDNAME can't be the target of spells.":
|
||||
if (sa.isSpell()) {
|
||||
result.setFalse();
|
||||
}
|
||||
break;
|
||||
}
|
||||
return result.isTrue();
|
||||
}
|
||||
});
|
||||
if (result.isFalse()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sa.isSpell()) {
|
||||
for(KeywordInterface inst : source.getKeywords()) {
|
||||
String kw = inst.getOriginal();
|
||||
|
||||
@@ -4501,7 +4501,9 @@ public class CardFactoryUtil {
|
||||
effect = "Mode$ CantTarget | Hexproof$ True | ValidCard$ Card.Self | Secondary$ True"
|
||||
+ sbValid.toString() + " | Activator$ Opponent | Description$ "
|
||||
+ sbDesc.toString() + " (" + inst.getReminderText() + ")";
|
||||
|
||||
} else if (keyword.equals("Shroud")) {
|
||||
effect = "Mode$ CantTarget | Shroud$ True | ValidCard$ Card.Self | Secondary$ True"
|
||||
+ " | Description$ Shroud (" + inst.getReminderText() + ")";
|
||||
} else if (keyword.startsWith("Strive")) {
|
||||
final String[] k = keyword.split(":");
|
||||
final String manacost = k[1];
|
||||
@@ -4693,19 +4695,30 @@ public class CardFactoryUtil {
|
||||
}
|
||||
sa.setAdventure(true);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Event$ Moved | ValidCard$ Card.Self | Origin$ Stack | ExcludeDestination$ Exile ");
|
||||
sb.append("| ValidStackSa$ Spell.Adventure | Fizzle$ False | Secondary$ True | Description$ Adventure");
|
||||
|
||||
String repeffstr = sb.toString();
|
||||
|
||||
String abExile = "DB$ ChangeZone | Defined$ Self | Origin$ Stack | Destination$ Exile | StackDescription$ None";
|
||||
|
||||
AbilitySub saExile = (AbilitySub)AbilityFactory.getAbility(abExile, card);
|
||||
SpellAbility saExile = AbilityFactory.getAbility(abExile, card);
|
||||
|
||||
String abEffect = "DB$ Effect | RememberObjects$ Self | StaticAbilities$ Play | ExileOnMoved$ Exile | Duration$ Permanent | ConditionDefined$ Self | ConditionPresent$ Card.nonCopiedSpell";
|
||||
AbilitySub saEffect = (AbilitySub)AbilityFactory.getAbility(abEffect, card);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered+nonAdventure");
|
||||
sb.append(" | AffectedZone$ Exile | Description$ You may cast the card.");
|
||||
saEffect.setSVar("Play", sb.toString());
|
||||
StringBuilder sbPlay = new StringBuilder();
|
||||
sbPlay.append("Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered+nonAdventure");
|
||||
sbPlay.append(" | AffectedZone$ Exile | Description$ You may cast the card.");
|
||||
saEffect.setSVar("Play", sbPlay.toString());
|
||||
|
||||
saExile.setSubAbility(saEffect);
|
||||
sa.appendSubAbility(saExile);
|
||||
|
||||
ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, card, true);
|
||||
re.setLayer(ReplacementLayer.Other);
|
||||
|
||||
re.setOverridingAbility(saExile);
|
||||
card.addReplacementEffect(re);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,6 +532,9 @@ public class CardState extends GameObject {
|
||||
staticAbilities.add(sa.copy(card, lki));
|
||||
}
|
||||
}
|
||||
if (lki && source.loyaltyRep != null) {
|
||||
this.loyaltyRep = source.loyaltyRep.copy(card, lki);
|
||||
}
|
||||
}
|
||||
|
||||
public CardState copy(final Card host, CardStateName name, final boolean lki) {
|
||||
|
||||
@@ -523,7 +523,6 @@ public class CardView extends GameEntityView {
|
||||
void updateChangedColorWords(Card c) {
|
||||
set(TrackableProperty.ChangedColorWords, c.getChangedTextColorWords());
|
||||
}
|
||||
|
||||
public Map<String, String> getChangedTypes() {
|
||||
return get(TrackableProperty.ChangedTypes);
|
||||
}
|
||||
@@ -706,11 +705,13 @@ public class CardView extends GameEntityView {
|
||||
// update the color only while in Game
|
||||
if (c.getGame() != null) {
|
||||
currentStateView.updateColors(currentState);
|
||||
currentStateView.updateHasChangeColors(!c.getChangedCardColors().isEmpty());
|
||||
}
|
||||
} else {
|
||||
currentStateView.updateLoyalty(currentState);
|
||||
}
|
||||
currentState.getView().updateKeywords(c, currentState); //update keywords even if state doesn't change
|
||||
currentState.getView().setOriginalColors(c); //set original Colors
|
||||
|
||||
CardState alternateState = isSplitCard && isFaceDown() ? c.getState(CardStateName.RightSplit) : c.getAlternateState();
|
||||
|
||||
@@ -840,13 +841,22 @@ public class CardView extends GameEntityView {
|
||||
public ColorSet getColors() {
|
||||
return get(TrackableProperty.Colors);
|
||||
}
|
||||
public ColorSet getOriginalColors() {
|
||||
return get(TrackableProperty.OriginalColors);
|
||||
}
|
||||
void updateColors(Card c) {
|
||||
set(TrackableProperty.Colors, c.determineColor());
|
||||
}
|
||||
void updateColors(CardState c) {
|
||||
set(TrackableProperty.Colors, ColorSet.fromMask(c.getColor()));
|
||||
}
|
||||
|
||||
void setOriginalColors(Card c) {
|
||||
set(TrackableProperty.OriginalColors, c.determineColor());
|
||||
}
|
||||
void updateHasChangeColors(boolean hasChangeColor) {
|
||||
set(TrackableProperty.HasChangedColors, hasChangeColor);
|
||||
}
|
||||
public boolean hasChangeColors() { return get(TrackableProperty.HasChangedColors); }
|
||||
public String getImageKey() {
|
||||
return getImageKey(null);
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@ package forge.game.card.token;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import forge.ImageKeys;
|
||||
import forge.StaticData;
|
||||
import forge.card.CardType;
|
||||
import forge.card.MagicColor;
|
||||
import forge.game.Game;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardFactory;
|
||||
@@ -166,19 +166,18 @@ public class TokenInfo {
|
||||
Player player = controller;
|
||||
Card proto = prototype;
|
||||
|
||||
final Map<String, Object> repParams = Maps.newHashMap();
|
||||
repParams.put("Affected", player);
|
||||
repParams.put("Token", prototype);
|
||||
repParams.put("TokenNum", multiplier);
|
||||
repParams.put("EffectOnly", applyMultiplier);
|
||||
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(player);
|
||||
repParams.put(AbilityKey.Token, prototype);
|
||||
repParams.put(AbilityKey.TokenNum, multiplier);
|
||||
repParams.put(AbilityKey.EffectOnly, applyMultiplier);
|
||||
|
||||
switch (game.getReplacementHandler().run(ReplacementType.CreateToken, repParams)) {
|
||||
case NotReplaced:
|
||||
break;
|
||||
case Updated: {
|
||||
multiplier = (int) repParams.get("TokenNum");
|
||||
player = (Player) repParams.get("Affected");
|
||||
proto = (Card) repParams.get("Token");
|
||||
multiplier = (int) repParams.get(AbilityKey.TokenNum);
|
||||
player = (Player) repParams.get(AbilityKey.Affected);
|
||||
proto = (Card) repParams.get(AbilityKey.Token);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -50,7 +50,7 @@ import java.util.Map.Entry;
|
||||
*/
|
||||
public class Combat {
|
||||
private final Player playerWhoAttacks;
|
||||
private final AttackConstraints attackConstraints;
|
||||
private AttackConstraints attackConstraints;
|
||||
// Defenders, as they are attacked by hostile forces
|
||||
private final FCollection<GameEntity> attackableEntries = new FCollection<>();
|
||||
|
||||
@@ -70,11 +70,7 @@ public class Combat {
|
||||
|
||||
public Combat(final Player attacker) {
|
||||
playerWhoAttacks = attacker;
|
||||
|
||||
// Create keys for all possible attack targets
|
||||
attackableEntries.addAll(CombatUtil.getAllPossibleDefenders(playerWhoAttacks));
|
||||
|
||||
attackConstraints = new AttackConstraints(this);
|
||||
initConstraints();
|
||||
}
|
||||
|
||||
public Combat(Combat combat, GameObjectMap map) {
|
||||
@@ -119,6 +115,13 @@ public class Combat {
|
||||
attackConstraints = new AttackConstraints(this);
|
||||
}
|
||||
|
||||
public void initConstraints() {
|
||||
attackableEntries.clear();
|
||||
// Create keys for all possible attack targets
|
||||
attackableEntries.addAll(CombatUtil.getAllPossibleDefenders(playerWhoAttacks));
|
||||
attackConstraints = new AttackConstraints(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
@@ -192,7 +192,7 @@ public class CostAdjustment {
|
||||
}
|
||||
|
||||
for (final StaticAbility stAb : reduceAbilities) {
|
||||
sumGeneric += applyReduceCostAbility(stAb, sa, cost);
|
||||
sumGeneric += applyReduceCostAbility(stAb, sa, cost, sumGeneric);
|
||||
}
|
||||
// need to reduce generic extra because of 2 hybrid mana
|
||||
cost.decreaseGenericMana(sumGeneric);
|
||||
@@ -360,7 +360,7 @@ public class CostAdjustment {
|
||||
* @param manaCost
|
||||
* a ManaCost
|
||||
*/
|
||||
private static int applyReduceCostAbility(final StaticAbility staticAbility, final SpellAbility sa, final ManaCostBeingPaid manaCost) {
|
||||
private static int applyReduceCostAbility(final StaticAbility staticAbility, final SpellAbility sa, final ManaCostBeingPaid manaCost, int sumReduced) {
|
||||
//Can't reduce zero cost
|
||||
if (manaCost.toString().equals("{0}")) {
|
||||
return 0;
|
||||
@@ -393,7 +393,7 @@ public class CostAdjustment {
|
||||
minMana = Integer.valueOf(staticAbility.getParam("MinMana"));
|
||||
}
|
||||
|
||||
final int maxReduction = Math.max(0, manaCost.getConvertedManaCost() - minMana);
|
||||
final int maxReduction = Math.max(0, manaCost.getConvertedManaCost() - minMana - sumReduced);
|
||||
if (maxReduction > 0) {
|
||||
return Math.min(value, maxReduction);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import com.google.common.collect.Lists;
|
||||
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardFactoryUtil;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.player.PlayerFactoryUtil;
|
||||
import forge.game.replacement.ReplacementEffect;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.staticability.StaticAbility;
|
||||
@@ -82,7 +84,7 @@ public abstract class KeywordInstance<T extends KeywordInstance<?>> implements K
|
||||
public final void createTraits(final Card host, final boolean intrinsic) {
|
||||
createTraits(host, intrinsic, false);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see forge.game.keyword.KeywordInterface#createTraits(forge.game.card.Card, boolean, boolean)
|
||||
@@ -125,6 +127,53 @@ public abstract class KeywordInstance<T extends KeywordInstance<?>> implements K
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see forge.game.keyword.KeywordInterface#createTraits(forge.game.player.Player)
|
||||
*/
|
||||
@Override
|
||||
public void createTraits(Player player) {
|
||||
createTraits(player, false);
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see forge.game.keyword.KeywordInterface#createTraits(forge.game.player.Player, boolean)
|
||||
*/
|
||||
@Override
|
||||
public void createTraits(Player player, boolean clear) {
|
||||
if (clear) {
|
||||
triggers.clear();
|
||||
replacements.clear();
|
||||
abilities.clear();
|
||||
staticAbilities.clear();
|
||||
}
|
||||
try {
|
||||
String msg = "KeywordInstance:createTraits: make Traits for Keyword";
|
||||
Sentry.getContext().recordBreadcrumb(
|
||||
new BreadcrumbBuilder().setMessage(msg)
|
||||
.withData("Player", player.getName()).withData("Keyword", this.original).build()
|
||||
);
|
||||
|
||||
// add Extra for debugging
|
||||
Sentry.getContext().addExtra("Player", player);
|
||||
Sentry.getContext().addExtra("Keyword", this.original);
|
||||
|
||||
PlayerFactoryUtil.addTriggerAbility(this, player);
|
||||
PlayerFactoryUtil.addReplacementEffect(this, player);
|
||||
PlayerFactoryUtil.addSpellAbility(this, player);
|
||||
PlayerFactoryUtil.addStaticAbility(this, player);
|
||||
} catch (Exception e) {
|
||||
String msg = "KeywordInstance:createTraits: failed Traits for Keyword";
|
||||
Sentry.getContext().recordBreadcrumb(
|
||||
new BreadcrumbBuilder().setMessage(msg)
|
||||
.withData("Player", player.getName()).withData("Keyword", this.original).build()
|
||||
);
|
||||
//rethrow
|
||||
throw new RuntimeException("Error in Keyword " + this.original + " for player " + player.getName(), e);
|
||||
} finally {
|
||||
// remove added extra
|
||||
Sentry.getContext().removeExtra("Player");
|
||||
Sentry.getContext().removeExtra("Keyword");
|
||||
}
|
||||
}
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see forge.game.keyword.KeywordInterface#addTrigger(forge.game.trigger.Trigger)
|
||||
|
||||
@@ -3,6 +3,7 @@ package forge.game.keyword;
|
||||
import java.util.Collection;
|
||||
|
||||
import forge.game.card.Card;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.replacement.ReplacementEffect;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.staticability.StaticAbility;
|
||||
@@ -24,6 +25,9 @@ public interface KeywordInterface extends Cloneable {
|
||||
void createTraits(final Card host, final boolean intrinsic);
|
||||
void createTraits(final Card host, final boolean intrinsic, final boolean clear);
|
||||
|
||||
void createTraits(final Player player);
|
||||
void createTraits(final Player player, final boolean clear);
|
||||
|
||||
void addTrigger(final Trigger trg);
|
||||
|
||||
void addReplacement(final ReplacementEffect trg);
|
||||
|
||||
@@ -23,6 +23,11 @@ import java.util.List;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import forge.game.card.Card;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.replacement.ReplacementEffect;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.staticability.StaticAbility;
|
||||
import forge.game.trigger.Trigger;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -131,7 +136,13 @@ public class KeywordsChange implements Cloneable {
|
||||
inst.createTraits(host, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public final void addKeywordsToPlayer(final Player player) {
|
||||
for (KeywordInterface inst : keywords.getValues()) {
|
||||
inst.createTraits(player, true);
|
||||
}
|
||||
}
|
||||
|
||||
public final boolean removeKeywordfromAdd(final String keyword) {
|
||||
return keywords.remove(keyword);
|
||||
}
|
||||
@@ -201,6 +212,47 @@ public class KeywordsChange implements Cloneable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the triggers
|
||||
*/
|
||||
public Collection<Trigger> getTriggers() {
|
||||
List<Trigger> result = Lists.newArrayList();
|
||||
for (KeywordInterface k : this.keywords.getValues()) {
|
||||
result.addAll(k.getTriggers());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* @return the replacements
|
||||
*/
|
||||
public Collection<ReplacementEffect> getReplacements() {
|
||||
List<ReplacementEffect> result = Lists.newArrayList();
|
||||
for (KeywordInterface k : this.keywords.getValues()) {
|
||||
result.addAll(k.getReplacements());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* @return the abilities
|
||||
*/
|
||||
public Collection<SpellAbility> getAbilities() {
|
||||
List<SpellAbility> result = Lists.newArrayList();
|
||||
for (KeywordInterface k : this.keywords.getValues()) {
|
||||
result.addAll(k.getAbilities());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* @return the staticAbilities
|
||||
*/
|
||||
public Collection<StaticAbility> getStaticAbilities() {
|
||||
List<StaticAbility> result = Lists.newArrayList();
|
||||
for (KeywordInterface k : this.keywords.getValues()) {
|
||||
result.addAll(k.getStaticAbilities());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
|
||||
@@ -234,7 +234,7 @@ public class ManaPool extends ManaConversionMatrix implements Iterable<Mana> {
|
||||
final Card host = sa.getHostCard();
|
||||
if (mana.addsKeywords(sa) && mana.addsKeywordsType()
|
||||
&& host.getType().hasStringType(mana.getManaAbility().getAddsKeywordsType())) {
|
||||
final long timestamp = sa.getHostCard().getGame().getNextTimestamp();
|
||||
final long timestamp = host.getGame().getNextTimestamp();
|
||||
final List<String> kws = Arrays.asList(mana.getAddedKeywords().split(" & "));
|
||||
host.addChangedCardKeywords(kws, null, false, false, timestamp);
|
||||
if (mana.addsKeywordsUntil()) {
|
||||
@@ -243,14 +243,7 @@ public class ManaPool extends ManaConversionMatrix implements Iterable<Mana> {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!kws.isEmpty()) {
|
||||
for (String kw : kws) {
|
||||
if (kw.startsWith("HIDDEN")) {
|
||||
sa.getHostCard().removeHiddenExtrinsicKeyword(kw);
|
||||
}
|
||||
}
|
||||
host.removeChangedCardKeywords(timestamp);
|
||||
}
|
||||
host.removeChangedCardKeywords(timestamp);
|
||||
host.getGame().fireEvent(new GameEventCardStatsChanged(host));
|
||||
}
|
||||
};
|
||||
@@ -261,10 +254,10 @@ public class ManaPool extends ManaConversionMatrix implements Iterable<Mana> {
|
||||
}
|
||||
}
|
||||
if (mana.addsCounters(sa)) {
|
||||
mana.getManaAbility().createETBCounters(sa.getHostCard());
|
||||
mana.getManaAbility().createETBCounters(host);
|
||||
}
|
||||
if (mana.triggersWhenSpent()) {
|
||||
mana.getManaAbility().addTriggersWhenSpent(sa, sa.getHostCard());
|
||||
mana.getManaAbility().addTriggersWhenSpent(sa, host);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -283,6 +283,7 @@ public class PhaseHandler implements java.io.Serializable {
|
||||
|
||||
case COMBAT_DECLARE_ATTACKERS:
|
||||
if (!playerTurn.hasLost()) {
|
||||
combat.initConstraints();
|
||||
game.getStack().freezeStack();
|
||||
declareAttackersTurnBasedAction();
|
||||
game.getStack().unfreezeStack();
|
||||
|
||||
@@ -44,7 +44,16 @@ public enum PhaseType {
|
||||
nameForScripts = name_for_scripts;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public final boolean phaseforUpdateField() {
|
||||
boolean result =
|
||||
((ALL_PHASES.indexOf(this) >= ALL_PHASES.indexOf(UNTAP)
|
||||
&& ALL_PHASES.indexOf(this) < ALL_PHASES.indexOf(COMBAT_FIRST_STRIKE_DAMAGE))
|
||||
|| (ALL_PHASES.indexOf(this) >= ALL_PHASES.indexOf(MAIN2)
|
||||
&& ALL_PHASES.indexOf(this) < ALL_PHASES.indexOf(CLEANUP)));
|
||||
return result;
|
||||
}
|
||||
|
||||
public final boolean isAfter(final PhaseType phase) {
|
||||
return ALL_PHASES.indexOf(this) > ALL_PHASES.indexOf(phase);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ package forge.game.player;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.*;
|
||||
|
||||
import forge.ImageKeys;
|
||||
import forge.LobbyPlayer;
|
||||
import forge.card.MagicColor;
|
||||
import forge.game.*;
|
||||
@@ -41,7 +43,6 @@ import forge.game.phase.PhaseType;
|
||||
import forge.game.replacement.ReplacementHandler;
|
||||
import forge.game.replacement.ReplacementResult;
|
||||
import forge.game.replacement.ReplacementType;
|
||||
import forge.game.spellability.AbilityActivated;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.staticability.StaticAbility;
|
||||
import forge.game.trigger.Trigger;
|
||||
@@ -155,6 +156,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
|
||||
private Card monarchEffect = null;
|
||||
private Card blessingEffect = null;
|
||||
private Card keywordEffect = null;
|
||||
|
||||
private final AchievementTracker achievementTracker = new AchievementTracker();
|
||||
private final PlayerView view;
|
||||
@@ -235,10 +237,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
}
|
||||
|
||||
// Replacement effects
|
||||
final Map<String, Object> repRunParams = Maps.newHashMap();
|
||||
repRunParams.put("Affected", this);
|
||||
|
||||
if (game.getReplacementHandler().run(ReplacementType.SetInMotion, repRunParams) != ReplacementResult.NotReplaced) {
|
||||
if (game.getReplacementHandler().run(ReplacementType.SetInMotion, AbilityKey.mapFromAffected(this)) != ReplacementResult.NotReplaced) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -403,10 +402,9 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
public final boolean gainLife(int lifeGain, final Card source, final SpellAbility sa) {
|
||||
|
||||
// Run any applicable replacement effects.
|
||||
final Map<String, Object> repParams = Maps.newHashMap();
|
||||
repParams.put("Affected", this);
|
||||
repParams.put("LifeGained", lifeGain);
|
||||
repParams.put("Source", source);
|
||||
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(this);
|
||||
repParams.put(AbilityKey.LifeGained, lifeGain);
|
||||
repParams.put(AbilityKey.Source, source);
|
||||
|
||||
if (!canGainLife()) {
|
||||
return false;
|
||||
@@ -417,8 +415,8 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
break;
|
||||
case Updated:
|
||||
// check if this is still the affected player
|
||||
if (this.equals(repParams.get("Affected"))) {
|
||||
lifeGain = (int) repParams.get("LifeGained");
|
||||
if (this.equals(repParams.get(AbilityKey.Affected))) {
|
||||
lifeGain = (int) repParams.get(AbilityKey.LifeGained);
|
||||
// negative update means life loss
|
||||
if (lifeGain < 0) {
|
||||
this.loseLife(-lifeGain);
|
||||
@@ -914,18 +912,17 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
return 0;
|
||||
}
|
||||
|
||||
final Map<String, Object> repParams = Maps.newHashMap();
|
||||
repParams.put("Affected", this);
|
||||
repParams.put("Source", source);
|
||||
repParams.put("CounterType", counterType);
|
||||
repParams.put("CounterNum", addAmount);
|
||||
repParams.put("EffectOnly", applyMultiplier);
|
||||
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(this);
|
||||
repParams.put(AbilityKey.Source, source);
|
||||
repParams.put(AbilityKey.CounterType, counterType);
|
||||
repParams.put(AbilityKey.CounterNum, addAmount);
|
||||
repParams.put(AbilityKey.EffectOnly, applyMultiplier);
|
||||
|
||||
switch (getGame().getReplacementHandler().run(ReplacementType.AddCounter, repParams)) {
|
||||
case NotReplaced:
|
||||
break;
|
||||
case Updated: {
|
||||
addAmount = (int) repParams.get("CounterNum");
|
||||
addAmount = (int) repParams.get(AbilityKey.CounterNum);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -1030,23 +1027,25 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
|
||||
public final void addChangedKeywords(final List<String> addKeywords, final List<String> removeKeywords, final Long timestamp) {
|
||||
// if the key already exists - merge entries
|
||||
KeywordsChange cks = null;
|
||||
if (changedKeywords.containsKey(timestamp)) {
|
||||
final KeywordsChange cks = changedKeywords.get(timestamp);
|
||||
getKeywordCard().removeChangedCardTraits(timestamp);
|
||||
|
||||
changedKeywords.put(timestamp, cks.merge(addKeywords, removeKeywords,
|
||||
cks.isRemoveAllKeywords(), cks.isRemoveIntrinsicKeywords()));
|
||||
updateKeywords();
|
||||
return;
|
||||
cks = changedKeywords.get(timestamp).merge(addKeywords, removeKeywords, false, false);
|
||||
} else {
|
||||
cks = new KeywordsChange(addKeywords, removeKeywords, false, false);
|
||||
}
|
||||
|
||||
changedKeywords.put(timestamp, new KeywordsChange(addKeywords, removeKeywords, false, false));
|
||||
cks.addKeywordsToPlayer(this);
|
||||
getKeywordCard().addChangedCardTraits(cks.getAbilities(), null, cks.getTriggers(), cks.getReplacements(), cks.getStaticAbilities(), false, false, false, timestamp);
|
||||
changedKeywords.put(timestamp, cks);
|
||||
updateKeywords();
|
||||
game.fireEvent(new GameEventPlayerStatsChanged(this));
|
||||
}
|
||||
|
||||
public final KeywordsChange removeChangedKeywords(final Long timestamp) {
|
||||
KeywordsChange change = changedKeywords.remove(Long.valueOf(timestamp));
|
||||
KeywordsChange change = changedKeywords.remove(timestamp);
|
||||
if (change != null) {
|
||||
getKeywordCard().removeChangedCardTraits(timestamp);
|
||||
updateKeywords();
|
||||
game.fireEvent(new GameEventPlayerStatsChanged(this));
|
||||
}
|
||||
@@ -1105,6 +1104,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
for (final Entry<Long, KeywordsChange> ck : ImmutableList.copyOf(changedKeywords.entrySet())) {
|
||||
if (ck.getValue().isEmpty() && changedKeywords.remove(ck.getKey()) != null) {
|
||||
keywordRemoved = true;
|
||||
getKeywordCard().removeChangedCardTraits(ck.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1183,33 +1183,17 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
|
||||
@Override
|
||||
public final boolean canBeTargetedBy(final SpellAbility sa) {
|
||||
if (hasKeyword("Shroud")) {
|
||||
return false;
|
||||
}
|
||||
if (hasKeyword("Hexproof")) {
|
||||
final Player a = sa.getActivatingPlayer();
|
||||
if (isOpponentOf(a)) {
|
||||
boolean cancelHexproof = false;
|
||||
for (String k : a.getKeywords()) {
|
||||
if (k.startsWith("IgnoreHexproof")) {
|
||||
String[] m = k.split(":");
|
||||
if (isValid(m[1].split(","), a, sa.getHostCard(), sa)) {
|
||||
cancelHexproof = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!cancelHexproof) {
|
||||
|
||||
// CantTarget static abilities
|
||||
for (final Card ca : getGame().getCardsIn(ZoneType.listValueOf("Battlefield,Command"))) {
|
||||
for (final StaticAbility stAb : ca.getStaticAbilities()) {
|
||||
if (stAb.applyAbility("CantTarget", this, sa)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasProtectionFrom(sa.getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (!hasKeyword("You can't be the targets of spells or activated abilities") || (!sa.isSpell() && (!(sa instanceof AbilityActivated))));
|
||||
return !hasProtectionFrom(sa.getHostCard());
|
||||
}
|
||||
|
||||
|
||||
@@ -1276,16 +1260,15 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
|
||||
public void surveil(int num, SpellAbility cause) {
|
||||
|
||||
final Map<String, Object> repParams = Maps.newHashMap();
|
||||
repParams.put("Affected", this);
|
||||
repParams.put("Source", cause);
|
||||
repParams.put("SurveilNum", num);
|
||||
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(this);
|
||||
repParams.put(AbilityKey.Source, cause);
|
||||
repParams.put(AbilityKey.SurveilNum, num);
|
||||
|
||||
switch (getGame().getReplacementHandler().run(ReplacementType.Surveil, repParams)) {
|
||||
case NotReplaced:
|
||||
break;
|
||||
case Updated: {
|
||||
num = (int) repParams.get("SurveilNum");
|
||||
num = (int) repParams.get(AbilityKey.SurveilNum);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -1346,9 +1329,8 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
final CardCollection toReveal = new CardCollection();
|
||||
|
||||
// Replacement effects
|
||||
final Map<String, Object> repRunParams = Maps.newHashMap();
|
||||
repRunParams.put("Affected", this);
|
||||
repRunParams.put("Number", n);
|
||||
final Map<AbilityKey, Object> repRunParams = AbilityKey.mapFromAffected(this);
|
||||
repRunParams.put(AbilityKey.Number, n);
|
||||
|
||||
if (game.getReplacementHandler().run(ReplacementType.DrawCards, repRunParams) != ReplacementResult.NotReplaced) {
|
||||
return drawn;
|
||||
@@ -1378,10 +1360,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
final PlayerZone library = getZone(ZoneType.Library);
|
||||
|
||||
// Replacement effects
|
||||
final Map<String, Object> repRunParams = Maps.newHashMap();
|
||||
repRunParams.put("Affected", this);
|
||||
|
||||
if (game.getReplacementHandler().run(ReplacementType.Draw, repRunParams) != ReplacementResult.NotReplaced) {
|
||||
if (game.getReplacementHandler().run(ReplacementType.Draw, AbilityKey.mapFromAffected(this)) != ReplacementResult.NotReplaced) {
|
||||
return drawn;
|
||||
}
|
||||
|
||||
@@ -1556,10 +1535,9 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
// that should not trigger other Replacement again
|
||||
if (!discardToTopOfLibrary && !discardMadness) {
|
||||
// Replacement effects
|
||||
final Map<String, Object> repRunParams = Maps.newHashMap();
|
||||
repRunParams.put("Card", c);
|
||||
repRunParams.put("Source", source);
|
||||
repRunParams.put("Affected", this);
|
||||
final Map<AbilityKey, Object> repRunParams = AbilityKey.mapFromCard(c);
|
||||
repRunParams.put(AbilityKey.Source, source);
|
||||
repRunParams.put(AbilityKey.Affected, this);
|
||||
|
||||
if (game.getReplacementHandler().run(ReplacementType.Discard, repRunParams) != ReplacementResult.NotReplaced) {
|
||||
return null;
|
||||
@@ -1861,10 +1839,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
}
|
||||
|
||||
// Replacement effects
|
||||
final Map<String, Object> runParams = Maps.newHashMap();
|
||||
runParams.put("Affected", this);
|
||||
|
||||
if (game.getReplacementHandler().run(ReplacementType.GameLoss, runParams) != ReplacementResult.NotReplaced) {
|
||||
if (game.getReplacementHandler().run(ReplacementType.GameLoss, AbilityKey.mapFromAffected(this)) != ReplacementResult.NotReplaced) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -2455,6 +2430,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
controllerCreator = ctrlr;
|
||||
controller = ctrlr;
|
||||
updateAvatar();
|
||||
updateSleeve();
|
||||
view.updateIsAI(this);
|
||||
view.updateLobbyPlayerName(this);
|
||||
}
|
||||
@@ -2464,6 +2440,10 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
view.updateAvatarCardImageKey(this);
|
||||
}
|
||||
|
||||
public void updateSleeve() {
|
||||
view.updateSleeveIndex(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a procedure using a different controller
|
||||
*/
|
||||
@@ -2985,4 +2965,26 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
|| !hasKeyword("Spells and abilities you control can't cause you to search your library.");
|
||||
|
||||
}
|
||||
|
||||
public Card getKeywordCard() {
|
||||
if (keywordEffect != null) {
|
||||
return keywordEffect;
|
||||
}
|
||||
|
||||
final PlayerZone com = getZone(ZoneType.Command);
|
||||
|
||||
keywordEffect = new Card(game.nextCardId(), null, false, game);
|
||||
keywordEffect.setImmutable(true);
|
||||
keywordEffect.setOwner(this);
|
||||
keywordEffect.setName("Keyword Effects");
|
||||
keywordEffect.setImageKey(ImageKeys.HIDDEN_CARD);
|
||||
keywordEffect.addType("Effect");
|
||||
|
||||
keywordEffect.updateStateForView();
|
||||
|
||||
com.add(keywordEffect);
|
||||
|
||||
this.updateZoneForView(com);
|
||||
return keywordEffect;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ public abstract class PlayerController {
|
||||
Map<String, Object> params);
|
||||
|
||||
public abstract boolean confirmPayment(CostPart costPart, String string, SpellAbility sa);
|
||||
public abstract ReplacementEffect chooseSingleReplacementEffect(String prompt, List<ReplacementEffect> possibleReplacers, Map<String, Object> runParams);
|
||||
public abstract ReplacementEffect chooseSingleReplacementEffect(String prompt, List<ReplacementEffect> possibleReplacers);
|
||||
public abstract String chooseProtectionType(String string, SpellAbility sa, List<String> choices);
|
||||
|
||||
// these 4 need some refining.
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package forge.game.player;
|
||||
|
||||
import forge.game.card.Card;
|
||||
import forge.game.keyword.KeywordInterface;
|
||||
import forge.game.staticability.StaticAbility;
|
||||
|
||||
public class PlayerFactoryUtil {
|
||||
|
||||
public static void addStaticAbility(final KeywordInterface inst, final Player player) {
|
||||
final Card card = player.getKeywordCard();
|
||||
String keyword = inst.getOriginal();
|
||||
String effect = null;
|
||||
if (keyword.startsWith("Hexproof")) {
|
||||
final StringBuilder sbDesc = new StringBuilder("Hexproof");
|
||||
final StringBuilder sbValid = new StringBuilder();
|
||||
|
||||
if (!keyword.equals("Hexproof")) {
|
||||
final String[] k = keyword.split(":");
|
||||
|
||||
sbDesc.append(" from ").append(k[2]);
|
||||
sbValid.append("| ValidSource$ ").append(k[1]);
|
||||
}
|
||||
|
||||
effect = "Mode$ CantTarget | Hexproof$ True | ValidPlayer$ Player.You | Secondary$ True "
|
||||
+ sbValid.toString() + " | Activator$ Opponent | EffectZone$ Command | Description$ "
|
||||
+ sbDesc.toString() + " (" + inst.getReminderText() + ")";
|
||||
} else if (keyword.equals("Shroud")) {
|
||||
effect = "Mode$ CantTarget | Shroud$ True | ValidPlayer$ Player.You | Secondary$ True "
|
||||
+ "| EffectZone$ Command | Description$ Shroud (" + inst.getReminderText() + ")";
|
||||
}
|
||||
if (effect != null) {
|
||||
StaticAbility st = new StaticAbility(effect, card);
|
||||
st.setIntrinsic(false);
|
||||
inst.addStaticAbility(st);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addTriggerAbility(final KeywordInterface inst, Player player) {
|
||||
}
|
||||
|
||||
public static void addReplacementEffect(final KeywordInterface inst, Player player) {
|
||||
}
|
||||
|
||||
public static void addSpellAbility(final KeywordInterface inst, Player player) {
|
||||
}
|
||||
}
|
||||
@@ -85,6 +85,13 @@ public class PlayerView extends GameEntityView {
|
||||
set(TrackableProperty.AvatarCardImageKey, p.getLobbyPlayer().getAvatarCardImageKey());
|
||||
}
|
||||
|
||||
public int getSleeveIndex() {
|
||||
return get(TrackableProperty.SleeveIndex);
|
||||
}
|
||||
void updateSleeveIndex(Player p) {
|
||||
set(TrackableProperty.SleeveIndex, p.getLobbyPlayer().getSleeveIndex());
|
||||
}
|
||||
|
||||
public String getCurrentPlaneName() { return get(TrackableProperty.CurrentPlane); }
|
||||
void updateCurrentPlaneName( String plane ) {
|
||||
set(TrackableProperty.CurrentPlane, plane);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package forge.game.replacement;
|
||||
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CounterType;
|
||||
import forge.game.player.Player;
|
||||
@@ -27,20 +28,20 @@ public class ReplaceAddCounter extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
|
||||
*/
|
||||
@Override
|
||||
public boolean canReplace(Map<String, Object> runParams) {
|
||||
if (((int) runParams.get("CounterNum")) <= 0) {
|
||||
public boolean canReplace(Map<AbilityKey, Object> runParams) {
|
||||
if (((int) runParams.get(AbilityKey.CounterNum)) <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hasParam("EffectOnly")) {
|
||||
final Boolean effectOnly = (Boolean) runParams.get("EffectOnly");
|
||||
final Boolean effectOnly = (Boolean) runParams.get(AbilityKey.EffectOnly);
|
||||
if (!effectOnly) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasParam("ValidCard")) {
|
||||
Object o = runParams.get("Affected");
|
||||
Object o = runParams.get(AbilityKey.Affected);
|
||||
if (!(o instanceof Card)) {
|
||||
return false;
|
||||
}
|
||||
@@ -48,7 +49,7 @@ public class ReplaceAddCounter extends ReplacementEffect {
|
||||
return false;
|
||||
}
|
||||
} else if (hasParam("ValidPlayer")) {
|
||||
Object o = runParams.get("Affected");
|
||||
Object o = runParams.get(AbilityKey.Affected);
|
||||
if (!(o instanceof Player)) {
|
||||
return false;
|
||||
}
|
||||
@@ -59,7 +60,7 @@ public class ReplaceAddCounter extends ReplacementEffect {
|
||||
|
||||
if (hasParam("ValidCounterType")) {
|
||||
String type = getParam("ValidCounterType");
|
||||
if (CounterType.getType(type) != runParams.get("CounterType")) {
|
||||
if (CounterType.getType(type) != runParams.get(AbilityKey.CounterType)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -71,14 +72,14 @@ public class ReplaceAddCounter extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
|
||||
*/
|
||||
@Override
|
||||
public void setReplacingObjects(Map<String, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject("CounterNum", runParams.get("CounterNum"));
|
||||
sa.setReplacingObject("CounterType", ((CounterType) runParams.get("CounterType")).getName());
|
||||
Object o = runParams.get("Affected");
|
||||
public void setReplacingObjects(Map<AbilityKey, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject(AbilityKey.CounterNum, runParams.get(AbilityKey.CounterNum));
|
||||
sa.setReplacingObject(AbilityKey.CounterType, ((CounterType) runParams.get(AbilityKey.CounterType)).getName());
|
||||
Object o = runParams.get(AbilityKey.Affected);
|
||||
if (o instanceof Card) {
|
||||
sa.setReplacingObject("Card", o);
|
||||
sa.setReplacingObject(AbilityKey.Card, o);
|
||||
} else if (o instanceof Player) {
|
||||
sa.setReplacingObject("Player", o);
|
||||
sa.setReplacingObject(AbilityKey.Player, o);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package forge.game.replacement;
|
||||
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
|
||||
@@ -42,15 +43,15 @@ public class ReplaceCounter extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
|
||||
*/
|
||||
@Override
|
||||
public boolean canReplace(Map<String, Object> runParams) {
|
||||
final SpellAbility spellAbility = (SpellAbility) runParams.get("TgtSA");
|
||||
public boolean canReplace(Map<AbilityKey, Object> runParams) {
|
||||
final SpellAbility spellAbility = (SpellAbility) runParams.get(AbilityKey.TgtSA);
|
||||
if (hasParam("ValidCard")) {
|
||||
if (!matchesValid(runParams.get("Affected"), getParam("ValidCard").split(","), this.getHostCard())) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidCard").split(","), this.getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (hasParam("ValidCause")) {
|
||||
if (!matchesValid(runParams.get("Cause"), getParam("ValidCause").split(","), this.getHostCard())) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.Cause), getParam("ValidCause").split(","), this.getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -67,8 +68,8 @@ public class ReplaceCounter extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
|
||||
*/
|
||||
@Override
|
||||
public void setReplacingObjects(Map<String, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject("Card", runParams.get("Affected"));
|
||||
public void setReplacingObjects(Map<AbilityKey, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject(AbilityKey.Card, runParams.get(AbilityKey.Affected));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package forge.game.replacement;
|
||||
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardFactoryUtil;
|
||||
@@ -46,49 +47,49 @@ public class ReplaceDamage extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
|
||||
*/
|
||||
@Override
|
||||
public boolean canReplace(Map<String, Object> runParams) {
|
||||
if (!(runParams.containsKey("Prevention") == (hasParam("PreventionEffect") || hasParam("Prevent")))) {
|
||||
public boolean canReplace(Map<AbilityKey, Object> runParams) {
|
||||
if (!(runParams.containsKey(AbilityKey.Prevention) == (hasParam("PreventionEffect") || hasParam("Prevent")))) {
|
||||
return false;
|
||||
}
|
||||
if (((Integer) runParams.get("DamageAmount")) == 0) {
|
||||
if (((Integer) runParams.get(AbilityKey.DamageAmount)) == 0) {
|
||||
// If no actual damage is dealt, there is nothing to replace
|
||||
return false;
|
||||
}
|
||||
if (hasParam("ValidSource")) {
|
||||
String validSource = getParam("ValidSource");
|
||||
validSource = AbilityUtils.applyAbilityTextChangeEffects(validSource, this);
|
||||
if (!matchesValid(runParams.get("DamageSource"), validSource.split(","), getHostCard())) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.DamageSource), validSource.split(","), getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (hasParam("ValidTarget")) {
|
||||
String validTarget = getParam("ValidTarget");
|
||||
validTarget = AbilityUtils.applyAbilityTextChangeEffects(validTarget, this);
|
||||
if (!matchesValid(runParams.get("Affected"), validTarget.split(","), getHostCard())) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.Affected), validTarget.split(","), getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (hasParam("ValidCause")) {
|
||||
if (!runParams.containsKey("Cause")) {
|
||||
if (!runParams.containsKey(AbilityKey.Cause)) {
|
||||
return false;
|
||||
}
|
||||
SpellAbility cause = (SpellAbility) runParams.get("Cause");
|
||||
SpellAbility cause = (SpellAbility) runParams.get(AbilityKey.Cause);
|
||||
String validCause = getParam("ValidCause");
|
||||
validCause = AbilityUtils.applyAbilityTextChangeEffects(validCause, this);
|
||||
if (!matchesValid(cause, validCause.split(","), getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
if (hasParam("CauseIsSource")) {
|
||||
if (!cause.getHostCard().equals(runParams.get("DamageSource"))) {
|
||||
if (!cause.getHostCard().equals(runParams.get(AbilityKey.DamageSource))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasParam("RelativeToSource")) {
|
||||
Card source = (Card) runParams.get("DamageSource");
|
||||
Card source = (Card) runParams.get(AbilityKey.DamageSource);
|
||||
String validRelative = getParam("RelativeToSource");
|
||||
validRelative = AbilityUtils.applyAbilityTextChangeEffects(validRelative, this);
|
||||
if (!matchesValid(runParams.get("DamageTarget"), validRelative.split(","), source)) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.DamageTarget), validRelative.split(","), source)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -103,17 +104,17 @@ public class ReplaceDamage extends ReplacementEffect {
|
||||
intoperand = CardFactoryUtil.xCount(getHostCard(), getHostCard().getSVar(operand));
|
||||
}
|
||||
|
||||
if (!Expressions.compare((Integer) runParams.get("DamageAmount"), operator, intoperand)) {
|
||||
if (!Expressions.compare((Integer) runParams.get(AbilityKey.DamageAmount), operator, intoperand)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (hasParam("IsCombat")) {
|
||||
if (getParam("IsCombat").equals("True")) {
|
||||
if (!((Boolean) runParams.get("IsCombat"))) {
|
||||
if (!((Boolean) runParams.get(AbilityKey.IsCombat))) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if ((Boolean) runParams.get("IsCombat")) {
|
||||
if ((Boolean) runParams.get(AbilityKey.IsCombat)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -149,10 +150,10 @@ public class ReplaceDamage extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
|
||||
*/
|
||||
@Override
|
||||
public void setReplacingObjects(Map<String, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject("DamageAmount", runParams.get("DamageAmount"));
|
||||
sa.setReplacingObject("Target", runParams.get("Affected"));
|
||||
sa.setReplacingObject("Source", runParams.get("DamageSource"));
|
||||
public void setReplacingObjects(Map<AbilityKey, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject(AbilityKey.DamageAmount, runParams.get(AbilityKey.DamageAmount));
|
||||
sa.setReplacingObject(AbilityKey.Target, runParams.get(AbilityKey.Affected));
|
||||
sa.setReplacingObject(AbilityKey.Source, runParams.get(AbilityKey.DamageSource));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package forge.game.replacement;
|
||||
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
|
||||
@@ -42,23 +43,23 @@ public class ReplaceDestroy extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
|
||||
*/
|
||||
@Override
|
||||
public boolean canReplace(Map<String, Object> runParams) {
|
||||
public boolean canReplace(Map<AbilityKey, Object> runParams) {
|
||||
if (hasParam("ValidPlayer")) {
|
||||
if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), getHostCard())) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (hasParam("ValidCard")) {
|
||||
Card card = (Card)runParams.get("Card");
|
||||
Card card = (Card)runParams.get(AbilityKey.Card);
|
||||
if (!matchesValid(card, getParam("ValidCard").split(","), getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
// extra check for Regeneration
|
||||
if (hasParam("Regeneration")) {
|
||||
if (!runParams.containsKey("Regeneration")) {
|
||||
if (!runParams.containsKey(AbilityKey.Regeneration)) {
|
||||
return false;
|
||||
}
|
||||
if (!(Boolean)runParams.get("Regeneration")) {
|
||||
if (!(Boolean)runParams.get(AbilityKey.Regeneration)) {
|
||||
return false;
|
||||
}
|
||||
if (!card.canBeShielded()) {
|
||||
@@ -71,7 +72,7 @@ public class ReplaceDestroy extends ReplacementEffect {
|
||||
}
|
||||
}
|
||||
if (hasParam("ValidSource")) {
|
||||
if (!matchesValid(runParams.get("Source"), getParam("ValidSource").split(","), getHostCard())) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.Source), getParam("ValidSource").split(","), getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -83,8 +84,8 @@ public class ReplaceDestroy extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
|
||||
*/
|
||||
@Override
|
||||
public void setReplacingObjects(Map<String, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject("Card", runParams.get("Card"));
|
||||
public void setReplacingObjects(Map<AbilityKey, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject(AbilityKey.Card, runParams.get(AbilityKey.Card));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package forge.game.replacement;
|
||||
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
|
||||
@@ -42,24 +43,24 @@ public class ReplaceDiscard extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
|
||||
*/
|
||||
@Override
|
||||
public boolean canReplace(Map<String, Object> runParams) {
|
||||
public boolean canReplace(Map<AbilityKey, Object> runParams) {
|
||||
if (hasParam("ValidPlayer")) {
|
||||
if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), this.getHostCard())) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), this.getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (hasParam("ValidCard")) {
|
||||
if (!matchesValid(runParams.get("Card"), getParam("ValidCard").split(","), this.getHostCard())) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.Card), getParam("ValidCard").split(","), this.getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (hasParam("ValidSource")) {
|
||||
if (!matchesValid(runParams.get("Source"), getParam("ValidSource").split(","), this.getHostCard())) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.Source), getParam("ValidSource").split(","), this.getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (hasParam("DiscardFromEffect")) {
|
||||
if (null == runParams.get("Source")) {
|
||||
if (null == runParams.get(AbilityKey.Source)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -71,10 +72,10 @@ public class ReplaceDiscard extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
|
||||
*/
|
||||
@Override
|
||||
public void setReplacingObjects(Map<String, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject("Card", runParams.get("Card"));
|
||||
sa.setReplacingObject("Player", runParams.get("Affected"));
|
||||
sa.setReplacingObject("Source", runParams.get("Source"));
|
||||
public void setReplacingObjects(Map<AbilityKey, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject(AbilityKey.Card, runParams.get(AbilityKey.Card));
|
||||
sa.setReplacingObject(AbilityKey.Player, runParams.get(AbilityKey.Affected));
|
||||
sa.setReplacingObject(AbilityKey.Source, runParams.get(AbilityKey.Source));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package forge.game.replacement;
|
||||
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.Player;
|
||||
@@ -44,14 +45,14 @@ public class ReplaceDraw extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
|
||||
*/
|
||||
@Override
|
||||
public boolean canReplace(Map<String, Object> runParams) {
|
||||
public boolean canReplace(Map<AbilityKey, Object> runParams) {
|
||||
if (hasParam("ValidPlayer")) {
|
||||
if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), this.getHostCard())) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), this.getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (hasParam("NotFirstCardInDrawStep")) {
|
||||
final Player p = (Player)runParams.get("Affected");
|
||||
final Player p = (Player)runParams.get(AbilityKey.Affected);
|
||||
if (p.numDrawnThisDrawStep() == 0
|
||||
&& this.getHostCard().getGame().getPhaseHandler().is(PhaseType.DRAW)
|
||||
&& this.getHostCard().getGame().getPhaseHandler().isPlayerTurn(p)) {
|
||||
@@ -68,7 +69,7 @@ public class ReplaceDraw extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
|
||||
*/
|
||||
@Override
|
||||
public void setReplacingObjects(Map<String, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject("Player", runParams.get("Affected"));
|
||||
public void setReplacingObjects(Map<AbilityKey, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject(AbilityKey.Player, runParams.get(AbilityKey.Affected));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package forge.game.replacement;
|
||||
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.Expressions;
|
||||
@@ -43,14 +44,14 @@ public class ReplaceDrawCards extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
|
||||
*/
|
||||
@Override
|
||||
public boolean canReplace(Map<String, Object> runParams) {
|
||||
public boolean canReplace(Map<AbilityKey, Object> runParams) {
|
||||
if (hasParam("ValidPlayer")) {
|
||||
if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), this.getHostCard())) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), this.getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (hasParam("Number")) {
|
||||
final int n = (Integer)runParams.get("Number");
|
||||
final int n = (Integer)runParams.get(AbilityKey.Number);
|
||||
String comparator = getParam("Number");
|
||||
final String operator = comparator.substring(0, 2);
|
||||
final int operandValue = Integer.parseInt(comparator.substring(2));
|
||||
@@ -68,7 +69,7 @@ public class ReplaceDrawCards extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
|
||||
*/
|
||||
@Override
|
||||
public void setReplacingObjects(Map<String, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject("Player", runParams.get("Affected"));
|
||||
public void setReplacingObjects(Map<AbilityKey, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject(AbilityKey.Player, runParams.get(AbilityKey.Affected));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package forge.game.replacement;
|
||||
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
|
||||
@@ -42,22 +43,22 @@ public class ReplaceGainLife extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
|
||||
*/
|
||||
@Override
|
||||
public boolean canReplace(Map<String, Object> runParams) {
|
||||
if (((int)runParams.get("LifeGained")) <= 0) {
|
||||
public boolean canReplace(Map<AbilityKey, Object> runParams) {
|
||||
if (((int)runParams.get(AbilityKey.LifeGained)) <= 0) {
|
||||
return false;
|
||||
}
|
||||
if (hasParam("ValidPlayer")) {
|
||||
if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), this.getHostCard())) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), this.getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (hasParam("ValidSource")) {
|
||||
if (!matchesValid(runParams.get("Source"), getParam("ValidSource").split(","), this.getHostCard())) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.Source), getParam("ValidSource").split(","), this.getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ("True".equals(getParam("SourceController"))) {
|
||||
if (runParams.get("Source") == null || !runParams.get("Affected").equals(((Card)runParams.get("Source")).getController())) {
|
||||
if (runParams.get(AbilityKey.Source) == null || !runParams.get(AbilityKey.Affected).equals(((Card)runParams.get(AbilityKey.Source)).getController())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -69,9 +70,9 @@ public class ReplaceGainLife extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
|
||||
*/
|
||||
@Override
|
||||
public void setReplacingObjects(Map<String, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject("LifeGained", runParams.get("LifeGained"));
|
||||
sa.setReplacingObject("Player", runParams.get("Affected"));
|
||||
public void setReplacingObjects(Map<AbilityKey, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject(AbilityKey.LifeGained, runParams.get(AbilityKey.LifeGained));
|
||||
sa.setReplacingObject(AbilityKey.Player, runParams.get(AbilityKey.Affected));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package forge.game.replacement;
|
||||
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
|
||||
import java.util.Map;
|
||||
@@ -24,9 +25,9 @@ public class ReplaceGameLoss extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
|
||||
*/
|
||||
@Override
|
||||
public boolean canReplace(Map<String, Object> runParams) {
|
||||
public boolean canReplace(Map<AbilityKey, Object> runParams) {
|
||||
if (hasParam("ValidPlayer")) {
|
||||
if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), this.getHostCard())) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), this.getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package forge.game.replacement;
|
||||
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
|
||||
import forge.game.player.Player;
|
||||
@@ -28,9 +29,9 @@ public class ReplaceMoved extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
|
||||
*/
|
||||
@Override
|
||||
public boolean canReplace(Map<String, Object> runParams) {
|
||||
public boolean canReplace(Map<AbilityKey, Object> runParams) {
|
||||
final Player controller = getHostCard().getController();
|
||||
final Card affected = (Card) runParams.get("Affected");
|
||||
final Card affected = (Card) runParams.get(AbilityKey.Affected);
|
||||
|
||||
if (hasParam("ValidCard")) {
|
||||
if (!matchesValid(affected, getParam("ValidCard").split(","), getHostCard())) {
|
||||
@@ -39,27 +40,27 @@ public class ReplaceMoved extends ReplacementEffect {
|
||||
}
|
||||
|
||||
if (hasParam("ValidLKI")) {
|
||||
if (!matchesValid(runParams.get("CardLKI"), getParam("ValidLKI").split(","), getHostCard())) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.CardLKI), getParam("ValidLKI").split(","), getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasParam("Origin")) {
|
||||
ZoneType zt = (ZoneType) runParams.get("Origin");
|
||||
ZoneType zt = (ZoneType) runParams.get(AbilityKey.Origin);
|
||||
if (!ZoneType.listValueOf(getParam("Origin")).contains(zt)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasParam("Destination")) {
|
||||
ZoneType zt = (ZoneType) runParams.get("Destination");
|
||||
ZoneType zt = (ZoneType) runParams.get(AbilityKey.Destination);
|
||||
if (!ZoneType.listValueOf(getParam("Destination")).contains(zt)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasParam("ExcludeDestination")) {
|
||||
ZoneType zt = (ZoneType) runParams.get("Destination");
|
||||
ZoneType zt = (ZoneType) runParams.get(AbilityKey.Destination);
|
||||
if (ZoneType.listValueOf(getParam("ExcludeDestination")).contains(zt)) {
|
||||
return false;
|
||||
}
|
||||
@@ -67,29 +68,29 @@ public class ReplaceMoved extends ReplacementEffect {
|
||||
|
||||
if (hasParam("Fizzle")) {
|
||||
// if Replacement look for Fizzle
|
||||
if (!runParams.containsKey("Fizzle")) {
|
||||
if (!runParams.containsKey(AbilityKey.Fizzle)) {
|
||||
return false;
|
||||
}
|
||||
Boolean val = (Boolean) runParams.get("Fizzle");
|
||||
Boolean val = (Boolean) runParams.get(AbilityKey.Fizzle);
|
||||
if ("True".equals(getParam("Fizzle")) != val) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasParam("ValidStackSa")) {
|
||||
if (!runParams.containsKey("StackSa")) {
|
||||
if (!runParams.containsKey(AbilityKey.StackSa)) {
|
||||
return false;
|
||||
}
|
||||
if (!((SpellAbility)runParams.get("StackSa")).isValid(getParam("ValidStackSa").split(","), getHostCard().getController(), getHostCard(), null)) {
|
||||
if (!((SpellAbility)runParams.get(AbilityKey.StackSa)).isValid(getParam("ValidStackSa").split(","), getHostCard().getController(), getHostCard(), null)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasParam("Cause")) {
|
||||
if (!runParams.containsKey("Cause")) {
|
||||
if (!runParams.containsKey(AbilityKey.Cause)) {
|
||||
return false;
|
||||
}
|
||||
SpellAbility cause = (SpellAbility) runParams.get("Cause");
|
||||
SpellAbility cause = (SpellAbility) runParams.get(AbilityKey.Cause);
|
||||
if (cause == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -99,8 +100,8 @@ public class ReplaceMoved extends ReplacementEffect {
|
||||
}
|
||||
|
||||
if (hasParam("NotCause")) {
|
||||
if (runParams.containsKey("Cause")) {
|
||||
SpellAbility cause = (SpellAbility) runParams.get("Cause");
|
||||
if (runParams.containsKey(AbilityKey.Cause)) {
|
||||
SpellAbility cause = (SpellAbility) runParams.get(AbilityKey.Cause);
|
||||
if (cause != null) {
|
||||
if (cause.isValid(getParam("NotCause").split(","), controller, getHostCard(), null)) {
|
||||
return false;
|
||||
@@ -116,10 +117,10 @@ public class ReplaceMoved extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
|
||||
*/
|
||||
@Override
|
||||
public void setReplacingObjects(Map<String, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject("Card", runParams.get("Affected"));
|
||||
sa.setReplacingObject("CardLKI", runParams.get("CardLKI"));
|
||||
sa.setReplacingObject("Cause", runParams.get("Cause"));
|
||||
public void setReplacingObjects(Map<AbilityKey, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject(AbilityKey.Card, runParams.get(AbilityKey.Affected));
|
||||
sa.setReplacingObject(AbilityKey.CardLKI, runParams.get(AbilityKey.CardLKI));
|
||||
sa.setReplacingObject(AbilityKey.Cause, runParams.get(AbilityKey.Cause));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package forge.game.replacement;
|
||||
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardFactoryUtil;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
@@ -29,10 +30,10 @@ public class ReplaceProduceMana extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
|
||||
*/
|
||||
@Override
|
||||
public boolean canReplace(Map<String, Object> runParams) {
|
||||
public boolean canReplace(Map<AbilityKey, Object> runParams) {
|
||||
//Check for tapping
|
||||
if (!hasParam("NoTapCheck")) {
|
||||
final SpellAbility manaAbility = (SpellAbility) runParams.get("AbilityMana");
|
||||
final SpellAbility manaAbility = (SpellAbility) runParams.get(AbilityKey.AbilityMana);
|
||||
if (manaAbility == null || manaAbility.getRootAbility().getPayCosts() == null || !manaAbility.getRootAbility().getPayCosts().hasTapCost()) {
|
||||
return false;
|
||||
}
|
||||
@@ -48,14 +49,14 @@ public class ReplaceProduceMana extends ReplacementEffect {
|
||||
} catch (NumberFormatException e) {
|
||||
intoperand = CardFactoryUtil.xCount(getHostCard(), getHostCard().getSVar(operand));
|
||||
}
|
||||
int manaAmount = StringUtils.countMatches((String) runParams.get("Mana"), " ") + 1;
|
||||
int manaAmount = StringUtils.countMatches((String) runParams.get(AbilityKey.Mana), " ") + 1;
|
||||
if (!Expressions.compare(manaAmount, operator, intoperand)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasParam("ValidCard")) {
|
||||
if (!matchesValid(runParams.get("Affected"), getParam("ValidCard").split(","), this.getHostCard())) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidCard").split(","), this.getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package forge.game.replacement;
|
||||
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
|
||||
import java.util.Map;
|
||||
@@ -41,9 +42,9 @@ public class ReplaceSetInMotion extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
|
||||
*/
|
||||
@Override
|
||||
public boolean canReplace(Map<String, Object> runParams) {
|
||||
public boolean canReplace(Map<AbilityKey, Object> runParams) {
|
||||
if (hasParam("ValidPlayer")) {
|
||||
if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), getHostCard())) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package forge.game.replacement;
|
||||
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
|
||||
@@ -25,13 +26,13 @@ public class ReplaceSurveil extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.Map)
|
||||
*/
|
||||
@Override
|
||||
public boolean canReplace(Map<String, Object> runParams) {
|
||||
if (((int) runParams.get("SurveilNum")) <= 0) {
|
||||
public boolean canReplace(Map<AbilityKey, Object> runParams) {
|
||||
if (((int) runParams.get(AbilityKey.SurveilNum)) <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hasParam("ValidPlayer")) {
|
||||
if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), this.getHostCard())) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), this.getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -43,9 +44,9 @@ public class ReplaceSurveil extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.Map, forge.card.spellability.SpellAbility)
|
||||
*/
|
||||
@Override
|
||||
public void setReplacingObjects(Map<String, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject("Player", runParams.get("Affected"));
|
||||
sa.setReplacingObject("SurveilNum", runParams.get("SurveilNum"));
|
||||
public void setReplacingObjects(Map<AbilityKey, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject(AbilityKey.Player, runParams.get(AbilityKey.Affected));
|
||||
sa.setReplacingObject(AbilityKey.SurveilNum, runParams.get(AbilityKey.SurveilNum));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package forge.game.replacement;
|
||||
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
|
||||
@@ -25,27 +26,27 @@ public class ReplaceToken extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.Map)
|
||||
*/
|
||||
@Override
|
||||
public boolean canReplace(Map<String, Object> runParams) {
|
||||
if (((int) runParams.get("TokenNum")) <= 0) {
|
||||
public boolean canReplace(Map<AbilityKey, Object> runParams) {
|
||||
if (((int) runParams.get(AbilityKey.TokenNum)) <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hasParam("EffectOnly")) {
|
||||
final Boolean effectOnly = (Boolean) runParams.get("EffectOnly");
|
||||
final Boolean effectOnly = (Boolean) runParams.get(AbilityKey.EffectOnly);
|
||||
if (!effectOnly) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasParam("ValidPlayer")) {
|
||||
if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), getHostCard())) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasParam("ValidToken")) {
|
||||
if (runParams.containsKey("Token")) {
|
||||
if (!matchesValid(runParams.get("Token"), getParam("ValidToken").split(","), getHostCard())) {
|
||||
if (runParams.containsKey(AbilityKey.Token)) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.Token), getParam("ValidToken").split(","), getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
@@ -61,9 +62,9 @@ public class ReplaceToken extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.Map, forge.card.spellability.SpellAbility)
|
||||
*/
|
||||
@Override
|
||||
public void setReplacingObjects(Map<String, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject("TokenNum", runParams.get("TokenNum"));
|
||||
sa.setReplacingObject("Player", runParams.get("Affected"));
|
||||
public void setReplacingObjects(Map<AbilityKey, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject(AbilityKey.TokenNum, runParams.get(AbilityKey.TokenNum));
|
||||
sa.setReplacingObject(AbilityKey.Player, runParams.get(AbilityKey.Affected));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package forge.game.replacement;
|
||||
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
|
||||
@@ -25,9 +26,9 @@ public class ReplaceTurnFaceUp extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
|
||||
*/
|
||||
@Override
|
||||
public boolean canReplace(Map<String, Object> runParams) {
|
||||
public boolean canReplace(Map<AbilityKey, Object> runParams) {
|
||||
if (hasParam("ValidCard")) {
|
||||
if (!matchesValid(runParams.get("Affected"), getParam("ValidCard").split(","), this.getHostCard())) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidCard").split(","), this.getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -38,8 +39,8 @@ public class ReplaceTurnFaceUp extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
|
||||
*/
|
||||
@Override
|
||||
public void setReplacingObjects(Map<String, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject("Card", runParams.get("Affected"));
|
||||
public void setReplacingObjects(Map<AbilityKey, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject(AbilityKey.Card, runParams.get(AbilityKey.Affected));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
package forge.game.replacement;
|
||||
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.phase.PhaseType;
|
||||
@@ -44,14 +45,14 @@ public class ReplaceUntap extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap)
|
||||
*/
|
||||
@Override
|
||||
public boolean canReplace(Map<String, Object> runParams) {
|
||||
public boolean canReplace(Map<AbilityKey, Object> runParams) {
|
||||
if (hasParam("ValidCard")) {
|
||||
if (!matchesValid(runParams.get("Affected"), getParam("ValidCard").split(","), this.getHostCard())) {
|
||||
if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidCard").split(","), this.getHostCard())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (hasParam("UntapStep")) {
|
||||
final Object o = runParams.get("Affected");
|
||||
final Object o = runParams.get(AbilityKey.Affected);
|
||||
//normally should not happen, but protect from possible crash.
|
||||
if (!(o instanceof Card)) {
|
||||
return false;
|
||||
@@ -72,8 +73,8 @@ public class ReplaceUntap extends ReplacementEffect {
|
||||
* @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility)
|
||||
*/
|
||||
@Override
|
||||
public void setReplacingObjects(Map<String, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject("Card", runParams.get("Affected"));
|
||||
public void setReplacingObjects(Map<AbilityKey, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject(AbilityKey.Card, runParams.get(AbilityKey.Affected));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package forge.game.replacement;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.game.TriggerReplacementBase;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.phase.PhaseType;
|
||||
@@ -121,7 +122,7 @@ public abstract class ReplacementEffect extends TriggerReplacementBase {
|
||||
* the run params
|
||||
* @return true, if successful
|
||||
*/
|
||||
public abstract boolean canReplace(final Map<String, Object> runParams);
|
||||
public abstract boolean canReplace (final Map<AbilityKey, Object> runParams);
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -198,13 +199,11 @@ public abstract class ReplacementEffect extends TriggerReplacementBase {
|
||||
|
||||
/**
|
||||
* Sets the replacing objects.
|
||||
*
|
||||
* @param runParams
|
||||
* @param runParams
|
||||
* the run params
|
||||
* @param spellAbility
|
||||
* the SpellAbility
|
||||
*/
|
||||
public void setReplacingObjects(final Map<String, Object> runParams, final SpellAbility spellAbility) {
|
||||
public void setReplacingObjects(final Map<AbilityKey, Object> runParams, final SpellAbility spellAbility) {
|
||||
// Should be overridden by replacers that need it.
|
||||
}
|
||||
|
||||
|
||||
@@ -21,10 +21,14 @@ import forge.card.MagicColor;
|
||||
import forge.game.Game;
|
||||
import forge.game.GameLogEntryType;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardTraitChanges;
|
||||
import forge.game.card.CardUtil;
|
||||
import forge.game.keyword.KeywordInterface;
|
||||
import forge.game.keyword.KeywordsChange;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.zone.Zone;
|
||||
@@ -42,6 +46,8 @@ import java.util.*;
|
||||
|
||||
public class ReplacementHandler {
|
||||
private final Game game;
|
||||
|
||||
private Set<ReplacementEffect> hasRun = Sets.newHashSet();
|
||||
/**
|
||||
* ReplacementHandler.
|
||||
* @param gameState
|
||||
@@ -52,57 +58,82 @@ public class ReplacementHandler {
|
||||
|
||||
//private final List<ReplacementEffect> tmpEffects = new ArrayList<ReplacementEffect>();
|
||||
|
||||
public ReplacementResult run(ReplacementType event, final Map<String, Object> runParams) {
|
||||
final Object affected = runParams.get("Affected");
|
||||
Player decider = null;
|
||||
|
||||
// Figure out who decides which of multiple replacements to apply
|
||||
// as well as whether or not to apply optional replacements.
|
||||
if (affected instanceof Player) {
|
||||
decider = (Player) affected;
|
||||
} else {
|
||||
decider = ((Card) affected).getController();
|
||||
}
|
||||
|
||||
// try out all layer
|
||||
for (ReplacementLayer layer : ReplacementLayer.values()) {
|
||||
ReplacementResult res = run(event, runParams, layer, decider);
|
||||
if (res != ReplacementResult.NotReplaced) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
return ReplacementResult.NotReplaced;
|
||||
|
||||
}
|
||||
|
||||
public List<ReplacementEffect> getReplacementList(final ReplacementType event, final Map<String, Object> runParams, final ReplacementLayer layer) {
|
||||
public List<ReplacementEffect> getReplacementList(final ReplacementType event, final Map<AbilityKey, Object> runParams, final ReplacementLayer layer) {
|
||||
|
||||
final CardCollection preList = new CardCollection();
|
||||
boolean checkAgain = false;
|
||||
Card affectedLKI = null;
|
||||
Card affectedCard = null;
|
||||
|
||||
if (ReplacementType.Moved.equals(event) && ZoneType.Battlefield.equals(runParams.get("Destination"))) {
|
||||
if (ReplacementType.Moved.equals(event) && ZoneType.Battlefield.equals(runParams.get(AbilityKey.Destination))) {
|
||||
// if it was caused by an replacement effect, use the already calculated RE list
|
||||
// otherwise the RIOT card would cause a StackError
|
||||
SpellAbility cause = (SpellAbility) runParams.get("Cause");
|
||||
SpellAbility cause = (SpellAbility) runParams.get(AbilityKey.Cause);
|
||||
if (cause != null && cause.isReplacementAbility()) {
|
||||
final ReplacementEffect re = cause.getReplacementEffect();
|
||||
// only return for same layer
|
||||
if (ReplacementType.Moved.equals(re.getMode()) && layer.equals(re.getLayer())) {
|
||||
return re.getOtherChoices();
|
||||
if (!re.getOtherChoices().isEmpty())
|
||||
return re.getOtherChoices();
|
||||
}
|
||||
}
|
||||
|
||||
// Rule 614.12 Enter the Battlefield Replacement Effects look at what the card would be on the battlefield
|
||||
affectedCard = (Card) runParams.get("Affected");
|
||||
affectedCard = (Card) runParams.get(AbilityKey.Affected);
|
||||
affectedLKI = CardUtil.getLKICopy(affectedCard);
|
||||
affectedLKI.setLastKnownZone(affectedCard.getController().getZone(ZoneType.Battlefield));
|
||||
preList.add(affectedLKI);
|
||||
game.getAction().checkStaticAbilities(false, Sets.newHashSet(affectedLKI), preList);
|
||||
checkAgain = true;
|
||||
runParams.put("Affected", affectedLKI);
|
||||
|
||||
// need to check if Intrinsic has run
|
||||
for (ReplacementEffect re : affectedLKI.getReplacementEffects()) {
|
||||
if (re.isIntrinsic() && this.hasRun.contains(re)) {
|
||||
re.setHasRun(true);
|
||||
}
|
||||
}
|
||||
|
||||
// need to check non Intrinsic
|
||||
for (Map.Entry<Long, CardTraitChanges> e : affectedLKI.getChangedCardTraits().entrySet()) {
|
||||
boolean hasRunRE = false;
|
||||
String skey = String.valueOf(e.getKey());
|
||||
|
||||
for (ReplacementEffect re : this.hasRun) {
|
||||
if (!re.isIntrinsic() && skey.equals(re.getSVar("_ReplacedTimestamp"))) {
|
||||
hasRunRE = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (ReplacementEffect re : e.getValue().getReplacements()) {
|
||||
re.setSVar("_ReplacedTimestamp", skey);
|
||||
if (hasRunRE) {
|
||||
re.setHasRun(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Map.Entry<Long, KeywordsChange> e : affectedLKI.getChangedCardKeywords().entrySet()) {
|
||||
boolean hasRunRE = false;
|
||||
String skey = String.valueOf(e.getKey());
|
||||
|
||||
for (ReplacementEffect re : this.hasRun) {
|
||||
if (!re.isIntrinsic() && skey.equals(re.getSVar("_ReplacedTimestamp"))) {
|
||||
hasRunRE = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (KeywordInterface k : e.getValue().getKeywords()) {
|
||||
for (ReplacementEffect re : k.getReplacements()) {
|
||||
re.setSVar("_ReplacedTimestamp", skey);
|
||||
if (hasRunRE) {
|
||||
re.setHasRun(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
runParams.put(AbilityKey.Affected, affectedLKI);
|
||||
}
|
||||
|
||||
final List<ReplacementEffect> possibleReplacers = Lists.newArrayList();
|
||||
@@ -157,7 +188,7 @@ public class ReplacementHandler {
|
||||
for (final ReplacementEffect re : affectedLKI.getReplacementEffects()) {
|
||||
re.setHostCard(affectedCard);
|
||||
}
|
||||
runParams.put("Affected", affectedCard);
|
||||
runParams.put(AbilityKey.Affected, affectedCard);
|
||||
}
|
||||
game.getAction().checkStaticAbilities(false);
|
||||
}
|
||||
@@ -171,20 +202,45 @@ public class ReplacementHandler {
|
||||
*
|
||||
* @param runParams
|
||||
* the run params,same as for triggers.
|
||||
* @return true if the event was replaced.
|
||||
* @return ReplacementResult, an enum that represents what happened to the replacement effect.
|
||||
*/
|
||||
public ReplacementResult run(final ReplacementType event, final Map<String, Object> runParams, final ReplacementLayer layer, final Player decider) {
|
||||
public ReplacementResult run(ReplacementType event, final Map<AbilityKey, Object> runParams) {
|
||||
final Object affected = runParams.get(AbilityKey.Affected);
|
||||
Player decider = null;
|
||||
|
||||
// Figure out who decides which of multiple replacements to apply
|
||||
// as well as whether or not to apply optional replacements.
|
||||
if (affected instanceof Player) {
|
||||
decider = (Player) affected;
|
||||
} else {
|
||||
decider = ((Card) affected).getController();
|
||||
}
|
||||
|
||||
// try out all layer
|
||||
for (ReplacementLayer layer : ReplacementLayer.values()) {
|
||||
ReplacementResult res = run(event, runParams, layer, decider);
|
||||
if (res != ReplacementResult.NotReplaced) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
return ReplacementResult.NotReplaced;
|
||||
|
||||
}
|
||||
|
||||
private ReplacementResult run(final ReplacementType event, final Map<AbilityKey, Object> runParams, final ReplacementLayer layer, final Player decider) {
|
||||
final List<ReplacementEffect> possibleReplacers = getReplacementList(event, runParams, layer);
|
||||
|
||||
if (possibleReplacers.isEmpty()) {
|
||||
return ReplacementResult.NotReplaced;
|
||||
}
|
||||
|
||||
ReplacementEffect chosenRE = decider.getController().chooseSingleReplacementEffect("Choose a replacement effect to apply first.", possibleReplacers, runParams);
|
||||
ReplacementEffect chosenRE = decider.getController().chooseSingleReplacementEffect("Choose a replacement effect to apply first.", possibleReplacers);
|
||||
|
||||
possibleReplacers.remove(chosenRE);
|
||||
|
||||
chosenRE.setHasRun(true);
|
||||
hasRun.add(chosenRE);
|
||||
chosenRE.setOtherChoices(possibleReplacers);
|
||||
ReplacementResult res = executeReplacement(runParams, chosenRE, decider, game);
|
||||
if (res == ReplacementResult.NotReplaced) {
|
||||
@@ -192,10 +248,12 @@ public class ReplacementHandler {
|
||||
res = run(event, runParams);
|
||||
}
|
||||
chosenRE.setHasRun(false);
|
||||
hasRun.remove(chosenRE);
|
||||
chosenRE.setOtherChoices(null);
|
||||
return res;
|
||||
}
|
||||
chosenRE.setHasRun(false);
|
||||
hasRun.remove(chosenRE);
|
||||
chosenRE.setOtherChoices(null);
|
||||
String message = chosenRE.toString();
|
||||
if ( !StringUtils.isEmpty(message))
|
||||
@@ -213,7 +271,7 @@ public class ReplacementHandler {
|
||||
* @param replacementEffect
|
||||
* the replacement effect to run
|
||||
*/
|
||||
private ReplacementResult executeReplacement(final Map<String, Object> runParams,
|
||||
private ReplacementResult executeReplacement(final Map<AbilityKey, Object> runParams,
|
||||
final ReplacementEffect replacementEffect, final Player decider, final Game game) {
|
||||
final Map<String, String> mapParams = replacementEffect.getMapParams();
|
||||
|
||||
@@ -237,7 +295,7 @@ public class ReplacementHandler {
|
||||
do {
|
||||
replacementEffect.setReplacingObjects(runParams, tailend);
|
||||
//set original Params to update them later
|
||||
tailend.setReplacingObject("OriginalParams", runParams);
|
||||
tailend.setReplacingObject(AbilityKey.OriginalParams, runParams);
|
||||
tailend = tailend.getSubAbility();
|
||||
} while(tailend != null);
|
||||
|
||||
@@ -248,7 +306,7 @@ public class ReplacementHandler {
|
||||
do {
|
||||
replacementEffect.setReplacingObjects(runParams, tailend);
|
||||
//set original Params to update them later
|
||||
tailend.setReplacingObject("OriginalParams", runParams);
|
||||
tailend.setReplacingObject(AbilityKey.OriginalParams, runParams);
|
||||
tailend = tailend.getSubAbility();
|
||||
} while(tailend != null);
|
||||
}
|
||||
@@ -275,7 +333,7 @@ public class ReplacementHandler {
|
||||
Card cardForUi = host.getCardForUi();
|
||||
String effectDesc = TextUtil.fastReplace(replacementEffect.toString(), "CARDNAME", cardForUi.getName());
|
||||
final String question = replacementEffect instanceof ReplaceDiscard
|
||||
? TextUtil.concatWithSpace("Apply replacement effect of", cardForUi.toString(), "to", TextUtil.addSuffix(runParams.get("Card").toString(),"?\r\n"), TextUtil.enclosedParen(effectDesc))
|
||||
? TextUtil.concatWithSpace("Apply replacement effect of", cardForUi.toString(), "to", TextUtil.addSuffix(runParams.get(AbilityKey.Card).toString(),"?\r\n"), TextUtil.enclosedParen(effectDesc))
|
||||
: TextUtil.concatWithSpace("Apply replacement effect of", TextUtil.addSuffix(cardForUi.toString(),"?\r\n"), TextUtil.enclosedParen(effectDesc));
|
||||
boolean confirmed = optDecider.getController().confirmReplacementEffect(replacementEffect, effectSA, question);
|
||||
if (!confirmed) {
|
||||
@@ -292,9 +350,9 @@ public class ReplacementHandler {
|
||||
Player player = host.getController();
|
||||
|
||||
if (mapParams.containsKey("ManaReplacement")) {
|
||||
final SpellAbility manaAb = (SpellAbility) runParams.get("AbilityMana");
|
||||
final Player player1 = (Player) runParams.get("Player");
|
||||
final String rep = (String) runParams.get("Mana");
|
||||
final SpellAbility manaAb = (SpellAbility) runParams.get(AbilityKey.AbilityMana);
|
||||
final Player player1 = (Player) runParams.get(AbilityKey.Player);
|
||||
final String rep = (String) runParams.get(AbilityKey.Mana);
|
||||
// Replaced mana type
|
||||
final Card repHost = host;
|
||||
String repType = repHost.getSVar(mapParams.get("ManaReplacement"));
|
||||
@@ -307,8 +365,8 @@ public class ReplacementHandler {
|
||||
player.getController().playSpellAbilityNoStack(effectSA, true);
|
||||
// if the spellability is a replace effect then its some new logic
|
||||
// if ReplacementResult is set in run params use that instead
|
||||
if (runParams.containsKey("ReplacementResult")) {
|
||||
return (ReplacementResult) runParams.get("ReplacementResult");
|
||||
if (runParams.containsKey(AbilityKey.ReplacementResult)) {
|
||||
return (ReplacementResult) runParams.get(AbilityKey.ReplacementResult);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -128,11 +128,10 @@ public class AbilityManaPart implements java.io.Serializable {
|
||||
final Card source = this.getSourceCard();
|
||||
final ManaPool manaPool = player.getManaPool();
|
||||
String afterReplace = applyManaReplacement(sa, produced);
|
||||
final Map<String, Object> repParams = Maps.newHashMap();
|
||||
repParams.put("Mana", afterReplace);
|
||||
repParams.put("Affected", source);
|
||||
repParams.put("Player", player);
|
||||
repParams.put("AbilityMana", sa);
|
||||
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(source);
|
||||
repParams.put(AbilityKey.Mana, afterReplace);
|
||||
repParams.put(AbilityKey.Player, player);
|
||||
repParams.put(AbilityKey.AbilityMana, sa);
|
||||
if (player.getGame().getReplacementHandler().run(ReplacementType.ProduceMana, repParams) != ReplacementResult.NotReplaced) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
|
||||
private EnumMap<AbilityKey, Object> triggeringObjects = AbilityKey.newMap();
|
||||
|
||||
private HashMap<String, Object> replacingObjects = Maps.newHashMap();
|
||||
private EnumMap<AbilityKey, Object> replacingObjects = AbilityKey.newMap();
|
||||
|
||||
private List<AbilitySub> chosenList = null;
|
||||
private CardCollection tappedForConvoke = new CardCollection();
|
||||
@@ -593,17 +593,15 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
triggerRemembered = Lists.newArrayList();
|
||||
}
|
||||
|
||||
public HashMap<String, Object> getReplacingObjects() {
|
||||
public Map<AbilityKey, Object> getReplacingObjects() {
|
||||
return replacingObjects;
|
||||
}
|
||||
public boolean hasReplacingObject(final String type) {
|
||||
return replacingObjects.containsKey(type);
|
||||
}
|
||||
public Object getReplacingObject(final String type) {
|
||||
public Object getReplacingObject(final AbilityKey type) {
|
||||
final Object res = replacingObjects.get(type);
|
||||
return res;
|
||||
}
|
||||
public void setReplacingObject(final String type, final Object o) {
|
||||
|
||||
public void setReplacingObject(final AbilityKey type, final Object o) {
|
||||
replacingObjects.put(type, o);
|
||||
}
|
||||
|
||||
|
||||
@@ -391,6 +391,23 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone
|
||||
return false;
|
||||
}
|
||||
|
||||
public final boolean applyAbility(final String mode, final Player player, final SpellAbility spellAbility) {
|
||||
// don't apply the ability if it hasn't got the right mode
|
||||
if (!getParam("Mode").equals(mode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.isSuppressed() || !this.checkConditions()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mode.equals("CantTarget")) {
|
||||
return StaticAbilityCantTarget.applyCantTargetAbility(this, player, spellAbility);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public final boolean applyAbility(String mode, Card card, CounterType type) {
|
||||
|
||||
// don't apply the ability if it hasn't got the right mode
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
@@ -22,8 +22,6 @@ import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.zone.ZoneType;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The Class StaticAbilityCantTarget.
|
||||
*/
|
||||
@@ -31,8 +29,8 @@ public class StaticAbilityCantTarget {
|
||||
|
||||
/**
|
||||
* Apply can't target ability.
|
||||
*
|
||||
* @param staticAbility
|
||||
*
|
||||
* @param st
|
||||
* the static ability
|
||||
* @param card
|
||||
* the card
|
||||
@@ -40,16 +38,19 @@ public class StaticAbilityCantTarget {
|
||||
* the spell/ability
|
||||
* @return true, if successful
|
||||
*/
|
||||
public static boolean applyCantTargetAbility(final StaticAbility staticAbility, final Card card,
|
||||
public static boolean applyCantTargetAbility(final StaticAbility st, final Card card,
|
||||
final SpellAbility spellAbility) {
|
||||
final Map<String, String> params = staticAbility.getMapParams();
|
||||
final Card hostCard = staticAbility.getHostCard();
|
||||
final Card hostCard = st.getHostCard();
|
||||
final Card source = spellAbility.getHostCard();
|
||||
final Player activator = spellAbility.getActivatingPlayer();
|
||||
|
||||
if (params.containsKey("AffectedZone")) {
|
||||
if (st.hasParam("ValidPlayer")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (st.hasParam("AffectedZone")) {
|
||||
boolean inZone = false;
|
||||
for (final ZoneType zt : ZoneType.listValueOf(params.get("AffectedZone"))) {
|
||||
for (final ZoneType zt : ZoneType.listValueOf(st.getParam("AffectedZone"))) {
|
||||
if (card.isInZone(zt)) {
|
||||
inZone = true;
|
||||
break;
|
||||
@@ -65,38 +66,14 @@ public class StaticAbilityCantTarget {
|
||||
}
|
||||
}
|
||||
|
||||
if (params.containsKey("ValidSA")
|
||||
&& !spellAbility.isValid(params.get("ValidSA").split(","), hostCard.getController(), hostCard, spellAbility)) {
|
||||
|
||||
if (st.hasParam("ValidCard")
|
||||
&& !card.isValid(st.getParam("ValidCard").split(","), hostCard.getController(), hostCard, null)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (params.containsKey("ValidCard")
|
||||
&& !card.isValid(params.get("ValidCard").split(","), hostCard.getController(), hostCard, null)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (params.containsKey("ValidSource")
|
||||
&& !source.isValid(params.get("ValidSource").split(","), hostCard.getController(), hostCard, null)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (params.containsKey("Activator") && (activator != null)
|
||||
&& !activator.isValid(params.get("Activator"), hostCard.getController(), hostCard, spellAbility)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (spellAbility.getParam("ValidTgts")!=null &&
|
||||
(params.containsKey("SourceCanOnlyTarget")
|
||||
&& (!spellAbility.getParam("ValidTgts").contains(params.get("SourceCanOnlyTarget"))
|
||||
|| spellAbility.getParam("ValidTgts").contains(","))
|
||||
|| spellAbility.getParam("ValidTgts").contains("non" + params.get("SourceCanOnlyTarget")
|
||||
)
|
||||
)
|
||||
){
|
||||
return false;
|
||||
}
|
||||
|
||||
if (params.containsKey("Hexproof") && (activator != null)) {
|
||||
if (st.hasParam("Hexproof") && (activator != null)) {
|
||||
for (String k : activator.getKeywords()) {
|
||||
if (k.startsWith("IgnoreHexproof")) {
|
||||
String[] m = k.split(":");
|
||||
@@ -106,8 +83,81 @@ public class StaticAbilityCantTarget {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (st.hasParam("Shroud") && (activator != null)) {
|
||||
for (String k : activator.getKeywords()) {
|
||||
if (k.startsWith("IgnoreShroud")) {
|
||||
String[] m = k.split(":");
|
||||
if (card.isValid(m[1].split(","), activator, source, spellAbility)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return common(st, spellAbility);
|
||||
}
|
||||
|
||||
public static boolean applyCantTargetAbility(final StaticAbility st, final Player player,
|
||||
final SpellAbility spellAbility) {
|
||||
final Card hostCard = st.getHostCard();
|
||||
final Card source = spellAbility.getHostCard();
|
||||
final Player activator = spellAbility.getActivatingPlayer();
|
||||
|
||||
if (st.hasParam("ValidCard") || st.hasParam("AffectedZone")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (st.hasParam("ValidPlayer")
|
||||
&& !player.isValid(st.getParam("ValidPlayer").split(","), hostCard.getController(), hostCard, null)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (st.hasParam("Hexproof") && (activator != null)) {
|
||||
for (String k : activator.getKeywords()) {
|
||||
if (k.startsWith("IgnoreHexproof")) {
|
||||
String[] m = k.split(":");
|
||||
if (player.isValid(m[1].split(","), activator, source, spellAbility)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return common(st, spellAbility);
|
||||
}
|
||||
|
||||
protected static boolean common(final StaticAbility st, final SpellAbility spellAbility) {
|
||||
final Card hostCard = st.getHostCard();
|
||||
final Card source = spellAbility.getHostCard();
|
||||
final Player activator = spellAbility.getActivatingPlayer();
|
||||
|
||||
if (st.hasParam("ValidSA")
|
||||
&& !spellAbility.isValid(st.getParam("ValidSA").split(","), hostCard.getController(), hostCard, spellAbility)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (st.hasParam("ValidSource")
|
||||
&& !source.isValid(st.getParam("ValidSource").split(","), hostCard.getController(), hostCard, null)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (st.hasParam("Activator") && (activator != null)
|
||||
&& !activator.isValid(st.getParam("Activator"), hostCard.getController(), hostCard, spellAbility)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (spellAbility.hasParam("ValidTgts") &&
|
||||
(st.hasParam("SourceCanOnlyTarget")
|
||||
&& (!spellAbility.getParam("ValidTgts").contains(st.getParam("SourceCanOnlyTarget"))
|
||||
|| spellAbility.getParam("ValidTgts").contains(","))
|
||||
|| spellAbility.getParam("ValidTgts").contains("non" + st.getParam("SourceCanOnlyTarget")
|
||||
)
|
||||
)
|
||||
){
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.Map;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.Localizer;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -71,7 +72,7 @@ public class TriggerAdapt extends Trigger {
|
||||
@Override
|
||||
public String getImportantStackObjects(SpellAbility sa) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Adapt: ").append(sa.getTriggeringObject(AbilityKey.Card));
|
||||
sb.append(Localizer.getInstance().getMessage("lblAdapt")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card));
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package forge.game.trigger;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.Localizer;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -83,7 +84,7 @@ public class TriggerAttached extends Trigger {
|
||||
@Override
|
||||
public String getImportantStackObjects(SpellAbility sa) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Attachee: ").append(sa.getTriggeringObject(AbilityKey.Target));
|
||||
sb.append(Localizer.getInstance().getMessage("lblAttachee")).append(": ").append(sa.getTriggeringObject(AbilityKey.Target));
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.Localizer;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -99,8 +100,8 @@ public class TriggerAttackerBlocked extends Trigger {
|
||||
@Override
|
||||
public String getImportantStackObjects(SpellAbility sa) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Attacker: ").append(sa.getTriggeringObject(AbilityKey.Attacker)).append(", ");
|
||||
sb.append("Number Blockers: ").append(sa.getTriggeringObject(AbilityKey.NumBlockers));
|
||||
sb.append(Localizer.getInstance().getMessage("lblAttacker")).append(": ").append(sa.getTriggeringObject(AbilityKey.Attacker)).append(", ");
|
||||
sb.append(Localizer.getInstance().getMessage("lblNumberBlockers")).append(": ").append(sa.getTriggeringObject(AbilityKey.NumBlockers));
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.Map;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.Localizer;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -95,8 +96,8 @@ public class TriggerAttackerBlockedByCreature extends Trigger {
|
||||
@Override
|
||||
public String getImportantStackObjects(SpellAbility sa) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Attacker: ").append(sa.getTriggeringObject(AbilityKey.Attacker)).append(", ");
|
||||
sb.append("Blocker: ").append(sa.getTriggeringObject(AbilityKey.Blocker));
|
||||
sb.append(Localizer.getInstance().getMessage("lblAttacker")).append(": ").append(sa.getTriggeringObject(AbilityKey.Attacker)).append(", ");
|
||||
sb.append(Localizer.getInstance().getMessage("lblBlocker")).append(": ").append(sa.getTriggeringObject(AbilityKey.Blocker));
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package forge.game.trigger;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.Localizer;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -77,7 +78,7 @@ public class TriggerAttackerUnblocked extends Trigger {
|
||||
@Override
|
||||
public String getImportantStackObjects(SpellAbility sa) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Attacker: ").append(sa.getTriggeringObject(AbilityKey.Attacker));
|
||||
sb.append(Localizer.getInstance().getMessage("lblAttacker")).append(": ").append(sa.getTriggeringObject(AbilityKey.Attacker));
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import forge.game.GameEntity;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.Localizer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -92,8 +93,8 @@ public class TriggerAttackerUnblockedOnce extends Trigger {
|
||||
@Override
|
||||
public String getImportantStackObjects(SpellAbility sa) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("AttackingPlayer: ").append(sa.getTriggeringObject(AbilityKey.AttackingPlayer));
|
||||
sb.append("Defenders: ").append(sa.getTriggeringObject(AbilityKey.Defenders));
|
||||
sb.append(Localizer.getInstance().getMessage("lblAttackingPlayer")).append(": ").append(sa.getTriggeringObject(AbilityKey.AttackingPlayer));
|
||||
sb.append(Localizer.getInstance().getMessage("lblDefenders")).append(": ").append(sa.getTriggeringObject(AbilityKey.Defenders));
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import forge.game.GameEntity;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.Localizer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -94,7 +95,7 @@ public class TriggerAttackersDeclared extends Trigger {
|
||||
@Override
|
||||
public String getImportantStackObjects(SpellAbility sa) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Number Attackers: ").append(sa.getTriggeringObject(AbilityKey.Attackers));
|
||||
sb.append(Localizer.getInstance().getMessage("lblNumberAttackers")).append(": ").append(sa.getTriggeringObject(AbilityKey.Attackers));
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.Localizer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -139,7 +140,7 @@ public class TriggerAttacks extends Trigger {
|
||||
public String getImportantStackObjects(SpellAbility sa) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("Attacker: ").append(sa.getTriggeringObject(AbilityKey.Attacker));
|
||||
sb.append(Localizer.getInstance().getMessage("lblAttacker")).append(": ").append(sa.getTriggeringObject(AbilityKey.Attacker));
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import forge.game.Game;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.Localizer;
|
||||
|
||||
public class TriggerBecomeMonarch extends Trigger {
|
||||
|
||||
@@ -42,7 +43,7 @@ public class TriggerBecomeMonarch extends Trigger {
|
||||
@Override
|
||||
public String getImportantStackObjects(SpellAbility sa) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Player: ").append(sa.getTriggeringObject(AbilityKey.Player)).append(", ");
|
||||
sb.append(Localizer.getInstance().getMessage("lblPlayer")).append(": ").append(sa.getTriggeringObject(AbilityKey.Player)).append(", ");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.Map;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.Localizer;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -72,7 +73,7 @@ public class TriggerBecomeMonstrous extends Trigger {
|
||||
@Override
|
||||
public String getImportantStackObjects(SpellAbility sa) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Monstrous: ").append(sa.getTriggeringObject(AbilityKey.Card));
|
||||
sb.append(Localizer.getInstance().getMessage("lblMonstrous")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card));
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package forge.game.trigger;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.Localizer;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -72,7 +73,7 @@ public class TriggerBecomeRenowned extends Trigger {
|
||||
@Override
|
||||
public String getImportantStackObjects(SpellAbility sa) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Renowned: ").append(sa.getTriggeringObject(AbilityKey.Card));
|
||||
sb.append(Localizer.getInstance().getMessage("lblRenowned")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card));
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package forge.game.trigger;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.Localizer;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -96,8 +97,8 @@ public class TriggerBecomesTarget extends Trigger {
|
||||
@Override
|
||||
public String getImportantStackObjects(SpellAbility sa) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Source: ").append(((SpellAbility) sa.getTriggeringObject(AbilityKey.SourceSA)).getHostCard()).append(", ");
|
||||
sb.append("Target: ").append(sa.getTriggeringObject(AbilityKey.Target));
|
||||
sb.append(Localizer.getInstance().getMessage("lblSource")).append(": ").append(((SpellAbility) sa.getTriggeringObject(AbilityKey.SourceSA)).getHostCard()).append(", ");
|
||||
sb.append(Localizer.getInstance().getMessage("lblTarget")).append(": ").append(sa.getTriggeringObject(AbilityKey.Target));
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import forge.game.GameObject;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.Localizer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -88,8 +89,8 @@ public class TriggerBecomesTargetOnce extends Trigger {
|
||||
@Override
|
||||
public String getImportantStackObjects(SpellAbility sa) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Source: ").append(((SpellAbility) sa.getTriggeringObject(AbilityKey.SourceSA)).getHostCard()).append(", ");
|
||||
sb.append("Targets: ").append(sa.getTriggeringObject(AbilityKey.Targets));
|
||||
sb.append(Localizer.getInstance().getMessage("lblSource")).append(": ").append(((SpellAbility) sa.getTriggeringObject(AbilityKey.SourceSA)).getHostCard()).append(", ");
|
||||
sb.append(Localizer.getInstance().getMessage("lblTargets")).append(": ").append(sa.getTriggeringObject(AbilityKey.Targets));
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package forge.game.trigger;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.Localizer;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -59,7 +60,7 @@ public class TriggerBlockersDeclared extends Trigger {
|
||||
@Override
|
||||
public String getImportantStackObjects(SpellAbility sa) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Blockers: ").append(sa.getTriggeringObject(AbilityKey.Blockers));
|
||||
sb.append(Localizer.getInstance().getMessage("lblBlockers")).append(": ").append(sa.getTriggeringObject(AbilityKey.Blockers));
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package forge.game.trigger;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.Localizer;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -96,7 +97,7 @@ public class TriggerBlocks extends Trigger {
|
||||
@Override
|
||||
public String getImportantStackObjects(SpellAbility sa) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Blocker: ").append(sa.getTriggeringObject(AbilityKey.Blocker));
|
||||
sb.append(Localizer.getInstance().getMessage("lblBlocker")).append(": ").append(sa.getTriggeringObject(AbilityKey.Blocker));
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package forge.game.trigger;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.util.Localizer;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -81,7 +82,7 @@ public class TriggerChampioned extends Trigger {
|
||||
@Override
|
||||
public String getImportantStackObjects(SpellAbility sa) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Championed: ").append(sa.getTriggeringObject(AbilityKey.Championed));
|
||||
sb.append(Localizer.getInstance().getMessage("lblChampioned")).append(": ").append(sa.getTriggeringObject(AbilityKey.Championed));
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user