mirror of
https://github.com/correl/mage.git
synced 2024-12-25 11:11:16 +00:00
Merge branch 'master' into Zzooouhh-banding-final
This commit is contained in:
commit
3dbd5a72c4
18 changed files with 175 additions and 110 deletions
|
@ -1,7 +1,7 @@
|
||||||
XMage.de 1 (Europe/Germany) fast :xmage.de:17171
|
XMage.de 1 (Europe/Germany) fast :xmage.de:17171
|
||||||
woogerworks (North America/USA) :xmage.woogerworks.com:17171
|
old xmage.de (Europe/Germany) :185.3.232.200:17171
|
||||||
play.xmage.net (North America/Canada) :play.xmage.net:17171
|
xmage.us (North America/USA) :xmage.us:17171
|
||||||
XMageBr. (South America/Brazil) :magic.ncs3sistemas.com.br:17171
|
XMage Players MTG:xmageplayersmtg.ddns.net:17171
|
||||||
XMage.tahiti :xmage.tahiti.one:443
|
XMage.tahiti :xmage.tahiti.one:443
|
||||||
Seedds Server (Asia) :115.29.203.80:17171
|
Seedds Server (Asia) :115.29.203.80:17171
|
||||||
localhost -> connect to your local server (must be started):localhost:17171
|
localhost -> connect to your local server (must be started):localhost:17171
|
||||||
|
|
|
@ -134,12 +134,6 @@ public final class GuiDisplayUtil {
|
||||||
for (String rule : card.getRules()) {
|
for (String rule : card.getRules()) {
|
||||||
textLines.basicTextLength += rule.length();
|
textLines.basicTextLength += rule.length();
|
||||||
}
|
}
|
||||||
if (card.getMageObjectType() == MageObjectType.PERMANENT) {
|
|
||||||
if (card.getPairedCard() != null) {
|
|
||||||
textLines.lines.add("<span color='green'><i>Paired with another creature</i></span>");
|
|
||||||
textLines.basicTextLength += 30;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (card.getMageObjectType().canHaveCounters()) {
|
if (card.getMageObjectType().canHaveCounters()) {
|
||||||
ArrayList<CounterView> counters = new ArrayList<>();
|
ArrayList<CounterView> counters = new ArrayList<>();
|
||||||
if (card instanceof PermanentView) {
|
if (card instanceof PermanentView) {
|
||||||
|
|
|
@ -41,7 +41,7 @@ public class MageVersion implements Serializable, Comparable<MageVersion> {
|
||||||
public final static int MAGE_VERSION_MAJOR = 1;
|
public final static int MAGE_VERSION_MAJOR = 1;
|
||||||
public final static int MAGE_VERSION_MINOR = 4;
|
public final static int MAGE_VERSION_MINOR = 4;
|
||||||
public final static int MAGE_VERSION_PATCH = 27;
|
public final static int MAGE_VERSION_PATCH = 27;
|
||||||
public final static String MAGE_VERSION_MINOR_PATCH = "V3";
|
public final static String MAGE_VERSION_MINOR_PATCH = "V4";
|
||||||
public final static String MAGE_VERSION_INFO = "";
|
public final static String MAGE_VERSION_INFO = "";
|
||||||
|
|
||||||
private final int major;
|
private final int major;
|
||||||
|
|
|
@ -55,7 +55,7 @@ public class ContestedWarZone extends CardImpl {
|
||||||
private static final FilterAttackingCreature filter = new FilterAttackingCreature("Attacking creatures");
|
private static final FilterAttackingCreature filter = new FilterAttackingCreature("Attacking creatures");
|
||||||
|
|
||||||
public ContestedWarZone(UUID ownerId, CardSetInfo setInfo) {
|
public ContestedWarZone(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId,setInfo,new CardType[]{CardType.LAND},null);
|
super(ownerId, setInfo, new CardType[]{CardType.LAND}, null);
|
||||||
|
|
||||||
// Whenever a creature deals combat damage to you, that creature's controller gains control of Contested War Zone.
|
// Whenever a creature deals combat damage to you, that creature's controller gains control of Contested War Zone.
|
||||||
this.addAbility(new ContestedWarZoneAbility());
|
this.addAbility(new ContestedWarZoneAbility());
|
||||||
|
@ -102,7 +102,7 @@ class ContestedWarZoneAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkTrigger(GameEvent event, Game game) {
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
DamagedPlayerEvent damageEvent = (DamagedPlayerEvent)event;
|
DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event;
|
||||||
if (damageEvent.isCombatDamage()) {
|
if (damageEvent.isCombatDamage()) {
|
||||||
Permanent permanent = game.getPermanent(event.getSourceId());
|
Permanent permanent = game.getPermanent(event.getSourceId());
|
||||||
if (damageEvent.getPlayerId().equals(getControllerId()) && permanent != null && permanent.isCreature()) {
|
if (damageEvent.getPlayerId().equals(getControllerId()) && permanent != null && permanent.isCreature()) {
|
||||||
|
@ -137,7 +137,7 @@ class ContestedWarZoneEffect extends ContinuousEffectImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Permanent permanent = (Permanent) source.getSourceObjectIfItStillExists(game);
|
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||||
UUID controllerId = (UUID) game.getState().getValue(source.getSourceId().toString());
|
UUID controllerId = (UUID) game.getState().getValue(source.getSourceId().toString());
|
||||||
if (permanent != null && controllerId != null) {
|
if (permanent != null && controllerId != null) {
|
||||||
return permanent.changeControllerId(controllerId, game);
|
return permanent.changeControllerId(controllerId, game);
|
||||||
|
|
|
@ -45,7 +45,7 @@ import mage.target.common.TargetCreatureOrPlayer;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author KholdFuzion
|
* @author KholdFuzion
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public class DrainLife extends CardImpl {
|
public class DrainLife extends CardImpl {
|
||||||
|
|
||||||
|
@ -55,10 +55,8 @@ public class DrainLife extends CardImpl {
|
||||||
filterBlack.setBlack(true);
|
filterBlack.setBlack(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public DrainLife(UUID ownerId, CardSetInfo setInfo) {
|
public DrainLife(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{1}{B}");
|
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{1}{B}");
|
||||||
|
|
||||||
|
|
||||||
// Spend only black mana on X.
|
// Spend only black mana on X.
|
||||||
// Drain Life deals X damage to target creature or player. You gain life equal to the damage dealt, but not more life than the player's life total before Drain Life dealt damage or the creature's toughness.
|
// Drain Life deals X damage to target creature or player. You gain life equal to the damage dealt, but not more life than the player's life total before Drain Life dealt damage or the creature's toughness.
|
||||||
|
@ -84,7 +82,7 @@ class DrainLifeEffect extends OneShotEffect {
|
||||||
|
|
||||||
public DrainLifeEffect() {
|
public DrainLifeEffect() {
|
||||||
super(Outcome.Damage);
|
super(Outcome.Damage);
|
||||||
staticText = "Drain Life deals X damage to target creature or player. You gain life equal to the damage dealt, but not more life than the player's life total before Drain Life dealt damage or the creature's toughness.";
|
staticText = "Spend only black mana on X.<br>{this} deals X damage to target creature or player. You gain life equal to the damage dealt, but not more life than the player's life total before Drain Life dealt damage or the creature's toughness";
|
||||||
}
|
}
|
||||||
|
|
||||||
public DrainLifeEffect(final DrainLifeEffect effect) {
|
public DrainLifeEffect(final DrainLifeEffect effect) {
|
||||||
|
@ -97,7 +95,7 @@ class DrainLifeEffect extends OneShotEffect {
|
||||||
int lifetogain = amount;
|
int lifetogain = amount;
|
||||||
if (amount > 0) {
|
if (amount > 0) {
|
||||||
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
|
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||||
if (permanent != null ) {
|
if (permanent != null) {
|
||||||
if (permanent.getToughness().getValue() < amount) {
|
if (permanent.getToughness().getValue() < amount) {
|
||||||
lifetogain = permanent.getToughness().getValue();
|
lifetogain = permanent.getToughness().getValue();
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,7 +178,7 @@ class EyeOfTheStormEffect1 extends OneShotEffect {
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean continueCasting = true;
|
boolean continueCasting = true;
|
||||||
while (continueCasting) {
|
while (spellController.isInGame() && continueCasting) {
|
||||||
continueCasting = copiedCards.size() > 1 && spellController.chooseUse(outcome, "Cast one of the copied cards without paying its mana cost?", source, game);
|
continueCasting = copiedCards.size() > 1 && spellController.chooseUse(outcome, "Cast one of the copied cards without paying its mana cost?", source, game);
|
||||||
|
|
||||||
Card cardToCopy;
|
Card cardToCopy;
|
||||||
|
|
|
@ -2,10 +2,8 @@ package mage.cards.g;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.abilities.Ability;
|
|
||||||
import mage.abilities.TriggeredAbility;
|
import mage.abilities.TriggeredAbility;
|
||||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||||
import mage.abilities.condition.Condition;
|
|
||||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||||
import mage.abilities.decorator.ConditionalTriggeredAbility;
|
import mage.abilities.decorator.ConditionalTriggeredAbility;
|
||||||
import mage.abilities.effects.common.ReturnToHandTargetEffect;
|
import mage.abilities.effects.common.ReturnToHandTargetEffect;
|
||||||
|
@ -16,7 +14,6 @@ import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.SubType;
|
import mage.constants.SubType;
|
||||||
import mage.filter.common.FilterCreatureCard;
|
import mage.filter.common.FilterCreatureCard;
|
||||||
import mage.game.Game;
|
|
||||||
import mage.target.common.TargetCardInGraveyard;
|
import mage.target.common.TargetCardInGraveyard;
|
||||||
|
|
||||||
public class GraveScrabbler extends CardImpl {
|
public class GraveScrabbler extends CardImpl {
|
||||||
|
@ -35,7 +32,7 @@ public class GraveScrabbler extends CardImpl {
|
||||||
//you may return target creature card from a graveyard to its owner's hand.
|
//you may return target creature card from a graveyard to its owner's hand.
|
||||||
TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true);
|
TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true);
|
||||||
ability.addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card in a graveyard")));
|
ability.addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card in a graveyard")));
|
||||||
this.addAbility(new ConditionalTriggeredAbility(ability, MadnessPaidCondition.instance,
|
this.addAbility(new ConditionalTriggeredAbility(ability, MadnessAbility.GetCondition(),
|
||||||
"When {this} enters the battlefield, if its madness cost was paid, you may return target creature card from a graveyard to its owner's hand."));
|
"When {this} enters the battlefield, if its madness cost was paid, you may return target creature card from a graveyard to its owner's hand."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,21 +46,3 @@ public class GraveScrabbler extends CardImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MadnessPaidCondition implements Condition {
|
|
||||||
instance;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean apply(Game game, Ability source) {
|
|
||||||
Card card = game.getCard(source.getSourceId());
|
|
||||||
if (card != null) {
|
|
||||||
for (Ability ability : card.getAbilities()) {
|
|
||||||
if (ability instanceof MadnessAbility) {
|
|
||||||
return ((MadnessAbility) ability).getCosts().isPaid();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -44,14 +44,13 @@ import mage.target.targetpointer.SecondTargetPointer;
|
||||||
public class Lunge extends CardImpl {
|
public class Lunge extends CardImpl {
|
||||||
|
|
||||||
public Lunge(UUID ownerId, CardSetInfo setInfo) {
|
public Lunge(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{R}");
|
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}");
|
||||||
|
|
||||||
|
|
||||||
// Lunge deals 2 damage to target creature and 2 damage to target player.
|
// Lunge deals 2 damage to target creature and 2 damage to target player.
|
||||||
this.getSpellAbility().addEffect(new DamageTargetEffect(2));
|
this.getSpellAbility().addEffect(new DamageTargetEffect(2).setUseOnlyTargetPointer(true));
|
||||||
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
|
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
|
||||||
|
|
||||||
Effect effect = new DamageTargetEffect(2);
|
Effect effect = new DamageTargetEffect(2).setUseOnlyTargetPointer(true);
|
||||||
effect.setTargetPointer(new SecondTargetPointer());
|
effect.setTargetPointer(new SecondTargetPointer());
|
||||||
effect.setText("and 2 damage to target player");
|
effect.setText("and 2 damage to target player");
|
||||||
this.getSpellAbility().addEffect(effect);
|
this.getSpellAbility().addEffect(effect);
|
||||||
|
|
|
@ -29,6 +29,7 @@ package org.mage.test.cards.abilities.keywords;
|
||||||
|
|
||||||
import mage.constants.PhaseStep;
|
import mage.constants.PhaseStep;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
@ -512,4 +513,45 @@ public class FlashbackTest extends CardTestPlayerBase {
|
||||||
assertExileCount(playerA, dReturn, 1);
|
assertExileCount(playerA, dReturn, 1);
|
||||||
assertPermanentCount(playerA, bSable, 1);
|
assertPermanentCount(playerA, bSable, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* I can play Force of Will with flashback paying his alternative mana cost.
|
||||||
|
* The ruling say no to it, because we only can choose one alternative cost
|
||||||
|
* to a spell, and the flashback cost is already an alternative cost.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
@Ignore
|
||||||
|
public void testSnapcasterMageSpellWithAlternateCost() {
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
||||||
|
// When Snapcaster Mage enters the battlefield, target instant or sorcery card in your graveyard gains flashback until end of turn.
|
||||||
|
// The flashback cost is equal to its mana cost.
|
||||||
|
addCard(Zone.HAND, playerA, "Snapcaster Mage", 2); // Creature{1}{U}
|
||||||
|
|
||||||
|
// You may pay 1 life and exile a blue card from your hand rather than pay Force of Will's mana cost.
|
||||||
|
// Counter target spell.
|
||||||
|
addCard(Zone.GRAVEYARD, playerA, "Force of Will");
|
||||||
|
|
||||||
|
addCard(Zone.HAND, playerB, "Lightning Bolt", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Snapcaster Mage");
|
||||||
|
setChoice(playerA, "Force of Will");
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Lightning Bolt", "Snapcaster Mage");
|
||||||
|
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Flashback", null, "Lightning Bolt");
|
||||||
|
addTarget(playerA, "Lightning Bolt");
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, "Snapcaster Mage", 0);
|
||||||
|
assertGraveyardCount(playerA, "Snapcaster Mage", 1);
|
||||||
|
|
||||||
|
assertGraveyardCount(playerA, "Force of Will", 1);
|
||||||
|
assertGraveyardCount(playerB, "Lightning Bolt", 1);
|
||||||
|
|
||||||
|
assertLife(playerA, 20);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@ import mage.cards.Card;
|
||||||
import mage.cards.SplitCard;
|
import mage.cards.SplitCard;
|
||||||
import mage.constants.AbilityType;
|
import mage.constants.AbilityType;
|
||||||
import mage.constants.AsThoughEffectType;
|
import mage.constants.AsThoughEffectType;
|
||||||
|
import mage.constants.SpellAbilityCastMode;
|
||||||
import mage.constants.SpellAbilityType;
|
import mage.constants.SpellAbilityType;
|
||||||
import mage.constants.TimingRule;
|
import mage.constants.TimingRule;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
|
@ -51,6 +52,7 @@ import mage.players.Player;
|
||||||
public class SpellAbility extends ActivatedAbilityImpl {
|
public class SpellAbility extends ActivatedAbilityImpl {
|
||||||
|
|
||||||
protected SpellAbilityType spellAbilityType;
|
protected SpellAbilityType spellAbilityType;
|
||||||
|
protected SpellAbilityCastMode spellAbilityCastMode;
|
||||||
protected String cardName;
|
protected String cardName;
|
||||||
|
|
||||||
public SpellAbility(ManaCost cost, String cardName) {
|
public SpellAbility(ManaCost cost, String cardName) {
|
||||||
|
@ -62,23 +64,22 @@ public class SpellAbility extends ActivatedAbilityImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
public SpellAbility(ManaCost cost, String cardName, Zone zone, SpellAbilityType spellAbilityType) {
|
public SpellAbility(ManaCost cost, String cardName, Zone zone, SpellAbilityType spellAbilityType) {
|
||||||
|
this(cost, cardName, zone, spellAbilityType, SpellAbilityCastMode.NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpellAbility(ManaCost cost, String cardName, Zone zone, SpellAbilityType spellAbilityType, SpellAbilityCastMode spellAbilityCastMode) {
|
||||||
super(AbilityType.SPELL, zone);
|
super(AbilityType.SPELL, zone);
|
||||||
this.cardName = cardName;
|
this.cardName = cardName;
|
||||||
this.spellAbilityType = spellAbilityType;
|
this.spellAbilityType = spellAbilityType;
|
||||||
|
this.spellAbilityCastMode = spellAbilityCastMode;
|
||||||
this.addManaCost(cost);
|
this.addManaCost(cost);
|
||||||
switch (spellAbilityType) {
|
setSpellName();
|
||||||
case SPLIT_FUSED:
|
|
||||||
this.name = "Cast fused " + cardName;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
this.name = "Cast " + cardName;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SpellAbility(final SpellAbility ability) {
|
public SpellAbility(final SpellAbility ability) {
|
||||||
super(ability);
|
super(ability);
|
||||||
this.spellAbilityType = ability.spellAbilityType;
|
this.spellAbilityType = ability.spellAbilityType;
|
||||||
|
this.spellAbilityCastMode = ability.spellAbilityCastMode;
|
||||||
this.cardName = ability.cardName;
|
this.cardName = ability.cardName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,4 +210,24 @@ public class SpellAbility extends ActivatedAbilityImpl {
|
||||||
}
|
}
|
||||||
return amount * xMultiplier;
|
return amount * xMultiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setSpellName() {
|
||||||
|
switch (spellAbilityType) {
|
||||||
|
case SPLIT_FUSED:
|
||||||
|
this.name = "Cast fused " + cardName;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.name = "Cast " + cardName + (this.spellAbilityCastMode != SpellAbilityCastMode.NORMAL ? " by " + spellAbilityCastMode.toString() : "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpellAbilityCastMode getSpellAbilityCastMode() {
|
||||||
|
return spellAbilityCastMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSpellAbilityCastMode(SpellAbilityCastMode spellAbilityCastMode) {
|
||||||
|
this.spellAbilityCastMode = spellAbilityCastMode;
|
||||||
|
setSpellName();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,9 @@ public class AddManaOfAnyColorEffect extends BasicManaEffect {
|
||||||
String mes = String.format("Select color of %d mana to add it to your mana pool", this.amount);
|
String mes = String.format("Select color of %d mana to add it to your mana pool", this.amount);
|
||||||
ChoiceColor choice = new ChoiceColor(true, mes, game.getObject(source.getSourceId()));
|
ChoiceColor choice = new ChoiceColor(true, mes, game.getObject(source.getSourceId()));
|
||||||
if (controller.choose(outcome, choice, game)) {
|
if (controller.choose(outcome, choice, game)) {
|
||||||
|
if (choice.getColor() == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Mana createdMana = choice.getMana(amount);
|
Mana createdMana = choice.getMana(amount);
|
||||||
if (createdMana != null) {
|
if (createdMana != null) {
|
||||||
checkToFirePossibleEvents(createdMana, game, source);
|
checkToFirePossibleEvents(createdMana, game, source);
|
||||||
|
|
|
@ -11,8 +11,6 @@ import mage.constants.SubLayer;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class PlayLandsFromGraveyardEffect extends ContinuousEffectImpl {
|
public class PlayLandsFromGraveyardEffect extends ContinuousEffectImpl {
|
||||||
|
|
||||||
public PlayLandsFromGraveyardEffect() {
|
public PlayLandsFromGraveyardEffect() {
|
||||||
|
@ -33,11 +31,10 @@ public class PlayLandsFromGraveyardEffect extends ContinuousEffectImpl {
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Player player = game.getPlayer(source.getControllerId());
|
Player player = game.getPlayer(source.getControllerId());
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
for (UUID cardId: player.getGraveyard()) {
|
for (Card card : player.getGraveyard().getCards(game)) {
|
||||||
Card card = game.getCard(cardId);
|
if (card != null && card.isLand()) {
|
||||||
if(card != null && card.isLand()){
|
|
||||||
PlayLandFromGraveyardAbility ability = new PlayLandFromGraveyardAbility(card.getName());
|
PlayLandFromGraveyardAbility ability = new PlayLandFromGraveyardAbility(card.getName());
|
||||||
ability.setSourceId(cardId);
|
ability.setSourceId(card.getId());
|
||||||
ability.setControllerId(card.getOwnerId());
|
ability.setControllerId(card.getOwnerId());
|
||||||
game.getState().addOtherAbility(card, ability);
|
game.getState().addOtherAbility(card, ability);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package mage.abilities.keyword;
|
package mage.abilities.keyword;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import mage.MageObject;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.SpellAbility;
|
||||||
import mage.abilities.StaticAbility;
|
import mage.abilities.StaticAbility;
|
||||||
import mage.abilities.TriggeredAbilityImpl;
|
import mage.abilities.TriggeredAbilityImpl;
|
||||||
import mage.abilities.condition.Condition;
|
import mage.abilities.condition.Condition;
|
||||||
|
@ -13,10 +14,13 @@ import mage.abilities.effects.ReplacementEffectImpl;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.constants.Duration;
|
import mage.constants.Duration;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
|
import mage.constants.SpellAbilityCastMode;
|
||||||
|
import mage.constants.SpellAbilityType;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
import mage.game.events.ZoneChangeEvent;
|
import mage.game.events.ZoneChangeEvent;
|
||||||
|
import mage.game.stack.Spell;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -133,8 +137,6 @@ class MadnessReplacementEffect extends ReplacementEffectImpl {
|
||||||
*/
|
*/
|
||||||
class MadnessTriggeredAbility extends TriggeredAbilityImpl {
|
class MadnessTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
//This array holds the Id's of all of the cards that activated madness
|
|
||||||
private static ArrayList<UUID> activatedIds = new ArrayList<>();
|
|
||||||
private final UUID madnessOriginalId;
|
private final UUID madnessOriginalId;
|
||||||
|
|
||||||
MadnessTriggeredAbility(ManaCosts<ManaCost> madnessCost, UUID madnessOriginalId) {
|
MadnessTriggeredAbility(ManaCosts<ManaCost> madnessCost, UUID madnessOriginalId) {
|
||||||
|
@ -176,25 +178,9 @@ class MadnessTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
activatedIds.add(getSourceId());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isActivated() {
|
|
||||||
//Look through the list of activated Ids and see if the current source's Id is one of them
|
|
||||||
for (UUID currentId : activatedIds) {
|
|
||||||
if (currentId.equals(getSourceId())) {
|
|
||||||
//Remove the current source from the list, so if the card is somehow recast without
|
|
||||||
//paying the madness cost, this will return false
|
|
||||||
activatedIds.remove(currentId);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//If the current source's Id was not found, return false
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getRule() {
|
public String getRule() {
|
||||||
return "When this card is exiled this way, " + super.getRule();
|
return "When this card is exiled this way, " + super.getRule();
|
||||||
|
@ -225,17 +211,15 @@ class MadnessCastEffect extends OneShotEffect {
|
||||||
}
|
}
|
||||||
if (owner != null && card != null
|
if (owner != null && card != null
|
||||||
&& owner.chooseUse(outcome, "Cast " + card.getLogName() + " by madness?", source, game)) {
|
&& owner.chooseUse(outcome, "Cast " + card.getLogName() + " by madness?", source, game)) {
|
||||||
ManaCosts<ManaCost> costRef = card.getSpellAbility().getManaCostsToPay();
|
|
||||||
// replace with the new cost
|
// replace with the new cost
|
||||||
|
SpellAbility castByMadness = card.getSpellAbility().copy();
|
||||||
|
ManaCosts<ManaCost> costRef = castByMadness.getManaCostsToPay();
|
||||||
|
castByMadness.setSpellAbilityType(SpellAbilityType.BASE_ALTERNATE);
|
||||||
|
castByMadness.setSpellAbilityCastMode(SpellAbilityCastMode.MADNESS);
|
||||||
costRef.clear();
|
costRef.clear();
|
||||||
costRef.add(madnessCost);
|
costRef.add(madnessCost);
|
||||||
boolean result = owner.cast(card.getSpellAbility(), game, false);
|
boolean result = owner.cast(castByMadness, game, false);
|
||||||
// Reset the casting costs (in case the player cancels cast and plays the card later)
|
|
||||||
// TODO: Check if this is neccessary
|
|
||||||
costRef.clear();
|
|
||||||
for (ManaCost manaCost : card.getSpellAbility().getManaCosts()) {
|
|
||||||
costRef.add(manaCost);
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -254,14 +238,10 @@ enum MadnessCondition implements Condition {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Card card = game.getCard(source.getSourceId());
|
MageObject madnessSpell = game.getLastKnownInformation(source.getSourceId(), Zone.STACK, source.getSourceObjectZoneChangeCounter() - 1);
|
||||||
if (card != null) {
|
if (madnessSpell instanceof Spell) {
|
||||||
for (Ability ability : card.getAbilities()) {
|
if (((Spell) madnessSpell).getSpellAbility() != null) {
|
||||||
if (ability instanceof MadnessTriggeredAbility) {
|
return ((Spell) madnessSpell).getSpellAbility().getSpellAbilityCastMode() == SpellAbilityCastMode.MADNESS;
|
||||||
if (ability.isActivated()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -32,7 +32,6 @@ import mage.abilities.Ability;
|
||||||
import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
|
import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
|
||||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.constants.CardType;
|
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
import mage.constants.SetTargetPointer;
|
import mage.constants.SetTargetPointer;
|
||||||
import mage.constants.TargetController;
|
import mage.constants.TargetController;
|
||||||
|
@ -47,6 +46,7 @@ import mage.game.Game;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
import mage.target.common.TargetControlledPermanent;
|
import mage.target.common.TargetControlledPermanent;
|
||||||
|
import mage.util.GameLog;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 702.94. Soulbond
|
* 702.94. Soulbond
|
||||||
|
@ -168,7 +168,9 @@ class SoulboundEntersSelfEffect extends OneShotEffect {
|
||||||
Permanent chosen = game.getPermanent(target.getFirstTarget());
|
Permanent chosen = game.getPermanent(target.getFirstTarget());
|
||||||
if (chosen != null) {
|
if (chosen != null) {
|
||||||
chosen.setPairedCard(new MageObjectReference(permanent, game));
|
chosen.setPairedCard(new MageObjectReference(permanent, game));
|
||||||
|
chosen.addInfo("soulbond", "Soulbond to " + GameLog.getColoredObjectIdNameForTooltip(permanent), game);
|
||||||
permanent.setPairedCard(new MageObjectReference(chosen, game));
|
permanent.setPairedCard(new MageObjectReference(chosen, game));
|
||||||
|
permanent.addInfo("soulbond", "Soulbond to " + GameLog.getColoredObjectIdNameForTooltip(chosen), game);
|
||||||
if (!game.isSimulation()) {
|
if (!game.isSimulation()) {
|
||||||
game.informPlayers(controller.getLogName() + " soulbonds " + permanent.getLogName() + " with " + chosen.getLogName());
|
game.informPlayers(controller.getLogName() + " soulbonds " + permanent.getLogName() + " with " + chosen.getLogName());
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ public enum CardRepository {
|
||||||
// raise this if db structure was changed
|
// raise this if db structure was changed
|
||||||
private static final long CARD_DB_VERSION = 51;
|
private static final long CARD_DB_VERSION = 51;
|
||||||
// raise this if new cards were added to the server
|
// raise this if new cards were added to the server
|
||||||
private static final long CARD_CONTENT_VERSION = 103;
|
private static final long CARD_CONTENT_VERSION = 104;
|
||||||
private Dao<CardInfo, Object> cardDao;
|
private Dao<CardInfo, Object> cardDao;
|
||||||
private Set<String> classNames;
|
private Set<String> classNames;
|
||||||
|
|
||||||
|
|
48
Mage/src/main/java/mage/constants/SpellAbilityCastMode.java
Normal file
48
Mage/src/main/java/mage/constants/SpellAbilityCastMode.java
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification, are
|
||||||
|
* permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* The views and conclusions contained in the software and documentation are those of the
|
||||||
|
* authors and should not be interpreted as representing official policies, either expressed
|
||||||
|
* or implied, of BetaSteward_at_googlemail.com.
|
||||||
|
*/
|
||||||
|
package mage.constants;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author LevelX2
|
||||||
|
*/
|
||||||
|
public enum SpellAbilityCastMode {
|
||||||
|
NORMAL("Normal"),
|
||||||
|
MADNESS("Madness");
|
||||||
|
|
||||||
|
private final String text;
|
||||||
|
|
||||||
|
SpellAbilityCastMode(String text) {
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
|
@ -30,9 +30,7 @@ package mage.game.draft;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.repository.CardCriteria;
|
|
||||||
import mage.cards.repository.CardInfo;
|
import mage.cards.repository.CardInfo;
|
||||||
import mage.cards.repository.CardRepository;
|
import mage.cards.repository.CardRepository;
|
||||||
import mage.util.RandomUtil;
|
import mage.util.RandomUtil;
|
||||||
|
|
|
@ -1333,6 +1333,10 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
@Override
|
@Override
|
||||||
public void setPairedCard(MageObjectReference pairedCard) {
|
public void setPairedCard(MageObjectReference pairedCard) {
|
||||||
this.pairedPermanent = pairedCard;
|
this.pairedPermanent = pairedCard;
|
||||||
|
if (pairedCard == null) {
|
||||||
|
// remove existing soulbond info text
|
||||||
|
this.addInfo("soulbond", null, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in a new issue