Merge origin/master

Conflicts:
	Mage.Sets/src/mage/cards/c/CogworkAssembler.java
This commit is contained in:
Ludwig.Hirth 2017-01-19 17:01:34 +01:00
commit a175ac3a1d
486 changed files with 6577 additions and 6675 deletions

View file

@ -30,6 +30,7 @@ package mage.abilities;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.MageObject;
import mage.MageObjectReference;
import mage.Mana;
@ -76,7 +77,6 @@ import mage.watchers.Watcher;
import org.apache.log4j.Logger;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public abstract class AbilityImpl implements Ability {
@ -197,7 +197,7 @@ public abstract class AbilityImpl implements Ability {
boolean effectResult = effect.apply(game, this);
result &= effectResult;
if (logger.isDebugEnabled()) {
if (!this.getAbilityType().equals(AbilityType.MANA)) {
if (this.getAbilityType() != AbilityType.MANA) {
if (!effectResult) {
if (this.getSourceId() != null) {
MageObject mageObject = game.getObject(this.getSourceId());
@ -267,7 +267,7 @@ public abstract class AbilityImpl implements Ability {
* If the player wishes to splice any cards onto the spell (see rule 702.45), he
* or she reveals those cards in his or her hand.
*/
if (this.abilityType.equals(AbilityType.SPELL)) {
if (this.abilityType == AbilityType.SPELL) {
game.getContinuousEffects().applySpliceEffects(this, game);
}
@ -290,8 +290,8 @@ public abstract class AbilityImpl implements Ability {
// or her intentions to pay any or all of those costs (see rule 601.2e).
// A player can't apply two alternative methods of casting or two alternative costs to a single spell.
if (!activateAlternateOrAdditionalCosts(sourceObject, noMana, controller, game)) {
if (getAbilityType().equals(AbilityType.SPELL)
&& ((SpellAbility) this).getSpellAbilityType().equals(SpellAbilityType.FACE_DOWN_CREATURE)) {
if (getAbilityType() == AbilityType.SPELL
&& ((SpellAbility) this).getSpellAbilityType() == SpellAbilityType.FACE_DOWN_CREATURE) {
return false;
}
}
@ -302,7 +302,7 @@ public abstract class AbilityImpl implements Ability {
VariableManaCost variableManaCost = handleManaXCosts(game, noMana, controller);
String announceString = handleOtherXCosts(game, controller);
// For effects from cards like Void Winnower x costs have to be set
if (this.getAbilityType().equals(AbilityType.SPELL)
if (this.getAbilityType() == AbilityType.SPELL
&& game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.CAST_SPELL_LATE, getId(), getSourceId(), getControllerId()), this)) {
return false;
}
@ -325,7 +325,7 @@ public abstract class AbilityImpl implements Ability {
// and/or zones become the target of a spell trigger at this point; they'll wait to be put on
// the stack until the spell has finished being cast.)
if (sourceObject != null && !this.getAbilityType().equals(AbilityType.TRIGGERED)) { // triggered abilities check this already in playerImpl.triggerAbility
if (sourceObject != null && this.getAbilityType() != AbilityType.TRIGGERED) { // triggered abilities check this already in playerImpl.triggerAbility
sourceObject.adjustTargets(this, game);
}
// Flashback abilities haven't made the choices the underlying spell might need for targeting.
@ -408,7 +408,7 @@ public abstract class AbilityImpl implements Ability {
}
activated = true;
// fire if tapped for mana (may only fire now because else costs of ability itself can be payed with mana of abilities that trigger for that event
if (this.getAbilityType().equals(AbilityType.MANA)) {
if (this.getAbilityType() == AbilityType.MANA) {
for (Cost cost : costs) {
if (cost instanceof TapSourceCost) {
Mana mana = null;
@ -466,10 +466,10 @@ public abstract class AbilityImpl implements Ability {
}
// controller specific alternate spell costs
if (!noMana && !alternativeCostisUsed) {
if (this.getAbilityType().equals(AbilityType.SPELL)
if (this.getAbilityType() == AbilityType.SPELL
// 117.9a Only one alternative cost can be applied to any one spell as its being cast.
// So an alternate spell ability can't be paid with Omniscience
&& !((SpellAbility) this).getSpellAbilityType().equals(SpellAbilityType.BASE_ALTERNATE)) {
&& ((SpellAbility) this).getSpellAbilityType() != SpellAbilityType.BASE_ALTERNATE) {
for (AlternativeSourceCosts alternativeSourceCosts : controller.getAlternativeSourceCosts()) {
if (alternativeSourceCosts.isAvailable(this, game)) {
if (alternativeSourceCosts.askToActivateAlternativeCosts(this, game)) {
@ -489,10 +489,8 @@ public abstract class AbilityImpl implements Ability {
* Handles the setting of non mana X costs
*
* @param controller
*
* @param game
* @return announce message
*
*/
protected String handleOtherXCosts(Game game, Player controller) {
String announceString = null;
@ -873,7 +871,6 @@ public abstract class AbilityImpl implements Ability {
}
/**
*
* @param game
* @param source
* @return
@ -883,7 +880,7 @@ public abstract class AbilityImpl implements Ability {
if (!this.hasSourceObjectAbility(game, source, event)) {
return false;
}
if (zone.equals(Zone.COMMAND)) {
if (zone == Zone.COMMAND) {
if (this.getSourceId() == null) { // commander effects
return true;
}
@ -1027,7 +1024,7 @@ public abstract class AbilityImpl implements Ability {
sb.append("unknown");
}
if (object instanceof Spell && ((Spell) object).getSpellAbilities().size() > 1) {
if (((Spell) object).getSpellAbility().getSpellAbilityType().equals(SpellAbilityType.SPLIT_FUSED)) {
if (((Spell) object).getSpellAbility().getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED) {
Spell spell = (Spell) object;
int i = 0;
for (SpellAbility spellAbility : spell.getSpellAbilities()) {

View file

@ -30,6 +30,7 @@ package mage.abilities.common;
import mage.abilities.StaticAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.EntersBattlefieldEffect;
import mage.constants.EnterEventType;
import mage.constants.Zone;
/**
@ -39,14 +40,18 @@ import mage.constants.Zone;
public class AsEntersBattlefieldAbility extends StaticAbility {
public AsEntersBattlefieldAbility(Effect effect) {
super(Zone.ALL, new EntersBattlefieldEffect(effect));
this(effect, null, EnterEventType.OTHER);
}
public AsEntersBattlefieldAbility(Effect effect, String text) {
super(Zone.ALL, new EntersBattlefieldEffect(effect, text));
this(effect, text, EnterEventType.OTHER);
}
public AsEntersBattlefieldAbility(AsEntersBattlefieldAbility ability) {
public AsEntersBattlefieldAbility(Effect effect, String text, EnterEventType enterEventType) {
super(Zone.ALL, new EntersBattlefieldEffect(effect, null, text, true, false, enterEventType));
}
public AsEntersBattlefieldAbility(final AsEntersBattlefieldAbility ability) {
super(ability);
}

View file

@ -37,7 +37,6 @@ import mage.game.permanent.Permanent;
import mage.game.permanent.PermanentToken;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class DiesTriggeredAbility extends ZoneChangeTriggeredAbility {
@ -69,7 +68,7 @@ public class DiesTriggeredAbility extends ZoneChangeTriggeredAbility {
@Override
public boolean checkEventType(GameEvent event, Game game) {
if (super.checkEventType(event, game)) {
return ((ZoneChangeEvent) event).getFromZone().equals(Zone.BATTLEFIELD) && ((ZoneChangeEvent) event).getToZone().equals(Zone.GRAVEYARD);
return ((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD && ((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD;
}
return false;
}

View file

@ -46,7 +46,7 @@ public class EntersBattlefieldAllTriggeredAbility extends TriggeredAbilityImpl {
protected FilterPermanent filter;
protected String rule;
protected boolean controlled;
protected boolean controlledText;
protected SetTargetPointer setTargetPointer;
/**
@ -71,19 +71,19 @@ public class EntersBattlefieldAllTriggeredAbility extends TriggeredAbilityImpl {
this(zone, effect, filter, optional, rule, false);
}
public EntersBattlefieldAllTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean optional, String rule, boolean controlled) {
this(zone, effect, filter, optional, SetTargetPointer.NONE, rule, controlled);
public EntersBattlefieldAllTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean optional, String rule, boolean controlledText) {
this(zone, effect, filter, optional, SetTargetPointer.NONE, rule, controlledText);
}
public EntersBattlefieldAllTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean optional, SetTargetPointer setTargetPointer, String rule) {
this(zone, effect, filter, optional, setTargetPointer, rule, false);
}
public EntersBattlefieldAllTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean optional, SetTargetPointer setTargetPointer, String rule, boolean controlled) {
public EntersBattlefieldAllTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean optional, SetTargetPointer setTargetPointer, String rule, boolean controlledText) {
super(zone, effect, optional);
this.filter = filter;
this.rule = rule;
this.controlled = controlled;
this.controlledText = controlledText;
this.setTargetPointer = setTargetPointer;
}
@ -91,7 +91,7 @@ public class EntersBattlefieldAllTriggeredAbility extends TriggeredAbilityImpl {
super(ability);
this.filter = ability.filter;
this.rule = ability.rule;
this.controlled = ability.controlled;
this.controlledText = ability.controlledText;
this.setTargetPointer = ability.setTargetPointer;
}
@ -130,7 +130,7 @@ public class EntersBattlefieldAllTriggeredAbility extends TriggeredAbilityImpl {
}
StringBuilder sb = new StringBuilder("Whenever ").append(filter.getMessage());
sb.append(" enters the battlefield");
if (controlled) {
if (controlledText) {
sb.append(" under your control, ");
} else {
sb.append(", ");

View file

@ -36,7 +36,6 @@ import mage.game.events.GameEvent.EventType;
import mage.game.events.ZoneChangeEvent;
/**
*
* @author LevelX2
*/
public class EntersBattlefieldOrLeavesSourceTriggeredAbility extends TriggeredAbilityImpl {
@ -68,7 +67,7 @@ public class EntersBattlefieldOrLeavesSourceTriggeredAbility extends TriggeredAb
}
if (event.getType() == EventType.ZONE_CHANGE && event.getTargetId().equals(this.getSourceId())) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
if (zEvent.getFromZone().equals(Zone.BATTLEFIELD)) {
if (zEvent.getFromZone() == Zone.BATTLEFIELD) {
return true;
}
}

View file

@ -0,0 +1,62 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package mage.abilities.common;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.stack.Spell;
import mage.game.stack.StackObject;
/**
*
* @author fireshoes
*/
public class SpellCounteredControllerTriggeredAbility extends TriggeredAbilityImpl {
public SpellCounteredControllerTriggeredAbility(Effect effect) {
this(effect, false);
}
public SpellCounteredControllerTriggeredAbility(Effect effect, boolean optional) {
super(Zone.BATTLEFIELD, effect, optional);
}
public SpellCounteredControllerTriggeredAbility(final SpellCounteredControllerTriggeredAbility ability) {
super(ability);
}
@Override
public SpellCounteredControllerTriggeredAbility copy() {
return new SpellCounteredControllerTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == EventType.COUNTERED;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
StackObject stackObjectThatCountered = (StackObject) game.getStack().getStackObject(event.getSourceId());
if (stackObjectThatCountered == null) {
stackObjectThatCountered = (StackObject) game.getLastKnownInformation(event.getSourceId(), Zone.STACK);
}
if (stackObjectThatCountered != null && stackObjectThatCountered.getControllerId().equals(getControllerId())) {
StackObject counteredStackObject = (StackObject) game.getLastKnownInformation(event.getTargetId(), Zone.STACK);
return counteredStackObject != null && (counteredStackObject instanceof Spell);
}
return false;
}
@Override
public String getRule() {
return "Whenever a spell or ability you control counters a spell, " + super.getRule();
}
}

View file

@ -32,6 +32,7 @@ import mage.abilities.Ability;
import mage.abilities.condition.Condition;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.mageobject.NamePredicate;
import mage.filter.predicate.other.OwnerIdPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
@ -39,7 +40,6 @@ import mage.game.permanent.Permanent;
*
* @author emerald000
*/
public class MeldCondition implements Condition {
private final String meldWithName;
@ -57,11 +57,8 @@ public class MeldCondition implements Condition {
&& sourcePermanent.getOwnerId().equals(source.getControllerId())) {
FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent();
filter.add(new NamePredicate(this.meldWithName));
for (Permanent meldWithPermanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) {
if (meldWithPermanent.getOwnerId().equals(source.getControllerId())) {
return true;
}
}
filter.add(new OwnerIdPredicate(source.getControllerId()));
return game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) > 0;
}
}
return false;

View file

@ -38,7 +38,6 @@ import mage.constants.AbilityType;
import mage.filter.FilterPermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetControlledPermanent;
/**
*

View file

@ -96,6 +96,7 @@ public class ConditionalManaEffect extends ManaEffect {
}
if (mana != null) {
checkToFirePossibleEvents(mana, game, source);
controller.getManaPool().addMana(mana, game, source);
}
return true;
@ -114,9 +115,6 @@ public class ConditionalManaEffect extends ManaEffect {
} else if (otherwiseEffect != null) {
mana = otherwiseEffect.getMana();
}
if (mana != null) {
checkToFirePossibleEvents(mana, game, source);
}
return mana;
}
}

View file

@ -32,6 +32,7 @@ import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.condition.Condition;
import mage.constants.Duration;
import mage.constants.EnterEventType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
@ -50,6 +51,7 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl {
protected String text;
protected Condition condition;
protected boolean optional;
protected EnterEventType enterEventType;
public static final String SOURCE_CAST_SPELL_ABILITY = "sourceCastSpellAbility";
@ -66,19 +68,25 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl {
}
public EntersBattlefieldEffect(Effect baseEffect, Condition condition, String text, boolean selfScope, boolean optional) {
this(baseEffect, condition, text, selfScope, optional, EnterEventType.OTHER);
}
public EntersBattlefieldEffect(Effect baseEffect, Condition condition, String text, boolean selfScope, boolean optional, EnterEventType enterEventType) {
super(Duration.WhileOnBattlefield, baseEffect.getOutcome(), selfScope);
this.baseEffects.add(baseEffect);
this.enterEventType = enterEventType;
this.text = text;
this.condition = condition;
this.optional = optional;
}
public EntersBattlefieldEffect(EntersBattlefieldEffect effect) {
public EntersBattlefieldEffect(final EntersBattlefieldEffect effect) {
super(effect);
this.baseEffects = effect.baseEffects.copy();
this.text = effect.text;
this.condition = effect.condition;
this.optional = effect.optional;
this.enterEventType = effect.enterEventType;
}
public void addEffect(Effect effect) {
@ -87,7 +95,17 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl {
@Override
public boolean checksEventType(GameEvent event, Game game) {
return EventType.ENTERS_THE_BATTLEFIELD.equals(event.getType());
switch (enterEventType) {
case OTHER:
return EventType.ENTERS_THE_BATTLEFIELD.equals(event.getType());
case SELF:
return EventType.ENTERS_THE_BATTLEFIELD_SELF.equals(event.getType());
case CONTROL:
return EventType.ENTERS_THE_BATTLEFIELD_CONTROL.equals(event.getType());
case COPY:
return EventType.ENTERS_THE_BATTLEFIELD_COPY.equals(event.getType());
}
return false;
}
@Override

View file

@ -0,0 +1,58 @@
package mage.abilities.effects.common;
import mage.Mana;
import mage.abilities.Ability;
import mage.choices.ChoiceColor;
import mage.game.Game;
import mage.players.Player;
import java.util.UUID;
/**
*
* Created by Galatolol
*/
public class AddManaOfAnyColorToManaPoolTargetPlayerEffect extends ManaEffect {
public AddManaOfAnyColorToManaPoolTargetPlayerEffect(String textManaPoolOwner) {
super();
this.staticText = (textManaPoolOwner.equals("his or her")?"that player adds ":"add ") + "one mana of any color" + " to " + textManaPoolOwner + " mana pool";
}
public AddManaOfAnyColorToManaPoolTargetPlayerEffect(final AddManaOfAnyColorToManaPoolTargetPlayerEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
UUID playerId = (UUID) game.getState().getValue(source.getSourceId() + "_player");
Player player = game.getPlayer(playerId);
if (player != null) {
ChoiceColor choice = new ChoiceColor();
while (!player.choose(outcome, choice, game)) {
if (!player.canRespond()) {
return false;
}
}
Mana mana = choice.getMana(1);
if (mana != null) {
checkToFirePossibleEvents(mana, game, source);
player.getManaPool().addMana(mana, game, source);
return true;
}
}
return false;
}
@Override
public AddManaOfAnyColorToManaPoolTargetPlayerEffect copy() {
return new AddManaOfAnyColorToManaPoolTargetPlayerEffect(this);
}
@Override
public Mana getMana(Game game, Ability source) {
return null;
}
}

View file

@ -96,12 +96,16 @@ public class CounterTargetWithReplacementEffect extends OneShotEffect {
switch (zoneDetail) {
case BOTTOM:
sb.append("the bottom");
break;
case TOP:
sb.append("top");
break;
case CHOOSE:
sb.append("top or bottom");
break;
case NONE:
sb.append("<not allowed value>");
break;
}
sb.append(" of its owner's library instead of into that player's graveyard");
}

View file

@ -137,8 +137,8 @@ public class ExileTargetEffect extends OneShotEffect {
}
} else {
StackObject stackObject = game.getStack().getStackObject(targetId);
if (stackObject instanceof Spell && ((Spell) stackObject).getCard() != null) {
toExile.add(((Spell) stackObject).getCard());
if (stackObject instanceof Spell) {
toExile.add((Spell) stackObject);
}
}
}

View file

@ -63,7 +63,7 @@ public abstract class ManaEffect extends OneShotEffect {
* @param source
*/
public void checkToFirePossibleEvents(Mana mana, Game game, Ability source) {
if (source.getAbilityType().equals(AbilityType.MANA)) {
if (source.getAbilityType()==AbilityType.MANA) {
for (Cost cost: source.getCosts()) {
if (cost instanceof TapSourceCost) {
ManaEvent event = new ManaEvent(GameEvent.EventType.TAPPED_FOR_MANA, source.getSourceId(), source.getSourceId(), source.getControllerId(), mana);

View file

@ -27,6 +27,7 @@
*/
package mage.abilities.effects.common;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.abilities.Ability;
@ -93,12 +94,14 @@ public class MeldEffect extends OneShotEffect {
Permanent sourcePermanent = game.getPermanent(sourceId);
Permanent meldWithPermanent = game.getPermanent(meldWithId);
if (sourcePermanent != null && meldWithPermanent != null) {
sourcePermanent.moveToExile(null, "", sourceId, game);
meldWithPermanent.moveToExile(null, "", sourceId, game);
Set<Card> toExile = new HashSet<>();
toExile.add(sourcePermanent);
toExile.add(meldWithPermanent);
controller.moveCards(toExile, Zone.EXILED, source, game);
// Create the meld card and move it to the battlefield.
Card sourceCard = game.getExile().getCard(sourceId, game);
Card meldWithCard = game.getExile().getCard(meldWithId, game);
if (!sourceCard.isCopy() && !meldWithCard.isCopy()) {
if (sourceCard != null && !sourceCard.isCopy() && meldWithCard != null && !meldWithCard.isCopy()) {
meldCard.setOwnerId(controller.getId());
meldCard.setTopHalfCard(meldWithCard, game);
meldCard.setBottomHalfCard(sourceCard, game);
@ -106,7 +109,7 @@ public class MeldEffect extends OneShotEffect {
game.addMeldCard(meldCard.getId(), meldCard);
game.getState().addCard(meldCard);
meldCard.setZone(Zone.EXILED, game);
meldCard.moveToZone(Zone.BATTLEFIELD, sourceId, game, false);
controller.moveCards(meldCard, Zone.BATTLEFIELD, source, game);
}
return true;
}

View file

@ -88,7 +88,7 @@ public class PreventDamageToControllerEffect extends PreventionEffectImpl {
sb.append("combat ");
}
sb.append("damage that would be dealt to you");
if (duration.equals(Duration.EndOfTurn)) {
if (duration == Duration.EndOfTurn) {
sb.append(" this turn");
}
return sb.toString();

View file

@ -25,7 +25,6 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.effects.common;
import mage.abilities.Ability;
@ -42,7 +41,7 @@ public class SwordsToPlowsharesEffect extends OneShotEffect {
public SwordsToPlowsharesEffect() {
super(Outcome.GainLife);
staticText = "Its controller gains life equal to its power";
staticText = "Exile target creature. Its controller gains life equal to its power";
}
public SwordsToPlowsharesEffect(final SwordsToPlowsharesEffect effect) {
@ -60,7 +59,9 @@ public class SwordsToPlowsharesEffect extends OneShotEffect {
if (permanent != null) {
Player player = game.getPlayer(permanent.getControllerId());
if (player != null) {
player.gainLife(permanent.getPower().getValue(), game);
int creaturePower = permanent.getPower().getValue();
permanent.moveToExile(null, null, source.getSourceId(), game);
player.gainLife(creaturePower, game);
}
return true;
}

View file

@ -91,9 +91,8 @@ public class DiscardTargetEffect extends OneShotEffect {
if (player != null) {
player.discard(amount.calculate(game, source, this), randomDiscard, source, game);
}
return true;
}
return false;
return true;
}
@Override

View file

@ -0,0 +1,73 @@
/*
* 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.abilities.effects.common.enterAttribute;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
*
* @author LevelX2
*/
public class EnterAttributeAddChosenSubtypeEffect extends OneShotEffect {
public EnterAttributeAddChosenSubtypeEffect() {
super(Outcome.Benefit);
this.staticText = "{this} is the chosen type in addition to its other types";
}
public EnterAttributeAddChosenSubtypeEffect(final EnterAttributeAddChosenSubtypeEffect effect) {
super(effect);
}
@Override
public EnterAttributeAddChosenSubtypeEffect copy() {
return new EnterAttributeAddChosenSubtypeEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanentEntering(source.getSourceId());
String subtype = (String) game.getState().getValue(source.getSourceId() + "_type");
if (permanent != null && subtype != null) {
MageObject mageObject = permanent.getBasicMageObject(game);
if (!mageObject.getSubtype(null).contains(subtype)) {
mageObject.getSubtype(null).add(subtype);
}
if (!permanent.getSubtype(null).contains(subtype)) {
permanent.getSubtype(null).add(subtype);
}
return true;
}
return false;
}
}

View file

@ -0,0 +1,113 @@
/*
* 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.abilities.effects.common.search;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.CardsImpl;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetCard;
import mage.target.common.TargetCardInLibrary;
/**
*
* @author Styxo
*/
public class SearchLibraryGraveyardPutInHandEffect extends OneShotEffect {
private FilterCard filter;
private boolean forceToSearchBoth;
public SearchLibraryGraveyardPutInHandEffect(FilterCard filter) {
this(filter, false);
}
public SearchLibraryGraveyardPutInHandEffect(FilterCard filter, boolean forceToSearchBoth) {
super(Outcome.Benefit);
this.filter = filter;
this.forceToSearchBoth = forceToSearchBoth;
staticText = "Search your library and" + (forceToSearchBoth ? "" : "/or ") + " graveyard for a card named " + filter.getMessage() + ", reveal it, and put it into your hand. Then shuffle your library";
}
public SearchLibraryGraveyardPutInHandEffect(final SearchLibraryGraveyardPutInHandEffect effect) {
super(effect);
this.filter = effect.filter;
this.forceToSearchBoth = effect.forceToSearchBoth;
}
@Override
public SearchLibraryGraveyardPutInHandEffect copy() {
return new SearchLibraryGraveyardPutInHandEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = source.getSourceObject(game);
Card cardFound = null;
if (controller != null && sourceObject != null) {
if (forceToSearchBoth || controller.chooseUse(outcome, "Search your library for a card named " + filter.getMessage() + "?", source, game)) {
TargetCardInLibrary target = new TargetCardInLibrary(0, 1, filter);
target.clearChosen();
if (controller.searchLibrary(target, game)) {
if (target.getTargets().size() > 0) {
cardFound = game.getCard(target.getFirstTarget());
}
}
controller.shuffleLibrary(source, game);
}
if (cardFound == null && controller.chooseUse(outcome, "Search your graveyard for a card named " + filter.getMessage() + "?", source, game)) {
TargetCard target = new TargetCard(0, 1, Zone.GRAVEYARD, filter);
target.clearChosen();
if (controller.choose(outcome, controller.getGraveyard(), target, game)) {
if (target.getTargets().size() > 0) {
cardFound = game.getCard(target.getFirstTarget());
}
}
}
if (cardFound != null) {
controller.revealCards(sourceObject.getIdName(), new CardsImpl(cardFound), game);
controller.moveCards(cardFound, Zone.HAND, source, game);
}
return true;
}
return false;
}
}

View file

@ -0,0 +1,90 @@
/*
* 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.abilities.effects.common.search;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.Filter;
import mage.filter.FilterCard;
import mage.filter.predicate.mageobject.ConvertedManaCostPredicate;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetCardInLibrary;
/**
*
* @author Styxo
*/
public class SearchLibraryWithLessCMCPutInPlayEffect extends OneShotEffect {
private FilterCard filter;
public SearchLibraryWithLessCMCPutInPlayEffect() {
this(new FilterCard());
}
public SearchLibraryWithLessCMCPutInPlayEffect(FilterCard filter) {
super(Outcome.PutCreatureInPlay);
this.filter = filter;
staticText = "Search your library for a " + filter.getMessage() + " with converted mana cost X or less, put it onto the battlefield, then shuffle your library";
}
public SearchLibraryWithLessCMCPutInPlayEffect(final SearchLibraryWithLessCMCPutInPlayEffect effect) {
super(effect);
this.filter = effect.filter;
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
filter.add(new ConvertedManaCostPredicate(Filter.ComparisonType.LessThan, source.getManaCostsToPay().getX() + 1));
TargetCardInLibrary target = new TargetCardInLibrary(filter);
if (controller.searchLibrary(target, game)) {
if (target.getTargets().size() > 0) {
Card card = controller.getLibrary().getCard(target.getFirstTarget(), game);
if (card != null) {
controller.moveCards(card, Zone.BATTLEFIELD, source, game);
}
}
controller.shuffleLibrary(source, game);
}
return true;
}
return false;
}
@Override
public SearchLibraryWithLessCMCPutInPlayEffect copy() {
return new SearchLibraryWithLessCMCPutInPlayEffect(this);
}
}

View file

@ -27,25 +27,23 @@
*/
package mage.abilities.keyword;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.continuous.SourceEffect;
import mage.cards.Card;
import mage.cards.repository.CardRepository;
import mage.constants.CardType;
import mage.constants.DependencyType;
import mage.constants.Duration;
import mage.constants.Layer;
import mage.constants.Outcome;
import mage.constants.SpellAbilityType;
import mage.constants.SubLayer;
import mage.constants.TimingRule;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent;
@ -123,7 +121,7 @@ public class BestowAbility extends SpellAbility {
TargetPermanent auraTarget = new TargetCreaturePermanent();
this.addTarget(auraTarget);
this.addEffect(new AttachEffect(Outcome.BoostCreature));
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BestowTypeChangingEffect());
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BestowEntersBattlefieldEffect());
ability.setRuleVisible(false);
addSubAbility(ability);
}
@ -147,64 +145,60 @@ public class BestowAbility extends SpellAbility {
return "Bestow " + getManaCostsToPay().getText() + " <i>(If you cast this card for its bestow cost, it's an Aura spell with enchant creature. It becomes a creature again if it's not attached to a creature.)</i>";
}
class BestowTypeChangingEffect extends ContinuousEffectImpl implements SourceEffect {
private boolean wasAttached;
public BestowTypeChangingEffect() {
super(Duration.WhileOnBattlefield, Outcome.BoostCreature);
wasAttached = false;
dependencyTypes.add(DependencyType.AuraAddingRemoving);
}
public BestowTypeChangingEffect(final BestowTypeChangingEffect effect) {
super(effect);
this.wasAttached = effect.wasAttached;
}
@Override
public BestowTypeChangingEffect copy() {
return new BestowTypeChangingEffect(this);
}
@Override
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null) {
switch (layer) {
case TypeChangingEffects_4:
if (sublayer == SubLayer.NA) {
if (permanent.getAttachedTo() == null) {
if (wasAttached && permanent.getSubtype(game).contains("Aura")) {
permanent.getSubtype(game).remove("Aura");
wasAttached = false;
}
} else {
permanent.getCardType().remove(CardType.CREATURE);
permanent.getSubtype(game).retainAll(CardRepository.instance.getLandTypes());
if (!permanent.getSubtype(game).contains("Aura")) {
permanent.getSubtype(game).add("Aura");
}
wasAttached = true;
}
}
break;
static public void becomeCreature(Permanent permanent, Game game) {
if (permanent != null) {
MageObject basicObject = permanent.getBasicMageObject(game);
if (basicObject != null) {
basicObject.getSubtype(null).remove("Aura");
if (!basicObject.getCardType().contains(CardType.CREATURE)) {
basicObject.getCardType().add(CardType.CREATURE);
}
return true;
}
return false;
}
permanent.getSubtype(null).remove("Aura");
if (!permanent.getCardType().contains(CardType.CREATURE)) {
permanent.getCardType().add(CardType.CREATURE);
}
@Override
public boolean apply(Game game, Ability source) {
return false;
}
}
}
@Override
public boolean hasLayer(Layer layer) {
return layer == Layer.TypeChangingEffects_4;
class BestowEntersBattlefieldEffect extends ReplacementEffectImpl {
public BestowEntersBattlefieldEffect() {
super(Duration.WhileOnBattlefield, Outcome.Neutral);
}
public BestowEntersBattlefieldEffect(final BestowEntersBattlefieldEffect effect) {
super(effect);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return EventType.ENTERS_THE_BATTLEFIELD_SELF.equals(event.getType());
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
return event.getTargetId().equals(source.getSourceId());
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Permanent bestowPermanent = game.getPermanentEntering(source.getSourceId());
if (bestowPermanent != null) {
if (bestowPermanent.getSubtype(game).contains("Aura")) {
MageObject basicObject = bestowPermanent.getBasicMageObject(game);
basicObject.getSubtype(null).add("Aura");
basicObject.getCardType().remove(CardType.CREATURE);
}
}
return false;
}
@Override
public BestowEntersBattlefieldEffect copy() {
return new BestowEntersBattlefieldEffect(this);
}
}

View file

@ -6,6 +6,7 @@
package mage.abilities.keyword;
import java.util.UUID;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.SpecialAction;
@ -30,7 +31,6 @@ import mage.target.Target;
import mage.target.common.TargetControlledPermanent;
/**
*
* @author LevelX2
*/
public class ImproviseAbility extends SimpleStaticAbility implements AlternateManaPaymentAbility {
@ -59,7 +59,7 @@ public class ImproviseAbility extends SimpleStaticAbility implements AlternateMa
public void addSpecialAction(Ability source, Game game, ManaCost unpaid) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null && game.getBattlefield().contains(filterUntapped, controller.getId(), 1, game)) {
if (source.getAbilityType().equals(AbilityType.SPELL) && unpaid.getMana().getGeneric() > 0) {
if (source.getAbilityType() == AbilityType.SPELL && unpaid.getMana().getGeneric() > 0) {
SpecialAction specialAction = new ImproviseSpecialAction(unpaid);
specialAction.setControllerId(source.getControllerId());
specialAction.setSourceId(source.getSourceId());

View file

@ -30,7 +30,6 @@ package mage.abilities.keyword;
import java.util.UUID;
import mage.MageObject;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.StaticAbility;
import mage.cards.Card;
import mage.constants.CardType;

View file

@ -49,7 +49,6 @@ import mage.constants.Zone;
import mage.counters.Counter;
import mage.counters.Counters;
import mage.game.*;
import mage.game.command.Commander;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent;

View file

@ -230,9 +230,7 @@ public class CardsImpl extends LinkedHashSet<UUID> implements Cards, Serializabl
Map<String, Card> cards = new HashMap<>();
for (UUID cardId : this) {
Card card = game.getCard(cardId);
if (!cards.containsKey(card.getName())) {
cards.put(card.getName(), card);
}
cards.putIfAbsent(card.getName(), card);
}
return cards.values();
}

View file

@ -406,7 +406,7 @@ public abstract class ExpansionSet implements Serializable {
Iterator<CardInfo> iterator = savedCardsInfos.iterator();
while (iterator.hasNext()) {
CardInfo next = iterator.next();
if (Integer.valueOf(next.getCardNumber()) > maxCardNumberInBooster) {
if (Integer.valueOf(next.getCardNumber()) > maxCardNumberInBooster && !rarity.equals(Rarity.LAND)) {
iterator.remove();
}
}

View file

@ -55,13 +55,13 @@ public abstract class MeldCard extends CardImpl {
halves = new CardsImpl();
}
public MeldCard(MeldCard card) {
public MeldCard(final MeldCard card) {
super(card);
this.topHalfCard = card.topHalfCard;
this.bottomHalfCard = card.bottomHalfCard;
this.topLastZoneChangeCounter = card.topLastZoneChangeCounter;
this.bottomLastZoneChangeCounter = card.bottomLastZoneChangeCounter;
this.halves = new CardsImpl(halves);
this.halves = new CardsImpl(card.halves);
this.isMelded = card.isMelded;
}
@ -211,4 +211,5 @@ public abstract class MeldCard extends CardImpl {
public Cards getHalves() {
return halves;
}
}

View file

@ -60,7 +60,7 @@ public enum CardRepository {
// raise this if db structure was changed
private static final long CARD_DB_VERSION = 50;
// raise this if new cards were added to the server
private static final long CARD_CONTENT_VERSION = 67;
private static final long CARD_CONTENT_VERSION = 68;
private final TreeSet<String> landTypes = new TreeSet();
private Dao<CardInfo, Object> cardDao;
private Set<String> classNames;

View file

@ -16,7 +16,7 @@ public class ExpansionInfo {
@DatabaseField(unique = true)
protected String name;
@DatabaseField(unique = true)
@DatabaseField(id = true,unique = true)
protected String code;
@DatabaseField
protected String blockName;

View file

@ -0,0 +1,12 @@
package mage.constants;
/**
*
* @author LevelX2
*/
public enum EnterEventType {
SELF,
CONTROL,
COPY,
OTHER
}

View file

@ -47,4 +47,7 @@ public enum Zone {
return super.toString();
}
public static boolean isPublicZone(Zone zone) {
return GRAVEYARD.equals(zone) || BATTLEFIELD.equals(zone) || STACK.equals(zone) || EXILED.equals(zone) || COMMAND.equals(zone);
}
}

View file

@ -73,13 +73,6 @@ public class Counter implements Serializable {
this.count = counter.count;
}
/**
* Increases the {@code count} by 1
*/
public void increase() {
count++;
}
/**
* Adds the passed in {@code amount} to the {@code count}
*

View file

@ -24,8 +24,7 @@
* 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.counters;
import java.io.Serializable;
@ -35,15 +34,15 @@ import java.util.List;
import java.util.Map;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class Counters extends HashMap<String, Counter> implements Serializable {
public Counters() {}
public Counters() {
}
public Counters(final Counters counters) {
for (Map.Entry<String, Counter> entry: counters.entrySet()) {
for (Map.Entry<String, Counter> entry : counters.entrySet()) {
this.put(entry.getKey(), entry.getValue().copy());
}
}
@ -52,17 +51,8 @@ public class Counters extends HashMap<String, Counter> implements Serializable {
return new Counters(this);
}
public void addCounter(String name) {
if (!this.containsKey(name)) {
this.put(name, new Counter(name));
}
this.get(name).increase();
}
public void addCounter(String name, int amount) {
if (!this.containsKey(name)) {
this.put(name, new Counter(name));
}
putIfAbsent(name, new Counter(name));
this.get(name).add(amount);
}
@ -100,13 +90,14 @@ public class Counters extends HashMap<String, Counter> implements Serializable {
return false;
}
public void removeAllCounters(CounterType counterType){
public void removeAllCounters(CounterType counterType) {
removeAllCounters(counterType.getName());
}
public void removeAllCounters(String name){
if (this.containsKey(name)){
public void removeAllCounters(String name) {
if (this.containsKey(name)) {
this.remove(name);
}
}
@ -130,9 +121,9 @@ public class Counters extends HashMap<String, Counter> implements Serializable {
public List<BoostCounter> getBoostCounters() {
List<BoostCounter> boosters = new ArrayList<>();
for (Counter counter: this.values()) {
for (Counter counter : this.values()) {
if (counter instanceof BoostCounter) {
boosters.add((BoostCounter)counter);
boosters.add((BoostCounter) counter);
}
}
return boosters;

View file

@ -27,7 +27,6 @@
*/
package mage.game;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@ -38,7 +37,6 @@ import mage.abilities.effects.common.InfoEffect;
import mage.abilities.effects.common.continuous.CommanderReplacementEffect;
import mage.abilities.effects.common.cost.CommanderCostModification;
import mage.cards.Card;
import mage.cards.Cards;
import mage.constants.MultiplayerAttackOption;
import mage.constants.PhaseStep;
import mage.constants.RangeOfInfluence;
@ -49,11 +47,8 @@ import mage.watchers.common.CommanderInfoWatcher;
public abstract class GameCommanderImpl extends GameImpl {
static boolean CHECK_COMMANDER_DAMAGE = true;
private final Map<UUID, Cards> mulliganedCards = new HashMap<>();
// private final Set<CommanderInfoWatcher> commanderCombatWatcher = new HashSet<>();
// private final Map<UUID, Cards> mulliganedCards = new HashMap<>();
protected boolean checkCommanderDamage = true;
protected boolean alsoHand; // replace commander going to hand
protected boolean alsoLibrary; // replace commander going to library
protected boolean startingPlayerSkipsDraw = true;
@ -67,6 +62,7 @@ public abstract class GameCommanderImpl extends GameImpl {
this.alsoHand = game.alsoHand;
this.alsoLibrary = game.alsoLibrary;
this.startingPlayerSkipsDraw = game.startingPlayerSkipsDraw;
this.checkCommanderDamage = game.checkCommanderDamage;
}
@Override
@ -85,7 +81,7 @@ public abstract class GameCommanderImpl extends GameImpl {
ability.addEffect(new CommanderReplacementEffect(commander.getId(), alsoHand, alsoLibrary));
ability.addEffect(new CommanderCostModification(commander.getId()));
getState().setValue(commander.getId() + "_castCount", 0);
CommanderInfoWatcher watcher = new CommanderInfoWatcher(commander.getId(), CHECK_COMMANDER_DAMAGE);
CommanderInfoWatcher watcher = new CommanderInfoWatcher(commander.getId(), checkCommanderDamage);
getState().getWatchers().add(watcher);
watcher.addCardInfoToCommander(this);
}
@ -227,4 +223,13 @@ public abstract class GameCommanderImpl extends GameImpl {
public void setAlsoLibrary(boolean alsoLibrary) {
this.alsoLibrary = alsoLibrary;
}
public boolean isCheckCommanderDamage() {
return checkCommanderDamage;
}
public void setCheckCommanderDamage(boolean checkCommanderDamage) {
this.checkCommanderDamage = checkCommanderDamage;
}
}

View file

@ -57,6 +57,7 @@ import mage.abilities.effects.ContinuousEffects;
import mage.abilities.effects.Effect;
import mage.abilities.effects.PreventionEffectData;
import mage.abilities.effects.common.CopyEffect;
import mage.abilities.keyword.BestowAbility;
import mage.abilities.keyword.MorphAbility;
import mage.abilities.keyword.TransformAbility;
import mage.abilities.mana.DelayedTriggeredManaAbility;
@ -109,7 +110,6 @@ import mage.game.events.TableEventSource;
import mage.game.permanent.Battlefield;
import mage.game.permanent.Permanent;
import mage.game.permanent.PermanentCard;
import mage.game.permanent.PermanentImpl;
import mage.game.stack.Spell;
import mage.game.stack.SpellStack;
import mage.game.stack.StackObject;
@ -1788,7 +1788,7 @@ public abstract class GameImpl implements Game, Serializable {
}
} else {
SpellAbility spellAbility = perm.getSpellAbility();
if (perm.getSpellAbility().getTargets().isEmpty()) {
if (spellAbility.getTargets().isEmpty()) {
for (Ability ability : perm.getAbilities(this)) {
if ((ability instanceof SpellAbility)
&& SpellAbilityType.BASE_ALTERNATE.equals(((SpellAbility) ability).getSpellAbilityType())
@ -1811,6 +1811,7 @@ public abstract class GameImpl implements Game, Serializable {
if (card != null && card.getCardType().contains(CardType.CREATURE)) {
UUID wasAttachedTo = perm.getAttachedTo();
perm.attachTo(null, this);
BestowAbility.becomeCreature(perm, this);
fireEvent(new GameEvent(GameEvent.EventType.UNATTACHED, wasAttachedTo, perm.getId(), perm.getControllerId()));
} else if (movePermanentToGraveyardWithInfo(perm)) {
somethingHappened = true;
@ -2676,17 +2677,17 @@ public abstract class GameImpl implements Game, Serializable {
card.setZone(Zone.GRAVEYARD, this);
player.getGraveyard().add(card);
}
for (PermanentCard card : battlefield) {
card.setZone(Zone.BATTLEFIELD, this);
card.setOwnerId(ownerId);
PermanentCard permanent = new PermanentCard(card.getCard(), ownerId, this);
getPermanentsEntering().put(permanent.getId(), permanent);
permanent.entersBattlefield(permanent.getId(), this, Zone.OUTSIDE, false);
getBattlefield().addPermanent(permanent);
getPermanentsEntering().remove(permanent.getId());
permanent.removeSummoningSickness();
if (card.isTapped()) {
permanent.setTapped(true);
for (PermanentCard permanentCard : battlefield) {
permanentCard.setZone(Zone.BATTLEFIELD, this);
permanentCard.setOwnerId(ownerId);
PermanentCard newPermanent = new PermanentCard(permanentCard.getCard(), ownerId, this);
getPermanentsEntering().put(newPermanent.getId(), newPermanent);
newPermanent.entersBattlefield(newPermanent.getId(), this, Zone.OUTSIDE, false);
getBattlefield().addPermanent(newPermanent);
getPermanentsEntering().remove(newPermanent.getId());
newPermanent.removeSummoningSickness();
if (permanentCard.isTapped()) {
newPermanent.setTapped(true);
}
}
applyEffects();

View file

@ -64,9 +64,7 @@ public class LookedAt extends HashMap<String, Cards> implements Serializable, Co
}
public Cards createLookedAt(String name) {
if (!this.containsKey(name)) {
this.put(name, new CardsImpl());
}
putIfAbsent(name, new CardsImpl());
return this.get(name);
}

View file

@ -204,8 +204,7 @@ public class ZonesHandler {
// If we can't find the card we can't remove it.
return false;
}
// If needed take attributes from the spell (e.g. color of spell was changed)
card = takeAttributesFromSpell(card, event, game);
boolean success = false;
if (info.faceDown) {
card.setFaceDown(true, game);
@ -213,6 +212,8 @@ public class ZonesHandler {
if (!game.replaceEvent(event)) {
Zone fromZone = event.getFromZone();
if (event.getToZone() == Zone.BATTLEFIELD) {
// If needed take attributes from the spell (e.g. color of spell was changed)
card = takeAttributesFromSpell(card, event, game);
// controlling player can be replaced so use event player now
Permanent permanent;
if (card instanceof MeldCard) {
@ -232,7 +233,6 @@ public class ZonesHandler {
if (info.faceDown) {
card.setFaceDown(false, game);
}
// make sure the controller of all continuous effects of this card are switched to the current controller
game.setScopeRelevant(true);
game.getContinuousEffects().setController(permanent.getId(), permanent.getControllerId());
@ -282,16 +282,12 @@ public class ZonesHandler {
}
private static Card takeAttributesFromSpell(Card card, ZoneChangeEvent event, Game game) {
card = card.copy();
if (Zone.STACK.equals(event.getFromZone())) {
Spell spell = game.getStack().getSpell(event.getTargetId());
if (spell != null && !spell.isFaceDown(game)) {
boolean doCopy = false;
if (!card.getColor(game).equals(spell.getColor(game))) {
doCopy = true;
}
if (doCopy) {
// the card that is referenced to in the permanent is copied and the spell attributes are set to this copied card
card = card.copy();
card.getColor(game).setColor(spell.getColor(game));
}
}

View file

@ -24,12 +24,12 @@
* 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.game.events;
import java.util.ArrayList;
import java.util.UUID;
import mage.constants.EnterEventType;
import static mage.constants.EnterEventType.SELF;
import mage.constants.Zone;
import mage.game.permanent.Permanent;
@ -43,17 +43,24 @@ public class EntersTheBattlefieldEvent extends GameEvent {
private Permanent target;
public EntersTheBattlefieldEvent(Permanent target, UUID sourceId, UUID playerId, Zone fromZone) {
super(EventType.ENTERS_THE_BATTLEFIELD, target.getId(), sourceId, playerId);
this.fromZone = fromZone;
this.target = target;
this(target, sourceId, playerId, fromZone, EnterEventType.OTHER);
}
public EntersTheBattlefieldEvent(Permanent target, UUID sourceId, UUID playerId, Zone fromZone, ArrayList<UUID> appliedEffects) {
public EntersTheBattlefieldEvent(Permanent target, UUID sourceId, UUID playerId, Zone fromZone, EnterEventType enterType) {
super(EventType.ENTERS_THE_BATTLEFIELD, target.getId(), sourceId, playerId);
this.fromZone = fromZone;
if (appliedEffects != null) {
this.appliedEffects = appliedEffects;
switch (enterType) {
case SELF:
type = EventType.ENTERS_THE_BATTLEFIELD_SELF;
break;
case CONTROL:
type = EventType.ENTERS_THE_BATTLEFIELD_CONTROL;
break;
case COPY:
type = EventType.ENTERS_THE_BATTLEFIELD_COPY;
break;
}
this.fromZone = fromZone;
this.target = target;
}
public Zone getFromZone() {

View file

@ -229,7 +229,10 @@ public class GameEvent implements Serializable {
PAID_CUMULATIVE_UPKEEP,
DIDNT_PAY_CUMULATIVE_UPKEEP,
//permanent events
ENTERS_THE_BATTLEFIELD,
ENTERS_THE_BATTLEFIELD_SELF, // 616.1a If any of the replacement and/or prevention effects are self-replacement effects (see rule 614.15), one of them must be chosen. If not, proceed to rule 616.1b.
ENTERS_THE_BATTLEFIELD_CONTROL, // 616.1b
ENTERS_THE_BATTLEFIELD_COPY, // 616.1c
ENTERS_THE_BATTLEFIELD, // 616.1d
TAP, TAPPED, TAPPED_FOR_MANA,
UNTAP, UNTAPPED,
FLIP, FLIPPED,

View file

@ -149,6 +149,8 @@ public interface Permanent extends Card, Controllable {
void reset(Game game);
MageObject getBasicMageObject(Game game);
boolean destroy(UUID sourceId, Game game, boolean noRegen);
boolean sacrifice(UUID sourceId, Game game);

View file

@ -28,6 +28,7 @@
package mage.game.permanent;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Abilities;
import mage.abilities.Ability;
import mage.abilities.costs.mana.ManaCost;
@ -44,6 +45,7 @@ import mage.game.events.ZoneChangeEvent;
public class PermanentCard extends PermanentImpl {
protected int maxLevelCounters;
// A copy of the origin card that was cast (this is not the original card, so it's possible to chnage some attribute to this blueprint to change attributes to the permanent if it enters the battlefield with e.g. a subtype)
protected Card card;
// the number this permanent instance had
protected int zoneChangeCounter;
@ -141,6 +143,11 @@ public class PermanentCard extends PermanentImpl {
this.flipCardName = card.getFlipCardName();
}
@Override
public MageObject getBasicMageObject(Game game) {
return card;
}
public Card getCard() {
return card;
}

View file

@ -59,6 +59,7 @@ import mage.cards.CardImpl;
import mage.constants.AsThoughEffectType;
import mage.constants.CardType;
import mage.constants.EffectType;
import mage.constants.EnterEventType;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.counters.Counter;
@ -872,12 +873,18 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
// remove some attributes here, because first apply effects comes later otherwise abilities (e.g. color related) will unintended trigger
MorphAbility.setPermanentToFaceDownCreature(this);
}
EntersTheBattlefieldEvent event = new EntersTheBattlefieldEvent(this, sourceId, getControllerId(), fromZone);
EntersTheBattlefieldEvent event = new EntersTheBattlefieldEvent(this, sourceId, getControllerId(), fromZone, EnterEventType.SELF);
if (game.replaceEvent(event)) {
return false;
}
event = new EntersTheBattlefieldEvent(this, sourceId, getControllerId(), fromZone);
if (!game.replaceEvent(event)) {
if (fireEvent) {
game.addSimultaneousEvent(event);
return true;
}
}
return false;
}

View file

@ -28,6 +28,7 @@
package mage.game.permanent;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.costs.mana.ManaCost;
import mage.game.Game;
@ -92,6 +93,11 @@ public class PermanentToken extends PermanentImpl {
this.tokenDescriptor = token.getTokenDescriptor();
}
@Override
public MageObject getBasicMageObject(Game game) {
return token;
}
public Token getToken() {
return token;
}

View file

@ -27,7 +27,6 @@
*/
package mage.game.permanent.token;
import java.util.Arrays;
import java.util.Collections;
import mage.MageInt;

View file

@ -27,7 +27,6 @@
*/
package mage.game.permanent.token;
import java.util.Arrays;
import java.util.Collections;
import mage.MageInt;

View file

@ -28,7 +28,6 @@
package mage.game.permanent.token;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import mage.MageInt;

View file

@ -27,7 +27,6 @@
*/
package mage.game.permanent.token;
import java.util.Arrays;
import java.util.Collections;
import mage.constants.CardType;

View file

@ -0,0 +1,48 @@
/*
* 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.game.permanent.token;
import mage.MageInt;
import mage.constants.CardType;
/**
*
* @author Styxo
*/
public class GremlinToken extends Token {
public GremlinToken() {
super("Gremlin", "2/2 red Gremlin creature token");
cardType.add(CardType.CREATURE);
this.setOriginalExpansionSetCode("AER");
subtype.add("Gremlin");
color.setRed(true);
power = new MageInt(2);
toughness = new MageInt(2);
}
}

View file

@ -28,7 +28,6 @@
package mage.game.permanent.token;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import mage.MageInt;

View file

@ -28,7 +28,6 @@
package mage.game.permanent.token;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import mage.MageInt;

View file

@ -28,7 +28,6 @@
package mage.game.permanent.token;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import mage.MageInt;

View file

@ -29,7 +29,6 @@
package mage.game.permanent.token;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import mage.MageInt;

View file

@ -27,7 +27,6 @@
*/
package mage.game.permanent.token;
import java.util.Arrays;
import java.util.Collections;
import mage.MageInt;

View file

@ -161,6 +161,7 @@ public class Spell extends StackObjImpl implements Card {
}
}
}
setDoneActivatingManaAbilities(false); // can be activated again maybe during the resolution of the spell (e.g. Metallic Rebuke)
return true;
}
@ -256,8 +257,8 @@ public class Spell extends StackObjImpl implements Card {
Permanent permanent = game.getPermanent(card.getId());
if (permanent != null && permanent instanceof PermanentCard) {
permanent.setSpellAbility(ability); // otherwise spell ability without bestow will be set
((PermanentCard) permanent).getCard().getCardType().add(CardType.CREATURE);
((PermanentCard) permanent).getCard().getSubtype(game).remove("Aura");
card.getCardType().add(CardType.CREATURE);
card.getSubtype(game).remove("Aura");
}
}
return ability.resolve(game);
@ -270,7 +271,15 @@ public class Spell extends StackObjImpl implements Card {
// Aura has no legal target and its a bestow enchantment -> Add it to battlefield as creature
if (this.getSpellAbility() instanceof BestowAbility) {
updateOptionalCosts(0);
return controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null);
if (controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null)) {
Permanent permanent = game.getPermanent(card.getId());
if (permanent != null && permanent instanceof PermanentCard) {
((PermanentCard) permanent).getCard().getCardType().add(CardType.CREATURE);
((PermanentCard) permanent).getCard().getSubtype(game).remove("Aura");
return true;
}
}
return false;
} else {
//20091005 - 608.2b
if (!game.isSimulation()) {

View file

@ -107,7 +107,7 @@ public abstract class Phase implements Serializable {
if (game.isPaused() || game.gameOver(null)) {
return false;
}
if (game.getTurn().isEndTurnRequested() && !step.getType().equals(PhaseStep.CLEANUP)) {
if (game.getTurn().isEndTurnRequested() && step.getType()!=PhaseStep.CLEANUP) {
continue;
}
currentStep = step;

View file

@ -208,9 +208,7 @@ public class Library implements Serializable {
Map<String, Card> cards = new HashMap<>();
for (UUID cardId : library) {
Card card = game.getCard(cardId);
if (!cards.containsKey(card.getName())) {
cards.put(card.getName(), card);
}
cards.putIfAbsent(card.getName(), card);
}
return cards.values();
}

View file

@ -29,53 +29,22 @@ package mage.players;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.*;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import mage.ConditionalMana;
import mage.MageObject;
import mage.Mana;
import mage.abilities.Abilities;
import mage.abilities.AbilitiesImpl;
import mage.abilities.Ability;
import mage.abilities.ActivatedAbility;
import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.Mode;
import mage.abilities.PlayLandAbility;
import mage.abilities.SpecialAction;
import mage.abilities.SpellAbility;
import mage.abilities.TriggeredAbility;
import mage.abilities.*;
import mage.abilities.common.PassAbility;
import mage.abilities.common.delayed.AtTheEndOfTurnStepPostDelayedTriggeredAbility;
import mage.abilities.costs.AdjustingSourceCosts;
import mage.abilities.costs.AlternativeCostSourceAbility;
import mage.abilities.costs.AlternativeSourceCosts;
import mage.abilities.costs.Cost;
import mage.abilities.costs.Costs;
import mage.abilities.costs.OptionalAdditionalSourceCosts;
import mage.abilities.costs.*;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.RestrictionEffect;
import mage.abilities.effects.RestrictionUntapNotMoreThanEffect;
import mage.abilities.effects.common.LoseControlOnOtherPlayersControllerEffect;
import mage.abilities.keyword.ConvokeAbility;
import mage.abilities.keyword.FlashbackAbility;
import mage.abilities.keyword.HexproofAbility;
import mage.abilities.keyword.InfectAbility;
import mage.abilities.keyword.LifelinkAbility;
import mage.abilities.keyword.ProtectionAbility;
import mage.abilities.keyword.ShroudAbility;
import mage.abilities.keyword.*;
import mage.abilities.mana.ActivatedManaAbilityImpl;
import mage.abilities.mana.ManaOptions;
import mage.actions.MageDrawAction;
@ -84,17 +53,7 @@ import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.cards.SplitCard;
import mage.cards.decks.Deck;
import mage.constants.AbilityType;
import mage.constants.AsThoughEffectType;
import mage.constants.CardType;
import mage.constants.ManaType;
import mage.constants.Outcome;
import mage.constants.PhaseStep;
import mage.constants.PlayerAction;
import mage.constants.RangeOfInfluence;
import mage.constants.SpellAbilityType;
import mage.constants.TimingRule;
import mage.constants.Zone;
import mage.constants.*;
import mage.counters.Counter;
import mage.counters.CounterType;
import mage.counters.Counters;
@ -105,12 +64,7 @@ import mage.filter.common.FilterCreatureForCombat;
import mage.filter.common.FilterCreatureForCombatBlock;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.permanent.PermanentIdPredicate;
import mage.game.ExileZone;
import mage.game.Game;
import mage.game.Graveyard;
import mage.game.Table;
import mage.game.ZoneChangeInfo;
import mage.game.ZonesHandler;
import mage.game.*;
import mage.game.combat.CombatGroup;
import mage.game.command.CommandObject;
import mage.game.events.DamagePlayerEvent;
@ -472,7 +426,6 @@ public abstract class PlayerImpl implements Player, Serializable {
/**
* called before apply effects
*
*/
@Override
public void reset() {
@ -701,7 +654,6 @@ public abstract class PlayerImpl implements Player, Serializable {
}
/**
*
* @param amount
* @param source
* @param game
@ -998,7 +950,7 @@ public abstract class PlayerImpl implements Player, Serializable {
if (game == null || ability == null) {
return false;
}
if (!ability.getSpellAbilityType().equals(SpellAbilityType.BASE)) {
if (ability.getSpellAbilityType() != SpellAbilityType.BASE) {
ability = chooseSpellAbilityForCast(ability, game, noMana);
}
//20091005 - 601.2a
@ -1221,7 +1173,7 @@ public abstract class PlayerImpl implements Player, Serializable {
//if player has taken an action then reset all player passed flags
justActivatedType = null;
if (result) {
if (isHuman() && (ability.getAbilityType().equals(AbilityType.SPELL) || ability.getAbilityType().equals(AbilityType.ACTIVATED))) {
if (isHuman() && (ability.getAbilityType() == AbilityType.SPELL || ability.getAbilityType() == AbilityType.ACTIVATED)) {
if (ability.isUsesStack()) { // if the ability does not use the stack (e.g. Suspend) auto pass would go to next phase unintended
setJustActivatedType(ability.getAbilityType());
}
@ -1269,8 +1221,8 @@ public abstract class PlayerImpl implements Player, Serializable {
LinkedHashMap<UUID, ActivatedAbility> useable = new LinkedHashMap<>();
for (Ability ability : object.getAbilities()) {
if (ability instanceof SpellAbility) {
if (((SpellAbility) ability).getSpellAbilityType().equals(SpellAbilityType.SPLIT_FUSED)) {
if (zone.equals(Zone.HAND)) {
if (((SpellAbility) ability).getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED) {
if (zone == Zone.HAND) {
// Fix so you don't need to choose Fuse twice
useable.clear();
useable.put(ability.getId(), (SpellAbility) ability);
@ -1280,7 +1232,7 @@ public abstract class PlayerImpl implements Player, Serializable {
continue;
}
}
if (((SpellAbility) ability).getSpellAbilityType().equals(SpellAbilityType.SPLIT)) {
if (((SpellAbility) ability).getSpellAbilityType() == SpellAbilityType.SPLIT) {
continue;
}
useable.put(ability.getId(), (SpellAbility) ability);
@ -1297,7 +1249,7 @@ public abstract class PlayerImpl implements Player, Serializable {
// ManaOptions availableMana = getManaAvailable(game); // can only be activated if mana calculation works flawless otherwise player can't play spells they could play if calculation would work correctly
// availableMana.addMana(manaPool.getMana());
for (Ability ability : object.getAbilities()) {
if (canUse || ability.getAbilityType().equals(AbilityType.SPECIAL_ACTION)) {
if (canUse || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) {
if (ability.getZone().match(zone)) {
if (ability instanceof ActivatedAbility) {
if (ability instanceof ActivatedManaAbilityImpl) {
@ -1320,9 +1272,9 @@ public abstract class PlayerImpl implements Player, Serializable {
}
}
if (zone != Zone.HAND) {
if (Zone.GRAVEYARD.equals(zone) && canPlayCardsFromGraveyard()) {
if (Zone.GRAVEYARD == zone && canPlayCardsFromGraveyard()) {
for (ActivatedAbility ability : object.getAbilities().getPlayableAbilities(Zone.HAND)) {
if (canUse || ability.getAbilityType().equals(AbilityType.SPECIAL_ACTION)) {
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
}
@ -1334,7 +1286,7 @@ 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 : object.getAbilities()) {
if (canUse || ability.getAbilityType().equals(AbilityType.SPECIAL_ACTION)) {
if (canUse || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) {
if (ability.getManaCosts().isEmpty() && ability.getCosts().isEmpty() && ability instanceof SpellAbility && !(ability.getSourceId() == getCastSourceIdWithAlternateMana())) {
continue; // You can't play spells that have no costs, unless you can play them without paying their mana costs
}
@ -1358,7 +1310,7 @@ public abstract class PlayerImpl implements Player, Serializable {
if (otherAbilities != null) {
boolean canUse = !(object instanceof Permanent) || ((Permanent) object).canUseActivatedAbilities(game);
for (ActivatedAbility ability : otherAbilities) {
if (canUse || ability.getAbilityType().equals(AbilityType.SPECIAL_ACTION)) {
if (canUse || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) {
Card card = game.getCard(ability.getSourceId());
if (card.isSplitCard() && ability instanceof FlashbackAbility) {
FlashbackAbility flashbackAbility;
@ -1401,7 +1353,7 @@ public abstract class PlayerImpl implements Player, Serializable {
LinkedHashMap<UUID, ActivatedManaAbilityImpl> useable = new LinkedHashMap<>();
boolean canUse = !(object instanceof Permanent) || ((Permanent) object).canUseActivatedAbilities(game);
for (ActivatedManaAbilityImpl ability : object.getAbilities().getActivatedManaAbilities(zone)) {
if (canUse || ability.getAbilityType().equals(AbilityType.SPECIAL_ACTION)) {
if (canUse || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) {
if (ability.canActivate(playerId, game)) {
useable.put(ability.getId(), ability);
}
@ -2057,7 +2009,7 @@ public abstract class PlayerImpl implements Player, Serializable {
passedUntilEndOfTurn = true;
passedUntilStackResolved = false;
passedUntilEndStepBeforeMyTurn = false;
skippedAtLeastOnce = !PhaseStep.END_TURN.equals(game.getTurn().getStepType());
skippedAtLeastOnce = PhaseStep.END_TURN != game.getTurn().getStepType();
this.skip();
break;
case PASS_PRIORITY_UNTIL_NEXT_TURN: // F4
@ -2088,7 +2040,7 @@ public abstract class PlayerImpl implements Player, Serializable {
passedUntilNextMain = true;
passedUntilStackResolved = false;
passedUntilEndStepBeforeMyTurn = false;
skippedAtLeastOnce = !(game.getTurn().getStepType().equals(PhaseStep.POSTCOMBAT_MAIN) || game.getTurn().getStepType().equals(PhaseStep.PRECOMBAT_MAIN));
skippedAtLeastOnce = !(game.getTurn().getStepType() == PhaseStep.POSTCOMBAT_MAIN || game.getTurn().getStepType() == PhaseStep.PRECOMBAT_MAIN);
this.skip();
break;
case PASS_PRIORITY_UNTIL_STACK_RESOLVED: //F8
@ -2333,7 +2285,6 @@ public abstract class PlayerImpl implements Player, Serializable {
/**
* @param game
* @param appliedEffects
*
* @return true if player won the toss
*/
@Override
@ -2470,7 +2421,6 @@ public abstract class PlayerImpl implements Player, Serializable {
}
/**
*
* @param ability
* @param available if null, it won't be checked if enough mana is available
* @param sourceObject
@ -2608,7 +2558,7 @@ public abstract class PlayerImpl implements Player, Serializable {
if (!(sourceObject instanceof Permanent)) {
Ability sourceAbility = null;
for (Ability landAbility : sourceObject.getAbilities()) {
if (landAbility.getAbilityType().equals(AbilityType.PLAY_LAND)) {
if (landAbility.getAbilityType() == AbilityType.PLAY_LAND) {
sourceAbility = landAbility;
break;
}
@ -2748,9 +2698,7 @@ public abstract class PlayerImpl implements Player, Serializable {
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(playerId)) {
LinkedHashMap<UUID, ActivatedAbility> useableAbilities = getUseableActivatedAbilities(permanent, Zone.BATTLEFIELD, game);
for (ActivatedAbility ability : useableAbilities.values()) {
if (!playableActivated.containsKey(ability.toString())) {
playableActivated.put(ability.toString(), ability);
}
playableActivated.putIfAbsent(ability.toString(), ability);
}
}
// activated abilities from stack objects
@ -2781,10 +2729,8 @@ public abstract class PlayerImpl implements Player, Serializable {
* Creates a list of card ids that are currently playable.<br>
* Used to mark the playable cards in GameView
*
* @return A Set of cardIds that are playable
*
* @param game
*
* @return A Set of cardIds that are playable
*/
@Override
public Set<UUID> getPlayableInHand(Game game
@ -3191,8 +3137,8 @@ public abstract class PlayerImpl implements Player, Serializable {
case HAND:
for (Card card : cards) {
fromZone = game.getState().getZone(card.getId());
boolean hideCard = fromZone.equals(Zone.LIBRARY)
|| (card.isFaceDown(game) && !fromZone.equals(Zone.STACK) && !fromZone.equals(Zone.BATTLEFIELD));
boolean hideCard = fromZone == Zone.LIBRARY
|| (card.isFaceDown(game) && fromZone != Zone.STACK && fromZone != Zone.BATTLEFIELD);
if (moveCardToHandWithInfo(card, source == null ? null : source.getSourceId(), game, !hideCard)) {
successfulMovedCards.add(card);
}
@ -3201,7 +3147,7 @@ public abstract class PlayerImpl implements Player, Serializable {
case EXILED:
for (Card card : cards) {
fromZone = game.getState().getZone(card.getId());
boolean withName = (fromZone.equals(Zone.BATTLEFIELD) || fromZone.equals(Zone.STACK)) || !card.isFaceDown(game);
boolean withName = (fromZone == Zone.BATTLEFIELD || fromZone == Zone.STACK) || !card.isFaceDown(game);
if (moveCardToExileWithInfo(card, null, "", source == null ? null : source.getSourceId(), game, fromZone, withName)) {
successfulMovedCards.add(card);
}
@ -3214,7 +3160,7 @@ public abstract class PlayerImpl implements Player, Serializable {
} else {
fromZone = game.getState().getZone(card.getId());
}
boolean hideCard = fromZone.equals(Zone.HAND) || fromZone.equals(Zone.LIBRARY);
boolean hideCard = fromZone == Zone.HAND || fromZone == Zone.LIBRARY;
if (moveCardToLibraryWithInfo(card, source == null ? null : source.getSourceId(), game, fromZone, true, !hideCard)) {
successfulMovedCards.add(card);
}
@ -3255,7 +3201,7 @@ public abstract class PlayerImpl implements Player, Serializable {
public boolean moveCardToHandWithInfo(Card card, UUID sourceId, Game game, boolean withName) {
boolean result = false;
Zone fromZone = game.getState().getZone(card.getId());
if (fromZone.equals(Zone.BATTLEFIELD) && !(card instanceof Permanent)) {
if (fromZone == Zone.BATTLEFIELD && !(card instanceof Permanent)) {
card = game.getPermanent(card.getId());
}
if (card.moveToZone(Zone.HAND, sourceId, game, false)) {
@ -3345,7 +3291,7 @@ public abstract class PlayerImpl implements Player, Serializable {
public boolean moveCardToGraveyardWithInfo(Card card, UUID sourceId, Game game, Zone fromZone) {
boolean result = false;
// Zone fromZone = game.getState().getZone(card.getId());
if (card.moveToZone(Zone.GRAVEYARD, sourceId, game, fromZone != null ? fromZone.equals(Zone.BATTLEFIELD) : false)) {
if (card.moveToZone(Zone.GRAVEYARD, sourceId, game, fromZone != null ? fromZone == Zone.BATTLEFIELD : false)) {
if (!game.isSimulation()) {
if (card instanceof PermanentCard && game.getCard(card.getId()) != null) {
card = game.getCard(card.getId());
@ -3406,7 +3352,7 @@ public abstract class PlayerImpl implements Player, Serializable {
card = basicCard;
}
}
game.informPlayers(this.getLogName() + " moves " + (withName ? card.getLogName() : "a card face down") + " "
game.informPlayers(this.getLogName() + " moves " + (withName ? card.getLogName() + (card.isCopy() ? " (Copy)" : "") : "a card face down") + " "
+ (fromZone != null ? "from " + fromZone.toString().toLowerCase(Locale.ENGLISH) + " " : "") + "to the exile zone");
}
result = true;

View file

@ -36,6 +36,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.cards.Card;
@ -49,7 +50,6 @@ import mage.players.Player;
import mage.util.RandomUtil;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public abstract class TargetImpl implements Target {
@ -184,7 +184,7 @@ public abstract class TargetImpl implements Target {
@Override
public boolean isRequired(Ability ability) {
return ability == null || ability.isActivated() || !(ability.getAbilityType().equals(AbilityType.SPELL) || ability.getAbilityType().equals(AbilityType.ACTIVATED));
return ability == null || ability.isActivated() || !(ability.getAbilityType() == AbilityType.SPELL || ability.getAbilityType() == AbilityType.ACTIVATED);
}
@Override

View file

@ -132,6 +132,6 @@ public class TargetSpell extends TargetObject {
private boolean canBeChosen(StackObject stackObject, UUID sourceID, UUID sourceControllerId, Game game) {
return stackObject instanceof Spell
&& game.getState().getPlayersInRange(sourceControllerId, game).contains(stackObject.getControllerId())
&& filter.match((Spell) stackObject, sourceID, sourceControllerId, game);
&& filter.match(stackObject, sourceID, sourceControllerId, game);
}
}

View file

@ -28,7 +28,6 @@
package mage.target.common;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.UUID;

View file

@ -27,12 +27,9 @@
*/
package mage.target.common;
import java.util.UUID;
import mage.constants.TargetController;
import mage.abilities.Ability;
import mage.filter.FilterPlayer;
import mage.filter.predicate.other.PlayerPredicate;
import mage.game.Game;
import mage.target.TargetPlayer;
/**
@ -56,16 +53,6 @@ public class TargetOpponent extends TargetPlayer {
super(target);
}
@Override
public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) {
return super.canChoose(sourceId, sourceControllerId, game);
}
@Override
public boolean canTarget(UUID id, Ability source, Game game) {
return super.canTarget(id, source, game);
}
@Override
public TargetOpponent copy() {
return new TargetOpponent(this);

View file

@ -69,7 +69,7 @@ public class CardUtil {
private static final String SOURCE_EXILE_ZONE_TEXT = "SourceExileZone";
static String numberStrings[] = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
static final String[] numberStrings = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
"ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "ninteen", "twenty"};
public static final String[] NON_CHANGELING_SUBTYPES_VALUES = new String[]{

View file

@ -45,7 +45,7 @@ import java.util.concurrent.locks.ReentrantLock;
public class CircularList<E> implements List<E>, Iterable<E>, Serializable {
//TODO: might have to make E extend Copyable
protected List<E> list = new ArrayList<>();
protected final List<E> list = new ArrayList<>();
protected final ReentrantLock lock = new ReentrantLock();
@ -357,8 +357,8 @@ public class CircularList<E> implements List<E>, Iterable<E>, Serializable {
private class CircularIterator<E> implements Iterator<E> {
int cursor;
int lastIndex;
int curModCount;
final int lastIndex;
final int curModCount;
boolean hasMoved = false;
private CircularIterator() {
@ -399,9 +399,9 @@ public class CircularList<E> implements List<E>, Iterable<E>, Serializable {
private class CircularListIterator<E> implements ListIterator<E> {
int cursor;
int lastIndex;
int firstIndex;
int curModCount;
final int lastIndex;
final int firstIndex;
final int curModCount;
boolean hasMoved = false;
private CircularListIterator() {

View file

@ -32,7 +32,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;
import java.io.StreamCorruptedException;
/**
*

View file

@ -42,9 +42,9 @@ import mage.target.Target;
*/
public class TargetAddress {
protected int spellAbilityIndex;
protected UUID mode;
protected int targetIndex;
protected final int spellAbilityIndex;
protected final UUID mode;
protected final int targetIndex;
public TargetAddress(int spellAbilityIndex, UUID mode, int targetIndex) {
this.spellAbilityIndex = spellAbilityIndex;
@ -68,7 +68,7 @@ public class TargetAddress {
protected static class TargetAddressIterator implements Iterator<TargetAddress> {
protected Iterator<SpellAbility> spellAbilityIterator;
protected final Iterator<SpellAbility> spellAbilityIterator;
protected Integer lastSpellAbilityIndex = null;
protected Iterator<UUID> modeIterator = null;
protected Modes modes = null;

View file

@ -6,7 +6,7 @@ package mage.util;
*/
public class ThreadLocalStringBuilder extends ThreadLocal<StringBuilder> {
private int size;
private final int size;
public ThreadLocalStringBuilder(int size) {
this.size = size;

View file

@ -57,6 +57,7 @@ public abstract class Watcher implements Serializable {
this.controllerId = watcher.controllerId;
this.sourceId = watcher.sourceId;
this.scope = watcher.scope;
this.basicKey = watcher.basicKey;
}
public UUID getControllerId() {

View file

@ -28,7 +28,6 @@
package mage.watchers;
import java.util.HashMap;
import java.util.Iterator;
import java.util.UUID;
import mage.game.Game;
import mage.game.events.GameEvent;
@ -43,7 +42,7 @@ public class Watchers extends HashMap<String, Watcher> {
}
public Watchers(final Watchers watchers) {
watchers.entrySet().stream().forEach((entry) -> this.put(entry.getKey(), entry.getValue().copy()));
watchers.entrySet().forEach((entry) -> this.put(entry.getKey(), entry.getValue().copy()));
}
public Watchers copy() {
@ -51,9 +50,7 @@ public class Watchers extends HashMap<String, Watcher> {
}
public void add(Watcher watcher) {
if (!this.containsKey(watcher.getKey())) {
this.put(watcher.getKey(), watcher);
}
putIfAbsent(watcher.getKey(), watcher);
}
public void watch(GameEvent event, Game game) {
@ -63,7 +60,7 @@ public class Watchers extends HashMap<String, Watcher> {
}
public void reset() {
this.values().stream().forEach(Watcher::reset);
this.values().forEach(Watcher::reset);
}
public Watcher get(String key, UUID id) {

View file

@ -33,6 +33,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;
import mage.MageObjectReference;
import mage.constants.WatcherScope;
import mage.constants.Zone;
@ -80,7 +81,7 @@ public class CardsPutIntoGraveyardWatcher extends Watcher {
++amount;
}
amountOfCardsThisTurn.put(playerId, amount);
if (((ZoneChangeEvent) event).getFromZone().equals(Zone.BATTLEFIELD)) {
if (((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD) {
cardsPutToGraveyardFromBattlefield.add(new MageObjectReference(event.getTargetId(), game));
}
}

View file

@ -66,11 +66,7 @@ public class CastFromGraveyardWatcher extends Watcher {
if (event.getType() == GameEvent.EventType.SPELL_CAST && event.getZone().equals(Zone.GRAVEYARD)) {
Spell spell = (Spell) game.getObject(event.getTargetId());
if (spell != null) {
HashSet<Integer> zcc = spellsCastFromGraveyard.get(spell.getSourceId());
if (zcc == null) {
zcc = new HashSet<>();
spellsCastFromGraveyard.put(spell.getSourceId(), zcc);
}
HashSet<Integer> zcc = spellsCastFromGraveyard.computeIfAbsent(spell.getSourceId(), k -> new HashSet<>());
zcc.add(spell.getZoneChangeCounter(game));
}

View file

@ -64,9 +64,4 @@ public class FirstTimeStepWatcher extends Watcher {
condition = true;
}
}
@Override
public void reset() {
super.reset();
}
}