From a67da177ff2a4162e7a5084ea5766d69afd72bbc Mon Sep 17 00:00:00 2001 From: Hanmac Date: Mon, 26 Dec 2016 13:31:20 +0000 Subject: [PATCH] add new Replacement Effect its for manipulating the original request Card#addCounter does show how it is done --- .gitattributes | 2 + .../src/main/java/forge/ai/SpellApiToAi.java | 1 + .../main/java/forge/game/ability/ApiType.java | 1 + .../game/ability/effects/ReplaceEffect.java | 42 ++++++++++++++ .../src/main/java/forge/game/card/Card.java | 47 +++++++++------ .../forge/game/replacement/ReplaceToken.java | 58 +++++++++++++++++++ .../game/replacement/ReplacementHandler.java | 13 ++++- .../game/replacement/ReplacementResult.java | 3 +- .../game/replacement/ReplacementType.java | 7 ++- 9 files changed, 149 insertions(+), 25 deletions(-) create mode 100644 forge-game/src/main/java/forge/game/ability/effects/ReplaceEffect.java create mode 100644 forge-game/src/main/java/forge/game/replacement/ReplaceToken.java diff --git a/.gitattributes b/.gitattributes index d191902d9e4..4dc777caf36 100644 --- a/.gitattributes +++ b/.gitattributes @@ -441,6 +441,7 @@ forge-game/src/main/java/forge/game/ability/effects/RemoveFromCombatEffect.java forge-game/src/main/java/forge/game/ability/effects/ReorderZoneEffect.java -text forge-game/src/main/java/forge/game/ability/effects/RepeatEachEffect.java -text forge-game/src/main/java/forge/game/ability/effects/RepeatEffect.java -text +forge-game/src/main/java/forge/game/ability/effects/ReplaceEffect.java -text svneol=unset#text/plain forge-game/src/main/java/forge/game/ability/effects/RestartGameEffect.java -text forge-game/src/main/java/forge/game/ability/effects/RevealEffect.java -text forge-game/src/main/java/forge/game/ability/effects/RevealHandEffect.java -text @@ -634,6 +635,7 @@ forge-game/src/main/java/forge/game/replacement/ReplaceGameLoss.java -text forge-game/src/main/java/forge/game/replacement/ReplaceMoved.java -text forge-game/src/main/java/forge/game/replacement/ReplaceProduceMana.java -text forge-game/src/main/java/forge/game/replacement/ReplaceSetInMotion.java -text +forge-game/src/main/java/forge/game/replacement/ReplaceToken.java -text svneol=unset#text/plain forge-game/src/main/java/forge/game/replacement/ReplaceTurnFaceUp.java -text forge-game/src/main/java/forge/game/replacement/ReplaceUntap.java -text forge-game/src/main/java/forge/game/replacement/ReplacementEffect.java -text diff --git a/forge-ai/src/main/java/forge/ai/SpellApiToAi.java b/forge-ai/src/main/java/forge/ai/SpellApiToAi.java index 7ca249be3cf..47316918519 100644 --- a/forge-ai/src/main/java/forge/ai/SpellApiToAi.java +++ b/forge-ai/src/main/java/forge/ai/SpellApiToAi.java @@ -119,6 +119,7 @@ public enum SpellApiToAi { .put(ApiType.ReorderZone, AlwaysPlayAi.class) .put(ApiType.Repeat, RepeatAi.class) .put(ApiType.RepeatEach, RepeatEachAi.class) + .put(ApiType.ReplaceEffect, AlwaysPlayAi.class) .put(ApiType.RestartGame, RestartGameAi.class) .put(ApiType.Reveal, RevealAi.class) .put(ApiType.RevealHand, RevealHandAi.class) diff --git a/forge-game/src/main/java/forge/game/ability/ApiType.java b/forge-game/src/main/java/forge/game/ability/ApiType.java index 98e528c6eaa..92bd0a7a9b7 100644 --- a/forge-game/src/main/java/forge/game/ability/ApiType.java +++ b/forge-game/src/main/java/forge/game/ability/ApiType.java @@ -117,6 +117,7 @@ public enum ApiType { ReorderZone (ReorderZoneEffect.class), Repeat (RepeatEffect.class), RepeatEach (RepeatEachEffect.class), + ReplaceEffect (ReplaceEffect.class), RestartGame (RestartGameEffect.class), Reveal (RevealEffect.class), RevealHand (RevealHandEffect.class), diff --git a/forge-game/src/main/java/forge/game/ability/effects/ReplaceEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ReplaceEffect.java new file mode 100644 index 00000000000..6c3aeeba527 --- /dev/null +++ b/forge-game/src/main/java/forge/game/ability/effects/ReplaceEffect.java @@ -0,0 +1,42 @@ +package forge.game.ability.effects; + +import java.util.Map; + +import com.google.common.collect.Maps; + +import forge.game.Game; +import forge.game.ability.AbilityUtils; +import forge.game.ability.SpellAbilityEffect; +import forge.game.card.Card; +import forge.game.spellability.SpellAbility; + +public class ReplaceEffect extends SpellAbilityEffect { + + @Override + public void resolve(SpellAbility sa) { + final Card card = sa.getHostCard(); + final Game game = card.getGame(); + + final String varName = sa.getParam("VarName"); + final String varValue = sa.getParam("VarValue"); + + @SuppressWarnings("unchecked") + Map originalParams = (Map) sa.getReplacingObject("OriginalParams"); + Map params = Maps.newHashMap(originalParams); + + params.put(varName, AbilityUtils.calculateAmount(card, varValue, sa)); + + //try to call replacementHandler with new Params + switch (game.getReplacementHandler().run(params)) { + case NotReplaced: + case Updated: { + for (Map.Entry e : params.entrySet()) { + originalParams.replace(e.getKey(), e.getValue()); + } + } + default: + break; + } + } + +} diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index 7749e6f8d33..526990ed818 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -96,7 +96,7 @@ public class Card extends GameEntity implements Comparable { private SpellAbility castSA = null; private final CardDamageHistory damageHistory = new CardDamageHistory(); - private Map> countersAddedBy = new TreeMap<>(); + private Map> countersAddedBy = Maps.newTreeMap(); private List extrinsicKeyword = new ArrayList<>(); // Hidden keywords won't be displayed on the card private final CopyOnWriteArrayList hiddenExtrinsicKeyword = new CopyOnWriteArrayList<>(); @@ -301,7 +301,7 @@ public class Card extends GameEntity implements Comparable { // Clear old dfc trigger from the trigger handler getGame().getTriggerHandler().clearInstrinsicActiveTriggers(this, null); getGame().getTriggerHandler().registerActiveTrigger(this, false); - HashMap runParams = new HashMap<>(); + Map runParams = Maps.newHashMap(); runParams.put("Transformer", this); getGame().getTriggerHandler().runTrigger(TriggerType.Transformed, runParams, false); this.incrementTransformedTimestamp(); @@ -546,14 +546,14 @@ public class Card extends GameEntity implements Comparable { boolean result = setState(preFaceDownState, true); if (result && runTriggers) { // Run replacement effects - HashMap repParams = new HashMap<>(); + Map repParams = Maps.newHashMap(); repParams.put("Event", "TurnFaceUp"); repParams.put("Affected", this); getGame().getReplacementHandler().run(repParams); // Run triggers getGame().getTriggerHandler().registerActiveTrigger(this, false); - final Map runParams = new TreeMap<>(); + final Map runParams = Maps.newTreeMap(); runParams.put("Card", this); getGame().getTriggerHandler().runTrigger(TriggerType.TurnFaceUp, runParams, false); } @@ -750,7 +750,7 @@ public class Card extends GameEntity implements Comparable { } public final void addFlipResult(final Player flipper, final String result) { if (flipResult == null) { - flipResult = new TreeMap<>(); + flipResult = Maps.newTreeMap(); } flipResult.put(flipper, result); } @@ -975,15 +975,24 @@ public class Card extends GameEntity implements Comparable { if(addAmount < 0) { addAmount = 0; // As per rule 107.1b } - final HashMap repParams = new HashMap<>(); + final Map repParams = Maps.newHashMap(); repParams.put("Event", "AddCounter"); repParams.put("Affected", this); repParams.put("CounterType", counterType); repParams.put("CounterNum", addAmount); repParams.put("EffectOnly", applyMultiplier); - if (getGame().getReplacementHandler().run(repParams) != ReplacementResult.NotReplaced) { + + switch (getGame().getReplacementHandler().run(repParams)) { + case NotReplaced: + break; + case Updated: { + addAmount = (int) repParams.get("CounterNum"); + break; + } + default: return; } + if (canReceiveCounters(counterType)) { if (counterType == CounterType.DREAM && hasKeyword("CARDNAME can't have more than seven dream counters on it.")) { addAmount = Math.min(7 - getCounters(CounterType.DREAM), addAmount); @@ -1021,7 +1030,7 @@ public class Card extends GameEntity implements Comparable { } // Run triggers - final Map runParams = new TreeMap<>(); + final Map runParams = Maps.newTreeMap(); runParams.put("Card", this); runParams.put("CounterType", counterType); for (int i = 0; i < addAmount; i++) { @@ -1042,7 +1051,7 @@ public class Card extends GameEntity implements Comparable { * @param counterAmount - the amount of counters added */ public final void addCountersAddedBy(final Card source, final CounterType counterType, final int counterAmount) { - final Map counterMap = new TreeMap<>(); + final Map counterMap = Maps.newTreeMap(); counterMap.put(counterType, counterAmount); countersAddedBy.put(source, counterMap); } @@ -1096,7 +1105,7 @@ public class Card extends GameEntity implements Comparable { // Run triggers int curCounters = oldValue == null ? 0 : oldValue; for (int i = 0; i < delta && curCounters != 0; i++) { - final Map runParams = new TreeMap<>(); + final Map runParams = Maps.newTreeMap(); runParams.put("Card", this); runParams.put("CounterType", counterName); runParams.put("NewCounterAmount", --curCounters); @@ -2498,7 +2507,7 @@ public class Card extends GameEntity implements Comparable { getGame().fireEvent(new GameEventCardAttachment(this, c, null, AttachMethod.Equip)); // Run triggers - final Map runParams = new TreeMap<>(); + final Map runParams = Maps.newTreeMap(); runParams.put("Equipment", this); runParams.put("Card", c); getGame().getTriggerHandler().runTrigger(TriggerType.Unequip, runParams, false); @@ -3044,7 +3053,7 @@ public class Card extends GameEntity implements Comparable { if (tapped) { return; } // Run triggers - final Map runParams = new TreeMap<>(); + final Map runParams = Maps.newTreeMap(); runParams.put("Card", this); getGame().getTriggerHandler().runTrigger(TriggerType.Taps, runParams, false); @@ -3065,7 +3074,7 @@ public class Card extends GameEntity implements Comparable { } // Run triggers - final Map runParams = new TreeMap<>(); + final Map runParams = Maps.newTreeMap(); runParams.put("Card", this); getGame().getTriggerHandler().runTrigger(TriggerType.Untaps, runParams, false); @@ -3604,7 +3613,7 @@ public class Card extends GameEntity implements Comparable { return false; } - final Map runParams = new TreeMap<>(); + final Map runParams = Maps.newTreeMap(); runParams.put("Card", this); if (!isPhasedOut()) { @@ -5968,8 +5977,8 @@ public class Card extends GameEntity implements Comparable { CardCollectionView preventionEffectSources = new CardCollection(shieldMap.keySet()); Card shieldSource = preventionEffectSources.get(0); if (preventionEffectSources.size() > 1) { - Map choiceMap = new TreeMap<>(); - List choices = new ArrayList<>(); + Map choiceMap = Maps.newTreeMap(); + List choices = Lists.newArrayList(); for (final Card key : preventionEffectSources) { String effDesc = shieldMap.get(key).get("EffectString"); int descIndex = effDesc.indexOf("SpellDescription"); @@ -6126,7 +6135,7 @@ public class Card extends GameEntity implements Comparable { @Override public final int replaceDamage(final int damageIn, final Card source, final boolean isCombat) { // Replacement effects - final HashMap repParams = new HashMap<>(); + final Map repParams = Maps.newHashMap(); repParams.put("Event", "DamageDone"); repParams.put("Affected", this); repParams.put("DamageSource", source); @@ -6168,7 +6177,7 @@ public class Card extends GameEntity implements Comparable { } // Run triggers - final Map runParams = new TreeMap<>(); + final Map runParams = Maps.newTreeMap(); runParams.put("DamageSource", source); runParams.put("DamageTarget", this); runParams.put("DamageAmount", damageIn); @@ -6958,7 +6967,7 @@ public class Card extends GameEntity implements Comparable { return CardFactory.getCard(pc, owner, owner == null ? null : owner.getGame()); } - private static final Map cp2card = new HashMap<>(); + private static final Map cp2card = Maps.newHashMap(); public static Card getCardForUi(IPaperCard pc) { if (pc instanceof PaperCard) { Card res = cp2card.get(pc); diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceToken.java b/forge-game/src/main/java/forge/game/replacement/ReplaceToken.java new file mode 100644 index 00000000000..215dac2c118 --- /dev/null +++ b/forge-game/src/main/java/forge/game/replacement/ReplaceToken.java @@ -0,0 +1,58 @@ +package forge.game.replacement; + +import forge.game.card.Card; +import forge.game.spellability.SpellAbility; + +import java.util.Map; + +/** + * TODO: Write javadoc for this type. + * + */ +public class ReplaceToken extends ReplacementEffect { + + /** + * + * ReplaceProduceMana. + * @param mapParams   HashMap + * @param host   Card + */ + public ReplaceToken(final Map mapParams, final Card host, final boolean intrinsic) { + super(mapParams, host, intrinsic); + } + + /* (non-Javadoc) + * @see forge.card.replacement.ReplacementEffect#canReplace(java.util.Map) + */ + @Override + public boolean canReplace(Map runParams) { + if (!runParams.get("Event").equals("CreateToken") || ((int) runParams.get("TokenNum")) <= 0) { + return false; + } + + if (mapParams.containsKey("EffectOnly")) { + final Boolean effectOnly = (Boolean) runParams.get("EffectOnly"); + if (!effectOnly) { + return false; + } + } + + if (this.getMapParams().containsKey("ValidPlayer")) { + if (!matchesValid(runParams.get("Affected"), this.getMapParams().get("ValidPlayer").split(","), this.getHostCard())) { + return false; + } + } + + return true; + } + + /* (non-Javadoc) + * @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.Map, forge.card.spellability.SpellAbility) + */ + @Override + public void setReplacingObjects(Map runParams, SpellAbility sa) { + sa.setReplacingObject("TokenNum", runParams.get("TokenNum")); + sa.setReplacingObject("Player", runParams.get("Affected")); + } + +} diff --git a/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java b/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java index 402c80005b7..917f10da3bb 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java @@ -22,6 +22,7 @@ import forge.game.Game; import forge.game.GameLogEntryType; import forge.game.ability.AbilityFactory; import forge.game.ability.AbilityUtils; +import forge.game.ability.ApiType; import forge.game.card.Card; import forge.game.player.Player; import forge.game.spellability.SpellAbility; @@ -46,7 +47,7 @@ public class ReplacementHandler { //private final List tmpEffects = new ArrayList(); - public ReplacementResult run(final HashMap runParams) { + public ReplacementResult run(final Map runParams) { final Object affected = runParams.get("Affected"); Player decider = null; @@ -97,7 +98,7 @@ public class ReplacementHandler { * the run params,same as for triggers. * @return true if the event was replaced. */ - public ReplacementResult run(final HashMap runParams, final ReplacementLayer layer, final Player decider, final Game game) { + public ReplacementResult run(final Map runParams, final ReplacementLayer layer, final Player decider, final Game game) { final List possibleReplacers = new ArrayList(); // Round up Non-static replacement effects ("Until EOT," or // "The next time you would..." etc) @@ -185,6 +186,8 @@ public class ReplacementHandler { SpellAbility tailend = effectSA; do { replacementEffect.setReplacingObjects(runParams, tailend); + //set original Params to update them later + tailend.setReplacingObject("OriginalParams", runParams); tailend = tailend.getSubAbility(); } while(tailend != null); @@ -194,6 +197,8 @@ public class ReplacementHandler { SpellAbility tailend = effectSA; do { replacementEffect.setReplacingObjects(runParams, tailend); + //set original Params to update them later + tailend.setReplacingObject("OriginalParams", runParams); tailend = tailend.getSubAbility(); } while(tailend != null); } @@ -250,6 +255,10 @@ public class ReplacementHandler { manaAb.getManaPart().produceMana(rep, player1, manaAb); } else { player.getController().playSpellAbilityNoStack(effectSA, true); + // if the spellability is a replace effect then its some new logic + if (ApiType.ReplaceEffect.equals(effectSA.getApi())) { + return ReplacementResult.Updated; + } } return ReplacementResult.Replaced; diff --git a/forge-game/src/main/java/forge/game/replacement/ReplacementResult.java b/forge-game/src/main/java/forge/game/replacement/ReplacementResult.java index f56cbced895..60695eac083 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplacementResult.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplacementResult.java @@ -7,5 +7,6 @@ package forge.game.replacement; public enum ReplacementResult { Replaced, NotReplaced, - Prevented; + Prevented, + Updated; } diff --git a/forge-game/src/main/java/forge/game/replacement/ReplacementType.java b/forge-game/src/main/java/forge/game/replacement/ReplacementType.java index 6f83148cc28..831e1b3df00 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplacementType.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplacementType.java @@ -11,8 +11,9 @@ import java.util.Map; * */ public enum ReplacementType { - AddCounter(ReplaceAddCounter.class), + AddCounter(ReplaceAddCounter.class), Counter(ReplaceCounter.class), + CreateToken(ReplaceToken.class), DamageDone(ReplaceDamage.class), Destroy(ReplaceDestroy.class), Discard(ReplaceDiscard.class), @@ -24,12 +25,12 @@ public enum ReplacementType { SetInMotion(ReplaceSetInMotion.class), TurnFaceUp(ReplaceTurnFaceUp.class), Untap(ReplaceUntap.class); - + Class clasz; private ReplacementType(Class cls) { clasz = cls; } - + public static ReplacementType getTypeFor(ReplacementEffect e) { final Class cls = e.getClass(); for (final ReplacementType v : ReplacementType.values()) {