From 4dd196f3733ab1781504f094dde8c1a88808f71a Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 4 Feb 2018 12:27:08 +0100 Subject: [PATCH] * Fixed some problems with getting cards at random from collection that could cause loops. --- .../mage/player/ai/SimulatedPlayerMCTS.java | 8 ++-- Mage.Sets/src/mage/cards/c/CursedScroll.java | 5 +- .../src/mage/cards/d/DeployTheGatewatch.java | 22 ++++----- Mage.Sets/src/mage/cards/f/FriendlyFire.java | 16 ++++--- .../src/mage/cards/g/GontiLordOfLuxury.java | 6 +-- Mage.Sets/src/mage/cards/h/HeroesPodium.java | 47 +++++++------------ .../src/mage/cards/i/IgniteMemories.java | 13 +++-- .../src/mage/cards/m/MadcapExperiment.java | 10 +--- .../src/mage/cards/m/MagusOfTheScroll.java | 5 +- Mage.Sets/src/mage/cards/m/MakeAWish.java | 5 +- .../src/mage/cards/m/ManifoldInsights.java | 10 +--- .../src/mage/cards/o/OrcishLibrarian.java | 33 +++++++------ .../mage/cards/p/PlaneswalkersMischief.java | 3 ++ Mage.Sets/src/mage/cards/r/RiseFall.java | 6 +++ Mage.Sets/src/mage/cards/s/SingeMindOgre.java | 16 ++++--- Mage.Sets/src/mage/cards/t/TellingTime.java | 44 ++++++++--------- .../org/mage/test/player/RandomPlayer.java | 7 ++- .../common/LookLibraryControllerEffect.java | 13 +---- .../abilities/keyword/CascadeAbility.java | 11 +---- .../main/java/mage/players/PlayerImpl.java | 14 ++++-- 20 files changed, 134 insertions(+), 160 deletions(-) diff --git a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java index aeceb34f6d0..b1bb268a5ff 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java +++ b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java @@ -29,7 +29,6 @@ package mage.player.ai; import java.io.Serializable; import java.util.*; - import mage.abilities.Ability; import mage.abilities.ActivatedAbility; import mage.abilities.Mode; @@ -323,8 +322,11 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { return !target.isRequired(source); } Card card = cards.getRandom(game); - target.addTarget(card.getId(), source, game); - return true; + if (card != null) { + target.addTarget(card.getId(), source, game); + return true; + } + return false; } @Override diff --git a/Mage.Sets/src/mage/cards/c/CursedScroll.java b/Mage.Sets/src/mage/cards/c/CursedScroll.java index 16e46cb65ce..37e13a27ade 100644 --- a/Mage.Sets/src/mage/cards/c/CursedScroll.java +++ b/Mage.Sets/src/mage/cards/c/CursedScroll.java @@ -52,7 +52,7 @@ import mage.target.common.TargetCreatureOrPlayer; public class CursedScroll extends CardImpl { public CursedScroll(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{1}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); // {3}, {T}: Name a card. Reveal a card at random from your hand. If it's the named card, Cursed Scroll deals 2 damage to target creature or player. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new NameACardEffect(NameACardEffect.TypeOfName.ALL), new ManaCostsImpl("{3}")); @@ -92,6 +92,9 @@ class CursedScrollEffect extends OneShotEffect { if (!controller.getHand().isEmpty()) { Cards revealed = new CardsImpl(); Card card = controller.getHand().getRandom(game); + if (card == null) { + return false; + } revealed.add(card); controller.revealCards(sourceObject.getIdName(), revealed, game); if (card.getName().equals(cardName)) { diff --git a/Mage.Sets/src/mage/cards/d/DeployTheGatewatch.java b/Mage.Sets/src/mage/cards/d/DeployTheGatewatch.java index 2479e1461c2..e056e3cf2eb 100644 --- a/Mage.Sets/src/mage/cards/d/DeployTheGatewatch.java +++ b/Mage.Sets/src/mage/cards/d/DeployTheGatewatch.java @@ -47,7 +47,7 @@ import mage.target.TargetCard; public class DeployTheGatewatch extends CardImpl { public DeployTheGatewatch(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{W}{W}"); // Look at the top seven cards of your library. Put up to two planeswalker cards from among them onto the battlefield. // Put the rest on the bottom of your library in a random order. @@ -90,15 +90,15 @@ class DeployTheGatewatchEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } // Look at the top seven cards of your library. Cards cards = new CardsImpl(); boolean planeswalkerIncluded = false; for (int i = 0; i < 7; i++) { - Card card = player.getLibrary().removeFromTop(game); + Card card = controller.getLibrary().removeFromTop(game); if (card != null) { cards.add(card); if (filter.match(card, game)) { @@ -106,26 +106,20 @@ class DeployTheGatewatchEffect extends OneShotEffect { } } } - player.lookAtCards("Deploy the Gatewatch", cards, game); + controller.lookAtCards("Deploy the Gatewatch", cards, game); // Put up to two planeswalker cards from among them onto the battlefield. if (planeswalkerIncluded) { TargetCard target = new TargetCard(0, 2, Zone.LIBRARY, filter); - if (player.choose(Outcome.DrawCard, cards, target, game)) { + if (controller.choose(Outcome.DrawCard, cards, target, game)) { Cards pickedCards = new CardsImpl(target.getTargets()); cards.removeAll(pickedCards); - player.moveCards(pickedCards.getCards(game), Zone.BATTLEFIELD, source, game); + controller.moveCards(pickedCards.getCards(game), Zone.BATTLEFIELD, source, game); } } // Put the rest on the bottom of your library in a random order - while (!cards.isEmpty()) { - Card card = cards.getRandom(game); - if (card != null) { - cards.remove(card); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } - } + controller.putCardsOnBottomOfLibrary(cards, game, source, false); return true; } } diff --git a/Mage.Sets/src/mage/cards/f/FriendlyFire.java b/Mage.Sets/src/mage/cards/f/FriendlyFire.java index 53df09468a0..8176cc73fd2 100644 --- a/Mage.Sets/src/mage/cards/f/FriendlyFire.java +++ b/Mage.Sets/src/mage/cards/f/FriendlyFire.java @@ -46,7 +46,7 @@ import mage.target.common.TargetCreaturePermanent; public class FriendlyFire extends CardImpl { public FriendlyFire(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{R}"); // Target creature's controller reveals a card at random from his or her hand. Friendly Fire deals damage to that creature and that player equal to the revealed card's converted mana cost. this.getSpellAbility().addEffect(new FriendlyFireEffect()); @@ -92,12 +92,14 @@ class FriendlyFireEffect extends OneShotEffect { if (!controllerOfTargetCreature.getHand().isEmpty()) { Cards cards = new CardsImpl(); Card card = controllerOfTargetCreature.getHand().getRandom(game); - cards.add(card); - controllerOfTargetCreature.revealCards(sourceObject.getName(), cards, game); - int damage = card.getConvertedManaCost(); - targetCreature.damage(damage, source.getSourceId(), game, false, true); - controllerOfTargetCreature.damage(damage, source.getSourceId(), game, false, true); - return true; + if (card != null) { + cards.add(card); + controllerOfTargetCreature.revealCards(sourceObject.getName(), cards, game); + int damage = card.getConvertedManaCost(); + targetCreature.damage(damage, source.getSourceId(), game, false, true); + controllerOfTargetCreature.damage(damage, source.getSourceId(), game, false, true); + return true; + } } } } diff --git a/Mage.Sets/src/mage/cards/g/GontiLordOfLuxury.java b/Mage.Sets/src/mage/cards/g/GontiLordOfLuxury.java index 328db4a1803..1702679c4a2 100644 --- a/Mage.Sets/src/mage/cards/g/GontiLordOfLuxury.java +++ b/Mage.Sets/src/mage/cards/g/GontiLordOfLuxury.java @@ -142,11 +142,7 @@ class GontiLordOfLuxuryEffect extends OneShotEffect { } } // then put the rest on the bottom of that library in a random order - while (!topCards.isEmpty() && controller.isInGame()) { - Card libCard = topCards.getRandom(game); - topCards.remove(libCard); - controller.moveCardToLibraryWithInfo(libCard, source.getSourceId(), game, Zone.LIBRARY, false, false); - } + controller.putCardsOnBottomOfLibrary(topCards, game, source, false); return true; } diff --git a/Mage.Sets/src/mage/cards/h/HeroesPodium.java b/Mage.Sets/src/mage/cards/h/HeroesPodium.java index 5598d0a97ab..a7f54579a7f 100644 --- a/Mage.Sets/src/mage/cards/h/HeroesPodium.java +++ b/Mage.Sets/src/mage/cards/h/HeroesPodium.java @@ -28,6 +28,7 @@ package mage.cards.h; import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; @@ -58,9 +59,9 @@ public class HeroesPodium extends CardImpl { static { filter.add(new SupertypePredicate(SuperType.LEGENDARY)); } - + public HeroesPodium(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{5}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}"); addSuperType(SuperType.LEGENDARY); // Each legendary creature you control gets +1/+1 for each other legendary creature you control. @@ -88,6 +89,7 @@ public class HeroesPodium extends CardImpl { class HeroesPodiumLegendaryCount implements DynamicValue { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("other legendary creature you control"); + static { filter.add(new SupertypePredicate(SuperType.LEGENDARY)); } @@ -120,6 +122,7 @@ class HeroesPodiumLegendaryCount implements DynamicValue { class HeroesPodiumEffect extends OneShotEffect { private static final FilterCreatureCard filter = new FilterCreatureCard("a legendary creature card"); + static { filter.add(new SupertypePredicate(SuperType.LEGENDARY)); } @@ -140,54 +143,36 @@ class HeroesPodiumEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + if (controller == null || sourceObject == null) { return false; } Cards cards = new CardsImpl(); - int count = source.getManaCostsToPay().getX(); - count = Math.min(player.getLibrary().size(), count); - boolean legendaryIncluded = false; - for (int i = 0; i < count; i++) { - Card card = player.getLibrary().removeFromTop(game); - if (card != null) { - cards.add(card); - if (filter.match(card, game)) { - legendaryIncluded = true; - } - } - } - player.lookAtCards("Heroes' Podium", cards, game); + cards.addAll(controller.getLibrary().getTopCards(game, source.getManaCostsToPay().getX())); + boolean legendaryIncluded = cards.count(filter, game) > 0; + controller.lookAtCards(sourceObject.getIdName(), cards, game); // You may reveal a legendary creature card from among them and put it into your hand. - if (!cards.isEmpty() && legendaryIncluded && player.chooseUse(outcome, "Put a legendary creature card into your hand?", source, game)) { + if (!cards.isEmpty() && legendaryIncluded && controller.chooseUse(outcome, "Put a legendary creature card into your hand?", source, game)) { if (cards.size() == 1) { - Card card = cards.getRandom(game); - cards.remove(card); - card.moveToZone(Zone.HAND, source.getSourceId(), game, false); + controller.moveCards(cards, Zone.HAND, source, game); return true; } else { TargetCard target = new TargetCard(Zone.LIBRARY, filter); - if (player.choose(outcome, cards, target, game)) { + if (controller.choose(outcome, cards, target, game)) { Card card = cards.get(target.getFirstTarget(), game); if (card != null) { cards.remove(card); - card.moveToZone(Zone.HAND, source.getSourceId(), game, false); + controller.moveCards(card, Zone.HAND, source, game); } } } } // Put the rest on the bottom of your library in a random order - while (!cards.isEmpty()) { - Card card = cards.getRandom(game); - if (card != null) { - cards.remove(card); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - } - } + controller.putCardsOnBottomOfLibrary(cards, game, source, false); return true; } } diff --git a/Mage.Sets/src/mage/cards/i/IgniteMemories.java b/Mage.Sets/src/mage/cards/i/IgniteMemories.java index 30b01dd623a..02ecf7e1226 100644 --- a/Mage.Sets/src/mage/cards/i/IgniteMemories.java +++ b/Mage.Sets/src/mage/cards/i/IgniteMemories.java @@ -73,7 +73,7 @@ class IgniteMemoriesEffect extends OneShotEffect { public IgniteMemoriesEffect() { super(Outcome.Damage); - staticText = "Target player reveals a card at random from his or her hand. Ignite Memories deals damage to that player equal to that card's converted mana cost"; + staticText = "Target player reveals a card at random from his or her hand. {this} deals damage to that player equal to that card's converted mana cost"; } public IgniteMemoriesEffect(final IgniteMemoriesEffect effect) { @@ -88,10 +88,13 @@ class IgniteMemoriesEffect extends OneShotEffect { if (!controller.getHand().isEmpty()) { Cards revealed = new CardsImpl(); Card card = controller.getHand().getRandom(game); - revealed.add(card); - controller.revealCards(sourceObject.getIdName(), revealed, game); - controller.damage(card.getConvertedManaCost(), source.getSourceId(), game, false, true); - + if (card != null) { + revealed.add(card); + controller.revealCards(sourceObject.getIdName(), revealed, game); + controller.damage(card.getConvertedManaCost(), source.getSourceId(), game, false, true); + return true; + } + return false; } return true; } diff --git a/Mage.Sets/src/mage/cards/m/MadcapExperiment.java b/Mage.Sets/src/mage/cards/m/MadcapExperiment.java index 5982a6ddfe7..7d5acba730b 100644 --- a/Mage.Sets/src/mage/cards/m/MadcapExperiment.java +++ b/Mage.Sets/src/mage/cards/m/MadcapExperiment.java @@ -49,7 +49,7 @@ import mage.players.Player; public class MadcapExperiment extends CardImpl { public MadcapExperiment(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}"); // Reveal cards from the top of your library until you reveal an artifact card. Put that card onto the battlefield and the rest on the bottom of your library in a random order. Madcap Experiment deals damage to you equal to the number of cards revealed this way. this.getSpellAbility().addEffect(new MadcapExperimentEffect()); @@ -107,13 +107,7 @@ class MadcapExperimentEffect extends OneShotEffect { cards.remove(card); } // Put the rest on the bottom of your library in a random order - while (!cards.isEmpty()) { - card = cards.getRandom(game); - if (card != null) { - cards.remove(card); - controller.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.HAND, false, false); - } - } + controller.putCardsOnBottomOfLibrary(cards, game, source, false); controller.damage(revealed, source.getSourceId(), game, false, true); return true; } diff --git a/Mage.Sets/src/mage/cards/m/MagusOfTheScroll.java b/Mage.Sets/src/mage/cards/m/MagusOfTheScroll.java index aab52ad5417..2ec8ede24a9 100644 --- a/Mage.Sets/src/mage/cards/m/MagusOfTheScroll.java +++ b/Mage.Sets/src/mage/cards/m/MagusOfTheScroll.java @@ -42,8 +42,8 @@ import mage.cards.CardSetInfo; import mage.cards.Cards; import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; @@ -101,6 +101,9 @@ class MagusOfTheScrollEffect extends OneShotEffect { if (!you.getHand().isEmpty()) { Cards revealed = new CardsImpl(); Card card = you.getHand().getRandom(game); + if (card == null) { + return false; + } revealed.add(card); you.revealCards(sourceObject.getName(), revealed, game); if (card.getName().equals(cardName)) { diff --git a/Mage.Sets/src/mage/cards/m/MakeAWish.java b/Mage.Sets/src/mage/cards/m/MakeAWish.java index 8c165ca3820..990a655b9b0 100644 --- a/Mage.Sets/src/mage/cards/m/MakeAWish.java +++ b/Mage.Sets/src/mage/cards/m/MakeAWish.java @@ -47,8 +47,7 @@ import mage.players.Player; public class MakeAWish extends CardImpl { public MakeAWish(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{G}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}"); // Return two cards at random from your graveyard to your hand. this.getSpellAbility().addEffect(new MakeAWishEffect()); @@ -91,6 +90,8 @@ class MakeAWishEffect extends OneShotEffect { card.moveToZone(Zone.HAND, source.getSourceId(), game, true); cards.remove(card); game.informPlayers(card.getName() + " returned to the hand of " + player.getLogName()); + } else { + return false; } } return true; diff --git a/Mage.Sets/src/mage/cards/m/ManifoldInsights.java b/Mage.Sets/src/mage/cards/m/ManifoldInsights.java index 019bbbbc918..0e1ac70ef06 100644 --- a/Mage.Sets/src/mage/cards/m/ManifoldInsights.java +++ b/Mage.Sets/src/mage/cards/m/ManifoldInsights.java @@ -113,15 +113,7 @@ class ManifoldInsightsEffect extends OneShotEffect { } } controller.moveCards(chosenCards, Zone.HAND, source, game); - while (!topLib.isEmpty() && controller.isInGame()) { - Card card = topLib.getRandom(game); - if (card != null) { - topLib.remove(card); - controller.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.LIBRARY, false, false); - } else { - return false; - } - } + controller.putCardsOnBottomOfLibrary(topLib, game, source, false); return true; } return false; diff --git a/Mage.Sets/src/mage/cards/o/OrcishLibrarian.java b/Mage.Sets/src/mage/cards/o/OrcishLibrarian.java index eec0c3417b2..e804d80f323 100644 --- a/Mage.Sets/src/mage/cards/o/OrcishLibrarian.java +++ b/Mage.Sets/src/mage/cards/o/OrcishLibrarian.java @@ -29,6 +29,7 @@ package mage.cards.o; import java.util.UUID; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; @@ -40,9 +41,9 @@ import mage.cards.CardSetInfo; import mage.cards.Cards; import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ColoredManaSymbol; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; @@ -56,7 +57,7 @@ import mage.target.TargetCard; public class OrcishLibrarian extends CardImpl { public OrcishLibrarian(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); this.subtype.add(SubType.ORC); this.power = new MageInt(1); @@ -96,32 +97,30 @@ class OrcishLibrarianEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - - if (player != null) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + if (controller != null && sourceObject != null) { Cards cards = new CardsImpl(); - int cardsCount = Math.min(8, player.getLibrary().size()); + int cardsCount = Math.min(8, controller.getLibrary().size()); for (int i = 0; i < cardsCount; i++) { - Card card = player.getLibrary().removeFromTop(game); + Card card = controller.getLibrary().removeFromTop(game); if (card != null) { cards.add(card); } } if (!cards.isEmpty()) { - for (int i = 0; i < 4; i++) - { - if (!cards.isEmpty()) - { + for (int i = 0; i < 4; i++) { + if (!cards.isEmpty()) { Card card = cards.getRandom(game); - player.moveCardToExileWithInfo(card, null, null, source.getId(), game, Zone.LIBRARY, true); + controller.moveCardToExileWithInfo(card, null, null, source.getId(), game, Zone.LIBRARY, true); cards.remove(card); } } - player.lookAtCards("OrcishLibrarian", cards, game); - TargetCard target = new TargetCard (Zone.LIBRARY, new FilterCard("card to put on the top of target player's library")); - while (player.canRespond() && !cards.isEmpty()) { - player.choose(Outcome.Neutral, cards, target, game); + controller.lookAtCards(sourceObject.getIdName(), cards, game); + TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put on the top of target player's library")); + while (controller.canRespond() && !cards.isEmpty()) { + controller.choose(Outcome.Neutral, cards, target, game); Card card = cards.get(target.getFirstTarget(), game); if (card != null) { cards.remove(card); @@ -134,4 +133,4 @@ class OrcishLibrarianEffect extends OneShotEffect { } return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/p/PlaneswalkersMischief.java b/Mage.Sets/src/mage/cards/p/PlaneswalkersMischief.java index 3e2d14811d3..a313513140c 100644 --- a/Mage.Sets/src/mage/cards/p/PlaneswalkersMischief.java +++ b/Mage.Sets/src/mage/cards/p/PlaneswalkersMischief.java @@ -105,6 +105,9 @@ class PlaneswalkersMischiefEffect extends OneShotEffect { if (opponent != null && opponent.getHand().size() > 0) { Card revealedCard = opponent.getHand().getRandom(game); + if (revealedCard == null) { + return false; + } Cards cards = new CardsImpl(); cards.add(revealedCard); opponent.revealCards("Planeswalker's Mischief Reveal", cards, game); diff --git a/Mage.Sets/src/mage/cards/r/RiseFall.java b/Mage.Sets/src/mage/cards/r/RiseFall.java index a8f403015e9..41107fcfb69 100644 --- a/Mage.Sets/src/mage/cards/r/RiseFall.java +++ b/Mage.Sets/src/mage/cards/r/RiseFall.java @@ -141,10 +141,16 @@ class FallEffect extends OneShotEffect { if (!targetPlayer.getHand().isEmpty()) { Cards cards = new CardsImpl(); Card card = targetPlayer.getHand().getRandom(game); + if (card == null) { + return false; + } cards.add(card); if (targetPlayer.getHand().size() > 1) { do { card = targetPlayer.getHand().getRandom(game); + if (card == null) { + return false; + } } while (cards.contains(card.getId())); cards.add(card); } diff --git a/Mage.Sets/src/mage/cards/s/SingeMindOgre.java b/Mage.Sets/src/mage/cards/s/SingeMindOgre.java index db5a96093b8..16dee3e818b 100644 --- a/Mage.Sets/src/mage/cards/s/SingeMindOgre.java +++ b/Mage.Sets/src/mage/cards/s/SingeMindOgre.java @@ -38,8 +38,8 @@ import mage.cards.CardSetInfo; import mage.cards.Cards; import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; @@ -51,7 +51,7 @@ import mage.target.TargetPlayer; public class SingeMindOgre extends CardImpl { public SingeMindOgre(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{R}"); this.subtype.add(SubType.OGRE); this.subtype.add(SubType.MUTANT); @@ -62,7 +62,7 @@ public class SingeMindOgre extends CardImpl { Ability ability = new EntersBattlefieldTriggeredAbility(new SingeMindOgreEffect(), false); ability.addTarget(new TargetPlayer()); this.addAbility(ability); - + } public SingeMindOgre(final SingeMindOgre card) { @@ -97,10 +97,12 @@ class SingeMindOgreEffect extends OneShotEffect { if (targetPlayer != null && !targetPlayer.getHand().isEmpty()) { Cards revealed = new CardsImpl(); Card card = targetPlayer.getHand().getRandom(game); - revealed.add(card); - targetPlayer.revealCards("Singe-Mind Ogre", revealed, game); - targetPlayer.loseLife(card.getConvertedManaCost(), game, false); - return true; + if (card != null) { + revealed.add(card); + targetPlayer.revealCards("Singe-Mind Ogre", revealed, game); + targetPlayer.loseLife(card.getConvertedManaCost(), game, false); + return true; + } } return false; } diff --git a/Mage.Sets/src/mage/cards/t/TellingTime.java b/Mage.Sets/src/mage/cards/t/TellingTime.java index 7185bca0e73..4baa5c7f981 100644 --- a/Mage.Sets/src/mage/cards/t/TellingTime.java +++ b/Mage.Sets/src/mage/cards/t/TellingTime.java @@ -28,6 +28,7 @@ package mage.cards.t; import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -40,7 +41,6 @@ import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; -import mage.players.Library; import mage.players.Player; import mage.target.TargetCard; @@ -51,8 +51,7 @@ import mage.target.TargetCard; public class TellingTime extends CardImpl { public TellingTime(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // Look at the top three cards of your library. // Put one of those cards into your hand, one on top of your library, and one on the bottom of your library. @@ -87,36 +86,35 @@ class TellingTimeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + if (controller == null || sourceObject == null) { return false; } Cards cards = new CardsImpl(); - - Library library = player.getLibrary(); - int n = Math.min(3, library.size()); - for (int i = 0; i < n; i++) { - cards.add(library.removeFromTop(game)); + cards.addAll(controller.getLibrary().getTopCards(game, 3)); + controller.lookAtCards(sourceObject.getIdName(), cards, game); + if (cards.isEmpty()) { + return true; } - - player.lookAtCards("Telling Time", cards, game); - - Card card = pickCard(game, player, cards, "card to put in your hand"); + Card card = pickCard(game, controller, cards, "card to put in your hand"); if (card != null) { - card.moveToZone(Zone.HAND, source.getSourceId(), game, false); + controller.moveCards(card, Zone.HAND, source, game); + cards.remove(card); + } + if (cards.isEmpty()) { + return true; } - card = pickCard(game, player, cards, "card to put on top of your library"); + card = pickCard(game, controller, cards, "card to put on top of your library"); if (card != null) { - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); + controller.moveCards(card, Zone.LIBRARY, source, game); + cards.remove(card); } - if (!cards.isEmpty()) { - card = cards.getRandom(game); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); + controller.putCardsOnBottomOfLibrary(cards, game, source, false); } - return true; } @@ -125,7 +123,9 @@ class TellingTimeEffect extends OneShotEffect { return null; } if (cards.size() == 1) { - return cards.getRandom(null); + Card card = cards.getRandom(game); + cards.remove(card); + return card; } TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard(message)); diff --git a/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java index b17461f02a8..e244c7f4e63 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java @@ -321,8 +321,11 @@ public class RandomPlayer extends ComputerPlayer { return !target.isRequired(source); } Card card = cards.getRandom(game); - target.addTarget(card.getId(), source, game); - return true; + if (card != null) { + target.addTarget(card.getId(), source, game); + return true; + } + return false; } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/LookLibraryControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/LookLibraryControllerEffect.java index 42bd8e092fc..18dfa8b0461 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/LookLibraryControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/LookLibraryControllerEffect.java @@ -177,18 +177,7 @@ public class LookLibraryControllerEffect extends OneShotEffect { switch (targetZoneLookedCards) { case LIBRARY: if (putOnTop) { - player.putCardsOnTopOfLibrary(cards, game, source, true); - } else { - if (backInRandomOrder) { - Cards newOrder = new CardsImpl(); - while (!cards.isEmpty()) { - Card card = cards.getRandom(game); - newOrder.add(card); - cards.remove(card); - } - cards = newOrder; - } - player.putCardsOnBottomOfLibrary(cards, game, source, true); + player.putCardsOnBottomOfLibrary(cards, game, source, !backInRandomOrder); } break; case GRAVEYARD: diff --git a/Mage/src/main/java/mage/abilities/keyword/CascadeAbility.java b/Mage/src/main/java/mage/abilities/keyword/CascadeAbility.java index 6133ddc933d..4c59a830136 100644 --- a/Mage/src/main/java/mage/abilities/keyword/CascadeAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/CascadeAbility.java @@ -31,7 +31,6 @@ import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; -import mage.cards.Cards; import mage.cards.CardsImpl; import mage.constants.Outcome; import mage.constants.Zone; @@ -129,15 +128,7 @@ class CascadeEffect extends OneShotEffect { } } // Move the remaining cards to the buttom of the library in a random order - Cards cardsFromExile = new CardsImpl(); - Cards cardsToLibrary = new CardsImpl(); - cardsFromExile.addAll(exile); - while (!cardsFromExile.isEmpty()) { - card = cardsFromExile.getRandom(game); - cardsFromExile.remove(card.getId()); - cardsToLibrary.add(card); - } - return controller.putCardsOnBottomOfLibrary(cardsToLibrary, game, source, false); + return controller.putCardsOnBottomOfLibrary(new CardsImpl(exile), game, source, false); } @Override diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index ae0881750e2..2879a82cb0c 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -861,6 +861,8 @@ public abstract class PlayerImpl implements Player, Serializable { if (card != null) { cards.remove(card); moveObjectToLibrary(card.getId(), source == null ? null : source.getSourceId(), game, false, false); + } else { + return false;// probably cards were removed because player left the game } } } else { @@ -900,9 +902,13 @@ public abstract class PlayerImpl implements Player, Serializable { UUID sourceId = (source == null ? null : source.getSourceId()); if (!anyOrder) { while (!cards.isEmpty()) { - UUID cardId = cards.getRandom(game).getId(); - cards.remove(cardId); - moveObjectToLibrary(cardId, source == null ? null : source.getSourceId(), game, true, false); + Card card = cards.getRandom(game); + if (card != null) { + cards.remove(card.getId()); + moveObjectToLibrary(card.getId(), source == null ? null : source.getSourceId(), game, true, false); + } else { + return false; // probably cards were removed because player left the game + } } } else { TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put on the top of your library (last one chosen will be topmost)")); @@ -1360,7 +1366,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public LinkedHashMap getUseableActivatedAbilities(MageObject object, Zone zone, Game game) { LinkedHashMap useable = new LinkedHashMap<>(); - if (object instanceof StackAbility) { // It may not be possible to activate abilities of stack actilities + if (object instanceof StackAbility) { // It may not be possible to activate abilities of stack actilities return useable; } if (object instanceof SplitCard) {