mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-15 18:28:00 +00:00
chains_of_mephistopheles.txt hardcode moved from specific player classes
several instances of Chains of Mephistopheles are handled closer to the rules
This commit is contained in:
@@ -2,6 +2,8 @@ Name:Chains of Mephistopheles
|
|||||||
ManaCost:1 B
|
ManaCost:1 B
|
||||||
Types:Enchantment
|
Types:Enchantment
|
||||||
Text:If a player would draw a card except the first one he or she draws in his or her draw step each turn, that player discards a card instead. If the player discards a card this way, he or she draws a card. If the player doesn't discard a card this way, he or she puts the top card of his or her library into his or her graveyard.
|
Text:If a player would draw a card except the first one he or she draws in his or her draw step each turn, that player discards a card instead. If the player discards a card this way, he or she draws a card. If the player doesn't discard a card this way, he or she puts the top card of his or her library into his or her graveyard.
|
||||||
|
SVar:MillOne:DB$ Mill | NumCards$ 1
|
||||||
|
SVar:DiscardOne:DB$ Discard | Mandatory$ True | NumCards$ 1 | Mode$ TgtChoose
|
||||||
SVar:RemRandomDeck:True
|
SVar:RemRandomDeck:True
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/chains_of_mephistopheles.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/chains_of_mephistopheles.jpg
|
||||||
Oracle:If a player would draw a card except the first one he or she draws in his or her draw step each turn, that player discards a card instead. If the player discards a card this way, he or she draws a card. If the player doesn't discard a card this way, he or she puts the top card of his or her library into his or her graveyard.
|
Oracle:If a player would draw a card except the first one he or she draws in his or her draw step each turn, that player discards a card instead. If the player discards a card this way, he or she draws a card. If the player doesn't discard a card this way, he or she puts the top card of his or her library into his or her graveyard.
|
||||||
|
|||||||
@@ -9052,7 +9052,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
* the rE
|
* the rE
|
||||||
*/
|
*/
|
||||||
public void addReplacementEffect(final ReplacementEffect replacementEffect) {
|
public void addReplacementEffect(final ReplacementEffect replacementEffect) {
|
||||||
final ReplacementEffect replacementEffectCopy = replacementEffect.getCopy();
|
final ReplacementEffect replacementEffectCopy = replacementEffect.getCopy(); // doubtful - every caller provides a newly parsed instance, why copy?
|
||||||
replacementEffectCopy.setHostCard(this);
|
replacementEffectCopy.setHostCard(this);
|
||||||
this.getCharacteristics().getReplacementEffects().add(replacementEffectCopy);
|
this.getCharacteristics().getReplacementEffects().add(replacementEffectCopy);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -265,7 +265,7 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
|
|||||||
if (getTurn() == 1 || this.getPlayerTurn().isSkippingDraw()) {
|
if (getTurn() == 1 || this.getPlayerTurn().isSkippingDraw()) {
|
||||||
this.setPlayersPriorityPermission(false);
|
this.setPlayersPriorityPermission(false);
|
||||||
} else {
|
} else {
|
||||||
this.getPlayerTurn().drawCards(1, true);
|
this.getPlayerTurn().drawCard();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
@@ -144,17 +144,6 @@ public class AIPlayer extends Player {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
*
|
|
||||||
* @see forge.Player#discard_Chains_of_Mephistopheles()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected final void discardChainsOfMephistopheles() {
|
|
||||||
this.discard(1, null);
|
|
||||||
this.drawCard();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see forge.game.player.Player#getType()
|
* @see forge.game.player.Player#getType()
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -100,19 +100,6 @@ public class HumanPlayer extends Player {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
*
|
|
||||||
* @see forge.Player#discard_Chains_of_Mephistopheles()
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected final void discardChainsOfMephistopheles() {
|
|
||||||
Singletons.getModel().getMatch().getInput().setInputInterrupt(PlayerUtil.inputChainsDiscard());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public final void sacrificePermanent(final String prompt, final List<Card> choices) {
|
public final void sacrificePermanent(final String prompt, final List<Card> choices) {
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ import forge.Constant.Preferences;
|
|||||||
import forge.CounterType;
|
import forge.CounterType;
|
||||||
import forge.GameEntity;
|
import forge.GameEntity;
|
||||||
import forge.Singletons;
|
import forge.Singletons;
|
||||||
|
import forge.card.ability.AbilityFactory;
|
||||||
|
import forge.card.ability.AbilityUtils;
|
||||||
import forge.card.cardfactory.CardFactoryUtil;
|
import forge.card.cardfactory.CardFactoryUtil;
|
||||||
import forge.card.cost.Cost;
|
import forge.card.cost.Cost;
|
||||||
import forge.card.mana.ManaPool;
|
import forge.card.mana.ManaPool;
|
||||||
@@ -50,6 +52,7 @@ import forge.card.replacement.ReplacementResult;
|
|||||||
import forge.card.spellability.Ability;
|
import forge.card.spellability.Ability;
|
||||||
import forge.card.spellability.Spell;
|
import forge.card.spellability.Spell;
|
||||||
import forge.card.spellability.SpellAbility;
|
import forge.card.spellability.SpellAbility;
|
||||||
|
import forge.card.spellability.Target;
|
||||||
import forge.card.staticability.StaticAbility;
|
import forge.card.staticability.StaticAbility;
|
||||||
import forge.card.trigger.TriggerType;
|
import forge.card.trigger.TriggerType;
|
||||||
import forge.game.GameActionUtil;
|
import forge.game.GameActionUtil;
|
||||||
@@ -65,6 +68,7 @@ import forge.game.event.MulliganEvent;
|
|||||||
import forge.game.event.PoisonCounterEvent;
|
import forge.game.event.PoisonCounterEvent;
|
||||||
import forge.game.event.ShuffleEvent;
|
import forge.game.event.ShuffleEvent;
|
||||||
import forge.game.phase.PhaseHandler;
|
import forge.game.phase.PhaseHandler;
|
||||||
|
import forge.game.phase.PhaseType;
|
||||||
import forge.game.zone.PlayerZone;
|
import forge.game.zone.PlayerZone;
|
||||||
import forge.game.zone.PlayerZoneBattlefield;
|
import forge.game.zone.PlayerZoneBattlefield;
|
||||||
import forge.game.zone.Zone;
|
import forge.game.zone.Zone;
|
||||||
@@ -125,6 +129,7 @@ public abstract class Player extends GameEntity implements Comparable<Player> {
|
|||||||
|
|
||||||
/** The num drawn this turn. */
|
/** The num drawn this turn. */
|
||||||
private int numDrawnThisTurn = 0;
|
private int numDrawnThisTurn = 0;
|
||||||
|
private int numDrawnThisDrawStep = 0;
|
||||||
|
|
||||||
/** The slowtrip list. */
|
/** The slowtrip list. */
|
||||||
private List<Card> slowtripList = new ArrayList<Card>();
|
private List<Card> slowtripList = new ArrayList<Card>();
|
||||||
@@ -1239,70 +1244,6 @@ public abstract class Player extends GameEntity implements Comparable<Player> {
|
|||||||
*/
|
*/
|
||||||
public abstract boolean dredge();
|
public abstract boolean dredge();
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* drawCards.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param n
|
|
||||||
* a int.
|
|
||||||
* @return a List<Card> of cards actually drawn
|
|
||||||
*/
|
|
||||||
public final List<Card> drawCards(final int n) {
|
|
||||||
return this.drawCards(n, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* drawCards.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param n
|
|
||||||
* a int.
|
|
||||||
* @param firstFromDraw
|
|
||||||
* true if this is the card drawn from that player's draw step
|
|
||||||
* each turn
|
|
||||||
* @return a List<Card> of cards actually drawn
|
|
||||||
*/
|
|
||||||
public final List<Card> drawCards(final int n, final boolean firstFromDraw) {
|
|
||||||
final List<Card> drawn = new ArrayList<Card>();
|
|
||||||
|
|
||||||
if (!this.canDraw()) {
|
|
||||||
return drawn;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < n; i++) {
|
|
||||||
|
|
||||||
// TODO: multiple replacements need to be selected by the controller
|
|
||||||
if (this.getDredge().size() != 0) {
|
|
||||||
if (this.dredge()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!firstFromDraw && game.isCardInPlay("Chains of Mephistopheles")) {
|
|
||||||
if (!this.getZone(ZoneType.Hand).isEmpty()) {
|
|
||||||
if (this.isHuman()) {
|
|
||||||
this.discardChainsOfMephistopheles();
|
|
||||||
} else { // Computer
|
|
||||||
this.discard(1, null);
|
|
||||||
// true causes this code not to be run again
|
|
||||||
drawn.addAll(this.drawCards(1, true));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.mill(1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
drawn.addAll(this.doDraw());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Play the Draw sound
|
|
||||||
game.getEvents().post(new DrawCardEvent());
|
|
||||||
|
|
||||||
return drawn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* TODO Write javadoc for this method.
|
* TODO Write javadoc for this method.
|
||||||
@@ -1328,6 +1269,40 @@ public abstract class Player extends GameEntity implements Comparable<Player> {
|
|||||||
stats.notifyOpeningHandSize(newHand);
|
stats.notifyOpeningHandSize(newHand);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* drawCards.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param n
|
||||||
|
* a int.
|
||||||
|
* @return a List<Card> of cards actually drawn
|
||||||
|
*/
|
||||||
|
public final List<Card> drawCards(final int n) {
|
||||||
|
final List<Card> drawn = new ArrayList<Card>();
|
||||||
|
|
||||||
|
if (!this.canDraw()) {
|
||||||
|
return drawn;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
|
||||||
|
// TODO: multiple replacements need to be selected by the controller
|
||||||
|
if (!this.getDredge().isEmpty()) {
|
||||||
|
if (this.dredge()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drawn.addAll(this.doDraw());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Play the Draw sound
|
||||||
|
game.getEvents().post(new DrawCardEvent());
|
||||||
|
|
||||||
|
return drawn;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* doDraw.
|
* doDraw.
|
||||||
@@ -1348,7 +1323,46 @@ public abstract class Player extends GameEntity implements Comparable<Player> {
|
|||||||
return drawn;
|
return drawn;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (library.size() != 0) {
|
// ======== Chains of Mephistopheles hardcode. =========
|
||||||
|
// This card requires player to either discard a card, and then he may proceed drawing, or mill 1 - then no draw will happen
|
||||||
|
// It's oracle-worded as a replacement effect ("If a player would draw a card ... discards a card instead") (rule 419.1a)
|
||||||
|
// Yet, gatherer's rulings read: The effect is cumulative. If there are two of these on the battlefield, each of them will modify each draw
|
||||||
|
// That means player isn't supposed to choose one replacement effect out of two (generated by Chains Of Mephistopheles), but both happen.
|
||||||
|
// So it's not a common replacement effect and has to handled by special code.
|
||||||
|
|
||||||
|
// This is why the code is placed after any other replacement effects could affect the draw event.
|
||||||
|
List<Card> chainsList = null;
|
||||||
|
for(Card c: game.getCardsInGame()) {
|
||||||
|
if ( c.getName().equals("Chains of Mephistopheles") ) {
|
||||||
|
if ( null == chainsList )
|
||||||
|
chainsList = new ArrayList<Card>();
|
||||||
|
chainsList.add(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chainsList != null && (numDrawnThisDrawStep > 0 || !game.getPhaseHandler().is(PhaseType.DRAW))) {
|
||||||
|
for(Card c : chainsList) {
|
||||||
|
// I have to target this player - don't know how to do it.
|
||||||
|
Target target = new Target(c, null, "");
|
||||||
|
target.addTarget(this);
|
||||||
|
|
||||||
|
if (getCardsIn(ZoneType.Hand).isEmpty()) {
|
||||||
|
SpellAbility saMill = AbilityFactory.getAbility(c.getSVar("MillOne"), c);
|
||||||
|
saMill.setActivatingPlayer(c.getController());
|
||||||
|
saMill.setTarget(target);
|
||||||
|
AbilityUtils.resolve(saMill, false);
|
||||||
|
|
||||||
|
return drawn; // Draw is cancelled
|
||||||
|
} else {
|
||||||
|
SpellAbility saDiscard = AbilityFactory.getAbility(c.getSVar("DiscardOne"), c);
|
||||||
|
saDiscard.setActivatingPlayer(c.getController());
|
||||||
|
saDiscard.setTarget(target);
|
||||||
|
AbilityUtils.resolve(saDiscard, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// End of = Chains of Mephistopheles hardcode. =========
|
||||||
|
|
||||||
|
if (!library.isEmpty()) {
|
||||||
|
|
||||||
Card c = library.get(0);
|
Card c = library.get(0);
|
||||||
c = game.getAction().moveToHand(c);
|
c = game.getAction().moveToHand(c);
|
||||||
@@ -1371,6 +1385,8 @@ public abstract class Player extends GameEntity implements Comparable<Player> {
|
|||||||
this.setLastDrawnCard(c);
|
this.setLastDrawnCard(c);
|
||||||
c.setDrawnThisTurn(true);
|
c.setDrawnThisTurn(true);
|
||||||
this.numDrawnThisTurn++;
|
this.numDrawnThisTurn++;
|
||||||
|
if ( game.getPhaseHandler().is(PhaseType.DRAW))
|
||||||
|
this.numDrawnThisDrawStep++;
|
||||||
|
|
||||||
// Miracle draws
|
// Miracle draws
|
||||||
if (this.numDrawnThisTurn == 1 && game.getPhaseHandler().getTurn() != 0) {
|
if (this.numDrawnThisTurn == 1 && game.getPhaseHandler().getTurn() != 0) {
|
||||||
@@ -1550,6 +1566,7 @@ public abstract class Player extends GameEntity implements Comparable<Player> {
|
|||||||
*/
|
*/
|
||||||
public final void resetNumDrawnThisTurn() {
|
public final void resetNumDrawnThisTurn() {
|
||||||
this.numDrawnThisTurn = 0;
|
this.numDrawnThisTurn = 0;
|
||||||
|
this.numDrawnThisDrawStep = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1569,11 +1586,6 @@ public abstract class Player extends GameEntity implements Comparable<Player> {
|
|||||||
// /
|
// /
|
||||||
// //////////////////////////////
|
// //////////////////////////////
|
||||||
|
|
||||||
/**
|
|
||||||
* Discard_ chains_of_ mephistopheles.
|
|
||||||
*/
|
|
||||||
protected abstract void discardChainsOfMephistopheles();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* discard.
|
* discard.
|
||||||
|
|||||||
@@ -154,45 +154,6 @@ public final class PlayerUtil {
|
|||||||
return target;
|
return target;
|
||||||
} // input_discard()
|
} // input_discard()
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* input_chainsDiscard.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @return a {@link forge.control.input.Input} object.
|
|
||||||
*/
|
|
||||||
public static Input inputChainsDiscard() {
|
|
||||||
final Input target = new Input() {
|
|
||||||
private static final long serialVersionUID = 2856894846224546303L;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void showMessage() {
|
|
||||||
if (Singletons.getControl().getPlayer().getZone(ZoneType.Hand).size() == 0) {
|
|
||||||
this.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
CMatchUI.SINGLETON_INSTANCE.showMessage("Chains of Mephistopheles:\n" + "Select a card to discard");
|
|
||||||
ButtonUtil.disableAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void selectCard(final Card card) {
|
|
||||||
Zone zone = Singletons.getModel().getGame().getZoneOf(card);
|
|
||||||
if (zone.is(ZoneType.Hand)) {
|
|
||||||
card.getController().discard(card, null);
|
|
||||||
this.done();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void done() {
|
|
||||||
this.stop();
|
|
||||||
// hack to not trigger Chains of Mephistopheles recursively
|
|
||||||
Singletons.getControl().getPlayer().drawCards(1, true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return target;
|
|
||||||
} // input_chainsDiscard()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* input_sacrificePermanent.
|
* input_sacrificePermanent.
|
||||||
|
|||||||
Reference in New Issue
Block a user