add new Replacement Effect its for manipulating the original request

Card#addCounter does show how it is done
This commit is contained in:
Hanmac
2016-12-26 13:31:20 +00:00
parent cae93fbc3c
commit a67da177ff
9 changed files with 149 additions and 25 deletions

View File

@@ -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),

View File

@@ -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<String, Object> originalParams = (Map<String, Object>) sa.getReplacingObject("OriginalParams");
Map<String, Object> 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<String, Object> e : params.entrySet()) {
originalParams.replace(e.getKey(), e.getValue());
}
}
default:
break;
}
}
}

View File

@@ -96,7 +96,7 @@ public class Card extends GameEntity implements Comparable<Card> {
private SpellAbility castSA = null;
private final CardDamageHistory damageHistory = new CardDamageHistory();
private Map<Card, Map<CounterType, Integer>> countersAddedBy = new TreeMap<>();
private Map<Card, Map<CounterType, Integer>> countersAddedBy = Maps.newTreeMap();
private List<String> extrinsicKeyword = new ArrayList<>();
// Hidden keywords won't be displayed on the card
private final CopyOnWriteArrayList<String> hiddenExtrinsicKeyword = new CopyOnWriteArrayList<>();
@@ -301,7 +301,7 @@ public class Card extends GameEntity implements Comparable<Card> {
// Clear old dfc trigger from the trigger handler
getGame().getTriggerHandler().clearInstrinsicActiveTriggers(this, null);
getGame().getTriggerHandler().registerActiveTrigger(this, false);
HashMap<String, Object> runParams = new HashMap<>();
Map<String, Object> 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<Card> {
boolean result = setState(preFaceDownState, true);
if (result && runTriggers) {
// Run replacement effects
HashMap<String, Object> repParams = new HashMap<>();
Map<String, Object> repParams = Maps.newHashMap();
repParams.put("Event", "TurnFaceUp");
repParams.put("Affected", this);
getGame().getReplacementHandler().run(repParams);
// Run triggers
getGame().getTriggerHandler().registerActiveTrigger(this, false);
final Map<String, Object> runParams = new TreeMap<>();
final Map<String, Object> 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<Card> {
}
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<Card> {
if(addAmount < 0) {
addAmount = 0; // As per rule 107.1b
}
final HashMap<String, Object> repParams = new HashMap<>();
final Map<String, Object> 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<Card> {
}
// Run triggers
final Map<String, Object> runParams = new TreeMap<>();
final Map<String, Object> 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<Card> {
* @param counterAmount - the amount of counters added
*/
public final void addCountersAddedBy(final Card source, final CounterType counterType, final int counterAmount) {
final Map<CounterType, Integer> counterMap = new TreeMap<>();
final Map<CounterType, Integer> counterMap = Maps.newTreeMap();
counterMap.put(counterType, counterAmount);
countersAddedBy.put(source, counterMap);
}
@@ -1096,7 +1105,7 @@ public class Card extends GameEntity implements Comparable<Card> {
// Run triggers
int curCounters = oldValue == null ? 0 : oldValue;
for (int i = 0; i < delta && curCounters != 0; i++) {
final Map<String, Object> runParams = new TreeMap<>();
final Map<String, Object> 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<Card> {
getGame().fireEvent(new GameEventCardAttachment(this, c, null, AttachMethod.Equip));
// Run triggers
final Map<String, Object> runParams = new TreeMap<>();
final Map<String, Object> 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<Card> {
if (tapped) { return; }
// Run triggers
final Map<String, Object> runParams = new TreeMap<>();
final Map<String, Object> 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<Card> {
}
// Run triggers
final Map<String, Object> runParams = new TreeMap<>();
final Map<String, Object> 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<Card> {
return false;
}
final Map<String, Object> runParams = new TreeMap<>();
final Map<String, Object> runParams = Maps.newTreeMap();
runParams.put("Card", this);
if (!isPhasedOut()) {
@@ -5968,8 +5977,8 @@ public class Card extends GameEntity implements Comparable<Card> {
CardCollectionView preventionEffectSources = new CardCollection(shieldMap.keySet());
Card shieldSource = preventionEffectSources.get(0);
if (preventionEffectSources.size() > 1) {
Map<String, Card> choiceMap = new TreeMap<>();
List<String> choices = new ArrayList<>();
Map<String, Card> choiceMap = Maps.newTreeMap();
List<String> 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<Card> {
@Override
public final int replaceDamage(final int damageIn, final Card source, final boolean isCombat) {
// Replacement effects
final HashMap<String, Object> repParams = new HashMap<>();
final Map<String, Object> 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<Card> {
}
// Run triggers
final Map<String, Object> runParams = new TreeMap<>();
final Map<String, Object> 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<Card> {
return CardFactory.getCard(pc, owner, owner == null ? null : owner.getGame());
}
private static final Map<PaperCard, Card> cp2card = new HashMap<>();
private static final Map<PaperCard, Card> cp2card = Maps.newHashMap();
public static Card getCardForUi(IPaperCard pc) {
if (pc instanceof PaperCard) {
Card res = cp2card.get(pc);

View File

@@ -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 &emsp; HashMap<String, String>
* @param host &emsp; Card
*/
public ReplaceToken(final Map<String, String> 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<String, Object> 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<String, Object> runParams, SpellAbility sa) {
sa.setReplacingObject("TokenNum", runParams.get("TokenNum"));
sa.setReplacingObject("Player", runParams.get("Affected"));
}
}

View File

@@ -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<ReplacementEffect> tmpEffects = new ArrayList<ReplacementEffect>();
public ReplacementResult run(final HashMap<String, Object> runParams) {
public ReplacementResult run(final Map<String, Object> 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<String, Object> runParams, final ReplacementLayer layer, final Player decider, final Game game) {
public ReplacementResult run(final Map<String, Object> runParams, final ReplacementLayer layer, final Player decider, final Game game) {
final List<ReplacementEffect> possibleReplacers = new ArrayList<ReplacementEffect>();
// 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;

View File

@@ -7,5 +7,6 @@ package forge.game.replacement;
public enum ReplacementResult {
Replaced,
NotReplaced,
Prevented;
Prevented,
Updated;
}

View File

@@ -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<? extends ReplacementEffect> clasz;
private ReplacementType(Class<? extends ReplacementEffect> cls) {
clasz = cls;
}
public static ReplacementType getTypeFor(ReplacementEffect e) {
final Class<? extends ReplacementEffect> cls = e.getClass();
for (final ReplacementType v : ReplacementType.values()) {