1
0
Fork 0
mirror of https://github.com/correl/mage.git synced 2025-04-08 09:11:04 -09:00
This commit is contained in:
klayhamn 2015-07-28 21:17:00 +03:00
commit 0ddc11f4dc
85 changed files with 3845 additions and 759 deletions
Mage.Client/src/main/java/mage/client/game
Mage.Common/src/mage/view
Mage.Server.Plugins
Mage.Deck.Constructed/src/mage/deck
Mage.Player.Human/src/mage/player/human
Mage.Server
config
release/config
Mage.Sets/src/mage/sets
Mage.Tests/src/test/java/org/mage/test
Mage/src/mage
readme.md

View file

@ -333,7 +333,7 @@ public class PlayAreaPanel extends javax.swing.JPanel {
}
};
JMenu rollbackMainItem = new JMenu("Roll back");
JMenu rollbackMainItem = new JMenu("Rollback");
rollbackMainItem.setMnemonic(KeyEvent.VK_R);
rollbackMainItem.setToolTipText("The game will be rolled back to the start of the requested turn if all players agree.");
popupMenu.add(rollbackMainItem);

View file

@ -1,30 +1,30 @@
/*
* 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.
*/
* 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.client.game;
/**
@ -39,20 +39,21 @@ public class PlayAreaPanelOptions {
this.playerItself = playerItself;
this.rollbackTurnsAllowed = rollbackTurnsAllowed;
}
/**
* true if the client is a player / false if the client is a watcher
* true if the client is a player / false if the client is a watcher
*/
public boolean isPlayer = false;
/**
* true if the player is the client player itself, false if the player is another player playing with the clinet player
* true if the player is the client player itself, false if the player is
* another player playing with the clinet player
*/
public boolean playerItself = false;
/**
* true if the player can roll back turns if all players agree
* true if the player can rollback turns if all players agree
*/
public boolean rollbackTurnsAllowed = false;
}

View file

@ -49,6 +49,7 @@ import mage.game.GameState;
import mage.game.command.Emblem;
import mage.game.permanent.Permanent;
import mage.target.targetpointer.TargetPointer;
import mage.util.GameLog;
/**
*
@ -145,11 +146,11 @@ public class CardsView extends LinkedHashMap<UUID, CardView> {
for (UUID uuid : abilityTargets) {
MageObject mageObject = game.getObject(uuid);
if (mageObject != null) {
names.add(mageObject.getName());
names.add(GameLog.getColoredObjectIdNameForTooltip(mageObject));
}
}
if (!names.isEmpty()) {
abilityView.getRules().add("<i>Related to: " + names.toString() + "</i>");
abilityView.getRules().add("<i>Related objects: " + names.toString() + "</i>");
}
}
}

View file

@ -41,6 +41,7 @@ import mage.game.Game;
import mage.game.stack.StackAbility;
import mage.target.targetpointer.FixedTarget;
import mage.target.targetpointer.TargetPointer;
import mage.util.GameLog;
/**
*
@ -118,7 +119,7 @@ public class StackAbilityView extends CardView {
if ((mageObject instanceof Card) && ((Card) mageObject).isFaceDown(game)) {
continue;
}
names.add(mageObject.getName());
names.add(GameLog.getColoredObjectIdNameForTooltip(mageObject));
}
}

View file

@ -0,0 +1,235 @@
package mage.deck;
import mage.cards.ExpansionSet;
import mage.cards.Sets;
import mage.cards.decks.Constructed;
import mage.cards.decks.Deck;
import mage.constants.SetType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;
/**
* This class represents a deck from any past standard.
*
* This class was originally made to work with the historical standard ruleset.
* Data taken from http://thattournament.website/historic-tournament.php
* (site changed, originally http://mtgt.nfshost.com/historic-tournament.php)
*
* If there are any questions or corrections, feel free to contact me.
*
* @author Marthinwurer (at gmail.com)
*/
public class HistoricalStandard extends Constructed {
/*
* This array stores the set codes of each standard up to
* Kamigawa/Ravnica standard, where rotation stabilized.
*/
protected static final String[][] standards = {
// 1st standard: The Dark, Fallen Empires, and 4th.
{ "DRK", "FEM", "4ED" },
// 2nd standard: 4th, Fallen Empires, Ice Age, Chronicles, Homelands,
// Alliances, and Mirage.
{"FEM", "4ED", "ICE", "HML", "ALL", "MIR"},
// 3rd standard: 4th, Chronicles, Alliances, Mirage, Visions.
{"4ED", "ALL", "MIR", "VIS"},
// 4th Standard: Ice Age, Homelands, Alliances, Mirage, Visions, 5th,
// and Weatherlight.
{"ICE", "HML", "ALL", "MIR", "VIS", "5ED", "WTH"},
// 5th Standard: Mirage, Visions, 5th, Weatherlight, Tempest,
// Stronghold, and Exodus.
{"MIR", "VIS", "5ED", "WTH", "TMP", "STH", "EXO"},
// 6th Standard: 5th, Tempest, Stronghold, Exodus, Urza's Saga, Urza's
// Legacy, Urza's Destiny.
{"5ED", "TMP", "STH", "EXO", "USG", "ULG"},
// 7th Standard: Tempest, Stronghold, Exodus, Urza's Saga, Urza's
// Legacy, 6th, Urza's Destiny.
{"TMP", "STH", "EXO", "USG", "ULG", "6ED", "UDS"},
// 8th Standard: Urza's Saga, Urza's Legacy, 6th, Urza's Destiny,
// Mercadian Masques, Nemesis, Prophecy.
{"USG", "ULG", "6ED", "UDS", "MMQ", "NMS", "PCY"},
// 9th Standard
{"6ED", "MMQ", "NMS", "PCY", "INV", "PLS"},
// 10th Standard
{"7ED", "MMQ", "NMS", "PCY", "INV", "PLS", "APC"},
// 11th Standard
{"7ED", "INV", "APC", "PLS", "ODY", "TOR", "JUD"},
// 12th Standard
{"7ED", "ODY", "TOR", "JUD", "ONS", "LGN", "LGN"},
// 13th Standard
{"8ED", "ODY", "TOR", "JUD", "ONS", "LGN", "LGN"},
// 14th Standard
{"8ED", "ONS", "LGN", "LGN", "MRD", "DST", "5DN"},
// 15th Standard
{"8ED", "MRD", "DST", "5DN", "CHK", "BOK", "SOK"},
// 16th Standard
{"9ED", "MRD", "DST", "5DN", "CHK", "BOK", "SOK"},
// 17th Standard
{"9ED", "CHK", "BOK", "SOK", "RAV", "GPT", "DIS", "CSP"},
// 18th Standard
{"9ED", "RAV", "GPT", "DIS", "CSP", "TSP", "TSB", "PLC", "FUT"},
// 19th Standard
{"10E", "RAV", "GPT", "DIS", "CSP", "TSP", "PLC", "FUT"},
// 20th Standard
{"10E", "CSP", "TSP", "PLC", "FUT", "LRW", "MOR", "SHM", "EVE"},
// 21st Standard
{"10E", "LRW", "MOR", "SHM", "EVE", "ALA", "CON", "ARB"}
};
/**
* Constructor. Don't need to mess with any of the sets yet; that will be
* done in the overridden validate function.
*/
public HistoricalStandard() {
super("Constructed - Historical Standard");
// banned cards
banned.add("Balance");
banned.add("Memory Jar");
banned.add("Mind Over Matter");
banned.add("Mind Twist");
banned.add("Skullclamp");
banned.add("Tolarian Academy");
banned.add("Yawgmoth's Bargain");
}
/**
* Overridden validate function. Changes the standard sets, then uses the
* regular validation function to test validity.
* @param deck - the deck to validate.
* @return
*/
@Override
public boolean validate(Deck deck) {
Map<String, String> leastInvalid = null;
boolean valid = false;
// first, check whether misty and batterskull are in the same deck.
Map<String, Integer> counts = new HashMap<>();
countCards(counts, deck.getCards());
countCards(counts, deck.getSideboard());
if( counts.containsKey("Stoneforge Mystic")
&& counts.containsKey("Batterskull")){
// if both, then skip all following tests by returning
return false;
}
// up to Lorwyn/Alara, standards will have to be hard-coded.
// iterate through the array of standards.
for (String[] sets : standards) {
// clear the invalid list
invalid.clear();
// add the sets to the setCodes.
setCodes = new ArrayList<>(Arrays.asList(sets));
// validate it. If it validates, clear the invalid cards and break.
if (super.validate(deck)) {
valid = true;
break;
}
// if the map holding the invalid cards is empty, set it to a
// copy of the current invalid list.
if (leastInvalid == null) {
leastInvalid = new HashMap<>(this.getInvalid());
continue;
}
// see how many invalid cards there are. if there are less invalid
// cards than the stored invalid list, assign the current invalid
// to leastInvalid.
if (leastInvalid.size() > this.getInvalid().size()) {
leastInvalid = new HashMap<>(this.getInvalid());
}
}
// After testing the first few standards, do the regular ones.
// set the initial starting and ending date, as well as the current.
GregorianCalendar start = new GregorianCalendar(2006,
Calendar.SEPTEMBER, 1);
GregorianCalendar end = new GregorianCalendar(2008,
Calendar.SEPTEMBER, 1);
GregorianCalendar current = new GregorianCalendar();
// use the method for determining regular standard legality, but change
// the date for each standard.
while (end.before(current) && !valid) {
// clear the invalid list and set codes.
setCodes.clear();
invalid.clear();
// increment the start and end dates.
start.set(Calendar.YEAR, start.get(Calendar.YEAR) + 1);
end.set(Calendar.YEAR, start.get(Calendar.YEAR) + 2);
// Get the sets in that time period.
// (code taken from standard.java)
for (ExpansionSet set : Sets.getInstance().values()) {
if (set.getReleaseDate().after(start.getTime())
&& set.getReleaseDate().before(end.getTime())
&& (set.getSetType() == SetType.CORE || set.getSetType() == SetType.EXPANSION)) {
setCodes.add(set.getCode());
}
}
// validate it. If it validates, clear the invalid cards and break.
if (super.validate(deck)) {
invalid.clear();
valid = true;
break;
}
// see how many invalid cards there are. if there are less invalid
// cards than the stored invalid list, assign the current invalid
// to leastInvalid.
if (leastInvalid == null){
leastInvalid = new HashMap<>(this.getInvalid());
}else if (leastInvalid.size() > this.getInvalid().size()) {
leastInvalid = new HashMap<>(this.getInvalid());
}
}
// if no standard environment is valid, set the invalid to the
// invalid that had the least errors.
if( !valid ){
this.invalid = new HashMap<>(leastInvalid);
}
// return the validity.
return valid;
}
}

View file

@ -0,0 +1,216 @@
package mage.deck;
import mage.cards.ExpansionSet;
import mage.cards.Sets;
import mage.cards.decks.Constructed;
import mage.cards.decks.Deck;
import mage.constants.SetType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;
/**
* This class represents a deck conforming to the rules contained in the
subreddit /r/SuperStandard.
*
* This class was originally made to work with the historical standard ruleset.
* Data taken from http://thattournament.website/historic-tournament.php
* (site changed, originally thtp://mtgt.nfshost.com/historic-tournament.php)
*
* If there are any questions or corrections, feel free to contact me.
*
* @author Marthinwurer (at gmail.com)
*/
public class SuperStandard extends Constructed {
/*
* This array stores the set codes of each standard up to
* Kamigawa/Ravnica standard, where rotation stabilized.
* Data taken from http://thattournament.website/historic-tournament.php
*/
protected static final String[][] standards = {
// 11th Standard
{"7ED", "INV", "APC", "PLS", "ODY", "TOR", "JUD"},
// 12th Standard
{"7ED", "ODY", "TOR", "JUD", "ONS", "LGN", "LGN"},
// 13th Standard
{"8ED", "ODY", "TOR", "JUD", "ONS", "LGN", "LGN"},
// 14th Standard
{"8ED", "ONS", "LGN", "LGN", "MRD", "DST", "5DN"},
// 15th Standard
{"8ED", "MRD", "DST", "5DN", "CHK", "BOK", "SOK"},
// 16th Standard
{"9ED", "MRD", "DST", "5DN", "CHK", "BOK", "SOK"},
// 17th Standard
{"9ED", "CHK", "BOK", "SOK", "RAV", "GPT", "DIS", "CSP"},
// 18th Standard
{"9ED", "RAV", "GPT", "DIS", "CSP", "TSP", "TSB", "PLC", "FUT"},
// 19th Standard
{"10E", "RAV", "GPT", "DIS", "CSP", "TSP", "PLC", "FUT"},
// 20th Standard
{"10E", "CSP", "TSP", "PLC", "FUT", "LRW", "MOR", "SHM", "EVE"},
// 21st Standard
{"10E", "LRW", "MOR", "SHM", "EVE", "ALA", "CON", "ARB"}
};
/**
* Constructor. Don't need to mess with any of the sets yet; that will be
* done in the overridden validate function.
*/
public SuperStandard() {
super("Constructed - All Standards");
banned.add("Ancient Den");
banned.add("Disciple of the Vault");
banned.add("Great Furnace");
banned.add("Seat of the Synod");
banned.add("Skullclamp");
banned.add("Tree of Tales");
banned.add("Vault of Whispers");
}
/**
* Overridden validate function. Changes the standard sets, then uses the
* regular validation function to test validity.
* @param deck - the deck to validate.
* @return
*/
@Override
public boolean validate(Deck deck) {
Map<String, String> leastInvalid = null;
boolean valid = false;
// first, check whether misty and batterskull are in the same deck.
Map<String, Integer> counts = new HashMap<>();
countCards(counts, deck.getCards());
countCards(counts, deck.getSideboard());
if( counts.containsKey("Stoneforge Mystic")
&& counts.containsKey("Batterskull")){
// if both, then skip all following tests by returning
return false;
}
// up to Lorwyn/Alara, standards will have to be hard-coded.
// iterate through the array of standards.
for (String[] sets : standards) {
// clear the invalid list
invalid.clear();
// add the sets to the setCodes.
setCodes = new ArrayList<>(Arrays.asList(sets));
// if either of the mirrodin blocks are in the time period, ban
// misty and darksteel citadel
if( setCodes.contains("MRD") || setCodes.contains("SOM")){
banned.add("Darksteel Citadel");
}else{
banned.remove("Darksteel Citadel");
}
// validate it. If it validates, clear the invalid cards and break.
if (super.validate(deck)) {
valid = true;
break;
}
// if the map holding the invalid cards is empty, set it to a
// copy of the current invalid list.
if (leastInvalid == null) {
leastInvalid = new HashMap<>(this.getInvalid());
continue;
}
// see how many invalid cards there are. if there are less invalid
// cards than the stored invalid list, assign the current invalid
// to leastInvalid.
if (leastInvalid.size() > this.getInvalid().size()) {
leastInvalid = new HashMap<>(this.getInvalid());
}
}
// After testing the first few standards, do the regular ones.
// set the initial starting and ending date, as well as the current.
GregorianCalendar start = new GregorianCalendar(2006,
Calendar.SEPTEMBER, 1);
GregorianCalendar end = new GregorianCalendar(2008,
Calendar.SEPTEMBER, 1);
GregorianCalendar current = new GregorianCalendar();
// use the method for determining regular standard legality, but change
// the date for each standard.
while (end.before(current) && !valid) {
// clear the invalid list and set codes.
setCodes.clear();
invalid.clear();
// increment the start and end dates.
start.set(Calendar.YEAR, start.get(Calendar.YEAR) + 1);
end.set(Calendar.YEAR, start.get(Calendar.YEAR) + 2);
// Get the sets in that time period.
// (code taken from standard.java)
for (ExpansionSet set : Sets.getInstance().values()) {
if (set.getReleaseDate().after(start.getTime())
&& set.getReleaseDate().before(end.getTime())
&& (set.getSetType() == SetType.CORE || set.getSetType() == SetType.EXPANSION)) {
setCodes.add(set.getCode());
}
}
// if either of the mirrodin blocks are in the time period, ban
// misty and darksteel citadel
if( setCodes.contains("MRD") || setCodes.contains("SOM")){
banned.add("Darksteel Citadel");
}else{
banned.remove("Darksteel Citadel");
}
// validate it. If it validates, clear the invalid cards and break.
if (super.validate(deck)) {
invalid.clear();
valid = true;
break;
}
// see how many invalid cards there are. if there are less invalid
// cards than the stored invalid list, assign the current invalid
// to leastInvalid.
if (leastInvalid == null){
leastInvalid = new HashMap<>(this.getInvalid());
}else if (leastInvalid.size() > this.getInvalid().size()) {
leastInvalid = new HashMap<>(this.getInvalid());
}
}
// if no standard environment is valid, set the invalid to the
// invalid that had the least errors.
if( !valid ){
this.invalid = new HashMap<>(leastInvalid);
}
// return the validity.
return valid;
}
}

View file

@ -251,7 +251,7 @@ public class HumanPlayer extends PlayerImpl {
@Override
public boolean choose(Outcome outcome, Choice choice, Game game) {
if (outcome.equals(Outcome.PutManaInPool)) {
if (Outcome.PutManaInPool.equals(outcome)) {
if (currentlyUnpaidMana != null
&& ManaUtil.tryToAutoSelectAManaColor(choice, currentlyUnpaidMana)) {
return true;

View file

@ -87,7 +87,9 @@
<deckType name="Constructed - Pauper" jar="mage-deck-constructed.jar" className="mage.deck.Pauper"/>
<deckType name="Variant Magic - Commander" jar="mage-deck-constructed.jar" className="mage.deck.Commander"/>
<deckType name="Variant Magic - Duel Commander" jar="mage-deck-constructed.jar" className="mage.deck.DuelCommander"/>
<deckType name="Variant Magic - Historical Standard" jar="mage-deck-constructed.jar" className="mage.deck.HistoricalStandard"/>
<deckType name="Variant Magic - Tiny Leaders" jar="mage-deck-constructed.jar" className="mage.deck.TinyLeaders"/>
<deckType name="Variant Magic - Super Standard" jar="mage-deck-constructed.jar" className="mage.deck.SuperStandard"/>
<deckType name="Block Constructed - Innistrad" jar="mage-deck-constructed.jar" className="mage.deck.InnistradBlock"/>
<deckType name="Block Constructed - Kamigawa" jar="mage-deck-constructed.jar" className="mage.deck.KamigawaBlock"/>
<deckType name="Block Constructed - Khans of Tarkir" jar="mage-deck-constructed.jar" className="mage.deck.KhansOfTarkirBlock"/>

View file

@ -66,7 +66,9 @@
<deckType name="Constructed - Pauper" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.Pauper"/>
<deckType name="Variant Magic - Commander" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.Commander"/>
<deckType name="Variant Magic - Duel Commander" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.DuelCommander"/>
<deckType name="Variant Magic - Historical Standard" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.HistoricalStandard"/>
<deckType name="Variant Magic - Tiny Leaders" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.TinyLeaders"/>
<deckType name="Variant Magic - Super Standard" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.SuperStandard"/>
<deckType name="Block Constructed - Innistrad" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.InnistradBlock"/>
<deckType name="Block Constructed - Kamigawa" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.KamigawaBlock"/>
<deckType name="Block Constructed - Khans of Tarkir" jar="mage-deck-constructed-${project.version}.jar" className="mage.deck.KhansOfTarkirBlock"/>

View file

@ -84,7 +84,8 @@ public class DragonsMaze extends ExpansionSet {
savedCardsInfos = CardRepository.instance.findCards(criteria);
savedCards.put(rarity, savedCardsInfos);
}
return savedCardsInfos;
// Return a copy of the saved cards information, as not to modify the original.
return new ArrayList<>(savedCardsInfos);
} else {
return super.getCardsByRarity(rarity);
}

View file

@ -81,9 +81,8 @@ public class FateReforged extends ExpansionSet {
savedCardsInfos = CardRepository.instance.findCards(criteria);
savedCards.put(rarity, savedCardsInfos);
}
List<CardInfo> cards = new ArrayList<>();
cards.addAll(savedCardsInfos);
return cards;
// Return a copy of the saved cards information, as not to modify the original.
return new ArrayList<>(savedCardsInfos);
} else {
return super.getCardsByRarity(rarity);
}

View file

@ -0,0 +1,97 @@
/*
* 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.sets.apocalypse;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.DiscardOntoBattlefieldEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.events.GameEvent;
/**
*
* @author LoneFox
*/
public class Dodecapod extends CardImpl {
public Dodecapod(UUID ownerId) {
super(ownerId, 134, "Dodecapod", Rarity.UNCOMMON, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}");
this.expansionSetCode = "APC";
this.subtype.add("Golem");
this.power = new MageInt(3);
this.toughness = new MageInt(3);
// If a spell or ability an opponent controls causes you to discard Dodecapod, put it onto the battlefield with two +1/+1 counters on it instead of putting it into your graveyard.
this.addAbility(new SimpleStaticAbility(Zone.HAND, new DodecapodEffect()));
}
public Dodecapod(final Dodecapod card) {
super(card);
}
@Override
public Dodecapod copy() {
return new Dodecapod(this);
}
}
class DodecapodEffect extends DiscardOntoBattlefieldEffect {
public DodecapodEffect() {
super();
staticText = "If a spell or ability an opponent controls causes you to discard {this}, put it onto the battlefield with two +1/+1 counters on it instead of putting it into your graveyard";
}
public DodecapodEffect(final DodecapodEffect effect) {
super(effect);
}
@Override
public DodecapodEffect copy() {
return new DodecapodEffect(this);
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
if(super.replaceEvent(event, source, game)) {
new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)).apply(game, source);
return true;
}
return false;
}
}

View file

@ -0,0 +1,79 @@
/*
* 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.sets.apocalypse;
import java.util.UUID;
import mage.abilities.condition.common.KickedCostCondition;
import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.dynamicvalue.common.ManacostVariableValue;
import mage.abilities.effects.common.DamageTargetControllerEffect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.keyword.KickerAbility;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.target.common.TargetCreaturePermanent;
/**
*
* @author LoneFox
*/
public class Illuminate extends CardImpl {
public Illuminate(UUID ownerId) {
super(ownerId, 63, "Illuminate", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{X}{R}");
this.expansionSetCode = "APC";
// Kicker {2}{R} and/or {3}{U}
KickerAbility kickerAbility = new KickerAbility("{2}{R}");
kickerAbility.addKickerCost("{3}{U}");
this.addAbility(kickerAbility);
// Illuminate deals X damage to target creature. If Illuminate was kicked with its {2}{R} kicker, it deals X damage to that creature's controller. If Illuminate was kicked with its {3}{U} kicker, you draw X cards.
this.getSpellAbility().addEffect(new DamageTargetEffect(new ManacostVariableValue()));
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
this.getSpellAbility().addEffect(new ConditionalOneShotEffect(
new DamageTargetControllerEffect(new ManacostVariableValue()),
new KickedCostCondition("{2}{R}"),
"If {this} was kicked with its {2}{R} kicker, it deals X damage to that creature's controller."));
this.getSpellAbility().addEffect(new ConditionalOneShotEffect(
new DrawCardSourceControllerEffect(new ManacostVariableValue()),
new KickedCostCondition("{3}{U}"),
"If {this} was kicked with its {3}{U} kicker, you draw X cards."));
}
public Illuminate(final Illuminate card) {
super(card);
}
@Override
public Illuminate copy() {
return new Illuminate(this);
}
}

View file

@ -0,0 +1,82 @@
/*
* 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.sets.apocalypse;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.common.continuous.BecomesColorTargetEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.filter.FilterSpell;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.target.TargetSpell;
/**
*
* @author LoneFox
*/
public class VodalianMystic extends CardImpl {
private static final FilterSpell filter = new FilterSpell("instant or sorcery spell");
static {
filter.add(Predicates.or(
new CardTypePredicate(CardType.INSTANT),
new CardTypePredicate(CardType.SORCERY)));
}
public VodalianMystic(UUID ownerId) {
super(ownerId, 33, "Vodalian Mystic", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{U}");
this.expansionSetCode = "APC";
this.subtype.add("Merfolk");
this.subtype.add("Wizard");
this.power = new MageInt(1);
this.toughness = new MageInt(1);
// {T}: Target instant or sorcery spell becomes the color of your choice.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesColorTargetEffect(Duration.WhileOnStack), new TapSourceCost());
ability.addTarget(new TargetSpell(filter));
this.addAbility(ability);
}
public VodalianMystic(final VodalianMystic card) {
super(card);
}
@Override
public VodalianMystic copy() {
return new VodalianMystic(this);
}
}

View file

@ -28,15 +28,12 @@
package mage.sets.betrayersofkamigawa;
import java.util.UUID;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DamageTargetControllerEffect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.cards.CardImpl;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.target.common.TargetCreaturePermanent;
/**
@ -50,9 +47,11 @@ public class FirstVolley extends CardImpl {
this.expansionSetCode = "BOK";
this.subtype.add("Arcane");
// First Volley deals 1 damage to target creature and 1 damage to that creature's controller.
this.getSpellAbility().addEffect(new FirstVolleyEffect());
this.getSpellAbility().addEffect(new DamageTargetEffect(1));
Effect effect = new DamageTargetControllerEffect(1);
effect.setText("and 1 damage to that creature's controller");
this.getSpellAbility().addEffect(effect);
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
}
@ -66,34 +65,3 @@ public class FirstVolley extends CardImpl {
return new FirstVolley(this);
}
}
class FirstVolleyEffect extends OneShotEffect {
public FirstVolleyEffect() {
super(Outcome.Damage);
this.staticText = "{this} deals 1 damage to target creature and 1 damage to that creature's controller";
}
public FirstVolleyEffect(final FirstVolleyEffect effect) {
super(effect);
}
@Override
public FirstVolleyEffect copy() {
return new FirstVolleyEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source));
if (permanent != null) {
Player controller = game.getPlayer(permanent.getControllerId());
if (controller != null) {
permanent.damage(1, source.getSourceId(), game, false, true);
controller.damage(1, source.getSourceId(), game, false, true);
return true;
}
}
return false;
}
}

View file

@ -0,0 +1,119 @@
/*
* 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.sets.commander;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.VigilanceAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.filter.common.FilterCreatureCard;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetOpponent;
/**
*
* @author LevelX2
*/
public class TarielReckonerOfSouls extends CardImpl {
public TarielReckonerOfSouls(UUID ownerId) {
super(ownerId, 229, "Tariel, Reckoner of Souls", Rarity.MYTHIC, new CardType[]{CardType.CREATURE}, "{4}{W}{B}{R}");
this.expansionSetCode = "CMD";
this.supertype.add("Legendary");
this.subtype.add("Angel");
this.power = new MageInt(4);
this.toughness = new MageInt(7);
// Flying
this.addAbility(FlyingAbility.getInstance());
// Vigilance
this.addAbility(VigilanceAbility.getInstance());
// {T}: Choose a creature card at random from target opponent's graveyard. Put that card onto the battlefield under your control.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new TarielReckonerOfSoulsEffect(), new TapSourceCost());
ability.addTarget(new TargetOpponent());
this.addAbility(ability);
}
public TarielReckonerOfSouls(final TarielReckonerOfSouls card) {
super(card);
}
@Override
public TarielReckonerOfSouls copy() {
return new TarielReckonerOfSouls(this);
}
}
class TarielReckonerOfSoulsEffect extends OneShotEffect {
public TarielReckonerOfSoulsEffect() {
super(Outcome.PutCardInPlay);
this.staticText = "Choose a creature card at random from target opponent's graveyard. Put that card onto the battlefield under your control";
}
public TarielReckonerOfSoulsEffect(final TarielReckonerOfSoulsEffect effect) {
super(effect);
}
@Override
public TarielReckonerOfSoulsEffect copy() {
return new TarielReckonerOfSoulsEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Player targetOpponent = game.getPlayer(getTargetPointer().getFirst(game, source));
if (controller != null && targetOpponent != null) {
Cards creatureCards = new CardsImpl();
for (Card card : targetOpponent.getGraveyard().getCards(new FilterCreatureCard(), game)) {
creatureCards.add(card);
}
if (!creatureCards.isEmpty()) {
Card card = creatureCards.getRandom(game);
controller.putOntoBattlefieldWithInfo(card, game, Zone.GRAVEYARD, source.getSourceId());
}
return true;
}
return false;
}
}

View file

@ -0,0 +1,52 @@
/*
* 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.sets.conspiracy;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public class SelvalaExplorerReturned extends mage.sets.vintagemasters.SelvalaExplorerReturned {
public SelvalaExplorerReturned(UUID ownerId) {
super(ownerId);
this.cardNumber = 51;
this.expansionSetCode = "CNS";
}
public SelvalaExplorerReturned(final SelvalaExplorerReturned card) {
super(card);
}
@Override
public SelvalaExplorerReturned copy() {
return new SelvalaExplorerReturned(this);
}
}

View file

@ -0,0 +1,69 @@
/*
* 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.sets.darksteel;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.common.turn.SkipNextTurnSourceEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.TrampleAbility;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Rarity;
/**
*
* @author LevelX2
*/
public class EaterOfDays extends CardImpl {
public EaterOfDays(UUID ownerId) {
super(ownerId, 120, "Eater of Days", Rarity.RARE, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}");
this.expansionSetCode = "DST";
this.subtype.add("Leviathan");
this.power = new MageInt(9);
this.toughness = new MageInt(8);
// Flying
this.addAbility(FlyingAbility.getInstance());
// Trample
this.addAbility(TrampleAbility.getInstance());
// When Eater of Days enters the battlefield, you skip your next two turns.
this.addAbility(new EntersBattlefieldTriggeredAbility(new SkipNextTurnSourceEffect(2)));
}
public EaterOfDays(final EaterOfDays card) {
super(card);
}
@Override
public EaterOfDays copy() {
return new EaterOfDays(this);
}
}

View file

@ -0,0 +1,73 @@
/*
* 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.sets.dissension;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.PreventNextDamageFromChosenSourceToYouEffect;
import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Rarity;
import mage.constants.TargetController;
import mage.constants.Zone;
/**
*
* @author anonymous
*/
public class HaazdaShieldMate extends CardImpl {
public HaazdaShieldMate(UUID ownerId) {
super(ownerId, 12, "Haazda Shield Mate", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{2}{W}");
this.expansionSetCode = "DIS";
this.subtype.add("Human");
this.subtype.add("Soldier");
this.power = new MageInt(1);
this.toughness = new MageInt(1);
// At the beginning of your upkeep, sacrifice Haazda Shield Mate unless you pay {W}{W}.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new ManaCostsImpl("{W}{W}")), TargetController.YOU, false));
// {W}: The next time a source of your choice would deal damage to you this turn, prevent that damage.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreventNextDamageFromChosenSourceToYouEffect(Duration.EndOfTurn), new ManaCostsImpl("{W}")));
}
public HaazdaShieldMate(final HaazdaShieldMate card) {
super(card);
}
@Override
public HaazdaShieldMate copy() {
return new HaazdaShieldMate(this);
}
}

View file

@ -0,0 +1,104 @@
/*
* 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.sets.eighthedition;
import java.util.UUID;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.discard.DiscardTargetEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.target.targetpointer.FixedTarget;
/**
*
* @author LoneFox
*/
public class WarpedDevotion extends CardImpl {
public WarpedDevotion(UUID ownerId) {
super(ownerId, 172, "Warped Devotion", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}");
this.expansionSetCode = "8ED";
// Whenever a permanent is returned to a player's hand, that player discards a card.
this.addAbility(new WarpedDevotionTriggeredAbility());
}
public WarpedDevotion(final WarpedDevotion card) {
super(card);
}
@Override
public WarpedDevotion copy() {
return new WarpedDevotion(this);
}
}
class WarpedDevotionTriggeredAbility extends TriggeredAbilityImpl {
public WarpedDevotionTriggeredAbility() {
super(Zone.BATTLEFIELD, new DiscardTargetEffect(1), false);
}
public WarpedDevotionTriggeredAbility(final WarpedDevotionTriggeredAbility ability) {
super(ability);
}
public WarpedDevotionTriggeredAbility copy() {
return new WarpedDevotionTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
ZoneChangeEvent zce = (ZoneChangeEvent)event;
if(zce.getFromZone() == Zone.BATTLEFIELD && zce.getToZone() == Zone.HAND) {
for(Effect effect: getEffects()) {
effect.setTargetPointer(new FixedTarget(zce.getTarget().getOwnerId()));
}
return true;
}
return false;
}
@Override
public String getRule() {
return "Whenever a permanent is returned to a player's hand, that player discards a card.";
}
}

View file

@ -37,7 +37,7 @@ import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.filter.common.FilterControlledPermanent;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterCreatureCard;
import mage.target.common.TargetCardInYourGraveyard;
import mage.target.common.TargetControlledPermanent;
@ -47,15 +47,14 @@ import mage.target.common.TargetControlledPermanent;
* @author jeffwadsworth
*/
public class RecurringNightmare extends CardImpl {
private static final FilterCreatureCard filter = new FilterCreatureCard("creature card in your graveyard");
private static final FilterControlledPermanent filter2 = new FilterControlledPermanent("creature");
private static final FilterControlledCreaturePermanent filter2 = new FilterControlledCreaturePermanent("creature");
public RecurringNightmare(UUID ownerId) {
super(ownerId, 72, "Recurring Nightmare", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}");
this.expansionSetCode = "EXO";
// Sacrifice a creature, Return Recurring Nightmare to its owner's hand: Return target creature card from your graveyard to the battlefield. Activate this ability only any time you could cast a sorcery.
Ability ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new ReturnFromGraveyardToBattlefieldTargetEffect(), new SacrificeTargetCost(new TargetControlledPermanent(filter2)));
ability.addTarget(new TargetCardInYourGraveyard(filter));

View file

@ -0,0 +1,52 @@
/*
* 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.sets.fifthedition;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public class IslandSanctuary extends mage.sets.limitedalpha.IslandSanctuary {
public IslandSanctuary(UUID ownerId) {
super(ownerId);
this.cardNumber = 315;
this.expansionSetCode = "5ED";
}
public IslandSanctuary(final IslandSanctuary card) {
super(card);
}
@Override
public IslandSanctuary copy() {
return new IslandSanctuary(this);
}
}

View file

@ -0,0 +1,52 @@
/*
* 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.sets.fourthedition;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public class IslandSanctuary extends mage.sets.limitedalpha.IslandSanctuary {
public IslandSanctuary(UUID ownerId) {
super(ownerId);
this.cardNumber = 281;
this.expansionSetCode = "4ED";
}
public IslandSanctuary(final IslandSanctuary card) {
super(card);
}
@Override
public IslandSanctuary copy() {
return new IslandSanctuary(this);
}
}

View file

@ -31,17 +31,16 @@ import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.effects.common.continuous.PlayWithHandRevealedEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Layer;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.SubLayer;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
@ -59,8 +58,8 @@ public class ZursWeirding extends CardImpl {
this.expansionSetCode = "ICE";
// Players play with their hands revealed.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayerRevealHandCardsEffect()));
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayWithHandRevealedEffect(TargetController.ANY)));
// If a player would draw a card, he or she reveals it instead. Then any other player may pay 2 life. If a player does, put that card into its owner's graveyard. Otherwise, that player draws a card.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ZursWeirdingReplacementEffect()));
}
@ -81,7 +80,7 @@ class ZursWeirdingReplacementEffect extends ReplacementEffectImpl {
super(Duration.WhileOnBattlefield, Outcome.Neutral);
this.staticText = "If a player would draw a card, he or she reveals it instead. Then any other player may pay 2 life. If a player does, put that card into its owner's graveyard. Otherwise, that player draws a card.";
}
public ZursWeirdingReplacementEffect(final ZursWeirdingReplacementEffect effect) {
super(effect);
}
@ -90,7 +89,7 @@ class ZursWeirdingReplacementEffect extends ReplacementEffectImpl {
public ZursWeirdingReplacementEffect copy() {
return new ZursWeirdingReplacementEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
@ -105,7 +104,7 @@ class ZursWeirdingReplacementEffect extends ReplacementEffectImpl {
if (card != null) {
// reveals it instead
player.revealCards(sourceObject.getIdName() + " next draw of " + player.getName() + " (" + game.getTurnNum()+"|"+game.getPhase().getType() +")", new CardsImpl(card), game);
// Then any other player may pay 2 life. If a player does, put that card into its owner's graveyard
PlayerList playerList = game.getPlayerList().copy();
playerList.setCurrent(player.getId());
@ -116,14 +115,14 @@ class ZursWeirdingReplacementEffect extends ReplacementEffectImpl {
currentPlayer.getLife() >= 2 &&
currentPlayer.chooseUse(Outcome.Benefit, message, source, game)) {
currentPlayer.loseLife(2, game);
player.moveCards(card, Zone.LIBRARY, Zone.GRAVEYARD, source, game);
player.moveCards(card, Zone.LIBRARY, Zone.GRAVEYARD, source, game);
// game.getState().getRevealed().reset();
return true;
}
currentPlayer = playerList.getNext(game);
}
// game.getState().getRevealed().reset();
}
}
@ -132,43 +131,11 @@ class ZursWeirdingReplacementEffect extends ReplacementEffectImpl {
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DRAW_CARD;
}
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
return true;
}
}
class PlayerRevealHandCardsEffect extends ContinuousEffectImpl {
public PlayerRevealHandCardsEffect() {
super(Duration.WhileOnBattlefield, Layer.PlayerEffects, SubLayer.NA, Outcome.Detriment);
staticText = "Players play with their hands revealed";
}
public PlayerRevealHandCardsEffect(final PlayerRevealHandCardsEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
for (UUID playerID : controller.getInRange()) {
Player player = game.getPlayer(playerID);
if (player != null) {
player.revealCards(player.getName() + "'s hand cards", player.getHand(), game, false);
}
}
return true;
}
return false;
}
@Override
public PlayerRevealHandCardsEffect copy() {
return new PlayerRevealHandCardsEffect(this);
}
}

View file

@ -0,0 +1,71 @@
/*
* 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.sets.invasion;
import java.util.UUID;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.DontUntapInControllersUntapStepAllEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Rarity;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.filter.Filter;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.PowerPredicate;
/**
*
* @author LoneFox
*/
public class JuntuStakes extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures with power 1 or less");
static {
filter.add(new PowerPredicate(Filter.ComparisonType.LessThan, 2));
}
public JuntuStakes(UUID ownerId) {
super(ownerId, 304, "Juntu Stakes", Rarity.RARE, new CardType[]{CardType.ARTIFACT}, "{2}");
this.expansionSetCode = "INV";
// Creatures with power 1 or less don't untap during their controllers' untap steps.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DontUntapInControllersUntapStepAllEffect(Duration.WhileOnBattlefield, TargetController.ANY, filter)));
}
public JuntuStakes(final JuntuStakes card) {
super(card);
}
@Override
public JuntuStakes copy() {
return new JuntuStakes(this);
}
}

View file

@ -0,0 +1,70 @@
/*
* 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.sets.invasion;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.ActivateAsSorceryActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.effects.common.continuous.PlayWithHandRevealedEffect;
import mage.abilities.effects.common.discard.DiscardCardYouChooseTargetEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.target.TargetPlayer;
/**
*
* @author LoneFox
*/
public class SeersVision extends CardImpl {
public SeersVision(UUID ownerId) {
super(ownerId, 270, "Seer's Vision", Rarity.UNCOMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{B}");
this.expansionSetCode = "INV";
// Your opponents play with their hands revealed.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayWithHandRevealedEffect(TargetController.OPPONENT)));
// Sacrifice Seer's Vision: Look at target player's hand and choose a card from it. That player discards that card. Activate this ability only any time you could cast a sorcery.
Ability ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new DiscardCardYouChooseTargetEffect(), new SacrificeSourceCost());
ability.addTarget(new TargetPlayer());
this.addAbility(ability);
}
public SeersVision(final SeersVision card) {
super(card);
}
@Override
public SeersVision copy() {
return new SeersVision(this);
}
}

View file

@ -0,0 +1,79 @@
/*
* 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.sets.invasion;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.CantBlockAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.PreventCombatDamageBySourceEffect;
import mage.abilities.effects.common.PreventCombatDamageToSourceEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Rarity;
import mage.constants.Zone;
/**
*
* @author LoneFox
*/
public class UrborgPhantom extends CardImpl {
public UrborgPhantom(UUID ownerId) {
super(ownerId, 132, "Urborg Phantom", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{B}");
this.expansionSetCode = "INV";
this.subtype.add("Spirit");
this.subtype.add("Minion");
this.power = new MageInt(3);
this.toughness = new MageInt(1);
// Urborg Phantom can't block.
this.addAbility(new CantBlockAbility());
// {U}: Prevent all combat damage that would be dealt to and dealt by Urborg Phantom this turn.
Effect effect = new PreventCombatDamageToSourceEffect(Duration.EndOfTurn);
effect.setText("Prevent all combat damage that would be dealt to");
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{U}"));
effect = new PreventCombatDamageBySourceEffect(Duration.EndOfTurn);
effect.setText("and dealt by {this} this turn");
ability.addEffect(effect);
this.addAbility(ability);
}
public UrborgPhantom(final UrborgPhantom card) {
super(card);
}
@Override
public UrborgPhantom copy() {
return new UrborgPhantom(this);
}
}

View file

@ -0,0 +1,62 @@
/*
* 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.sets.legends;
import java.util.UUID;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.continuous.PlayWithHandRevealedEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.constants.TargetController;
import mage.constants.Zone;
/**
*
* @author LoneFox
*/
public class Revelation extends CardImpl {
public Revelation(UUID ownerId) {
super(ownerId, 116, "Revelation", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{G}");
this.expansionSetCode = "LEG";
this.supertype.add("World");
// Players play with their hands revealed.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayWithHandRevealedEffect(TargetController.ANY)));
}
public Revelation(final Revelation card) {
super(card);
}
@Override
public Revelation copy() {
return new Revelation(this);
}
}

View file

@ -0,0 +1,123 @@
/*
* 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.sets.limitedalpha;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.effects.common.combat.CantAttackYouAllEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.IslandwalkAbility;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.PhaseStep;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.AbilityPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.players.Player;
/**
*
* @author LevelX2
*/
public class IslandSanctuary extends CardImpl {
public IslandSanctuary(UUID ownerId) {
super(ownerId, 209, "Island Sanctuary", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}");
this.expansionSetCode = "LEA";
// If you would draw a card during your draw step, instead you may skip that draw. If you do, until your next turn, you can't be attacked except by creatures with flying and/or islandwalk.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new IslandSanctuaryEffect()));
}
public IslandSanctuary(final IslandSanctuary card) {
super(card);
}
@Override
public IslandSanctuary copy() {
return new IslandSanctuary(this);
}
}
class IslandSanctuaryEffect extends ReplacementEffectImpl {
private final static FilterCreaturePermanent notFlyingorIslandwalkCreatures = new FilterCreaturePermanent("except by creatures with flying and/or islandwalk");
static {
notFlyingorIslandwalkCreatures.add(Predicates.not(new AbilityPredicate(FlyingAbility.class)));
notFlyingorIslandwalkCreatures.add(Predicates.not(new AbilityPredicate(IslandwalkAbility.class)));
}
IslandSanctuaryEffect() {
super(Duration.WhileOnBattlefield, Outcome.Benefit);
staticText = "If you would draw a card during your draw step, instead you may skip that draw. If you do, until your next turn, you can't be attacked except by creatures with flying and/or islandwalk";
}
IslandSanctuaryEffect(final IslandSanctuaryEffect effect) {
super(effect);
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player controller = game.getPlayer(event.getPlayerId());
if (controller != null && controller.chooseUse(outcome, "Skip draw card? (If you do, until your next turn, you can't be attacked except by creatures with flying and/or islandwalk)", source, game)) {
game.informPlayers(controller.getLogName() + " skips his or her draw card action. Until his or her next turn, he or she can't be attacked except by creatures with flying and/or islandwalk");
game.addEffect(new CantAttackYouAllEffect(Duration.UntilYourNextTurn, notFlyingorIslandwalkCreatures), source);
return true;
}
return false;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DRAW_CARD;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
return source.getControllerId().equals(event.getPlayerId()) && game.getTurn().getStepType().equals(PhaseStep.DRAW);
}
@Override
public boolean apply(Game game, Ability source) {
return false;
}
@Override
public IslandSanctuaryEffect copy() {
return new IslandSanctuaryEffect(this);
}
}

View file

@ -0,0 +1,52 @@
/*
* 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.sets.limitedbeta;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public class IslandSanctuary extends mage.sets.limitedalpha.IslandSanctuary {
public IslandSanctuary(UUID ownerId) {
super(ownerId);
this.cardNumber = 211;
this.expansionSetCode = "LEB";
}
public IslandSanctuary(final IslandSanctuary card) {
super(card);
}
@Override
public IslandSanctuary copy() {
return new IslandSanctuary(this);
}
}

View file

@ -1,16 +1,16 @@
/*
* 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
@ -20,7 +20,7 @@
* 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.
@ -29,15 +29,12 @@
package mage.sets.magic2011;
import java.util.UUID;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DamageTargetControllerEffect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.cards.CardImpl;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.target.common.TargetCreaturePermanent;
/**
@ -50,7 +47,11 @@ public class ChandrasOutrage extends CardImpl {
super(ownerId, 128, "Chandra's Outrage", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{2}{R}{R}");
this.expansionSetCode = "M11";
this.getSpellAbility().addEffect(new ChandrasOutrageEffect());
// Chandra's Outrage deals 4 damage to target creature and 2 damage to that creature's controller.
this.getSpellAbility().addEffect(new DamageTargetEffect(4));
Effect effect = new DamageTargetControllerEffect(2);
effect.setText("and 2 damage to that creature's controller");
this.getSpellAbility().addEffect(effect);
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
}
@ -64,35 +65,3 @@ public class ChandrasOutrage extends CardImpl {
}
}
class ChandrasOutrageEffect extends OneShotEffect {
public ChandrasOutrageEffect() {
super(Outcome.Damage);
staticText = "{this} deals 4 damage to target creature and 2 damage to that creature's controller";
}
public ChandrasOutrageEffect(final ChandrasOutrageEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getFirstTarget());
if (permanent != null) {
Player player = game.getPlayer(permanent.getControllerId());
if (player != null) {
permanent.damage(4, source.getSourceId(), game, false, true);
player.damage(2, source.getSourceId(), game, false, true);
return true;
}
}
return false;
}
@Override
public ChandrasOutrageEffect copy() {
return new ChandrasOutrageEffect(this);
}
}

View file

@ -1,16 +1,16 @@
/*
* 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
@ -20,7 +20,7 @@
* 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.
@ -29,25 +29,15 @@
package mage.sets.magic2011;
import java.util.UUID;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.effects.common.DiscardOntoBattlefieldEffect;
import mage.abilities.effects.common.GainLifeEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.events.ZoneChangeEvent;
import mage.game.stack.StackObject;
import mage.players.Player;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.constants.Zone;
/**
*
@ -65,9 +55,9 @@ public class ObstinateBaloth extends CardImpl {
// When Obstinate Baloth enters the battlefield, you gain 4 life.
this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(4), false));
// If a spell or ability an opponent controls causes you to discard Obstinate Baloth, put it onto the battlefield instead of putting it into your graveyard.
this.addAbility(new SimpleStaticAbility(Zone.HAND, new ObstinateBalothEffect()));
this.addAbility(new SimpleStaticAbility(Zone.HAND, new DiscardOntoBattlefieldEffect()));
}
public ObstinateBaloth(final ObstinateBaloth card) {
@ -81,53 +71,3 @@ public class ObstinateBaloth extends CardImpl {
}
class ObstinateBalothEffect extends ReplacementEffectImpl {
public ObstinateBalothEffect() {
super(Duration.EndOfGame, Outcome.PutCardInPlay);
staticText = "If a spell or ability an opponent controls causes you to discard {this}, put it onto the battlefield instead of putting it into your graveyard";
}
public ObstinateBalothEffect(final ObstinateBalothEffect effect) {
super(effect);
}
@Override
public ObstinateBalothEffect copy() {
return new ObstinateBalothEffect(this);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == EventType.ZONE_CHANGE;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getTargetId().equals(source.getSourceId())) {
ZoneChangeEvent zcEvent = (ZoneChangeEvent) event;
if (zcEvent.getFromZone() == Zone.HAND && zcEvent.getToZone() == Zone.GRAVEYARD) {
StackObject spell = game.getStack().getStackObject(event.getSourceId());
if (spell != null && game.getOpponents(source.getControllerId()).contains(spell.getControllerId())) {
return true;
}
}
}
return false;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Card card = game.getCard(source.getSourceId());
if (card != null) {
Player owner = game.getPlayer(card.getOwnerId());
if (owner != null) {
if (owner.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId())) {
return true;
}
}
}
return false;
}
}

View file

@ -44,8 +44,8 @@ import mage.filter.predicate.mageobject.CardTypePredicate;
* @author fireshoes
*/
public class ArtificersEpiphany extends CardImpl {
private static final FilterControlledPermanent filter = new FilterControlledPermanent("artifacts");
private static final FilterControlledPermanent filter = new FilterControlledPermanent("you control no artifacts");
static {
filter.add(new CardTypePredicate(CardType.ARTIFACT));

View file

@ -89,7 +89,7 @@ class OrbsOfWardingEffect extends PreventionEffectImpl {
public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getTargetId().equals(source.getControllerId())) {
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getSourceId());
if (permanent.getCardType().contains(CardType.CREATURE)) {
if (permanent != null && permanent.getCardType().contains(CardType.CREATURE)) {
return super.applies(event, source, game);
}
}

View file

@ -28,16 +28,14 @@
package mage.sets.magicorigins;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.condition.common.SpellMasteryCondition;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.dynamicvalue.common.ManacostVariableValue;
import mage.abilities.effects.common.DamageTargetControllerEffect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCreaturePermanent;
/**
@ -50,10 +48,12 @@ public class RavagingBlaze extends CardImpl {
super(ownerId, 159, "Ravaging Blaze", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{X}{R}{R}");
this.expansionSetCode = "ORI";
// Ravaging Blaze deals X damage to target creature.
// <i>Spell mastery</i> If there are two or more instant and/or sorcery cards in your graveyard, Ravaging Blaze also deals X damage to that creature's controller.
this.getSpellAbility().addEffect(new RavagingBlazeEffect());
// Ravaging Blaze deals X damage to target creature.
this.getSpellAbility().addEffect(new DamageTargetEffect(new ManacostVariableValue()));
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
// <i>Spell mastery</i> If there are two or more instant and/or sorcery cards in your graveyard, Ravaging Blaze also deals X damage to that creature's controller.
this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new DamageTargetControllerEffect(new ManacostVariableValue()),
SpellMasteryCondition.getInstance(), "<br><i>Spell mastery</i> — If there are two or more instant and/or sorcery cards in your graveyard, Ravaging Blaze also deals X damage to that creature's controller."));
}
public RavagingBlaze(final RavagingBlaze card) {
@ -65,41 +65,3 @@ public class RavagingBlaze extends CardImpl {
return new RavagingBlaze(this);
}
}
class RavagingBlazeEffect extends OneShotEffect {
public RavagingBlazeEffect() {
super(Outcome.Damage);
staticText = "{this} deals X damage to target creature.<br>"
+ "<i>Spell mastery</i> &mdash; If there are two or more instant and/or sorcery cards in your graveyard, {this} also deals X damage to that creature's controller.";
}
public RavagingBlazeEffect(final RavagingBlazeEffect effect) {
super(effect);
}
@Override
public RavagingBlazeEffect copy() {
return new RavagingBlazeEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent != null) {
int xValue = source.getManaCostsToPay().getX();
if (xValue > 0) {
permanent.damage(xValue, source.getSourceId(), game, false, true);
if (SpellMasteryCondition.getInstance().apply(game, source)) {
Player targetController = game.getPlayer(permanent.getControllerId());
if (targetController != null) {
targetController.damage(xValue, source.getSourceId(), game, false, true);
}
}
}
return true;
}
return false;
}
}

View file

@ -0,0 +1,52 @@
/*
* 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.sets.masterseditioniv;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public class IslandSanctuary extends mage.sets.limitedalpha.IslandSanctuary {
public IslandSanctuary(UUID ownerId) {
super(ownerId);
this.cardNumber = 15;
this.expansionSetCode = "ME4";
}
public IslandSanctuary(final IslandSanctuary card) {
super(card);
}
@Override
public IslandSanctuary copy() {
return new IslandSanctuary(this);
}
}

View file

@ -0,0 +1,134 @@
/*
* 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.sets.mercadianmasques;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.DiscardCardCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.PreventionEffectData;
import mage.abilities.effects.PreventionEffectImpl;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.players.Player;
import mage.target.TargetSource;
/**
*
* @author anonymous
*/
public class ChoArrimAlchemist extends CardImpl {
public ChoArrimAlchemist(UUID ownerId) {
super(ownerId, 8, "Cho-Arrim Alchemist", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{W}");
this.expansionSetCode = "MMQ";
this.subtype.add("Human");
this.subtype.add("Spellshaper");
this.power = new MageInt(1);
this.toughness = new MageInt(1);
// {1}{W}{W}, {tap}, Discard a card: The next time a source of your choice would deal damage to you this turn, prevent that damage. You gain life equal to the damage prevented this way.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ChoArrimAlchemistEffect(), new ManaCostsImpl("{1}{W}{W}"));
ability.addCost(new TapSourceCost());
ability.addCost(new DiscardCardCost());
this.addAbility(ability);
}
public ChoArrimAlchemist(final ChoArrimAlchemist card) {
super(card);
}
@Override
public ChoArrimAlchemist copy() {
return new ChoArrimAlchemist(this);
}
}
class ChoArrimAlchemistEffect extends PreventionEffectImpl {
private final TargetSource target;
public ChoArrimAlchemistEffect() {
super(Duration.EndOfTurn, Integer.MAX_VALUE, false, false);
this.staticText = "The next time a source of your choice would deal damage to you this turn, prevent that damage. You gain life equal to the damage prevented this way.";
this.target = new TargetSource();
}
public ChoArrimAlchemistEffect(final ChoArrimAlchemistEffect effect) {
super(effect);
this.target = effect.target.copy();
}
@Override
public ChoArrimAlchemistEffect copy() {
return new ChoArrimAlchemistEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public void init(Ability source, Game game) {
this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game);
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
PreventionEffectData preventionData = preventDamageAction(event, source, game);
this.used = true;
this.discard(); // only one use
if (preventionData.getPreventedDamage() > 0) {
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
player.gainLife(preventionData.getPreventedDamage(), game);
}
}
return true;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (!this.used && super.applies(event, source, game)) {
if (event.getTargetId().equals(source.getControllerId()) && event.getSourceId().equals(target.getFirstTarget())) {
return true;
}
}
return false;
}
}

View file

@ -0,0 +1,54 @@
/*
* 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.sets.mercadianmasques;
import java.util.UUID;
import mage.constants.Rarity;
/**
*
* @author anonymous
*/
public class RighteousAura extends mage.sets.visions.RighteousAura {
public RighteousAura(UUID ownerId) {
super(ownerId);
this.cardNumber = 45;
this.expansionSetCode = "MMQ";
this.rarity = Rarity.UNCOMMON;
}
public RighteousAura(final RighteousAura card) {
super(card);
}
@Override
public RighteousAura copy() {
return new RighteousAura(this);
}
}

View file

@ -0,0 +1,68 @@
/*
* 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.sets.nemesis;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.continuous.PlayWithHandRevealedEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.constants.TargetController;
import mage.constants.Zone;
/**
*
* @author LoneFox
*/
public class WanderingEye extends CardImpl {
public WanderingEye(UUID ownerId) {
super(ownerId, 50, "Wandering Eye", Rarity.COMMON, new CardType[]{CardType.CREATURE}, "{2}{U}");
this.expansionSetCode = "NMS";
this.subtype.add("Illusion");
this.power = new MageInt(1);
this.toughness = new MageInt(3);
// Flying
this.addAbility(FlyingAbility.getInstance());
// Players play with their hands revealed.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayWithHandRevealedEffect(TargetController.ANY)));
}
public WanderingEye(final WanderingEye card) {
super(card);
}
@Override
public WanderingEye copy() {
return new WanderingEye(this);
}
}

View file

@ -0,0 +1,71 @@
/*
* 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.sets.planeshift;
import java.util.UUID;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.effects.common.SacrificeEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.constants.TargetController;
import mage.filter.common.FilterLandPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.SupertypePredicate;
/**
*
* @author LoneFox
*/
public class DestructiveFlow extends CardImpl {
private static final FilterLandPermanent filter = new FilterLandPermanent("nonbasic land");
static {
filter.add(Predicates.not(new SupertypePredicate("Basic")));
}
public DestructiveFlow(UUID ownerId) {
super(ownerId, 102, "Destructive Flow", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{B}{R}{G}");
this.expansionSetCode = "PLS";
// At the beginning of each player's upkeep, that player sacrifices a nonbasic land.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SacrificeEffect(filter, 1, "that player"),
TargetController.ANY, false));
}
public DestructiveFlow(final DestructiveFlow card) {
super(card);
}
@Override
public DestructiveFlow copy() {
return new DestructiveFlow(this);
}
}

View file

@ -0,0 +1,76 @@
/*
* 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.sets.planeshift;
import java.util.UUID;
import mage.MageInt;
import mage.ObjectColor;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.PreventAllDamageByAllEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.ColorPredicate;
/**
*
* @author LoneFox
*/
public class RadiantKavu extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("blue creatures and black creatures");
static {
filter.add(Predicates.or(new ColorPredicate(ObjectColor.BLUE), new ColorPredicate(ObjectColor.BLACK)));
}
public RadiantKavu(UUID ownerId) {
super(ownerId, 120, "Radiant Kavu", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{R}{G}{W}");
this.expansionSetCode = "PLS";
this.subtype.add("Kavu");
this.power = new MageInt(3);
this.toughness = new MageInt(3);
// {R}{G}{W}: Prevent all combat damage blue creatures and black creatures would deal this turn.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, (new PreventAllDamageByAllEffect(filter,
Duration.EndOfTurn, true)), new ManaCostsImpl("{R}{G}{W}")));
}
public RadiantKavu(final RadiantKavu card) {
super(card);
}
@Override
public RadiantKavu copy() {
return new RadiantKavu(this);
}
}

View file

@ -0,0 +1,54 @@
/*
* 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.sets.planeshift;
import java.util.UUID;
import mage.constants.Rarity;
/**
*
* @author LoneFox
*/
public class WarpedDevotion extends mage.sets.eighthedition.WarpedDevotion {
public WarpedDevotion(UUID ownerId) {
super(ownerId);
this.cardNumber = 57;
this.expansionSetCode = "PLS";
this.rarity = Rarity.UNCOMMON;
}
public WarpedDevotion(final WarpedDevotion card) {
super(card);
}
@Override
public WarpedDevotion copy() {
return new WarpedDevotion(this);
}
}

View file

@ -31,6 +31,7 @@ import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTappedAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.TapTargetEffect;
@ -58,6 +59,7 @@ public class WintermoonMesa extends CardImpl {
// {2}, {tap}, Sacrifice Wintermoon Mesa: Tap two target lands.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new TapTargetEffect(), new ManaCostsImpl<>("{2}"));
ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeSourceCost());
ability.addTarget(new TargetLandPermanent(2));
this.addAbility(ability);
}

View file

@ -32,19 +32,12 @@ import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.CantBeCounteredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.cards.Card;
import mage.abilities.effects.common.DiscardOntoBattlefieldEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.stack.StackObject;
import mage.players.Player;
/**
*
@ -67,7 +60,7 @@ public class LoxodonSmiter extends CardImpl {
this.addAbility(new CantBeCounteredAbility());
// If a spell or ability an opponent controls causes you to discard Loxodon Smiter, put it onto the battlefield instead of putting it into your graveyard.
this.addAbility(new SimpleStaticAbility(Zone.HAND, new LoxodonSmiterEffect()));
this.addAbility(new SimpleStaticAbility(Zone.HAND, new DiscardOntoBattlefieldEffect()));
}
public LoxodonSmiter(final LoxodonSmiter card) {
@ -79,59 +72,3 @@ public class LoxodonSmiter extends CardImpl {
return new LoxodonSmiter(this);
}
}
class LoxodonSmiterEffect extends ReplacementEffectImpl {
public LoxodonSmiterEffect() {
super(Duration.EndOfGame, Outcome.PutCardInPlay);
staticText = "If a spell or ability an opponent controls causes you to discard {this}, put it onto the battlefield instead of putting it into your graveyard";
}
public LoxodonSmiterEffect(final LoxodonSmiterEffect effect) {
super(effect);
}
@Override
public LoxodonSmiterEffect copy() {
return new LoxodonSmiterEffect(this);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getTargetId().equals(source.getSourceId())) {
ZoneChangeEvent zcEvent = (ZoneChangeEvent) event;
if (zcEvent.getFromZone() == Zone.HAND && zcEvent.getToZone() == Zone.GRAVEYARD) {
StackObject spell = game.getStack().getStackObject(event.getSourceId());
if (spell != null && game.getOpponents(source.getControllerId()).contains(spell.getControllerId())) {
return true;
}
}
}
return false;
}
@Override
public boolean apply(Game game, Ability source) {
Card card = game.getCard(source.getSourceId());
if (card != null) {
Player player = game.getPlayer(card.getOwnerId());
if (player != null) {
if (card.putOntoBattlefield(game, Zone.HAND, source.getSourceId(), player.getId())) {
return true;
}
}
}
return false;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
return apply(game, source);
}
}

View file

@ -0,0 +1,52 @@
/*
* 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.sets.revisededition;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public class IslandSanctuary extends mage.sets.limitedalpha.IslandSanctuary {
public IslandSanctuary(UUID ownerId) {
super(ownerId);
this.cardNumber = 209;
this.expansionSetCode = "3ED";
}
public IslandSanctuary(final IslandSanctuary card) {
super(card);
}
@Override
public IslandSanctuary copy() {
return new IslandSanctuary(this);
}
}

View file

@ -36,7 +36,7 @@ import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.SacrificeTargetCost;
import mage.abilities.effects.PreventionEffectImpl;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect;
import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
@ -82,7 +82,7 @@ public class SekkiSeasonsGuide extends CardImpl {
// Sacrifice eight Spirits: Return Sekki from your graveyard to the battlefield.
this.addAbility(new SimpleActivatedAbility(
Zone.GRAVEYARD,
new ReturnSourceFromGraveyardToHandEffect(),
new ReturnSourceFromGraveyardToBattlefieldEffect(),
new SacrificeTargetCost(new TargetControlledPermanent(8, 8, filter, true))));
}

View file

@ -30,27 +30,18 @@ package mage.sets.shadowmoor;
import java.util.UUID;
import mage.MageInt;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.effects.common.DiscardOntoBattlefieldEffect;
import mage.abilities.effects.common.continuous.BoostAllEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.filter.predicate.permanent.ControllerPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.stack.StackObject;
import mage.players.Player;
/**
*
@ -66,7 +57,7 @@ public class WiltLeafLiege extends CardImpl {
filterWhite.add(new ColorPredicate(ObjectColor.WHITE));
filterWhite.add(new ControllerPredicate(TargetController.YOU));
}
public WiltLeafLiege(UUID ownerId) {
super(ownerId, 245, "Wilt-Leaf Liege", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{1}{G/W}{G/W}{G/W}");
this.expansionSetCode = "SHM";
@ -77,11 +68,11 @@ public class WiltLeafLiege extends CardImpl {
this.toughness = new MageInt(4);
// Other green creatures you control get +1/+1.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(new StaticValue(1), new StaticValue(1), Duration.WhileOnBattlefield, filterGreen, true)));
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(1, 1, Duration.WhileOnBattlefield, filterGreen, true)));
// Other white creatures you control get +1/+1.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(new StaticValue(1), new StaticValue(1), Duration.WhileOnBattlefield, filterWhite, true)));
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(1, 1, Duration.WhileOnBattlefield, filterWhite, true)));
// If a spell or ability an opponent controls causes you to discard Wilt-Leaf Liege, put it onto the battlefield instead of putting it into your graveyard.
this.addAbility(new SimpleStaticAbility(Zone.HAND, new WiltLeafLiegeEffect()));
this.addAbility(new SimpleStaticAbility(Zone.HAND, new DiscardOntoBattlefieldEffect()));
}
public WiltLeafLiege(final WiltLeafLiege card) {
@ -93,58 +84,3 @@ public class WiltLeafLiege extends CardImpl {
return new WiltLeafLiege(this);
}
}
class WiltLeafLiegeEffect extends ReplacementEffectImpl {
public WiltLeafLiegeEffect() {
super(Duration.EndOfGame, Outcome.PutCardInPlay);
staticText = "If a spell or ability an opponent controls causes you to discard {this}, put it onto the battlefield instead of putting it into your graveyard";
}
public WiltLeafLiegeEffect(final WiltLeafLiegeEffect effect) {
super(effect);
}
@Override
public WiltLeafLiegeEffect copy() {
return new WiltLeafLiegeEffect(this);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType().equals(GameEvent.EventType.ZONE_CHANGE);
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getTargetId().equals(source.getSourceId())) {
ZoneChangeEvent zcEvent = (ZoneChangeEvent) event;
if (zcEvent.getFromZone() == Zone.HAND && zcEvent.getToZone() == Zone.GRAVEYARD) {
StackObject spell = game.getStack().getStackObject(event.getSourceId());
if (spell != null && game.getOpponents(source.getControllerId()).contains(spell.getControllerId())) {
return true;
}
}
}
return false;
}
@Override
public boolean apply(Game game, Ability source) {
Card card = game.getCard(source.getSourceId());
if (card != null) {
Player player = game.getPlayer(card.getOwnerId());
if (player != null) {
card.putOntoBattlefield(game, Zone.HAND, source.getSourceId(), player.getId());
return true;
}
}
return false;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
return apply(game, source);
}
}

View file

@ -0,0 +1,72 @@
/*
* 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.sets.stronghold;
import java.util.UUID;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.effects.common.UntapAllEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.constants.TargetController;
import mage.filter.FilterPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate;
/**
*
* @author LevelX2
*/
public class Awakening extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("creatures and lands");
static {
filter.add(Predicates.or(
new CardTypePredicate(CardType.CREATURE),
new CardTypePredicate(CardType.LAND)
));
}
public Awakening(UUID ownerId) {
super(ownerId, 51, "Awakening", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}{G}");
this.expansionSetCode = "STH";
// At the beginning of each upkeep, untap all creatures and lands.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new UntapAllEffect(filter), TargetController.ANY, false));
}
public Awakening(final Awakening card) {
super(card);
}
@Override
public Awakening copy() {
return new Awakening(this);
}
}

View file

@ -0,0 +1,64 @@
/*
* 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.sets.tempest;
import java.util.UUID;
import mage.abilities.effects.common.PreventNextDamageFromChosenSourceToYouEffect;
import mage.abilities.keyword.BuybackAbility;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Rarity;
/**
*
* @author anonymous
*/
public class Invulnerability extends CardImpl {
public Invulnerability(UUID ownerId) {
super(ownerId, 237, "Invulnerability", Rarity.UNCOMMON, new CardType[]{CardType.INSTANT}, "{1}{W}");
this.expansionSetCode = "TMP";
// Buyback {3}
this.addAbility(new BuybackAbility("{3}"));
// The next time a source of your choice would deal damage to you this turn, prevent that damage.
this.getSpellAbility().addEffect(new PreventNextDamageFromChosenSourceToYouEffect(Duration.EndOfTurn));
}
public Invulnerability(final Invulnerability card) {
super(card);
}
@Override
public Invulnerability copy() {
return new Invulnerability(this);
}
}

View file

@ -0,0 +1,54 @@
/*
* 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.sets.timeshifted;
import java.util.UUID;
import mage.constants.Rarity;
/**
*
* @author LoneFox
*/
public class Dodecapod extends mage.sets.apocalypse.Dodecapod {
public Dodecapod(UUID ownerId) {
super(ownerId);
this.cardNumber = 108;
this.expansionSetCode = "TSB";
this.rarity = Rarity.SPECIAL;
}
public Dodecapod(final Dodecapod card) {
super(card);
}
@Override
public Dodecapod copy() {
return new Dodecapod(this);
}
}

View file

@ -0,0 +1,52 @@
/*
* 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.sets.unlimitededition;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public class IslandSanctuary extends mage.sets.limitedalpha.IslandSanctuary {
public IslandSanctuary(UUID ownerId) {
super(ownerId);
this.cardNumber = 210;
this.expansionSetCode = "2ED";
}
public IslandSanctuary(final IslandSanctuary card) {
super(card);
}
@Override
public IslandSanctuary copy() {
return new IslandSanctuary(this);
}
}

View file

@ -27,16 +27,18 @@
*/
package mage.sets.urzassaga;
import mage.constants.*;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.cards.CardImpl;
import mage.game.Game;
import mage.players.Player;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.continuous.PlayWithHandRevealedEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.game.Game;
import mage.players.Player;
/**
*
@ -49,7 +51,7 @@ public class Telepathy extends CardImpl {
this.expansionSetCode = "USG";
// Your opponents play with their hands revealed.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new OpponentsPlayWithTheTopCardRevealedEffect()));
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayWithHandRevealedEffect(TargetController.OPPONENT)));
}
public Telepathy(final Telepathy card) {
@ -61,37 +63,3 @@ public class Telepathy extends CardImpl {
return new Telepathy(this);
}
}
class OpponentsPlayWithTheTopCardRevealedEffect extends ContinuousEffectImpl {
public OpponentsPlayWithTheTopCardRevealedEffect() {
super(Duration.WhileOnBattlefield, Layer.PlayerEffects, SubLayer.NA, Outcome.Detriment);
staticText = "Your opponents play with their hands revealed";
}
public OpponentsPlayWithTheTopCardRevealedEffect(final OpponentsPlayWithTheTopCardRevealedEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source.getSourceId());
if (controller != null) {
for (UUID opponentId : game.getOpponents(controller.getId())) {
Player opponent = game.getPlayer(opponentId);
if (opponent != null) {
controller.revealCards(sourceObject.getIdName() + " " + opponent.getName(), opponent.getHand(), game, false);
}
}
return true;
}
return false;
}
@Override
public OpponentsPlayWithTheTopCardRevealedEffect copy() {
return new OpponentsPlayWithTheTopCardRevealedEffect(this);
}
}

View file

@ -0,0 +1,112 @@
/*
* 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.sets.vintagemasters;
import java.util.UUID;
import mage.MageInt;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.dynamicvalue.common.ParleyCount;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DrawCardAllEffect;
import mage.cards.CardImpl;
import mage.constants.AbilityWord;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.game.Game;
import mage.players.Player;
/**
*
* @author LevelX2
*/
public class SelvalaExplorerReturned extends CardImpl {
public SelvalaExplorerReturned(UUID ownerId) {
super(ownerId, 260, "Selvala, Explorer Returned", Rarity.RARE, new CardType[]{CardType.CREATURE}, "{1}{G}{W}");
this.expansionSetCode = "VMA";
this.supertype.add("Legendary");
this.subtype.add("Elf");
this.subtype.add("Scout");
this.power = new MageInt(2);
this.toughness = new MageInt(4);
// Parley - {T}: Each player reveals the top card of his or her library. For each nonland card revealed this way, add {G} to your mana pool and you gain 1 life. Then each player draws a card.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SelvalaExplorerReturnedEffect(), new TapSourceCost());
ability.setAbilityWord(AbilityWord.PARLEY);
Effect effect = new DrawCardAllEffect(1);
effect.setText("Then each player draws a card");
ability.addEffect(effect);
this.addAbility(ability);
}
public SelvalaExplorerReturned(final SelvalaExplorerReturned card) {
super(card);
}
@Override
public SelvalaExplorerReturned copy() {
return new SelvalaExplorerReturned(this);
}
}
class SelvalaExplorerReturnedEffect extends OneShotEffect {
public SelvalaExplorerReturnedEffect() {
super(Outcome.Benefit);
this.staticText = "Each player reveals the top card of his or her library. For each nonland card revealed this way, add {G} to your mana pool and you gain 1 life";
}
public SelvalaExplorerReturnedEffect(final SelvalaExplorerReturnedEffect effect) {
super(effect);
}
@Override
public SelvalaExplorerReturnedEffect copy() {
return new SelvalaExplorerReturnedEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
int parley = ParleyCount.getInstance().calculate(game, source, this);
if (parley > 0) {
controller.getManaPool().addMana(new Mana(0, parley, 0, 0, 0, 0, 0), game, source);
controller.gainLife(parley, game);
}
return true;
}
return false;
}
}

View file

@ -0,0 +1,66 @@
/*
* 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.sets.visions;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.PayLifeCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.PreventNextDamageFromChosenSourceToYouEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Rarity;
import mage.constants.Zone;
/**
*
* @author anonymous
*/
public class RighteousAura extends CardImpl {
public RighteousAura(UUID ownerId) {
super(ownerId, 120, "Righteous Aura", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}");
this.expansionSetCode = "VIS";
// {W}, Pay 2 life: The next time a source of your choice would deal damage to you this turn, prevent that damage.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreventNextDamageFromChosenSourceToYouEffect(Duration.EndOfTurn), new ManaCostsImpl("{W}"));
ability.addCost(new PayLifeCost(2));
this.addAbility(ability);
}
public RighteousAura(final RighteousAura card) {
super(card);
}
@Override
public RighteousAura copy() {
return new RighteousAura(this);
}
}

View file

@ -28,14 +28,13 @@
package mage.sets.worldwake;
import java.util.UUID;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.filter.common.FilterCreatureCard;
import mage.game.Game;
@ -54,7 +53,6 @@ public class DeadReckoning extends CardImpl {
super(ownerId, 56, "Dead Reckoning", Rarity.COMMON, new CardType[]{CardType.SORCERY}, "{1}{B}{B}");
this.expansionSetCode = "WWK";
// You may put target creature card from your graveyard on top of your library. If you do, Dead Reckoning deals damage equal to that card's power to target creature.
this.getSpellAbility().addEffect(new DeadReckoningEffect());
@ -103,7 +101,7 @@ class DeadReckoningEffect extends OneShotEffect {
int power = creatureInGraveyard.getPower().getValue();
Permanent creature = game.getPermanent(target2.getFirstTarget());
if (creature != null) {
creature.damage(power, id, game, true, true);
creature.damage(power, source.getSourceId(), game, true, true);
return true;
}
}

View file

@ -27,6 +27,7 @@
*/
package mage.sets.worldwake;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
@ -42,8 +43,6 @@ import mage.game.Game;
import mage.players.Player;
import mage.target.TargetPlayer;
import java.util.UUID;
/**
*
* @author jeffwadsworth
@ -61,7 +60,7 @@ public class DeathforgeShaman extends CardImpl {
// Multikicker {R}
this.addAbility(new MultikickerAbility("{R}"));
// When Deathforge Shaman enters the battlefield, it deals damage to target player equal to twice the number of times it was kicked.
Ability ability = new EntersBattlefieldTriggeredAbility(new DeathforgeShamanEffect());
ability.addTarget(new TargetPlayer());
@ -101,7 +100,7 @@ class DeathforgeShamanEffect extends OneShotEffect {
Player player = game.getPlayer(source.getFirstTarget());
if (player != null) {
player.damage(damage, id, game, false, true);
player.damage(damage, source.getSourceId(), game, false, true);
return true;
}
return false;

View file

@ -28,10 +28,6 @@
package mage.sets.zendikar;
import java.util.UUID;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
@ -40,6 +36,10 @@ import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.Token;
@ -53,16 +53,16 @@ public class KalitasBloodchiefOfGhet extends CardImpl {
public KalitasBloodchiefOfGhet(UUID ownerId) {
super(ownerId, 99, "Kalitas, Bloodchief of Ghet", Rarity.MYTHIC, new CardType[]{CardType.CREATURE}, "{5}{B}{B}");
this.supertype.add("Legendary");
this.expansionSetCode = "ZEN";
this.subtype.add("Vampire");
this.subtype.add("Warrior");
this.power = new MageInt(5);
this.toughness = new MageInt(5);
// {B}{B}{B}, {T}: Destroy target creature. If that creature dies this way, put a black Vampire creature token onto the battlefield. Its power is equal to that creature's power and its toughness is equal to that creature's toughness.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new KalitasDestroyEffect(), new ManaCostsImpl("{B}{B}{B}"));
ability.addCost(new TapSourceCost());
this.power = new MageInt(5);
this.toughness = new MageInt(5);
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
}
@ -114,4 +114,4 @@ class VampireToken extends Token {
toughness = new MageInt(tokenToughness);
}
}
}

View file

@ -28,9 +28,6 @@
package mage.sets.zendikar;
import java.util.UUID;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTappedAbility;
import mage.abilities.common.SimpleActivatedAbility;
@ -38,17 +35,15 @@ import mage.abilities.costs.common.RemoveCountersSourceCost;
import mage.abilities.costs.common.ReturnToHandSourceCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.effects.common.turn.AddExtraTurnControllerEffect;
import mage.abilities.effects.common.turn.SkipNextTurnSourceEffect;
import mage.abilities.mana.BlueManaAbility;
import mage.cards.CardImpl;
import mage.constants.Outcome;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.turn.TurnMod;
import mage.players.Player;
/**
*
@ -62,21 +57,22 @@ public class MagosiTheWaterveil extends CardImpl {
// Magosi, the Waterveil enters the battlefield tapped.
this.addAbility(new EntersBattlefieldTappedAbility());
// {tap}: Add {U} to your mana pool.
// {T}: Add {U} to your mana pool.
this.addAbility(new BlueManaAbility());
// {U}, {tap}: Put an eon counter on Magosi, the Waterveil. Skip your next turn.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new MagosiTheWaterveilEffect(), new ManaCostsImpl("{U}"));
// {U}, {T}: Put an eon counter on Magosi, the Waterveil. Skip your next turn.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.EON.createInstance()), new ManaCostsImpl("{U}"));
ability.addEffect(new SkipNextTurnSourceEffect());
ability.addCost(new TapSourceCost());
this.addAbility(ability);
// {tap}, Remove an eon counter from Magosi, the Waterveil and return it to its owner's hand: Take an extra turn after this one.
// {T}, Remove an eon counter from Magosi, the Waterveil and return it to its owner's hand: Take an extra turn after this one.
Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddExtraTurnControllerEffect(), new TapSourceCost());
ability2.addCost(new RemoveCountersSourceCost(CounterType.EON.createInstance()));
ability2.addCost(new ReturnToHandSourceCost());
this.addAbility(ability2);
}
public MagosiTheWaterveil(final MagosiTheWaterveil card) {
@ -88,35 +84,3 @@ public class MagosiTheWaterveil extends CardImpl {
return new MagosiTheWaterveil(this);
}
}
class MagosiTheWaterveilEffect extends OneShotEffect {
public MagosiTheWaterveilEffect() {
super(Outcome.Neutral);
staticText = "Put an eon counter on Magosi, the Waterveil. Skip your next turn";
}
public MagosiTheWaterveilEffect(final MagosiTheWaterveilEffect effect) {
super(effect);
}
@Override
public MagosiTheWaterveilEffect copy() {
return new MagosiTheWaterveilEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent magosi = game.getPermanent(source.getSourceId());
Player player = game.getPlayer(source.getControllerId());
if (magosi != null) {
magosi.addCounters(CounterType.EON.createInstance(), game);
}
if (player != null) {
game.getState().getTurnMods().add(new TurnMod(player.getId(), true));
}
return true;
}
}

View file

@ -25,19 +25,19 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.sets.zendikar;
import java.util.UUID;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Rarity;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.UntapTargetEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.effects.common.continuous.GainControlTargetEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.abilities.effects.common.UntapTargetEffect;
import mage.abilities.keyword.HasteAbility;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Rarity;
import mage.counters.CounterType;
import mage.target.common.TargetCreaturePermanent;
@ -47,18 +47,28 @@ import mage.target.common.TargetCreaturePermanent;
*/
public class MarkOfMutiny extends CardImpl {
public MarkOfMutiny (UUID ownerId) {
public MarkOfMutiny(UUID ownerId) {
super(ownerId, 137, "Mark of Mutiny", Rarity.UNCOMMON, new CardType[]{CardType.SORCERY}, "{2}{R}");
this.expansionSetCode = "ZEN";
// Gain control of target creature until end of turn.
// Put a +1/+1 counter on it and untap it.
// That creature gains haste until end of turn. (It can attack and this turn.)
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.EndOfTurn));
this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance()));
this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn));
this.getSpellAbility().addEffect(new UntapTargetEffect());
Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance());
effect.setText("Put a +1/+1 counter on it");
this.getSpellAbility().addEffect(effect);
effect = new UntapTargetEffect();
effect.setText("and untap it");
this.getSpellAbility().addEffect(effect);
effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn);
effect.setText("That creature gains haste until end of turn. <i>(It can {T} attack and this turn.)</i>");
this.getSpellAbility().addEffect(effect);
}
public MarkOfMutiny (final MarkOfMutiny card) {
public MarkOfMutiny(final MarkOfMutiny card) {
super(card);
}

View file

@ -66,4 +66,21 @@ public class PreventRepeatedActionsTest extends CardTestPlayerBaseAI {
Assert.assertEquals("AI should only used Equipment once", 2, tappedLands);
}
/**
* If the AI on a local server gets control of a Basalt Monolith it will
* infinite loop taping for three mana and then using the mana to untap lol.
* Seeing the computer durdle troll is quite the hillarious thing
*/
@Test
public void testBasaltMonolith() {
// Basalt Monolith doesn't untap during your untap step.
// {T}: Add {3} to your mana pool.
// {3}: Untap Basalt Monolith.
addCard(Zone.BATTLEFIELD, playerA, "Basalt Monolith", 1);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertTapped("Basalt Monolith", false);
}
}

View file

@ -0,0 +1,82 @@
/*
* 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 org.mage.test.commander.duel;
import java.io.FileNotFoundException;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.GameException;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestCommanderDuelBase;
/**
*
* @author LevelX2
*/
public class CommanderManaReplacmentTest extends CardTestCommanderDuelBase {
@Override
protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException {
setDecknamePlayerA("CommanderDuel_UW.dck"); // Commander = Daxos of Meletis
return super.createNewGameAndPlayers();
}
/**
* This issue appears to arise in both Commander Two Player Duel and
* Commander Free For All. Whenever a player (call her player 1) controls a
* permanent with a mana doubling continuous effect (e.g. Mana Flare) and
* another player (call her player 2) taps an affected permanent for mana
* that is outside of player 1's color identity, player 2 gets an additional
* colorless mana rather than the correct color of mana. I suspect the
* reason for this is that Xmage is treating Mana Flare as producing mana of
* the appropriate color and adding it to another player's mana pool, which
* is both incorrect in the game rules and would cause this problem.
*
* For example, I am playing a mono red deck and control a Mana Flare. You
* are playing a mono green deck and you tap a Forest for mana. You should
* add GG to your mana pool, but instead, Xmage shows you adding 1G to your
* mana pool.
*/
@Test
public void castCommanderWithFlash() {
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
addCard(Zone.HAND, playerA, "Vedalken Mastermind", 1); // {U}{U}
addCard(Zone.BATTLEFIELD, playerB, "Mana Flare");
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {U}"); // should add {U}{U}
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Vedalken Mastermind");
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
execute();
assertPermanentCount(playerA, "Vedalken Mastermind", 1);
}
}

View file

@ -0,0 +1,63 @@
/*
* 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 org.mage.test.turnmod;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.counters.CounterType;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
*
* @author LevelX2
*/
public class SkipTurnTest extends CardTestPlayerBase {
@Test
public void testEaterOfDays() {
// At the beginning of your upkeep or whenever you cast a green spell, put a charge counter on Shrine of Boundless Growth.
// {T}, Sacrifice Shrine of Boundless Growth: Add {1} to your mana pool for each charge counter on Shrine of Boundless Growth.
addCard(Zone.HAND, playerA, "Shrine of Boundless Growth", 1);
addCard(Zone.BATTLEFIELD, playerA, "Island", 7);
// Flying
// Trample
// When Eater of Days enters the battlefield, you skip your next two turns.
addCard(Zone.HAND, playerA, "Eater of Days", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Eater of Days");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Shrine of Boundless Growth");
setStopAt(5, PhaseStep.PRECOMBAT_MAIN);
execute();
assertPermanentCount(playerA, "Eater of Days", 1);
assertPermanentCount(playerA, "Shrine of Boundless Growth", 1);
assertCounterCount("Shrine of Boundless Growth", CounterType.CHARGE, 1);
}
}

View file

@ -0,0 +1,98 @@
/*
* 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.abilities.dynamicvalue.common;
import java.io.ObjectStreamException;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.MageSingleton;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.cards.Card;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.game.Game;
import mage.players.Player;
/**
* Don't use this for continuous effects because it applies a reveal effect!
*
* @author LevelX2
*/
public class ParleyCount implements DynamicValue, MageSingleton {
private static final ParleyCount fINSTANCE = new ParleyCount();
private Object readResolve() throws ObjectStreamException {
return fINSTANCE;
}
public static ParleyCount getInstance() {
return fINSTANCE;
}
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
// Each player reveals the top card of his or her library. For each nonland card revealed this way
int parleyValue = 0;
MageObject sourceObject = game.getObject(sourceAbility.getSourceId());
if (sourceObject != null) {
for (UUID playerId : game.getState().getPlayerList(sourceAbility.getControllerId())) {
Player player = game.getPlayer(playerId);
if (player != null) {
Card card = player.getLibrary().getFromTop(game);
if (card != null) {
if (!card.getCardType().contains(CardType.LAND)) {
parleyValue++;
}
player.revealCards(sourceObject.getIdName() + " (" + player.getName() + ")", new CardsImpl(card), game);
}
}
}
}
return parleyValue;
}
@Override
public DynamicValue copy() {
return fINSTANCE;
}
@Override
public String toString() {
return "1";
}
@Override
public String getMessage() {
return "Parley";
}
}

View file

@ -51,13 +51,15 @@ import mage.target.common.TargetCardInGraveyard;
/**
* Cards with the Aura subtype don't change the zone they are in, if there is no
* valid target on the battlefield. Also, when entering the battlefield and it
* was not cast (so from Zone != Hand), this effect gets the target to whitch to attach it
* and adds the Aura the the battlefield and attachs it to the target.
* was not cast (so from Zone != Hand), this effect gets the target to whitch to
* attach it and adds the Aura the the battlefield and attachs it to the target.
* The "attachTo:" value in game state has to be set therefore.
*
* If no "attachTo:" value is defined, the controlling player has to chose the aura target.
*
* This effect is automatically added to ContinuousEffects at the start of a game
* If no "attachTo:" value is defined, the controlling player has to chose the
* aura target.
*
* This effect is automatically added to ContinuousEffects at the start of a
* game
*
* @author North
*/
@ -93,7 +95,7 @@ public class AuraReplacementEffect extends ReplacementEffectImpl {
return false;
}
// Aura enters the battlefield attached
Object object = game.getState().getValue("attachTo:"+card.getId());
Object object = game.getState().getValue("attachTo:" + card.getId());
if (object != null && object instanceof PermanentCard) {
return false;
}
@ -113,7 +115,7 @@ public class AuraReplacementEffect extends ReplacementEffectImpl {
targetId = stackAbility.getEffects().get(0).getTargetPointer().getFirst(game, stackAbility);
}
}
if (targetId == null) {
Target target = card.getSpellAbility().getTargets().get(0);
enchantCardInGraveyard = target instanceof TargetCardInGraveyard;
@ -122,9 +124,10 @@ public class AuraReplacementEffect extends ReplacementEffectImpl {
}
Player player = game.getPlayer(card.getOwnerId());
Outcome auraOutcome = Outcome.BoostCreature;
Ability: for (Ability ability:card.getAbilities()) {
Ability:
for (Ability ability : card.getAbilities()) {
if (ability instanceof SpellAbility) {
for (Effect effect: ability.getEffects()) {
for (Effect effect : ability.getEffects()) {
if (effect instanceof AttachEffect) {
auraOutcome = effect.getOutcome();
break Ability;
@ -167,13 +170,16 @@ public class AuraReplacementEffect extends ReplacementEffectImpl {
game.getBattlefield().addPermanent(permanent);
card.setZone(Zone.BATTLEFIELD, game);
game.applyEffects();
permanent.entersBattlefield(event.getSourceId(), game, fromZone, true);
boolean entered = permanent.entersBattlefield(event.getSourceId(), game, fromZone, true);
game.applyEffects();
if (!entered) {
return false;
}
game.fireEvent(new ZoneChangeEvent(permanent, controllerId, fromZone, Zone.BATTLEFIELD));
if (targetCard != null) {
permanent.attachTo(targetCard.getId(), game);
}
}
if (targetPermanent != null) {
targetPermanent.addAttachment(permanent.getId(), game);
}
@ -183,7 +189,7 @@ public class AuraReplacementEffect extends ReplacementEffectImpl {
}
return true;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
@ -192,7 +198,7 @@ public class AuraReplacementEffect extends ReplacementEffectImpl {
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (((ZoneChangeEvent) event).getToZone().equals(Zone.BATTLEFIELD)
&& !(((ZoneChangeEvent) event).getFromZone().equals(Zone.HAND)) ) {
&& !(((ZoneChangeEvent) event).getFromZone().equals(Zone.HAND))) {
Card card = game.getCard(event.getTargetId());
if (card != null && card.getCardType().contains(CardType.ENCHANTMENT) && card.hasSubtype("Aura")) {
return true;

View file

@ -0,0 +1,103 @@
/*
* 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.abilities.effects.common;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
/**
*
* @author LoneFox
*/
public class DamageTargetControllerEffect extends OneShotEffect {
protected DynamicValue amount;
protected boolean preventable;
public DamageTargetControllerEffect(int amount) {
this(new StaticValue(amount), true);
}
public DamageTargetControllerEffect(int amount, boolean preventable) {
this(new StaticValue(amount), preventable);
}
public DamageTargetControllerEffect(DynamicValue amount) {
this(amount, true);
}
public DamageTargetControllerEffect(DynamicValue amount, boolean preventable) {
super(Outcome.Damage);
this.amount = amount;
this.preventable = preventable;
}
public DamageTargetControllerEffect(final DamageTargetControllerEffect effect) {
super(effect);
amount = effect.amount.copy();
preventable = effect.preventable;
}
@Override
public DamageTargetControllerEffect copy() {
return new DamageTargetControllerEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if(permanent != null) {
Player targetController = game.getPlayer(permanent.getControllerId());
if(targetController != null) {
targetController.damage(amount.calculate(game, source, this), source.getSourceId(), game, false, preventable);
}
return true;
}
return false;
}
@Override
public String getText(Mode mode) {
if (staticText != null && !staticText.isEmpty()) {
return staticText;
}
String text = "{this} deals " + amount.getMessage() + " damage to target "
+ mode.getTargets().get(0).getTargetName() + "'s controller";
if(!preventable) {
text += ". The damage can't be prevented";
}
return text;
}
}

View file

@ -0,0 +1,96 @@
/*
* 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.abilities.effects.common;
import mage.abilities.Ability;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.cards.Card;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent.EventType;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.stack.StackObject;
import mage.players.Player;
/**
*
* @author LoneFox
*/
public class DiscardOntoBattlefieldEffect extends ReplacementEffectImpl {
public DiscardOntoBattlefieldEffect() {
super(Duration.EndOfGame, Outcome.PutCardInPlay);
staticText = "If a spell or ability an opponent controls causes you to discard {this}, put it onto the battlefield instead of putting it into your graveyard";
}
public DiscardOntoBattlefieldEffect(final DiscardOntoBattlefieldEffect effect) {
super(effect);
}
@Override
public DiscardOntoBattlefieldEffect copy() {
return new DiscardOntoBattlefieldEffect(this);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == EventType.ZONE_CHANGE;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getTargetId().equals(source.getSourceId())) {
ZoneChangeEvent zcEvent = (ZoneChangeEvent) event;
if (zcEvent.getFromZone() == Zone.HAND && zcEvent.getToZone() == Zone.GRAVEYARD) {
StackObject spell = game.getStack().getStackObject(event.getSourceId());
if (spell != null && game.getOpponents(source.getControllerId()).contains(spell.getControllerId())) {
return true;
}
}
}
return false;
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Card card = game.getCard(source.getSourceId());
if (card != null) {
Player owner = game.getPlayer(card.getOwnerId());
if (owner != null) {
if (owner.putOntoBattlefieldWithInfo(card, game, Zone.HAND, source.getSourceId())) {
return true;
}
}
}
return false;
}
}

View file

@ -0,0 +1,69 @@
/*
* 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.abilities.effects.common;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.filter.FilterPermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
*
* @author LevelX2
*/
public class UntapAllEffect extends OneShotEffect {
private final FilterPermanent filter;
public UntapAllEffect(FilterPermanent filter) {
super(Outcome.Untap);
staticText = "untap all " + filter.getMessage();
this.filter = filter;
}
public UntapAllEffect(final UntapAllEffect effect) {
super(effect);
this.filter = effect.filter;
}
@Override
public boolean apply(Game game, Ability source) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) {
permanent.untap(game);
}
return true;
}
@Override
public UntapAllEffect copy() {
return new UntapAllEffect(this);
}
}

View file

@ -0,0 +1,114 @@
/*
* 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.abilities.effects.common.continuous;
import java.util.ArrayList;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.constants.Duration;
import mage.constants.Layer;
import mage.constants.Outcome;
import mage.constants.SubLayer;
import mage.constants.TargetController;
import mage.game.Game;
import mage.players.Player;
/**
*
* @author LoneFox
*/
public class PlayWithHandRevealedEffect extends ContinuousEffectImpl {
private TargetController who;
public PlayWithHandRevealedEffect(TargetController who) {
super(Duration.WhileOnBattlefield, Layer.PlayerEffects, SubLayer.NA, Outcome.Detriment);
this.who = who;
}
public PlayWithHandRevealedEffect(final PlayWithHandRevealedEffect effect) {
super(effect);
who = effect.who;
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Iterable<UUID> affectedPlayers;
switch(who) {
case ANY:
affectedPlayers = controller.getInRange();
break;
case OPPONENT:
affectedPlayers = game.getOpponents(source.getControllerId());
break;
case YOU:
ArrayList tmp = new ArrayList<UUID>();
tmp.add(source.getControllerId());
affectedPlayers = tmp;
break;
default:
return false;
}
for(UUID playerID: affectedPlayers) {
Player player = game.getPlayer(playerID);
if (player != null) {
player.revealCards(player.getName() + "'s hand cards", player.getHand(), game, false);
}
}
return true;
}
return false;
}
@Override
public PlayWithHandRevealedEffect copy() {
return new PlayWithHandRevealedEffect(this);
}
@Override
public String getText(Mode mode) {
if (staticText != null && !staticText.isEmpty()) {
return staticText;
}
switch(who) {
case ANY:
return "Players play with their hands revealed";
case OPPONENT:
return "Your opponents play with their hands revealed";
case YOU:
return "Play with your hand revealed";
default:
return "Unknown TargetController for PlayWithHandRevealedEffect";
}
}
}

View file

@ -27,12 +27,12 @@
*/
package mage.abilities.effects.common.discard;
import mage.constants.Outcome;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.constants.Outcome;
import mage.game.Game;
import mage.players.Player;
import mage.util.CardUtil;
@ -98,7 +98,7 @@ public class DiscardControllerEffect extends OneShotEffect {
}
private void setText() {
StringBuilder sb = new StringBuilder("Discard ");
StringBuilder sb = new StringBuilder("discard ");
if (amount.toString().equals("1")) {
sb.append("a");
} else {

View file

@ -10,20 +10,29 @@ import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.game.Game;
import mage.game.turn.TurnMod;
import mage.util.CardUtil;
/**
*
* @author Mael
*/
public class SkipNextTurnSourceEffect extends OneShotEffect {
int numberOfTurns;
public SkipNextTurnSourceEffect() {
this(1);
}
public SkipNextTurnSourceEffect(int numberOfTurns) {
super(Outcome.Neutral);
staticText = "You skip your next turn";
this.numberOfTurns = numberOfTurns;
staticText = "you skip your next " + (numberOfTurns == 1 ? "turn" : CardUtil.numberToText(numberOfTurns) + " turns");
}
public SkipNextTurnSourceEffect(final SkipNextTurnSourceEffect effect) {
super(effect);
this.numberOfTurns = effect.numberOfTurns;
}
@Override
@ -33,7 +42,9 @@ public class SkipNextTurnSourceEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
game.getState().getTurnMods().add(new TurnMod(source.getControllerId(), true));
for (int i = 0; i < numberOfTurns; i++) {
game.getState().getTurnMods().add(new TurnMod(source.getControllerId(), true));
}
return true;
}
}

View file

@ -421,13 +421,17 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
game.setZone(objectId, Zone.BATTLEFIELD);
game.setScopeRelevant(true);
game.applyEffects();
permanent.entersBattlefield(sourceId, game, event.getFromZone(), true);
boolean entered = permanent.entersBattlefield(sourceId, game, event.getFromZone(), true);
game.setScopeRelevant(false);
game.applyEffects();
if (flag) {
permanent.setTapped(true);
if (entered) {
if (flag) {
permanent.setTapped(true);
}
event.setTarget(permanent);
} else {
return false;
}
event.setTarget(permanent);
break;
default:
Card sourceCard = game.getCard(sourceId);
@ -603,11 +607,13 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
game.setScopeRelevant(true);
permanent.setTapped(tapped);
permanent.setFaceDown(facedown, game);
permanent.entersBattlefield(sourceId, game, event.getFromZone(), true);
boolean entered = permanent.entersBattlefield(sourceId, game, event.getFromZone(), true);
game.setScopeRelevant(false);
game.applyEffects();
game.addSimultaneousEvent(new ZoneChangeEvent(permanent, event.getPlayerId(), fromZone, Zone.BATTLEFIELD));
return true;
if (entered) {
game.addSimultaneousEvent(new ZoneChangeEvent(permanent, event.getPlayerId(), fromZone, Zone.BATTLEFIELD));
return true;
}
}
if (facedown) {
this.setFaceDown(false, game);

View file

@ -117,16 +117,11 @@ public abstract class ExpansionSet implements Serializable {
// if the packs are too big, it removes the first cards.
// since it adds lands then commons before uncommons
// and rares this should be the least disruptive.
List<Card> theBooster = this.createBooster();
List<CardInfo> commons = getCardsByRarity(Rarity.COMMON);
int iterations = 0;
while (15 > theBooster.size() && !commons.isEmpty()) {
while (15 > theBooster.size()) {
addToBooster(theBooster, commons);
iterations++;
if (iterations > 14) {
break;
}
}
while (theBooster.size() > 15) {
@ -301,9 +296,8 @@ public abstract class ExpansionSet implements Serializable {
savedCardsInfos = CardRepository.instance.findCards(criteria);
savedCards.put(rarity, savedCardsInfos);
}
List<CardInfo> cards = new ArrayList<>();
cards.addAll(savedCardsInfos);
return cards;
// Return a copy of the saved cards information, as not to modify the original.
return new ArrayList<>(savedCardsInfos);
}
public List<CardInfo> getSpecialCommon() {

View file

@ -25,7 +25,6 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.constants;
/**
@ -33,15 +32,17 @@ package mage.constants;
* @author LevelX2
*/
public enum AbilityWord {
BLOODRUSH("Bloodrush"),
CONSTELLATION("Constellation"),
FEROCIOUS("Ferocious"),
FEROCIOUS("Ferocious"),
FORMIDABLE("Formidable"),
GRANDEUR("Grandeur"),
HELLBENT("Hellbent"),
HEROIC("Heroic"),
FORMIDABLE("Formidable"),
LANDFALL("Landfall"),
METALCRAFT("Metalcraft"),
GRANDEUR("Grandeur"),
PARLEY("Parley"),
RAID("Raid");
private final String text;

View file

@ -174,7 +174,7 @@ public abstract class GameImpl implements Game, Serializable {
protected GameState state;
private transient Stack<Integer> savedStates = new Stack<>();
protected transient GameStates gameStates = new GameStates();
// game states to allow player roll back
// game states to allow player rollback
protected transient Map<Integer, GameState> gameStatesRollBack = new HashMap<>();
protected boolean executingRollback;
@ -700,7 +700,6 @@ public abstract class GameImpl implements Game, Serializable {
if (!playTurn(playerByOrder)) {
break;
}
state.setTurnNum(state.getTurnNum() + 1);
}
playExtraTurns();
playerByOrder = playerList.getNext(this);
@ -741,7 +740,6 @@ public abstract class GameImpl implements Game, Serializable {
informPlayers(extraPlayer.getLogName() + " takes an extra turn");
}
playTurn(extraPlayer);
state.setTurnNum(state.getTurnNum() + 1);
}
}
extraTurn = getNextExtraTurn();
@ -768,6 +766,7 @@ public abstract class GameImpl implements Game, Serializable {
}
private boolean playTurn(Player player) {
boolean skipTurn = false;
do {
if (executingRollback) {
executingRollback = false;
@ -781,41 +780,23 @@ public abstract class GameImpl implements Game, Serializable {
state.setActivePlayerId(player.getId());
saveRollBackGameState();
}
this.logStartOfTurn(player);
if (checkStopOnTurnOption()) {
return false;
}
state.getTurn().play(this, player);
skipTurn = state.getTurn().play(this, player);
} while (executingRollback);
if (isPaused() || gameOver(null)) {
return false;
}
endOfTurn();
if (!skipTurn) {
endOfTurn();
state.setTurnNum(state.getTurnNum() + 1);
}
return true;
}
private void logStartOfTurn(Player player) {
StringBuilder sb = new StringBuilder("Turn ").append(state.getTurnNum()).append(" ");
sb.append(player.getLogName());
sb.append(" (");
int delimiter = this.getPlayers().size() - 1;
for (Player gamePlayer : this.getPlayers().values()) {
sb.append(gamePlayer.getLife());
int poison = gamePlayer.getCounters().getCount(CounterType.POISON);
if (poison > 0) {
sb.append("[P:").append(poison).append("]");
}
if (delimiter > 0) {
sb.append(" - ");
delimiter--;
}
}
sb.append(")");
fireStatusEvent(sb.toString(), true);
}
private boolean checkStopOnTurnOption() {
if (gameOptions.stopOnTurn != null && gameOptions.stopAtStep == PhaseStep.UNTAP) {
if (gameOptions.stopOnTurn.equals(state.getTurnNum())) {

View file

@ -4,8 +4,8 @@ import java.io.Serializable;
import mage.constants.PhaseStep;
/**
* Game options for Mage game.
* Mainly used in tests to configure {@link GameImpl} with specific params.
* Game options for Mage game. Mainly used in tests to configure
* {@link GameImpl} with specific params.
*
* @author ayratn
*/
@ -23,8 +23,8 @@ public class GameOptions implements Serializable {
public boolean testMode = false;
/**
* Defines the turn number game should stop on.
* By default, is null meaning that game shouldn't stop on any specific turn.
* Defines the turn number game should stop on. By default, is null meaning
* that game shouldn't stop on any specific turn.
*/
public Integer stopOnTurn = null;
@ -37,9 +37,9 @@ public class GameOptions implements Serializable {
* If true, library won't be shuffled at the beginning of the game
*/
public boolean skipInitShuffling = false;
/**
* If true, players can roll back turn if all players agree
* If true, players can rollback turn if all players agree
*/
public boolean rollbackTurnsAllowed = true;
}

View file

@ -41,6 +41,7 @@ import mage.abilities.Ability;
import mage.abilities.ActivatedAbility;
import mage.abilities.DelayedTriggeredAbilities;
import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.MageSingleton;
import mage.abilities.Mode;
import mage.abilities.SpecialActions;
import mage.abilities.StaticAbility;
@ -856,13 +857,19 @@ public class GameState implements Serializable, Copyable<GameState> {
* @param ability
*/
public void addOtherAbility(Card attachedTo, Ability ability) {
ability.setSourceId(attachedTo.getId());
ability.setControllerId(attachedTo.getOwnerId());
Ability newAbility;
if (ability instanceof MageSingleton) {
newAbility = ability;
} else {
newAbility = ability.copy();
}
newAbility.setSourceId(attachedTo.getId());
newAbility.setControllerId(attachedTo.getOwnerId());
if (!cardState.containsKey(attachedTo.getId())) {
cardState.put(attachedTo.getId(), new CardState());
}
cardState.get(attachedTo.getId()).addAbility(ability);
addAbility(ability, attachedTo.getId(), attachedTo);
cardState.get(attachedTo.getId()).addAbility(newAbility);
addAbility(newAbility, attachedTo.getId(), attachedTo);
}
/**

View file

@ -810,19 +810,21 @@ public class Combat implements Serializable, Copyable<Combat> {
// check now, if it already blocks a creature that mustBeBlockedByAtLeastOne
if (possibleBlocker.getBlocking() > 0) {
CombatGroup combatGroupOfPossibleBlocker = findGroupOfBlocker(possibleBlockerId);
for (UUID blockedAttackerId : combatGroupOfPossibleBlocker.getAttackers()) {
if (mustBeBlockedByAtLeastOne.containsKey(blockedAttackerId)) {
// blocks a creature that has to be blocked by at least one
if (combatGroupOfPossibleBlocker.getBlockers().size() == 1) {
// the creature blocks alone already a creature that has to be blocked by at least one,
// so this is ok
return null;
if (combatGroupOfPossibleBlocker != null) {
for (UUID blockedAttackerId : combatGroupOfPossibleBlocker.getAttackers()) {
if (mustBeBlockedByAtLeastOne.containsKey(blockedAttackerId)) {
// blocks a creature that has to be blocked by at least one
if (combatGroupOfPossibleBlocker.getBlockers().size() == 1) {
// the creature blocks alone already a creature that has to be blocked by at least one,
// so this is ok
return null;
}
// TODO: Check if the attacker is already blocked by another creature
// and despite there is need that this attacker blocks this attacker also
// I don't know why
Permanent blockedAttacker = game.getPermanent(blockedAttackerId);
return possibleBlocker.getIdName() + " blocks with other creatures " + blockedAttacker.getIdName() + ", which has to be blocked by only one creature. ";
}
// TODO: Check if the attacker is already blocked by another creature
// and despite there is need that this attacker blocks this attacker also
// I don't know why
Permanent blockedAttacker = game.getPermanent(blockedAttackerId);
return possibleBlocker.getIdName() + " blocks with other creatures " + blockedAttacker.getIdName() + ", which has to be blocked by only one creature. ";
}
}
}
@ -947,9 +949,12 @@ public class Combat implements Serializable, Copyable<Combat> {
if (!canDefenderBeAttacked(attackerId, defenderId, game)) {
return false;
}
Permanent attacker = game.getPermanent(attackerId);
if (attacker == null) {
return false;
}
CombatGroup newGroup = new CombatGroup(defenderId, defender != null, defender != null ? defender.getControllerId() : defenderId);
newGroup.attackers.add(attackerId);
Permanent attacker = game.getPermanent(attackerId);
attacker.setAttacking(true);
groups.add(newGroup);
return true;

View file

@ -119,7 +119,20 @@ public class GameEvent implements Serializable {
*/
SPELL_CAST,
ACTIVATE_ABILITY, ACTIVATED_ABILITY,
ADD_MANA, MANA_ADDED,
/* ADD_MANA
targetId id of the ability that added the mana
sourceId sourceId of the ability that added the mana
playerId player the mana is added to the mana pool for
mana the mana added
*/
ADD_MANA,
/* MANA_ADDED
targetId id of the ability that added the mana
sourceId sourceId of the ability that added the mana
playerId player the mana is added to the mana pool for
mana the mana added
*/
MANA_ADDED,
/* MANA_PAYED
targetId id if the ability the mana was paid for (not the sourceId)
sourceId sourceId of the mana source

View file

@ -1,31 +1,30 @@
/*
* 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.
*/
* 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.game.permanent;
import java.util.ArrayList;
@ -45,60 +44,89 @@ import mage.game.Game;
public interface Permanent extends Card, Controllable {
void setControllerId(UUID controllerId);
boolean isTapped();
boolean untap(Game game);
boolean tap(Game game);
/**
* use tap(game)
* <p>setTapped doesn't trigger TAPPED event and should be used
* only if you want permanent to enter battlefield tapped</p>
* <p>
* setTapped doesn't trigger TAPPED event and should be used only if you
* want permanent to enter battlefield tapped</p>
*
* @param tapped
* @deprecated
*/
@Deprecated
void setTapped(boolean tapped);
boolean canTap();
boolean isFlipped();
boolean unflip(Game game);
boolean flip(Game game);
boolean transform(Game game);
boolean isTransformed();
void setTransformed(boolean value);
boolean isPhasedIn();
boolean phaseIn(Game game);
boolean phaseOut(Game game);
boolean isMonstrous();
void setMonstrous(boolean value);
boolean isRenowned();
void setRenowned(boolean value);
void setCardNumber(int cid);
void setExpansionSetCode(String expansionSetCode);
void setRarity(Rarity rarity);
void setFlipCard(boolean flipCard);
void setFlipCardName(String flipCardName);
void setSecondCardFace(Card card);
Counters getCounters();
List<UUID> getAttachments();
UUID getAttachedTo();
void attachTo(UUID permanentId, Game game);
boolean addAttachment(UUID permanentId, Game game);
boolean removeAttachment(UUID permanentId, Game game);
boolean canBeTargetedBy(MageObject source, UUID controllerId, Game game);
boolean hasProtectionFrom(MageObject source, Game game);
boolean cantBeEnchantedBy(MageObject source, Game game);
boolean wasControlledFromStartOfControllerTurn();
boolean hasSummoningSickness();
int getDamage();
int damage(int damage, UUID sourceId, Game game, boolean combat, boolean preventable);
int damage(int damage, UUID sourceId, Game game, boolean combat, boolean preventable, ArrayList<UUID> appliedEffects);
@ -114,58 +142,83 @@ public interface Permanent extends Card, Controllable {
* @return
*/
int markDamage(int damage, UUID sourceId, Game game, boolean preventable, boolean combat);
int applyDamage(Game game);
void removeAllDamage(Game game);
void reset(Game game);
boolean destroy(UUID sourceId, Game game, boolean noRegen);
boolean sacrifice(UUID sourceId, Game game);
boolean regenerate(UUID sourceId, Game game);
boolean fight(Permanent fightTarget, Ability source, Game game);
void entersBattlefield(UUID sourceId, Game game, Zone fromZone, boolean fireEvent);
boolean entersBattlefield(UUID sourceId, Game game, Zone fromZone, boolean fireEvent);
String getValue();
@Deprecated
void addAbility(Ability ability);
@Deprecated
void addAbility(Ability ability, Game game);
void addAbility(Ability ability, UUID sourceId, Game game);
void addAbility(Ability ability, UUID sourceId, Game game, boolean createNewId);
void removeAllAbilities(UUID sourceId, Game game);
void addLoyaltyUsed();
boolean canLoyaltyBeUsed(Game game);
public void resetControl();
boolean changeControllerId(UUID controllerId, Game game);
boolean checkControlChanged(Game game);
void beginningOfTurn(Game game);
void endOfTurn(Game game);
int getTurnsOnBattlefield();
void addPower(int power);
void addToughness(int toughness);
boolean isAttacking();
int getBlocking();
void setAttacking(boolean attacking);
void setBlocking(int blocking);
int getMaxBlocks();
void setMaxBlocks(int maxBlocks);
int getMinBlockedBy();
void setMinBlockedBy(int minBlockedBy);
int getMaxBlockedBy();
boolean isRemovedFromCombat();
void setRemovedFromCombat(boolean removedFromCombat);
/**
* Sets the maximum number of blockers the creature can be blocked by.
* Default = 0 which means there is no restriction in the number of blockers.
* Default = 0 which means there is no restriction in the number of
* blockers.
*
* @param maxBlockedBy maximum number of blockers
*/
@ -180,11 +233,14 @@ public interface Permanent extends Card, Controllable {
* @return
*/
boolean canAttack(UUID defenderId, Game game);
boolean canBlock(UUID attackerId, Game game);
boolean canBlockAny(Game game);
/**
* Checks by restriction effects if the permanent can use activated abilities
* Checks by restriction effects if the permanent can use activated
* abilities
*
* @param game
* @return true - permanent can use activated abilities
@ -192,11 +248,15 @@ public interface Permanent extends Card, Controllable {
boolean canUseActivatedAbilities(Game game);
boolean removeFromCombat(Game game);
boolean removeFromCombat(Game game, boolean withInfo);
boolean isDeathtouched();
/**
* Returns a list of object refrences that dealt damage this turn to this permanent
* Returns a list of object refrences that dealt damage this turn to this
* permanent
*
* @return
*/
HashSet<MageObjectReference> getDealtDamageByThisTurn();
@ -222,13 +282,14 @@ public interface Permanent extends Card, Controllable {
* Get card that was imprinted on this one.
*
* Can be null if no card was imprinted.
*
* @return Imprinted card UUID.
*/
List<UUID> getImprinted();
/**
* Allows to connect any card to permanent.
* Very similar to Imprint except that it is for internal use only.
* Allows to connect any card to permanent. Very similar to Imprint except
* that it is for internal use only.
*
* @param key
* @param connectedCard
@ -236,8 +297,9 @@ public interface Permanent extends Card, Controllable {
void addConnectedCard(String key, UUID connectedCard);
/**
* Returns connected cards.
* Very similar to Imprint except that it is for internal use only.
* Returns connected cards. Very similar to Imprint except that it is for
* internal use only.
*
* @param key
* @return
*/
@ -245,6 +307,7 @@ public interface Permanent extends Card, Controllable {
/**
* Clear all connected cards.
*
* @param key
*/
void clearConnectedCards(String key);
@ -269,9 +332,11 @@ public interface Permanent extends Card, Controllable {
void clearPairedCard();
void setMorphed(boolean value);
boolean isMorphed();
void setManifested(boolean value);
boolean isManifested();
@Override
@ -280,5 +345,6 @@ public interface Permanent extends Card, Controllable {
// Simple int counter to set a timewise create order , the lower the number the earlier the object was created
// if objects enter the battlefield at the same time they can get (and should) get the same number.
int getCreateOrder();
void setCreateOrder(int createOrder);
}

View file

@ -899,10 +899,10 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
}
@Override
public void entersBattlefield(UUID sourceId, Game game, Zone fromZone, boolean fireEvent) {
public boolean entersBattlefield(UUID sourceId, Game game, Zone fromZone, boolean fireEvent) {
controlledFromStartOfControllerTurn = false;
if (this.isFaceDown(game)) {
// remove some attributes here, bceause first apply effects comes later otherwise abilities (e.g. color related) will unintended trigger
// remove some attributes here, because first apply effects comes later otherwise abilities (e.g. color related) will unintended trigger
MorphAbility.setPermanentToFaceDownCreature(this);
}
EntersTheBattlefieldEvent event = new EntersTheBattlefieldEvent(this, sourceId, getControllerId(), fromZone);
@ -914,7 +914,9 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
game.addSimultaneousEvent(event);
}
}
return true;
}
return false;
}
@Override

View file

@ -159,15 +159,17 @@ public class Token extends MageObjectImpl {
this.lastAddedTokenId = newToken.getId();
game.setScopeRelevant(true);
game.applyEffects();
newToken.entersBattlefield(sourceId, game, Zone.OUTSIDE, true);
boolean entered = newToken.entersBattlefield(sourceId, game, Zone.OUTSIDE, true);
game.setScopeRelevant(false);
game.applyEffects();
game.fireEvent(new ZoneChangeEvent(newToken, event.getPlayerId(), Zone.OUTSIDE, Zone.BATTLEFIELD));
if (attacking && game.getCombat() != null) {
game.getCombat().addAttackingCreature(newToken.getId(), game);
}
if (!game.isSimulation()) {
game.informPlayers(controller.getLogName() + " puts a " + newToken.getLogName() + " token onto the battlefield");
if (entered) {
game.fireEvent(new ZoneChangeEvent(newToken, event.getPlayerId(), Zone.OUTSIDE, Zone.BATTLEFIELD));
if (attacking && game.getCombat() != null) {
game.getCombat().addAttackingCreature(newToken.getId(), game);
}
if (!game.isSimulation()) {
game.informPlayers(controller.getLogName() + " puts a " + newToken.getLogName() + " token onto the battlefield");
}
}
}

View file

@ -34,6 +34,7 @@ import java.util.List;
import java.util.UUID;
import mage.constants.PhaseStep;
import mage.constants.TurnPhase;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
@ -116,16 +117,24 @@ public class Turn implements Serializable {
return null;
}
public void play(Game game, Player activePlayer) {
/**
*
* @param game
* @param activePlayer
* @return true if turn is skipped
*/
public boolean play(Game game, Player activePlayer) {
activePlayer.becomesActivePlayer();
this.setDeclareAttackersStepStarted(false);
if (game.isPaused() || game.gameOver(null)) {
return;
return false;
}
if (game.getState().getTurnMods().skipTurn(activePlayer.getId())) {
return;
game.informPlayers(activePlayer.getLogName() + " skips his or her turn.");
return true;
}
logStartOfTurn(game, activePlayer);
checkTurnIsControlledByOtherPlayer(game, activePlayer.getId());
@ -134,7 +143,7 @@ public class Turn implements Serializable {
game.getPlayer(activePlayer.getId()).beginTurn(game);
for (Phase phase : phases) {
if (game.isPaused() || game.gameOver(null)) {
return;
return false;
}
if (!isEndTurnRequested() || phase.getType().equals(TurnPhase.END)) {
currentPhase = phase;
@ -142,7 +151,7 @@ public class Turn implements Serializable {
if (!game.getState().getTurnMods().skipPhase(activePlayer.getId(), currentPhase.getType())) {
if (phase.play(game, activePlayer.getId())) {
if (game.executingRollback()) {
return;
return false;
}
//20091005 - 500.4/703.4n
game.emptyManaPools();
@ -155,7 +164,7 @@ public class Turn implements Serializable {
}
}
}
return false;
}
public void resumePlay(Game game, boolean wasPaused) {
@ -327,4 +336,23 @@ public class Turn implements Serializable {
return sb.toString();
}
private void logStartOfTurn(Game game, Player player) {
StringBuilder sb = new StringBuilder("Turn ").append(game.getState().getTurnNum()).append(" ");
sb.append(player.getLogName());
sb.append(" (");
int delimiter = game.getPlayers().size() - 1;
for (Player gamePlayer : game.getPlayers().values()) {
sb.append(gamePlayer.getLife());
int poison = gamePlayer.getCounters().getCount(CounterType.POISON);
if (poison > 0) {
sb.append("[P:").append(poison).append("]");
}
if (delimiter > 0) {
sb.append(" - ");
delimiter--;
}
}
sb.append(")");
game.fireStatusEvent(sb.toString(), true);
}
}

View file

@ -1,31 +1,30 @@
/*
* 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.
*/
* 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.players;
import java.io.Serializable;
@ -63,7 +62,7 @@ public class ManaPool implements Serializable {
private boolean autoPayment; // auto payment from mana pool: true - mode is active
private boolean autoPaymentRestricted; // auto payment from mana pool: true - if auto Payment is on, it will only pay if one kind of mana is in the pool
private ManaType unlockedManaType; // type of mana that was selected to pay manually
private final Set<ManaType> doNotEmptyManaTypes = new HashSet<>();
public ManaPool(UUID playerId) {
@ -75,7 +74,7 @@ public class ManaPool implements Serializable {
public ManaPool(final ManaPool pool) {
this.playerId = pool.playerId;
for (ManaPoolItem item: pool.manaItems) {
for (ManaPoolItem item : pool.manaItems) {
manaItems.add(item.copy());
}
this.autoPayment = pool.autoPayment;
@ -105,24 +104,24 @@ public class ManaPool implements Serializable {
}
/**
*
*
* @param manaType the mana type that should be paid
* @param ability
* @param filter
* @param game
* @return
* @return
*/
public boolean pay(ManaType manaType, Ability ability, Filter filter, Game game) {
if (!autoPayment && !manaType.equals(unlockedManaType)) {
// if manual payment and the needed mana type was not unlocked, nothing will be paid
return false;
}
if (autoPayment && autoPaymentRestricted && !wasManaAddedBeyondStock() && !manaType.equals(unlockedManaType)) {
if (autoPayment && autoPaymentRestricted && !wasManaAddedBeyondStock() && !manaType.equals(unlockedManaType)) {
// if automatic restricted payment and there is laready mana in the pool
// and the needed mana type was not unlocked, nothing will be paid
return false;
}
if (getConditional(manaType, ability, filter, game) > 0) {
removeConditional(manaType, ability, game);
lockManaType(); // pay only one mana if mana payment is set to manually
@ -134,7 +133,7 @@ public class ManaPool implements Serializable {
if (!filter.match(sourceObject, game)) {
continue;
}
}
}
if (!manaType.equals(unlockedManaType) && autoPayment && autoPaymentRestricted && mana.count() == mana.getStock()) {
// no mana added beyond the stock so don't auto pay this
continue;
@ -202,7 +201,7 @@ public class ManaPool implements Serializable {
public void clearEmptyManaPoolRules() {
doNotEmptyManaTypes.clear();
}
public void addDoNotEmptyManaType(ManaType manaType) {
doNotEmptyManaTypes.add(manaType);
}
@ -217,7 +216,7 @@ public class ManaPool implements Serializable {
if (!doNotEmptyManaTypes.contains(manaType)) {
if (item.get(manaType) > 0) {
if (!item.getDuration().equals(Duration.EndOfTurn) || game.getPhase().getType().equals(TurnPhase.END)) {
if (game.replaceEvent(new GameEvent(GameEvent.EventType.EMPTY_MANA_POOL, playerId, null, playerId))) {
if (game.replaceEvent(new GameEvent(GameEvent.EventType.EMPTY_MANA_POOL, playerId, null, playerId))) {
int amount = item.get(manaType);
item.clear(manaType);
item.add(ManaType.COLORLESS, amount);
@ -230,7 +229,7 @@ public class ManaPool implements Serializable {
if (conditionalItem != null) {
if (conditionalItem.get(manaType) > 0) {
if (!item.getDuration().equals(Duration.EndOfTurn) || game.getPhase().getType().equals(TurnPhase.END)) {
if (game.replaceEvent(new GameEvent(GameEvent.EventType.EMPTY_MANA_POOL, playerId, null, playerId))) {
if (game.replaceEvent(new GameEvent(GameEvent.EventType.EMPTY_MANA_POOL, playerId, null, playerId))) {
int amount = conditionalItem.get(manaType);
conditionalItem.clear(manaType);
conditionalItem.add(ManaType.COLORLESS, amount);
@ -246,8 +245,8 @@ public class ManaPool implements Serializable {
if (item.count() == 0) {
it.remove();
}
}
return total;
}
return total;
}
private int payX(Ability ability, Game game) {
@ -261,8 +260,7 @@ public class ManaPool implements Serializable {
total += item.count();
it.remove();
}
}
else {
} else {
total += item.count();
it.remove();
}
@ -272,10 +270,11 @@ public class ManaPool implements Serializable {
/**
* remove all mana from pool that applies and that matches filter
*
* @param ability
* @param game
* @param filter
* @return
* @return
*/
public int payX(Ability ability, Game game, FilterMana filter) {
if (filter == null) {
@ -297,8 +296,7 @@ public class ManaPool implements Serializable {
}
}
}
}
else {
} else {
if (filter.isBlack()) {
total += item.getBlack();
item.removeBlack();
@ -333,7 +331,7 @@ public class ManaPool implements Serializable {
public Mana getMana() {
Mana m = new Mana();
for (ManaPoolItem item: manaItems) {
for (ManaPoolItem item : manaItems) {
m.add(item.getMana());
}
return m;
@ -375,12 +373,12 @@ public class ManaPool implements Serializable {
public void addMana(Mana manaToAdd, Game game, Ability source) {
addMana(manaToAdd, game, source, false);
}
public void addMana(Mana manaToAdd, Game game, Ability source, boolean emptyOnTurnsEnd) {
Mana mana = manaToAdd.copy();
if (!game.replaceEvent(new ManaEvent(EventType.ADD_MANA, source.getId(), source.getSourceId(), source.getControllerId(), mana))) {
if (!game.replaceEvent(new ManaEvent(EventType.ADD_MANA, source.getId(), source.getSourceId(), playerId, mana))) {
if (mana instanceof ConditionalMana) {
ManaPoolItem item = new ManaPoolItem((ConditionalMana)mana, source.getSourceId(), source.getOriginalId());
ManaPoolItem item = new ManaPoolItem((ConditionalMana) mana, source.getSourceId(), source.getOriginalId());
if (emptyOnTurnsEnd) {
item.setDuration(Duration.EndOfTurn);
}
@ -389,18 +387,18 @@ public class ManaPool implements Serializable {
ManaPoolItem item = new ManaPoolItem(mana.getRed(), mana.getGreen(), mana.getBlue(), mana.getWhite(), mana.getBlack(), mana.getColorless(), source.getSourceId(), source.getOriginalId(), mana.getFlag());
if (emptyOnTurnsEnd) {
item.setDuration(Duration.EndOfTurn);
}
}
this.manaItems.add(item);
}
GameEvent event = GameEvent.getEvent(GameEvent.EventType.MANA_ADDED, source.getId(), source.getSourceId(), source.getControllerId());
event.setData(mana.toString());
game.fireEvent(event);
ManaEvent manaEvent = new ManaEvent(EventType.MANA_ADDED, source.getId(), source.getSourceId(), playerId, mana);
manaEvent.setData(mana.toString());
game.fireEvent(manaEvent);
}
}
public List<ConditionalMana> getConditionalMana() {
List<ConditionalMana> conditionalMana = new ArrayList<>();
for (ManaPoolItem item: manaItems) {
for (ManaPoolItem item : manaItems) {
if (item.isConditional()) {
conditionalMana.add(item.getConditionalMana());
}
@ -410,7 +408,7 @@ public class ManaPool implements Serializable {
public int count() {
int x = 0;
for (ManaPoolItem item: manaItems) {
for (ManaPoolItem item : manaItems) {
x += item.count();
}
return x;
@ -465,7 +463,7 @@ public class ManaPool implements Serializable {
mana.setStock(mana.count());
}
}
private boolean wasManaAddedBeyondStock() {
for (ManaPoolItem mana : manaItems) {
if (mana.getStock() < mana.count()) {

View file

@ -39,6 +39,7 @@ public class GameLog {
static final String LOG_COLOR_PLAYER = "#20B2AA"; // LightSeaGreen
static final String LOG_COLOR_PLAYER_REQUEST = "#D2691E"; // Chocolate
static final String LOG_COLOR_PLAYER_CONFIRM = "#D2691E"; // Chocolate
// colors for more dark background
static final String LOG_COLOR_GREEN = "#90EE90"; // LightGreen
static final String LOG_COLOR_RED = "#FF6347"; // Tomato
static final String LOG_COLOR_BLUE = "#87CEFA"; // LightSkyBlue
@ -46,6 +47,14 @@ public class GameLog {
static final String LOG_COLOR_WHITE = "#F0E68C"; // Khaki
static final String LOG_COLOR_MULTI = "#DAA520"; // GoldenRod
static final String LOG_COLOR_COLORLESS = "#B0C4DE"; // LightSteelBlue
// colors for tooltip (light background)
static final String LOG_TT_COLOR_RED = "Red"; // Tomato
static final String LOG_TT_COLOR_GREEN = "Green"; // LightGreen
static final String LOG_TT_COLOR_BLUE = "Blue";
static final String LOG_TT_COLOR_BLACK = "Black";
static final String LOG_TT_COLOR_WHITE = "#CCDB00";
static final String LOG_TT_COLOR_MULTI = "#FFAC40";
static final String LOG_TT_COLOR_COLORLESS = "#94A4BA";
static final String LOG_COLOR_NEUTRAL = "#F0F8FF"; // AliceBlue
public static String replaceNameByColoredName(MageObject mageObject, String text) {
@ -60,6 +69,10 @@ public class GameLog {
return "<font color=\'" + getColorName(mageObject.getColor(null)) + "\'>" + mageObject.getName() + " [" + mageObject.getId().toString().substring(0, 3) + "]</font>";
}
public static String getColoredObjectIdNameForTooltip(MageObject mageObject) {
return "<font color=\'" + getTooltipColorName(mageObject.getColor(null)) + "\'>" + mageObject.getName() + " [" + mageObject.getId().toString().substring(0, 3) + "]</font>";
}
public static String getNeutralColoredText(String text) {
return "<font color=\'" + LOG_COLOR_NEUTRAL + "\'>" + text + "</font>";
}
@ -97,4 +110,22 @@ public class GameLog {
return LOG_COLOR_BLACK;
}
}
private static String getTooltipColorName(ObjectColor objectColor) {
if (objectColor.isMulticolored()) {
return LOG_TT_COLOR_MULTI;
} else if (objectColor.isColorless()) {
return LOG_TT_COLOR_COLORLESS;
} else if (objectColor.isRed()) {
return LOG_TT_COLOR_RED;
} else if (objectColor.isGreen()) {
return LOG_TT_COLOR_GREEN;
} else if (objectColor.isBlue()) {
return LOG_TT_COLOR_BLUE;
} else if (objectColor.isWhite()) {
return LOG_TT_COLOR_WHITE;
} else {
return LOG_TT_COLOR_BLACK;
}
}
}

View file

@ -7,19 +7,18 @@ There are public servers where you can play XMage against other players. You can
You can visit the XMage forum [here](http://www.slightlymagic.net/forum/viewforum.php?f=70).
## Features
* Deck editor to build your desired decks.
* There is a simple computer AI opponent available.
* You can play either a two player duel or a multiplayer free-for-all game with up to 10 players.
* Commander format (also up to 10 players).
* Tiny Leaders duels.
* There are two tournament types supported, which can be played with up to 16 players:
* Elimination or swiss type handling
* Booster (also Cube) draft tournaments (4-16)
* Sealed (also from Cube) tournaments (2-16)
* Deck editor (load and save decks)
* Simple computer AI opponent
* Two player duel or a multiplayer free-for-all game with up to 10 players
* Supports special formats like Commander (up to 10 players), Cube, Tiny Leaders, Super Standard, Historic Standard
* There are two tournament types supported (elimination or swiss type handling), which can be played with up to 16 players:
* Booster (also Cube) draft tournaments (4-16)
* Sealed (also from Cube) tournaments (2-16)
## Installation
Download and install the [latest XMage release](http://XMage.de).
You will need to have the [Java Runtime Environment](http://java.com/en/) Version 7 or later.
You will need to have Version 7 or later of the [Java Runtime Environment](http://java.com/en/).
Look [here](http://www.slightlymagic.net/forum/viewtopic.php?f=70&t=13632) for more detailed instructions.
[Here](http://github.com/magefree/mage/wiki/Release-changes) you can find a log of the latest changes.
@ -32,4 +31,4 @@ If you are interested in developing XMage, here are some useful resources:
* [Developer Testing Tools](http://github.com/magefree/mage/wiki/Developer-Testing-Tools)
* [Double Faced Cards](http://github.com/magefree/mage/wiki/Double-Faced-Cards)
* [Card Requests](http://www.slightlymagic.net/forum/viewtopic.php?f=70&t=4554)
* [Tournament Relevant Card Requests](http://www.slightlymagic.net/forum/viewtopic.php?f=70&t=14062)
* [Tournament Relevant Card Requests](http://www.slightlymagic.net/forum/viewtopic.php?f=70&t=14062)