mirror of
https://github.com/magefree/mage.git
synced 2025-12-27 05:52:06 -08:00
[CMR] implemented Opposition Agent and other changes:
* You may play cards and you may spend mana of any color - refactored cards to use same code; * Library search event allows to change searching controller (gives full game control for another player); * Library searched event allows to remove founded cards from result; * Improved library searching effects with Panglacial Wurm's effects; * Little changes to test framework;
This commit is contained in:
parent
13fa98ec44
commit
c2a636e2b2
22 changed files with 806 additions and 721 deletions
|
|
@ -0,0 +1,53 @@
|
|||
package mage.abilities.effects.common.asthought;
|
||||
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.AsThoughEffectImpl;
|
||||
import mage.constants.AsThoughEffectType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Play card from current zone. Will be discarded on any card movements or blinks.
|
||||
* <p>
|
||||
* Recommends to use combo effects from CardUtil.makeCardPlayableAndSpendManaAsAnyColor instead signle effect
|
||||
*
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class CanPlayCardControllerEffect extends AsThoughEffectImpl {
|
||||
|
||||
protected final MageObjectReference mor;
|
||||
|
||||
public CanPlayCardControllerEffect(Game game, UUID cardId, int cardZCC, Duration duration) {
|
||||
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, duration, Outcome.Benefit);
|
||||
this.staticText = "You may play those card";
|
||||
this.mor = new MageObjectReference(cardId, cardZCC, game);
|
||||
}
|
||||
|
||||
public CanPlayCardControllerEffect(final CanPlayCardControllerEffect effect) {
|
||||
super(effect);
|
||||
this.mor = effect.mor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CanPlayCardControllerEffect copy() {
|
||||
return new CanPlayCardControllerEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) {
|
||||
if (mor.getCard(game) == null) {
|
||||
discard();
|
||||
return false;
|
||||
}
|
||||
return mor.refersTo(sourceId, game) && source.isControlledBy(affectedControllerId);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package mage.abilities.effects.common.asthought;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.AsThoughEffectImpl;
|
||||
import mage.abilities.effects.AsThoughManaEffect;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.players.ManaPoolItem;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Spend mana as any color to cast targeted card. Will not affected after any card movements or blinks.
|
||||
*
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class YouMaySpendManaAsAnyColorToCastTargetEffect extends AsThoughEffectImpl implements AsThoughManaEffect {
|
||||
|
||||
public YouMaySpendManaAsAnyColorToCastTargetEffect(Duration duration) {
|
||||
super(AsThoughEffectType.SPEND_OTHER_MANA, duration, Outcome.Benefit);
|
||||
this.staticText = "You may spend mana as though it were mana of any color to cast it";
|
||||
}
|
||||
|
||||
public YouMaySpendManaAsAnyColorToCastTargetEffect(final YouMaySpendManaAsAnyColorToCastTargetEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public YouMaySpendManaAsAnyColorToCastTargetEffect copy() {
|
||||
return new YouMaySpendManaAsAnyColorToCastTargetEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
||||
objectId = CardUtil.getMainCardId(game, objectId); // for split cards
|
||||
FixedTarget fixedTarget = ((FixedTarget) getTargetPointer());
|
||||
return source.isControlledBy(affectedControllerId)
|
||||
&& Objects.equals(objectId, fixedTarget.getTarget())
|
||||
&& game.getState().getZoneChangeCounter(objectId) <= fixedTarget.getZoneChangeCounter() + 1
|
||||
&& (game.getState().getZone(objectId) == Zone.STACK || game.getState().getZone(objectId) == Zone.EXILED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ManaType getAsThoughManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) {
|
||||
return mana.getFirstAvailable();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package mage.abilities.effects.common.replacement;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.SearchLibraryEvent;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class YouControlYourOpponentsWhileSearchingReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
public YouControlYourOpponentsWhileSearchingReplacementEffect() {
|
||||
super(Duration.WhileOnBattlefield, Outcome.Benefit);
|
||||
staticText = "You control your opponents while they’re searching their libraries";
|
||||
}
|
||||
|
||||
YouControlYourOpponentsWhileSearchingReplacementEffect(final YouControlYourOpponentsWhileSearchingReplacementEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
SearchLibraryEvent se = (SearchLibraryEvent) event;
|
||||
se.setSearchingControllerId(source.getControllerId());
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.SEARCH_LIBRARY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
return controller != null && game.isOpponent(controller, event.getPlayerId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public YouControlYourOpponentsWhileSearchingReplacementEffect copy() {
|
||||
return new YouControlYourOpponentsWhileSearchingReplacementEffect(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package mage.game.events;
|
||||
|
||||
import mage.target.Target;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class LibrarySearchedEvent extends GameEvent {
|
||||
|
||||
protected Target searchedTarget;
|
||||
|
||||
/**
|
||||
* Searched library event (after library searching finished). Return false on replaceEvent to
|
||||
*
|
||||
* @param targetPlayerId whose library searched
|
||||
* @param sourceId source of the searching effect
|
||||
* @param playerId who must search the library
|
||||
* @param searchedTarget founded cards (targets list can be changed by replace events, see Opposition Agent)
|
||||
*/
|
||||
public LibrarySearchedEvent(UUID targetPlayerId, UUID sourceId, UUID playerId, Target searchedTarget) {
|
||||
super(EventType.LIBRARY_SEARCHED, targetPlayerId, sourceId, playerId, searchedTarget.getTargets().size(), false);
|
||||
this.searchedTarget = searchedTarget;
|
||||
}
|
||||
|
||||
public Target getSearchedTarget() {
|
||||
return this.searchedTarget;
|
||||
}
|
||||
}
|
||||
32
Mage/src/main/java/mage/game/events/SearchLibraryEvent.java
Normal file
32
Mage/src/main/java/mage/game/events/SearchLibraryEvent.java
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
package mage.game.events;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class SearchLibraryEvent extends GameEvent {
|
||||
|
||||
protected UUID searchingControllerId; // who controls the searching process, see Opposition Agent
|
||||
|
||||
/**
|
||||
* Searching library event
|
||||
*
|
||||
* @param targetPlayerId whose library will be searched
|
||||
* @param sourceId source of the searching effect
|
||||
* @param playerId who must search the library (also see searchingControllerId)
|
||||
* @param amount cards amount to search
|
||||
*/
|
||||
public SearchLibraryEvent(UUID targetPlayerId, UUID sourceId, UUID playerId, int amount) {
|
||||
super(GameEvent.EventType.SEARCH_LIBRARY, targetPlayerId, sourceId, playerId, amount, false);
|
||||
this.searchingControllerId = playerId;
|
||||
}
|
||||
|
||||
public UUID getSearchingControllerId() {
|
||||
return this.searchingControllerId;
|
||||
}
|
||||
|
||||
public void setSearchingControllerId(UUID searchingControllerId) {
|
||||
this.searchingControllerId = searchingControllerId;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,7 @@
|
|||
package mage.players;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import mage.ApprovingObject;
|
||||
import mage.ConditionalMana;
|
||||
import mage.MageObject;
|
||||
import mage.Mana;
|
||||
import mage.*;
|
||||
import mage.abilities.*;
|
||||
import mage.abilities.ActivatedAbility.ActivationStatus;
|
||||
import mage.abilities.common.PassAbility;
|
||||
|
|
@ -28,7 +25,6 @@ import mage.abilities.mana.ManaOptions;
|
|||
import mage.actions.MageDrawAction;
|
||||
import mage.cards.*;
|
||||
import mage.cards.decks.Deck;
|
||||
import mage.choices.ChoiceImpl;
|
||||
import mage.constants.*;
|
||||
import mage.counters.Counter;
|
||||
import mage.counters.CounterType;
|
||||
|
|
@ -38,6 +34,7 @@ import mage.designations.DesignationType;
|
|||
import mage.filter.FilterCard;
|
||||
import mage.filter.FilterMana;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterControlledPermanent;
|
||||
import mage.filter.common.FilterCreatureForCombat;
|
||||
import mage.filter.common.FilterCreatureForCombatBlock;
|
||||
|
|
@ -2609,73 +2606,97 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
@Override
|
||||
public boolean searchLibrary(TargetCardInLibrary target, Ability source, Game game, UUID targetPlayerId) {
|
||||
//20091005 - 701.14c
|
||||
Library searchedLibrary = null;
|
||||
String searchInfo = null;
|
||||
if (targetPlayerId.equals(playerId)) {
|
||||
searchInfo = getLogName() + " searches their library";
|
||||
searchedLibrary = library;
|
||||
|
||||
// searching control can be intercepted by another player, see Opposition Agent
|
||||
SearchLibraryEvent searchEvent = new SearchLibraryEvent(targetPlayerId, source.getSourceId(), playerId, Integer.MAX_VALUE);
|
||||
if (game.replaceEvent(searchEvent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Player targetPlayer = game.getPlayer(targetPlayerId);
|
||||
Player searchingPlayer = this;
|
||||
Player searchingController = game.getPlayer(searchEvent.getSearchingControllerId());
|
||||
if (targetPlayer == null || searchingController == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String searchInfo = searchingPlayer.getLogName();
|
||||
if (!searchingPlayer.getId().equals(searchingController.getId())) {
|
||||
searchInfo = searchInfo + " under control of " + searchingPlayer.getLogName();
|
||||
}
|
||||
if (targetPlayer.getId().equals(searchingPlayer.getId())) {
|
||||
searchInfo = searchInfo + " searches their library";
|
||||
} else {
|
||||
Player targetPlayer = game.getPlayer(targetPlayerId);
|
||||
if (targetPlayer != null) {
|
||||
searchInfo = getLogName() + " searches the library of " + targetPlayer.getLogName();
|
||||
searchedLibrary = targetPlayer.getLibrary();
|
||||
}
|
||||
}
|
||||
if (searchedLibrary == null) {
|
||||
return false;
|
||||
}
|
||||
GameEvent event = GameEvent.getEvent(GameEvent.EventType.SEARCH_LIBRARY,
|
||||
targetPlayerId, source.getSourceId(), playerId, Integer.MAX_VALUE);
|
||||
if (game.replaceEvent(event)) {
|
||||
return false;
|
||||
searchInfo = searchInfo + " searches the library of " + targetPlayer.getLogName();
|
||||
}
|
||||
|
||||
if (!game.isSimulation()) {
|
||||
game.informPlayers(searchInfo);
|
||||
}
|
||||
|
||||
// https://www.reddit.com/r/magicTCG/comments/jj8gh9/opposition_agent_and_panglacial_wurm_interaction/
|
||||
// You must take full player control while searching, e.g. you can cast opponent's cards by Panglacial Wurm effect:
|
||||
// * While you’re searching your library, you may cast Panglacial Wurm from your library.
|
||||
// So use here same code as Word of Command
|
||||
// P.S. no needs in searchingController, but it helps with unit tests, see TakeControlWhileSearchingLibraryTest
|
||||
boolean takeControl = false;
|
||||
if (!searchingPlayer.getId().equals(searchingController.getId())) {
|
||||
CardUtil.takeControlUnderPlayerStart(game, searchingController, searchingPlayer, true);
|
||||
takeControl = true;
|
||||
}
|
||||
|
||||
Library searchingLibrary = targetPlayer.getLibrary();
|
||||
TargetCardInLibrary newTarget = target.copy();
|
||||
int count;
|
||||
int librarySearchLimit = event.getAmount();
|
||||
int librarySearchLimit = searchEvent.getAmount();
|
||||
List<Card> cardsFromTop = null;
|
||||
do {
|
||||
// TODO: prevent shuffling from moving the visualized cards
|
||||
if (librarySearchLimit == Integer.MAX_VALUE) {
|
||||
count = searchedLibrary.count(target.getFilter(), game);
|
||||
count = searchingLibrary.count(target.getFilter(), game);
|
||||
} else {
|
||||
Player targetPlayer = game.getPlayer(targetPlayerId);
|
||||
if (targetPlayer == null) {
|
||||
return false;
|
||||
}
|
||||
if (cardsFromTop == null) {
|
||||
cardsFromTop = new ArrayList<>(targetPlayer.getLibrary().getTopCards(game, librarySearchLimit));
|
||||
cardsFromTop = new ArrayList<>(searchingLibrary.getTopCards(game, librarySearchLimit));
|
||||
} else {
|
||||
cardsFromTop.retainAll(targetPlayer.getLibrary().getCards(game));
|
||||
cardsFromTop.retainAll(searchingLibrary.getCards(game));
|
||||
}
|
||||
newTarget.setCardLimit(Math.min(librarySearchLimit, cardsFromTop.size()));
|
||||
count = Math.min(searchedLibrary.count(target.getFilter(), game), librarySearchLimit);
|
||||
count = Math.min(searchingLibrary.count(target.getFilter(), game), librarySearchLimit);
|
||||
}
|
||||
|
||||
if (count < target.getNumberOfTargets()) {
|
||||
newTarget.setMinNumberOfTargets(count);
|
||||
}
|
||||
if (newTarget.choose(Outcome.Neutral, playerId, targetPlayerId, game)) {
|
||||
if (targetPlayerId.equals(playerId) && handleLibraryCastableCards(library,
|
||||
game, targetPlayerId)) { // for handling Panglacial Wurm
|
||||
|
||||
// handling Panglacial Wurm - cast cards while searching from own library
|
||||
if (targetPlayer.getId().equals(searchingPlayer.getId())) {
|
||||
if (handleCastableCardsWhileLibrarySearching(library, game, targetPlayer)) {
|
||||
// clear all choices to start from scratch (casted cards must be removed from library)
|
||||
newTarget.clearChosen();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (newTarget.choose(Outcome.Neutral, searchingController.getId(), targetPlayer.getId(), game)) {
|
||||
target.getTargets().clear();
|
||||
for (UUID targetId : newTarget.getTargets()) {
|
||||
target.add(targetId, game);
|
||||
}
|
||||
|
||||
} else if (targetPlayerId.equals(playerId) && handleLibraryCastableCards(library,
|
||||
game, targetPlayerId)) { // for handling Panglacial Wurm
|
||||
newTarget.clearChosen();
|
||||
continue;
|
||||
}
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LIBRARY_SEARCHED, targetPlayerId, playerId));
|
||||
|
||||
// END SEARCH
|
||||
if (takeControl) {
|
||||
CardUtil.takeControlUnderPlayerEnd(game, searchingController, searchingPlayer);
|
||||
game.informPlayers("Control of " + searchingPlayer.getLogName() + " is back");
|
||||
}
|
||||
|
||||
LibrarySearchedEvent searchedEvent = new LibrarySearchedEvent(targetPlayer.getId(), source.getSourceId(), searchingPlayer.getId(), target);
|
||||
if (game.replaceEvent(searchedEvent)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
} while (true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -2690,58 +2711,53 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean handleLibraryCastableCards(Library library, Game game, UUID targetPlayerId) {
|
||||
// for handling Panglacial Wurm
|
||||
boolean alreadyChosenUse = false;
|
||||
Map<UUID, String> libraryCastableCardTracker = new HashMap<>();
|
||||
searchForCards:
|
||||
do {
|
||||
for (Card card : library.getCards(game)) {
|
||||
for (Ability ability : card.getAbilities()) {
|
||||
if (ability.getClass() == WhileSearchingPlayFromLibraryAbility.class) {
|
||||
libraryCastableCardTracker.put(card.getId(), card.getIdName());
|
||||
}
|
||||
}
|
||||
private boolean handleCastableCardsWhileLibrarySearching(Library library, Game game, Player targetPlayer) {
|
||||
// must return true after cast try (to restart searching process without casted cards)
|
||||
// uses for handling Panglacial Wurm:
|
||||
// * While you're searching your library, you may cast Panglacial Wurm from your library.
|
||||
|
||||
List<UUID> castableCards = library.getCards(game).stream()
|
||||
.filter(card -> card.getAbilities(game).containsClass(WhileSearchingPlayFromLibraryAbility.class))
|
||||
.map(MageItem::getId)
|
||||
.collect(Collectors.toList());
|
||||
if (castableCards.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// only humans can use it
|
||||
if (!targetPlayer.isHuman() && !targetPlayer.isTestMode()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!targetPlayer.chooseUse(Outcome.AIDontUseIt, "Library have " + castableCards.size() + " castable cards on searching. Do you want to cast it?", null, game)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean casted = false;
|
||||
TargetCard targetCard = new TargetCard(0, 1, Zone.LIBRARY, StaticFilters.FILTER_CARD);
|
||||
targetCard.setTargetName("card to cast from library");
|
||||
targetCard.setNotTarget(true);
|
||||
while (castableCards.size() > 0) {
|
||||
targetCard.clearChosen();
|
||||
if (!targetPlayer.choose(Outcome.AIDontUseIt, new CardsImpl(castableCards), targetCard, game)) {
|
||||
break;
|
||||
}
|
||||
if (!libraryCastableCardTracker.isEmpty()) {
|
||||
Player player = game.getPlayer(targetPlayerId);
|
||||
if (player != null) {
|
||||
if (player.isHuman() && (alreadyChosenUse || player.chooseUse(Outcome.AIDontUseIt,
|
||||
"Cast a creature card from your library? (choose \"No\" to finish search)", null, game))) {
|
||||
ChoiceImpl chooseCard = new ChoiceImpl();
|
||||
chooseCard.setMessage("Which creature do you wish to cast from your library?");
|
||||
Set<String> choice = new LinkedHashSet<>();
|
||||
for (Entry<UUID, String> entry : libraryCastableCardTracker.entrySet()) {
|
||||
choice.add(new AbstractMap.SimpleEntry<>(entry).getValue());
|
||||
}
|
||||
chooseCard.setChoices(choice);
|
||||
while (!choice.isEmpty()) {
|
||||
if (player.choose(Outcome.AIDontUseIt, chooseCard, game)) {
|
||||
String chosenCard = chooseCard.getChoice();
|
||||
for (Entry<UUID, String> entry : libraryCastableCardTracker.entrySet()) {
|
||||
if (chosenCard.equals(entry.getValue())) {
|
||||
Card card = game.getCard(entry.getKey());
|
||||
if (card != null) {
|
||||
// TODO: fix costs (why is Panglacial Wurm automatically accepting payment?)
|
||||
player.cast(card.getSpellAbility(), game, false, null);
|
||||
}
|
||||
chooseCard.clearChoice();
|
||||
libraryCastableCardTracker.clear();
|
||||
alreadyChosenUse = true;
|
||||
continue searchForCards;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Card card = game.getCard(targetCard.getFirstTarget());
|
||||
if (card == null) {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
} while (alreadyChosenUse);
|
||||
return alreadyChosenUse;
|
||||
|
||||
// AI NOTICE: if you want AI implement here then remove selected card from castable after each
|
||||
// choice (otherwise you catch infinite freeze on uncastable use case)
|
||||
|
||||
// casting selected card
|
||||
// TODO: fix costs (why is Panglacial Wurm automatically accepting payment?)
|
||||
targetPlayer.cast(targetPlayer.chooseAbilityForCast(card, game, false), game, false, null);
|
||||
castableCards.remove(card.getId());
|
||||
casted = true;
|
||||
}
|
||||
return casted;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import mage.abilities.SpellAbility;
|
|||
import mage.abilities.costs.VariableCost;
|
||||
import mage.abilities.costs.mana.*;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.common.asthought.CanPlayCardControllerEffect;
|
||||
import mage.abilities.effects.common.asthought.YouMaySpendManaAsAnyColorToCastTargetEffect;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.abilities.hint.HintUtils;
|
||||
import mage.cards.Card;
|
||||
|
|
@ -28,6 +30,7 @@ import mage.game.permanent.token.Token;
|
|||
import mage.game.stack.Spell;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.util.functions.CopyTokenFunction;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
|
|
@ -955,4 +958,56 @@ public final class CardUtil {
|
|||
}
|
||||
return RULES_ERROR_INFO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take control under another player, use it in inner effects like Word of Commands. Don't forget to end it in same code.
|
||||
*
|
||||
* @param game
|
||||
* @param controller
|
||||
* @param targetPlayer
|
||||
* @param givePauseForResponse if you want to give controller time to watch opponent's hand (if you remove control effect in the end of code)
|
||||
*/
|
||||
public static void takeControlUnderPlayerStart(Game game, Player controller, Player targetPlayer, boolean givePauseForResponse) {
|
||||
controller.controlPlayersTurn(game, targetPlayer.getId());
|
||||
if (givePauseForResponse) {
|
||||
while (controller.canRespond()) {
|
||||
if (controller.chooseUse(Outcome.Benefit, "You got control of " + targetPlayer.getLogName()
|
||||
+ ". Use switch hands button to view opponent's hand.", null,
|
||||
"Continue", "Wait", null, game)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return control under another player, use it in inner effects like Word of Commands.
|
||||
*
|
||||
* @param game
|
||||
* @param controller
|
||||
* @param targetPlayer
|
||||
*/
|
||||
public static void takeControlUnderPlayerEnd(Game game, Player controller, Player targetPlayer) {
|
||||
targetPlayer.setGameUnderYourControl(true, false);
|
||||
if (!targetPlayer.getTurnControlledBy().equals(controller.getId())) {
|
||||
controller.getPlayersUnderYourControl().remove(targetPlayer.getId());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add effects to game that allows to play/cast card from current zone and spend mana as any type for it.
|
||||
* Effects will be discarded/ignored on any card movements or blinks (after ZCC change)
|
||||
*
|
||||
* @param game
|
||||
* @param card
|
||||
* @param duration
|
||||
*/
|
||||
public static void makeCardPlayableAndSpendManaAsAnyColor(Game game, Ability source, Card card, Duration duration) {
|
||||
// Effect can be used for cards in zones and permanents on battlefield
|
||||
// So there is a workaround to get real ZCC (PermanentCard's ZCC is static, but it must be from Card's ZCC)
|
||||
// Example: Hostage Taker
|
||||
int zcc = game.getState().getZoneChangeCounter(card.getId());
|
||||
game.addEffect(new CanPlayCardControllerEffect(game, card.getId(), zcc, duration), source);
|
||||
game.addEffect(new YouMaySpendManaAsAnyColorToCastTargetEffect(duration).setTargetPointer(new FixedTarget(card.getId(), zcc)), source);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue