mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 12:48:00 +00:00
CardFactory: Token Copy of transforming permanent
This commit is contained in:
@@ -294,7 +294,7 @@ public class GameCopier {
|
||||
private Card createCardCopy(Game newGame, Player newOwner, Card c) {
|
||||
if (c.isToken() && !c.isImmutable()) {
|
||||
Card result = new TokenInfo(c).makeOneToken(newOwner);
|
||||
CardFactory.copyCopiableCharacteristics(c, result);
|
||||
CardFactory.copyCopiableCharacteristics(c, result, null, null);
|
||||
return result;
|
||||
}
|
||||
if (USE_FROM_PAPER_CARD && !c.isImmutable() && c.getPaperCard() != null) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.google.common.collect.Lists;
|
||||
|
||||
import forge.StaticData;
|
||||
import forge.card.CardRulesPredicates;
|
||||
import forge.card.CardStateName;
|
||||
import forge.game.Game;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.card.Card;
|
||||
@@ -267,17 +268,27 @@ public class CopyPermanentEffect extends TokenEffectBase {
|
||||
copy.setOwner(newOwner);
|
||||
copy.setSetCode(original.getSetCode());
|
||||
|
||||
if (sa.hasParam("Embalm")) {
|
||||
copy.setEmbalmed(true);
|
||||
copy.setTokenSpawningAbility(sa);
|
||||
// 707.8a If an effect creates a token that is a copy of a transforming permanent or a transforming double-faced card not on the battlefield,
|
||||
// the resulting token is a transforming token that has both a front face and a back face.
|
||||
// The characteristics of each face are determined by the copiable values of the same face of the permanent it is a copy of, as modified by any other copy effects that apply to that permanent.
|
||||
// If the token is a copy of a transforming permanent with its back face up, the token enters the battlefield with its back face up.
|
||||
// This rule does not apply to tokens that are created with their own set of characteristics and enter the battlefield as a copy of a transforming permanent due to a replacement effect.
|
||||
if (original.isTransformable()) {
|
||||
copy.setBackSide(original.isBackSide());
|
||||
copy.setRules(original.getRules());
|
||||
if (original.isTransformed()) {
|
||||
copy.incrementTransformedTimestamp();
|
||||
}
|
||||
|
||||
if (sa.hasParam("Eternalize")) {
|
||||
copy.setEternalized(true);
|
||||
}
|
||||
|
||||
copy.setStates(CardFactory.getCloneStates(original, copy, sa));
|
||||
// force update the now set State
|
||||
if (original.isTransformable()) {
|
||||
copy.setState(original.isTransformed() ? CardStateName.Transformed : CardStateName.Original, true, true);
|
||||
} else {
|
||||
copy.setState(copy.getCurrentStateName(), true, true);
|
||||
}
|
||||
copy.setToken(true);
|
||||
|
||||
return copy;
|
||||
|
||||
@@ -84,6 +84,7 @@ public class ReplaceTokenEffect extends SpellAbilityEffect {
|
||||
if (token == null) {
|
||||
throw new RuntimeException("don't find Token for TokenScript: " + script);
|
||||
}
|
||||
token.setTokenSpawningAbility((SpellAbility)repSA.getReplacingObject(AbilityKey.Cause));
|
||||
token.setController(e.getKey(), timestamp);
|
||||
table.put(p, token, e.getValue());
|
||||
}
|
||||
@@ -136,6 +137,7 @@ public class ReplaceTokenEffect extends SpellAbilityEffect {
|
||||
throw new RuntimeException("don't find Token for TokenScript: " + script);
|
||||
}
|
||||
|
||||
token.setTokenSpawningAbility((SpellAbility)repSA.getReplacingObject(AbilityKey.Cause));
|
||||
token.setController(pe.getKey(), timestamp);
|
||||
// if token is created from ForEach keep that
|
||||
token.addRemembered(pe.getValue().getRight());
|
||||
|
||||
@@ -44,8 +44,7 @@ public abstract class TokenEffectBase extends SpellAbilityEffect {
|
||||
if (result == null) {
|
||||
throw new RuntimeException("don't find Token for TokenScript: " + script);
|
||||
}
|
||||
// set owner
|
||||
result.setOwner(owner);
|
||||
result.setTokenSpawningAbility(sa);
|
||||
tokenTable.put(owner, result, finalAmount);
|
||||
}
|
||||
}
|
||||
@@ -59,8 +58,7 @@ public abstract class TokenEffectBase extends SpellAbilityEffect {
|
||||
if (result == null) {
|
||||
throw new RuntimeException("don't find Token for TokenScript: " + script);
|
||||
}
|
||||
// set owner
|
||||
result.setOwner(owner);
|
||||
result.setTokenSpawningAbility(sa);
|
||||
tokenTable.put(owner, result, finalAmount);
|
||||
|
||||
return tokenTable;
|
||||
@@ -81,6 +79,7 @@ public abstract class TokenEffectBase extends SpellAbilityEffect {
|
||||
for (Player p : Sets.newHashSet(tokenTable.rowKeySet())) {
|
||||
final Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(p);
|
||||
repParams.put(AbilityKey.Token, tokenTable);
|
||||
repParams.put(AbilityKey.Cause, sa);
|
||||
repParams.put(AbilityKey.EffectOnly, true); // currently only effects can create tokens?
|
||||
|
||||
switch (game.getReplacementHandler().run(ReplacementType.CreateToken, repParams)) {
|
||||
|
||||
@@ -120,6 +120,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
private Card mergedTo;
|
||||
|
||||
private SpellAbility effectSourceAbility;
|
||||
private SpellAbility tokenSpawningAbility;
|
||||
|
||||
private GameEntity entityAttachedTo;
|
||||
|
||||
@@ -223,8 +224,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
private long prototypeTimestamp = -1;
|
||||
private int timesMutated = 0;
|
||||
private boolean tributed = false;
|
||||
private boolean embalmed = false;
|
||||
private boolean eternalized = false;
|
||||
private boolean discarded = false;
|
||||
|
||||
private boolean flipped = false;
|
||||
@@ -1562,6 +1561,8 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
newValue = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
final int delta = oldValue - newValue;
|
||||
@@ -5885,18 +5886,22 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
||||
tributed = b;
|
||||
}
|
||||
|
||||
public final boolean isEmbalmed() {
|
||||
return embalmed;
|
||||
public final SpellAbility getTokenSpawningAbility() {
|
||||
return tokenSpawningAbility;
|
||||
}
|
||||
public final void setEmbalmed(final boolean b) {
|
||||
embalmed = b;
|
||||
|
||||
public void setTokenSpawningAbility(SpellAbility sa) {
|
||||
tokenSpawningAbility = sa;
|
||||
}
|
||||
|
||||
public final boolean isEmbalmed() {
|
||||
SpellAbility sa = getTokenSpawningAbility();
|
||||
return sa != null && sa.hasParam("Embalm");
|
||||
}
|
||||
|
||||
public final boolean isEternalized() {
|
||||
return eternalized;
|
||||
}
|
||||
public final void setEternalized(final boolean b) {
|
||||
eternalized = b;
|
||||
SpellAbility sa = getTokenSpawningAbility();
|
||||
return sa != null && sa.hasParam("Eternalize");
|
||||
}
|
||||
|
||||
public final int getExertedThisTurn() {
|
||||
|
||||
@@ -29,6 +29,7 @@ import forge.game.CardTraitBase;
|
||||
import forge.game.Game;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.ApiType;
|
||||
import forge.game.cost.Cost;
|
||||
import forge.game.keyword.KeywordInterface;
|
||||
import forge.game.player.Player;
|
||||
@@ -85,8 +86,7 @@ public class CardFactory {
|
||||
out.setToken(true);
|
||||
|
||||
// need to copy this values for the tokens
|
||||
out.setEmbalmed(in.isEmbalmed());
|
||||
out.setEternalized(in.isEternalized());
|
||||
out.setTokenSpawningAbility(in.getTokenSpawningAbility());
|
||||
}
|
||||
|
||||
out.setZone(in.getZone());
|
||||
@@ -125,7 +125,7 @@ public class CardFactory {
|
||||
final Card original = targetSA.getHostCard();
|
||||
final Game game = source.getGame();
|
||||
final Card c = new Card(game.nextCardId(), original.getPaperCard(), game);
|
||||
copyCopiableCharacteristics(original, c);
|
||||
copyCopiableCharacteristics(original, c, sourceSA, targetSA);
|
||||
|
||||
if (sourceSA.hasParam("NonLegendary")) {
|
||||
c.removeType(CardType.Supertype.Legendary);
|
||||
@@ -525,12 +525,12 @@ public class CardFactory {
|
||||
* @param from the {@link Card} to copy from.
|
||||
* @param to the {@link Card} to copy to.
|
||||
*/
|
||||
public static void copyCopiableCharacteristics(final Card from, final Card to) {
|
||||
public static void copyCopiableCharacteristics(final Card from, final Card to, SpellAbility sourceSA, SpellAbility targetSA) {
|
||||
final boolean toIsFaceDown = to.isFaceDown();
|
||||
if (toIsFaceDown) {
|
||||
// If to is face down, copy to its front side
|
||||
to.setState(CardStateName.Original, false);
|
||||
copyCopiableCharacteristics(from, to);
|
||||
copyCopiableCharacteristics(from, to, sourceSA, targetSA);
|
||||
to.setState(CardStateName.FaceDown, false);
|
||||
return;
|
||||
}
|
||||
@@ -545,6 +545,18 @@ public class CardFactory {
|
||||
copyState(from, CardStateName.Original, to, to.getCurrentStateName());
|
||||
}
|
||||
copyState(from, CardStateName.Flipped, to, CardStateName.Flipped);
|
||||
} else if (from.isTransformable()
|
||||
&& sourceSA != null && ApiType.CopySpellAbility.equals(sourceSA.getApi())
|
||||
&& targetSA != null && targetSA.isSpell() && targetSA.getHostCard().isPermanent()) {
|
||||
copyState(from, CardStateName.Original, to, CardStateName.Original);
|
||||
copyState(from, CardStateName.Transformed, to, CardStateName.Transformed);
|
||||
// 707.10g If an effect creates a copy of a transforming permanent spell, the copy is also a transforming permanent spell that has both a front face and a back face.
|
||||
// The characteristics of its front and back face are determined by the copiable values of the same face of the spell it is a copy of, as modified by any other copy effects.
|
||||
// If the spell it is a copy of has its back face up, the copy is created with its back face up. The token that’s put onto the battlefield as that spell resolves is a transforming token.
|
||||
to.setBackSide(from.isBackSide());
|
||||
if (from.isTransformed()) {
|
||||
to.incrementTransformedTimestamp();
|
||||
}
|
||||
} else if (fromIsTransformedCard) {
|
||||
copyState(from, from.getCurrentStateName(), to, CardStateName.Original);
|
||||
} else {
|
||||
@@ -585,6 +597,9 @@ public class CardFactory {
|
||||
|
||||
c.setState(in.getCurrentStateName(), false);
|
||||
c.setRules(in.getRules());
|
||||
if (in.isTransformed()) {
|
||||
c.incrementTransformedTimestamp();
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
@@ -738,6 +753,15 @@ public class CardFactory {
|
||||
final CardState ret2 = new CardState(out, CardStateName.Adventure);
|
||||
ret2.copyFrom(in.getState(CardStateName.Adventure), false, sa);
|
||||
result.put(CardStateName.Adventure, ret2);
|
||||
} else if (in.isTransformable() && sa instanceof SpellAbility && ApiType.CopyPermanent.equals(((SpellAbility)sa).getApi())) {
|
||||
// CopyPermanent can copy token
|
||||
final CardState ret1 = new CardState(out, CardStateName.Original);
|
||||
ret1.copyFrom(in.getState(CardStateName.Original), false, sa);
|
||||
result.put(CardStateName.Original, ret1);
|
||||
|
||||
final CardState ret2 = new CardState(out, CardStateName.Transformed);
|
||||
ret2.copyFrom(in.getState(CardStateName.Transformed), false, sa);
|
||||
result.put(CardStateName.Transformed, ret2);
|
||||
} else {
|
||||
// in all other cases just copy the current state to original
|
||||
final CardState ret = new CardState(out, CardStateName.Original);
|
||||
@@ -871,12 +895,14 @@ public class CardFactory {
|
||||
state.setColor(MagicColor.WHITE);
|
||||
state.setManaCost(ManaCost.NO_COST);
|
||||
|
||||
if (sa.isIntrinsic()) {
|
||||
String name = TextUtil.fastReplace(
|
||||
TextUtil.fastReplace(host.getName(), ",", ""),
|
||||
" ", "_").toLowerCase();
|
||||
String set = host.getSetCode().toLowerCase();
|
||||
state.setImageKey(ImageKeys.getTokenKey("embalm_" + name + "_" + set));
|
||||
}
|
||||
}
|
||||
|
||||
if (sa.hasParam("Eternalize") && out.isEternalized()) {
|
||||
state.addType("Zombie");
|
||||
@@ -885,12 +911,14 @@ public class CardFactory {
|
||||
state.setBasePower(4);
|
||||
state.setBaseToughness(4);
|
||||
|
||||
if (sa.isIntrinsic()) {
|
||||
String name = TextUtil.fastReplace(
|
||||
TextUtil.fastReplace(host.getName(), ",", ""),
|
||||
" ", "_").toLowerCase();
|
||||
String set = host.getSetCode().toLowerCase();
|
||||
state.setImageKey(ImageKeys.getTokenKey("eternalize_" + name + "_" + set));
|
||||
}
|
||||
}
|
||||
|
||||
if (sa.hasParam("GainTextOf") && originalState != null) {
|
||||
state.setSetCode(originalState.getSetCode());
|
||||
|
||||
@@ -28,12 +28,6 @@ public class ReplaceToken extends ReplacementEffect {
|
||||
*/
|
||||
@Override
|
||||
public boolean canReplace(Map<AbilityKey, Object> runParams) {
|
||||
/*
|
||||
if (((int) runParams.get(AbilityKey.TokenNum)) <= 0) {
|
||||
return false;
|
||||
}
|
||||
//*/
|
||||
|
||||
if (hasParam("EffectOnly")) {
|
||||
final Boolean effectOnly = (Boolean) runParams.get(AbilityKey.EffectOnly);
|
||||
if (!effectOnly) {
|
||||
@@ -64,7 +58,7 @@ public class ReplaceToken extends ReplacementEffect {
|
||||
@Override
|
||||
public void setReplacingObjects(Map<AbilityKey, Object> runParams, SpellAbility sa) {
|
||||
sa.setReplacingObject(AbilityKey.TokenNum, filterAmount((TokenCreateTable) runParams.get(AbilityKey.Token)));
|
||||
sa.setReplacingObject(AbilityKey.Token, runParams.get(AbilityKey.Token));
|
||||
sa.setReplacingObjectsFrom(runParams, AbilityKey.Token, AbilityKey.Cause);
|
||||
sa.setReplacingObject(AbilityKey.Player, runParams.get(AbilityKey.Affected));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user