Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java
Original file line number Diff line number Diff line change
Expand Up @@ -3078,6 +3078,11 @@ public boolean putCardOnTopXOfLibrary(Card card, Game game, Ability source, int
return computerPlayer.putCardOnTopXOfLibrary(card, game, source, xFromTheTop, withName);
}

@Override
public boolean putCardsOnTopXOfLibrary(Cards cards, Game game, Ability source, int xFromTheTop, boolean withName) {
return computerPlayer.putCardsOnTopXOfLibrary(cards, game, source, xFromTheTop, withName);
}

@Override
public boolean putCardsOnTopOfLibrary(Cards cards, Game game, Ability source, boolean anyOrder) {
return computerPlayer.putCardsOnTopOfLibrary(cards, game, source, anyOrder);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
package mage.abilities.common;

import mage.MageObject;
import mage.MageObjectReference;
import mage.MageItem;
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;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.targetpointer.FixedTargets;
import mage.util.CardUtil;

import java.util.Objects;
import java.util.stream.Collectors;

/**
* @author TheElk801
*/
public class GodEternalDiesTriggeredAbility extends TriggeredAbilityImpl {

public GodEternalDiesTriggeredAbility() {
super(Zone.ALL, null, true);
super(Zone.ALL, new GodEternalEffect(), true);
setLeavesTheBattlefieldTrigger(true);
}

Expand All @@ -43,8 +47,8 @@ public boolean checkEventType(GameEvent event, Game game) {
public boolean checkTrigger(GameEvent event, Game game) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
if (zEvent.getTargetId().equals(this.getSourceId())) {
this.getEffects().clear();
this.addEffect(new GodEternalEffect(new MageObjectReference(zEvent.getTarget(), game)));
this.getEffects().setTargetPointer(new FixedTargets(
CardUtil.getAllCardsFromPermanentLeftBattlefield(zEvent.getTarget(), game), game));
return true;
}
return false;
Expand All @@ -64,16 +68,12 @@ public String getRule() {

class GodEternalEffect extends OneShotEffect {

private final MageObjectReference mor;

GodEternalEffect(MageObjectReference mor) {
GodEternalEffect() {
super(Outcome.Benefit);
this.mor = mor;
}

private GodEternalEffect(final GodEternalEffect effect) {
super(effect);
this.mor = effect.mor;
}

@Override
Expand All @@ -84,13 +84,15 @@ public GodEternalEffect copy() {
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return false;
}
Card card = game.getCard(mor.getSourceId());
if (card == null || card.getZoneChangeCounter(game) - 1 != mor.getZoneChangeCounter()) {
Cards cards = getTargetPointer().getTargets(game, source)
.stream()
.map(game::getCard)
.filter(Objects::nonNull)
.map(MageItem::getId)
.collect(Collectors.toCollection(CardsImpl::new));
if (player == null || cards.isEmpty()) {
return false;
}
return player.putCardOnTopXOfLibrary(card, game, source, 3, true);
return player.putCardsOnTopXOfLibrary(cards, game, source, 3, true);
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package mage.abilities.effects.common;

import mage.MageItem;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.Outcome;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.util.CardUtil;

import java.util.UUID;
import java.util.Objects;
import java.util.stream.Collectors;

/**
* @author TheElk801
Expand All @@ -35,19 +38,15 @@ public PutIntoLibraryNFromTopTargetEffect copy() {

@Override
public boolean apply(Game game, Ability source) {
boolean result = false;
for (UUID permanentId : getTargetPointer().getTargets(game, source)) {
Permanent permanent = game.getPermanent(permanentId);
if (permanent == null) {
continue;
}
Player player = game.getPlayer(permanent.getOwnerId());
if (player == null) {
continue;
}
result |= player.putCardOnTopXOfLibrary(permanent, game, source, position, true);
}
return result;
Cards cards = getTargetPointer().getTargets(game, source)
.stream()
.map(game::getPermanent)
.filter(Objects::nonNull)
.map(MageItem::getId)
.collect(Collectors.toCollection(CardsImpl::new));
Player player = game.getPlayer(source.getControllerId());
return player != null && !cards.isEmpty()
&& player.putCardsOnTopXOfLibrary(cards, game, source, position, true);
}

@Override
Expand Down
12 changes: 12 additions & 0 deletions Mage/src/main/java/mage/players/Player.java
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,18 @@ default GameState restoreState(int bookmark, String text, Game game) {
*/
boolean putCardOnTopXOfLibrary(Card card, Game game, Ability source, int xFromTheTop, boolean withName);

/**
* Moves the cards to the top x position of the library
*
* @param cards
* @param game
* @param source
* @param xFromTheTop
* @param withName - show card name in game logs for all players
* @return
*/
boolean putCardsOnTopXOfLibrary(Cards cards, Game game, Ability source, int xFromTheTop, boolean withName);

/**
* Moves the cards from cards to the top of players library.
*
Expand Down
47 changes: 47 additions & 0 deletions Mage/src/main/java/mage/players/PlayerImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -1136,6 +1136,53 @@ public boolean putCardOnTopXOfLibrary(Card card, Game game, Ability source, int
return true;
}

@Override
public boolean putCardsOnTopXOfLibrary(Cards cards, Game game, Ability source, int xFromTheTop, boolean withName) {
if (cards.isEmpty()) {
return false;
}
Map<UUID, Cards> playerMap = new HashMap<>();
for (Card card : cards.getCards(game)) {
playerMap.computeIfAbsent(card.getOwnerId(), k -> new CardsImpl()).add(card);
}
for (UUID playerId : game.getState().getPlayersInRange(this.getId(), game)) {
Player owner = game.getPlayer(playerId);
Cards ownedCards = playerMap.getOrDefault(playerId, new CardsImpl());
if (owner != null && !ownedCards.isEmpty()) {
if (owner.getLibrary().size() + 1 < xFromTheTop) {
owner.putCardsOnBottomOfLibrary(ownedCards, game, source, true);
continue;
}
if (ownedCards.size() == 1) {
owner.putCardOnTopXOfLibrary(ownedCards.getRandom(game), game, source, xFromTheTop, withName);
continue;
}
// 401.4. If an effect puts two or more cards in a specific position in a library at the same time,
// the owner of those cards may arrange them in any order.
// That library's owner doesn't reveal the order in which the cards go into the library.
TargetCard target = new TargetCard(Zone.ALL,
new FilterCard("card ORDER to put " + CardUtil.numberToOrdinalText(xFromTheTop) +
" from the TOP of your library (last one chosen will be topmost)"));
target.setRequired(true);
while (ownedCards.size() > 1
&& owner.canRespond()
&& owner.choose(Outcome.Neutral, ownedCards, target, source, game)) {
UUID targetObjectId = target.getFirstTarget();
if (targetObjectId == null) {
break;
}
ownedCards.remove(targetObjectId);
owner.putCardOnTopXOfLibrary(game.getCard((targetObjectId)), game, source, xFromTheTop, false);
target.clearChosen();
}
for (UUID c : ownedCards) {
owner.putCardOnTopXOfLibrary(game.getCard((c)), game, source, xFromTheTop, false);
}
}
}
return true;
}

/**
* Can be cards or permanents that go to library
*
Expand Down
Loading