ReplacementEffect: add Mode for ReplacementType

This commit is contained in:
Hans Mackowiak
2019-09-23 11:53:48 +00:00
committed by swordshine
parent d0fe0640f9
commit 14c9a8ccc3
39 changed files with 167 additions and 358 deletions

View File

@@ -48,6 +48,7 @@ import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode; import forge.game.player.PlayerActionConfirmMode;
import forge.game.replacement.ReplaceMoved; import forge.game.replacement.ReplaceMoved;
import forge.game.replacement.ReplacementEffect; import forge.game.replacement.ReplacementEffect;
import forge.game.replacement.ReplacementType;
import forge.game.spellability.*; import forge.game.spellability.*;
import forge.game.staticability.StaticAbility; import forge.game.staticability.StaticAbility;
import forge.game.trigger.Trigger; import forge.game.trigger.Trigger;
@@ -1660,13 +1661,13 @@ public class AiController {
hostCard = game.getCardState(hostCard); hostCard = game.getCardState(hostCard);
} }
if (effect.getMapParams().containsKey("AICheckSVar")) { if (effect.hasParam("AICheckSVar")) {
System.out.println("aiShouldRun?" + sa); System.out.println("aiShouldRun?" + sa);
final String svarToCheck = effect.getMapParams().get("AICheckSVar"); final String svarToCheck = effect.getMapParams().get("AICheckSVar");
String comparator = "GE"; String comparator = "GE";
int compareTo = 1; int compareTo = 1;
if (effect.getMapParams().containsKey("AISVarCompare")) { if (effect.hasParam("AISVarCompare")) {
final String fullCmp = effect.getMapParams().get("AISVarCompare"); final String fullCmp = effect.getMapParams().get("AISVarCompare");
comparator = fullCmp.substring(0, 2); comparator = fullCmp.substring(0, 2);
final String strCmpTo = fullCmp.substring(2); final String strCmpTo = fullCmp.substring(2);
@@ -1690,7 +1691,7 @@ public class AiController {
} }
System.out.println("aiShouldRun?" + left + comparator + compareTo); System.out.println("aiShouldRun?" + left + comparator + compareTo);
return Expressions.compare(left, comparator, compareTo); return Expressions.compare(left, comparator, compareTo);
} else if (effect.getMapParams().containsKey("AICheckDredge")) { } else if (effect.hasParam("AICheckDredge")) {
return player.getCardsIn(ZoneType.Library).size() > 8 || player.isCardInPlay("Laboratory Maniac"); return player.getCardsIn(ZoneType.Library).size() > 8 || player.isCardInPlay("Laboratory Maniac");
} else return sa != null && doTrigger(sa, false); } else return sa != null && doTrigger(sa, false);
@@ -2085,35 +2086,35 @@ public class AiController {
return Iterables.getFirst(list, null); return Iterables.getFirst(list, null);
} }
if (runParams.containsKey("Event")) { ReplacementType mode = Iterables.getFirst(list, null).getMode();
// replace lifegain effects
if ("GainLife".equals(runParams.get("Event"))) {
List<ReplacementEffect> noGain = filterListByAiLogic(list, "NoLife");
List<ReplacementEffect> loseLife = filterListByAiLogic(list, "LoseLife");
List<ReplacementEffect> doubleLife = filterListByAiLogic(list, "DoubleLife");
List<ReplacementEffect> lichDraw = filterListByAiLogic(list, "LichDraw");
if (!noGain.isEmpty()) { // replace lifegain effects
// no lifegain is better than lose life if (mode.equals(ReplacementType.GainLife)) {
return Iterables.getFirst(noGain, null); List<ReplacementEffect> noGain = filterListByAiLogic(list, "NoLife");
} else if (!loseLife.isEmpty()) { List<ReplacementEffect> loseLife = filterListByAiLogic(list, "LoseLife");
// lose life before double life to prevent lose double List<ReplacementEffect> doubleLife = filterListByAiLogic(list, "DoubleLife");
return Iterables.getFirst(loseLife, null); List<ReplacementEffect> lichDraw = filterListByAiLogic(list, "LichDraw");
} else if (!lichDraw.isEmpty()) {
// lich draw before double life to prevent to draw to much
return Iterables.getFirst(lichDraw, null);
} else if (!doubleLife.isEmpty()) {
// other than that, do double life
return Iterables.getFirst(doubleLife, null);
}
} else if ("DamageDone".equals(runParams.get("Event"))) {
List<ReplacementEffect> prevention = filterList(list, CardTraitPredicates.hasParam("Prevention"));
// TODO when Protection is done as ReplacementEffect do them if (!noGain.isEmpty()) {
// before normal prevention // no lifegain is better than lose life
if (!prevention.isEmpty()) { return Iterables.getFirst(noGain, null);
return Iterables.getFirst(prevention, null); } else if (!loseLife.isEmpty()) {
} // lose life before double life to prevent lose double
return Iterables.getFirst(loseLife, null);
} else if (!lichDraw.isEmpty()) {
// lich draw before double life to prevent to draw to much
return Iterables.getFirst(lichDraw, null);
} else if (!doubleLife.isEmpty()) {
// other than that, do double life
return Iterables.getFirst(doubleLife, null);
}
} else if (mode.equals(ReplacementType.DamageDone)) {
List<ReplacementEffect> prevention = filterList(list, CardTraitPredicates.hasParam("Prevention"));
// TODO when Protection is done as ReplacementEffect do them
// before normal prevention
if (!prevention.isEmpty()) {
return Iterables.getFirst(prevention, null);
} }
} }

View File

@@ -43,6 +43,7 @@ import forge.game.phase.PhaseType;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.replacement.ReplacementEffect; import forge.game.replacement.ReplacementEffect;
import forge.game.replacement.ReplacementLayer; import forge.game.replacement.ReplacementLayer;
import forge.game.replacement.ReplacementType;
import forge.game.spellability.*; import forge.game.spellability.*;
import forge.game.staticability.StaticAbility; import forge.game.staticability.StaticAbility;
import forge.game.trigger.Trigger; import forge.game.trigger.Trigger;
@@ -2849,12 +2850,13 @@ public class ComputerUtil {
// Run any applicable replacement effects. // Run any applicable replacement effects.
final Map<String, Object> repParams = Maps.newHashMap(); final Map<String, Object> repParams = Maps.newHashMap();
repParams.put("Event", "GainLife");
repParams.put("Affected", player); repParams.put("Affected", player);
repParams.put("LifeGained", 1); repParams.put("LifeGained", 1);
repParams.put("Source", source); repParams.put("Source", source);
List<ReplacementEffect> list = player.getGame().getReplacementHandler().getReplacementList(repParams, List<ReplacementEffect> list = player.getGame().getReplacementHandler().getReplacementList(
ReplacementType.GainLife,
repParams,
ReplacementLayer.Other); ReplacementLayer.Other);
if (Iterables.any(list, CardTraitPredicates.hasParam("AiLogic", "NoLife"))) { if (Iterables.any(list, CardTraitPredicates.hasParam("AiLogic", "NoLife"))) {
@@ -2879,12 +2881,13 @@ public class ComputerUtil {
// Run any applicable replacement effects. // Run any applicable replacement effects.
final Map<String, Object> repParams = Maps.newHashMap(); final Map<String, Object> repParams = Maps.newHashMap();
repParams.put("Event", "GainLife");
repParams.put("Affected", player); repParams.put("Affected", player);
repParams.put("LifeGained", n); repParams.put("LifeGained", n);
repParams.put("Source", source); repParams.put("Source", source);
List<ReplacementEffect> list = player.getGame().getReplacementHandler().getReplacementList(repParams, List<ReplacementEffect> list = player.getGame().getReplacementHandler().getReplacementList(
ReplacementType.GainLife,
repParams,
ReplacementLayer.Other); ReplacementLayer.Other);
if (Iterables.any(list, CardTraitPredicates.hasParam("AiLogic", "NoLife"))) { if (Iterables.any(list, CardTraitPredicates.hasParam("AiLogic", "NoLife"))) {

View File

@@ -42,6 +42,7 @@ import forge.game.phase.Untap;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.replacement.ReplacementEffect; import forge.game.replacement.ReplacementEffect;
import forge.game.replacement.ReplacementLayer; import forge.game.replacement.ReplacementLayer;
import forge.game.replacement.ReplacementType;
import forge.game.spellability.AbilityActivated; import forge.game.spellability.AbilityActivated;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.staticability.StaticAbility; import forge.game.staticability.StaticAbility;
@@ -2397,7 +2398,7 @@ public class ComputerUtilCombat {
for (final Card ca : game.getCardsIn(ZoneType.listValueOf("Battlefield,Command"))) { for (final Card ca : game.getCardsIn(ZoneType.listValueOf("Battlefield,Command"))) {
for (final ReplacementEffect re : ca.getReplacementEffects()) { for (final ReplacementEffect re : ca.getReplacementEffects()) {
Map<String, String> params = re.getMapParams(); Map<String, String> params = re.getMapParams();
if (!"DamageDone".equals(params.get("Event")) || !params.containsKey("PreventionEffect")) { if (!re.getMode().equals(ReplacementType.DamageDone) || !params.containsKey("PreventionEffect")) {
continue; continue;
} }
// Immortal Coil prevents the damage but has a similar negative effect // Immortal Coil prevents the damage but has a similar negative effect
@@ -2583,7 +2584,6 @@ public class ComputerUtilCombat {
// first try to replace the damage // first try to replace the damage
final Map<String, Object> repParams = Maps.newHashMap(); final Map<String, Object> repParams = Maps.newHashMap();
repParams.put("Event", "DamageDone");
repParams.put("Affected", target); repParams.put("Affected", target);
repParams.put("DamageSource", attacker); repParams.put("DamageSource", attacker);
repParams.put("DamageAmount", damage); repParams.put("DamageAmount", damage);
@@ -2591,8 +2591,8 @@ public class ComputerUtilCombat {
repParams.put("Prevention", true); repParams.put("Prevention", true);
// repParams.put("PreventMap", preventMap); // repParams.put("PreventMap", preventMap);
List<ReplacementEffect> list = game.getReplacementHandler().getReplacementList(repParams, List<ReplacementEffect> list = game.getReplacementHandler().getReplacementList(
ReplacementLayer.Other); ReplacementType.DamageDone, repParams, ReplacementLayer.Other);
return !list.isEmpty(); return !list.isEmpty();
} }

View File

@@ -25,6 +25,7 @@ import forge.game.phase.PhaseType;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.player.PlayerPredicates; import forge.game.player.PlayerPredicates;
import forge.game.replacement.ReplacementEffect; import forge.game.replacement.ReplacementEffect;
import forge.game.replacement.ReplacementType;
import forge.game.spellability.AbilityManaPart; import forge.game.spellability.AbilityManaPart;
import forge.game.spellability.AbilitySub; import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
@@ -1364,7 +1365,8 @@ public class ComputerUtilMana {
for (final Card crd : p.getAllCards()) { for (final Card crd : p.getAllCards()) {
for (final ReplacementEffect replacementEffect : crd.getReplacementEffects()) { for (final ReplacementEffect replacementEffect : crd.getReplacementEffects()) {
if (replacementEffect.requirementsCheck(game) if (replacementEffect.requirementsCheck(game)
&& replacementEffect.getMapParams().containsKey("ManaReplacement") && replacementEffect.getMode() == ReplacementType.ProduceMana
&& replacementEffect.hasParam("ManaReplacement")
&& replacementEffect.zonesCheck(game.getZoneOf(crd))) { && replacementEffect.zonesCheck(game.getZoneOf(crd))) {
replacementEffects.add(replacementEffect); replacementEffects.add(replacementEffect);
} }
@@ -1405,7 +1407,6 @@ public class ComputerUtilMana {
// setup produce mana replacement effects // setup produce mana replacement effects
final Map<String, Object> repParams = new HashMap<>(); final Map<String, Object> repParams = new HashMap<>();
repParams.put("Event", "ProduceMana");
repParams.put("Mana", mp.getOrigProduced()); repParams.put("Mana", mp.getOrigProduced());
repParams.put("Affected", sourceCard); repParams.put("Affected", sourceCard);
repParams.put("Player", ai); repParams.put("Player", ai);

View File

@@ -19,6 +19,7 @@ import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode; import forge.game.player.PlayerActionConfirmMode;
import forge.game.replacement.ReplacementEffect; import forge.game.replacement.ReplacementEffect;
import forge.game.replacement.ReplacementLayer; import forge.game.replacement.ReplacementLayer;
import forge.game.replacement.ReplacementType;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.MyRandom; import forge.util.MyRandom;
@@ -97,12 +98,11 @@ public class ManifestAi extends SpellAbilityAi {
topCopy.setManifested(true); topCopy.setManifested(true);
final Map<String, Object> repParams = Maps.newHashMap(); final Map<String, Object> repParams = Maps.newHashMap();
repParams.put("Event", "Moved");
repParams.put("Affected", topCopy); repParams.put("Affected", topCopy);
repParams.put("Origin", card.getZone().getZoneType()); repParams.put("Origin", card.getZone().getZoneType());
repParams.put("Destination", ZoneType.Battlefield); repParams.put("Destination", ZoneType.Battlefield);
repParams.put("Source", sa.getHostCard()); repParams.put("Source", sa.getHostCard());
List<ReplacementEffect> list = game.getReplacementHandler().getReplacementList(repParams, ReplacementLayer.Other); List<ReplacementEffect> list = game.getReplacementHandler().getReplacementList(ReplacementType.Moved, repParams, ReplacementLayer.Other);
if (!list.isEmpty()) { if (!list.isEmpty()) {
return false; return false;
} }

View File

@@ -35,6 +35,7 @@ import forge.game.player.GameLossReason;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.replacement.ReplacementEffect; import forge.game.replacement.ReplacementEffect;
import forge.game.replacement.ReplacementResult; import forge.game.replacement.ReplacementResult;
import forge.game.replacement.ReplacementType;
import forge.game.spellability.AbilitySub; import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityPredicates; import forge.game.spellability.SpellAbilityPredicates;
@@ -292,7 +293,6 @@ public class GameAction {
} }
Map<AbilityKey, Object> repParams = AbilityKey.newMap(); Map<AbilityKey, Object> repParams = AbilityKey.newMap();
repParams.put(AbilityKey.Event, "Moved");
repParams.put(AbilityKey.Affected, copied); repParams.put(AbilityKey.Affected, copied);
repParams.put(AbilityKey.CardLKI, lastKnownInfo); repParams.put(AbilityKey.CardLKI, lastKnownInfo);
repParams.put(AbilityKey.Cause, cause); repParams.put(AbilityKey.Cause, cause);
@@ -303,7 +303,7 @@ public class GameAction {
repParams.putAll(params); repParams.putAll(params);
} }
ReplacementResult repres = game.getReplacementHandler().run(toStringMap(repParams)); ReplacementResult repres = game.getReplacementHandler().run(ReplacementType.Moved, toStringMap(repParams));
if (repres != ReplacementResult.NotReplaced) { if (repres != ReplacementResult.NotReplaced) {
// reset failed manifested Cards back to original // reset failed manifested Cards back to original
if (c.isManifested()) { if (c.isManifested()) {
@@ -1399,13 +1399,12 @@ public class GameAction {
// Replacement effects // Replacement effects
final Map<String, Object> repRunParams = Maps.newHashMap(); final Map<String, Object> repRunParams = Maps.newHashMap();
repRunParams.put("Event", "Destroy");
repRunParams.put("Source", sa); repRunParams.put("Source", sa);
repRunParams.put("Card", c); repRunParams.put("Card", c);
repRunParams.put("Affected", c); repRunParams.put("Affected", c);
repRunParams.put("Regeneration", regenerate); repRunParams.put("Regeneration", regenerate);
if (game.getReplacementHandler().run(repRunParams) != ReplacementResult.NotReplaced) { if (game.getReplacementHandler().run(ReplacementType.Destroy, repRunParams) != ReplacementResult.NotReplaced) {
return false; return false;
} }

View File

@@ -28,6 +28,7 @@ import forge.game.card.CounterType;
import forge.game.event.GameEventCardAttachment; import forge.game.event.GameEventCardAttachment;
import forge.game.keyword.Keyword; import forge.game.keyword.Keyword;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.replacement.ReplacementType;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions; import forge.game.spellability.TargetRestrictions;
import forge.game.staticability.StaticAbility; import forge.game.staticability.StaticAbility;
@@ -115,7 +116,6 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
final CardDamageMap damageMap, final CardDamageMap preventMap, GameEntityCounterTable counterTable, final SpellAbility cause) { final CardDamageMap damageMap, final CardDamageMap preventMap, GameEntityCounterTable counterTable, final SpellAbility cause) {
// Replacement effects // Replacement effects
final Map<String, Object> repParams = Maps.newHashMap(); final Map<String, Object> repParams = Maps.newHashMap();
repParams.put("Event", "DamageDone");
repParams.put("Affected", this); repParams.put("Affected", this);
repParams.put("DamageSource", source); repParams.put("DamageSource", source);
repParams.put("DamageAmount", damage); repParams.put("DamageAmount", damage);
@@ -128,7 +128,7 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
repParams.put("Cause", cause); repParams.put("Cause", cause);
} }
switch (getGame().getReplacementHandler().run(repParams)) { switch (getGame().getReplacementHandler().run(ReplacementType.DamageDone, repParams)) {
case NotReplaced: case NotReplaced:
return damage; return damage;
case Updated: case Updated:
@@ -171,7 +171,6 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
// first try to replace the damage // first try to replace the damage
final Map<String, Object> repParams = Maps.newHashMap(); final Map<String, Object> repParams = Maps.newHashMap();
repParams.put("Event", "DamageDone");
repParams.put("Affected", this); repParams.put("Affected", this);
repParams.put("DamageSource", source); repParams.put("DamageSource", source);
repParams.put("DamageAmount", damage); repParams.put("DamageAmount", damage);
@@ -182,7 +181,7 @@ public abstract class GameEntity extends GameObject implements IIdentifiable {
repParams.put("Cause", cause); repParams.put("Cause", cause);
} }
switch (getGame().getReplacementHandler().run(repParams)) { switch (getGame().getReplacementHandler().run(ReplacementType.DamageDone, repParams)) {
case NotReplaced: case NotReplaced:
restDamage = damage; restDamage = damage;
break; break;

View File

@@ -3,6 +3,8 @@ package forge.game.ability;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.Map; import java.util.Map;
import forge.game.card.Card;
/** /**
* Keys for Ability parameter maps. * Keys for Ability parameter maps.
*/ */
@@ -112,184 +114,12 @@ public enum AbilityKey {
* @return the corresponding key if there is one or null otherwise * @return the corresponding key if there is one or null otherwise
*/ */
public static AbilityKey fromString(String s) { public static AbilityKey fromString(String s) {
switch (s) { for (AbilityKey k : values()) {
case "AbilityMana": if (k.toString().equalsIgnoreCase(s)) {
return AbilityMana; return k;
case "Activator": }
return Activator;
case "Affected":
return Affected;
case "AllVotes":
return AllVotes;
case "Amount":
return Amount;
case "Attach":
return Attach;
case "AttachSource":
return AttachSource;
case "AttachTarget":
return AttachTarget;
case "Attacked":
return Attacked;
case "Attacker":
return Attacker;
case "Attackers":
return Attackers;
case "AttackingPlayer":
return AttackingPlayer;
case "AttackedTarget":
return AttackedTarget;
case "Blocker":
return Blocker;
case "Blockers":
return Blockers;
case "CastSA":
return CastSA;
case "CastSACMC":
return CastSACMC;
case "Card":
return Card;
case "Cards":
return Cards;
case "CardLKI":
return CardLKI;
case "Cause":
return Cause;
case "Causer":
return Causer;
case "Championed":
return Championed;
case "CopySA":
return CopySA;
case "Cost":
return Cost;
case "CostStack":
return CostStack;
case "CounterAmount":
return CounterAmount;
case "CounteredSA":
return CounteredSA;
case "CounterType":
return CounterType;
case "Crew":
return Crew;
case "CumulativeUpkeepPaid":
return CumulativeUpkeepPaid;
case "CurrentCastSpells":
return CurrentCastSpells;
case "CurrentStormCount":
return CurrentStormCount;
case "DamageAmount":
return DamageAmount;
case "DamageSource":
return DamageSource;
case "DamageSources":
return DamageSources;
case "DamageTarget":
return DamageTarget;
case "DamageTargets":
return DamageTargets;
case "Defender":
return Defender;
case "Defenders":
return Defenders;
case "DefendingPlayer":
return DefendingPlayer;
case "Destination":
return Destination;
case "Devoured":
return Devoured;
case "EchoPaid":
return EchoPaid;
case "Exploited":
return Exploited;
case "Explorer":
return Explorer;
case "Event":
return Event;
case "Fighter":
return Fighter;
case "FirstTime":
return FirstTime;
case "Fizzle":
return Fizzle;
case "IsCombatDamage":
return IsCombatDamage;
case "IndividualCostPaymentInstance":
return IndividualCostPaymentInstance;
case "IsMadness":
return IsMadness;
case "LifeAmount":
return LifeAmount;
case "MonstrosityAmount":
return MonstrosityAmount;
case "NewCounterAmount":
return NewCounterAmount;
case "Num":
return Num;
case "NumBlockers":
return NumBlockers;
case "NumThisTurn":
return NumThisTurn;
case "Number":
return Number;
case "Object":
return Object;
case "Objects":
return Objects;
case "OtherAttackers":
return OtherAttackers;
case "OtherVoters":
return OtherVoters;
case "Origin":
return Origin;
case "OriginalController":
return OriginalController;
case "OriginalDefender":
return OriginalDefender;
case "PayingMana":
return PayingMana;
case "Phase":
return Phase;
case "Player":
return Player;
case "Produced":
return Produced;
case "Result":
return Result;
case "Scheme":
return Scheme;
case "Source":
return Source;
case "Sources":
return Sources;
case "SourceSA":
return SourceSA;
case "SpellAbility":
return SpellAbility;
case "SpellAbilityStackInstance":
return SpellAbilityStackInstance;
case "SpellAbilityTargetingCards":
return SpellAbilityTargetingCards;
case "StackInstance":
return StackInstance;
case "StackSa":
return StackSa;
case "StackSi":
return StackSi;
case "Target":
return Target;
case "Targets":
return Targets;
case "Transformer":
return Transformer;
case "Vehicle":
return Vehicle;
case "Won":
return Won;
default:
return null;
} }
return null;
} }
@@ -305,7 +135,7 @@ public enum AbilityKey {
return new EnumMap<>(map); return new EnumMap<>(map);
} }
public static Map<AbilityKey, Object> mapFromCard(forge.game.card.Card card) { public static Map<AbilityKey, Object> mapFromCard(Card card) {
final Map<AbilityKey, Object> runParams = newMap(); final Map<AbilityKey, Object> runParams = newMap();
runParams.put(Card, card); runParams.put(Card, card);

View File

@@ -1714,7 +1714,7 @@ public class AbilityUtils {
} }
public static final String applyAbilityTextChangeEffects(final String def, final CardTraitBase ability) { public static final String applyAbilityTextChangeEffects(final String def, final CardTraitBase ability) {
if (ability == null || !ability.isIntrinsic() || ability.getMapParams().containsKey("LockInText")) { if (ability == null || !ability.isIntrinsic() || ability.hasParam("LockInText")) {
return def; return def;
} }
return applyTextChangeEffects(def, ability.getHostCard(), false); return applyTextChangeEffects(def, ability.getHostCard(), false);
@@ -1728,7 +1728,7 @@ public class AbilityUtils {
} }
public static final String applyDescriptionTextChangeEffects(final String def, final CardTraitBase ability) { public static final String applyDescriptionTextChangeEffects(final String def, final CardTraitBase ability) {
if (ability == null || !ability.isIntrinsic() || ability.getMapParams().containsKey("LockInText")) { if (ability == null || !ability.isIntrinsic() || ability.hasParam("LockInText")) {
return def; return def;
} }
return applyTextChangeEffects(def, ability.getHostCard(), true); return applyTextChangeEffects(def, ability.getHostCard(), true);

View File

@@ -7,6 +7,7 @@ import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardFactoryUtil; import forge.game.card.CardFactoryUtil;
import forge.game.replacement.ReplacementResult; import forge.game.replacement.ReplacementResult;
import forge.game.replacement.ReplacementType;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityStackInstance; import forge.game.spellability.SpellAbilityStackInstance;
import forge.game.spellability.SpellPermanent; import forge.game.spellability.SpellPermanent;
@@ -155,11 +156,10 @@ public class CounterEffect extends SpellAbilityEffect {
final Game game = tgtSA.getActivatingPlayer().getGame(); final Game game = tgtSA.getActivatingPlayer().getGame();
// Run any applicable replacement effects. // Run any applicable replacement effects.
final Map<String, Object> repParams = Maps.newHashMap(); final Map<String, Object> repParams = Maps.newHashMap();
repParams.put("Event", "Counter");
repParams.put("TgtSA", tgtSA); repParams.put("TgtSA", tgtSA);
repParams.put("Affected", tgtSA.getHostCard()); repParams.put("Affected", tgtSA.getHostCard());
repParams.put("Cause", srcSA.getHostCard()); repParams.put("Cause", srcSA.getHostCard());
if (game.getReplacementHandler().run(repParams) != ReplacementResult.NotReplaced) { if (game.getReplacementHandler().run(ReplacementType.Counter, repParams) != ReplacementResult.NotReplaced) {
return; return;
} }
game.getStack().remove(si); game.getStack().remove(si);

View File

@@ -11,6 +11,7 @@ import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.replacement.ReplacementResult; import forge.game.replacement.ReplacementResult;
import forge.game.replacement.ReplacementType;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
public class ReplaceDamageEffect extends SpellAbilityEffect { public class ReplaceDamageEffect extends SpellAbilityEffect {
@@ -21,10 +22,12 @@ public class ReplaceDamageEffect extends SpellAbilityEffect {
final Game game = card.getGame(); final Game game = card.getGame();
// outside of Replacement Effect, unwanted result // outside of Replacement Effect, unwanted result
if (!sa.getRootAbility().isReplacementAbility()) { if (!sa.isReplacementAbility()) {
return; return;
} }
final ReplacementType event = sa.getReplacementEffect().getMode();
String varValue = sa.getParamOrDefault("VarName", "1"); String varValue = sa.getParamOrDefault("VarName", "1");
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -58,7 +61,7 @@ public class ReplaceDamageEffect extends SpellAbilityEffect {
//try to call replacementHandler with new Params //try to call replacementHandler with new Params
ReplacementResult result = game.getReplacementHandler().run(params); ReplacementResult result = game.getReplacementHandler().run(event, params);
switch (result) { switch (result) {
case NotReplaced: case NotReplaced:
case Updated: { case Updated: {

View File

@@ -13,6 +13,7 @@ import forge.game.card.Card;
import forge.game.card.token.TokenInfo; import forge.game.card.token.TokenInfo;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.replacement.ReplacementResult; import forge.game.replacement.ReplacementResult;
import forge.game.replacement.ReplacementType;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
public class ReplaceEffect extends SpellAbilityEffect { public class ReplaceEffect extends SpellAbilityEffect {
@@ -25,6 +26,7 @@ public class ReplaceEffect extends SpellAbilityEffect {
final String varName = sa.getParam("VarName"); final String varName = sa.getParam("VarName");
final String varValue = sa.getParam("VarValue"); final String varValue = sa.getParam("VarValue");
final String type = sa.getParamOrDefault("VarType", "amount"); final String type = sa.getParamOrDefault("VarType", "amount");
final ReplacementType retype = sa.getReplacementEffect().getMode();
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Map<String, Object> originalParams = (Map<String, Object>) sa.getReplacingObject("OriginalParams"); Map<String, Object> originalParams = (Map<String, Object>) sa.getReplacingObject("OriginalParams");
@@ -59,7 +61,7 @@ public class ReplaceEffect extends SpellAbilityEffect {
} }
//try to call replacementHandler with new Params //try to call replacementHandler with new Params
ReplacementResult result = game.getReplacementHandler().run(params); ReplacementResult result = game.getReplacementHandler().run(retype, params);
switch (result) { switch (result) {
case NotReplaced: case NotReplaced:
case Updated: { case Updated: {

View File

@@ -16,6 +16,7 @@ import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardDamageMap; import forge.game.card.CardDamageMap;
import forge.game.replacement.ReplacementResult; import forge.game.replacement.ReplacementResult;
import forge.game.replacement.ReplacementType;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
public class ReplaceSplitDamageEffect extends SpellAbilityEffect { public class ReplaceSplitDamageEffect extends SpellAbilityEffect {
@@ -26,10 +27,12 @@ public class ReplaceSplitDamageEffect extends SpellAbilityEffect {
final Game game = card.getGame(); final Game game = card.getGame();
// outside of Replacement Effect, unwanted result // outside of Replacement Effect, unwanted result
if (!sa.getRootAbility().isReplacementAbility()) { if (!sa.isReplacementAbility()) {
return; return;
} }
final ReplacementType event = sa.getReplacementEffect().getMode();
String varValue = sa.getParamOrDefault("VarName", "1"); String varValue = sa.getParamOrDefault("VarName", "1");
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -77,7 +80,7 @@ public class ReplaceSplitDamageEffect extends SpellAbilityEffect {
params.put("DamageAmount", dmg); params.put("DamageAmount", dmg);
//try to call replacementHandler with new Params //try to call replacementHandler with new Params
ReplacementResult result = game.getReplacementHandler().run(params); ReplacementResult result = game.getReplacementHandler().run(event, params);
switch (result) { switch (result) {
case NotReplaced: case NotReplaced:
case Updated: { case Updated: {

View File

@@ -48,6 +48,7 @@ import forge.game.player.PlayerCollection;
import forge.game.replacement.ReplaceMoved; import forge.game.replacement.ReplaceMoved;
import forge.game.replacement.ReplacementEffect; import forge.game.replacement.ReplacementEffect;
import forge.game.replacement.ReplacementResult; import forge.game.replacement.ReplacementResult;
import forge.game.replacement.ReplacementType;
import forge.game.spellability.*; import forge.game.spellability.*;
import forge.game.staticability.StaticAbility; import forge.game.staticability.StaticAbility;
import forge.game.trigger.Trigger; import forge.game.trigger.Trigger;
@@ -687,9 +688,8 @@ public class Card extends GameEntity implements Comparable<Card> {
if (result && runTriggers) { if (result && runTriggers) {
// Run replacement effects // Run replacement effects
Map<String, Object> repParams = Maps.newHashMap(); Map<String, Object> repParams = Maps.newHashMap();
repParams.put("Event", "TurnFaceUp");
repParams.put("Affected", this); repParams.put("Affected", this);
getGame().getReplacementHandler().run(repParams); getGame().getReplacementHandler().run(ReplacementType.TurnFaceUp, repParams);
// Run triggers // Run triggers
getGame().getTriggerHandler().registerActiveTrigger(this, false); getGame().getTriggerHandler().registerActiveTrigger(this, false);
@@ -1234,14 +1234,13 @@ public class Card extends GameEntity implements Comparable<Card> {
return 0; return 0;
} }
final Map<String, Object> repParams = Maps.newHashMap(); final Map<String, Object> repParams = Maps.newHashMap();
repParams.put("Event", "AddCounter");
repParams.put("Affected", this); repParams.put("Affected", this);
repParams.put("Source", source); repParams.put("Source", source);
repParams.put("CounterType", counterType); repParams.put("CounterType", counterType);
repParams.put("CounterNum", addAmount); repParams.put("CounterNum", addAmount);
repParams.put("EffectOnly", applyMultiplier); repParams.put("EffectOnly", applyMultiplier);
switch (getGame().getReplacementHandler().run(repParams)) { switch (getGame().getReplacementHandler().run(ReplacementType.AddCounter, repParams)) {
case NotReplaced: case NotReplaced:
break; break;
case Updated: { case Updated: {
@@ -3574,10 +3573,9 @@ public class Card extends GameEntity implements Comparable<Card> {
// Run Replacement effects // Run Replacement effects
final Map<String, Object> repRunParams = Maps.newHashMap(); final Map<String, Object> repRunParams = Maps.newHashMap();
repRunParams.put("Event", "Untap");
repRunParams.put("Affected", this); repRunParams.put("Affected", this);
if (getGame().getReplacementHandler().run(repRunParams) != ReplacementResult.NotReplaced) { if (getGame().getReplacementHandler().run(ReplacementType.Untap, repRunParams) != ReplacementResult.NotReplaced) {
return; return;
} }
@@ -4702,7 +4700,7 @@ public class Card extends GameEntity implements Comparable<Card> {
for (final Card ca : getGame().getCardsIn(ZoneType.Battlefield)) { for (final Card ca : getGame().getCardsIn(ZoneType.Battlefield)) {
for (final ReplacementEffect re : ca.getReplacementEffects()) { for (final ReplacementEffect re : ca.getReplacementEffects()) {
Map<String, String> params = re.getMapParams(); Map<String, String> params = re.getMapParams();
if (!"DamageDone".equals(params.get("Event")) || !params.containsKey("PreventionEffect")) { if (!re.getMode().equals(ReplacementType.DamageDone) || !params.containsKey("PreventionEffect")) {
continue; continue;
} }
if (params.containsKey("ValidSource") if (params.containsKey("ValidSource")

View File

@@ -671,12 +671,12 @@ public class CardFactory {
} }
trig.setActivatingPlayer(sa.getActivatingPlayer()); trig.setActivatingPlayer(sa.getActivatingPlayer());
if (t.getMapParams().containsKey("TriggerController")) { if (t.hasParam("TriggerController")) {
Player p = AbilityUtils.getDefinedPlayers(t.getHostCard(), t.getMapParams().get("TriggerController"), trig).get(0); Player p = AbilityUtils.getDefinedPlayers(t.getHostCard(), t.getMapParams().get("TriggerController"), trig).get(0);
trig.setActivatingPlayer(p); trig.setActivatingPlayer(p);
} }
if (t.getMapParams().containsKey("RememberController")) { if (t.hasParam("RememberController")) {
sa.getHostCard().addRemembered(sa.getActivatingPlayer()); sa.getHostCard().addRemembered(sa.getActivatingPlayer());
} }

View File

@@ -16,6 +16,7 @@ import forge.game.card.CardFactoryUtil;
import forge.game.card.CardUtil; import forge.game.card.CardUtil;
import forge.game.keyword.KeywordInterface; import forge.game.keyword.KeywordInterface;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.replacement.ReplacementType;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.item.PaperToken; import forge.item.PaperToken;
@@ -166,13 +167,12 @@ public class TokenInfo {
Card proto = prototype; Card proto = prototype;
final Map<String, Object> repParams = Maps.newHashMap(); final Map<String, Object> repParams = Maps.newHashMap();
repParams.put("Event", "CreateToken");
repParams.put("Affected", player); repParams.put("Affected", player);
repParams.put("Token", prototype); repParams.put("Token", prototype);
repParams.put("TokenNum", multiplier); repParams.put("TokenNum", multiplier);
repParams.put("EffectOnly", applyMultiplier); repParams.put("EffectOnly", applyMultiplier);
switch (game.getReplacementHandler().run(repParams)) { switch (game.getReplacementHandler().run(ReplacementType.CreateToken, repParams)) {
case NotReplaced: case NotReplaced:
break; break;
case Updated: { case Updated: {

View File

@@ -40,6 +40,7 @@ import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
import forge.game.replacement.ReplacementHandler; import forge.game.replacement.ReplacementHandler;
import forge.game.replacement.ReplacementResult; import forge.game.replacement.ReplacementResult;
import forge.game.replacement.ReplacementType;
import forge.game.spellability.AbilityActivated; import forge.game.spellability.AbilityActivated;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.staticability.StaticAbility; import forge.game.staticability.StaticAbility;
@@ -235,10 +236,9 @@ public class Player extends GameEntity implements Comparable<Player> {
// Replacement effects // Replacement effects
final Map<String, Object> repRunParams = Maps.newHashMap(); final Map<String, Object> repRunParams = Maps.newHashMap();
repRunParams.put("Event", "SetInMotion");
repRunParams.put("Affected", this); repRunParams.put("Affected", this);
if (game.getReplacementHandler().run(repRunParams) != ReplacementResult.NotReplaced) { if (game.getReplacementHandler().run(ReplacementType.SetInMotion, repRunParams) != ReplacementResult.NotReplaced) {
return; return;
} }
@@ -404,7 +404,6 @@ public class Player extends GameEntity implements Comparable<Player> {
// Run any applicable replacement effects. // Run any applicable replacement effects.
final Map<String, Object> repParams = Maps.newHashMap(); final Map<String, Object> repParams = Maps.newHashMap();
repParams.put("Event", "GainLife");
repParams.put("Affected", this); repParams.put("Affected", this);
repParams.put("LifeGained", lifeGain); repParams.put("LifeGained", lifeGain);
repParams.put("Source", source); repParams.put("Source", source);
@@ -413,7 +412,7 @@ public class Player extends GameEntity implements Comparable<Player> {
return false; return false;
} }
switch (getGame().getReplacementHandler().run(repParams)) { switch (getGame().getReplacementHandler().run(ReplacementType.GainLife, repParams)) {
case NotReplaced: case NotReplaced:
break; break;
case Updated: case Updated:
@@ -916,14 +915,13 @@ public class Player extends GameEntity implements Comparable<Player> {
} }
final Map<String, Object> repParams = Maps.newHashMap(); final Map<String, Object> repParams = Maps.newHashMap();
repParams.put("Event", "AddCounter");
repParams.put("Affected", this); repParams.put("Affected", this);
repParams.put("Source", source); repParams.put("Source", source);
repParams.put("CounterType", counterType); repParams.put("CounterType", counterType);
repParams.put("CounterNum", addAmount); repParams.put("CounterNum", addAmount);
repParams.put("EffectOnly", applyMultiplier); repParams.put("EffectOnly", applyMultiplier);
switch (getGame().getReplacementHandler().run(repParams)) { switch (getGame().getReplacementHandler().run(ReplacementType.AddCounter, repParams)) {
case NotReplaced: case NotReplaced:
break; break;
case Updated: { case Updated: {
@@ -1279,12 +1277,11 @@ public class Player extends GameEntity implements Comparable<Player> {
public void surveil(int num, SpellAbility cause) { public void surveil(int num, SpellAbility cause) {
final Map<String, Object> repParams = Maps.newHashMap(); final Map<String, Object> repParams = Maps.newHashMap();
repParams.put("Event", "Surveil");
repParams.put("Affected", this); repParams.put("Affected", this);
repParams.put("Source", cause); repParams.put("Source", cause);
repParams.put("SurveilNum", num); repParams.put("SurveilNum", num);
switch (getGame().getReplacementHandler().run(repParams)) { switch (getGame().getReplacementHandler().run(ReplacementType.Surveil, repParams)) {
case NotReplaced: case NotReplaced:
break; break;
case Updated: { case Updated: {
@@ -1350,11 +1347,10 @@ public class Player extends GameEntity implements Comparable<Player> {
// Replacement effects // Replacement effects
final Map<String, Object> repRunParams = Maps.newHashMap(); final Map<String, Object> repRunParams = Maps.newHashMap();
repRunParams.put("Event", "DrawCards");
repRunParams.put("Affected", this); repRunParams.put("Affected", this);
repRunParams.put("Number", n); repRunParams.put("Number", n);
if (game.getReplacementHandler().run(repRunParams) != ReplacementResult.NotReplaced) { if (game.getReplacementHandler().run(ReplacementType.DrawCards, repRunParams) != ReplacementResult.NotReplaced) {
return drawn; return drawn;
} }
@@ -1383,10 +1379,9 @@ public class Player extends GameEntity implements Comparable<Player> {
// Replacement effects // Replacement effects
final Map<String, Object> repRunParams = Maps.newHashMap(); final Map<String, Object> repRunParams = Maps.newHashMap();
repRunParams.put("Event", "Draw");
repRunParams.put("Affected", this); repRunParams.put("Affected", this);
if (game.getReplacementHandler().run(repRunParams) != ReplacementResult.NotReplaced) { if (game.getReplacementHandler().run(ReplacementType.Draw, repRunParams) != ReplacementResult.NotReplaced) {
return drawn; return drawn;
} }
@@ -1562,12 +1557,11 @@ public class Player extends GameEntity implements Comparable<Player> {
if (!discardToTopOfLibrary && !discardMadness) { if (!discardToTopOfLibrary && !discardMadness) {
// Replacement effects // Replacement effects
final Map<String, Object> repRunParams = Maps.newHashMap(); final Map<String, Object> repRunParams = Maps.newHashMap();
repRunParams.put("Event", "Discard");
repRunParams.put("Card", c); repRunParams.put("Card", c);
repRunParams.put("Source", source); repRunParams.put("Source", source);
repRunParams.put("Affected", this); repRunParams.put("Affected", this);
if (game.getReplacementHandler().run(repRunParams) != ReplacementResult.NotReplaced) { if (game.getReplacementHandler().run(ReplacementType.Discard, repRunParams) != ReplacementResult.NotReplaced) {
return null; return null;
} }
} }
@@ -1869,9 +1863,8 @@ public class Player extends GameEntity implements Comparable<Player> {
// Replacement effects // Replacement effects
final Map<String, Object> runParams = Maps.newHashMap(); final Map<String, Object> runParams = Maps.newHashMap();
runParams.put("Affected", this); runParams.put("Affected", this);
runParams.put("Event", "GameLoss");
if (game.getReplacementHandler().run(runParams) != ReplacementResult.NotReplaced) { if (game.getReplacementHandler().run(ReplacementType.GameLoss, runParams) != ReplacementResult.NotReplaced) {
return false; return false;
} }
} }

View File

@@ -28,7 +28,7 @@ public class ReplaceAddCounter extends ReplacementEffect {
*/ */
@Override @Override
public boolean canReplace(Map<String, Object> runParams) { public boolean canReplace(Map<String, Object> runParams) {
if (!runParams.get("Event").equals("AddCounter") || ((int) runParams.get("CounterNum")) <= 0) { if (((int) runParams.get("CounterNum")) <= 0) {
return false; return false;
} }
@@ -44,7 +44,7 @@ public class ReplaceAddCounter extends ReplacementEffect {
if (!(o instanceof Card)) { if (!(o instanceof Card)) {
return false; return false;
} }
if (!matchesValid(o, this.getMapParams().get("ValidCard").split(","), this.getHostCard())) { if (!matchesValid(o, getParam("ValidCard").split(","), this.getHostCard())) {
return false; return false;
} }
} else if (mapParams.containsKey("ValidPlayer")) { } else if (mapParams.containsKey("ValidPlayer")) {
@@ -52,13 +52,13 @@ public class ReplaceAddCounter extends ReplacementEffect {
if (!(o instanceof Player)) { if (!(o instanceof Player)) {
return false; return false;
} }
if (!matchesValid(o, this.getMapParams().get("ValidPlayer").split(","), this.getHostCard())) { if (!matchesValid(o, getParam("ValidPlayer").split(","), this.getHostCard())) {
return false; return false;
} }
} }
if (mapParams.containsKey("ValidCounterType")) { if (mapParams.containsKey("ValidCounterType")) {
String type = this.getMapParams().get("ValidCounterType"); String type = getParam("ValidCounterType");
if (CounterType.getType(type) != runParams.get("CounterType")) { if (CounterType.getType(type) != runParams.get("CounterType")) {
return false; return false;
} }

View File

@@ -44,21 +44,18 @@ public class ReplaceCounter extends ReplacementEffect {
@Override @Override
public boolean canReplace(Map<String, Object> runParams) { public boolean canReplace(Map<String, Object> runParams) {
final SpellAbility spellAbility = (SpellAbility) runParams.get("TgtSA"); final SpellAbility spellAbility = (SpellAbility) runParams.get("TgtSA");
if (!runParams.get("Event").equals("Counter")) { if (hasParam("ValidCard")) {
return false; if (!matchesValid(runParams.get("Affected"), getParam("ValidCard").split(","), this.getHostCard())) {
}
if (this.getMapParams().containsKey("ValidCard")) {
if (!matchesValid(runParams.get("Affected"), this.getMapParams().get("ValidCard").split(","), this.getHostCard())) {
return false; return false;
} }
} }
if (this.getMapParams().containsKey("ValidCause")) { if (hasParam("ValidCause")) {
if (!matchesValid(runParams.get("Cause"), this.getMapParams().get("ValidCause").split(","), this.getHostCard())) { if (!matchesValid(runParams.get("Cause"), getParam("ValidCause").split(","), this.getHostCard())) {
return false; return false;
} }
} }
if (this.getMapParams().containsKey("ValidType")) { if (hasParam("ValidType")) {
String type = this.getMapParams().get("ValidType"); String type = getParam("ValidType");
if (type.equals("Spell") && !spellAbility.isSpell()) { if (type.equals("Spell") && !spellAbility.isSpell()) {
return false; return false;
} }

View File

@@ -47,9 +47,6 @@ public class ReplaceDamage extends ReplacementEffect {
*/ */
@Override @Override
public boolean canReplace(Map<String, Object> runParams) { public boolean canReplace(Map<String, Object> runParams) {
if (!runParams.get("Event").equals("DamageDone")) {
return false;
}
if (!(runParams.containsKey("Prevention") == (hasParam("PreventionEffect") || hasParam("Prevent")))) { if (!(runParams.containsKey("Prevention") == (hasParam("PreventionEffect") || hasParam("Prevent")))) {
return false; return false;
} }

View File

@@ -43,9 +43,6 @@ public class ReplaceDestroy extends ReplacementEffect {
*/ */
@Override @Override
public boolean canReplace(Map<String, Object> runParams) { public boolean canReplace(Map<String, Object> runParams) {
if (!runParams.get("Event").equals("Destroy")) {
return false;
}
if (hasParam("ValidPlayer")) { if (hasParam("ValidPlayer")) {
if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), getHostCard())) { if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), getHostCard())) {
return false; return false;

View File

@@ -43,25 +43,22 @@ public class ReplaceDiscard extends ReplacementEffect {
*/ */
@Override @Override
public boolean canReplace(Map<String, Object> runParams) { public boolean canReplace(Map<String, Object> runParams) {
if (!runParams.get("Event").equals("Discard")) { if (hasParam("ValidPlayer")) {
return false; if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), this.getHostCard())) {
}
if (this.getMapParams().containsKey("ValidPlayer")) {
if (!matchesValid(runParams.get("Affected"), this.getMapParams().get("ValidPlayer").split(","), this.getHostCard())) {
return false; return false;
} }
} }
if (this.getMapParams().containsKey("ValidCard")) { if (hasParam("ValidCard")) {
if (!matchesValid(runParams.get("Card"), this.getMapParams().get("ValidCard").split(","), this.getHostCard())) { if (!matchesValid(runParams.get("Card"), getParam("ValidCard").split(","), this.getHostCard())) {
return false; return false;
} }
} }
if (this.getMapParams().containsKey("ValidSource")) { if (hasParam("ValidSource")) {
if (!matchesValid(runParams.get("Source"), this.getMapParams().get("ValidSource").split(","), this.getHostCard())) { if (!matchesValid(runParams.get("Source"), getParam("ValidSource").split(","), this.getHostCard())) {
return false; return false;
} }
} }
if (this.getMapParams().containsKey("DiscardFromEffect")) { if (hasParam("DiscardFromEffect")) {
if (null == runParams.get("Source")) { if (null == runParams.get("Source")) {
return false; return false;
} }

View File

@@ -45,15 +45,12 @@ public class ReplaceDraw extends ReplacementEffect {
*/ */
@Override @Override
public boolean canReplace(Map<String, Object> runParams) { public boolean canReplace(Map<String, Object> runParams) {
if (!runParams.get("Event").equals("Draw")) { if (hasParam("ValidPlayer")) {
return false; if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), this.getHostCard())) {
}
if (this.getMapParams().containsKey("ValidPlayer")) {
if (!matchesValid(runParams.get("Affected"), this.getMapParams().get("ValidPlayer").split(","), this.getHostCard())) {
return false; return false;
} }
} }
if (this.getMapParams().containsKey("NotFirstCardInDrawStep")) { if (hasParam("NotFirstCardInDrawStep")) {
final Player p = (Player)runParams.get("Affected"); final Player p = (Player)runParams.get("Affected");
if (p.numDrawnThisDrawStep() == 0 if (p.numDrawnThisDrawStep() == 0
&& this.getHostCard().getGame().getPhaseHandler().is(PhaseType.DRAW) && this.getHostCard().getGame().getPhaseHandler().is(PhaseType.DRAW)

View File

@@ -44,17 +44,14 @@ public class ReplaceDrawCards extends ReplacementEffect {
*/ */
@Override @Override
public boolean canReplace(Map<String, Object> runParams) { public boolean canReplace(Map<String, Object> runParams) {
if (!runParams.get("Event").equals("DrawCards")) { if (hasParam("ValidPlayer")) {
return false; if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), this.getHostCard())) {
}
if (this.getMapParams().containsKey("ValidPlayer")) {
if (!matchesValid(runParams.get("Affected"), this.getMapParams().get("ValidPlayer").split(","), this.getHostCard())) {
return false; return false;
} }
} }
if (this.getMapParams().containsKey("Number")) { if (hasParam("Number")) {
final int n = (Integer)runParams.get("Number"); final int n = (Integer)runParams.get("Number");
String comparator = this.getMapParams().get("Number"); String comparator = getParam("Number");
final String operator = comparator.substring(0, 2); final String operator = comparator.substring(0, 2);
final int operandValue = Integer.parseInt(comparator.substring(2)); final int operandValue = Integer.parseInt(comparator.substring(2));
if (!Expressions.compare(n, operator, operandValue)) { if (!Expressions.compare(n, operator, operandValue)) {

View File

@@ -43,20 +43,20 @@ public class ReplaceGainLife extends ReplacementEffect {
*/ */
@Override @Override
public boolean canReplace(Map<String, Object> runParams) { public boolean canReplace(Map<String, Object> runParams) {
if (!runParams.get("Event").equals("GainLife") || ((int)runParams.get("LifeGained")) <= 0) { if (((int)runParams.get("LifeGained")) <= 0) {
return false; return false;
} }
if (this.getMapParams().containsKey("ValidPlayer")) { if (hasParam("ValidPlayer")) {
if (!matchesValid(runParams.get("Affected"), this.getMapParams().get("ValidPlayer").split(","), this.getHostCard())) { if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), this.getHostCard())) {
return false; return false;
} }
} }
if (this.getMapParams().containsKey("ValidSource")) { if (hasParam("ValidSource")) {
if (!matchesValid(runParams.get("Source"), this.getMapParams().get("ValidSource").split(","), this.getHostCard())) { if (!matchesValid(runParams.get("Source"), getParam("ValidSource").split(","), this.getHostCard())) {
return false; return false;
} }
} }
if ("True".equals(this.getMapParams().get("SourceController"))) { if ("True".equals(getParam("SourceController"))) {
if (runParams.get("Source") == null || !runParams.get("Affected").equals(((Card)runParams.get("Source")).getController())) { if (runParams.get("Source") == null || !runParams.get("Affected").equals(((Card)runParams.get("Source")).getController())) {
return false; return false;
} }

View File

@@ -25,11 +25,8 @@ public class ReplaceGameLoss extends ReplacementEffect {
*/ */
@Override @Override
public boolean canReplace(Map<String, Object> runParams) { public boolean canReplace(Map<String, Object> runParams) {
if (!runParams.get("Event").equals("GameLoss")) { if (hasParam("ValidPlayer")) {
return false; if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), this.getHostCard())) {
}
if (this.getMapParams().containsKey("ValidPlayer")) {
if (!matchesValid(runParams.get("Affected"), this.getMapParams().get("ValidPlayer").split(","), this.getHostCard())) {
return false; return false;
} }
} }

View File

@@ -29,9 +29,6 @@ public class ReplaceMoved extends ReplacementEffect {
*/ */
@Override @Override
public boolean canReplace(Map<String, Object> runParams) { public boolean canReplace(Map<String, Object> runParams) {
if (!runParams.get("Event").equals("Moved")) {
return false;
}
final Player controller = getHostCard().getController(); final Player controller = getHostCard().getController();
final Card affected = (Card) runParams.get("Affected"); final Card affected = (Card) runParams.get("Affected");

View File

@@ -30,9 +30,6 @@ public class ReplaceProduceMana extends ReplacementEffect {
*/ */
@Override @Override
public boolean canReplace(Map<String, Object> runParams) { public boolean canReplace(Map<String, Object> runParams) {
if (!runParams.get("Event").equals("ProduceMana")) {
return false;
}
//Check for tapping //Check for tapping
if (!mapParams.containsKey("NoTapCheck")) { if (!mapParams.containsKey("NoTapCheck")) {
final SpellAbility manaAbility = (SpellAbility) runParams.get("AbilityMana"); final SpellAbility manaAbility = (SpellAbility) runParams.get("AbilityMana");
@@ -57,8 +54,8 @@ public class ReplaceProduceMana extends ReplacementEffect {
} }
} }
if (this.getMapParams().containsKey("ValidCard")) { if (hasParam("ValidCard")) {
if (!matchesValid(runParams.get("Affected"), this.getMapParams().get("ValidCard").split(","), this.getHostCard())) { if (!matchesValid(runParams.get("Affected"), getParam("ValidCard").split(","), this.getHostCard())) {
return false; return false;
} }
} }

View File

@@ -42,11 +42,8 @@ public class ReplaceSetInMotion extends ReplacementEffect {
*/ */
@Override @Override
public boolean canReplace(Map<String, Object> runParams) { public boolean canReplace(Map<String, Object> runParams) {
if (!runParams.get("Event").equals("SetInMotion")) { if (hasParam("ValidPlayer")) {
return false; if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), getHostCard())) {
}
if (this.getMapParams().containsKey("ValidPlayer")) {
if (!matchesValid(runParams.get("Affected"), this.getMapParams().get("ValidPlayer").split(","), this.getHostCard())) {
return false; return false;
} }
} }

View File

@@ -26,12 +26,12 @@ public class ReplaceSurveil extends ReplacementEffect {
*/ */
@Override @Override
public boolean canReplace(Map<String, Object> runParams) { public boolean canReplace(Map<String, Object> runParams) {
if (!runParams.get("Event").equals("Surveil") || ((int) runParams.get("SurveilNum")) <= 0) { if (((int) runParams.get("SurveilNum")) <= 0) {
return false; return false;
} }
if (hasParam("ValidPlayer")) { if (hasParam("ValidPlayer")) {
if (!matchesValid(runParams.get("Affected"), this.getMapParams().get("ValidPlayer").split(","), this.getHostCard())) { if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), this.getHostCard())) {
return false; return false;
} }
} }

View File

@@ -26,7 +26,7 @@ public class ReplaceToken extends ReplacementEffect {
*/ */
@Override @Override
public boolean canReplace(Map<String, Object> runParams) { public boolean canReplace(Map<String, Object> runParams) {
if (!runParams.get("Event").equals("CreateToken") || ((int) runParams.get("TokenNum")) <= 0) { if (((int) runParams.get("TokenNum")) <= 0) {
return false; return false;
} }

View File

@@ -26,11 +26,8 @@ public class ReplaceTurnFaceUp extends ReplacementEffect {
*/ */
@Override @Override
public boolean canReplace(Map<String, Object> runParams) { public boolean canReplace(Map<String, Object> runParams) {
if (!runParams.get("Event").equals("TurnFaceUp")) { if (hasParam("ValidCard")) {
return false; if (!matchesValid(runParams.get("Affected"), getParam("ValidCard").split(","), this.getHostCard())) {
}
if (this.getMapParams().containsKey("ValidCard")) {
if (!matchesValid(runParams.get("Affected"), this.getMapParams().get("ValidCard").split(","), this.getHostCard())) {
return false; return false;
} }
} }

View File

@@ -45,15 +45,12 @@ public class ReplaceUntap extends ReplacementEffect {
*/ */
@Override @Override
public boolean canReplace(Map<String, Object> runParams) { public boolean canReplace(Map<String, Object> runParams) {
if (!runParams.get("Event").equals("Untap")) { if (hasParam("ValidCard")) {
return false; if (!matchesValid(runParams.get("Affected"), getParam("ValidCard").split(","), this.getHostCard())) {
}
if (this.getMapParams().containsKey("ValidCard")) {
if (!matchesValid(runParams.get("Affected"), this.getMapParams().get("ValidCard").split(","), this.getHostCard())) {
return false; return false;
} }
} }
if (this.getMapParams().containsKey("UntapStep")) { if (hasParam("UntapStep")) {
final Object o = runParams.get("Affected"); final Object o = runParams.get("Affected");
//normally should not happen, but protect from possible crash. //normally should not happen, but protect from possible crash.
if (!(o instanceof Card)) { if (!(o instanceof Card)) {

View File

@@ -40,6 +40,8 @@ public abstract class ReplacementEffect extends TriggerReplacementBase {
/** The ID. */ /** The ID. */
private int id; private int id;
private ReplacementType mode;
private ReplacementLayer layer = ReplacementLayer.Other; private ReplacementLayer layer = ReplacementLayer.Other;
/** The has run. */ /** The has run. */
@@ -264,4 +266,12 @@ public abstract class ReplacementEffect extends TriggerReplacementBase {
public int hashCode() { public int hashCode() {
return Objects.hash(ReplacementEffect.class, getId()); return Objects.hash(ReplacementEffect.class, getId());
} }
public ReplacementType getMode() {
return mode;
}
void setMode(ReplacementType mode) {
this.mode = mode;
}
} }

View File

@@ -52,7 +52,7 @@ public class ReplacementHandler {
//private final List<ReplacementEffect> tmpEffects = new ArrayList<ReplacementEffect>(); //private final List<ReplacementEffect> tmpEffects = new ArrayList<ReplacementEffect>();
public ReplacementResult run(final Map<String, Object> runParams) { public ReplacementResult run(ReplacementType event, final Map<String, Object> runParams) {
final Object affected = runParams.get("Affected"); final Object affected = runParams.get("Affected");
Player decider = null; Player decider = null;
@@ -66,7 +66,7 @@ public class ReplacementHandler {
// try out all layer // try out all layer
for (ReplacementLayer layer : ReplacementLayer.values()) { for (ReplacementLayer layer : ReplacementLayer.values()) {
ReplacementResult res = run(runParams, layer, decider); ReplacementResult res = run(event, runParams, layer, decider);
if (res != ReplacementResult.NotReplaced) { if (res != ReplacementResult.NotReplaced) {
return res; return res;
} }
@@ -76,21 +76,21 @@ public class ReplacementHandler {
} }
public List<ReplacementEffect> getReplacementList(final Map<String, Object> runParams, final ReplacementLayer layer) { public List<ReplacementEffect> getReplacementList(final ReplacementType event, final Map<String, Object> runParams, final ReplacementLayer layer) {
final CardCollection preList = new CardCollection(); final CardCollection preList = new CardCollection();
boolean checkAgain = false; boolean checkAgain = false;
Card affectedLKI = null; Card affectedLKI = null;
Card affectedCard = null; Card affectedCard = null;
if ("Moved".equals(runParams.get("Event")) && ZoneType.Battlefield.equals(runParams.get("Destination"))) { if (ReplacementType.Moved.equals(event) && ZoneType.Battlefield.equals(runParams.get("Destination"))) {
// if it was caused by an replacement effect, use the already calculated RE list // if it was caused by an replacement effect, use the already calculated RE list
// otherwise the RIOT card would cause a StackError // otherwise the RIOT card would cause a StackError
SpellAbility cause = (SpellAbility) runParams.get("Cause"); SpellAbility cause = (SpellAbility) runParams.get("Cause");
if (cause != null && cause.isReplacementAbility()) { if (cause != null && cause.isReplacementAbility()) {
final ReplacementEffect re = cause.getReplacementEffect(); final ReplacementEffect re = cause.getReplacementEffect();
// only return for same layer // only return for same layer
if ("Moved".equals(re.getParam("Event")) && layer.equals(re.getLayer())) { if (ReplacementType.Moved.equals(re.getMode()) && layer.equals(re.getLayer())) {
return re.getOtherChoices(); return re.getOtherChoices();
} }
} }
@@ -137,6 +137,7 @@ public class ReplacementHandler {
if (!replacementEffect.hasRun() if (!replacementEffect.hasRun()
&& (layer == null || replacementEffect.getLayer() == layer) && (layer == null || replacementEffect.getLayer() == layer)
&& event.equals(replacementEffect.getMode())
&& replacementEffect.requirementsCheck(game) && replacementEffect.requirementsCheck(game)
&& replacementEffect.canReplace(runParams) && replacementEffect.canReplace(runParams)
&& !possibleReplacers.contains(replacementEffect) && !possibleReplacers.contains(replacementEffect)
@@ -172,8 +173,8 @@ public class ReplacementHandler {
* the run params,same as for triggers. * the run params,same as for triggers.
* @return true if the event was replaced. * @return true if the event was replaced.
*/ */
public ReplacementResult run(final Map<String, Object> runParams, final ReplacementLayer layer, final Player decider) { public ReplacementResult run(final ReplacementType event, final Map<String, Object> runParams, final ReplacementLayer layer, final Player decider) {
final List<ReplacementEffect> possibleReplacers = getReplacementList(runParams, layer); final List<ReplacementEffect> possibleReplacers = getReplacementList(event, runParams, layer);
if (possibleReplacers.isEmpty()) { if (possibleReplacers.isEmpty()) {
return ReplacementResult.NotReplaced; return ReplacementResult.NotReplaced;
@@ -188,7 +189,7 @@ public class ReplacementHandler {
ReplacementResult res = executeReplacement(runParams, chosenRE, decider, game); ReplacementResult res = executeReplacement(runParams, chosenRE, decider, game);
if (res == ReplacementResult.NotReplaced) { if (res == ReplacementResult.NotReplaced) {
if (!possibleReplacers.isEmpty()) { if (!possibleReplacers.isEmpty()) {
res = run(runParams); res = run(event, runParams);
} }
chosenRE.setHasRun(false); chosenRE.setHasRun(false);
chosenRE.setOtherChoices(null); chosenRE.setOtherChoices(null);
@@ -263,7 +264,7 @@ public class ReplacementHandler {
} }
// Decider gets to choose whether or not to apply the replacement. // Decider gets to choose whether or not to apply the replacement.
if (replacementEffect.getMapParams().containsKey("Optional")) { if (replacementEffect.hasParam("Optional")) {
Player optDecider = decider; Player optDecider = decider;
if (mapParams.containsKey("OptionalDecider") && (effectSA != null)) { if (mapParams.containsKey("OptionalDecider") && (effectSA != null)) {
effectSA.setActivatingPlayer(host.getController()); effectSA.setActivatingPlayer(host.getController());

View File

@@ -58,6 +58,7 @@ public enum ReplacementType {
if (pp[0].isAssignableFrom(Map.class)) { if (pp[0].isAssignableFrom(Map.class)) {
try { try {
ReplacementEffect res = c.newInstance(mapParams, host, intrinsic); ReplacementEffect res = c.newInstance(mapParams, host, intrinsic);
res.setMode(this);
return res; return res;
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
// TODO Auto-generated catch block ignores the exception, but sends it to System.err and probably forge.log. // TODO Auto-generated catch block ignores the exception, but sends it to System.err and probably forge.log.

View File

@@ -45,6 +45,7 @@ import forge.game.replacement.ReplacementEffect;
import forge.game.replacement.ReplacementHandler; import forge.game.replacement.ReplacementHandler;
import forge.game.replacement.ReplacementLayer; import forge.game.replacement.ReplacementLayer;
import forge.game.replacement.ReplacementResult; import forge.game.replacement.ReplacementResult;
import forge.game.replacement.ReplacementType;
import forge.game.trigger.TriggerType; import forge.game.trigger.TriggerType;
/** /**
@@ -128,12 +129,11 @@ public class AbilityManaPart implements java.io.Serializable {
final ManaPool manaPool = player.getManaPool(); final ManaPool manaPool = player.getManaPool();
String afterReplace = applyManaReplacement(sa, produced); String afterReplace = applyManaReplacement(sa, produced);
final Map<String, Object> repParams = Maps.newHashMap(); final Map<String, Object> repParams = Maps.newHashMap();
repParams.put("Event", "ProduceMana");
repParams.put("Mana", afterReplace); repParams.put("Mana", afterReplace);
repParams.put("Affected", source); repParams.put("Affected", source);
repParams.put("Player", player); repParams.put("Player", player);
repParams.put("AbilityMana", sa); repParams.put("AbilityMana", sa);
if (player.getGame().getReplacementHandler().run(repParams) != ReplacementResult.NotReplaced) { if (player.getGame().getReplacementHandler().run(ReplacementType.ProduceMana, repParams) != ReplacementResult.NotReplaced) {
return; return;
} }
//clear lastProduced //clear lastProduced

View File

@@ -438,7 +438,7 @@ public class TriggerHandler {
} }
} }
if (t.getMapParams().containsKey("OncePerEffect")) { if (t.hasParam("OncePerEffect")) {
SpellAbilityStackInstance si = SpellAbilityStackInstance si =
(SpellAbilityStackInstance) runParams.get(AbilityKey.SpellAbilityStackInstance); (SpellAbilityStackInstance) runParams.get(AbilityKey.SpellAbilityStackInstance);
if (si != null) { if (si != null) {

View File

@@ -26,6 +26,7 @@ import forge.game.mana.ManaCostBeingPaid;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.player.PlayerView; import forge.game.player.PlayerView;
import forge.game.replacement.ReplacementEffect; import forge.game.replacement.ReplacementEffect;
import forge.game.replacement.ReplacementType;
import forge.game.spellability.AbilityManaPart; import forge.game.spellability.AbilityManaPart;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.player.HumanPlay; import forge.player.HumanPlay;
@@ -363,7 +364,6 @@ public abstract class InputPayMana extends InputSyncronizedBase {
final Player activator = am.getActivatingPlayer(); final Player activator = am.getActivatingPlayer();
final Game g = source.getGame(); final Game g = source.getGame();
final HashMap<String, Object> repParams = new HashMap<>(); final HashMap<String, Object> repParams = new HashMap<>();
repParams.put("Event", "ProduceMana");
repParams.put("Mana", m.getOrigProduced()); repParams.put("Mana", m.getOrigProduced());
repParams.put("Affected", source); repParams.put("Affected", source);
repParams.put("Player", activator); repParams.put("Player", activator);
@@ -373,8 +373,9 @@ public abstract class InputPayMana extends InputSyncronizedBase {
for (final Card crd : p.getAllCards()) { for (final Card crd : p.getAllCards()) {
for (final ReplacementEffect replacementEffect : crd.getReplacementEffects()) { for (final ReplacementEffect replacementEffect : crd.getReplacementEffects()) {
if (replacementEffect.requirementsCheck(g) if (replacementEffect.requirementsCheck(g)
&& replacementEffect.getMode() == ReplacementType.ProduceMana
&& replacementEffect.canReplace(repParams) && replacementEffect.canReplace(repParams)
&& replacementEffect.getMapParams().containsKey("ManaReplacement") && replacementEffect.hasParam("ManaReplacement")
&& replacementEffect.zonesCheck(g.getZoneOf(crd))) { && replacementEffect.zonesCheck(g.getZoneOf(crd))) {
return true; return true;
} }