mirror of
https://github.com/correl/mage.git
synced 2024-12-26 11:09:27 +00:00
Merge origin/master
This commit is contained in:
commit
c85d71049a
33 changed files with 1027 additions and 638 deletions
|
@ -50,7 +50,15 @@ public class AudioManager {
|
|||
* AudioManager singleton.
|
||||
*/
|
||||
private static final AudioManager audioManager = new AudioManager();
|
||||
private final LinePool linePool = new LinePool();
|
||||
private LinePool linePool;
|
||||
|
||||
public AudioManager() {
|
||||
try {
|
||||
linePool = new LinePool();
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to initialize AudioManager. No sounds will be played.", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static AudioManager getManager() {
|
||||
return audioManager;
|
||||
|
@ -269,35 +277,37 @@ public class AudioManager {
|
|||
checkAndPlayClip(getManager().playerWon);
|
||||
}
|
||||
|
||||
private static void checkAndPlayClip(MageClip mageClip) {
|
||||
try {
|
||||
if (mageClip != null) {
|
||||
boolean playSound = false;
|
||||
switch (mageClip.getAudioGroup()) {
|
||||
private static boolean audioGroupEnabled(AudioGroup audioGroup) {
|
||||
switch (audioGroup) {
|
||||
case GameSounds:
|
||||
playSound = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SOUNDS_GAME_ON, "true").equals("true");
|
||||
break;
|
||||
return "true".equals(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SOUNDS_GAME_ON, "true"));
|
||||
case DraftSounds:
|
||||
playSound = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SOUNDS_DRAFT_ON, "true").equals("true");
|
||||
break;
|
||||
return "true".equals(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SOUNDS_DRAFT_ON, "true"));
|
||||
case SkipSounds:
|
||||
playSound = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SOUNDS_SKIP_BUTTONS_ON, "true").equals("true");
|
||||
break;
|
||||
return "true".equals(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SOUNDS_SKIP_BUTTONS_ON, "true"));
|
||||
case OtherSounds:
|
||||
playSound = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SOUNDS_OTHER_ON, "true").equals("true");
|
||||
return "true".equals(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SOUNDS_OTHER_ON, "true"));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (playSound) {
|
||||
private static void checkAndPlayClip(MageClip mageClip) {
|
||||
try {
|
||||
if (mageClip == null || mageClip.getBuffer() == null) {
|
||||
return;
|
||||
}
|
||||
if (audioGroupEnabled(mageClip.getAudioGroup())) {
|
||||
audioManager.play(mageClip);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Logger.getLogger(AudioManager.class).fatal("Error while playing sound clip.", e);
|
||||
log.warn("Error while playing sound clip.", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void play(final MageClip mageClip) {
|
||||
if (linePool != null) {
|
||||
linePool.playSound(mageClip);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package mage.client.util.audio;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
@ -9,9 +11,7 @@ import java.util.TimerTask;
|
|||
import javax.sound.sampled.AudioFormat;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
import javax.sound.sampled.DataLine;
|
||||
import javax.sound.sampled.LineEvent;
|
||||
import javax.sound.sampled.LineEvent.Type;
|
||||
import javax.sound.sampled.LineListener;
|
||||
import javax.sound.sampled.LineUnavailableException;
|
||||
import javax.sound.sampled.Mixer;
|
||||
import javax.sound.sampled.SourceDataLine;
|
||||
|
@ -25,11 +25,11 @@ public class LinePool {
|
|||
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
private static final int LINE_CLEANUP_INTERVAL = 30000;
|
||||
AudioFormat format;
|
||||
Set<SourceDataLine> freeLines = new HashSet<>();
|
||||
Set<SourceDataLine> activeLines = new HashSet<>();
|
||||
Set<SourceDataLine> busyLines = new HashSet<>();
|
||||
LinkedList<MageClip> queue = new LinkedList<>();
|
||||
|
||||
private final Queue<SourceDataLine> freeLines = new ArrayDeque<>();
|
||||
private final Queue<SourceDataLine> activeLines = new ArrayDeque<>();
|
||||
private final Set<SourceDataLine> busyLines = new HashSet<>();
|
||||
private final LinkedList<MageClip> queue = new LinkedList<>();
|
||||
|
||||
/*
|
||||
* Initially all the lines are in the freeLines pool. When a sound plays, one line is being selected randomly from
|
||||
|
@ -47,7 +47,6 @@ public class LinePool {
|
|||
}
|
||||
|
||||
public LinePool(AudioFormat audioFormat, int size, int alwaysActive) {
|
||||
format = audioFormat;
|
||||
this.alwaysActive = alwaysActive;
|
||||
mixer = AudioSystem.getMixer(null);
|
||||
DataLine.Info lineInfo = new DataLine.Info(SourceDataLine.class, audioFormat);
|
||||
|
@ -56,11 +55,10 @@ public class LinePool {
|
|||
SourceDataLine line = (SourceDataLine) mixer.getLine(lineInfo);
|
||||
freeLines.add(line);
|
||||
} catch (LineUnavailableException e) {
|
||||
e.printStackTrace();
|
||||
log.warn("Failed to get line from mixer", e);
|
||||
}
|
||||
}
|
||||
new Timer("Line cleanup", true).scheduleAtFixedRate(new TimerTask() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (LinePool.this) {
|
||||
|
@ -75,38 +73,46 @@ public class LinePool {
|
|||
}, LINE_CLEANUP_INTERVAL, LINE_CLEANUP_INTERVAL);
|
||||
}
|
||||
|
||||
private synchronized SourceDataLine borrowLine() {
|
||||
SourceDataLine line = activeLines.poll();
|
||||
if (line == null) {
|
||||
line = freeLines.poll();
|
||||
}
|
||||
if (line != null) {
|
||||
busyLines.add(line);
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
private synchronized void returnLine(SourceDataLine line) {
|
||||
busyLines.remove(line);
|
||||
if (activeLines.size() < alwaysActive) {
|
||||
activeLines.add(line);
|
||||
} else {
|
||||
freeLines.add(line);
|
||||
}
|
||||
}
|
||||
|
||||
public void playSound(final MageClip mageClip) {
|
||||
final SourceDataLine line;
|
||||
synchronized (LinePool.this) {
|
||||
log.debug("Playing {}", mageClip.getFilename());
|
||||
logLineStats();
|
||||
if (activeLines.size() > 0) {
|
||||
line = activeLines.iterator().next();
|
||||
} else if (freeLines.size() > 0) {
|
||||
line = freeLines.iterator().next();
|
||||
} else {
|
||||
line = borrowLine();
|
||||
if (line == null) {
|
||||
// no lines available, queue sound to play it when a line is available
|
||||
queue.add(mageClip);
|
||||
log.debug("Sound {} queued.", mageClip.getFilename());
|
||||
return;
|
||||
}
|
||||
freeLines.remove(line);
|
||||
activeLines.remove(line);
|
||||
busyLines.add(line);
|
||||
logLineStats();
|
||||
}
|
||||
ThreadUtils.threadPool.submit(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
ThreadUtils.threadPool.submit(() -> {
|
||||
synchronized (LinePool.this) {
|
||||
try {
|
||||
if (!line.isOpen()) {
|
||||
line.open();
|
||||
line.addLineListener(new LineListener() {
|
||||
|
||||
@Override
|
||||
public void update(LineEvent event) {
|
||||
line.addLineListener(event -> {
|
||||
log.debug("Event: {}", event);
|
||||
if (event.getType() != Type.STOP) {
|
||||
return;
|
||||
|
@ -114,26 +120,20 @@ public class LinePool {
|
|||
synchronized (LinePool.this) {
|
||||
log.debug("Before stop on line {}", line);
|
||||
logLineStats();
|
||||
busyLines.remove(line);
|
||||
if (activeLines.size() < LinePool.this.alwaysActive) {
|
||||
activeLines.add(line);
|
||||
} else {
|
||||
freeLines.add(line);
|
||||
}
|
||||
returnLine(line);
|
||||
log.debug("After stop on line {}", line);
|
||||
logLineStats();
|
||||
if (queue.size() > 0) {
|
||||
MageClip queuedSound = queue.poll();
|
||||
if (queuedSound != null) {
|
||||
log.debug("Playing queued sound {}", queuedSound);
|
||||
playSound(queuedSound);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
line.start();
|
||||
} catch (LineUnavailableException e) {
|
||||
e.printStackTrace();
|
||||
log.warn("Failed to open line", e);
|
||||
}
|
||||
}
|
||||
byte[] buffer = mageClip.getBuffer();
|
||||
|
@ -142,7 +142,6 @@ public class LinePool {
|
|||
line.drain();
|
||||
line.stop();
|
||||
log.debug("Line completed: {}", line);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -28,8 +28,13 @@
|
|||
|
||||
package mage.client.util.audio;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import javax.sound.sampled.AudioInputStream;
|
||||
import javax.sound.sampled.AudioSystem;
|
||||
|
@ -40,30 +45,36 @@ import javax.sound.sampled.UnsupportedAudioFileException;
|
|||
* @author LevelX2
|
||||
*/
|
||||
public class MageClip {
|
||||
private static final Logger log = Logger.getLogger(MageClip.class);
|
||||
|
||||
private final AudioGroup audioGroup;
|
||||
private String filename;
|
||||
private byte buf[];
|
||||
private final String filename;
|
||||
private final byte buf[];
|
||||
|
||||
public MageClip(String filename, AudioGroup audioGroup) {
|
||||
this.filename = filename;
|
||||
this.audioGroup = audioGroup;
|
||||
loadStream();
|
||||
this.buf = loadStream();
|
||||
}
|
||||
|
||||
private void loadStream() {
|
||||
private byte[] loadStream() {
|
||||
File file = new File(filename);
|
||||
try {
|
||||
AudioInputStream soundIn = AudioSystem.getAudioInputStream(file);
|
||||
byte tmp[] = new byte[(int) file.length()];
|
||||
int read = 0;
|
||||
read = soundIn.read(tmp, 0, tmp.length);
|
||||
buf = new byte[read];
|
||||
System.arraycopy(tmp, 0, buf, 0, read); // truncate the buffer to the actual audio size
|
||||
} catch (UnsupportedAudioFileException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
|
||||
copy(soundIn, bytesOut);
|
||||
return bytesOut.toByteArray();
|
||||
} catch (UnsupportedAudioFileException | IOException e) {
|
||||
log.warn("Failed to read " + filename, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void copy(InputStream source, OutputStream sink) throws IOException {
|
||||
byte[] buf = new byte[1024];
|
||||
int n;
|
||||
while ((n = source.read(buf)) > 0) {
|
||||
sink.write(buf, 0, n);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,7 +82,7 @@ public class MageClip {
|
|||
return audioGroup;
|
||||
}
|
||||
|
||||
public byte[] getBuffer(){
|
||||
public byte[] getBuffer() {
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import mage.abilities.common.CanBeYourCommanderAbility;
|
||||
import mage.abilities.keyword.PartnerAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.ExpansionSet;
|
||||
import mage.cards.Sets;
|
||||
|
@ -105,9 +106,10 @@ public class Commander extends Constructed {
|
|||
@Override
|
||||
public boolean validate(Deck deck) {
|
||||
boolean valid = true;
|
||||
FilterMana colorIdentity = new FilterMana();
|
||||
|
||||
if (deck.getCards().size() != 99) {
|
||||
invalid.put("Deck", "Must contain 99 cards: has " + deck.getCards().size() + " cards");
|
||||
if (deck.getCards().size() + deck.getSideboard().size() != 100) {
|
||||
invalid.put("Deck", "Must contain 100 cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards");
|
||||
valid = false;
|
||||
}
|
||||
|
||||
|
@ -132,34 +134,48 @@ public class Commander extends Constructed {
|
|||
}
|
||||
}
|
||||
|
||||
if (deck.getSideboard().size() == 1) {
|
||||
Card commander = (Card) deck.getSideboard().toArray()[0];
|
||||
if (commander == null) {
|
||||
invalid.put("Commander", "Commander invalid ");
|
||||
return false;
|
||||
}
|
||||
if ((commander.getCardType().contains(CardType.CREATURE) && commander.getSupertype().contains("Legendary"))
|
||||
|| (commander.getCardType().contains(CardType.PLANESWALKER) && commander.getAbilities().contains(CanBeYourCommanderAbility.getInstance()))) {
|
||||
if (!bannedCommander.contains(commander.getName())) {
|
||||
FilterMana color = CardUtil.getColorIdentity(commander);
|
||||
for (Card card : deck.getCards()) {
|
||||
if (!cardHasValidColor(color, card)) {
|
||||
invalid.put(card.getName(), "Invalid color (" + commander.getName() + ")");
|
||||
if (deck.getSideboard().size() < 1 || deck.getSideboard().size() > 2) {
|
||||
invalid.put("Commander", "Sideboard must contain only the commander(s)");
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (Card commander : deck.getSideboard()) {
|
||||
if (bannedCommander.contains(commander.getName())) {
|
||||
invalid.put("Commander", "Commander banned (" + commander.getName() + ")");
|
||||
valid = false;
|
||||
}
|
||||
} else {
|
||||
if ((!commander.getCardType().contains(CardType.CREATURE) || !commander.getSupertype().contains("Legendary"))
|
||||
&& (!commander.getCardType().contains(CardType.PLANESWALKER) || !commander.getAbilities().contains(CanBeYourCommanderAbility.getInstance()))) {
|
||||
invalid.put("Commander", "Commander invalid (" + commander.getName() + ")");
|
||||
valid = false;
|
||||
}
|
||||
} else {
|
||||
invalid.put("Commander", "Sideboard must contain only the commander");
|
||||
if (deck.getSideboard().size() == 2 && !commander.getAbilities().contains(PartnerAbility.getInstance())) {
|
||||
invalid.put("Commander", "Commander without Partner (" + commander.getName() + ")");
|
||||
valid = false;
|
||||
}
|
||||
FilterMana commanderColor = CardUtil.getColorIdentity(commander);
|
||||
if (commanderColor.isWhite()) {
|
||||
colorIdentity.setWhite(true);
|
||||
}
|
||||
if (commanderColor.isBlue()) {
|
||||
colorIdentity.setBlue(true);
|
||||
}
|
||||
if (commanderColor.isBlack()) {
|
||||
colorIdentity.setBlack(true);
|
||||
}
|
||||
if (commanderColor.isRed()) {
|
||||
colorIdentity.setRed(true);
|
||||
}
|
||||
if (commanderColor.isGreen()) {
|
||||
colorIdentity.setGreen(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Card card : deck.getCards()) {
|
||||
if (!cardHasValidColor(colorIdentity, card)) {
|
||||
invalid.put(card.getName(), "Invalid color (" + colorIdentity.toString() + ")");
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (Card card : deck.getCards()) {
|
||||
if (!isSetAllowed(card.getExpansionSetCode())) {
|
||||
if (!legalSets(card)) {
|
||||
|
|
119
Mage.Sets/src/mage/cards/b/BruseTarlBoorishHerder.java
Normal file
119
Mage.Sets/src/mage/cards/b/BruseTarlBoorishHerder.java
Normal 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.cards.b;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
|
||||
import mage.abilities.keyword.DoubleStrikeAbility;
|
||||
import mage.abilities.keyword.LifelinkAbility;
|
||||
import mage.abilities.keyword.PartnerAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.target.common.TargetControlledCreaturePermanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author spjspj
|
||||
*/
|
||||
public class BruseTarlBoorishHerder extends CardImpl {
|
||||
|
||||
public BruseTarlBoorishHerder(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{W}");
|
||||
|
||||
this.supertype.add("Legendary");
|
||||
this.subtype.add("Human");
|
||||
this.subtype.add("Ally");
|
||||
this.power = new MageInt(3);
|
||||
this.toughness = new MageInt(3);
|
||||
|
||||
// Whenever Bruse Tarl, Boorish Herder enters the battlefield or attacks, target creature you control gains double strike and lifelink until end of turn.
|
||||
this.addAbility(new BruseTarlAbility());
|
||||
|
||||
// Partner
|
||||
this.addAbility(PartnerAbility.getInstance());
|
||||
}
|
||||
|
||||
public BruseTarlBoorishHerder(final BruseTarlBoorishHerder card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BruseTarlBoorishHerder copy() {
|
||||
return new BruseTarlBoorishHerder(this);
|
||||
}
|
||||
}
|
||||
|
||||
class BruseTarlAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("target creature you control");
|
||||
|
||||
public BruseTarlAbility() {
|
||||
super(Zone.BATTLEFIELD, new GainAbilityTargetEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn), false);
|
||||
addEffect(new GainAbilityTargetEffect(LifelinkAbility.getInstance(), Duration.EndOfTurn));
|
||||
this.addTarget(new TargetControlledCreaturePermanent(filter));
|
||||
}
|
||||
|
||||
public BruseTarlAbility(final BruseTarlAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BruseTarlAbility copy() {
|
||||
return new BruseTarlAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == EventType.ATTACKER_DECLARED || event.getType() == EventType.ENTERS_THE_BATTLEFIELD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (event.getType() == GameEvent.EventType.ATTACKER_DECLARED && event.getSourceId().equals(this.getSourceId())) {
|
||||
return true;
|
||||
}
|
||||
if (event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD && event.getTargetId().equals(this.getSourceId())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever {this} enters the battlefield or attacks, target creature you control gains double strike and lifelink until end of turn";
|
||||
}
|
||||
}
|
|
@ -27,6 +27,8 @@
|
|||
*/
|
||||
package mage.cards.c;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
|
@ -90,9 +92,25 @@ class CommandBeaconEffect extends OneShotEffect {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
Card commander = game.getCard(controller.getCommanderId());
|
||||
List<Card> commandersInCommandZone = new ArrayList<>(1);
|
||||
for (UUID commanderId : controller.getCommandersIds()) {
|
||||
Card commander = game.getCard(commanderId);
|
||||
if (commander != null && game.getState().getZone(commander.getId()) == Zone.COMMAND) {
|
||||
controller.moveCards(commander, Zone.HAND, source, game);
|
||||
commandersInCommandZone.add(commander);
|
||||
}
|
||||
}
|
||||
if (commandersInCommandZone.size() == 1) {
|
||||
controller.moveCards(commandersInCommandZone.get(0), Zone.HAND, source, game);
|
||||
}
|
||||
else if (commandersInCommandZone.size() == 2) {
|
||||
Card firstCommander = commandersInCommandZone.get(0);
|
||||
Card secondCommander = commandersInCommandZone.get(1);
|
||||
if (controller.chooseUse(Outcome.ReturnToHand, "Return which commander to hand?", null, firstCommander.getName(), secondCommander.getName(), source, game)) {
|
||||
controller.moveCards(firstCommander, Zone.HAND, source, game);
|
||||
}
|
||||
else {
|
||||
controller.moveCards(secondCommander, Zone.HAND, source, game);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
package mage.cards.c;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.CardImpl;
|
||||
|
@ -69,8 +68,6 @@ public class ConsignToDream extends CardImpl {
|
|||
|
||||
class ConsignToDreamEffect extends OneShotEffect {
|
||||
|
||||
boolean applied = false;
|
||||
|
||||
public ConsignToDreamEffect() {
|
||||
super(Outcome.ReturnToHand);
|
||||
this.staticText = "Return target permanent to its owner's hand. If that permanent is red or green, put it on top of its owner's library instead";
|
||||
|
@ -87,10 +84,10 @@ class ConsignToDreamEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
boolean applied = false;
|
||||
Permanent target = game.getPermanent(source.getFirstTarget());
|
||||
if (target != null) {
|
||||
if (target.getColor(game).contains(ObjectColor.RED)
|
||||
|| target.getColor(game).contains(ObjectColor.GREEN)) {
|
||||
if (target.getColor(game).isRed() || target.getColor(game).isGreen()) {
|
||||
applied = target.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true);
|
||||
} else {
|
||||
applied = target.moveToZone(Zone.HAND, source.getSourceId(), game, false);
|
||||
|
|
|
@ -127,12 +127,14 @@ class ConspiracyEffect extends ContinuousEffectImpl {
|
|||
}
|
||||
}
|
||||
// commander in command zone
|
||||
if (controller.getCommanderId() != null && game.getState().getZone(controller.getCommanderId()).equals(Zone.COMMAND)) {
|
||||
Card card = game.getCard(controller.getCommanderId());
|
||||
for (UUID commanderId : controller.getCommandersIds()) {
|
||||
if (game.getState().getZone(commanderId).equals(Zone.COMMAND)) {
|
||||
Card card = game.getCard(commanderId);
|
||||
if (card.getCardType().contains(CardType.CREATURE)) {
|
||||
setCreatureSubtype(card, choice, game);
|
||||
}
|
||||
}
|
||||
}
|
||||
// creature spells you control
|
||||
for (Iterator<StackObject> iterator = game.getStack().iterator(); iterator.hasNext();) {
|
||||
StackObject stackObject = iterator.next();
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
package mage.cards.c;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.effects.common.DoIfCostPaid;
|
||||
|
@ -89,7 +88,7 @@ class CrystalRodAbility extends TriggeredAbilityImpl {
|
|||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Spell spell = game.getStack().getSpell(event.getTargetId());
|
||||
return spell != null && spell.getColor(game).contains(ObjectColor.BLUE);
|
||||
return spell != null && spell.getColor(game).isBlue();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -29,7 +29,6 @@ package mage.cards.f;
|
|||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
|
||||
|
@ -122,8 +121,7 @@ class FiendslayerPaladinEffect extends ContinuousRuleModifyingEffectImpl {
|
|||
Card targetCard = game.getCard(event.getTargetId());
|
||||
StackObject stackObject = (StackObject) game.getStack().getStackObject(event.getSourceId());
|
||||
if (targetCard != null && stackObject != null && targetCard.getId().equals(source.getSourceId())) {
|
||||
if (stackObject.getColor(game).contains(ObjectColor.BLACK)
|
||||
|| stackObject.getColor(game).contains(ObjectColor.RED)) {
|
||||
if (stackObject.getColor(game).isBlack() || stackObject.getColor(game).isRed()) {
|
||||
if (!stackObject.getControllerId().equals(source.getControllerId())
|
||||
&& stackObject.getCardType().contains(CardType.INSTANT)
|
||||
|| stackObject.getCardType().contains(CardType.SORCERY)) {
|
||||
|
|
131
Mage.Sets/src/mage/cards/g/GoblinSpymaster.java
Normal file
131
Mage.Sets/src/mage/cards/g/GoblinSpymaster.java
Normal file
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
* 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.cards.g;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.BeginningOfEndStepTriggeredAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.combat.AttacksIfAbleAllEffect;
|
||||
import mage.abilities.keyword.FirstStrikeAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.TargetController;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.filter.predicate.permanent.ControllerPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.token.Token;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author spjspj
|
||||
*/
|
||||
public class GoblinSpymaster extends CardImpl {
|
||||
|
||||
public GoblinSpymaster(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}");
|
||||
|
||||
this.subtype.add("Goblin");
|
||||
this.subtype.add("Rogue");
|
||||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(1);
|
||||
|
||||
// First strike
|
||||
this.addAbility(FirstStrikeAbility.getInstance());
|
||||
|
||||
// At the beginning of each opponent's end step, that player creates a 1/1 red Goblin creature token with "Creatures you control attack each combat if able."
|
||||
this.addAbility(new BeginningOfEndStepTriggeredAbility(Zone.BATTLEFIELD, new SpyMasterGoblinCreateTokenEffect(), TargetController.OPPONENT, null, false));
|
||||
}
|
||||
|
||||
public GoblinSpymaster(final GoblinSpymaster card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GoblinSpymaster copy() {
|
||||
return new GoblinSpymaster(this);
|
||||
}
|
||||
}
|
||||
|
||||
class SpyMasterGoblinCreateTokenEffect extends OneShotEffect {
|
||||
|
||||
public SpyMasterGoblinCreateTokenEffect() {
|
||||
super(Outcome.Detriment);
|
||||
this.staticText = "that player creates a 1/1 red Goblin creature token with \"Creatures you control attack each combat if able.\"";
|
||||
}
|
||||
|
||||
public SpyMasterGoblinCreateTokenEffect(final SpyMasterGoblinCreateTokenEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpyMasterGoblinCreateTokenEffect copy() {
|
||||
return new SpyMasterGoblinCreateTokenEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(game.getActivePlayerId());
|
||||
|
||||
if (player != null) {
|
||||
Token token = new SpyMasterGoblinToken();
|
||||
token.putOntoBattlefield(1, game, source.getSourceId(), player.getId());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class SpyMasterGoblinToken extends Token {
|
||||
|
||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures you control");
|
||||
|
||||
static {
|
||||
filter.add(new ControllerPredicate(TargetController.YOU));
|
||||
}
|
||||
|
||||
SpyMasterGoblinToken() {
|
||||
super("Goblin", "1/1 red Goblin creature token with \"Creatures you control attack each combat if able.\"");
|
||||
cardType.add(CardType.CREATURE);
|
||||
color.setRed(true);
|
||||
subtype.add("Goblin");
|
||||
power = new MageInt(1);
|
||||
toughness = new MageInt(1);
|
||||
|
||||
Effect effect = new AttacksIfAbleAllEffect(filter, Duration.WhileOnBattlefield, true);
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect));
|
||||
}
|
||||
}
|
|
@ -28,7 +28,6 @@
|
|||
package mage.cards.i;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.PreventAllDamageByAllPermanentsEffect;
|
||||
|
@ -95,8 +94,7 @@ class InquisitorsSnareEffect extends OneShotEffect {
|
|||
FilterCreaturePermanent filter = new FilterCreaturePermanent();
|
||||
filter.add(new PermanentIdPredicate(targetCreature.getId()));
|
||||
game.addEffect(new PreventAllDamageByAllPermanentsEffect(filter, Duration.EndOfTurn, false), source);
|
||||
if (targetCreature.getColor(game).contains(ObjectColor.BLACK)
|
||||
|| targetCreature.getColor(game).contains(ObjectColor.RED)) {
|
||||
if (targetCreature.getColor(game).isBlack() || targetCreature.getColor(game).isRed()) {
|
||||
return targetCreature.destroy(source.getSourceId(), game, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
package mage.cards.i;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.effects.common.DoIfCostPaid;
|
||||
|
@ -45,7 +44,6 @@ import mage.game.stack.Spell;
|
|||
/**
|
||||
*
|
||||
* @author KholdFuzion
|
||||
|
||||
*/
|
||||
public class IronStar extends CardImpl {
|
||||
|
||||
|
@ -89,7 +87,7 @@ class IronStarAbility extends TriggeredAbilityImpl {
|
|||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Spell spell = game.getStack().getSpell(event.getTargetId());
|
||||
return spell != null && spell.getColor(game).contains(ObjectColor.RED);
|
||||
return spell != null && spell.getColor(game).isRed();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -88,7 +88,7 @@ class IvoryCupAbility extends TriggeredAbilityImpl {
|
|||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Spell spell = game.getStack().getSpell(event.getTargetId());
|
||||
return spell != null && spell.getColor(game).contains(ObjectColor.WHITE);
|
||||
return spell != null && spell.getColor(game).isWhite();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -140,7 +140,7 @@ class KarnLiberatedEffect extends OneShotEffect {
|
|||
if (card.getOwnerId().equals(player.getId()) && !card.isCopy() // no copies
|
||||
&& !player.getSideboard().contains(card.getId())
|
||||
&& !cards.contains(card)) { // not the exiled cards
|
||||
if (card.getId().equals(player.getCommanderId())) {
|
||||
if (player.getCommandersIds().contains(card.getId())) {
|
||||
game.addCommander(new Commander(card));
|
||||
game.setZone(card.getId(), Zone.COMMAND);
|
||||
} else {
|
||||
|
|
|
@ -119,7 +119,7 @@ class OpalPalaceWatcher extends Watcher {
|
|||
for (UUID playerId : game.getPlayerList()) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if (player != null) {
|
||||
if (player.getCommanderId() != null && player.getCommanderId().equals(card.getId())) {
|
||||
if (player.getCommandersIds().contains(card.getId())) {
|
||||
commanderId.add(card.getId());
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -131,12 +131,14 @@ class TeferiMageOfZhalfirAddFlashEffect extends ContinuousEffectImpl {
|
|||
}
|
||||
}
|
||||
// commander in command zone
|
||||
if (controller.getCommanderId() != null && game.getState().getZone(controller.getCommanderId()).equals(Zone.COMMAND)) {
|
||||
Card card = game.getCard(controller.getCommanderId());
|
||||
for (UUID commanderId : controller.getCommandersIds()) {
|
||||
if (game.getState().getZone(commanderId).equals(Zone.COMMAND)) {
|
||||
Card card = game.getCard(commanderId);
|
||||
if (card.getCardType().contains(CardType.CREATURE)) {
|
||||
game.getState().addOtherAbility(card, FlashAbility.getInstance());
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
package mage.cards.t;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.effects.common.DoIfCostPaid;
|
||||
|
@ -89,7 +88,7 @@ class ThroneOfBoneAbility extends TriggeredAbilityImpl {
|
|||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Spell spell = game.getStack().getSpell(event.getTargetId());
|
||||
return spell != null && spell.getColor(game).contains(ObjectColor.BLACK);
|
||||
return spell != null && spell.getColor(game).isBlack();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
106
Mage.Sets/src/mage/cards/t/TreacherousTerrain.java
Normal file
106
Mage.Sets/src/mage/cards/t/TreacherousTerrain.java
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* 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.cards.t;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.keyword.BasicLandcyclingAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.filter.common.FilterLandPermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Styxo
|
||||
*/
|
||||
public class TreacherousTerrain extends CardImpl {
|
||||
|
||||
public TreacherousTerrain(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{6}{R}{G}");
|
||||
|
||||
// Treacherous Terrain deals damage to each opponent requal to the number of lands that player controls.
|
||||
this.getSpellAbility().addEffect(new TreacherousTerrainEffect());
|
||||
|
||||
// Basic landcycling {2}
|
||||
this.addAbility(new BasicLandcyclingAbility(new ManaCostsImpl("{2}")));
|
||||
}
|
||||
|
||||
public TreacherousTerrain(final TreacherousTerrain card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TreacherousTerrain copy() {
|
||||
return new TreacherousTerrain(this);
|
||||
}
|
||||
}
|
||||
|
||||
class TreacherousTerrainEffect extends OneShotEffect {
|
||||
|
||||
public TreacherousTerrainEffect() {
|
||||
super(Outcome.Damage);
|
||||
staticText = "{this} deals damage to each opponent equal to the number of lands that player controls";
|
||||
}
|
||||
|
||||
public TreacherousTerrainEffect(final TreacherousTerrainEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
List<Permanent> permanents = game.getBattlefield().getActivePermanents(new FilterLandPermanent(), source.getControllerId(), source.getSourceId(), game);
|
||||
for (UUID playerId : game.getOpponents(source.getControllerId())) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if (player != null) {
|
||||
int amount = 0;
|
||||
for (Permanent permanent : permanents) {
|
||||
if (permanent.getControllerId().equals(playerId)) {
|
||||
amount++;
|
||||
}
|
||||
}
|
||||
if (amount > 0) {
|
||||
player.damage(amount, source.getSourceId(), game, false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TreacherousTerrainEffect copy() {
|
||||
return new TreacherousTerrainEffect(this);
|
||||
}
|
||||
}
|
|
@ -28,7 +28,6 @@
|
|||
package mage.cards.w;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.effects.common.DoIfCostPaid;
|
||||
|
@ -89,7 +88,7 @@ class WoodenSphereAbility extends TriggeredAbilityImpl {
|
|||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Spell spell = game.getStack().getSpell(event.getTargetId());
|
||||
return spell != null && spell.getColor(game).contains(ObjectColor.GREEN);
|
||||
return spell != null && spell.getColor(game).isGreen();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -88,6 +88,7 @@ public class Commander2016 extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Breath of Fury", 121, Rarity.RARE, mage.cards.b.BreathOfFury.class));
|
||||
cards.add(new SetCardInfo("Bred for the Hunt", 186, Rarity.UNCOMMON, mage.cards.b.BredForTheHunt.class));
|
||||
cards.add(new SetCardInfo("Breya, Etherium Shaper", 29, Rarity.MYTHIC, mage.cards.b.BreyaEtheriumShaper.class));
|
||||
cards.add(new SetCardInfo("Bruse Tarl, Boorish Herder", 30, Rarity.MYTHIC, mage.cards.b.BruseTarlBoorishHerder.class));
|
||||
cards.add(new SetCardInfo("Brutal Hordechief", 108, Rarity.MYTHIC, mage.cards.b.BrutalHordechief.class));
|
||||
cards.add(new SetCardInfo("Burgeoning", 143, Rarity.RARE, mage.cards.b.Burgeoning.class));
|
||||
cards.add(new SetCardInfo("Buried Ruin", 284, Rarity.UNCOMMON, mage.cards.b.BuriedRuin.class));
|
||||
|
@ -169,6 +170,7 @@ public class Commander2016 extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Ghave, Guru of Spores", 200, Rarity.MYTHIC, mage.cards.g.GhaveGuruOfSpores.class));
|
||||
cards.add(new SetCardInfo("Ghostly Prison", 66, Rarity.UNCOMMON, mage.cards.g.GhostlyPrison.class));
|
||||
cards.add(new SetCardInfo("Glint-Eye Nephilim", 201, Rarity.RARE, mage.cards.g.GlintEyeNephilim.class));
|
||||
cards.add(new SetCardInfo("Goblin Spymaster", 19, Rarity.RARE, mage.cards.g.GoblinSpymaster.class));
|
||||
cards.add(new SetCardInfo("Godo, Bandit Warlord", 125, Rarity.RARE, mage.cards.g.GodoBanditWarlord.class));
|
||||
cards.add(new SetCardInfo("Golgari Rot Farm", 298, Rarity.UNCOMMON, mage.cards.g.GolgariRotFarm.class));
|
||||
cards.add(new SetCardInfo("Golgari Signet", 255, Rarity.COMMON, mage.cards.g.GolgariSignet.class));
|
||||
|
@ -338,6 +340,7 @@ public class Commander2016 extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Trading Post", 278, Rarity.RARE, mage.cards.t.TradingPost.class));
|
||||
cards.add(new SetCardInfo("Transguild Promenade", 334, Rarity.COMMON, mage.cards.t.TransguildPromenade.class));
|
||||
cards.add(new SetCardInfo("Trash for Treasure", 136, Rarity.RARE, mage.cards.t.TrashForTreasure.class));
|
||||
cards.add(new SetCardInfo("Treacherous Terrain", 47, Rarity.UNCOMMON, mage.cards.t.TreacherousTerrain.class));
|
||||
cards.add(new SetCardInfo("Treasure Cruise", 101, Rarity.COMMON, mage.cards.t.TreasureCruise.class));
|
||||
cards.add(new SetCardInfo("Trial // Error", 239, Rarity.UNCOMMON, mage.cards.t.TrialError.class));
|
||||
cards.add(new SetCardInfo("Trinket Mage", 102, Rarity.COMMON, mage.cards.t.TrinketMage.class));
|
||||
|
|
|
@ -1868,13 +1868,13 @@ public class TestPlayer implements Player {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setCommanderId(UUID commanderId) {
|
||||
computerPlayer.setCommanderId(commanderId);
|
||||
public void addCommanderId(UUID commanderId) {
|
||||
computerPlayer.addCommanderId(commanderId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getCommanderId() {
|
||||
return computerPlayer.getCommanderId();
|
||||
public Set<UUID> getCommandersIds() {
|
||||
return computerPlayer.getCommandersIds();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1083,12 +1083,12 @@ public class PlayerStub implements Player {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setCommanderId(UUID commanderId) {
|
||||
public void addCommanderId(UUID commanderId) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getCommanderId() {
|
||||
public Set<UUID> getCommandersIds() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,12 +31,9 @@ import java.io.Serializable;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import mage.util.Copyable;
|
||||
import mage.util.ThreadLocalStringBuilder;
|
||||
|
||||
public class ObjectColor implements Serializable, Copyable<ObjectColor>, Comparable<ObjectColor> {
|
||||
|
||||
private static final ThreadLocalStringBuilder threadLocalBuilder = new ThreadLocalStringBuilder(10);
|
||||
|
||||
public static final ObjectColor WHITE = new ObjectColor("W");
|
||||
public static final ObjectColor BLUE = new ObjectColor("U");
|
||||
public static final ObjectColor BLACK = new ObjectColor("B");
|
||||
|
@ -231,7 +228,7 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = threadLocalBuilder.get();
|
||||
StringBuilder sb = new StringBuilder(5);
|
||||
if (white) {
|
||||
sb.append("W");
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
package mage.abilities.condition.common;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.game.Game;
|
||||
|
@ -56,8 +57,12 @@ public class CommanderInPlayCondition implements Condition {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
Permanent commander = game.getPermanent(controller.getCommanderId());
|
||||
return commander != null && commander.getControllerId().equals(source.getControllerId());
|
||||
for (UUID commanderId : controller.getCommandersIds()) {
|
||||
Permanent commander = game.getPermanent(commanderId);
|
||||
if (commander != null && commander.getControllerId().equals(source.getControllerId())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
package mage.abilities.mana;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.Cost;
|
||||
|
@ -49,20 +50,16 @@ import mage.util.CardUtil;
|
|||
*/
|
||||
public class CommanderColorIdentityManaAbility extends ManaAbility {
|
||||
|
||||
private FilterMana commanderMana;
|
||||
|
||||
public CommanderColorIdentityManaAbility() {
|
||||
super(Zone.BATTLEFIELD, new CommanderIdentityManaEffect(), new TapSourceCost());
|
||||
}
|
||||
|
||||
public CommanderColorIdentityManaAbility(Cost cost) {
|
||||
super(Zone.BATTLEFIELD, new CommanderIdentityManaEffect(), cost);
|
||||
commanderMana = null;
|
||||
}
|
||||
|
||||
public CommanderColorIdentityManaAbility(final CommanderColorIdentityManaAbility ability) {
|
||||
super(ability);
|
||||
this.commanderMana = ability.commanderMana;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -75,15 +72,10 @@ public class CommanderColorIdentityManaAbility extends ManaAbility {
|
|||
if (netMana.isEmpty() && game != null) {
|
||||
Player controller = game.getPlayer(getControllerId());
|
||||
if (controller != null) {
|
||||
if (commanderMana == null) {
|
||||
Card commander = game.getCard(controller.getCommanderId());
|
||||
for (UUID commanderId : controller.getCommandersIds()) {
|
||||
Card commander = game.getCard(commanderId);
|
||||
if (commander != null) {
|
||||
commanderMana = CardUtil.getColorIdentity(commander);
|
||||
} else {
|
||||
// In formats other than Commander, Command Tower's ability produces no mana.
|
||||
commanderMana = new FilterMana();
|
||||
}
|
||||
}
|
||||
FilterMana commanderMana = CardUtil.getColorIdentity(commander);
|
||||
if (commanderMana.isBlack()) {
|
||||
netMana.add(new Mana(ColoredManaSymbol.B));
|
||||
}
|
||||
|
@ -101,6 +93,8 @@ public class CommanderColorIdentityManaAbility extends ManaAbility {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return netMana;
|
||||
}
|
||||
|
||||
|
@ -113,17 +107,13 @@ public class CommanderColorIdentityManaAbility extends ManaAbility {
|
|||
|
||||
class CommanderIdentityManaEffect extends ManaEffect {
|
||||
|
||||
private FilterMana commanderMana;
|
||||
|
||||
public CommanderIdentityManaEffect() {
|
||||
super();
|
||||
this.staticText = "Add to your mana pool one mana of any color in your commander's color identity";
|
||||
commanderMana = null;
|
||||
}
|
||||
|
||||
public CommanderIdentityManaEffect(final CommanderIdentityManaEffect effect) {
|
||||
super(effect);
|
||||
this.commanderMana = effect.commanderMana;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -135,31 +125,28 @@ class CommanderIdentityManaEffect extends ManaEffect {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
if (commanderMana == null) {
|
||||
Card commander = game.getCard(controller.getCommanderId());
|
||||
if (commander != null) {
|
||||
commanderMana = CardUtil.getColorIdentity(commander);
|
||||
} else {
|
||||
// In formats other than Commander, Command Tower's ability produces no mana.
|
||||
commanderMana = new FilterMana();
|
||||
}
|
||||
}
|
||||
Choice choice = new ChoiceImpl();
|
||||
choice.setMessage("Pick a mana color");
|
||||
for (UUID commanderId : controller.getCommandersIds()) {
|
||||
Card commander = game.getCard(commanderId);
|
||||
if (commander != null) {
|
||||
FilterMana commanderMana = CardUtil.getColorIdentity(commander);
|
||||
if (commanderMana.isWhite()) {
|
||||
choice.getChoices().add("White");
|
||||
}
|
||||
if (commanderMana.isBlue()) {
|
||||
choice.getChoices().add("Blue");
|
||||
}
|
||||
if (commanderMana.isBlack()) {
|
||||
choice.getChoices().add("Black");
|
||||
}
|
||||
if (commanderMana.isRed()) {
|
||||
choice.getChoices().add("Red");
|
||||
}
|
||||
if (commanderMana.isBlue()) {
|
||||
choice.getChoices().add("Blue");
|
||||
}
|
||||
if (commanderMana.isGreen()) {
|
||||
choice.getChoices().add("Green");
|
||||
}
|
||||
if (commanderMana.isWhite()) {
|
||||
choice.getChoices().add("White");
|
||||
}
|
||||
}
|
||||
if (choice.getChoices().size() > 0) {
|
||||
if (choice.getChoices().size() == 1) {
|
||||
|
|
|
@ -22,7 +22,7 @@ public class CommanderPredicate implements Predicate<Permanent> {
|
|||
Player owner = game.getPlayer(input.getOwnerId());
|
||||
return input.getCardType().contains(CardType.CREATURE)
|
||||
&& owner != null
|
||||
&& input.getId().equals(owner.getCommanderId());
|
||||
&& input.getId().equals(owner.getCommandersIds());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -76,16 +76,14 @@ public abstract class GameCommanderImpl extends GameImpl {
|
|||
for (UUID playerId : state.getPlayerList(startingPlayerId)) {
|
||||
Player player = getPlayer(playerId);
|
||||
if (player != null) {
|
||||
if (player.getSideboard().size() > 0) {
|
||||
Card commander = getCard((UUID) player.getSideboard().toArray()[0]);
|
||||
while (player.getSideboard().size() > 0) {
|
||||
Card commander = this.getCard(player.getSideboard().iterator().next());
|
||||
if (commander != null) {
|
||||
player.setCommanderId(commander.getId());
|
||||
player.addCommanderId(commander.getId());
|
||||
commander.moveToZone(Zone.COMMAND, null, this, true);
|
||||
commander.getAbilities().setControllerId(player.getId());
|
||||
ability.addEffect(new CommanderReplacementEffect(commander.getId(), alsoHand, alsoLibrary));
|
||||
ability.addEffect(new CommanderCostModification(commander.getId()));
|
||||
// Commander rule #4 was removed Jan. 18, 2016
|
||||
// ability.addEffect(new CommanderManaReplacementEffect(player.getId(), CardUtil.getColorIdentity(commander)));
|
||||
getState().setValue(commander.getId() + "_castCount", 0);
|
||||
CommanderInfoWatcher watcher = new CommanderInfoWatcher(commander.getId(), CHECK_COMMANDER_DAMAGE);
|
||||
getState().getWatchers().add(watcher);
|
||||
|
@ -93,7 +91,6 @@ public abstract class GameCommanderImpl extends GameImpl {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
this.getState().addAbility(ability, null);
|
||||
super.init(choosingPlayerId);
|
||||
|
@ -189,7 +186,8 @@ public abstract class GameCommanderImpl extends GameImpl {
|
|||
@Override
|
||||
protected boolean checkStateBasedActions() {
|
||||
for (Player player : getPlayers().values()) {
|
||||
CommanderInfoWatcher damageWatcher = (CommanderInfoWatcher) getState().getWatchers().get("CommanderCombatDamageWatcher", player.getCommanderId());
|
||||
for (UUID commanderId : player.getCommandersIds()) {
|
||||
CommanderInfoWatcher damageWatcher = (CommanderInfoWatcher) getState().getWatchers().get("CommanderCombatDamageWatcher", commanderId);
|
||||
if (damageWatcher == null) {
|
||||
continue;
|
||||
}
|
||||
|
@ -202,6 +200,7 @@ public abstract class GameCommanderImpl extends GameImpl {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.checkStateBasedActions();
|
||||
}
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ public abstract class GameTinyLeadersImpl extends GameImpl {
|
|||
Set<Card> cards = new HashSet<>();
|
||||
cards.add(commander);
|
||||
this.loadCards(cards, playerId);
|
||||
player.setCommanderId(commander.getId());
|
||||
player.addCommanderId(commander.getId());
|
||||
commander.moveToZone(Zone.COMMAND, null, this, true);
|
||||
ability.addEffect(new CommanderReplacementEffect(commander.getId(), alsoHand, alsoLibrary));
|
||||
ability.addEffect(new CommanderCostModification(commander.getId()));
|
||||
|
|
|
@ -161,9 +161,6 @@ public interface Permanent extends Card, Controllable {
|
|||
|
||||
String getValue(GameState state);
|
||||
|
||||
@Deprecated
|
||||
void addAbility(Ability ability);
|
||||
|
||||
@Deprecated
|
||||
void addAbility(Ability ability, Game game);
|
||||
|
||||
|
|
|
@ -265,12 +265,6 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
return abilities;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void addAbility(Ability ability) {
|
||||
throw new UnsupportedOperationException("Unsupported operation: use addAbility(Ability ability, Game game) instead");
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param ability
|
||||
|
|
|
@ -645,16 +645,16 @@ public interface Player extends MageItem, Copyable<Player> {
|
|||
/**
|
||||
* Set the commanderId of the player
|
||||
*
|
||||
* @param commanderId
|
||||
* @param commandersIds
|
||||
*/
|
||||
void setCommanderId(UUID commanderId);
|
||||
void addCommanderId(UUID commanderId);
|
||||
|
||||
/**
|
||||
* Get the commanderId of the player
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
UUID getCommanderId();
|
||||
Set<UUID> getCommandersIds();
|
||||
|
||||
/**
|
||||
* Moves cards from one zone to another
|
||||
|
|
|
@ -105,7 +105,12 @@ import mage.filter.common.FilterCreatureForCombat;
|
|||
import mage.filter.common.FilterCreatureForCombatBlock;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.permanent.PermanentIdPredicate;
|
||||
import mage.game.*;
|
||||
import mage.game.ExileZone;
|
||||
import mage.game.Game;
|
||||
import mage.game.Graveyard;
|
||||
import mage.game.Table;
|
||||
import mage.game.ZoneChangeInfo;
|
||||
import mage.game.ZonesHandler;
|
||||
import mage.game.combat.CombatGroup;
|
||||
import mage.game.command.CommandObject;
|
||||
import mage.game.events.DamagePlayerEvent;
|
||||
|
@ -153,7 +158,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
protected Cards sideboard;
|
||||
protected Cards hand;
|
||||
protected Graveyard graveyard;
|
||||
protected UUID commanderId;
|
||||
protected Set<UUID> commandersIds = new HashSet<>(0);
|
||||
protected Abilities<Ability> abilities;
|
||||
protected Counters counters;
|
||||
protected int landsPlayed;
|
||||
|
@ -273,7 +278,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
this.sideboard = player.sideboard.copy();
|
||||
this.hand = player.hand.copy();
|
||||
this.graveyard = player.graveyard.copy();
|
||||
this.commanderId = player.commanderId;
|
||||
this.commandersIds = player.commandersIds;
|
||||
this.abilities = player.abilities.copy();
|
||||
this.counters = player.counters.copy();
|
||||
|
||||
|
@ -359,7 +364,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
this.sideboard = player.getSideboard().copy();
|
||||
this.hand = player.getHand().copy();
|
||||
this.graveyard = player.getGraveyard().copy();
|
||||
this.commanderId = player.getCommanderId();
|
||||
this.commandersIds = player.getCommandersIds();
|
||||
this.abilities = player.getAbilities().copy();
|
||||
this.counters = player.getCounters().copy();
|
||||
|
||||
|
@ -3124,13 +3129,13 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setCommanderId(UUID commanderId) {
|
||||
this.commanderId = commanderId;
|
||||
public void addCommanderId(UUID commanderId) {
|
||||
this.commandersIds.add(commanderId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getCommanderId() {
|
||||
return this.commanderId;
|
||||
public Set<UUID> getCommandersIds() {
|
||||
return this.commandersIds;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in a new issue