From 96cbaa1e9989ebf942b1025ac569ca81a154de3a Mon Sep 17 00:00:00 2001 From: jeffwadsworth Date: Tue, 8 Jan 2019 04:16:11 -0600 Subject: [PATCH 01/10] - little refactor --- Mage.Sets/src/mage/cards/a/AngrathsMarauders.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Mage.Sets/src/mage/cards/a/AngrathsMarauders.java b/Mage.Sets/src/mage/cards/a/AngrathsMarauders.java index 9d79dd18af8..cd6f1f23663 100644 --- a/Mage.Sets/src/mage/cards/a/AngrathsMarauders.java +++ b/Mage.Sets/src/mage/cards/a/AngrathsMarauders.java @@ -15,6 +15,7 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; +import mage.util.CardUtil; /** * @@ -62,9 +63,9 @@ class AngrathsMaraudersEffect extends ReplacementEffectImpl { @Override public boolean checksEventType(GameEvent event, Game game) { - return event.getType().equals(EventType.DAMAGED_PLAYER) - || event.getType().equals(EventType.DAMAGED_CREATURE) - || event.getType().equals(EventType.DAMAGED_PLANESWALKER); + return event.getType().equals(EventType.DAMAGE_PLAYER) + || event.getType().equals(EventType.DAMAGE_CREATURE) + || event.getType().equals(EventType.DAMAGE_PLANESWALKER); } @Override @@ -74,7 +75,7 @@ class AngrathsMaraudersEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - event.setAmount(event.getAmount() * 2); + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), event.getAmount())); return false; } } From 503f383963ecf382a8b0ef81b512030b4f67079c Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Tue, 8 Jan 2019 09:26:14 +0400 Subject: [PATCH 02/10] Fixed NPE error on some tournaments finish; --- Mage/src/main/java/mage/game/Table.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mage/src/main/java/mage/game/Table.java b/Mage/src/main/java/mage/game/Table.java index 5b6f223021a..eba4df35c6b 100644 --- a/Mage/src/main/java/mage/game/Table.java +++ b/Mage/src/main/java/mage/game/Table.java @@ -298,8 +298,8 @@ public class Table implements Serializable { .setGameType(this.getGameType()) .setDeckType(this.getDeckType()) .setControllerName(this.getControllerName()) - .setStartTimeMs(this.getStartTime().getTime()) - .setEndTimeMs(this.getEndTime().getTime()) + .setStartTimeMs(this.getStartTime() != null ? this.getStartTime().getTime() : 0L) + .setEndTimeMs(this.getEndTime() != null ? this.getEndTime().getTime() : 0L) .build(); } } From 8a9619bf805e047b2c44236f032d7f7b613c6f83 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Tue, 8 Jan 2019 11:00:26 +0400 Subject: [PATCH 03/10] Fixed build time --- Mage/src/main/java/mage/util/JarVersion.java | 11 +++++++---- pom.xml | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Mage/src/main/java/mage/util/JarVersion.java b/Mage/src/main/java/mage/util/JarVersion.java index d88439c0a29..5c494ed13b7 100644 --- a/Mage/src/main/java/mage/util/JarVersion.java +++ b/Mage/src/main/java/mage/util/JarVersion.java @@ -1,12 +1,13 @@ package mage.util; +import org.apache.log4j.Logger; + import java.net.URL; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.time.temporal.TemporalAccessor; import java.util.jar.Attributes; import java.util.jar.Manifest; -import org.apache.log4j.Logger; /** * @author JayDi85 @@ -19,6 +20,7 @@ public class JarVersion { public static String getBuildTime(Class clazz) { // build time info inserted by maven on jar build phase (see root pom.xml) + String resultFormat = "uuuu-MM-dd HH:mm"; String className = clazz.getSimpleName() + ".class"; String classPath = clazz.getResource(className).toString(); @@ -38,10 +40,11 @@ public class JarVersion { Manifest manifest = new Manifest(new URL(manifestPath).openStream()); Attributes attr = manifest.getMainAttributes(); String buildTime = attr.getValue("Build-Time"); - DateTimeFormatter sourceFormatter = DateTimeFormatter.ofPattern("uuuuMMdd-HHmm").withZone(ZoneOffset.UTC); + // default maven format: yyyy-MM-dd'T'HH:mm:ss'Z' or see maven.build.timestamp.format in pom file + DateTimeFormatter sourceFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss'Z'").withZone(ZoneOffset.UTC); TemporalAccessor ta = sourceFormatter.parse(buildTime); - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm").withZone(ZoneOffset.UTC); - return formatter.format(ta); + DateTimeFormatter resultFormatter = DateTimeFormatter.ofPattern(resultFormat).withZone(ZoneOffset.UTC); + return resultFormatter.format(ta); } catch (Throwable e) { logger.error("Can't read build time in jar manifest for class " + clazz.getName() + " and path " + manifestPath, e); return JAR_BUILD_TIME_ERROR; diff --git a/pom.xml b/pom.xml index e4f8e8f1ee1..c29fc8e2e1e 100644 --- a/pom.xml +++ b/pom.xml @@ -90,6 +90,7 @@ 1.4.32 UTF-8 + yyyy-MM-dd'T'HH:mm:ss'Z' From 6c3d813b579256de0d308697f441dd7f5fe75845 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Tue, 8 Jan 2019 11:12:44 +0400 Subject: [PATCH 04/10] * Samurai of the Pale Curtain - fixed that it's not replaces graveyard with exile; --- Mage.Sets/src/mage/cards/s/SamuraiOfThePaleCurtain.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Mage.Sets/src/mage/cards/s/SamuraiOfThePaleCurtain.java b/Mage.Sets/src/mage/cards/s/SamuraiOfThePaleCurtain.java index f9a3c72c9f1..06b0e682567 100644 --- a/Mage.Sets/src/mage/cards/s/SamuraiOfThePaleCurtain.java +++ b/Mage.Sets/src/mage/cards/s/SamuraiOfThePaleCurtain.java @@ -1,5 +1,3 @@ - - package mage.cards.s; import mage.MageInt; @@ -34,6 +32,7 @@ public final class SamuraiOfThePaleCurtain extends CardImpl { // Bushido 1 (When this blocks or becomes blocked, it gets +1/+1 until end of turn.) this.addAbility(new BushidoAbility(1)); + // If a permanent would be put into a graveyard, exile it instead. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SamuraiOfThePaleCurtainEffect())); } @@ -71,7 +70,7 @@ class SamuraiOfThePaleCurtainEffect extends ReplacementEffectImpl { Permanent permanent = ((ZoneChangeEvent) event).getTarget(); if (permanent != null) { Player player = game.getPlayer(permanent.getControllerId()); - if (player == null) { + if (player != null) { return player.moveCards(permanent, Zone.EXILED, source, game); } } From 1d8fbb330466f3eb7e4e3ca76cf9dc6c710ead9a Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Tue, 8 Jan 2019 11:14:46 +0400 Subject: [PATCH 05/10] Fixed NPE error --- Mage.Sets/src/mage/cards/a/Abeyance.java | 4 +--- Mage.Sets/src/mage/cards/k/KayasWrath.java | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Mage.Sets/src/mage/cards/a/Abeyance.java b/Mage.Sets/src/mage/cards/a/Abeyance.java index d822f91986b..2d44f2abf17 100644 --- a/Mage.Sets/src/mage/cards/a/Abeyance.java +++ b/Mage.Sets/src/mage/cards/a/Abeyance.java @@ -1,4 +1,3 @@ - package mage.cards.a; import mage.MageObject; @@ -92,8 +91,7 @@ class AbeyanceEffect extends ContinuousRuleModifyingEffectImpl { } if (event.getType() == GameEvent.EventType.ACTIVATE_ABILITY) { Optional ability = game.getAbility(event.getTargetId(), event.getSourceId()); - return ability != null && ability.isPresent() - && !(ability.get() instanceof ActivatedManaAbilityImpl); + return ability.isPresent() && !(ability.get() instanceof ActivatedManaAbilityImpl); } return false; } diff --git a/Mage.Sets/src/mage/cards/k/KayasWrath.java b/Mage.Sets/src/mage/cards/k/KayasWrath.java index b42c1212d4d..e8b9386f218 100644 --- a/Mage.Sets/src/mage/cards/k/KayasWrath.java +++ b/Mage.Sets/src/mage/cards/k/KayasWrath.java @@ -60,7 +60,7 @@ class KayasWrathEffect extends OneShotEffect { source.getControllerId(), source.getSourceId(), game )) { boolean isMine = permanent != null && permanent.getControllerId().equals(source.getControllerId()); - if (permanent.destroy(source.getSourceId(), game, false) && isMine) { + if (isMine && permanent.destroy(source.getSourceId(), game, false)) { counter++; } } From b313ab3b7cc514746cc4301c8f7e7dea81a2cd6a Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Tue, 8 Jan 2019 13:50:19 +0400 Subject: [PATCH 06/10] Fixed missing watchers on game start, added error on missing watcher; --- .../src/main/java/mage/view/GameView.java | 21 ++--- Mage/src/main/java/mage/game/GameImpl.java | 80 ++++++++++--------- .../src/main/java/mage/watchers/Watchers.java | 4 +- 3 files changed, 50 insertions(+), 55 deletions(-) diff --git a/Mage.Common/src/main/java/mage/view/GameView.java b/Mage.Common/src/main/java/mage/view/GameView.java index ffc10011df4..f0466f6950a 100644 --- a/Mage.Common/src/main/java/mage/view/GameView.java +++ b/Mage.Common/src/main/java/mage/view/GameView.java @@ -1,14 +1,7 @@ - package mage.view; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; import mage.MageObject; import mage.abilities.costs.Cost; import mage.cards.Card; @@ -32,8 +25,10 @@ import mage.players.Player; import mage.watchers.common.CastSpellLastTurnWatcher; import org.apache.log4j.Logger; +import java.io.Serializable; +import java.util.*; + /** - * * @author BetaSteward_at_googlemail.com */ public class GameView implements Serializable { @@ -90,7 +85,7 @@ public class GameView implements Serializable { if (object != null) { if (object instanceof Permanent) { boolean controlled = ((Permanent) object).getControllerId().equals(createdForPlayerId); - stack.put(stackObject.getId(), new StackAbilityView(game, (StackAbility) stackObject, ((Permanent) object).getName(), new CardView(((Permanent) object), game, controlled, false, false))); + stack.put(stackObject.getId(), new StackAbilityView(game, (StackAbility) stackObject, object.getName(), new CardView(((Permanent) object), game, controlled, false, false))); } else { stack.put(stackObject.getId(), new StackAbilityView(game, (StackAbility) stackObject, card.getName(), new CardView(card, game, false, false, false))); } @@ -109,14 +104,14 @@ public class GameView implements Serializable { } else if (object instanceof Emblem) { CardView cardView = new CardView(new EmblemView((Emblem) object)); // Card sourceCard = (Card) ((Emblem) object).getSourceObject(); - ((StackAbility) stackObject).setName(((Emblem) object).getName()); + stackObject.setName(object.getName()); // ((StackAbility) stackObject).setExpansionSetCode(sourceCard.getExpansionSetCode()); stack.put(stackObject.getId(), new StackAbilityView(game, (StackAbility) stackObject, object.getName(), cardView)); checkPaid(stackObject.getId(), ((StackAbility) stackObject)); } else if (object instanceof Plane) { CardView cardView = new CardView(new PlaneView((Plane) object)); - ((StackAbility) stackObject).setName(((Plane) object).getName()); + stackObject.setName(object.getName()); stack.put(stackObject.getId(), new StackAbilityView(game, (StackAbility) stackObject, object.getName(), cardView)); checkPaid(stackObject.getId(), ((StackAbility) stackObject)); @@ -131,7 +126,7 @@ public class GameView implements Serializable { } else if (object instanceof StackAbility) { StackAbility stackAbility = ((StackAbility) object); stackAbility.newId(); - stack.put(stackObject.getId(), new CardView(((StackAbility) stackObject))); + stack.put(stackObject.getId(), new CardView(stackObject)); checkPaid(stackObject.getId(), ((StackAbility) stackObject)); } else { LOGGER.fatal("Object can't be cast to StackAbility: " + object.getName() + ' ' + object.toString() + ' ' + object.getClass().toString()); @@ -182,7 +177,7 @@ public class GameView implements Serializable { this.special = false; } - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); if (watcher != null) { spellsCastCurrentTurn = watcher.getAmountOfSpellsAllPlayersCastOnCurrentTurn(); } else { diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 3dafafacec8..7b17f8cdd11 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -1,9 +1,5 @@ package mage.game; -import java.io.IOException; -import java.io.Serializable; -import java.util.*; -import java.util.Map.Entry; import mage.MageException; import mage.MageObject; import mage.abilities.*; @@ -65,10 +61,14 @@ import mage.util.GameLog; import mage.util.MessageToClient; import mage.util.RandomUtil; import mage.util.functions.ApplyToPermanent; -import mage.watchers.Watchers; import mage.watchers.common.*; import org.apache.log4j.Logger; +import java.io.IOException; +import java.io.Serializable; +import java.util.*; +import java.util.Map.Entry; + public abstract class GameImpl implements Game, Serializable { private static final int ROLLBACK_TURNS_MAX = 4; @@ -150,6 +150,7 @@ public abstract class GameImpl implements Game, Serializable { this.state = new GameState(); this.startLife = startLife; this.executingRollback = false; + initGameDefaultWatchers(); } public GameImpl(final GameImpl game) { @@ -259,6 +260,7 @@ public abstract class GameImpl implements Game, Serializable { public void addPlayer(Player player, Deck deck) { player.useDeck(deck, this); state.addPlayer(player); + initPlayerDefaultWatchers(player.getId()); } @Override @@ -504,7 +506,7 @@ public abstract class GameImpl implements Game, Serializable { return Optional.empty(); } -// @Override + // @Override // public Zone getZone(UUID objectId) { // return state.getZone(objectId); // } @@ -532,7 +534,7 @@ public abstract class GameImpl implements Game, Serializable { } } -// /** + // /** // * Starts check if game is over or if playerId is given let the player // * concede. // * @@ -1012,20 +1014,6 @@ public abstract class GameImpl implements Game, Serializable { } getState().setChoosingPlayerId(null); state.resetWatchers(); // watcher objects from cards are reused during match so reset all card watchers already added - // add default watchers - for (UUID playerId : state.getPlayerList(startingPlayerId)) { - getState().addWatcher(new PlayerDamagedBySourceWatcher(playerId)); - getState().addWatcher(new BloodthirstWatcher(playerId)); - } - getState().addWatcher(new MorbidWatcher()); - getState().addWatcher(new CastSpellLastTurnWatcher()); - getState().addWatcher(new CastSpellYourLastTurnWatcher()); - getState().addWatcher(new PlayerLostLifeWatcher()); - getState().addWatcher(new PlayerLostLifeNonCombatWatcher()); - getState().addWatcher(new BlockedAttackerWatcher()); - getState().addWatcher(new DamageDoneWatcher()); - getState().addWatcher(new PlanarRollWatcher()); - getState().addWatcher(new PlayersAttackedThisTurnWatcher()); //20100716 - 103.5 for (UUID playerId : state.getPlayerList(startingPlayerId)) { @@ -1074,6 +1062,24 @@ public abstract class GameImpl implements Game, Serializable { } } + + private void initGameDefaultWatchers() { + getState().addWatcher(new MorbidWatcher()); + getState().addWatcher(new CastSpellLastTurnWatcher()); + getState().addWatcher(new CastSpellYourLastTurnWatcher()); + getState().addWatcher(new PlayerLostLifeWatcher()); + getState().addWatcher(new PlayerLostLifeNonCombatWatcher()); + getState().addWatcher(new BlockedAttackerWatcher()); + getState().addWatcher(new DamageDoneWatcher()); + getState().addWatcher(new PlanarRollWatcher()); + getState().addWatcher(new PlayersAttackedThisTurnWatcher()); + } + + private void initPlayerDefaultWatchers(UUID playerId) { + getState().addWatcher(new PlayerDamagedBySourceWatcher(playerId)); + getState().addWatcher(new BloodthirstWatcher(playerId)); + } + protected void sendStartMessage(Player choosingPlayer, Player startingPlayer) { StringBuilder message = new StringBuilder(); if (choosingPlayer != null) { @@ -1205,7 +1211,7 @@ public abstract class GameImpl implements Game, Serializable { fireInformEvent(new StringBuilder(player.getLogName()) .append(" mulligans") .append(deduction == 0 ? " for free and draws " : " down to ") - .append(Integer.toString(numCards - deduction)) + .append((numCards - deduction)) .append(numCards - deduction == 1 ? " card" : " cards").toString()); player.drawCards(numCards - deduction, this); } @@ -1542,10 +1548,9 @@ public abstract class GameImpl implements Game, Serializable { } /** - * * @param emblem * @param sourceObject - * @param toPlayerId controller and owner of the emblem + * @param toPlayerId controller and owner of the emblem */ @Override public void addEmblem(Emblem emblem, MageObject sourceObject, UUID toPlayerId) { @@ -1561,11 +1566,10 @@ public abstract class GameImpl implements Game, Serializable { } /** - * * @param plane * @param sourceObject - * @param toPlayerId controller and owner of the plane (may only be one per - * game..) + * @param toPlayerId controller and owner of the plane (may only be one per + * game..) * @return boolean - whether the plane was added successfully or not */ @Override @@ -1794,7 +1798,7 @@ public abstract class GameImpl implements Game, Serializable { break; } // triggered abilities that don't use the stack have to be executed first (e.g. Banisher Priest Return exiled creature - for (Iterator it = abilities.iterator(); it.hasNext();) { + for (Iterator it = abilities.iterator(); it.hasNext(); ) { TriggeredAbility triggeredAbility = it.next(); if (!triggeredAbility.isUsesStack()) { state.removeTriggeredAbility(triggeredAbility); @@ -1979,7 +1983,7 @@ public abstract class GameImpl implements Game, Serializable { if ((ability instanceof SpellAbility) && SpellAbilityType.BASE_ALTERNATE == ((SpellAbility) ability).getSpellAbilityType() && !ability.getTargets().isEmpty()) { - spellAbility = (SpellAbility) ability; + spellAbility = ability; break; } } @@ -2529,7 +2533,7 @@ public abstract class GameImpl implements Game, Serializable { } //20100423 - 800.4a Set toOutside = new HashSet<>(); - for (Iterator it = getBattlefield().getAllPermanents().iterator(); it.hasNext();) { + for (Iterator it = getBattlefield().getAllPermanents().iterator(); it.hasNext(); ) { Permanent perm = it.next(); if (perm.isOwnedBy(playerId)) { if (perm.getAttachedTo() != null) { @@ -2572,7 +2576,7 @@ public abstract class GameImpl implements Game, Serializable { player.moveCards(toOutside, Zone.OUTSIDE, null, this); // triggered abilities that don't use the stack have to be executed List abilities = state.getTriggered(player.getId()); - for (Iterator it = abilities.iterator(); it.hasNext();) { + for (Iterator it = abilities.iterator(); it.hasNext(); ) { TriggeredAbility triggeredAbility = it.next(); if (!triggeredAbility.isUsesStack()) { state.removeTriggeredAbility(triggeredAbility); @@ -2592,7 +2596,7 @@ public abstract class GameImpl implements Game, Serializable { // Remove cards from the player in all exile zones for (ExileZone exile : this.getExile().getExileZones()) { - for (Iterator it = exile.iterator(); it.hasNext();) { + for (Iterator it = exile.iterator(); it.hasNext(); ) { Card card = this.getCard(it.next()); if (card != null && card.isOwnedBy(playerId)) { it.remove(); @@ -2602,7 +2606,7 @@ public abstract class GameImpl implements Game, Serializable { //Remove all commander/emblems/plane the player controls boolean addPlaneAgain = false; - for (Iterator it = this.getState().getCommand().iterator(); it.hasNext();) { + for (Iterator it = this.getState().getCommand().iterator(); it.hasNext(); ) { CommandObject obj = it.next(); if (obj.isControlledBy(playerId)) { if (obj instanceof Emblem) { @@ -2738,7 +2742,7 @@ public abstract class GameImpl implements Game, Serializable { } if (!game.isSimulation()) { StringBuilder message = new StringBuilder(preventionSource.getLogName()).append(": Prevented "); - message.append(Integer.toString(result.getPreventedDamage())).append(" damage from ").append(damageSource.getLogName()); + message.append(result.getPreventedDamage()).append(" damage from ").append(damageSource.getLogName()); if (!targetName.isEmpty()) { message.append(" to ").append(targetName); } @@ -2773,7 +2777,7 @@ public abstract class GameImpl implements Game, Serializable { * Gets last known information about object in the zone. At the moment * doesn't take into account zone (it is expected that it doesn't really * matter, if not, then Map> should be used instead). - * + *

* Can return null. * * @param objectId @@ -3128,7 +3132,7 @@ public abstract class GameImpl implements Game, Serializable { public void saveRollBackGameState() { if (gameOptions.rollbackTurnsAllowed) { int toDelete = getTurnNum() - ROLLBACK_TURNS_MAX; - if (toDelete > 0 && gameStatesRollBack.containsKey(toDelete)) { + if (toDelete > 0) { gameStatesRollBack.remove(toDelete); } gameStatesRollBack.put(getTurnNum(), state.copy()); @@ -3180,9 +3184,7 @@ public abstract class GameImpl implements Game, Serializable { @Override public void setEnterWithCounters(UUID sourceId, Counters counters) { if (counters == null) { - if (enterWithCounters.containsKey(sourceId)) { - enterWithCounters.remove(sourceId); - } + enterWithCounters.remove(sourceId); return; } enterWithCounters.put(sourceId, counters); diff --git a/Mage/src/main/java/mage/watchers/Watchers.java b/Mage/src/main/java/mage/watchers/Watchers.java index 5cbb45fc068..7fba3a54deb 100644 --- a/Mage/src/main/java/mage/watchers/Watchers.java +++ b/Mage/src/main/java/mage/watchers/Watchers.java @@ -1,4 +1,3 @@ - package mage.watchers; import mage.game.Game; @@ -7,7 +6,6 @@ import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import java.util.HashMap; -import java.util.UUID; /** * @author BetaSteward_at_googlemail.com @@ -50,7 +48,7 @@ public class Watchers extends HashMap { if (containsKey(key)) { return super.get(key); } - logger.info(key + " not found in watchers"); + logger.error(key + " not found in watchers", new Throwable()); return null; } } From f1afac8ecd222e677927208219134c776b55f3b8 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Tue, 8 Jan 2019 15:07:55 +0400 Subject: [PATCH 07/10] [RNA] implemented Senate Guildmage --- .../src/mage/cards/s/SenateGuildmage.java | 49 +++++++++++++++++++ .../mage/sets/GuildsOfRavnicaGuildKits.java | 1 + 2 files changed, 50 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SenateGuildmage.java diff --git a/Mage.Sets/src/mage/cards/s/SenateGuildmage.java b/Mage.Sets/src/mage/cards/s/SenateGuildmage.java new file mode 100644 index 00000000000..d70f55d3dda --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SenateGuildmage.java @@ -0,0 +1,49 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class SenateGuildmage extends CardImpl { + + public SenateGuildmage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}"); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {W}, {T}: You gain 2 life. + Ability ability1 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainLifeEffect(2), new ManaCostsImpl<>("{W}")); + ability1.addCost(new TapSourceCost()); + this.addAbility(ability1); + + // {U}, {T}: Draw a card, then discard a card. + Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawDiscardControllerEffect(), new ManaCostsImpl("{U}")); + ability2.addCost(new TapSourceCost()); + this.addAbility(ability2); + } + + public SenateGuildmage(final SenateGuildmage card) { + super(card); + } + + @Override + public SenateGuildmage copy() { + return new SenateGuildmage(this); + } +} diff --git a/Mage.Sets/src/mage/sets/GuildsOfRavnicaGuildKits.java b/Mage.Sets/src/mage/sets/GuildsOfRavnicaGuildKits.java index b98dc623af4..56ffdb8976e 100644 --- a/Mage.Sets/src/mage/sets/GuildsOfRavnicaGuildKits.java +++ b/Mage.Sets/src/mage/sets/GuildsOfRavnicaGuildKits.java @@ -123,6 +123,7 @@ public final class GuildsOfRavnicaGuildKits extends ExpansionSet { cards.add(new SetCardInfo("Selesnya Guildmage", 119, Rarity.UNCOMMON, mage.cards.s.SelesnyaGuildmage.class)); cards.add(new SetCardInfo("Selesnya Sanctuary", 125, Rarity.COMMON, mage.cards.s.SelesnyaSanctuary.class)); cards.add(new SetCardInfo("Selesnya Signet", 123, Rarity.COMMON, mage.cards.s.SelesnyaSignet.class)); + cards.add(new SetCardInfo("Senate Guildmage", 204, Rarity.UNCOMMON, mage.cards.s.SenateGuildmage.class)); cards.add(new SetCardInfo("Shambling Shell", 70, Rarity.COMMON, mage.cards.s.ShamblingShell.class)); cards.add(new SetCardInfo("Shattering Spree", 34, Rarity.UNCOMMON, mage.cards.s.ShatteringSpree.class)); cards.add(new SetCardInfo("Sisters of Stone Death", 71, Rarity.RARE, mage.cards.s.SistersOfStoneDeath.class)); From f6d3298bb36b8c35573e74b37dbc29134d1a3802 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Tue, 8 Jan 2019 15:18:29 +0400 Subject: [PATCH 08/10] [RNA] implemented Cult Guildmage --- Mage.Sets/src/mage/cards/c/CultGuildmage.java | 54 +++++++++++++++++++ .../src/mage/sets/RavnicaAllegiance.java | 1 + 2 files changed, 55 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/c/CultGuildmage.java diff --git a/Mage.Sets/src/mage/cards/c/CultGuildmage.java b/Mage.Sets/src/mage/cards/c/CultGuildmage.java new file mode 100644 index 00000000000..7fa8895aaeb --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CultGuildmage.java @@ -0,0 +1,54 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.target.TargetPlayer; +import mage.target.common.TargetOpponentOrPlaneswalker; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class CultGuildmage extends CardImpl { + + public CultGuildmage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{R}"); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {3}{B}, {T}: Target player discards a card. Activate this ability only any time you could cast a sorcery. + Ability ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new DiscardTargetEffect(1), new ManaCostsImpl("{3}{B}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + + // {R}, {T}: Cult Guildmage deals 1 damage to target opponent or planeswalker. + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new ManaCostsImpl("{R}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetOpponentOrPlaneswalker()); + this.addAbility(ability); + } + + public CultGuildmage(final CultGuildmage card) { + super(card); + } + + @Override + public CultGuildmage copy() { + return new CultGuildmage(this); + } +} diff --git a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java index 1194aed485f..8afbd922135 100644 --- a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java +++ b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java @@ -54,6 +54,7 @@ public final class RavnicaAllegiance extends ExpansionSet { cards.add(new SetCardInfo("Combine Guildmage", 163, Rarity.UNCOMMON, mage.cards.c.CombineGuildmage.class)); cards.add(new SetCardInfo("Consecrate // Consume", 224, Rarity.UNCOMMON, mage.cards.c.ConsecrateConsume.class)); cards.add(new SetCardInfo("Cry of the Carnarium", 70, Rarity.UNCOMMON, mage.cards.c.CryOfTheCarnarium.class)); + cards.add(new SetCardInfo("Cult Guildmage", 164, Rarity.UNCOMMON, mage.cards.c.CultGuildmage.class)); cards.add(new SetCardInfo("Depose // Deploy", 225, Rarity.UNCOMMON, mage.cards.d.DeposeDeploy.class)); cards.add(new SetCardInfo("Deputy of Detention", 165, Rarity.RARE, mage.cards.d.DeputyOfDetention.class)); cards.add(new SetCardInfo("Domri, Chaos Bringer", 166, Rarity.MYTHIC, mage.cards.d.DomriChaosBringer.class)); From 925954fe8b2bb5f1166f65f8d097358d7f0a09cc Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Tue, 8 Jan 2019 15:35:09 +0400 Subject: [PATCH 09/10] [RNA] implemented Warrant // Warden --- Mage.Sets/src/mage/cards/w/WarrantWarden.java | 47 +++++++++++++++++++ .../src/mage/sets/RavnicaAllegiance.java | 1 + 2 files changed, 48 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/w/WarrantWarden.java diff --git a/Mage.Sets/src/mage/cards/w/WarrantWarden.java b/Mage.Sets/src/mage/cards/w/WarrantWarden.java new file mode 100644 index 00000000000..1e89140d735 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WarrantWarden.java @@ -0,0 +1,47 @@ +package mage.cards.w; + +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.PutOnLibraryTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardSetInfo; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.constants.SpellAbilityType; +import mage.game.permanent.token.custom.CreatureToken; +import mage.target.common.TargetAttackingOrBlockingCreature; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class WarrantWarden extends SplitCard { + + public WarrantWarden(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, new CardType[]{CardType.SORCERY}, "{W/U}{W/U}", "{3}{W}{U}", SpellAbilityType.SPLIT); + + // Warrant + // Put target attacking or blocking creature on top of its owner’s library. + this.getLeftHalfCard().getSpellAbility().addEffect(new PutOnLibraryTargetEffect(true)); + this.getLeftHalfCard().getSpellAbility().addTarget(new TargetAttackingOrBlockingCreature()); + + // Warden + // Create a 4/4 white and blue Sphinx creature token with flying and vigilance. + this.getRightHalfCard().getSpellAbility().addEffect(new CreateTokenEffect( + new CreatureToken(4, 4, "4/4 white and blue Sphinx creature token with flying and vigilance") + .withColor("WU") + .withAbility(FlyingAbility.getInstance()) + .withAbility(VigilanceAbility.getInstance()) + )); + } + + private WarrantWarden(final WarrantWarden card) { + super(card); + } + + @Override + public WarrantWarden copy() { + return new WarrantWarden(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java index 8afbd922135..b371ebbd644 100644 --- a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java +++ b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java @@ -138,6 +138,7 @@ public final class RavnicaAllegiance extends ExpansionSet { cards.add(new SetCardInfo("Tithe Taker", 27, Rarity.RARE, mage.cards.t.TitheTaker.class)); cards.add(new SetCardInfo("Trollbred Guardian", 148, Rarity.UNCOMMON, mage.cards.t.TrollbredGuardian.class)); cards.add(new SetCardInfo("Verity Circle", 58, Rarity.RARE, mage.cards.v.VerityCircle.class)); + cards.add(new SetCardInfo("Warrant // Warden", 230, Rarity.RARE, mage.cards.w.WarrantWarden.class)); cards.add(new SetCardInfo("Wilderness Reclamation", 149, Rarity.UNCOMMON, mage.cards.w.WildernessReclamation.class)); cards.add(new SetCardInfo("Zegana, Utopian Speaker", 214, Rarity.RARE, mage.cards.z.ZeganaUtopianSpeaker.class)); cards.add(new SetCardInfo("Zhur-Taa Goblin", 215, Rarity.UNCOMMON, mage.cards.z.ZhurTaaGoblin.class)); From a9fe41ac5e847d872870b14db6ec72be00897399 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Tue, 8 Jan 2019 15:50:38 +0400 Subject: [PATCH 10/10] [RNA] implemented Archway Angel --- Mage.Sets/src/mage/cards/a/ArchwayAngel.java | 53 +++++++++++++++++++ .../src/mage/sets/RavnicaAllegiance.java | 1 + 2 files changed, 54 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/a/ArchwayAngel.java diff --git a/Mage.Sets/src/mage/cards/a/ArchwayAngel.java b/Mage.Sets/src/mage/cards/a/ArchwayAngel.java new file mode 100644 index 00000000000..20da6285c53 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArchwayAngel.java @@ -0,0 +1,53 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class ArchwayAngel extends CardImpl { + + + private static final FilterPermanent filter = new FilterControlledPermanent("Gate you control"); + + static { + filter.add(new SubtypePredicate(SubType.GATE)); + } + + public ArchwayAngel(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{W}"); + this.subtype.add(SubType.ANGEL); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Archway Angel enters the battlefield, you gain 2 life for each Gate you control. + Ability ability = new EntersBattlefieldTriggeredAbility(new GainLifeEffect(new PermanentsOnBattlefieldCount(filter, 2))); + this.addAbility(ability); + } + + public ArchwayAngel(final ArchwayAngel card) { + super(card); + } + + @Override + public ArchwayAngel copy() { + return new ArchwayAngel(this); + } +} diff --git a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java index b371ebbd644..1e95bc9d8b1 100644 --- a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java +++ b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java @@ -36,6 +36,7 @@ public final class RavnicaAllegiance extends ExpansionSet { cards.add(new SetCardInfo("Aeromunculus", 152, Rarity.COMMON, mage.cards.a.Aeromunculus.class)); cards.add(new SetCardInfo("Amplifire", 92, Rarity.RARE, mage.cards.a.Amplifire.class)); cards.add(new SetCardInfo("Angelic Exaltation", 2, Rarity.UNCOMMON, mage.cards.a.AngelicExaltation.class)); + cards.add(new SetCardInfo("Archway Angel", 3, Rarity.UNCOMMON, mage.cards.a.ArchwayAngel.class)); cards.add(new SetCardInfo("Azorius Guildgate", 243, Rarity.COMMON, mage.cards.a.AzoriusGuildgate.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Azorius Guildgate", 244, Rarity.COMMON, mage.cards.a.AzoriusGuildgate.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Azorius Locket", 231, Rarity.COMMON, mage.cards.a.AzoriusLocket.class));