mirror of
https://github.com/correl/mage.git
synced 2024-12-24 03:00:14 +00:00
Merge origin/master
This commit is contained in:
commit
7da69e5064
9 changed files with 248 additions and 10 deletions
|
@ -2187,7 +2187,7 @@ public final class GamePanel extends javax.swing.JPanel {
|
|||
|
||||
public void installComponents() {
|
||||
jLayeredPane.setOpaque(false);
|
||||
jLayeredPane.add(abilityPicker);
|
||||
jLayeredPane.add(abilityPicker, JLayeredPane.MODAL_LAYER);
|
||||
jLayeredPane.add(DialogManager.getManager(gameId), JLayeredPane.MODAL_LAYER, 0);
|
||||
abilityPicker.setVisible(false);
|
||||
}
|
||||
|
|
228
Mage.Sets/src/mage/cards/a/AsForetold.java
Normal file
228
Mage.Sets/src/mage/cards/a/AsForetold.java
Normal file
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are
|
||||
* permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* The views and conclusions contained in the software and documentation are those of the
|
||||
* authors and should not be interpreted as representing official policies, either expressed
|
||||
* or implied, of BetaSteward_at_googlemail.com.
|
||||
*/
|
||||
package mage.cards.a;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.costs.AlternativeCostSourceAbility;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.dynamicvalue.common.StaticValue;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.counters.CounterType;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.watchers.Watcher;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author stravant
|
||||
*
|
||||
* Note, this card is pretty hacky in its implementation due to the fact that the alternative cost system doesn't
|
||||
* really support "once each turn" alternative costs in an obvious way, but it should work in all scenarios as far
|
||||
* as I can see.
|
||||
*/
|
||||
public class AsForetold extends CardImpl {
|
||||
public AsForetold(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}");
|
||||
|
||||
|
||||
// At the beginning of your upkeep, put a time counter on As Foretold.
|
||||
addAbility(
|
||||
new BeginningOfUpkeepTriggeredAbility(
|
||||
new AddCountersSourceEffect(CounterType.TIME.createInstance(), new StaticValue(1), true),
|
||||
TargetController.YOU,
|
||||
/* optional = */false));
|
||||
|
||||
// Once each turn, you may pay {0} rather than pay the mana cost for a spell you cast with converted mana cost X or less, where X is the number of time counters on As Foretold.
|
||||
addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AsForetoldAddAltCostEffect()), new AsForetoldAltCostUsedWatcher());
|
||||
}
|
||||
|
||||
public AsForetold(final AsForetold card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsForetold copy() {
|
||||
return new AsForetold(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to determine what cast objects to apply the alternative cost to
|
||||
*/
|
||||
class SpellWithManaCostLessThanOrEqualToCondition implements Condition {
|
||||
private int counters;
|
||||
|
||||
public SpellWithManaCostLessThanOrEqualToCondition(int counters) {
|
||||
this.counters = counters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
MageObject object = game.getObject(source.getSourceId());
|
||||
return object != null && !object.isLand() && object.getConvertedManaCost() <= counters;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Special AlternativeCostSourceAbility implementation. We wrap the call to askToActivateAlternativeCosts in order to
|
||||
* tell when the alternative cost is used, and mark it as having been used this turn in the watcher
|
||||
*/
|
||||
class AsForetoldAlternativeCost extends AlternativeCostSourceAbility {
|
||||
private UUID sourceAsForetold;
|
||||
|
||||
AsForetoldAlternativeCost(UUID sourceAsForetold, int timeCounters) {
|
||||
super(new ManaCostsImpl("{0}"), new SpellWithManaCostLessThanOrEqualToCondition(timeCounters));
|
||||
this.sourceAsForetold = sourceAsForetold;
|
||||
}
|
||||
|
||||
AsForetoldAlternativeCost(final AsForetoldAlternativeCost ability) {
|
||||
super(ability);
|
||||
this.sourceAsForetold = ability.sourceAsForetold;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsForetoldAlternativeCost copy() {
|
||||
return new AsForetoldAlternativeCost(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean askToActivateAlternativeCosts(Ability ability, Game game) {
|
||||
boolean activated = super.askToActivateAlternativeCosts(ability, game);
|
||||
if (activated) {
|
||||
// Get the watcher
|
||||
AsForetoldAltCostUsedWatcher asForetoldAltCostUsedWatcher =
|
||||
(AsForetoldAltCostUsedWatcher)game.getState().getWatchers()
|
||||
.get("asForetoldAltCostUsedWatcher", sourceAsForetold);
|
||||
|
||||
// Mark as used
|
||||
asForetoldAltCostUsedWatcher.markUsedThisTurn();
|
||||
}
|
||||
return activated;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The continuous effect that adds the option to pay the alternative cost if we haven't used it yet this turn
|
||||
*/
|
||||
class AsForetoldAddAltCostEffect extends ContinuousEffectImpl {
|
||||
public AsForetoldAddAltCostEffect() {
|
||||
super(Duration.WhileOnBattlefield, Outcome.Benefit);
|
||||
staticText = "Once each turn, you may pay {0} rather than pay the mana cost for a spelly ou cast with converted mana cost X or less, where X is the number of time counters on {this}.";
|
||||
}
|
||||
|
||||
public AsForetoldAddAltCostEffect(final AsForetoldAddAltCostEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsForetoldAddAltCostEffect copy() {
|
||||
return new AsForetoldAddAltCostEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
|
||||
if (sourcePermanent != null) {
|
||||
// Get the watcher
|
||||
AsForetoldAltCostUsedWatcher asForetoldAltCostUsedWatcher =
|
||||
(AsForetoldAltCostUsedWatcher)game.getState().getWatchers()
|
||||
.get("asForetoldAltCostUsedWatcher", sourcePermanent.getId());
|
||||
|
||||
// If we haven't used it yet this turn, give the option of using the zero alternative cost
|
||||
if (!asForetoldAltCostUsedWatcher.hasBeenUsedThisTurn()) {
|
||||
int timeCounters = sourcePermanent.getCounters(game).getCount("time");
|
||||
controller.getAlternativeSourceCosts().add(new AsForetoldAlternativeCost(sourcePermanent.getId(), timeCounters));
|
||||
}
|
||||
|
||||
// Return true even if we didn't add the alt cost. We still applied the effect
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasLayer(Layer layer) {
|
||||
return layer == Layer.RulesEffects;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Watcher used as extra storage to record whether a given As Foretold has been used this turn.
|
||||
* Technically speaking this watcher doesn't *watch* any GameEvents, but it does "watch" the
|
||||
* alternative cost being used. That just isn't possible to watch through a game event. It's still
|
||||
* helpfull to co-op the Watcher system for this since it automatically handles ZoneChangeCounter
|
||||
* stuff and resetting the condition at the end of the turn.
|
||||
*/
|
||||
class AsForetoldAltCostUsedWatcher extends Watcher {
|
||||
public AsForetoldAltCostUsedWatcher() {
|
||||
super("asForetoldAltCostUsedWatcher", WatcherScope.CARD);
|
||||
}
|
||||
|
||||
public AsForetoldAltCostUsedWatcher(final AsForetoldAltCostUsedWatcher watcher) {
|
||||
super(watcher);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void watch(GameEvent event, Game game) {
|
||||
// Nothing to do, we explicitly mark used in the alternative cost
|
||||
}
|
||||
|
||||
public boolean hasBeenUsedThisTurn() {
|
||||
return conditionMet();
|
||||
}
|
||||
|
||||
public void markUsedThisTurn() {
|
||||
condition = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsForetoldAltCostUsedWatcher copy() {
|
||||
return new AsForetoldAltCostUsedWatcher(this);
|
||||
}
|
||||
}
|
|
@ -42,6 +42,9 @@ import mage.constants.Zone;
|
|||
import mage.target.TargetPlayer;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.costs.common.DiscardTargetCost;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.target.common.TargetCardInHand;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -61,6 +64,7 @@ public class GreelMindRaker extends CardImpl {
|
|||
// {X}{B}, {tap}, Discard two cards: Target player discards X cards at random.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DiscardTargetEffect(new ManacostVariableValue(), true), new ManaCostsImpl("{X}{B}"));
|
||||
ability.addCost(new TapSourceCost());
|
||||
ability.addCost(new DiscardTargetCost(new TargetCardInHand(2, new FilterCard())));
|
||||
ability.addTarget(new TargetPlayer());
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
|
|
@ -72,6 +72,7 @@ public class Amonkhet extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Angler Drake", 41, Rarity.UNCOMMON, mage.cards.a.AnglerDrake.class));
|
||||
cards.add(new SetCardInfo("Anointer Priest", 3, Rarity.COMMON, mage.cards.a.AnointerPriest.class));
|
||||
cards.add(new SetCardInfo("Archfiend of Ifnir", 78, Rarity.RARE, mage.cards.a.ArchfiendOfIfnir.class));
|
||||
cards.add(new SetCardInfo("As Foretold", 42, Rarity.MYTHIC, mage.cards.a.AsForetold.class));
|
||||
cards.add(new SetCardInfo("Aven Mindcensor", 5, Rarity.RARE, mage.cards.a.AvenMindcensor.class));
|
||||
cards.add(new SetCardInfo("Bontu's Monument", 225, Rarity.UNCOMMON, mage.cards.b.BontusMonument.class));
|
||||
cards.add(new SetCardInfo("Canyon Slough", 239, Rarity.RARE, mage.cards.c.CanyonSlough.class));
|
||||
|
|
|
@ -286,6 +286,17 @@ public abstract class AbilityImpl implements Ability {
|
|||
}
|
||||
}
|
||||
|
||||
// 117.6. Some mana costs contain no mana symbols. This represents an unpayable cost. An ability can
|
||||
// also have an unpayable cost if its cost is based on the mana cost of an object with no mana cost.
|
||||
// Attempting to cast a spell or activate an ability that has an unpayable cost is a legal action.
|
||||
// However, attempting to pay an unpayable cost is an illegal action.
|
||||
//
|
||||
// We apply this now, *AFTER* the user has made the choice to pay an alternative cost for the
|
||||
// spell. You can also still cast a spell with an unplayable cost by... not paying it's mana cost.
|
||||
if (getAbilityType() == AbilityType.SPELL && getManaCostsToPay().isEmpty() && !noMana) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 20121001 - 601.2b
|
||||
// If the spell has a variable cost that will be paid as it's being cast (such as an {X} in
|
||||
// its mana cost; see rule 107.3), the player announces the value of that variable.
|
||||
|
|
|
@ -61,8 +61,8 @@ public abstract class EffectImpl implements Effect {
|
|||
public EffectImpl(final EffectImpl effect) {
|
||||
this.id = effect.id;
|
||||
this.outcome = effect.outcome;
|
||||
this.effectType = effect.effectType;
|
||||
this.staticText = effect.staticText;
|
||||
this.effectType = effect.effectType;
|
||||
this.targetPointer = effect.targetPointer.copy();
|
||||
if (effect.values != null) {
|
||||
values = new HashMap<>();
|
||||
|
|
|
@ -1281,9 +1281,6 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
if (Zone.GRAVEYARD == zone && canPlayCardsFromGraveyard()) {
|
||||
for (ActivatedAbility ability : candidateAbilites.getPlayableAbilities(Zone.HAND)) {
|
||||
if (canUse || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) {
|
||||
if (ability.getManaCosts().isEmpty() && ability.getCosts().isEmpty() && ability instanceof SpellAbility) {
|
||||
continue; // You can't play spells from graveyard that have no costs
|
||||
}
|
||||
if (ability.canActivate(playerId, game)) {
|
||||
output.put(ability.getId(), ability);
|
||||
}
|
||||
|
@ -1293,9 +1290,6 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
if (zone != Zone.BATTLEFIELD && game.getContinuousEffects().asThough(object.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, this.getId(), game)) {
|
||||
for (Ability ability : candidateAbilites) {
|
||||
if (canUse || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) {
|
||||
if (ability.getManaCosts().isEmpty() && ability.getCosts().isEmpty() && ability instanceof SpellAbility && !(Objects.equals(ability.getSourceId(), getCastSourceIdWithAlternateMana()))) {
|
||||
continue; // You can't play spells that have no costs, unless you can play them without paying their mana costs
|
||||
}
|
||||
ability.setControllerId(this.getId());
|
||||
if (ability instanceof ActivatedAbility && ability.getZone().match(Zone.HAND)
|
||||
&& ((ActivatedAbility) ability).canActivate(playerId, game)) {
|
||||
|
|
|
@ -67,7 +67,7 @@ my $toPrint = '';
|
|||
|
||||
foreach my $card (sort cardSort @setCards) {
|
||||
my $className = toCamelCase(@{$card}[0]);
|
||||
my $currentFileName = "../Mage.Sets/src/mage/sets/" . $knownSets{$setName} . "/" . $className . ".java";
|
||||
my $currentFileName = "../Mage.Sets/src/mage/cards/" . lc(substr($className, 0, 1)) . "/" . $className . ".java";
|
||||
if (-e $currentFileName) {
|
||||
if ($toPrint) {
|
||||
$toPrint .= "\n";
|
||||
|
|
|
@ -94,7 +94,7 @@ foreach my $card (sort cardSort @setCards) {
|
|||
|
||||
$cardNames {@{$card}[0]} = 1;
|
||||
|
||||
my $currentFileName = "../Mage.Sets/src/mage/sets/" . $knownSets{$setName} . "/" . $className . ".java";
|
||||
my $currentFileName = "../Mage.Sets/src/mage/cards/" . lc(substr($className, 0, 1)) . "/" . $className . ".java";
|
||||
if(! -e $currentFileName) {
|
||||
$cardNames {@{$card}[0]} = 0;
|
||||
if ($toPrint) {
|
||||
|
|
Loading…
Reference in a new issue