mirror of
https://github.com/magefree/mage.git
synced 2025-12-26 21:42:07 -08:00
New commander types support:
* [KHM] fixed legendary status of mdf cards (closes #7370, #7404, #7465, #7481); * Game: added support of split cards as commander (signature spell); * Game: added support of adventure cards as commander; * Game: added support of modal double faces cards as commander;
This commit is contained in:
parent
bc72384f0d
commit
50e5809a79
9 changed files with 314 additions and 35 deletions
|
|
@ -41,7 +41,12 @@ public class CommanderCostModification extends CostModificationEffectImpl {
|
|||
|
||||
@Override
|
||||
public boolean applies(Ability abilityToModify, Ability source, Game game) {
|
||||
return commander.getId().equals(abilityToModify.getSourceId())
|
||||
Card cardToCheck = game.getCard(abilityToModify.getSourceId()); // split/mdf cards support
|
||||
if (cardToCheck == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return commander.getId().equals(cardToCheck.getMainCard().getId())
|
||||
&& (abilityToModify instanceof CastCommanderAbility
|
||||
|| abilityToModify instanceof PlayLandAsCommanderAbility);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,13 +86,13 @@ public interface Card extends MageObject {
|
|||
* @param zone
|
||||
* @param source ability which calls that move, can be null
|
||||
* @param game
|
||||
* @param flag If zone
|
||||
* <ul>
|
||||
* <li>LIBRARY: <ul><li>true - put on top</li><li>false - put on
|
||||
* bottom</li></ul></li>
|
||||
* <li>BATTLEFIELD: <ul><li>true - tapped</li><li>false -
|
||||
* untapped</li></ul></li>
|
||||
* </ul>
|
||||
* @param flag If zone
|
||||
* <ul>
|
||||
* <li>LIBRARY: <ul><li>true - put on top</li><li>false - put on
|
||||
* bottom</li></ul></li>
|
||||
* <li>BATTLEFIELD: <ul><li>true - tapped</li><li>false -
|
||||
* untapped</li></ul></li>
|
||||
* </ul>
|
||||
* @return true if card was moved to zone
|
||||
*/
|
||||
boolean moveToZone(Zone zone, Ability source, Game game, boolean flag);
|
||||
|
|
@ -102,8 +102,8 @@ public interface Card extends MageObject {
|
|||
/**
|
||||
* Moves the card to an exile zone
|
||||
*
|
||||
* @param exileId set to null for generic exile zone
|
||||
* @param name used for exile zone with the specified exileId
|
||||
* @param exileId set to null for generic exile zone
|
||||
* @param name used for exile zone with the specified exileId
|
||||
* @param source
|
||||
* @param game
|
||||
* @return true if card was moved to zone
|
||||
|
|
@ -183,7 +183,7 @@ public interface Card extends MageObject {
|
|||
|
||||
default boolean commanderCost(Game game, Ability source, Ability abilityToModify) {
|
||||
CommanderPlaysCountWatcher watcher = game.getState().getWatcher(CommanderPlaysCountWatcher.class);
|
||||
int castCount = watcher.getPlaysCount(getId());
|
||||
int castCount = watcher.getPlaysCount(getMainCard().getId());
|
||||
if (castCount > 0) {
|
||||
abilityToModify.getManaCostsToPay().add(ManaUtil.createManaCost(2 * castCount, false));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@ import mage.util.CardUtil;
|
|||
import mage.util.SubTypes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
|
|
@ -127,6 +127,12 @@ public abstract class ModalDoubleFacesCard extends CardImpl {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<SuperType> getSuperType() {
|
||||
// CardImpl's constructor can call some code on init, so you must check left/right before
|
||||
// it's a bad workaround
|
||||
return leftHalfCard != null ? leftHalfCard.getSuperType() : supertype;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<CardType> getCardType() {
|
||||
|
|
@ -154,11 +160,6 @@ public abstract class ModalDoubleFacesCard extends CardImpl {
|
|||
return leftHalfCard.hasSubtype(subtype, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<SuperType> getSuperType() {
|
||||
return EnumSet.noneOf(SuperType.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Abilities<Ability> getAbilities() {
|
||||
return getInnerAbilities(false);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import mage.abilities.text.TextPart;
|
|||
import mage.cards.Card;
|
||||
import mage.cards.FrameStyle;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SpellAbilityType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.game.Game;
|
||||
|
|
@ -36,16 +35,30 @@ public class Commander implements CommandObject {
|
|||
this.sourceObject = card;
|
||||
|
||||
// replace spell ability by commander cast spell (to cast from command zone)
|
||||
if (card.getSpellAbility() != null) {
|
||||
abilities.add(new CastCommanderAbility(card, card.getSpellAbility()));
|
||||
}
|
||||
|
||||
// replace alternative spell abilities by commander cast spell (to cast from command zone)
|
||||
for (Ability ability : card.getAbilities()) {
|
||||
if (ability instanceof SpellAbility) {
|
||||
SpellAbility spellAbility = (SpellAbility) ability;
|
||||
if (spellAbility.getSpellAbilityType() == SpellAbilityType.BASE_ALTERNATE) {
|
||||
abilities.add(new CastCommanderAbility(card, spellAbility));
|
||||
switch (spellAbility.getSpellAbilityType()) {
|
||||
case BASE:
|
||||
case BASE_ALTERNATE:
|
||||
case SPLIT:
|
||||
case SPLIT_FUSED:
|
||||
case SPLIT_LEFT:
|
||||
case SPLIT_RIGHT:
|
||||
case MODAL:
|
||||
case MODAL_LEFT:
|
||||
case MODAL_RIGHT:
|
||||
case ADVENTURE_SPELL:
|
||||
// can be used from command zone
|
||||
abilities.add(new CastCommanderAbility(card, spellAbility));
|
||||
break;
|
||||
case FACE_DOWN_CREATURE: // dynamic added spell for alternative cost like cast as face down
|
||||
case SPLICE: // only from hand
|
||||
case SPLIT_AFTERMATH: // only from graveyard
|
||||
// can't use from command zone
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Error, unknown spell type in commander card: " + spellAbility.getSpellAbilityType() + " from " + card.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import mage.constants.Zone;
|
|||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.util.CardUtil;
|
||||
import mage.watchers.Watcher;
|
||||
|
||||
import java.util.*;
|
||||
|
|
@ -12,7 +13,7 @@ import java.util.*;
|
|||
/**
|
||||
* Calcs commanders play count only from command zone (spell or land)
|
||||
* Cards like Remand can put command to hand and cast it without commander tax increase
|
||||
*
|
||||
* <p>
|
||||
* Warning, if your code can be called in non commander games then you must watcher in your ability
|
||||
* (example: you are using watcher in trigger, hint or effect, but do not checking another things like commander source or cost)
|
||||
*
|
||||
|
|
@ -33,14 +34,17 @@ public class CommanderPlaysCountWatcher extends Watcher {
|
|||
&& event.getType() != EventType.SPELL_CAST) {
|
||||
return;
|
||||
}
|
||||
|
||||
// must control main cards (split/mdf cards support)
|
||||
final UUID objectId;
|
||||
if (event.getType() == EventType.LAND_PLAYED) {
|
||||
objectId = event.getTargetId();
|
||||
objectId = CardUtil.getMainCardId(game, event.getTargetId());
|
||||
} else if (event.getType() == EventType.SPELL_CAST) {
|
||||
objectId = event.getSourceId();
|
||||
objectId = CardUtil.getMainCardId(game, event.getSourceId());
|
||||
} else {
|
||||
objectId = null;
|
||||
}
|
||||
|
||||
boolean isCommanderObject = game
|
||||
.getPlayerList()
|
||||
.stream()
|
||||
|
|
@ -51,8 +55,8 @@ public class CommanderPlaysCountWatcher extends Watcher {
|
|||
if (!isCommanderObject || event.getZone() != Zone.COMMAND) {
|
||||
return;
|
||||
}
|
||||
playsCount.putIfAbsent(event.getSourceId(), 0);
|
||||
playsCount.computeIfPresent(event.getSourceId(), (u, i) -> i + 1);
|
||||
playsCount.putIfAbsent(objectId, 0);
|
||||
playsCount.computeIfPresent(objectId, (u, i) -> i + 1);
|
||||
playerCount.putIfAbsent(event.getPlayerId(), 0);
|
||||
playerCount.compute(event.getPlayerId(), (u, i) -> i + 1);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue