Merge branch 'bloodyCardTraits' into 'master'

CardTaits: make cardtraits inside LKI has the same id's as the in the original

See merge request core-developers/forge!197
This commit is contained in:
Michael Kamensky
2018-02-14 03:28:25 +00:00
36 changed files with 290 additions and 266 deletions

View File

@@ -233,7 +233,7 @@ public final class GameActionUtil {
alternatives.add(newSA);
}
if (sa.hasParam("Equip") && sa instanceof AbilityActivated && keyword.equals("EquipInstantSpeed")) {
final SpellAbility newSA = ((AbilityActivated) sa).getCopy();
final SpellAbility newSA = sa.copy();
SpellAbilityRestriction sar = newSA.getRestrictions();
sar.setSorcerySpeed(false);
sar.setInstantSpeed(true);

View File

@@ -11,7 +11,7 @@ import forge.game.zone.ZoneType;
/**
* Created by Hellfish on 2014-02-09.
*/
public abstract class TriggerReplacementBase extends CardTraitBase {
public abstract class TriggerReplacementBase extends CardTraitBase implements IIdentifiable, Cloneable {
protected EnumSet<ZoneType> validHostZones;
/** The overriding ability. */

View File

@@ -5,7 +5,6 @@ import forge.game.ability.effects.ChangeZoneEffect;
import forge.game.ability.effects.ManaEffect;
import forge.game.ability.effects.ManaReflectedEffect;
import forge.game.card.Card;
import forge.game.card.CardFactory;
import forge.game.cost.Cost;
import forge.game.spellability.AbilityActivated;
import forge.game.spellability.AbilityManaPart;
@@ -41,17 +40,6 @@ public class AbilityApiBased extends AbilityActivated {
return effect.getStackDescriptionWithSubs(mapParams, this);
}
/* (non-Javadoc)
* @see forge.card.spellability.AbilityActivated#getCopy()
*/
@Override
public AbilityActivated getCopy() {
TargetRestrictions tgt = getTargetRestrictions() == null ? null : new TargetRestrictions(getTargetRestrictions());
AbilityActivated res = new AbilityApiBased(api, getHostCard(), getPayCosts(), tgt, mapParams);
CardFactory.copySpellAbility(this, res, getHostCard());
return res;
}
/* (non-Javadoc)
* @see forge.card.spellability.SpellAbility#resolve()
*/

View File

@@ -195,7 +195,7 @@ public class CharmEffect extends SpellAbilityEffect {
for (AbilitySub sub : chosen) {
// Clone the chosen, just in case the some subAb gets chosen multiple times
AbilitySub clone = (AbilitySub)sub.getCopy();
AbilitySub clone = (AbilitySub)sub.copy();
// update ActivatingPlayer
clone.setActivatingPlayer(sa.getActivatingPlayer());

View File

@@ -141,6 +141,10 @@ public class PumpEffect extends SpellAbilityEffect {
}
}
/*
* (non-Javadoc)
* @see forge.game.ability.SpellAbilityEffect#getStackDescription(forge.game.spellability.SpellAbility)
*/
@Override
protected String getStackDescription(final SpellAbility sa) {

View File

@@ -822,17 +822,18 @@ public class Card extends GameEntity implements Comparable<Card> {
public final FCollectionView<Trigger> getTriggers() {
return currentState.getTriggers();
}
// only used for LKI
public final void setTriggers(final Iterable<Trigger> trigs, boolean intrinsicOnly) {
final FCollection<Trigger> copyList = new FCollection<>();
for (final Trigger t : trigs) {
if (!intrinsicOnly || t.isIntrinsic()) {
copyList.add(t.getCopyForHostCard(this));
copyList.add(t.copy(this, true));
}
}
currentState.setTriggers(copyList);
}
public final Trigger addTrigger(final Trigger t) {
final Trigger newtrig = t.getCopyForHostCard(this);
final Trigger newtrig = t.copy(this, false);
currentState.addTrigger(newtrig);
return newtrig;
}
@@ -5171,16 +5172,14 @@ public class Card extends GameEntity implements Comparable<Card> {
currentState.clearReplacementEffects();
for (final ReplacementEffect replacementEffect : res) {
if (replacementEffect.isIntrinsic()) {
addReplacementEffect(replacementEffect);
addReplacementEffect(replacementEffect.copy(this, false));
}
}
}
public ReplacementEffect addReplacementEffect(final ReplacementEffect replacementEffect) {
final ReplacementEffect replacementEffectCopy = replacementEffect.getCopy(); // doubtful - every caller provides a newly parsed instance, why copy?
replacementEffectCopy.setHostCard(this);
currentState.addReplacementEffect(replacementEffectCopy);
return replacementEffectCopy;
currentState.addReplacementEffect(replacementEffect);
return replacementEffect;
}
public void removeReplacementEffect(ReplacementEffect replacementEffect) {
currentState.removeReplacementEffect(replacementEffect);
@@ -5192,6 +5191,17 @@ public class Card extends GameEntity implements Comparable<Card> {
}
}
public boolean hasReplacementEffect(final ReplacementEffect re) {
return currentState.hasReplacementEffect(re);
}
public boolean hasReplacementEffect(final int id) {
return currentState.hasReplacementEffect(id);
}
public ReplacementEffect getReplacementEffect(final int id) {
return currentState.getReplacementEffect(id);
}
/**
* Returns what zone this card was cast from (from what zone it was moved to the stack).
*/

View File

@@ -184,21 +184,10 @@ public class CardFactory {
c.setCopiedSpell(true);
final SpellAbility copySA;
if (sa instanceof AbilityActivated) {
copySA = ((AbilityActivated)sa).getCopy();
copySA.setHostCard(original);
}
else if (sa.isTrigger()) {
if (sa.isTrigger()) {
copySA = getCopiedTriggeredAbility(sa);
}
else {
copySA = sa.copy();
AbilitySub subSA = copySA.getSubAbility();
while (subSA != null) {
subSA.setCopied(true);
subSA = subSA.getSubAbility();
}
copySA.setHostCard(c);
} else {
copySA = sa.copy(c, false);
}
c.getCurrentState().setNonManaAbilities(copySA);
copySA.setCopied(true);
@@ -577,27 +566,28 @@ public class CardFactory {
to.addAlternateState(toState, updateView);
}
final CardState toCharacteristics = to.getState(toState), fromCharacteristics = from.getState(fromState);
toCharacteristics.copyFrom(from, fromCharacteristics);
toCharacteristics.copyFrom(fromCharacteristics, false);
}
public static void copySpellAbility(SpellAbility from, SpellAbility to, final Card host) {
if (from.getActivatingPlayer() != null) {
to.setActivatingPlayer(from.getActivatingPlayer());
public static void copySpellAbility(SpellAbility from, SpellAbility to, final Card host, final boolean lki) {
if (from.getTargetRestrictions() != null) {
to.setTargetRestrictions(from.getTargetRestrictions());
}
to.setDescription(from.getOriginalDescription());
to.setStackDescription(from.getOriginalStackDescription());
if (from.getSubAbility() != null) {
to.setSubAbility(from.getSubAbility().getCopy(host));
to.setSubAbility((AbilitySub) from.getSubAbility().copy(host, lki));
}
for (Map.Entry<String, AbilitySub> e : from.getAdditionalAbilities().entrySet()) {
to.setAdditionalAbility(e.getKey(), e.getValue().getCopy(host));
to.setAdditionalAbility(e.getKey(), (AbilitySub) e.getValue().copy(host, lki));
}
for (Map.Entry<String, List<AbilitySub>> e : from.getAdditionalAbilityLists().entrySet()) {
to.setAdditionalAbilityList(e.getKey(), Lists.transform(e.getValue(), new Function<AbilitySub, AbilitySub>() {
@Override
public AbilitySub apply(AbilitySub input) {
return input.getCopy(host);
return (AbilitySub) input.copy(host, lki);
}
}));
}
@@ -607,7 +597,12 @@ public class CardFactory {
if (from.getConditions() != null) {
to.setConditions((SpellAbilityCondition) from.getConditions().copy());
}
// do this after other abilties are copied
if (from.getActivatingPlayer() != null) {
to.setActivatingPlayer(from.getActivatingPlayer(), lki);
}
for (String sVar : from.getSVars()) {
to.setSVar(sVar, from.getSVar(sVar));
}

View File

@@ -170,10 +170,10 @@ public class CardState extends GameObject {
public final boolean hasIntrinsicKeyword(String k) {
return intrinsicKeywords.contains(k);
}
public final void setIntrinsicKeywords(final Iterable<KeywordInterface> intrinsicKeyword0) {
public final void setIntrinsicKeywords(final Iterable<KeywordInterface> intrinsicKeyword0, final boolean lki) {
intrinsicKeywords.clear();
for (KeywordInterface k : intrinsicKeyword0) {
intrinsicKeywords.insert(k.copy(card));
intrinsicKeywords.insert(k.copy(card, lki));
}
}
@@ -367,6 +367,24 @@ public class CardState extends GameObject {
return getReplacementEffects().contains(re);
}
public final boolean hasReplacementEffect(final int id) {
for (final ReplacementEffect r : getReplacementEffects()) {
if (id == r.getId()) {
return true;
}
}
return false;
}
public final ReplacementEffect getReplacementEffect(final int id) {
for (final ReplacementEffect r : getReplacementEffects()) {
if (id == r.getId()) {
return r;
}
}
return null;
}
public final Map<String, String> getSVars() {
return sVars;
}
@@ -406,7 +424,7 @@ public class CardState extends GameObject {
return 0;
}
public final void copyFrom(final Card c, final CardState source) {
public final void copyFrom(final CardState source, final boolean lki) {
// Makes a "deeper" copy of a CardState object
setName(source.getName());
setType(source.type);
@@ -419,36 +437,30 @@ public class CardState extends GameObject {
manaAbilities.clear();
for (SpellAbility sa : source.manaAbilities) {
if (sa.isIntrinsic()) {
SpellAbility saCopy = sa.copy();
saCopy.setHostCard(card); // update HostCard
manaAbilities.add(saCopy);
manaAbilities.add(sa.copy(card, lki));
}
}
nonManaAbilities.clear();
for (SpellAbility sa : source.nonManaAbilities) {
if (sa.isIntrinsic()) {
SpellAbility saCopy = sa.copy();
saCopy.setHostCard(card); // update HostCard
nonManaAbilities.add(saCopy);
nonManaAbilities.add(sa.copy(card, lki));
}
}
setIntrinsicKeywords(source.intrinsicKeywords.getValues());
setIntrinsicKeywords(source.intrinsicKeywords.getValues(), lki);
setImageKey(source.getImageKey());
setRarity(source.rarity);
setSetCode(source.setCode);
triggers.clear();
for (Trigger tr : source.triggers) {
triggers.add(tr.getCopyForHostCard(card));
triggers.add(tr.copy(card, lki));
}
replacementEffects.clear();
for (ReplacementEffect re : source.replacementEffects) {
ReplacementEffect reCopy = re.getCopy();
reCopy.setHostCard(card);
replacementEffects.add(reCopy);
replacementEffects.add(re.copy(card, lki));
}
staticAbilities.clear();
@@ -456,7 +468,6 @@ public class CardState extends GameObject {
StaticAbility saCopy = new StaticAbility(sa, this.card);
staticAbilities.add(saCopy);
}
view.updateKeywords(c, this);
}

View File

@@ -211,19 +211,18 @@ public final class CardUtil {
// used for the purpose of cards that care about the zone the card was known to be in last
newCopy.setLastKnownZone(in.getLastKnownZone());
newCopy.getCurrentState().copyFrom(in, in.getState(in.getCurrentStateName()));
newCopy.getCurrentState().copyFrom(in.getState(in.getCurrentStateName()), true);
if (in.isCloned()) {
newCopy.addAlternateState(CardStateName.Cloner, false);
newCopy.getState(CardStateName.Cloner).copyFrom(in, in.getState(CardStateName.Cloner));
newCopy.getState(CardStateName.Cloner).copyFrom(in.getState(CardStateName.Cloner), true);
}
newCopy.setType(new CardType(in.getType()));
newCopy.setToken(in.isToken());
newCopy.setTriggers(in.getTriggers(), false);
for (SpellAbility sa : in.getSpellAbilities()) {
newCopy.addSpellAbility(sa);
sa.setHostCard(in);
newCopy.addSpellAbility(sa.copy(newCopy, true));
}
// lock in the current P/T without bonus from counters
@@ -263,6 +262,11 @@ public final class CardUtil {
newCopy.setMeldedWith(in.getMeldedWith());
// update keyword cache on all states
for (CardStateName s : newCopy.getStates()) {
newCopy.updateKeywordsCache(newCopy.getState(s));
}
return newCopy;
}

View File

@@ -167,6 +167,17 @@ public class KeywordCollection implements Iterable<String>, Serializable {
};
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(map.values());
return sb.toString();
}
public KeywordCollectionView getView() {
if (view == null) {
view = new KeywordCollectionView();

View File

@@ -180,26 +180,23 @@ public abstract class KeywordInstance<T extends KeywordInstance<?>> implements K
* (non-Javadoc)
* @see forge.game.keyword.KeywordInterface#copy()
*/
public KeywordInterface copy(final Card host) {
public KeywordInterface copy(final Card host, final boolean lki) {
try {
KeywordInstance<?> result = (KeywordInstance<?>) super.clone();
result.abilities = Lists.newArrayList();
for (SpellAbility sa : this.abilities) {
SpellAbility saCopy = sa.copy(host);
result.abilities.add(saCopy);
result.abilities.add(sa.copy(host, lki));
}
result.triggers = Lists.newArrayList();
for (Trigger tr : this.triggers) {
result.triggers.add(tr.getCopyForHostCard(host));
result.triggers.add(tr.copy(host, lki));
}
result.replacements = Lists.newArrayList();
for (ReplacementEffect re : this.replacements) {
ReplacementEffect reCopy = re.getCopy();
reCopy.setHostCard(host);
result.replacements.add(reCopy);
result.replacements.add(re.copy(host, lki));
}
result.staticAbilities = Lists.newArrayList();
@@ -212,4 +209,12 @@ public abstract class KeywordInstance<T extends KeywordInstance<?>> implements K
throw new RuntimeException("KeywordInstance : clone() error, " + ex);
}
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return this.getOriginal();
}
}

View File

@@ -49,5 +49,5 @@ public interface KeywordInterface extends Cloneable {
*/
public Collection<StaticAbility> getStaticAbilities();
public KeywordInterface copy(final Card host);
public KeywordInterface copy(final Card host, final boolean lki);
}

View File

@@ -1,12 +1,16 @@
package forge.game.replacement;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardUtil;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import java.util.Map;
import com.google.common.collect.Sets;
/**
* TODO: Write javadoc for this type.
*
@@ -32,7 +36,7 @@ public class ReplaceMoved extends ReplacementEffect {
return false;
}
final Player controller = getHostCard().getController();
if (hasParam("ValidCard")) {
if (!matchesValid(runParams.get("Affected"), getParam("ValidCard").split(","), getHostCard())) {
return false;
@@ -44,31 +48,46 @@ public class ReplaceMoved extends ReplacementEffect {
return false;
}
}
boolean matchedZone = false;
if (hasParam("Origin")) {
for(ZoneType z : ZoneType.listValueOf(getParam("Origin"))) {
if(z == (ZoneType) runParams.get("Origin"))
matchedZone = true;
}
if(!matchedZone)
{
return false;
}
}
if (hasParam("Destination")) {
matchedZone = false;
ZoneType zt = (ZoneType) runParams.get("Destination");
for(ZoneType z : ZoneType.listValueOf(getParam("Destination"))) {
if(z == (ZoneType) runParams.get("Destination"))
if(z == zt)
matchedZone = true;
}
if(!matchedZone)
{
return false;
}
if (zt.equals(ZoneType.Battlefield)) {
// would be an etb replacement effect that enters the battlefield
Card lki = CardUtil.getLKICopy((Card) runParams.get("Affected"));
lki.setLastKnownZone(lki.getController().getZone(zt));
CardCollection preList = new CardCollection(lki);
getHostCard().getGame().getAction().checkStaticAbilities(false, Sets.newHashSet(lki), preList);
// check if when entering the battlefield would still has this RE or is suppressed
if (!lki.hasReplacementEffect(this) || lki.getReplacementEffect(getId()).isSuppressed()) {
return false;
}
}
}
if (hasParam("ExcludeDestination")) {

View File

@@ -19,11 +19,9 @@ package forge.game.replacement;
import forge.game.Game;
import forge.game.TriggerReplacementBase;
import forge.game.ability.AbilityApiBased;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.phase.PhaseType;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
import forge.util.TextUtil;
@@ -35,12 +33,37 @@ import java.util.Map;
*
*/
public abstract class ReplacementEffect extends TriggerReplacementBase {
private static int maxId = 0;
private static int nextId() { return ++maxId; }
/** The ID. */
private int id;
private ReplacementLayer layer = ReplacementLayer.None;
/** The has run. */
private boolean hasRun = false;
/**
* Gets the id.
*
* @return the id
*/
public int getId() {
return this.id;
}
/**
* <p>
* setID.
* </p>
*
* @param id
* a int.
*/
public final void setId(final int id) {
this.id = id;
}
/**
* Checks for run.
*
@@ -59,6 +82,7 @@ public abstract class ReplacementEffect extends TriggerReplacementBase {
* the host
*/
public ReplacementEffect(final Map<String, String> map, final Card host, final boolean intrinsic) {
this.id = nextId();
this.intrinsic = intrinsic;
originalMapParams.putAll(map);
mapParams.putAll(map);
@@ -133,32 +157,27 @@ public abstract class ReplacementEffect extends TriggerReplacementBase {
*
* @return the copy
*/
public final ReplacementEffect getCopy() {
final ReplacementType rt = ReplacementType.getTypeFor(this);
final ReplacementEffect res = rt.createReplacement(mapParams, hostCard, intrinsic);
final SpellAbility overridingAbility = this.getOverridingAbility();
if (overridingAbility != null) {
final SpellAbility overridingAbilityCopy;
if (overridingAbility instanceof AbilityApiBased) {
overridingAbilityCopy = ((AbilityApiBased) overridingAbility).getCopy();
} else if (overridingAbility instanceof AbilitySub) {
overridingAbilityCopy = ((AbilitySub) overridingAbility).getCopy();
} else {
System.err.println("Overriding ability of " + hostCard + " of unexpected type " + overridingAbility.getClass());
overridingAbilityCopy = null;
}
if (overridingAbilityCopy != null) {
overridingAbilityCopy.setHostCard(hostCard);
res.setOverridingAbility(overridingAbilityCopy);
}
}
res.setActiveZone(validHostZones);
res.setLayer(getLayer());
res.setTemporary(isTemporary());
public final ReplacementEffect copy(final Card host, final boolean lki) {
final ReplacementEffect res = (ReplacementEffect) clone();
for (String key : getSVars()) {
res.setSVar(key, getSVar(key));
}
final SpellAbility sa = this.getOverridingAbility();
if (sa != null) {
final SpellAbility overridingAbilityCopy = sa.copy(host, lki);
if (overridingAbilityCopy != null) {
res.setOverridingAbility(overridingAbilityCopy);
}
}
if (!lki) {
res.setId(nextId());
}
res.setActiveZone(validHostZones);
res.setLayer(getLayer());
res.setTemporary(isTemporary());
return res;
}
@@ -206,6 +225,29 @@ public abstract class ReplacementEffect extends TriggerReplacementBase {
}
}
/** {@inheritDoc} */
@Override
public final Object clone() {
try {
return super.clone();
} catch (final Exception ex) {
throw new RuntimeException("ReplacementEffect : clone() error, " + ex);
}
}
/** {@inheritDoc} */
@Override
public final boolean equals(final Object o) {
if (!(o instanceof ReplacementEffect)) {
return false;
}
return this.getId() == ((ReplacementEffect) o).getId();
}
/** {@inheritDoc} */
@Override
public int hashCode() {
return 42 * (42 + this.getId());
}
}

View File

@@ -61,21 +61,12 @@ public class ReplacementHandler {
decider = ((Card) affected).getController();
}
ReplacementResult res = run(runParams, ReplacementLayer.Control, decider);
if (res != ReplacementResult.NotReplaced) {
return res;
}
res = run(runParams, ReplacementLayer.Copy, decider);
if (res != ReplacementResult.NotReplaced) {
return res;
}
res = run(runParams, ReplacementLayer.Other, decider);
if (res != ReplacementResult.NotReplaced) {
return res;
}
res = run(runParams, ReplacementLayer.None, decider);
if (res != ReplacementResult.NotReplaced) {
return res;
// try out all layer
for (ReplacementLayer layer : ReplacementLayer.values()) {
ReplacementResult res = run(runParams, layer, decider);
if (res != ReplacementResult.NotReplaced) {
return res;
}
}
return ReplacementResult.NotReplaced;

View File

@@ -32,16 +32,6 @@ public enum ReplacementType {
clasz = cls;
}
public static ReplacementType getTypeFor(ReplacementEffect e) {
final Class<? extends ReplacementEffect> cls = e.getClass();
for (final ReplacementType v : ReplacementType.values()) {
if (v.clasz.equals(cls)) {
return v;
}
}
return null;
}
public static ReplacementType smartValueOf(String value) {
final String valToCompate = value.trim();
for (final ReplacementType v : ReplacementType.values()) {

View File

@@ -72,10 +72,6 @@ public abstract class AbilityActivated extends SpellAbility implements java.io.S
}
}
public abstract AbilityActivated getCopy(); /* {
return null;
}
/** {@inheritDoc} */
@Override
public boolean canPlay() {

View File

@@ -25,7 +25,6 @@ import forge.game.ability.effects.ChangeZoneEffect;
import forge.game.ability.effects.ManaEffect;
import forge.game.ability.effects.ManaReflectedEffect;
import forge.game.card.Card;
import forge.game.card.CardFactory;
import forge.game.cost.Cost;
import java.util.Map;
@@ -102,16 +101,6 @@ public final class AbilitySub extends SpellAbility implements java.io.Serializab
}
}
public AbilitySub getCopy() {
return getCopy(getHostCard());
}
public AbilitySub getCopy(Card host) {
TargetRestrictions t = getTargetRestrictions() == null ? null : new TargetRestrictions(getTargetRestrictions());
AbilitySub res = new AbilitySub(api, host, t, mapParams);
CardFactory.copySpellAbility(this, res, host);
return res;
}
@Override
public String getStackDescription() {
return effect.getStackDescriptionWithSubs(mapParams, this);

View File

@@ -313,24 +313,25 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
return activatingPlayer;
}
public void setActivatingPlayer(final Player player) {
setActivatingPlayer(player, false);
}
public void setActivatingPlayer(final Player player, final boolean lki) {
// trickle down activating player
activatingPlayer = player;
if (subAbility != null) {
subAbility.setActivatingPlayer(player);
subAbility.setActivatingPlayer(player, lki);
}
for (AbilitySub sa : additionalAbilities.values()) {
if (sa.getActivatingPlayer() != player) {
sa.setActivatingPlayer(player);
}
sa.setActivatingPlayer(player, lki);
}
for (List<AbilitySub> list : additionalAbilityLists.values()) {
for (AbilitySub sa : list) {
if (sa.getActivatingPlayer() != player) {
sa.setActivatingPlayer(player);
}
sa.setActivatingPlayer(player, lki);
}
}
view.updateCanPlay(this, false);
if (!lki) {
view.updateCanPlay(this, false);
}
}
public Player getDeltrigActivatingPlayer() {
@@ -789,17 +790,18 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
}
public SpellAbility copy() {
return copy(hostCard);
return copy(hostCard, false);
}
public SpellAbility copy(Card host) {
public SpellAbility copy(Card host, final boolean lki) {
SpellAbility clone = null;
try {
clone = (SpellAbility) clone();
clone.id = nextId();
clone.id = lki ? id : nextId();
clone.view = new SpellAbilityView(clone);
// dont use setHostCard to not trigger the not copied parts yet
clone.hostCard = host;
if (host != null && host.getGame() != null) {
if (!lki && host != null && host.getGame() != null) {
host.getGame().addSpellAbility(clone);
}
// need to clone the maps too so they can be changed
@@ -808,8 +810,11 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
clone.triggeringObjects = Maps.newHashMap(this.triggeringObjects);
if (getPayCosts() != null) {
clone.setPayCosts(getPayCosts().copy());
}
// run special copy Ability to make a deep copy
CardFactory.copySpellAbility(this, clone, host);
CardFactory.copySpellAbility(this, clone, host, lki);
} catch (final CloneNotSupportedException e) {
System.err.println(e);
}
@@ -1109,6 +1114,9 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
}
public void setCopied(boolean isCopied0) {
isCopied = isCopied0;
if (this.getSubAbility() != null) {
this.getSubAbility().setCopied(isCopied0);
}
}
/**

View File

@@ -369,12 +369,12 @@ public final class StaticAbilityContinuous {
cardsIGainedAbilitiesFrom = CardLists.getValidCards(cardsIGainedAbilitiesFrom, valids, hostCard.getController(), hostCard, null);
if (cardsIGainedAbilitiesFrom.size() > 0) {
addFullAbs = new ArrayList<SpellAbility>();
addFullAbs = Lists.newArrayList();
for (Card c : cardsIGainedAbilitiesFrom) {
for (SpellAbility sa : c.getSpellAbilities()) {
if (sa instanceof AbilityActivated) {
SpellAbility newSA = ((AbilityActivated) sa).getCopy();
SpellAbility newSA = sa.copy(hostCard, false);
if (params.containsKey("GainsAbilitiesLimitPerTurn")) {
newSA.setRestrictions(sa.getRestrictions());
newSA.getRestrictions().setLimitToCheck(params.get("GainsAbilitiesLimitPerTurn"));
@@ -382,7 +382,6 @@ public final class StaticAbilityContinuous {
newSA.setOriginalHost(c);
newSA.setIntrinsic(false);
newSA.setTemporary(true);
newSA.setHostCard(hostCard);
addFullAbs.add(newSA);
}
}

View File

@@ -29,7 +29,6 @@ import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
import forge.game.spellability.Ability;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.OptionalCost;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
@@ -49,9 +48,8 @@ import forge.util.TextUtil;
* @version $Id$
*/
public abstract class Trigger extends TriggerReplacementBase {
/** Constant <code>nextID=0</code>. */
private static int nextID = 0;
private static int maxId = 0;
private static int nextId() { return ++maxId; }
/**
* <p>
@@ -59,23 +57,12 @@ public abstract class Trigger extends TriggerReplacementBase {
* </p>
*/
public static void resetIDs() {
Trigger.nextID = 50000;
Trigger.maxId = 50000;
}
/** The ID. */
private int id = Trigger.nextID++;
private int id;
/**
* <p>
* setID.
* </p>
*
* @param id
* a int.
*/
public final void setID(final int id) {
this.id = id;
}
/** The run params. */
private Map<String, Object> runParams;
@@ -131,9 +118,10 @@ public abstract class Trigger extends TriggerReplacementBase {
* the intrinsic
*/
public Trigger(final Map<String, String> params, final Card host, final boolean intrinsic) {
this.id = nextId();
this.intrinsic = intrinsic;
this.setRunParams(new HashMap<String, Object>());
this.setRunParams(Maps.newHashMap());
this.originalMapParams.putAll(params);
this.mapParams.putAll(params);
this.setHostCard(host);
@@ -462,13 +450,25 @@ public abstract class Trigger extends TriggerReplacementBase {
/**
* Gets the id.
*
*
* @return the id
*/
public int getId() {
return this.id;
}
/**
* <p>
* setID.
* </p>
*
* @param id
* a int.
*/
public final void setId(final int id) {
this.id = id;
}
private Ability triggeredSA;
/**
@@ -515,33 +515,25 @@ public abstract class Trigger extends TriggerReplacementBase {
void setMode(TriggerType triggerType) {
mode = triggerType;
}
public final Trigger getCopyForHostCard(Card newHost) {
final TriggerType tt = TriggerType.getTypeFor(this);
final Trigger copy = tt.createTrigger(originalMapParams, newHost, intrinsic);
public final Trigger copy(Card newHost, boolean lki) {
final Trigger copy = (Trigger) clone();
if (this.getOverridingAbility() != null) {
SpellAbility old = this.getOverridingAbility();
SpellAbility sa = old;
// try to copy it if newHost is not the wanted host
final Card oldHost = old.getHostCard();
if (!newHost.equals(oldHost)) {
if (old instanceof AbilitySub) {
sa = ((AbilitySub)old).getCopy();
sa.setHostCard(newHost);
}
} else if (newHost != oldHost) {
//host would be the same, but different state?
sa.setHostCard(newHost);
}
copy.setOverridingAbility(sa);
copy.originalMapParams.putAll(originalMapParams);
copy.mapParams.putAll(originalMapParams);
copy.setHostCard(newHost);
if (getOverridingAbility() != null) {
copy.setOverridingAbility(getOverridingAbility().copy(newHost, lki));
}
// 2015-03-07 Removing the ID copying which makes copied triggers Identical to each other when removing
//copy.setID(this.getId());
copy.setMode(this.getMode());
copy.setTriggerPhases(this.validPhases);
if (!lki) {
copy.setId(nextId());
}
if (validPhases != null) {
copy.setTriggerPhases(Lists.newArrayList(validPhases));
}
copy.setActiveZone(validHostZones);
copy.setTemporary(isTemporary());
return copy;
@@ -572,4 +564,14 @@ public abstract class Trigger extends TriggerReplacementBase {
{
this.numberTurnActivations = 0;
}
/** {@inheritDoc} */
@Override
public final Object clone() {
try {
return super.clone();
} catch (final Exception ex) {
throw new RuntimeException("Trigger : clone() error, " + ex);
}
}
}

View File

@@ -86,11 +86,9 @@ public enum TriggerType {
Untaps(TriggerUntaps.class),
Vote(TriggerVote.class);
private final Class<? extends Trigger> classTrigger;
private final Constructor<? extends Trigger> constructor;
private TriggerType(Class<? extends Trigger> clasz) {
classTrigger = clasz;
constructor = findConstructor(clasz);
}
@@ -122,16 +120,6 @@ public enum TriggerType {
throw new RuntimeException("Element " + value + " not found in TriggerType enum");
}
public static TriggerType getTypeFor(Trigger t) {
final Class<? extends Trigger> cls = t.getClass();
for (final TriggerType v : TriggerType.values()) {
if (v.classTrigger.equals(cls)) {
return v;
}
}
return null;
}
/**
* TODO: Write javadoc for this method.