use of mage.ApprovingObject in project mage by magefree.
the class WordOfCommandTestFlashEffect method apply.
@Override
public boolean apply(Game game, Ability source) {
Player sourceController = game.getPlayer(source.getControllerId());
Player targetPlayer = game.getPlayer(source.getFirstTarget());
MageObject sourceObject = game.getObject(source.getSourceId());
Card card = null;
if (sourceController != null && targetPlayer != null && sourceObject != null) {
Player controller = null;
Spell wordOfCommand = game.getSpell(source.getSourceId());
if (wordOfCommand != null) {
if (wordOfCommand.getCommandedBy() != null) {
controller = game.getPlayer(wordOfCommand.getCommandedBy());
} else {
controller = game.getPlayer(sourceController.getTurnControlledBy());
}
}
if (controller == null) {
// reset the controller to avoid NPE
controller = sourceController;
}
// Look at target opponent's hand and choose a card from it
TargetCard targetCard = new TargetCard(Zone.HAND, new FilterCard());
if (controller.choose(Outcome.Discard, targetPlayer.getHand(), targetCard, game)) {
card = game.getCard(targetCard.getFirstTarget());
}
// You control that player until Word of Command finishes resolving
CardUtil.takeControlUnderPlayerStart(game, controller, targetPlayer, true);
// The player plays that card if able
if (card != null) {
// While doing so, the player can activate mana abilities only if they're from lands that player controls
RestrictionEffect effect = new WordOfCommandCantActivateEffect();
effect.setTargetPointer(new FixedTarget(targetPlayer.getId()));
game.addEffect(effect, source);
// and only if mana they produce is spent to activate other mana abilities of lands they control and/or play that card
ManaPool manaPool = targetPlayer.getManaPool();
manaPool.setForcedToPay(true);
manaPool.storeMana();
int bookmark = game.bookmarkState();
boolean canPlay = checkPlayability(card, targetPlayer, game, source);
while (canPlay && targetPlayer.canRespond() && !targetPlayer.playCard(card, game, false, new ApprovingObject(source, game))) {
SpellAbility spellAbility = card.getSpellAbility();
if (spellAbility != null) {
spellAbility.getManaCostsToPay().clear();
spellAbility.getManaCostsToPay().addAll(spellAbility.getManaCosts());
// force rollback if card was deemed playable
((ManaCostsImpl) spellAbility.getManaCostsToPay()).forceManaRollback(game, manaPool);
canPlay = checkPlayability(card, targetPlayer, game, source);
} else {
break;
}
}
if (!canPlay) {
game.informPlayers(targetPlayer.getLogName() + " didn't play " + card.getLogName() + " (card can't be played)");
}
// duplicate in case of a new mana pool existing - probably not necessary, but just in case
manaPool.setForcedToPay(false);
// a rollback creates a new mana pool for the player, so it's necessary to find it again
manaPool = targetPlayer.getManaPool();
manaPool.setForcedToPay(false);
game.removeBookmark(bookmark);
targetPlayer.resetStoredBookmark(game);
for (RestrictionEffect eff : game.getContinuousEffects().getRestrictionEffects()) {
if (eff instanceof WordOfCommandCantActivateEffect) {
eff.discard();
break;
}
}
game.getContinuousEffects().removeInactiveEffects(game);
Spell spell = game.getSpell(card.getId());
if (spell != null) {
// If the chosen card is cast as a spell, you control the player while that spell is resolving
spell.setCommandedBy(controller.getId());
}
}
wordOfCommand = game.getSpell(source.getSourceId());
if (wordOfCommand != null) {
// You control the player until Word of Command finishes resolving
wordOfCommand.setCommandedBy(controller.getId());
} else {
CardUtil.takeControlUnderPlayerEnd(game, controller, targetPlayer);
}
return true;
}
return false;
}
use of mage.ApprovingObject in project mage by magefree.
the class WizardsSpellbookEffect method apply.
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
Card card = game.getCard(getTargetPointer().getFirst(game, source));
if (player == null || card == null) {
return false;
}
UUID exileId = CardUtil.getExileZoneId(game, source);
player.moveCardsToExile(card, source, game, true, exileId, CardUtil.getSourceName(game, source));
if (level < 3) {
Card copiedCard = game.copyCard(card, source, source.getControllerId());
if (!player.chooseUse(Outcome.Benefit, "Cast " + copiedCard.getName() + (level == 1 ? "?" : " by paying {1}?"), source, game)) {
return false;
}
SpellAbility spellAbility = player.chooseAbilityForCast(copiedCard, game, level == 2);
if (spellAbility == null) {
return false;
}
game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), Boolean.TRUE);
if (level == 2) {
player.setCastSourceIdWithAlternateMana(copiedCard.getId(), new ManaCostsImpl<>("{1}"), null);
}
player.cast(spellAbility, game, false, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), null);
return true;
}
ExileZone exile = game.getExile().getExileZone(exileId);
if (exile == null || exile.isEmpty()) {
return true;
}
Set<Card> cards = new HashSet<>();
for (Card exiledCard : exile.getCards(game)) {
cards.add(game.copyCard(exiledCard, source, source.getControllerId()));
}
while (!cards.isEmpty()) {
for (Card copiedCard : cards) {
if (!player.chooseUse(Outcome.PlayForFree, "Cast " + copiedCard.getName() + " without paying its mana cost?", source, game)) {
continue;
}
game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), Boolean.TRUE);
player.cast(player.chooseAbilityForCast(copiedCard, game, true), game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), null);
}
if (!player.chooseUse(Outcome.Neutral, "Continue casting exiled cards?", source, game)) {
break;
}
cards.removeIf(c -> game.getState().getZone(c.getId()) != Zone.EXILED);
}
return true;
}
use of mage.ApprovingObject in project mage by magefree.
the class ActivatedAbilityImpl method canActivate.
/**
* Activated ability check, not spells. It contains costs and targets legality too.
* <p>
* WARNING, don't forget to call super.canActivate on override in card's code in most cases.
*
* @param playerId
* @param game
* @return
*/
@Override
public ActivationStatus canActivate(UUID playerId, Game game) {
// 20091005 - 602.2
if (!(hasMoreActivationsThisTurn(game) && (condition == null || condition.apply(game, this)))) {
return ActivationStatus.getFalse();
}
if (!this.checkTargetController(playerId, game)) {
return ActivationStatus.getFalse();
}
// timing check
// 20091005 - 602.5d/602.5e
boolean asInstant;
ApprovingObject approvingObject = game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_AS_INSTANT, this, controllerId, game);
asInstant = approvingObject != null;
asInstant |= (timing == TimingRule.INSTANT);
if (!asInstant && !game.canPlaySorcery(playerId)) {
return ActivationStatus.getFalse();
}
// targets and costs check
if (!costs.canPay(this, this, playerId, game) || !canChooseTarget(game, playerId)) {
return ActivationStatus.getFalse();
}
// all fine, can be activated
// TODO: WTF, must be rework to remove data change in canActivate call
// (it can be called from any place by any player or card).
// game.inCheckPlayableState() can't be a help here cause some cards checking activating status,
// activatorId must be removed
this.activatorId = playerId;
return new ActivationStatus(true, approvingObject);
}
use of mage.ApprovingObject in project mage by magefree.
the class ContinuousEffects method asThough.
/**
* @param objectId object to check
* @param type
* @param affectedAbility null if check full object or ability if check only one ability from that object
* @param controllerId
* @param game
* @return sourceId of the permitting effect if any exists otherwise returns null
*/
public ApprovingObject asThough(UUID objectId, AsThoughEffectType type, Ability affectedAbility, UUID controllerId, Game game) {
// usage check: effect must apply for specific ability only, not to full object (example: PLAY_FROM_NOT_OWN_HAND_ZONE)
if (type.needAffectedAbility() && affectedAbility == null) {
throw new IllegalArgumentException("ERROR, you can't call asThough check to whole object, call it with affected ability instead: " + type);
}
// need it then disable that check or add extra param to AsThoughEffectType like needAffectedAbilityOrFullObject
if (!type.needAffectedAbility() && affectedAbility != null) {
throw new IllegalArgumentException("ERROR, you can't call AsThough check to affected ability, call it with empty affected ability instead: " + type);
}
List<AsThoughEffect> asThoughEffectsList = getApplicableAsThoughEffects(type, game);
if (!asThoughEffectsList.isEmpty()) {
MageObject objectToCheck;
if (affectedAbility != null) {
objectToCheck = affectedAbility.getSourceObject(game);
} else {
objectToCheck = game.getCard(objectId);
}
UUID idToCheck;
if (!type.needPlayCardAbility() && objectToCheck instanceof SplitCardHalf) {
// each split side uses own characteristics to check for playing, all other cases must use main card
// rules:
// 708.4. In every zone except the stack, the characteristics of a split card are those of its two halves combined.
idToCheck = ((SplitCardHalf) objectToCheck).getMainCard().getId();
} else if (!type.needPlayCardAbility() && objectToCheck instanceof AdventureCardSpell) {
// adventure spell uses alternative characteristics for spell/stack, all other cases must use main card
idToCheck = ((AdventureCardSpell) objectToCheck).getMainCard().getId();
} else if (!type.needPlayCardAbility() && objectToCheck instanceof ModalDoubleFacesCardHalf) {
// each mdf side uses own characteristics to check for playing, all other cases must use main card
// rules:
// "If an effect allows you to play a land or cast a spell from among a group of cards,
// you may play or cast a modal double-faced card with any face that fits the criteria
// of that effect. For example, if Sejiri Shelter / Sejiri Glacier is in your graveyard
// and an effect allows you to play lands from your graveyard, you could play Sejiri Glacier.
// That effect doesn't allow you to cast Sejiri Shelter."
idToCheck = ((ModalDoubleFacesCardHalf) objectToCheck).getMainCard().getId();
} else {
idToCheck = objectId;
}
Set<ApprovingObject> possibleApprovingObjects = new HashSet<>();
for (AsThoughEffect effect : asThoughEffectsList) {
Set<Ability> abilities = asThoughEffectsMap.get(type).getAbility(effect.getId());
for (Ability ability : abilities) {
if (affectedAbility == null) {
// applies to full object (one effect can be used in multiple abilities)
if (effect.applies(idToCheck, ability, controllerId, game)) {
if (effect.isConsumable() && !game.inCheckPlayableState()) {
possibleApprovingObjects.add(new ApprovingObject(ability, game));
} else {
return new ApprovingObject(ability, game);
}
}
} else {
// filter play abilities (no need to check it in every effect's code)
if (type.needPlayCardAbility() && !affectedAbility.getAbilityType().isPlayCardAbility()) {
continue;
}
if (effect.applies(idToCheck, affectedAbility, ability, game, controllerId)) {
if (effect.isConsumable() && !game.inCheckPlayableState()) {
possibleApprovingObjects.add(new ApprovingObject(ability, game));
} else {
return new ApprovingObject(ability, game);
}
}
}
}
}
if (possibleApprovingObjects.size() == 1) {
return possibleApprovingObjects.iterator().next();
} else if (possibleApprovingObjects.size() > 1) {
// Select the ability that you use to permit the action
Map<String, String> keyChoices = new HashMap<>();
for (ApprovingObject approvingObject : possibleApprovingObjects) {
MageObject mageObject = game.getObject(approvingObject.getApprovingAbility().getSourceId());
String choiceKey = approvingObject.getApprovingAbility().getId().toString();
String choiceValue;
if (mageObject == null) {
choiceValue = approvingObject.getApprovingAbility().getRule();
} else {
choiceValue = mageObject.getIdName() + ": " + approvingObject.getApprovingAbility().getRule(mageObject.getName());
}
keyChoices.put(choiceKey, choiceValue);
}
Choice choicePermitting = new ChoiceImpl(true);
choicePermitting.setMessage("Choose the permitting object");
choicePermitting.setKeyChoices(keyChoices);
Player player = game.getPlayer(controllerId);
player.choose(Outcome.Detriment, choicePermitting, game);
for (ApprovingObject approvingObject : possibleApprovingObjects) {
if (approvingObject.getApprovingAbility().getId().toString().equals(choicePermitting.getChoiceKey())) {
return approvingObject;
}
}
}
}
return null;
}
use of mage.ApprovingObject in project mage by magefree.
the class MadWizardsLairEffect method apply.
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return false;
}
Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 3));
if (player.drawCards(3, source, game) != cards.size()) {
return true;
}
player.revealCards(source, cards, game);
TargetCardInHand target = new TargetCardInHand(0, 1, StaticFilters.FILTER_CARD_NON_LAND);
player.choose(Outcome.PlayForFree, cards, target, game);
Card card = player.getHand().get(target.getFirstTarget(), game);
if (card == null) {
return true;
}
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
player.cast(player.chooseAbilityForCast(card, game, true), game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
return true;
}
Aggregations