This commit is contained in:
Evan Kranzler 2019-01-07 22:02:47 -05:00
commit 32b800d99e
17 changed files with 190 additions and 224 deletions

View file

@ -5,7 +5,6 @@
*/
package mage.abilities.costs.common;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.costs.Cost;
import mage.abilities.costs.CostImpl;
@ -16,8 +15,9 @@ import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetCardInHand;
import java.util.UUID;
/**
*
* @author jeffwadsworth
*/
@ -40,7 +40,7 @@ public class PutCardFromHandOnTopOfLibraryCost extends CostImpl {
if (targetCardInHand.canChoose(controllerId, game)
&& controller.choose(Outcome.PreventDamage, targetCardInHand, sourceId, game)) {
card = game.getCard(targetCardInHand.getFirstTarget());
paid = controller.moveCardToLibraryWithInfo(card, sourceId, game, Zone.HAND, true, true);
paid = card != null && controller.moveCardToLibraryWithInfo(card, sourceId, game, Zone.HAND, true, true);
}
return paid;
}

View file

@ -1,7 +1,5 @@
package mage.abilities.keyword;
import java.util.UUID;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
@ -19,18 +17,19 @@ import mage.target.Target;
import mage.target.common.TargetControlledCreaturePermanent;
import mage.util.CardUtil;
import java.util.UUID;
/**
*
* 702.46. Offering # 702.46a Offering is a static ability of a card that
* functions in any zone from which the card can be cast. "[Subtype] offering"
* means "You may cast this card any time you could cast an instant by
* sacrificing a [subtype] permanent. If you do, the total cost to cast this
* card is reduced by the sacrificed permanent's mana cost." #
*
* <p>
* 702.46b The permanent is sacrificed at the same time the spell is announced
* (see rule 601.2a). The total cost of the spell is reduced by the sacrificed
* permanent's mana cost (see rule 601.2e). #
*
* <p>
* 702.46c Generic mana in the sacrificed permanent's mana cost reduces generic
* mana in the total cost to cast the card with offering. Colored mana in the
* sacrificed permanent's mana cost reduces mana of the same color in the total
@ -39,7 +38,6 @@ import mage.util.CardUtil;
* cost of the card with offering, or is in excess of the card's colored mana
* cost, reduces that much generic mana in the total cost. #
*
*
* @author LevelX2
*/
public class OfferingAbility extends StaticAbility {
@ -47,7 +45,6 @@ public class OfferingAbility extends StaticAbility {
private FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent();
/**
*
* @param subtype name of the subtype that can be offered
*/
public OfferingAbility(SubType subtype) {
@ -107,7 +104,7 @@ class OfferingAsThoughEffect extends AsThoughEffectImpl {
public boolean applies(UUID sourceId, Ability affectedAbility, Ability source, Game game, UUID playerId) {
if (sourceId.equals(source.getSourceId())) {
Card card = game.getCard(sourceId);
if (!card.isOwnedBy(source.getControllerId())) {
if (card == null || !card.isOwnedBy(source.getControllerId())) {
return false;
}
// because can activate is always called twice, result from first call will be used
@ -129,6 +126,9 @@ class OfferingAsThoughEffect extends AsThoughEffectImpl {
}
FilterControlledCreaturePermanent filter = ((OfferingAbility) source).getFilter();
Card spellToCast = game.getCard(source.getSourceId());
if (spellToCast == null) {
return false;
}
Player player = game.getPlayer(source.getControllerId());
if (player != null && !CardUtil.isCheckPlayableMode(affectedAbility)
&& player.chooseUse(Outcome.Benefit, "Offer a " + filter.getMessage() + " to cast " + spellToCast.getName() + '?', source, game)) {
@ -146,7 +146,6 @@ class OfferingAsThoughEffect extends AsThoughEffectImpl {
game.getState().setValue("offering_ok_" + card.getId(), true);
game.getState().setValue("offering_Id_" + card.getId(), activationId);
return true;
}
} else {
game.getState().setValue("offering_" + card.getId(), true);
@ -201,7 +200,7 @@ class OfferingCostReductionEffect extends CostModificationEffectImpl {
Card card = game.getCard(source.getSourceId());
if (card != null) {
Object object = game.getState().getValue("offering_Id_" + card.getId());
if (object != null && ((UUID) object).equals(this.activationId) && offeredPermanent.getPermanent(game) != null) {
if (object != null && object.equals(this.activationId) && offeredPermanent.getPermanent(game) != null) {
return true;
}
}

View file

@ -619,9 +619,7 @@ public abstract class PlayerImpl implements Player, Serializable {
return false;
}
}
if (hasProtectionFrom(source, game)) {
return false;
}
return !hasProtectionFrom(source, game);
}
return true;
@ -1122,6 +1120,9 @@ public abstract class PlayerImpl implements Player, Serializable {
@Override
public boolean playLand(Card card, Game game, boolean ignoreTiming) {
// Check for alternate casting possibilities: e.g. land with Morph
if (card == null) {
return false;
}
ActivatedAbility playLandAbility = null;
boolean found = false;
for (Ability ability : card.getAbilities()) {
@ -1342,7 +1343,7 @@ public abstract class PlayerImpl implements Player, Serializable {
switch (((SpellAbility) ability).getSpellAbilityType()) {
case SPLIT_FUSED:
if (zone == Zone.HAND) {
if (((SpellAbility) ability).canChooseTarget(game)) {
if (ability.canChooseTarget(game)) {
useable.put(ability.getId(), (SpellAbility) ability);
}
}
@ -1456,37 +1457,39 @@ public abstract class PlayerImpl implements Player, Serializable {
for (ActivatedAbility ability : otherAbilities) {
if (canUse || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) {
Card card = game.getCard(ability.getSourceId());
if (card.isSplitCard() && ability instanceof FlashbackAbility) {
FlashbackAbility flashbackAbility;
// Left Half
if (card.isInstant()) {
flashbackAbility = new FlashbackAbility(((SplitCard) card).getLeftHalfCard().getManaCost(), TimingRule.INSTANT);
} else {
flashbackAbility = new FlashbackAbility(((SplitCard) card).getLeftHalfCard().getManaCost(), TimingRule.SORCERY);
}
flashbackAbility.setSourceId(card.getId());
flashbackAbility.setControllerId(card.getOwnerId());
flashbackAbility.setSpellAbilityType(SpellAbilityType.SPLIT_LEFT);
flashbackAbility.setAbilityName(((SplitCard) card).getLeftHalfCard().getName());
if (flashbackAbility.canActivate(playerId, game).canActivate()) {
useable.put(flashbackAbility.getId(), flashbackAbility);
}
// Right Half
if (card.isInstant()) {
flashbackAbility = new FlashbackAbility(((SplitCard) card).getRightHalfCard().getManaCost(), TimingRule.INSTANT);
} else {
flashbackAbility = new FlashbackAbility(((SplitCard) card).getRightHalfCard().getManaCost(), TimingRule.SORCERY);
}
flashbackAbility.setSourceId(card.getId());
flashbackAbility.setControllerId(card.getOwnerId());
flashbackAbility.setSpellAbilityType(SpellAbilityType.SPLIT_RIGHT);
flashbackAbility.setAbilityName(((SplitCard) card).getRightHalfCard().getName());
if (flashbackAbility.canActivate(playerId, game).canActivate()) {
useable.put(flashbackAbility.getId(), flashbackAbility);
}
if (card != null) {
if (card.isSplitCard() && ability instanceof FlashbackAbility) {
FlashbackAbility flashbackAbility;
// Left Half
if (card.isInstant()) {
flashbackAbility = new FlashbackAbility(((SplitCard) card).getLeftHalfCard().getManaCost(), TimingRule.INSTANT);
} else {
flashbackAbility = new FlashbackAbility(((SplitCard) card).getLeftHalfCard().getManaCost(), TimingRule.SORCERY);
}
flashbackAbility.setSourceId(card.getId());
flashbackAbility.setControllerId(card.getOwnerId());
flashbackAbility.setSpellAbilityType(SpellAbilityType.SPLIT_LEFT);
flashbackAbility.setAbilityName(((SplitCard) card).getLeftHalfCard().getName());
if (flashbackAbility.canActivate(playerId, game).canActivate()) {
useable.put(flashbackAbility.getId(), flashbackAbility);
}
// Right Half
if (card.isInstant()) {
flashbackAbility = new FlashbackAbility(((SplitCard) card).getRightHalfCard().getManaCost(), TimingRule.INSTANT);
} else {
flashbackAbility = new FlashbackAbility(((SplitCard) card).getRightHalfCard().getManaCost(), TimingRule.SORCERY);
}
flashbackAbility.setSourceId(card.getId());
flashbackAbility.setControllerId(card.getOwnerId());
flashbackAbility.setSpellAbilityType(SpellAbilityType.SPLIT_RIGHT);
flashbackAbility.setAbilityName(((SplitCard) card).getRightHalfCard().getName());
if (flashbackAbility.canActivate(playerId, game).canActivate()) {
useable.put(flashbackAbility.getId(), flashbackAbility);
}
} else {
useable.put(ability.getId(), ability);
} else {
useable.put(ability.getId(), ability);
}
}
}
}
@ -1690,9 +1693,7 @@ public abstract class PlayerImpl implements Player, Serializable {
leftForUntap = getPermanentsThatCanBeUntapped(game, canBeUntapped, handledEntry.getKey().getKey(), notMoreThanEffectsUsage);
// remove already selected permanents
for (Permanent permanent : selectedToUntap) {
if (leftForUntap.contains(permanent)) {
leftForUntap.remove(permanent);
}
leftForUntap.remove(permanent);
}
} else {
@ -1961,7 +1962,7 @@ public abstract class PlayerImpl implements Player, Serializable {
sourceControllerId = ((Card) source).getOwnerId();
} else if (source instanceof CommandObject) {
sourceControllerId = ((CommandObject) source).getControllerId();
sourceAbilities = ((CommandObject) source).getAbilities();
sourceAbilities = source.getAbilities();
}
} else {
sourceAbilities = ((Permanent) source).getAbilities(game);
@ -2847,9 +2848,7 @@ public abstract class PlayerImpl implements Player, Serializable {
}
}
}
if (canPlayCardByAlternateCost(card, available, ability, game)) {
return true;
}
return canPlayCardByAlternateCost(card, available, ability, game);
}
return false;
}
@ -3582,7 +3581,7 @@ public abstract class PlayerImpl implements Player, Serializable {
case OUTSIDE:
for (Card card : cards) {
if (card instanceof Permanent) {
game.getBattlefield().removePermanent(((Permanent) card).getId());
game.getBattlefield().removePermanent(card.getId());
ZoneChangeEvent event = new ZoneChangeEvent(card.getId(), (source == null ? null : source.getSourceId()),
byOwner ? card.getOwnerId() : getId(), Zone.BATTLEFIELD, Zone.OUTSIDE, appliedEffects);
game.fireEvent(event);
@ -3731,7 +3730,7 @@ public abstract class PlayerImpl implements Player, Serializable {
}
boolean result = false;
// Zone fromZone = game.getState().getZone(card.getId());
if (card.moveToZone(Zone.GRAVEYARD, sourceId, game, fromZone != null ? fromZone == Zone.BATTLEFIELD : false)) {
if (card.moveToZone(Zone.GRAVEYARD, sourceId, game, fromZone != null && fromZone == Zone.BATTLEFIELD)) {
if (!game.isSimulation()) {
if (card instanceof PermanentCard && game.getCard(card.getId()) != null) {
card = game.getCard(card.getId());