Handle merged permanent as commander

This commit is contained in:
Lyu Zong-Hong
2021-02-12 00:52:24 +09:00
parent e987ccd743
commit 8128aba4f8
6 changed files with 70 additions and 8 deletions

View File

@@ -132,6 +132,7 @@ public class GameAction {
Card copied = null;
Card lastKnownInfo = null;
Card commanderEffect = null; // The effect card of commander replacement effect
// get the LKI from above like ChangeZoneEffect
if (params != null && params.containsKey(AbilityKey.CardLKI)) {
@@ -231,6 +232,26 @@ public class GameAction {
copied.updateStateForView();
if (!suppress) {
// Temporary disable commander replacement effect
// 903.9a
if (fromBattlefield && c.isCommander() && c.hasMergedCard()) {
// Find the commander replacement effect "card"
CardCollectionView comCards = c.getOwner().getCardsIn(ZoneType.Command);
for (final Card effCard : comCards) {
for (final ReplacementEffect re : effCard.getReplacementEffects()) {
if (re.getMode() == ReplacementType.Moved && "Card.EffectSource+YouOwn".equals(re.getParam("ValidCard"))) {
commanderEffect = effCard;
break;
}
}
if (commanderEffect != null) break;
}
// Disable the commander replacement effect
for (final ReplacementEffect re : commanderEffect.getReplacementEffects()) {
re.setSuppressed(true);
}
}
if (zoneFrom == null) {
copied.getOwner().addInboundToken(copied);
}
@@ -362,12 +383,24 @@ public class GameAction {
}
}
// "enter the battlefield as a copy" - apply code here
// but how to query for input here and continue later while the callers assume synchronous result?
if (mergedCards != null) {
// Move components of merged permanet here
// Also handle 721.3e and 903.9a
boolean wasToken = c.isToken();
if (commanderEffect != null) {
for (final ReplacementEffect re : commanderEffect.getReplacementEffects()) {
re.setSuppressed(false);
}
}
// Change zone of original card so components isToken() and isCommander() return correct value
// when running replacement effects here
c.setZone(zoneTo);
for (final Card card : mergedCards) {
// 721.3e
if (c.isToken()) {
if (card.isRealCommander()) {
card.setMoveToCommandZone(true);
}
// 721.3e & 903.9a
if (wasToken && !card.isToken() || card.isRealCommander()) {
Map<AbilityKey, Object> repParams = AbilityKey.mapFromAffected(card);
repParams.put(AbilityKey.CardLKI, card);
repParams.put(AbilityKey.Cause, cause);
@@ -389,6 +422,8 @@ public class GameAction {
card.setZone(zoneTo);
}
} else {
// "enter the battlefield as a copy" - apply code here
// but how to query for input here and continue later while the callers assume synchronous result?
zoneTo.add(copied, position, lastKnownInfo); // the modified state of the card is also reported here (e.g. for Morbid + Awaken)
c.setZone(zoneTo);
}
@@ -611,7 +646,7 @@ public class GameAction {
AttachEffect.attachAuraOnIndirectEnterBattlefield(c);
}
if (c.isCommander()) {
if (c.isRealCommander()) {
c.setMoveToCommandZone(true);
}
@@ -1234,7 +1269,7 @@ public class GameAction {
}
private boolean stateBasedAction903_9a(Card c) {
if (c.isCommander() && c.canMoveToCommandZone()) {
if (c.isRealCommander() && c.canMoveToCommandZone()) {
c.setMoveToCommandZone(false);
if (c.getOwner().getController().confirmAction(c.getSpellPermanent(), PlayerActionConfirmMode.ChangeZoneToAltDestination, c.getName() + ": If a commander is in a graveyard or in exile and that card was put into that zone since the last time state-based actions were checked, its owner may put it into the command zone.")) {
moveTo(c.getOwner().getZone(ZoneType.Command), c, null);

View File

@@ -80,6 +80,10 @@ public class MutateEffect extends SpellAbilityEffect {
host.setFlipped(target.isFlipped());
target.setTimesMutated(target.getTimesMutated() + 1);
target.updateTokenView();
if (host.isCommander()) {
target.updateCommanderView();
host.getOwner().updateMergedCommanderCast(target, host);
}
game.getTriggerHandler().runTrigger(TriggerType.Mutates, AbilityKey.mapFromCard(target), false);
}

View File

@@ -2757,7 +2757,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
// is this "Card" supposed to be a token?
public final boolean isToken() {
if (hasMergedCard()) {
if (isInZone(ZoneType.Battlefield) && hasMergedCard()) {
return getTopMergedCard().token;
}
return token;
@@ -6240,6 +6240,13 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
public boolean isCommander() {
if (this.getMeldedWith() != null && this.getMeldedWith().isCommander())
return true;
if (isInZone(ZoneType.Battlefield) && hasMergedCard()) {
for (final Card c : getMergedCards())
if (c.isCommander) return true;
}
return isCommander;
}
public boolean isRealCommander() {
return isCommander;
}
public void setCommander(boolean b) {
@@ -6247,6 +6254,9 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
isCommander = b;
view.updateCommander(this);
}
public void updateCommanderView() {
view.updateCommander(this);
}
public boolean canMoveToCommandZone() {
return canMoveToCommandZone;

View File

@@ -101,7 +101,7 @@ public class CardFactory {
for (final Card o : in.getImprintedCards()) {
out.addImprintedCard(o);
}
out.setCommander(in.isCommander());
out.setCommander(in.isRealCommander());
//out.setFaceDown(in.isFaceDown());
return out;

View File

@@ -2886,6 +2886,10 @@ public class Player extends GameEntity implements Comparable<Player> {
getGame().fireEvent(new GameEventPlayerStatsChanged(this, false));
}
public void updateMergedCommanderCast(Card target, Card commander) {
getView().updateMergedCommanderCast(this, target, commander);
}
public int getTotalCommanderCast() {
int result = 0;
for (Integer i : commanderCast.values()) {

View File

@@ -351,6 +351,15 @@ public class PlayerView extends GameEntityView {
set(TrackableProperty.CommanderCast, map);
}
void updateMergedCommanderCast(Player p, Card target, Card commander) {
Map<Integer, Integer> map = get(TrackableProperty.CommanderCast);
if (map == null) {
map = Maps.newHashMap();
}
map.put(target.getId(), p.getCommanderCast(commander));
set(TrackableProperty.CommanderCast, map);
}
public PlayerView getMindSlaveMaster() {
return get(TrackableProperty.MindSlaveMaster);
}