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:
Maxmtg
2013-03-16 14:27:15 +00:00
parent 1c23640e42
commit e9b51dc21d
7 changed files with 86 additions and 135 deletions

View File

@@ -2,6 +2,8 @@ Name:Chains of Mephistopheles
ManaCost:1 B
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.
SVar:MillOne:DB$ Mill | NumCards$ 1
SVar:DiscardOne:DB$ Discard | Mandatory$ True | NumCards$ 1 | Mode$ TgtChoose
SVar:RemRandomDeck:True
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.

View File

@@ -9052,7 +9052,7 @@ public class Card extends GameEntity implements Comparable<Card> {
* the rE
*/
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);
this.getCharacteristics().getReplacementEffects().add(replacementEffectCopy);
}

View File

@@ -265,7 +265,7 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable {
if (getTurn() == 1 || this.getPlayerTurn().isSkippingDraw()) {
this.setPlayersPriorityPermission(false);
} else {
this.getPlayerTurn().drawCards(1, true);
this.getPlayerTurn().drawCard();
}
break;

View File

@@ -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)
* @see forge.game.player.Player#getType()
*/

View File

@@ -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} */
@Override
public final void sacrificePermanent(final String prompt, final List<Card> choices) {

View File

@@ -42,6 +42,8 @@ import forge.Constant.Preferences;
import forge.CounterType;
import forge.GameEntity;
import forge.Singletons;
import forge.card.ability.AbilityFactory;
import forge.card.ability.AbilityUtils;
import forge.card.cardfactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.mana.ManaPool;
@@ -50,6 +52,7 @@ import forge.card.replacement.ReplacementResult;
import forge.card.spellability.Ability;
import forge.card.spellability.Spell;
import forge.card.spellability.SpellAbility;
import forge.card.spellability.Target;
import forge.card.staticability.StaticAbility;
import forge.card.trigger.TriggerType;
import forge.game.GameActionUtil;
@@ -65,6 +68,7 @@ import forge.game.event.MulliganEvent;
import forge.game.event.PoisonCounterEvent;
import forge.game.event.ShuffleEvent;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
import forge.game.zone.PlayerZone;
import forge.game.zone.PlayerZoneBattlefield;
import forge.game.zone.Zone;
@@ -125,6 +129,7 @@ public abstract class Player extends GameEntity implements Comparable<Player> {
/** The num drawn this turn. */
private int numDrawnThisTurn = 0;
private int numDrawnThisDrawStep = 0;
/** The slowtrip list. */
private List<Card> slowtripList = new ArrayList<Card>();
@@ -1239,70 +1244,6 @@ public abstract class Player extends GameEntity implements Comparable<Player> {
*/
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.
@@ -1328,6 +1269,40 @@ public abstract class Player extends GameEntity implements Comparable<Player> {
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>
* doDraw.
@@ -1348,7 +1323,46 @@ public abstract class Player extends GameEntity implements Comparable<Player> {
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);
c = game.getAction().moveToHand(c);
@@ -1371,6 +1385,8 @@ public abstract class Player extends GameEntity implements Comparable<Player> {
this.setLastDrawnCard(c);
c.setDrawnThisTurn(true);
this.numDrawnThisTurn++;
if ( game.getPhaseHandler().is(PhaseType.DRAW))
this.numDrawnThisDrawStep++;
// Miracle draws
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() {
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>
* discard.

View File

@@ -154,45 +154,6 @@ public final class PlayerUtil {
return target;
} // 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>
* input_sacrificePermanent.