diff --git a/Mage/src/mage/Constants.java b/Mage/src/mage/Constants.java index 7ed26c66a1..0dbeed3abe 100644 --- a/Mage/src/mage/Constants.java +++ b/Mage/src/mage/Constants.java @@ -214,6 +214,7 @@ public final class Constants { DrawCard(true), Discard(false), Sacrifice(false), + ReturnToHand(false), Exile(false), Protect(true), PutManaInPool(true), diff --git a/Mage/src/mage/abilities/AbilitiesImpl.java b/Mage/src/mage/abilities/AbilitiesImpl.java index ba2875ea53..b2ca281b83 100644 --- a/Mage/src/mage/abilities/AbilitiesImpl.java +++ b/Mage/src/mage/abilities/AbilitiesImpl.java @@ -61,7 +61,7 @@ public class AbilitiesImpl extends ArrayList implements Abilities, Seri public List getActivatedAbilities(Zone zone) { List zonedAbilities = new ArrayList(); for (Ability ability: this) { - if (ability.isEnabled() && ability instanceof ActivatedAbility && ability.getZone().match(zone)) { + if (ability instanceof ActivatedAbility && ability.getZone().match(zone)) { zonedAbilities.add((ActivatedAbility)ability); } } @@ -77,7 +77,7 @@ public class AbilitiesImpl extends ArrayList implements Abilities, Seri public List getManaAbilities(Zone zone) { List abilities = new ArrayList(); for (Ability ability: this) { - if (ability.isEnabled() && ability instanceof ManaAbility && ability.getZone().match(zone)) { + if (ability instanceof ManaAbility && ability.getZone().match(zone)) { abilities.add((ManaAbility)ability); } } @@ -88,7 +88,7 @@ public class AbilitiesImpl extends ArrayList implements Abilities, Seri public List getEvasionAbilities() { List abilities = new ArrayList(); for (Ability ability: this) { - if (ability.isEnabled() && ability instanceof EvasionAbility) { + if (ability instanceof EvasionAbility) { abilities.add((EvasionAbility)ability); } } @@ -99,7 +99,7 @@ public class AbilitiesImpl extends ArrayList implements Abilities, Seri public List getStaticAbilities(Zone zone) { List zonedAbilities = new ArrayList(); for (Ability ability: this) { - if (ability.isEnabled() && ability instanceof StaticAbility && ability.getZone().match(zone)) { + if (ability instanceof StaticAbility && ability.getZone().match(zone)) { zonedAbilities.add((StaticAbility)ability); } } @@ -110,7 +110,7 @@ public class AbilitiesImpl extends ArrayList implements Abilities, Seri public List getTriggeredAbilities(Zone zone) { List zonedAbilities = new ArrayList(); for (Ability ability: this) { - if (ability.isEnabled() && ability instanceof TriggeredAbility && ability.getZone().match(zone)) { + if (ability instanceof TriggeredAbility && ability.getZone().match(zone)) { zonedAbilities.add((TriggeredAbility)ability); } } @@ -121,7 +121,7 @@ public class AbilitiesImpl extends ArrayList implements Abilities, Seri public List getProtectionAbilities() { List abilities = new ArrayList(); for (Ability ability: this) { - if (ability.isEnabled() && ability instanceof ProtectionAbility) { + if (ability instanceof ProtectionAbility) { abilities.add((ProtectionAbility)ability); } } @@ -132,7 +132,7 @@ public class AbilitiesImpl extends ArrayList implements Abilities, Seri public List getKickerAbilities() { List abilities = new ArrayList(); for (Ability ability: this) { - if (ability.isEnabled() && ability instanceof KickerAbility) { + if (ability instanceof KickerAbility) { abilities.add((KickerAbility)ability); } } @@ -153,6 +153,7 @@ public class AbilitiesImpl extends ArrayList implements Abilities, Seri } } + @Override public boolean containsAll(Abilities abilities) { if (this.size() < abilities.size()) return false; @@ -170,6 +171,7 @@ public class AbilitiesImpl extends ArrayList implements Abilities, Seri return true; } + @Override public boolean containsKey(UUID abilityId) { for (Ability ability: this) { if (ability.getId().equals(abilityId)) @@ -178,6 +180,7 @@ public class AbilitiesImpl extends ArrayList implements Abilities, Seri return false; } + @Override public Ability get(UUID abilityId) { for (Ability ability: this) { if (ability.getId().equals(abilityId)) diff --git a/Mage/src/mage/abilities/Ability.java b/Mage/src/mage/abilities/Ability.java index b59fe07750..ecbb253fc0 100644 --- a/Mage/src/mage/abilities/Ability.java +++ b/Mage/src/mage/abilities/Ability.java @@ -66,10 +66,9 @@ public interface Ability extends Serializable { public Zone getZone(); public String getRule(); public String getName(); - public boolean isEnabled(); - public void setEnabled(boolean enabled); public boolean activate(Game game, boolean noMana); public boolean resolve(Game game); + public void reset(Game game); public void setControllerId(UUID controllerId); public void setSourceId(UUID sourceID); diff --git a/Mage/src/mage/abilities/AbilityImpl.java b/Mage/src/mage/abilities/AbilityImpl.java index 174b9f0376..87ed70c0c1 100644 --- a/Mage/src/mage/abilities/AbilityImpl.java +++ b/Mage/src/mage/abilities/AbilityImpl.java @@ -113,6 +113,9 @@ public abstract class AbilityImpl implements Ability, Serializable { return costs.pay(game, noMana); } + @Override + public void reset(Game game) {} + protected boolean useAlternativeCost(Game game) { for (AlternativeCost cost: alternativeCosts) { if (cost.isAvailable(game)) { @@ -197,6 +200,13 @@ public abstract class AbilityImpl implements Ability, Serializable { sbRule.append(cost.getText()).append("\n"); } } + else { + for (Cost cost: this.costs) { + if (!(cost instanceof ManaCost)) { + sbRule.append("As an additional cost to cast {this}, ").append(cost.getText()).append("\n"); + } + } + } sbRule.append(effects.getText()); @@ -208,16 +218,6 @@ public abstract class AbilityImpl implements Ability, Serializable { return name; } - @Override - public boolean isEnabled() { - return enabled; - } - - @Override - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - @Override public void addCost(Cost cost) { if (cost != null) { @@ -273,9 +273,7 @@ public abstract class AbilityImpl implements Ability, Serializable { @Override public UUID getFirstTarget() { - if (this.targets.size() > 0) - return this.targets.get(0).getFirstTarget(); - return null; + return targets.getFirstTarget(); } @Override diff --git a/Mage/src/mage/abilities/SpellAbility.java b/Mage/src/mage/abilities/SpellAbility.java index da31f873c1..78277d2e7d 100644 --- a/Mage/src/mage/abilities/SpellAbility.java +++ b/Mage/src/mage/abilities/SpellAbility.java @@ -32,6 +32,7 @@ import java.util.UUID; import mage.Constants.CardType; import mage.Constants.Zone; import mage.abilities.costs.mana.ManaCost; +import mage.abilities.keyword.FlashAbility; import mage.game.Game; /** @@ -48,8 +49,10 @@ public class SpellAbility extends ActivatedAbilityImpl { @Override public boolean canActivate(UUID playerId, Game game) { - if ((game.getObject(sourceId).getCardType().contains(CardType.INSTANT) || game.canPlaySorcery(playerId)) && - costs.canPay(playerId, game) && targets.canChoose(sourceId, playerId, game)) { + if ((game.getObject(sourceId).getCardType().contains(CardType.INSTANT) || + game.getObject(sourceId).getAbilities().containsKey(FlashAbility.getInstance().getId()) || + game.canPlaySorcery(playerId)) && + costs.canPay(playerId, game) && targets.canChoose(sourceId, playerId, game)) { return true; } return false; diff --git a/Mage/src/mage/abilities/common/ActivateOncePerTurnActivatedAbility.java b/Mage/src/mage/abilities/common/ActivateOncePerTurnActivatedAbility.java index 337d48f1ee..01cc36adba 100644 --- a/Mage/src/mage/abilities/common/ActivateOncePerTurnActivatedAbility.java +++ b/Mage/src/mage/abilities/common/ActivateOncePerTurnActivatedAbility.java @@ -42,19 +42,34 @@ import mage.game.Game; */ public class ActivateOncePerTurnActivatedAbility extends ActivatedAbilityImpl { - protected UUID effectId; public ActivateOncePerTurnActivatedAbility(Zone zone, Effect effect, Cost cost) { super(zone, effect, cost); - effectId = effect.getId(); } @Override public boolean canActivate(UUID playerId, Game game) { - //assumes that ability creates a continuous effect - if (game.getContinuousEffects().effectExists(this.id)) - return false; - return super.canActivate(playerId, game); + Boolean activated = (Boolean)game.getState().getValue(this.id.toString() + "activated"); + if (activated == null) + return true; + else + return !activated; + } + + @Override + public boolean activate(Game game, boolean noMana) { + if (canActivate(this.controllerId, game)) { + if (super.activate(game, noMana)) { + game.getState().setValue(this.id.toString() + "activated", Boolean.TRUE); + return true; + } + } + return false; + } + + @Override + public void reset(Game game) { + game.getState().setValue(this.id.toString() + "activated", Boolean.FALSE); } @Override diff --git a/Mage/src/mage/abilities/common/AsRequiredTriggeredAbility.java b/Mage/src/mage/abilities/common/AsRequiredTriggeredAbility.java deleted file mode 100644 index 3bce6ad4ca..0000000000 --- a/Mage/src/mage/abilities/common/AsRequiredTriggeredAbility.java +++ /dev/null @@ -1,50 +0,0 @@ -///* -//* 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.common; -// -//import mage.abilities.TriggeredAbilityImpl; -//import mage.abilities.effects.Effect; -//import mage.game.Game; -//import mage.game.events.GameEvent; -// -///** -// * -// * @author BetaSteward_at_googlemail.com -// */ -//public class AsRequiredTriggeredAbility extends TriggeredAbilityImpl { -// -// public AsRequiredTriggeredAbility(Effect effect) { -// super(null, effect); -// -// } -// -// @Override -// public void handleEvent(GameEvent event, Game game) { -// } -//} diff --git a/Mage/src/mage/abilities/common/AttacksEachTurnStaticAbility.java b/Mage/src/mage/abilities/common/AttacksEachTurnStaticAbility.java new file mode 100644 index 0000000000..0136776e30 --- /dev/null +++ b/Mage/src/mage/abilities/common/AttacksEachTurnStaticAbility.java @@ -0,0 +1,80 @@ +/* + * 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.common; + +import mage.Constants.Duration; +import mage.Constants.Outcome; +import mage.Constants.Zone; +import mage.abilities.StaticAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.RequirementAttackEffect; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetDefender; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class AttacksEachTurnStaticAbility extends StaticAbility { + + public AttacksEachTurnStaticAbility() { + super(Zone.BATTLEFIELD, new AttacksEachTurnEffect()); + } + +} + +class AttacksEachTurnEffect extends RequirementAttackEffect { + + public AttacksEachTurnEffect() { + super(Duration.WhileOnBattlefield); + } + + @Override + public boolean apply(Game game) { + Permanent creature = game.getPermanent(this.source.getSourceId()); + if (creature != null) { + if (creature.canAttack(game)) { + TargetDefender target = new TargetDefender(game.getCombat().getDefenders(), creature.getControllerId()); + Player controller = game.getPlayer(creature.getControllerId()); + while (!target.isChosen()) + controller.chooseTarget(Outcome.Damage, target, game); + game.getCombat().declareAttacker(creature.getId(), target.getFirstTarget(), game); + return true; + } + } + return false; + } + + @Override + public String getText() { + return "{this} attacks each turn if able."; + } +} \ No newline at end of file diff --git a/Mage/src/mage/abilities/costs/Cost.java b/Mage/src/mage/abilities/costs/Cost.java index 03addd3991..cb9fc99f80 100644 --- a/Mage/src/mage/abilities/costs/Cost.java +++ b/Mage/src/mage/abilities/costs/Cost.java @@ -32,6 +32,7 @@ import java.io.Serializable; import java.util.UUID; import mage.abilities.Ability; import mage.game.Game; +import mage.target.Targets; public interface Cost extends Serializable { @@ -41,7 +42,8 @@ public interface Cost extends Serializable { public boolean isPaid(); public void clearPaid(); public void setPaid(); - + public Targets getTargets(); + public Ability getAbility(); public void setAbility(Ability ability); diff --git a/Mage/src/mage/abilities/costs/CostImpl.java b/Mage/src/mage/abilities/costs/CostImpl.java index 5eda3fd3bb..6e13d68a3d 100644 --- a/Mage/src/mage/abilities/costs/CostImpl.java +++ b/Mage/src/mage/abilities/costs/CostImpl.java @@ -29,16 +29,15 @@ package mage.abilities.costs; import mage.abilities.Ability; +import mage.target.Target; +import mage.target.Targets; public abstract class CostImpl implements Cost { protected String text; protected Ability ability; protected boolean paid = false; - -// public CostImpl(Ability ability) { -// this.ability = ability; -// } + protected Targets targets = new Targets(null); public CostImpl() { } @@ -56,6 +55,19 @@ public abstract class CostImpl implements Cost { @Override public void setAbility(Ability ability) { this.ability = ability; + targets.setSource(ability); + } + + public void addTarget(Target target) { + if (target != null) { + target.setAbility(ability); + this.targets.add(target); + } + } + + @Override + public Targets getTargets() { + return this.targets; } @Override diff --git a/Mage/src/mage/abilities/costs/CostsImpl.java b/Mage/src/mage/abilities/costs/CostsImpl.java index 71b74001dc..4d1f301178 100644 --- a/Mage/src/mage/abilities/costs/CostsImpl.java +++ b/Mage/src/mage/abilities/costs/CostsImpl.java @@ -33,6 +33,7 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.mana.VariableManaCost; import mage.game.Game; +import mage.target.Targets; /** * @@ -142,4 +143,13 @@ public class CostsImpl extends ArrayList implements Costs return null; } + @Override + public Targets getTargets() { + Targets targets = new Targets(ability); + for (Cost cost: this) { + targets.addAll(cost.getTargets()); + } + return targets; + } + } diff --git a/Mage/src/mage/abilities/costs/common/ReturnToHandTargetCost.java b/Mage/src/mage/abilities/costs/common/ReturnToHandTargetCost.java new file mode 100644 index 0000000000..7a89def14e --- /dev/null +++ b/Mage/src/mage/abilities/costs/common/ReturnToHandTargetCost.java @@ -0,0 +1,67 @@ +/* + * 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.costs.common; + +import java.util.UUID; +import mage.Constants.Outcome; +import mage.Constants.Zone; +import mage.abilities.costs.CostImpl; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class ReturnToHandTargetCost extends CostImpl { + + public ReturnToHandTargetCost(TargetControlledPermanent target) { + this.addTarget(target); + this.text = "return " + target.getTargetName() + " you control to it's owner's hand"; + } + + @Override + public boolean pay(Game game, boolean noMana) { + if (targets.choose(Outcome.ReturnToHand, game)) { + Permanent source = game.getPermanent(targets.getFirstTarget()); + if (source != null) { + paid = source.moveToZone(Zone.HAND, game, false); + } + } + return paid; + } + + @Override + public boolean canPay(UUID playerId, Game game) { + return targets.canChoose(playerId, playerId, game); + } + + +} diff --git a/Mage/src/mage/abilities/costs/common/SacrificeTargetCost.java b/Mage/src/mage/abilities/costs/common/SacrificeTargetCost.java index 63fd3e4dfa..f8b65c1575 100644 --- a/Mage/src/mage/abilities/costs/common/SacrificeTargetCost.java +++ b/Mage/src/mage/abilities/costs/common/SacrificeTargetCost.java @@ -30,10 +30,11 @@ package mage.abilities.costs.common; import java.util.UUID; import mage.Constants.Outcome; +import mage.abilities.Ability; import mage.abilities.costs.CostImpl; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.common.TargetSacrificePermanent; +import mage.target.common.TargetControlledPermanent; /** * @@ -41,18 +42,15 @@ import mage.target.common.TargetSacrificePermanent; */ public class SacrificeTargetCost extends CostImpl { - public TargetSacrificePermanent target; - - public SacrificeTargetCost(TargetSacrificePermanent target) { - this.target = target; + public SacrificeTargetCost(TargetControlledPermanent target) { + this.addTarget(target); this.text = "Sacrifice " + target.getTargetName(); } @Override public boolean pay(Game game, boolean noMana) { - target.setAbility(ability); - if (target.choose(Outcome.Sacrifice, game)) { - Permanent source = game.getPermanent(target.getFirstTarget()); + if (targets.choose(Outcome.Sacrifice, game)) { + Permanent source = game.getPermanent(targets.getFirstTarget()); if (source != null) { paid = source.sacrifice(this.ability.getSourceId(), game); } @@ -62,7 +60,11 @@ public class SacrificeTargetCost extends CostImpl { @Override public boolean canPay(UUID playerId, Game game) { - return target.canChoose(playerId, playerId, game); + return targets.canChoose(playerId, playerId, game); } + @Override + public void setAbility(Ability ability) { + super.setAbility(ability); + } } diff --git a/Mage/src/mage/abilities/costs/mana/ManaCostImpl.java b/Mage/src/mage/abilities/costs/mana/ManaCostImpl.java index c4c917c775..a79e82d3ea 100644 --- a/Mage/src/mage/abilities/costs/mana/ManaCostImpl.java +++ b/Mage/src/mage/abilities/costs/mana/ManaCostImpl.java @@ -55,6 +55,12 @@ public abstract class ManaCostImpl extends CostImpl implements ManaCost { return options; } + @Override + public void clearPaid() { + payment.clear(); + super.clearPaid(); + } + protected boolean assignColored(ManaPool pool, ColoredManaSymbol mana) { switch (mana) { case B: diff --git a/Mage/src/mage/abilities/costs/mana/MonoHybridManaCost.java b/Mage/src/mage/abilities/costs/mana/MonoHybridManaCost.java index 5fbc856e92..e659dc4d28 100644 --- a/Mage/src/mage/abilities/costs/mana/MonoHybridManaCost.java +++ b/Mage/src/mage/abilities/costs/mana/MonoHybridManaCost.java @@ -76,6 +76,7 @@ public class MonoHybridManaCost extends ManaCostImpl implements ManaCost { return this; } + @Override public boolean testPay(Mana testMana) { switch (mana) { case B: diff --git a/Mage/src/mage/abilities/effects/RequirementAttackEffect.java b/Mage/src/mage/abilities/effects/RequirementAttackEffect.java new file mode 100644 index 0000000000..25c3124191 --- /dev/null +++ b/Mage/src/mage/abilities/effects/RequirementAttackEffect.java @@ -0,0 +1,61 @@ +/* + * 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; + +import mage.Constants.Duration; +import mage.Constants.Outcome; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public abstract class RequirementAttackEffect extends ReplacementEffectImpl { + + public RequirementAttackEffect(Duration duration) { + super(duration, Outcome.Detriment); + } + + @Override + public boolean replaceEvent(GameEvent event, Game game) { + apply(game); + return false; + } + + @Override + public boolean applies(GameEvent event, Game game) { + if (event.getType().equals(EventType.DECLARE_ATTACKERS_STEP_PRE)) + return true; + return false; + } + + +} diff --git a/Mage/src/mage/abilities/effects/RequirementBlockEffect.java b/Mage/src/mage/abilities/effects/RequirementBlockEffect.java new file mode 100644 index 0000000000..d6c018d0a9 --- /dev/null +++ b/Mage/src/mage/abilities/effects/RequirementBlockEffect.java @@ -0,0 +1,61 @@ +/* + * 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; + +import mage.Constants.Duration; +import mage.Constants.Outcome; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public abstract class RequirementBlockEffect extends ReplacementEffectImpl { + + public RequirementBlockEffect(Duration duration) { + super(duration, Outcome.Detriment); + } + + @Override + public boolean replaceEvent(GameEvent event, Game game) { + apply(game); + return false; + } + + @Override + public boolean applies(GameEvent event, Game game) { + if (event.getType().equals(EventType.DECLARE_BLOCKERS_STEP_PRE)) + return true; + return false; + } + + +} diff --git a/Mage/src/mage/abilities/effects/common/AddPlusOneCountersControlledEffect.java b/Mage/src/mage/abilities/effects/common/AddPlusOneCountersControlledEffect.java new file mode 100644 index 0000000000..2e1a984813 --- /dev/null +++ b/Mage/src/mage/abilities/effects/common/AddPlusOneCountersControlledEffect.java @@ -0,0 +1,81 @@ +/* +* 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; + +import mage.Constants.Duration; +import mage.Constants.Layer; +import mage.Constants.Outcome; +import mage.Constants.SubLayer; +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.counters.Counter; +import mage.counters.PlusOneCounter; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class AddPlusOneCountersControlledEffect extends OneShotEffect { + + private int amount; + private FilterPermanent filter; + + public AddPlusOneCountersControlledEffect(int amount) { + this(amount, new FilterCreaturePermanent()); + } + + public AddPlusOneCountersControlledEffect(int amount, FilterPermanent filter) { + super(Outcome.Benefit); + this.amount = amount; + this.filter = filter; + } + + @Override + public boolean apply(Game game) { + for (Permanent perm: game.getBattlefield().getAllActivePermanents(filter, this.source.getControllerId())) { + perm.getCounters().addCounter(new PlusOneCounter(amount)); } + return true; + } + + @Override + public String getText() { + StringBuilder sb = new StringBuilder(); + sb.append("Put ").append(amount).append(" +1/+1 counter"); + if (amount > 1) + sb.append("s"); + sb.append(" on each ").append(filter.getName()).append(" you control"); + return sb.toString(); + } + +} diff --git a/Mage/src/mage/abilities/effects/common/EquipEffect.java b/Mage/src/mage/abilities/effects/common/AttachEffect.java similarity index 94% rename from Mage/src/mage/abilities/effects/common/EquipEffect.java rename to Mage/src/mage/abilities/effects/common/AttachEffect.java index dd2bb1e7ec..a7175a1d35 100644 --- a/Mage/src/mage/abilities/effects/common/EquipEffect.java +++ b/Mage/src/mage/abilities/effects/common/AttachEffect.java @@ -37,12 +37,13 @@ import mage.game.permanent.Permanent; * * @author BetaSteward_at_googlemail.com */ -public class EquipEffect extends OneShotEffect { +public class AttachEffect extends OneShotEffect { - public EquipEffect(Outcome outcome) { + public AttachEffect(Outcome outcome) { super(outcome); } + @Override public boolean apply(Game game) { Permanent permanent = game.getPermanent(source.getFirstTarget()); if (permanent != null) { @@ -51,8 +52,4 @@ public class EquipEffect extends OneShotEffect { return false; } - @Override - public String getText() { - return "Equip"; - } } diff --git a/Mage/src/mage/abilities/effects/common/BecomesCreatureSourceEOTEffect.java b/Mage/src/mage/abilities/effects/common/BecomesCreatureSourceEOTEffect.java index af7c73652a..8b2ac7f687 100644 --- a/Mage/src/mage/abilities/effects/common/BecomesCreatureSourceEOTEffect.java +++ b/Mage/src/mage/abilities/effects/common/BecomesCreatureSourceEOTEffect.java @@ -46,10 +46,12 @@ import mage.game.permanent.token.Token; public class BecomesCreatureSourceEOTEffect extends ContinuousEffectImpl { protected Token token; + protected String type; - public BecomesCreatureSourceEOTEffect(Token token) { + public BecomesCreatureSourceEOTEffect(Token token, String type) { super(Duration.EndOfTurn, Outcome.BecomeCreature); this.token = token; + this.type = type; } @Override @@ -97,7 +99,7 @@ public class BecomesCreatureSourceEOTEffect extends ContinuousEffectImpl { @Override public String getText() { - return "Until end of turn {this} becomes a " + token.getDescription() + ". It's still a land"; + return "Until end of turn {this} becomes a " + token.getDescription() + " that's still a " + this.type; } @Override diff --git a/Mage/src/mage/abilities/effects/common/CantCounterControlledEffect.java b/Mage/src/mage/abilities/effects/common/CantCounterControlledEffect.java index 930bb5b7b6..10955ea8bc 100644 --- a/Mage/src/mage/abilities/effects/common/CantCounterControlledEffect.java +++ b/Mage/src/mage/abilities/effects/common/CantCounterControlledEffect.java @@ -51,14 +51,17 @@ public class CantCounterControlledEffect extends ReplacementEffectImpl { this.filter = filter; } + @Override public boolean apply(Game game) { return true; } + @Override public boolean replaceEvent(GameEvent event, Game game) { return true; } + @Override public boolean applies(GameEvent event, Game game) { if (event.getType() == EventType.COUNTER) { filter.getControllerId().clear(); diff --git a/Mage/src/mage/abilities/effects/common/DamageMultiEffect.java b/Mage/src/mage/abilities/effects/common/DamageMultiEffect.java new file mode 100644 index 0000000000..faaa61a643 --- /dev/null +++ b/Mage/src/mage/abilities/effects/common/DamageMultiEffect.java @@ -0,0 +1,86 @@ +/* + * 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; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import mage.Constants.Outcome; +import mage.abilities.effects.OneShotEffect; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetAmount; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class DamageMultiEffect extends OneShotEffect { + + protected int amount; + + public DamageMultiEffect(int amount) { + super(Outcome.Damage); + this.amount = amount; + } + + public int getAmount() { + return amount; + } + + @Override + public boolean apply(Game game) { + Target multiTarget = this.source.getTargets().get(0); + for (UUID target: multiTarget.getTargets()) { + Permanent permanent = game.getPermanent(target); + if (permanent != null) { + permanent.damage(multiTarget.getTargetAmount(target), this.source.getSourceId(), game); + } + else { + Player player = game.getPlayer(target); + if (player != null) { + player.damage(multiTarget.getTargetAmount(target), this.source.getSourceId(), game); + } + } + } + return true; + } + + @Override + public String getText() { + StringBuilder sb = new StringBuilder(); + sb.append("{source} deals ").append(Integer.toString(amount)); + sb.append(" damage divided as you choose among any number of target ").append(this.source.getTargets().get(0).getTargetName()); + return sb.toString(); + } + + +} diff --git a/Mage/src/mage/abilities/effects/common/DestroyTargetEffect.java b/Mage/src/mage/abilities/effects/common/DestroyTargetEffect.java index 78989092e7..6e7cea4d7a 100644 --- a/Mage/src/mage/abilities/effects/common/DestroyTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/DestroyTargetEffect.java @@ -50,6 +50,7 @@ public class DestroyTargetEffect extends OneShotEffect { this.noRegen = noRegen; } + @Override public boolean apply(Game game) { Permanent permanent = game.getPermanent(this.source.getFirstTarget()); if (permanent != null) { diff --git a/Mage/src/mage/abilities/effects/common/DrawCardControllerEffect.java b/Mage/src/mage/abilities/effects/common/DrawCardControllerEffect.java new file mode 100644 index 0000000000..9443292b45 --- /dev/null +++ b/Mage/src/mage/abilities/effects/common/DrawCardControllerEffect.java @@ -0,0 +1,67 @@ +/* + * 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; + +import mage.Constants.Outcome; +import mage.abilities.effects.OneShotEffect; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class DrawCardControllerEffect extends OneShotEffect { + + protected int amount; + + public DrawCardControllerEffect(int amount) { + super(Outcome.DrawCard); + this.amount = amount; + } + + @Override + public boolean apply(Game game) { + Player player = game.getPlayer(this.source.getControllerId()); + if (player != null) { + player.drawCards(amount, game); + return true; + } + return false; + } + + @Override + public String getText() { + StringBuilder sb = new StringBuilder(); + sb.append("draw ").append(Integer.toString(amount)).append(" card").append((amount == 1?"":"s")); + return sb.toString(); + } + + +} diff --git a/Mage/src/mage/abilities/effects/common/DrawCardTargetEffect.java b/Mage/src/mage/abilities/effects/common/DrawCardTargetEffect.java index 41b9f2eca8..16d8b0c68a 100644 --- a/Mage/src/mage/abilities/effects/common/DrawCardTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/DrawCardTargetEffect.java @@ -58,7 +58,9 @@ public class DrawCardTargetEffect extends OneShotEffect { @Override public String getText() { - return "Target player draws " + Integer.toString(amount) + " card" + (amount == 1?"":"s"); + StringBuilder sb = new StringBuilder(); + sb.append("Target player draws ").append(Integer.toString(amount)).append(" card").append((amount == 1?"":"s")); + return sb.toString(); } diff --git a/Mage/src/mage/abilities/effects/common/GainAbilityEquippedEffect.java b/Mage/src/mage/abilities/effects/common/GainAbilityAttachedEffect.java similarity index 95% rename from Mage/src/mage/abilities/effects/common/GainAbilityEquippedEffect.java rename to Mage/src/mage/abilities/effects/common/GainAbilityAttachedEffect.java index f69fc15023..b57d4e5008 100644 --- a/Mage/src/mage/abilities/effects/common/GainAbilityEquippedEffect.java +++ b/Mage/src/mage/abilities/effects/common/GainAbilityAttachedEffect.java @@ -41,11 +41,11 @@ import mage.game.permanent.Permanent; * * @author BetaSteward_at_googlemail.com */ -public class GainAbilityEquippedEffect extends ContinuousEffectImpl { +public class GainAbilityAttachedEffect extends ContinuousEffectImpl { protected Ability ability; - public GainAbilityEquippedEffect(Ability ability) { + public GainAbilityAttachedEffect(Ability ability) { super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); this.ability = ability; } diff --git a/Mage/src/mage/abilities/effects/common/GainProtectionFromColorTargetEOTEffect.java b/Mage/src/mage/abilities/effects/common/GainProtectionFromColorTargetEOTEffect.java index 2d4d073e07..cb4af20d85 100644 --- a/Mage/src/mage/abilities/effects/common/GainProtectionFromColorTargetEOTEffect.java +++ b/Mage/src/mage/abilities/effects/common/GainProtectionFromColorTargetEOTEffect.java @@ -55,8 +55,11 @@ public class GainProtectionFromColorTargetEOTEffect extends GainAbilityTargetEff protectionFilter.setColor(choice.getColor()); protectionFilter.setMessage(choice.getChoice()); Permanent creature = game.getPermanent(source.getFirstTarget()); - creature.addAbility(ability); - return true; + if (creature != null) { + creature.addAbility(ability); + return true; + } + return false; } @Override diff --git a/Mage/src/mage/abilities/effects/common/LoseLifeTargetEffect.java b/Mage/src/mage/abilities/effects/common/LoseLifeTargetEffect.java new file mode 100644 index 0000000000..60636afb4f --- /dev/null +++ b/Mage/src/mage/abilities/effects/common/LoseLifeTargetEffect.java @@ -0,0 +1,69 @@ +/* + * 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; + +import mage.Constants.Outcome; +import mage.abilities.effects.OneShotEffect; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class LoseLifeTargetEffect extends OneShotEffect { + + protected int amount; + + public LoseLifeTargetEffect(int amount) { + super(Outcome.Damage); + this.amount = amount; + } + + public int getAmount() { + return amount; + } + + @Override + public boolean apply(Game game) { + Player player = game.getPlayer(this.source.getFirstTarget()); + if (player != null) { + player.loseLife(amount, game); + return true; + } + return false; + } + + @Override + public String getText() { + return "Target " + this.source.getTargets().get(0).getTargetName() + " loses " + Integer.toString(amount) + " life"; + } + + +} diff --git a/Mage/src/mage/abilities/effects/common/PlayTargetWithoutPayingManaEffect.java b/Mage/src/mage/abilities/effects/common/PlayTargetWithoutPayingManaEffect.java index 20140ca0d8..282e6eaf4a 100644 --- a/Mage/src/mage/abilities/effects/common/PlayTargetWithoutPayingManaEffect.java +++ b/Mage/src/mage/abilities/effects/common/PlayTargetWithoutPayingManaEffect.java @@ -48,7 +48,7 @@ public class PlayTargetWithoutPayingManaEffect extends OneShotEffect { public boolean apply(Game game) { Player controller = game.getPlayer(this.source.getControllerId()); Card target = (Card) game.getObject(this.source.getFirstTarget()); - return controller.cast(target, game, true); + return controller.cast(target.getSpellAbility(), game, true); } @Override diff --git a/Mage/src/mage/abilities/effects/common/PreventAllCombatDamageEffect.java b/Mage/src/mage/abilities/effects/common/PreventAllCombatDamageEffect.java index 5685663b7d..44b7c0f53d 100644 --- a/Mage/src/mage/abilities/effects/common/PreventAllCombatDamageEffect.java +++ b/Mage/src/mage/abilities/effects/common/PreventAllCombatDamageEffect.java @@ -57,7 +57,7 @@ public class PreventAllCombatDamageEffect extends PreventionEffectImpl { @Override public boolean applies(GameEvent event, Game game) { - if (game.getTurn().getStep() == PhaseStep.COMBAT_DAMAGE) + if (game.getTurn().getStepType() == PhaseStep.COMBAT_DAMAGE) return super.applies(event, game); return false; } diff --git a/Mage/src/mage/abilities/effects/common/PreventAllDamageSourceEffect.java b/Mage/src/mage/abilities/effects/common/PreventAllDamageSourceEffect.java new file mode 100644 index 0000000000..63383c7fd1 --- /dev/null +++ b/Mage/src/mage/abilities/effects/common/PreventAllDamageSourceEffect.java @@ -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; + +import mage.Constants.Duration; +import mage.abilities.effects.PreventionEffectImpl; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class PreventAllDamageSourceEffect extends PreventionEffectImpl { + + public PreventAllDamageSourceEffect(Duration duration) { + super(duration); + } + + @Override + public boolean apply(Game game) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Game game) { + event.setAmount(0); + return false; + } + + @Override + public boolean applies(GameEvent event, Game game) { + if (super.applies(event, game)) { + if (event.getTargetId().equals(this.source.getId())) { + return true; + } + } + return false; + } + + @Override + public String getText() { + return "Prevent all damage that would be dealt to {this} " + duration.toString(); + } + +} diff --git a/Mage/src/mage/abilities/effects/common/ReturnToHandTargetEffect.java b/Mage/src/mage/abilities/effects/common/ReturnToHandTargetEffect.java new file mode 100644 index 0000000000..9ca529ec69 --- /dev/null +++ b/Mage/src/mage/abilities/effects/common/ReturnToHandTargetEffect.java @@ -0,0 +1,61 @@ +/* + * 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; + +import mage.Constants.Outcome; +import mage.Constants.Zone; +import mage.abilities.effects.OneShotEffect; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class ReturnToHandTargetEffect extends OneShotEffect { + + public ReturnToHandTargetEffect() { + super(Outcome.ReturnToHand); + } + + @Override + public boolean apply(Game game) { + Permanent permanent = game.getPermanent(this.source.getFirstTarget()); + if (permanent != null) { + return permanent.moveToZone(Zone.HAND, game, false); + } + return false; + } + + @Override + public String getText() { + return "Return target " + this.source.getTargets().get(0).getTargetName() + " to it's owner's hand"; + + } +} diff --git a/Mage/src/mage/abilities/effects/common/SearchLibraryPutInHandEffect.java b/Mage/src/mage/abilities/effects/common/SearchLibraryPutInHandEffect.java new file mode 100644 index 0000000000..d978295668 --- /dev/null +++ b/Mage/src/mage/abilities/effects/common/SearchLibraryPutInHandEffect.java @@ -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; + +import java.util.UUID; +import mage.Constants.Outcome; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInLibrary; + +/** + * + * @author LokiX + */ +public class SearchLibraryPutInHandEffect extends OneShotEffect { + + private TargetCardInLibrary target; + + public SearchLibraryPutInHandEffect(TargetCardInLibrary target) { + super(Outcome.DrawCard); + this.target = target; + } + + @Override + public boolean apply(Game game) { + Player player = game.getPlayer(this.source.getControllerId()); + player.searchLibrary(target, game); + if (target.getTargets().size() > 0) { + for (UUID cardId: target.getTargets()) { + Card card = player.getLibrary().remove(cardId); + if (card != null){ + player.putInHand(card, game); + } + } + player.shuffleLibrary(game); + } + return true; + } + + @Override + public String getText() { + StringBuilder sb = new StringBuilder(); + sb.append("Search your library for "); + if (target.getNumberOfTargets() == 0 && target.getMaxNumberOfTargets() > 0) { + sb.append("up to ").append(target.getMaxNumberOfTargets()).append(" "); + sb.append(target.getTargetName()).append(" and put them into your hand"); + } + else { + sb.append("a ").append(target.getTargetName()).append(" and put that card into your hand"); + } + sb.append(". Then shuffle your library"); + + return sb.toString(); + } + + @Override + public void setSource(Ability ability) { + super.setSource(ability); + target.setAbility(ability); + } +} diff --git a/Mage/src/mage/abilities/effects/common/SearchLibraryPutInPlayEffect.java b/Mage/src/mage/abilities/effects/common/SearchLibraryPutInPlayEffect.java index e8acb53a31..07f46071ed 100644 --- a/Mage/src/mage/abilities/effects/common/SearchLibraryPutInPlayEffect.java +++ b/Mage/src/mage/abilities/effects/common/SearchLibraryPutInPlayEffect.java @@ -64,23 +64,25 @@ public class SearchLibraryPutInPlayEffect extends OneShotEffect { @Override public boolean apply(Game game) { Player player = game.getPlayer(this.source.getControllerId()); - player.searchLibrary(target, game); - if (target.getTargets().size() > 0) { - for (UUID cardId: target.getTargets()) { - Card card = player.getLibrary().remove(cardId); - if (card != null) { - if (player.putOntoBattlefield(card, game)) { - if (tapped) { - Permanent permanent = game.getPermanent(card.getId()); - if (permanent != null) - permanent.setTapped(true); + if (player.searchLibrary(target, game)) { + if (target.getTargets().size() > 0) { + for (UUID cardId: target.getTargets()) { + Card card = player.getLibrary().remove(cardId); + if (card != null) { + if (player.putOntoBattlefield(card, game)) { + if (tapped) { + Permanent permanent = game.getPermanent(card.getId()); + if (permanent != null) + permanent.setTapped(true); + } } } } + player.shuffleLibrary(game); + return true; } - player.shuffleLibrary(game); } - return true; + return false; } @Override diff --git a/Mage/src/mage/abilities/effects/common/SearchLibraryRevealPutInHandEffect.java b/Mage/src/mage/abilities/effects/common/SearchLibraryRevealPutInHandEffect.java index 4280fd8c0e..a3e702b9fc 100644 --- a/Mage/src/mage/abilities/effects/common/SearchLibraryRevealPutInHandEffect.java +++ b/Mage/src/mage/abilities/effects/common/SearchLibraryRevealPutInHandEffect.java @@ -63,6 +63,7 @@ public class SearchLibraryRevealPutInHandEffect extends OneShotEffect { Card card = player.getLibrary().remove(cardId); if (card != null) { player.putInHand(card, game); + revealed.add(card); } } player.shuffleLibrary(game); diff --git a/Mage/src/mage/abilities/effects/common/SkipNextUntapTargetEffect.java b/Mage/src/mage/abilities/effects/common/SkipNextUntapTargetEffect.java index db745627f7..c98edebc4c 100644 --- a/Mage/src/mage/abilities/effects/common/SkipNextUntapTargetEffect.java +++ b/Mage/src/mage/abilities/effects/common/SkipNextUntapTargetEffect.java @@ -59,7 +59,7 @@ public class SkipNextUntapTargetEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Game game) { - if (game.getTurn().getStep() == PhaseStep.UNTAP && + if (game.getTurn().getStepType() == PhaseStep.UNTAP && event.getType() == EventType.UNTAP && event.getTargetId().equals(source.getFirstTarget())) { return true; diff --git a/Mage/src/mage/abilities/effects/common/TapTargetEffect.java b/Mage/src/mage/abilities/effects/common/TapTargetEffect.java new file mode 100644 index 0000000000..1abbd56904 --- /dev/null +++ b/Mage/src/mage/abilities/effects/common/TapTargetEffect.java @@ -0,0 +1,71 @@ +/* +* 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; + +import java.util.UUID; +import mage.Constants.Outcome; +import mage.abilities.effects.OneShotEffect; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.Target; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class TapTargetEffect extends OneShotEffect { + + public TapTargetEffect() { + super(Outcome.Tap); + } + + @Override + public boolean apply(Game game) { + for (UUID target: this.source.getTargets().get(0).getTargets()) { + Permanent permanent = game.getPermanent(target); + if (permanent != null) { + permanent.setTapped(true); + } + else { + return false; + } + } + return true; + } + + @Override + public String getText() { + Target target = this.source.getTargets().get(0); + if (target.getNumberOfTargets() > 1) + return "tap " + target.getNumberOfTargets() + " target " + this.source.getTargets().get(0).getTargetName() + "s"; + else + return "tap target " + this.source.getTargets().get(0).getTargetName(); + } + +} diff --git a/Mage/src/mage/abilities/keyword/CascadeAbility.java b/Mage/src/mage/abilities/keyword/CascadeAbility.java index 3cbc6da51f..27db22f65c 100644 --- a/Mage/src/mage/abilities/keyword/CascadeAbility.java +++ b/Mage/src/mage/abilities/keyword/CascadeAbility.java @@ -87,7 +87,7 @@ class CascadeEffect extends OneShotEffect { if (card != null) { if (player.chooseUse(outcome, "Use cascade effect on " + card.getName() + "?", game)) { - player.cast(card, game, true); + player.cast(card.getSpellAbility(), game, true); exile.remove(card.getId()); } } diff --git a/Mage/src/mage/abilities/keyword/EnchantAbility.java b/Mage/src/mage/abilities/keyword/EnchantAbility.java new file mode 100644 index 0000000000..5c00e0a6b6 --- /dev/null +++ b/Mage/src/mage/abilities/keyword/EnchantAbility.java @@ -0,0 +1,54 @@ +/* + * 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.keyword; + +import mage.Constants.Outcome; +import mage.Constants.Zone; +import mage.abilities.StaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.target.TargetPermanent; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class EnchantAbility extends StaticAbility { + + public EnchantAbility(Outcome outcome, TargetPermanent target) { + super(Zone.BATTLEFIELD, new AttachEffect(outcome)); + this.addTarget(target); + } + + @Override + public String getRule() { + return "Enchant " + this.getTargets().get(0).getTargetName(); + } + + +} diff --git a/Mage/src/mage/abilities/keyword/EquipAbility.java b/Mage/src/mage/abilities/keyword/EquipAbility.java index 73a16da91b..c254f3d8b6 100644 --- a/Mage/src/mage/abilities/keyword/EquipAbility.java +++ b/Mage/src/mage/abilities/keyword/EquipAbility.java @@ -34,7 +34,7 @@ import mage.Constants.TimingRule; import mage.Constants.Zone; import mage.abilities.ActivatedAbilityImpl; import mage.abilities.costs.Cost; -import mage.abilities.effects.common.EquipEffect; +import mage.abilities.effects.common.AttachEffect; import mage.target.common.TargetCreaturePermanent; /** @@ -44,9 +44,14 @@ import mage.target.common.TargetCreaturePermanent; public class EquipAbility extends ActivatedAbilityImpl { public EquipAbility(Outcome outcome, Cost cost) { - super(Zone.BATTLEFIELD, new EquipEffect(outcome), cost); - this.targets.add(new TargetCreaturePermanent(1, TargetController.YOU)); + super(Zone.BATTLEFIELD, new AttachEffect(outcome), cost); + this.addTarget(new TargetCreaturePermanent(1, TargetController.YOU)); this.timing = TimingRule.SORCERY; } + @Override + public String getRule() { + return "Equip" + super.getRule(); + } + } diff --git a/Mage/src/mage/abilities/keyword/ExaltedAbility.java b/Mage/src/mage/abilities/keyword/ExaltedAbility.java index 8d2c4614d0..e64e159c41 100644 --- a/Mage/src/mage/abilities/keyword/ExaltedAbility.java +++ b/Mage/src/mage/abilities/keyword/ExaltedAbility.java @@ -51,8 +51,9 @@ public class ExaltedAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { if (event.getType() == EventType.DECLARED_ATTACKERS && game.getActivePlayerId().equals(this.controllerId) ) { if (game.getCombat().attacksAlone()) { - this.targets.add(new TargetCreaturePermanent()); - this.targets.get(0).getTargets().add(game.getCombat().getAttackers().get(0)); + TargetCreaturePermanent target = new TargetCreaturePermanent(); + this.addTarget(target); + this.getTargets().get(0).addTarget(game.getCombat().getAttackers().get(0), game); trigger(game, event.getPlayerId()); return true; } diff --git a/Mage/src/mage/abilities/keyword/FlashAbility.java b/Mage/src/mage/abilities/keyword/FlashAbility.java new file mode 100644 index 0000000000..cf986366a8 --- /dev/null +++ b/Mage/src/mage/abilities/keyword/FlashAbility.java @@ -0,0 +1,60 @@ +/* + * 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.keyword; + +import java.io.ObjectStreamException; +import mage.Constants.Zone; +import mage.abilities.StaticAbility; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class FlashAbility extends StaticAbility { + + private static final FlashAbility fINSTANCE = new FlashAbility(); + + private Object readResolve() throws ObjectStreamException { + return fINSTANCE; + } + + public static FlashAbility getInstance() { + return fINSTANCE; + } + + private FlashAbility() { + super(Zone.BATTLEFIELD, null); + } + + @Override + public String getRule() { + return "Flash"; + } + +} diff --git a/Mage/src/mage/abilities/keyword/FortifyAbility.java b/Mage/src/mage/abilities/keyword/FortifyAbility.java index a158c9eea0..5088803091 100644 --- a/Mage/src/mage/abilities/keyword/FortifyAbility.java +++ b/Mage/src/mage/abilities/keyword/FortifyAbility.java @@ -33,7 +33,7 @@ import mage.Constants.TimingRule; import mage.Constants.Zone; import mage.abilities.ActivatedAbilityImpl; import mage.abilities.costs.Cost; -import mage.abilities.effects.common.EquipEffect; +import mage.abilities.effects.common.AttachEffect; import mage.target.common.TargetLandPermanent; /** @@ -43,9 +43,9 @@ import mage.target.common.TargetLandPermanent; public class FortifyAbility extends ActivatedAbilityImpl { //20091005 - 702.64 - public FortifyAbility(Zone zone, EquipEffect effect, Cost cost) { + public FortifyAbility(Zone zone, AttachEffect effect, Cost cost) { super(zone, effect, cost); - targets.add(new TargetLandPermanent(1, TargetController.YOU)); + this.addTarget(new TargetLandPermanent(1, TargetController.YOU)); timing = TimingRule.SORCERY; } diff --git a/Mage/src/mage/abilities/keyword/KickerAbility.java b/Mage/src/mage/abilities/keyword/KickerAbility.java index c36183dd46..9c23e98071 100644 --- a/Mage/src/mage/abilities/keyword/KickerAbility.java +++ b/Mage/src/mage/abilities/keyword/KickerAbility.java @@ -52,7 +52,16 @@ public class KickerAbility extends StaticAbility { public boolean activate(Game game, boolean noMana) { Player player = game.getPlayer(this.getControllerId()); if (player.chooseUse(this.effects.get(0).getOutcome(), "Use kicker " + this.effects.get(0).getText() + "?", game)) { - kicked = super.activate(game, noMana); + game.saveState(); + game.bookmarkState(); + if (super.activate(game, noMana)) { + game.removeLastBookmark(); + kicked = true; + } + else { + game.restoreState(); + kicked = false; + } return kicked; } return false; diff --git a/Mage/src/mage/abilities/keyword/LandwalkAbility.java b/Mage/src/mage/abilities/keyword/LandwalkAbility.java new file mode 100644 index 0000000000..e472389c21 --- /dev/null +++ b/Mage/src/mage/abilities/keyword/LandwalkAbility.java @@ -0,0 +1,60 @@ +/* + * 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.keyword; + +import mage.abilities.EvasionAbilityImpl; +import mage.filter.common.FilterLandCard; +import mage.filter.common.FilterLandPermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class LandwalkAbility extends EvasionAbilityImpl { + + FilterLandPermanent filter; + + public LandwalkAbility(FilterLandPermanent filter) { + this.filter = filter; + } + + @Override + public boolean canBlock(Permanent permanent, Game game) { + return game.getBattlefield().countAll(filter, permanent.getControllerId()) == 0; + } + + @Override + public String getRule() { + return filter.getMessage() + "walk"; + } + +} diff --git a/Mage/src/mage/abilities/keyword/MultikickerAbility.java b/Mage/src/mage/abilities/keyword/MultikickerAbility.java new file mode 100644 index 0000000000..c4b8a3c163 --- /dev/null +++ b/Mage/src/mage/abilities/keyword/MultikickerAbility.java @@ -0,0 +1,86 @@ +/* + * 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.keyword; + +import mage.abilities.effects.Effect; +import mage.game.Game; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class MultikickerAbility extends KickerAbility { + + int activateCount = 0; + + public MultikickerAbility(Effect effect, boolean replaces) { + super(effect, replaces); + } + + @Override + public boolean activate(Game game, boolean noMana) { + activateCount = 0; + while (true) { + this.costs.clearPaid(); + this.manaCosts.clearPaid(); + if (!super.activate(game, noMana)) + break; + activateCount++; + } + kicked = activateCount > 0; + return kicked; + } + + @Override + public boolean resolve(Game game) { + boolean result = false; + for (int i = 0; i < activateCount; i++) { + result |= super.resolve(game); + } + return result; + } + + @Override + public String getRule() { + StringBuilder sb = new StringBuilder(); + sb.append("Multikicker"); + if (manaCosts.size() > 0) { + sb.append(manaCosts.getText()); + if (costs.size() > 0) + sb.append(","); + } + if (costs.size() > 0) + sb.append(costs.getText()); + sb.append(":").append(effects.getText()); + if (replaces) + sb.append(" instead"); + return sb.toString(); + } + +} diff --git a/Mage/src/mage/abilities/keyword/UnearthAbility.java b/Mage/src/mage/abilities/keyword/UnearthAbility.java index 7f00ffb86c..027c90aa91 100644 --- a/Mage/src/mage/abilities/keyword/UnearthAbility.java +++ b/Mage/src/mage/abilities/keyword/UnearthAbility.java @@ -59,9 +59,9 @@ public class UnearthAbility extends ActivatedAbilityImpl { public UnearthAbility(ManaCosts costs) { super(Zone.GRAVEYARD, new UnearthEffect(), costs); this.timing = TimingRule.SORCERY; - this.effects.add(new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.WhileOnBattlefield)); - this.effects.add(new CreateDelayedTriggeredAbilityEffect(new UnearthDelayedTriggeredAbility())); - this.effects.add(new UnearthLeavesBattlefieldEffect()); + this.addEffect(new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.WhileOnBattlefield)); + this.addEffect(new CreateDelayedTriggeredAbilityEffect(new UnearthDelayedTriggeredAbility())); + this.addEffect(new UnearthLeavesBattlefieldEffect()); } public boolean isUnearthed() { diff --git a/Mage/src/mage/abilities/mana/ManaAbility.java b/Mage/src/mage/abilities/mana/ManaAbility.java index 45ad0bb3d5..9e885af45d 100644 --- a/Mage/src/mage/abilities/mana/ManaAbility.java +++ b/Mage/src/mage/abilities/mana/ManaAbility.java @@ -33,7 +33,6 @@ import mage.Constants.Zone; import mage.Mana; import mage.abilities.ActivatedAbilityImpl; import mage.abilities.costs.Cost; -import mage.abilities.costs.Costs; import mage.abilities.effects.common.ManaEffect; import mage.game.Game; @@ -57,7 +56,7 @@ public abstract class ManaAbility extends ActivatedAbilityImpl { return costs.canPay(playerId, game); } - public Mana getNetMana() { + public Mana getNetMana(Game game) { return netMana; } } diff --git a/Mage/src/mage/abilities/mana/ManaOptions.java b/Mage/src/mage/abilities/mana/ManaOptions.java index 54e6ce4465..1c4e21ff59 100644 --- a/Mage/src/mage/abilities/mana/ManaOptions.java +++ b/Mage/src/mage/abilities/mana/ManaOptions.java @@ -31,6 +31,7 @@ package mage.abilities.mana; import java.util.ArrayList; import java.util.List; import mage.Mana; +import mage.game.Game; import mage.util.Copier; /** @@ -44,13 +45,13 @@ import mage.util.Copier; */ public class ManaOptions extends ArrayList { - public void addMana(List abilities) { + public void addMana(List abilities, Game game) { if (isEmpty()) this.add(new Mana()); if (!abilities.isEmpty()) { if (abilities.size() == 1) { //if there is only one mana option available add it to all the existing options - addMana(abilities.get(0).getNetMana()); + addMana(abilities.get(0).getNetMana(game)); } else if (abilities.size() > 1) { //perform a union of all existing options and the new options @@ -61,7 +62,7 @@ public class ManaOptions extends ArrayList { for (Mana mana: copy) { Mana newMana = new Mana(); newMana.add(mana); - newMana.add(ability.getNetMana()); + newMana.add(ability.getNetMana(game)); this.add(newMana); } } diff --git a/Mage/src/mage/cards/Cards.java b/Mage/src/mage/cards/Cards.java index 9c764c3bdd..0cefeda031 100644 --- a/Mage/src/mage/cards/Cards.java +++ b/Mage/src/mage/cards/Cards.java @@ -29,6 +29,7 @@ package mage.cards; import java.io.Serializable; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.UUID; @@ -43,6 +44,7 @@ public interface Cards extends Map, Serializable { public void setOwner(UUID ownerId); public void addAll(List createCards); public List getCards(FilterCard filter); + public Collection getUniqueCards(); public Card getRandom(); public int count(FilterCard filter); diff --git a/Mage/src/mage/cards/CardsImpl.java b/Mage/src/mage/cards/CardsImpl.java index f9aa4e0bed..a9ac423e45 100644 --- a/Mage/src/mage/cards/CardsImpl.java +++ b/Mage/src/mage/cards/CardsImpl.java @@ -30,8 +30,11 @@ package mage.cards; import java.io.Serializable; import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.Random; import java.util.UUID; import mage.Constants.Zone; @@ -119,4 +122,15 @@ public class CardsImpl extends LinkedHashMap implements Cards, Seria } } + @Override + public Collection getUniqueCards() { + Map cards = new HashMap(); + for(Card card: this.values()) { + if (!cards.containsKey(card.getName())) { + cards.put(card.getName(), card); + } + } + return cards.values(); + } + } diff --git a/Mage/src/mage/filter/common/FilterCreatureForAttack.java b/Mage/src/mage/filter/common/FilterCreatureForAttack.java index 4f04257260..009baa1916 100644 --- a/Mage/src/mage/filter/common/FilterCreatureForAttack.java +++ b/Mage/src/mage/filter/common/FilterCreatureForAttack.java @@ -28,6 +28,9 @@ package mage.filter.common; +import mage.abilities.keyword.DefenderAbility; +import mage.game.permanent.Permanent; + /** * * @author BetaSteward_at_googlemail.com @@ -46,6 +49,15 @@ public class FilterCreatureForAttack extends FilterCreaturePermanent { this.useBlocking = true; this.tapped = false; this.useTapped = true; + this.abilities.add(DefenderAbility.getInstance()); + this.notAbilities = true; } + @Override + public boolean match(Permanent permanent) { + if (!super.match(permanent)) + return false; + + return permanent.canTap(); + } } diff --git a/Mage/src/mage/game/Exile.java b/Mage/src/mage/game/Exile.java index dd2cd72069..4cf82d44b8 100644 --- a/Mage/src/mage/game/Exile.java +++ b/Mage/src/mage/game/Exile.java @@ -33,6 +33,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.UUID; +import mage.cards.Card; import mage.game.events.GameEvent; /** @@ -73,9 +74,19 @@ public class Exile implements Serializable { return exileZones.get(id); } - void checkTriggers(GameEvent event, Game game) { + public void checkTriggers(GameEvent event, Game game) { for (ExileZone exile: exileZones.values()) { exile.checkTriggers(event, game); } } + + public Card getCard(UUID cardId) { + Card card; + for (ExileZone exile: exileZones.values()) { + card = exile.get(cardId); + if (card != null) + return card; + } + return null; + } } diff --git a/Mage/src/mage/game/Game.java b/Mage/src/mage/game/Game.java index 05a0b0e9b0..4288d30bc5 100644 --- a/Mage/src/mage/game/Game.java +++ b/Mage/src/mage/game/Game.java @@ -28,6 +28,7 @@ package mage.game; +import mage.cards.Card; import mage.game.stack.SpellStack; import mage.MageObject; import java.io.Serializable; @@ -65,13 +66,16 @@ public interface Game extends MageItem, Serializable { public MultiplayerAttackOption getAttackOption(); //game data methods + public Object getCustomData(); + public void setCustomData(Object data); public MageObject getObject(UUID objectId); public Permanent getPermanent(UUID permanentId); + public Card getCard(UUID cardId); public void addPlayer(Player player) throws GameException; public Player getPlayer(UUID playerId); public Players getPlayers(); - public PlayerList getPlayerList(UUID playerId); - public Set getOpponents(UUID controllerId); + public PlayerList getPlayerList(); + public Set getOpponents(UUID playerId); public Turn getTurn(); public int getTurnNum(); public boolean isMainPhase(); @@ -98,6 +102,7 @@ public interface Game extends MageItem, Serializable { public void fireSelectTargetEvent(UUID playerId, String message, TriggeredAbilities abilities, boolean required); public void fireRevealCardsEvent(String message, Cards cards); public void fireSelectEvent(UUID playerId, String message); + public void fireLookAtCardsEvent(UUID playerId, String message, Cards cards); public void firePriorityEvent(UUID playerId); public void firePlayManaEvent(UUID playerId, String message); public void firePlayXManaEvent(UUID playerId, String message); @@ -112,6 +117,7 @@ public interface Game extends MageItem, Serializable { public boolean replaceEvent(GameEvent event); //game play methods + public void init(); public void start(); public void end(); public void mulligan(UUID playerId); @@ -121,21 +127,8 @@ public interface Game extends MageItem, Serializable { public void addEffect(ContinuousEffect continuousEffect); public void addTriggeredAbility(TriggeredAbility ability); public void applyEffects(); -// public boolean checkStateAndTriggered(); -// public boolean checkStateBasedActions(); + public boolean checkStateAndTriggered(); public void playPriority(UUID activePlayerId); - public boolean playUntapStep(UUID activePlayerId); - public boolean playUpkeepStep(UUID activePlayerId); - public boolean playDrawStep(UUID activePlayerId); - public boolean playPreCombatMainStep(UUID activePlayerId); - public boolean playBeginCombatStep(UUID activePlayerId); - public boolean playDeclareAttackersStep(UUID activePlayerId); - public boolean playDeclareBlockersStep(UUID activePlayerId); - public boolean playCombatDamageStep(UUID activePlayerId, boolean first); - public boolean playEndCombatStep(UUID activePlayerId); - public boolean playPostMainStep(UUID activePlayerId); - public boolean playEndStep(UUID activePlayerId); - public boolean playCleanupStep(UUID activePlayerId); //game transaction methods public void saveState(); diff --git a/Mage/src/mage/game/GameImpl.java b/Mage/src/mage/game/GameImpl.java index c0d3ec3e2b..197540bbe8 100644 --- a/Mage/src/mage/game/GameImpl.java +++ b/Mage/src/mage/game/GameImpl.java @@ -28,10 +28,10 @@ package mage.game; +import java.io.IOException; import mage.game.stack.SpellStack; import java.io.Serializable; import java.util.Collection; -import java.util.List; import java.util.Random; import java.util.Stack; import java.util.UUID; @@ -47,6 +47,7 @@ import mage.abilities.TriggeredAbilities; import mage.abilities.TriggeredAbility; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffects; +import mage.cards.Card; import mage.cards.Cards; import mage.choices.Choice; import mage.filter.Filter.ComparisonScope; @@ -55,7 +56,6 @@ import mage.filter.common.FilterFortification; import mage.filter.common.FilterLegendaryPermanent; import mage.filter.common.FilterPlaneswalkerPermanent; import mage.game.combat.Combat; -import mage.game.combat.CombatGroup; import mage.game.events.GameEvent; import mage.players.Player; import mage.game.events.Listener; @@ -73,18 +73,19 @@ import mage.target.TargetPlayer; public abstract class GameImpl implements Game, Serializable { - private Stack savedStates = new Stack(); + private transient Stack savedStates = new Stack(); + private Object customData; protected UUID id; protected boolean ready = false; - protected TableEventSource tableEventSource = new TableEventSource(); - protected PlayerQueryEventSource playerQueryEventSource = new PlayerQueryEventSource(); + protected transient TableEventSource tableEventSource = new TableEventSource(); + protected transient PlayerQueryEventSource playerQueryEventSource = new PlayerQueryEventSource(); protected GameState state; protected UUID startingPlayerId; protected UUID choosingPlayerId; protected Player winner; - protected GameStates gameStates; + protected transient GameStates gameStates = new GameStates(); protected RangeOfInfluence range; protected MultiplayerAttackOption attackOption; @@ -93,7 +94,6 @@ public abstract class GameImpl implements Game, Serializable { this.range = range; this.attackOption = attackOption; state = new GameState(); - gameStates = new GameStates(); } @Override @@ -101,6 +101,16 @@ public abstract class GameImpl implements Game, Serializable { return id; } + @Override + public Object getCustomData() { + return customData; + } + + @Override + public void setCustomData(Object data) { + this.customData = data; + } + @Override public void addPlayer(Player player) throws GameException { state.addPlayer(player); @@ -131,6 +141,11 @@ public abstract class GameImpl implements Game, Serializable { return state.getPermanent(permanentId); } + @Override + public Card getCard(UUID cardId) { + return state.getCard(cardId); + } + @Override public GameStates getGameStates() { return gameStates; @@ -138,7 +153,8 @@ public abstract class GameImpl implements Game, Serializable { @Override public void saveState() { - gameStates.save(state); + if (gameStates != null) + gameStates.save(state); } @Override @@ -179,7 +195,9 @@ public abstract class GameImpl implements Game, Serializable { @Override public void restoreState() { - state.restore(gameStates.rollback(savedStates.pop())); + GameState restore = gameStates.rollback(savedStates.pop()); + if (restore != null) + state.restore(restore); } @Override @@ -189,6 +207,29 @@ public abstract class GameImpl implements Game, Serializable { @Override public void start() { + init(); + PlayerList players = state.getPlayerList(startingPlayerId); + Player player = getPlayer(players.get()); + while (!isGameOver()) { + if (player.getId().equals(startingPlayerId)) { + state.setTurnNum(state.getTurnNum() + 1); + fireInformEvent("Turn " + Integer.toString(state.getTurnNum())); + } + state.setActivePlayerId(player.getId()); + state.getTurn().play(this, player.getId()); + if (isGameOver()) + break; + endOfTurn(); + player = players.getNext(this); + } + + winner = findWinner(); + + saveState(); + } + + @Override + public void init() { for (Player player: state.getPlayers().values()) { player.init(this); } @@ -204,6 +245,7 @@ public abstract class GameImpl implements Game, Serializable { if (startingPlayerId == null) { TargetPlayer targetPlayer = new TargetPlayer(); targetPlayer.setRequired(true); + targetPlayer.setTargetName("starting player"); Player choosingPlayer = getPlayer(pickChoosingPlayer()); if (choosingPlayer.chooseTarget(Outcome.Benefit, targetPlayer, this)) { startingPlayerId = targetPlayer.getTargets().get(0); @@ -216,13 +258,15 @@ public abstract class GameImpl implements Game, Serializable { saveState(); //20091005 - 103.3 - for (Player player: state.getPlayerList(startingPlayerId)) { + for (UUID playerId: state.getPlayerList(startingPlayerId)) { + Player player = getPlayer(playerId); player.setLife(this.getLife(), this); player.drawCards(7, this); } //20091005 - 103.4 - for (Player player: state.getPlayerList(startingPlayerId)) { + for (UUID playerId: state.getPlayerList(startingPlayerId)) { + Player player = getPlayer(playerId); while (player.getHand().size() > 0 && player.chooseMulligan(this)) { mulligan(player.getId()); } @@ -230,21 +274,6 @@ public abstract class GameImpl implements Game, Serializable { saveState(); } - while (!isGameOver()) { - state.setTurnNum(state.getTurnNum() + 1); - fireInformEvent("Turn " + Integer.toString(state.getTurnNum())); - for (Player player: state.getPlayerList(startingPlayerId)) { - state.setActivePlayerId(player.getId()); - state.getTurn().play(this, player.getId()); - if (isGameOver()) - break; - endOfTurn(); - } - } - - winner = findWinner(); - - saveState(); } protected Player findWinner() { @@ -314,9 +343,12 @@ public abstract class GameImpl implements Game, Serializable { @Override public void playPriority(UUID activePlayerId) { - state.getPlayers().resetPassed(); while (!isGameOver()) { - for (Player player: getPlayerList(activePlayerId)) { + state.getPlayers().resetPassed(); + state.getPlayerList().setCurrent(activePlayerId); + Player player; + while (!isGameOver()) { + player = getPlayer(state.getPlayerList().get()); state.setPriorityPlayerId(player.getId()); while (!player.isPassed() && !player.hasLost() && !player.hasLeft()&& !isGameOver()) { checkStateAndTriggered(); @@ -338,8 +370,10 @@ public abstract class GameImpl implements Game, Serializable { saveState(); break; } - return; + else + return; } + state.getPlayerList().getNext(); } } } @@ -376,7 +410,8 @@ public abstract class GameImpl implements Game, Serializable { state.addTriggeredAbility((TriggeredAbility) ability.copy()); } - protected boolean checkStateAndTriggered() { + @Override + public boolean checkStateAndTriggered() { boolean somethingHappened = false; //20091005 - 115.5 while (true) { @@ -392,7 +427,8 @@ public abstract class GameImpl implements Game, Serializable { public boolean checkTriggered() { boolean played = false; - for (Player player: getPlayerList(state.getActivePlayerId())) { + for (UUID playerId: state.getPlayerList(state.getActivePlayerId())) { + Player player = getPlayer(playerId); while (true) { TriggeredAbilities abilities = state.getTriggered().getControlledBy(player.getId()); if (abilities.size() == 0) @@ -516,173 +552,14 @@ public abstract class GameImpl implements Game, Serializable { return somethingHappened; } - @Override - public boolean playUntapStep(UUID activePlayerId) { - fireEvent(new GameEvent(GameEvent.EventType.BEGINNING_PHASE_PRE, null, null, activePlayerId)); - if (!replaceEvent(new GameEvent(GameEvent.EventType.UNTAP_STEP, null, null, activePlayerId))) { - //20091005 - 502.1/703.4a - getPlayer(activePlayerId).phasing(this); - //20091005 - 502.2/703.4b - getPlayer(activePlayerId).untap(this); - fireEvent(new GameEvent(GameEvent.EventType.UNTAP_STEP_PRE, null, null, activePlayerId)); - fireEvent(new GameEvent(GameEvent.EventType.UNTAP_STEP_POST, null, null, activePlayerId)); - return true; - } - return false; - } - - @Override - public boolean playUpkeepStep(UUID activePlayerId) { - if (!replaceEvent(new GameEvent(GameEvent.EventType.UPKEEP_STEP, null, null, activePlayerId))) { - fireEvent(new GameEvent(GameEvent.EventType.UPKEEP_STEP_PRE, null, null, activePlayerId)); - playPriority(activePlayerId); - fireEvent(new GameEvent(GameEvent.EventType.UPKEEP_STEP_POST, null, null, activePlayerId)); - return true; - } - return false; - } - - @Override - public boolean playDrawStep(UUID activePlayerId) { - if (!replaceEvent(new GameEvent(GameEvent.EventType.DRAW_STEP, null, null, activePlayerId))) { - //20091005 - 504.1/703.4c - getPlayer(activePlayerId).drawCards(1, this); - saveState(); - fireEvent(new GameEvent(GameEvent.EventType.DRAW_STEP_PRE, null, null, activePlayerId)); - playPriority(activePlayerId); - fireEvent(new GameEvent(GameEvent.EventType.DRAW_STEP_POST, null, null, activePlayerId)); - return true; - } - return false; - } - - @Override - public boolean playPreCombatMainStep(UUID activePlayerId) { - if (!replaceEvent(new GameEvent(GameEvent.EventType.PRECOMBAT_MAIN_STEP, null, null, activePlayerId))) { - fireEvent(new GameEvent(GameEvent.EventType.PRECOMBAT_MAIN_STEP_PRE, null, null, activePlayerId)); - playPriority(activePlayerId); - fireEvent(new GameEvent(GameEvent.EventType.PRECOMBAT_MAIN_STEP_POST, null, null, activePlayerId)); - return true; - } - return false; - } - - @Override - public boolean playBeginCombatStep(UUID activePlayerId) { - if (!replaceEvent(new GameEvent(GameEvent.EventType.BEGIN_COMBAT_STEP, null, null, activePlayerId))) { - //20091005 - 507.1 - state.getCombat().clear(); - state.getCombat().setAttacker(activePlayerId); - state.getCombat().setDefenders(this); - fireEvent(new GameEvent(GameEvent.EventType.BEGIN_COMBAT_STEP_PRE, null, null, activePlayerId)); - playPriority(activePlayerId); - fireEvent(new GameEvent(GameEvent.EventType.PRECOMBAT_MAIN_STEP_POST, null, null, activePlayerId)); - return true; - } - return false; - } - - @Override - public boolean playDeclareAttackersStep(UUID activePlayerId) { - if (!replaceEvent(new GameEvent(GameEvent.EventType.DECLARE_ATTACKERS_STEP, null, null, activePlayerId))) { - state.getCombat().selectAttackers(this); - fireEvent(new GameEvent(GameEvent.EventType.DECLARE_ATTACKERS_STEP_PRE, null, null, activePlayerId)); - playPriority(activePlayerId); - fireEvent(new GameEvent(GameEvent.EventType.DECLARE_ATTACKERS_STEP_POST, null, null, activePlayerId)); - return true; - } - return false; - } - - @Override - public boolean playDeclareBlockersStep(UUID activePlayerId) { - if (!replaceEvent(new GameEvent(GameEvent.EventType.DECLARE_BLOCKERS_STEP, null, null, activePlayerId))) { - state.getCombat().selectBlockers(this); - fireEvent(new GameEvent(GameEvent.EventType.DECLARE_BLOCKERS_STEP_PRE, null, null, activePlayerId)); - playPriority(activePlayerId); - fireEvent(new GameEvent(GameEvent.EventType.DECLARE_BLOCKERS_STEP_POST, null, null, activePlayerId)); - return true; - } - return false; - } - - @Override - public boolean playCombatDamageStep(UUID activePlayerId, boolean first) { - if (!replaceEvent(new GameEvent(GameEvent.EventType.COMBAT_DAMAGE_STEP, null, null, activePlayerId))) { - fireEvent(new GameEvent(GameEvent.EventType.COMBAT_DAMAGE_STEP_PRE, null, null, activePlayerId)); - for (CombatGroup group: getCombat().getGroups()) { - group.assignDamage(first, this); - } - playPriority(activePlayerId); - fireEvent(new GameEvent(GameEvent.EventType.COMBAT_DAMAGE_STEP_POST, null, null, activePlayerId)); - return true; - } - return false; - } - - @Override - public boolean playEndCombatStep(UUID activePlayerId) { - if (!replaceEvent(new GameEvent(GameEvent.EventType.END_COMBAT_STEP, null, null, activePlayerId))) { - fireEvent(new GameEvent(GameEvent.EventType.END_COMBAT_STEP_PRE, null, null, activePlayerId)); - playPriority(activePlayerId); - fireEvent(new GameEvent(GameEvent.EventType.END_COMBAT_STEP_POST, null, null, activePlayerId)); - removeCreaturesFromCombat(); - saveState(); - return true; - } - return false; - } - - @Override - public boolean playPostMainStep(UUID activePlayerId) { - if (!replaceEvent(new GameEvent(GameEvent.EventType.POSTCOMBAT_MAIN_STEP, null, null, activePlayerId))) { - fireEvent(new GameEvent(GameEvent.EventType.POSTCOMBAT_MAIN_STEP_PRE, null, null, activePlayerId)); - playPriority(activePlayerId); - fireEvent(new GameEvent(GameEvent.EventType.POSTCOMBAT_MAIN_STEP_POST, null, null, activePlayerId)); - return true; - } - return false; - } - - @Override - public boolean playEndStep(UUID activePlayerId) { - if (!replaceEvent(new GameEvent(GameEvent.EventType.END_TURN_STEP, null, null, activePlayerId))) { - fireEvent(new GameEvent(GameEvent.EventType.END_TURN_STEP_PRE, null, null, activePlayerId)); - playPriority(activePlayerId); - fireEvent(new GameEvent(GameEvent.EventType.END_TURN_STEP_POST, null, null, activePlayerId)); - return true; - } - return false; - } - - @Override - public boolean playCleanupStep(UUID activePlayerId) { - if (!replaceEvent(new GameEvent(GameEvent.EventType.CLEANUP_STEP, null, null, activePlayerId))) { - fireEvent(new GameEvent(GameEvent.EventType.CLEANUP_STEP_PRE, null, null, activePlayerId)); - //20091005 - 514.1 - Player player = getPlayer(activePlayerId); - if (!player.hasLeft() && !player.hasLost()) - player.discardToMax(this); - state.getBattlefield().endOfTurn(activePlayerId, this); - state.removeEotEffects(this); - if (checkStateAndTriggered()) { - playPriority(activePlayerId); - playCleanupStep(activePlayerId); - } - fireEvent(new GameEvent(GameEvent.EventType.CLEANUP_STEP_POST, null, null, activePlayerId)); - return true; - } - return false; - } - @Override public void addPlayerQueryEventListener(Listener listener) { playerQueryEventSource.addListener(listener); } @Override - public void firePriorityEvent(UUID playerId) { - String message = this.state.getTurn().getStep().toString(); + public synchronized void firePriorityEvent(UUID playerId) { + String message = this.state.getTurn().getStepType().toString(); if (this.canPlaySorcery(playerId)) message += " - play spells and sorceries."; else @@ -692,7 +569,7 @@ public abstract class GameImpl implements Game, Serializable { } @Override - public void fireSelectEvent(UUID playerId, String message) { + public synchronized void fireSelectEvent(UUID playerId, String message) { playerQueryEventSource.select(playerId, message); } @@ -736,6 +613,11 @@ public abstract class GameImpl implements Game, Serializable { tableEventSource.fireTableEvent(EventType.REVEAL, message, cards, this); } + @Override + public void fireLookAtCardsEvent(UUID playerId, String message, Cards cards) { + playerQueryEventSource.target(playerId, message, cards); + } + @Override public void fireGetAmountEvent(UUID playerId, String message, int min, int max) { playerQueryEventSource.amount(playerId, message, min, max); @@ -768,8 +650,8 @@ public abstract class GameImpl implements Game, Serializable { } @Override - public PlayerList getPlayerList(UUID playerId) { - return state.getPlayerList(playerId); + public PlayerList getPlayerList() { + return state.getPlayerList(); } @Override @@ -814,7 +696,7 @@ public abstract class GameImpl implements Game, Serializable { @Override public boolean isMainPhase() { - return state.getTurn().getStep() == PhaseStep.PRECOMBAT_MAIN || state.getTurn().getStep() == PhaseStep.POSTCOMBAT_MAIN; + return state.getTurn().getStepType() == PhaseStep.PRECOMBAT_MAIN || state.getTurn().getStepType() == PhaseStep.POSTCOMBAT_MAIN; } @Override @@ -854,4 +736,12 @@ public abstract class GameImpl implements Game, Serializable { return state.getContinuousEffects(); } + private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + savedStates = new Stack(); + tableEventSource = new TableEventSource(); + playerQueryEventSource = new PlayerQueryEventSource(); + gameStates = new GameStates(); + } + } diff --git a/Mage/src/mage/game/GameState.java b/Mage/src/mage/game/GameState.java index dea952d83b..1a2627d573 100644 --- a/Mage/src/mage/game/GameState.java +++ b/Mage/src/mage/game/GameState.java @@ -29,12 +29,15 @@ package mage.game; import mage.abilities.TriggeredAbility; +import mage.cards.Card; import mage.game.events.GameEvent; import mage.game.stack.SpellStack; import mage.game.stack.StackObject; import java.io.Serializable; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.UUID; import mage.Constants.Zone; import mage.MageObject; @@ -67,6 +70,7 @@ import mage.watchers.Watchers; public class GameState implements Serializable { private Players players = new Players(); + private PlayerList playerList = new PlayerList(); private UUID activePlayerId; private UUID priorityPlayerId; private Turn turn = new Turn(); @@ -83,9 +87,11 @@ public class GameState implements Serializable { private Combat combat = new Combat(); private TurnMods turnMods = new TurnMods(); private Watchers watchers = new Watchers(); + private Map values = new HashMap(); public void addPlayer(Player player) { players.put(player.getId(), player); + playerList.add(player.getId()); } public Players getPlayers() { @@ -181,14 +187,18 @@ public class GameState implements Serializable { this.messages.add(message); } + public PlayerList getPlayerList() { + return playerList; + } + public PlayerList getPlayerList(UUID playerId) { - PlayerList playerList = new PlayerList(); + PlayerList newPlayerList = new PlayerList(); for (Player player: players.values()) { if (!player.hasLeft() && !player.hasLost()) - playerList.add(player); + newPlayerList.add(player.getId()); } - playerList.setCurrent(playerId); - return playerList; + newPlayerList.setCurrent(playerId); + return newPlayerList; } public MageObject getObject(UUID objectId) { @@ -198,28 +208,9 @@ public class GameState implements Serializable { object.setZone(Zone.BATTLEFIELD); return object; } - for(Player player: players.values()) { - if (player.getHand().containsKey(objectId)) { - object = player.getHand().get(objectId); - object.setZone(Zone.HAND); - return object; - } - if (player.getGraveyard().containsKey(objectId)) { - object = player.getGraveyard().get(objectId); - object.setZone(Zone.GRAVEYARD); - return object; - } -// if (player.getLibrary().containsKey(objectId)) { -// return player.getLibrary().get(objectId); -// } -// for (Cards cards: player..values()) { -// if (cards.containsKey(id)) -// return cards.get(id); -// } -// if (player.getSideboard().containsKey(id)) { -// return player.getSideboard().get(id); -// } - } + object = getCard(objectId); + if (object != null) + return object; for (StackObject item: stack) { if (item.getId().equals(objectId)) { item.setZone(Zone.STACK); @@ -230,6 +221,23 @@ public class GameState implements Serializable { return null; } + public Card getCard(UUID cardId) { + Card card; + for(Player player: players.values()) { + if (player.getHand().containsKey(cardId)) { + card = player.getHand().get(cardId); + card.setZone(Zone.HAND); + return card; + } + if (player.getGraveyard().containsKey(cardId)) { + card = player.getGraveyard().get(cardId); + card.setZone(Zone.GRAVEYARD); + return card; + } + } + return this.exile.getCard(cardId); + } + public Permanent getPermanent(UUID permanentId) { Permanent permanent; if (battlefield.containsPermanent(permanentId)) { @@ -296,4 +304,11 @@ public class GameState implements Serializable { return effects; } + public Object getValue(String valueId) { + return values.get(valueId); + } + + public void setValue(String valueId, Object value) { + values.put(valueId, value); + } } diff --git a/Mage/src/mage/game/GameStates.java b/Mage/src/mage/game/GameStates.java index deba1f4ba2..437fd8bf67 100644 --- a/Mage/src/mage/game/GameStates.java +++ b/Mage/src/mage/game/GameStates.java @@ -50,10 +50,13 @@ public class GameStates implements Serializable { } public GameState rollback(int index) { - while (states.size() > index) { - states.remove(index); + if (index < states.size()) { + while (states.size() > index) { + states.remove(index); + } + return new Copier().uncompressCopy(states.get(index - 1)); } - return new Copier().uncompressCopy(states.get(index - 1)); + return null; } public GameState get(int index) { diff --git a/Mage/src/mage/game/combat/Combat.java b/Mage/src/mage/game/combat/Combat.java index a451ad56e4..806a9b60cc 100644 --- a/Mage/src/mage/game/combat/Combat.java +++ b/Mage/src/mage/game/combat/Combat.java @@ -111,9 +111,9 @@ public class Combat implements Serializable { PlayerList players; switch (game.getAttackOption()) { case LEFT: - players = game.getPlayerList(attackerId); + players = game.getState().getPlayerList(attackerId); while (true) { - Player opponent = players.getNext(); + Player opponent = players.getNext(game); if (opponents.contains(opponent.getId())) { defenders.add(opponent.getId()); break; @@ -121,9 +121,9 @@ public class Combat implements Serializable { } break; case RIGHT: - players = game.getPlayerList(attackerId); + players = game.getState().getPlayerList(attackerId); while (true) { - Player opponent = players.getPrevious(); + Player opponent = players.getPrevious(game); if (opponents.contains(opponent.getId())) { defenders.add(opponent.getId()); break; @@ -217,7 +217,7 @@ public class Combat implements Serializable { return false; } - protected boolean isAttacked(UUID defenderId, Game game) { + public boolean isAttacked(UUID defenderId, Game game) { for (CombatGroup group: groups) { if (group.getDefenderId().equals(defenderId)) return true; diff --git a/Mage/src/mage/game/events/PlayerQueryEvent.java b/Mage/src/mage/game/events/PlayerQueryEvent.java index 140671c5f8..6ae7203a4d 100644 --- a/Mage/src/mage/game/events/PlayerQueryEvent.java +++ b/Mage/src/mage/game/events/PlayerQueryEvent.java @@ -44,7 +44,7 @@ import mage.cards.Cards; public class PlayerQueryEvent extends EventObject implements ExternalEvent, Serializable { public enum QueryType { - ASK, CHOOSE, CHOOSE_ABILITY, PICK_TARGET, PICK_ABILITY, SELECT, PLAY_MANA, PLAY_X_MANA, AMOUNT + ASK, CHOOSE, CHOOSE_ABILITY, PICK_TARGET, PICK_ABILITY, SELECT, PLAY_MANA, PLAY_X_MANA, AMOUNT, LOOK } private String message; @@ -109,6 +109,10 @@ public class PlayerQueryEvent extends EventObject implements ExternalEvent, Seri return new PlayerQueryEvent(playerId, message, null, null, null, QueryType.AMOUNT, min, max, false); } + public static PlayerQueryEvent lookEvent(UUID playerId, String message, Cards cards) { + return new PlayerQueryEvent(playerId, message, null, null, cards, QueryType.LOOK, 0, 0, false); + } + public String getMessage() { return message; } diff --git a/Mage/src/mage/game/events/PlayerQueryEventSource.java b/Mage/src/mage/game/events/PlayerQueryEventSource.java index e40293f766..68f3e90bda 100644 --- a/Mage/src/mage/game/events/PlayerQueryEventSource.java +++ b/Mage/src/mage/game/events/PlayerQueryEventSource.java @@ -68,6 +68,10 @@ public class PlayerQueryEventSource implements EventSource, Se dispatcher.fireEvent(PlayerQueryEvent.targetEvent(playerId, message, cards, required)); } + public void target(UUID playerId, String message, Cards cards) { + dispatcher.fireEvent(PlayerQueryEvent.lookEvent(playerId, message, cards)); + } + public void target(UUID playerId, String message, TriggeredAbilities abilities, boolean required) { dispatcher.fireEvent(PlayerQueryEvent.targetEvent(playerId, message, abilities, required)); } diff --git a/Mage/src/mage/game/events/TableEvent.java b/Mage/src/mage/game/events/TableEvent.java index 4422f6188f..c9b915c4aa 100644 --- a/Mage/src/mage/game/events/TableEvent.java +++ b/Mage/src/mage/game/events/TableEvent.java @@ -40,7 +40,7 @@ import mage.game.Game; public class TableEvent extends EventObject implements ExternalEvent, Serializable { public enum EventType { - UPDATE, INFO, REVEAL + UPDATE, INFO, REVEAL, LOOK } private Game game; diff --git a/Mage/src/mage/game/permanent/Battlefield.java b/Mage/src/mage/game/permanent/Battlefield.java index 8abb0af106..b091ff83a7 100644 --- a/Mage/src/mage/game/permanent/Battlefield.java +++ b/Mage/src/mage/game/permanent/Battlefield.java @@ -137,8 +137,7 @@ public class Battlefield implements Serializable { public void endOfTurn(UUID controllerId, Game game) { for (Permanent perm: field.values()) { - if (perm.getControllerId().equals(controllerId)) - perm.endOfTurn(game); + perm.endOfTurn(game); } } @@ -146,15 +145,6 @@ public class Battlefield implements Serializable { return field.values(); } - public Collection getAllPermanents(UUID controllerId) { - List perms = new ArrayList(); - for (Permanent perm: field.values()) { - if (perm.getControllerId().equals(controllerId)) - perms.add(perm); - } - return perms; - } - public List getAllActivePermanents() { List active = new ArrayList(); for (Permanent perm: field.values()) { @@ -164,6 +154,14 @@ public class Battlefield implements Serializable { return active; } + /** + * Returns all Permanents on the battlefield that are controlled by the specified + * player id. The method ignores the range of influence. + * + * @param controllerId + * @return a list of Permanent + * @see Permanent + */ public List getAllActivePermanents(UUID controllerId) { List active = new ArrayList(); for (Permanent perm: field.values()) { @@ -173,6 +171,14 @@ public class Battlefield implements Serializable { return active; } + /** + * Returns all Permanents on the battlefield that match the specified CardType. + * This method ignores the range of influence. + * + * @param type + * @return a list of Permanent + * @see Permanent + */ public List getAllActivePermanents(CardType type) { List active = new ArrayList(); for (Permanent perm: field.values()) { @@ -182,6 +188,14 @@ public class Battlefield implements Serializable { return active; } + /** + * Returns all Permanents on the battlefield that match the supplied filter. + * This method ignores the range of influence. + * + * @param filter + * @return a list of Permanent + * @see Permanent + */ public List getAllActivePermanents(FilterPermanent filter) { List active = new ArrayList(); for (Permanent perm: field.values()) { @@ -191,6 +205,15 @@ public class Battlefield implements Serializable { return active; } + /** + * Returns all Permanents that match the filter and are controlled by controllerId. + * This method ignores the range of influence. + * + * @param filter + * @param controllerId + * @return a list of Permanent + * @see Permanent + */ public List getAllActivePermanents(FilterPermanent filter, UUID controllerId) { List active = new ArrayList(); for (Permanent perm: field.values()) { @@ -200,6 +223,16 @@ public class Battlefield implements Serializable { return active; } + /** + * Returns all Permanents that are within the range of influence of the specified player id + * and that match the supplied filter. + * + * @param filter + * @param sourcePlayerId + * @param game + * @return a list of Permanent + * @see Permanent + */ public List getActivePermanents(FilterPermanent filter, UUID sourcePlayerId, Game game) { if (game.getRangeOfInfluence() == RangeOfInfluence.ALL) { return getAllActivePermanents(filter); @@ -215,6 +248,14 @@ public class Battlefield implements Serializable { } } + /** + * Returns all Permanents that are within the range of influence of the specified player id. + * + * @param sourcePlayerId + * @param game + * @return a list of Permanent + * @see Permanent + */ public List getActivePermanents(UUID sourcePlayerId, Game game) { if (game.getRangeOfInfluence() == RangeOfInfluence.ALL) { return getAllActivePermanents(); @@ -248,13 +289,4 @@ public class Battlefield implements Serializable { return phasedOut; } -// public List getMatches(FilterPermanent filter) { -// List matches = new ArrayList(); -// for (Permanent perm: field.values()) { -// if (filter.match(perm)) -// matches.add(perm); -// } -// return matches; -// } - } diff --git a/Mage/src/mage/game/permanent/PermanentImpl.java b/Mage/src/mage/game/permanent/PermanentImpl.java index 0ebdda99de..05221c63a2 100644 --- a/Mage/src/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/mage/game/permanent/PermanentImpl.java @@ -110,6 +110,9 @@ public abstract class PermanentImpl extends CardImpl implements Permanent this.damage = 0; this.loyaltyUsed = false; this.turnsOnBattlefield++; + for (Ability ability: this.abilities) { + ability.reset(game); + } } @Override diff --git a/Mage/src/mage/game/permanent/token/InsectToken.java b/Mage/src/mage/game/permanent/token/InsectToken.java new file mode 100644 index 0000000000..7f58e94b7d --- /dev/null +++ b/Mage/src/mage/game/permanent/token/InsectToken.java @@ -0,0 +1,49 @@ +/* +* 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.Constants.CardType; +import mage.MageInt; +import mage.ObjectColor; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class InsectToken extends Token { + + public InsectToken() { + super("Insect", "1/1 green Insect creature token"); + cardType.add(CardType.CREATURE); + color = ObjectColor.GREEN; + subtype.add("Insect"); + power = new MageInt(1); + toughness = new MageInt(1); + } +} \ No newline at end of file diff --git a/Mage/src/mage/game/stack/Spell.java b/Mage/src/mage/game/stack/Spell.java index 5d857feca6..3914cb5faf 100644 --- a/Mage/src/mage/game/stack/Spell.java +++ b/Mage/src/mage/game/stack/Spell.java @@ -56,10 +56,12 @@ public class Spell implements StackObject, Card { // private static final transient Copier copier = new Copier(); private Card card; + private SpellAbility ability; private UUID controllerId; - public Spell(Card card, UUID controllerId) { + public Spell(Card card, SpellAbility ability, UUID controllerId) { this.card = card; + this.ability = ability; this.controllerId = controllerId; } @@ -67,19 +69,12 @@ public class Spell implements StackObject, Card { public boolean resolve(Game game) { boolean result = false; if (card.getCardType().contains(CardType.INSTANT) || card.getCardType().contains(CardType.SORCERY)) { - SpellAbility ability = card.getSpellAbility(); if (ability.getTargets().stillLegal(game)) { - boolean replaced = false; - for (KickerAbility kicker: card.getAbilities().getKickerAbilities()) { - if (kicker.isKicked()) { - if (kicker.isReplaces()) { - replaced = true; - } - kicker.resolve(game); - } - } + boolean replaced = resolveKicker(game); if (!replaced) result = ability.resolve(game); + else + result = true; if (ability.getEffects().contains(ExileSpellEffect.getInstance())) game.getExile().getPermanentExile().add(card); @@ -91,12 +86,39 @@ public class Spell implements StackObject, Card { counter(game); return false; } + else if (card.getCardType().contains(CardType.ENCHANTMENT) && card.getSubtype().contains("Aura")) { + if (ability.getTargets().stillLegal(game)) { + Player controller = game.getPlayers().get(controllerId); + if (controller.putOntoBattlefield(card, game)) { + return ability.resolve(game); + } + return false; + } + //20091005 - 608.2b + counter(game); + return false; + } else { Player controller = game.getPlayers().get(controllerId); - return controller.putOntoBattlefield(card, game); + result = controller.putOntoBattlefield(card, game); + resolveKicker(game); + return result; } } + protected boolean resolveKicker(Game game) { + boolean replaced = false; + for (KickerAbility kicker: card.getAbilities().getKickerAbilities()) { + if (kicker.isKicked()) { + if (kicker.isReplaces()) { + replaced = true; + } + kicker.resolve(game); + } + } + return replaced; + } + @Override public void counter(Game game) { game.getPlayers().get(controllerId).putInGraveyard(card, game, false); diff --git a/Mage/src/mage/game/stack/StackAbility.java b/Mage/src/mage/game/stack/StackAbility.java index 9f2984e852..1fc49fb341 100644 --- a/Mage/src/mage/game/stack/StackAbility.java +++ b/Mage/src/mage/game/stack/StackAbility.java @@ -83,6 +83,9 @@ public class StackAbility implements StackObject, Ability { return false; } + @Override + public void reset(Game game) { } + @Override public void counter(Game game) { @@ -176,14 +179,6 @@ public class StackAbility implements StackObject, Ability { return ability.getRule(); } - @Override - public boolean isEnabled() { - return ability.isEnabled(); - } - - @Override - public void setEnabled(boolean enabled) {} - @Override public void setControllerId(UUID controllerId) { this.controllerId = controllerId; diff --git a/Mage/src/mage/game/turn/BeginCombatStep.java b/Mage/src/mage/game/turn/BeginCombatStep.java new file mode 100644 index 0000000000..088be68e74 --- /dev/null +++ b/Mage/src/mage/game/turn/BeginCombatStep.java @@ -0,0 +1,58 @@ +/* + * 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.turn; + +import java.util.UUID; +import mage.Constants.PhaseStep; +import mage.game.Game; +import mage.game.events.GameEvent.EventType; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class BeginCombatStep extends Step { + + public BeginCombatStep() { + super(PhaseStep.BEGIN_COMBAT, true); + this.stepEvent = EventType.BEGIN_COMBAT_STEP; + this.preStepEvent = EventType.BEGIN_COMBAT_STEP_PRE; + this.postStepEvent = EventType.BEGIN_COMBAT_STEP_POST; + } + + @Override + public void beginStep(Game game, UUID activePlayerId) { + //20091005 - 507.1 + game.getCombat().clear(); + game.getCombat().setAttacker(activePlayerId); + game.getCombat().setDefenders(game); + super.beginStep(game, activePlayerId); + } + +} diff --git a/Mage/src/mage/game/turn/BeginningPhase.java b/Mage/src/mage/game/turn/BeginningPhase.java index 915e714049..f676c865db 100644 --- a/Mage/src/mage/game/turn/BeginningPhase.java +++ b/Mage/src/mage/game/turn/BeginningPhase.java @@ -28,7 +28,6 @@ package mage.game.turn; -import mage.Constants.PhaseStep; import mage.Constants.TurnPhase; import mage.game.events.GameEvent.EventType; @@ -43,9 +42,9 @@ public class BeginningPhase extends Phase { this.event = EventType.BEGINNING_PHASE; this.preEvent = EventType.BEGINNING_PHASE_PRE; this.postEvent = EventType.BEGINNING_PHASE_POST; - this.steps.add(new Step(PhaseStep.UNTAP)); - this.steps.add(new Step(PhaseStep.UPKEEP)); - this.steps.add(new Step(PhaseStep.DRAW)); + this.steps.add(new UntapStep()); + this.steps.add(new UpkeepStep()); + this.steps.add(new DrawStep()); } } diff --git a/Mage/src/mage/game/turn/CleanupStep.java b/Mage/src/mage/game/turn/CleanupStep.java new file mode 100644 index 0000000000..de3747f174 --- /dev/null +++ b/Mage/src/mage/game/turn/CleanupStep.java @@ -0,0 +1,63 @@ +/* + * 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.turn; + +import java.util.UUID; +import mage.Constants.PhaseStep; +import mage.game.Game; +import mage.game.events.GameEvent.EventType; +import mage.players.Player; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class CleanupStep extends Step { + + public CleanupStep() { + super(PhaseStep.CLEANUP, true); + this.stepEvent = EventType.CLEANUP_STEP; + this.preStepEvent = EventType.CLEANUP_STEP_PRE; + this.postStepEvent = EventType.CLEANUP_STEP_POST; + } + + @Override + public void beginStep(Game game, UUID activePlayerId) { + super.beginStep(game, activePlayerId); + Player activePlayer = game.getPlayer(activePlayerId); + //20091005 - 514.1 + if (!activePlayer.hasLeft() && !activePlayer.hasLost()) + activePlayer.discardToMax(game); + //20100423 - 514.2 + game.getBattlefield().endOfTurn(activePlayerId, game); + game.getState().removeEotEffects(game); + + } + +} diff --git a/Mage/src/mage/game/turn/CombatDamageStep.java b/Mage/src/mage/game/turn/CombatDamageStep.java new file mode 100644 index 0000000000..7d32e04e3b --- /dev/null +++ b/Mage/src/mage/game/turn/CombatDamageStep.java @@ -0,0 +1,74 @@ +/* + * 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.turn; + +import java.util.UUID; +import mage.Constants.PhaseStep; +import mage.game.Game; +import mage.game.combat.CombatGroup; +import mage.game.events.GameEvent.EventType; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class CombatDamageStep extends Step { + + private boolean first; + + public CombatDamageStep(boolean first) { + super(PhaseStep.COMBAT_DAMAGE, true); + this.first = first; + this.stepEvent = EventType.COMBAT_DAMAGE_STEP; + this.preStepEvent = EventType.COMBAT_DAMAGE_STEP_PRE; + this.postStepEvent = EventType.COMBAT_DAMAGE_STEP_POST; + } + + @Override + public boolean skipStep(Game game, UUID activePlayerId) { + if (game.getCombat().noAttackers()) + return true; + if (first && !game.getCombat().hasFirstOrDoubleStrike(game)) + return true; + return super.skipStep(game, activePlayerId); + } + + @Override + public void beginStep(Game game, UUID activePlayerId) { + super.beginStep(game, activePlayerId); + for (CombatGroup group: game.getCombat().getGroups()) { + group.assignDamage(first, game); + } + } + + public boolean getFirst() { + return first; + } + +} diff --git a/Mage/src/mage/game/turn/CombatPhase.java b/Mage/src/mage/game/turn/CombatPhase.java index 15121effab..ce127d353f 100644 --- a/Mage/src/mage/game/turn/CombatPhase.java +++ b/Mage/src/mage/game/turn/CombatPhase.java @@ -28,7 +28,6 @@ package mage.game.turn; -import mage.Constants.PhaseStep; import mage.Constants.TurnPhase; import mage.game.events.GameEvent.EventType; @@ -43,12 +42,12 @@ public class CombatPhase extends Phase { this.event = EventType.COMBAT_PHASE; this.preEvent = EventType.COMBAT_PHASE_PRE; this.postEvent = EventType.COMBAT_PHASE_POST; - this.steps.add(new Step(PhaseStep.BEGIN_COMBAT)); - this.steps.add(new Step(PhaseStep.DECLARE_ATTACKERS)); - this.steps.add(new Step(PhaseStep.DECLARE_BLOCKERS)); - this.steps.add(new Step(PhaseStep.FIRST_COMBAT_DAMAGE)); - this.steps.add(new Step(PhaseStep.COMBAT_DAMAGE)); - this.steps.add(new Step(PhaseStep.END_COMBAT)); + this.steps.add(new BeginCombatStep()); + this.steps.add(new DeclareAttackersStep()); + this.steps.add(new DeclareBlockersStep()); + this.steps.add(new CombatDamageStep(true)); + this.steps.add(new CombatDamageStep(false)); + this.steps.add(new EndOfCombatStep()); } } diff --git a/Mage/src/mage/game/turn/DeclareAttackersStep.java b/Mage/src/mage/game/turn/DeclareAttackersStep.java new file mode 100644 index 0000000000..b2780f68f7 --- /dev/null +++ b/Mage/src/mage/game/turn/DeclareAttackersStep.java @@ -0,0 +1,62 @@ +/* + * 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.turn; + +import java.util.UUID; +import mage.Constants.PhaseStep; +import mage.game.Game; +import mage.game.events.GameEvent.EventType; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class DeclareAttackersStep extends Step { + + public DeclareAttackersStep() { + super(PhaseStep.DECLARE_ATTACKERS, true); + this.stepEvent = EventType.DECLARE_ATTACKERS_STEP; + this.preStepEvent = EventType.DECLARE_ATTACKERS_STEP_PRE; + this.postStepEvent = EventType.DECLARE_ATTACKERS_STEP_POST; + } + + @Override + public boolean skipStep(Game game, UUID activePlayerId) { + if (!game.getPlayer(activePlayerId).hasAvailableAttackers(game)) + return true; + return super.skipStep(game, activePlayerId); + } + + @Override + public void beginStep(Game game, UUID activePlayerId) { + super.beginStep(game, activePlayerId); + game.getCombat().selectAttackers(game); + } + +} diff --git a/Mage/src/mage/game/turn/DeclareBlockersStep.java b/Mage/src/mage/game/turn/DeclareBlockersStep.java new file mode 100644 index 0000000000..6aee8a83b7 --- /dev/null +++ b/Mage/src/mage/game/turn/DeclareBlockersStep.java @@ -0,0 +1,62 @@ +/* + * 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.turn; + +import java.util.UUID; +import mage.Constants.PhaseStep; +import mage.game.Game; +import mage.game.events.GameEvent.EventType; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class DeclareBlockersStep extends Step { + + public DeclareBlockersStep() { + super(PhaseStep.DECLARE_BLOCKERS, true); + this.stepEvent = EventType.DECLARE_BLOCKERS_STEP; + this.preStepEvent = EventType.DECLARE_BLOCKERS_STEP_PRE; + this.postStepEvent = EventType.DECLARE_BLOCKERS_STEP_POST; + } + + @Override + public boolean skipStep(Game game, UUID activePlayerId) { + if (game.getCombat().noAttackers()) + return true; + return super.skipStep(game, activePlayerId); + } + + @Override + public void beginStep(Game game, UUID activePlayerId) { + super.beginStep(game, activePlayerId); + game.getCombat().selectBlockers(game); + } + +} diff --git a/Mage/src/mage/game/turn/DrawStep.java b/Mage/src/mage/game/turn/DrawStep.java new file mode 100644 index 0000000000..fe4b409696 --- /dev/null +++ b/Mage/src/mage/game/turn/DrawStep.java @@ -0,0 +1,60 @@ +/* + * 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.turn; + +import java.util.UUID; +import mage.Constants.PhaseStep; +import mage.game.Game; +import mage.game.events.GameEvent.EventType; +import mage.players.Player; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class DrawStep extends Step { + + public DrawStep() { + super(PhaseStep.DRAW, true); + this.stepEvent = EventType.DRAW_STEP; + this.preStepEvent = EventType.DRAW_STEP_PRE; + this.postStepEvent = EventType.DRAW_STEP_POST; + } + + @Override + public void beginStep(Game game, UUID activePlayerId) { + Player activePlayer = game.getPlayer(activePlayerId); + //20091005 - 504.1/703.4c + activePlayer.drawCards(1, game); + game.saveState(); + super.beginStep(game, activePlayerId); + } + + +} diff --git a/Mage/src/mage/game/turn/EndOfCombatStep.java b/Mage/src/mage/game/turn/EndOfCombatStep.java new file mode 100644 index 0000000000..1399e0d8cc --- /dev/null +++ b/Mage/src/mage/game/turn/EndOfCombatStep.java @@ -0,0 +1,57 @@ +/* + * 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.turn; + +import java.util.UUID; +import mage.Constants.PhaseStep; +import mage.game.Game; +import mage.game.events.GameEvent.EventType; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class EndOfCombatStep extends Step { + + public EndOfCombatStep() { + super(PhaseStep.END_COMBAT, true); + this.stepEvent = EventType.END_COMBAT_STEP; + this.preStepEvent = EventType.END_COMBAT_STEP_PRE; + this.postStepEvent = EventType.END_COMBAT_STEP_POST; + } + + @Override + public void endStep(Game game, UUID activePlayerId) { + super.endStep(game, activePlayerId); + //20091005 - 511.3 + game.getCombat().endCombat(game); + game.saveState(); + } + +} diff --git a/Mage/src/mage/game/turn/EndPhase.java b/Mage/src/mage/game/turn/EndPhase.java index 0a45055092..91c79d117c 100644 --- a/Mage/src/mage/game/turn/EndPhase.java +++ b/Mage/src/mage/game/turn/EndPhase.java @@ -28,8 +28,10 @@ package mage.game.turn; +import java.util.UUID; import mage.Constants.PhaseStep; import mage.Constants.TurnPhase; +import mage.game.Game; import mage.game.events.GameEvent.EventType; /** @@ -43,8 +45,21 @@ public class EndPhase extends Phase { this.event = EventType.END_PHASE; this.preEvent = EventType.END_PHASE_PRE; this.postEvent = EventType.END_PHASE_POST; - this.steps.add(new Step(PhaseStep.END_TURN)); - this.steps.add(new Step(PhaseStep.CLEANUP)); + this.steps.add(new EndStep()); + this.steps.add(new CleanupStep()); + } + + @Override + protected void playStep(Game game, UUID activePlayerId) { + if (currentStep.getType() == PhaseStep.CLEANUP) { + currentStep.beginStep(game, activePlayerId); + if (game.checkStateAndTriggered()) { + playStep(game, activePlayerId); + } + currentStep.endStep(game, activePlayerId); + } + else + super.playStep(game, activePlayerId); } } diff --git a/Mage/src/mage/game/turn/EndStep.java b/Mage/src/mage/game/turn/EndStep.java new file mode 100644 index 0000000000..454caecdeb --- /dev/null +++ b/Mage/src/mage/game/turn/EndStep.java @@ -0,0 +1,47 @@ +/* + * 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.turn; + +import mage.Constants.PhaseStep; +import mage.game.events.GameEvent.EventType; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class EndStep extends Step { + + public EndStep() { + super(PhaseStep.END_TURN, true); + this.stepEvent = EventType.END_TURN_STEP; + this.preStepEvent = EventType.END_TURN_STEP_PRE; + this.postStepEvent = EventType.END_TURN_STEP_POST; + } + +} diff --git a/Mage/src/mage/game/turn/Phase.java b/Mage/src/mage/game/turn/Phase.java index a3de5dee82..4eda1d7e7d 100644 --- a/Mage/src/mage/game/turn/Phase.java +++ b/Mage/src/mage/game/turn/Phase.java @@ -58,10 +58,12 @@ public abstract class Phase implements Serializable { return type; } - public PhaseStep getStep() { - if (currentStep != null) - return currentStep.getType(); - return null; + public Step getStep() { + return currentStep; + } + + public void setStep(Step step) { + this.currentStep = step; } public void resetCount() { @@ -85,13 +87,8 @@ public abstract class Phase implements Serializable { if (game.isGameOver()) return false; currentStep = step; - if (step.play(game, activePlayerId)) { - //20091005 - 500.4/703.4n - game.emptyManaPools(); - game.saveState(); - //20091005 - 500.9 - playExtraSteps(game, step.getType()); - } + if (!game.getState().getTurnMods().skipStep(activePlayerId, currentStep.getType())) + playStep(game, activePlayerId); } count++; game.fireEvent(new GameEvent(postEvent, null, null, activePlayerId)); @@ -100,14 +97,34 @@ public abstract class Phase implements Serializable { return false; } + public void prePriority(Game game, UUID activePlayerId) { + currentStep.beginStep(game, activePlayerId); + } + + public void postPriority(Game game, UUID activePlayerId) { + currentStep.endStep(game, activePlayerId); + //20091005 - 500.4/703.4n + game.emptyManaPools(); + game.saveState(); + //20091005 - 500.9 + playExtraSteps(game, currentStep.getType()); + } + + protected void playStep(Game game, UUID activePlayerId) { + if (!currentStep.skipStep(game, activePlayerId)) { + prePriority(game, activePlayerId); + currentStep.priority(game, activePlayerId); + postPriority(game, activePlayerId); + } + } + private void playExtraSteps(Game game, PhaseStep afterStep) { while (true) { - PhaseStep extraStep = game.getState().getTurnMods().extraStep(activePlayerId, afterStep); + Step extraStep = game.getState().getTurnMods().extraStep(activePlayerId, afterStep); if (extraStep == null) return; - Step step = new Step(extraStep); - currentStep = step; - step.play(game, activePlayerId); + currentStep = extraStep; + playStep(game, activePlayerId); } } diff --git a/Mage/src/mage/game/turn/PostCombatMainPhase.java b/Mage/src/mage/game/turn/PostCombatMainPhase.java index 9aa63d452d..6c6143f811 100644 --- a/Mage/src/mage/game/turn/PostCombatMainPhase.java +++ b/Mage/src/mage/game/turn/PostCombatMainPhase.java @@ -43,7 +43,7 @@ public class PostCombatMainPhase extends Phase { this.event = EventType.POSTCOMBAT_MAIN_PHASE; this.preEvent = EventType.POSTCOMBAT_MAIN_PHASE_PRE; this.postEvent = EventType.POSTCOMBAT_MAIN_STEP_POST; - this.steps.add(new Step(PhaseStep.POSTCOMBAT_MAIN)); + this.steps.add(new PostCombatMainStep()); } } diff --git a/Mage/src/mage/game/turn/PostCombatMainStep.java b/Mage/src/mage/game/turn/PostCombatMainStep.java new file mode 100644 index 0000000000..e24464dfcb --- /dev/null +++ b/Mage/src/mage/game/turn/PostCombatMainStep.java @@ -0,0 +1,47 @@ +/* + * 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.turn; + +import mage.Constants.PhaseStep; +import mage.game.events.GameEvent.EventType; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class PostCombatMainStep extends Step { + + public PostCombatMainStep() { + super(PhaseStep.POSTCOMBAT_MAIN, true); + this.stepEvent = EventType.POSTCOMBAT_MAIN_STEP; + this.preStepEvent = EventType.POSTCOMBAT_MAIN_STEP_PRE; + this.postStepEvent = EventType.POSTCOMBAT_MAIN_STEP_POST; + } + +} diff --git a/Mage/src/mage/game/turn/PreCombatMainPhase.java b/Mage/src/mage/game/turn/PreCombatMainPhase.java index 390f224935..a458e50695 100644 --- a/Mage/src/mage/game/turn/PreCombatMainPhase.java +++ b/Mage/src/mage/game/turn/PreCombatMainPhase.java @@ -28,7 +28,6 @@ package mage.game.turn; -import mage.Constants.PhaseStep; import mage.Constants.TurnPhase; import mage.game.events.GameEvent.EventType; @@ -43,7 +42,7 @@ public class PreCombatMainPhase extends Phase { this.event = EventType.PRECOMBAT_MAIN_PHASE; this.preEvent = EventType.PRECOMBAT_MAIN_PHASE_PRE; this.postEvent = EventType.PRECOMBAT_MAIN_PHASE_POST; - this.steps.add(new Step(PhaseStep.PRECOMBAT_MAIN)); + this.steps.add(new PreCombatMainStep()); } } diff --git a/Mage/src/mage/game/turn/PreCombatMainStep.java b/Mage/src/mage/game/turn/PreCombatMainStep.java new file mode 100644 index 0000000000..09504e3b97 --- /dev/null +++ b/Mage/src/mage/game/turn/PreCombatMainStep.java @@ -0,0 +1,47 @@ +/* + * 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.turn; + +import mage.Constants.PhaseStep; +import mage.game.events.GameEvent.EventType; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class PreCombatMainStep extends Step { + + public PreCombatMainStep() { + super(PhaseStep.PRECOMBAT_MAIN, true); + this.stepEvent = EventType.PRECOMBAT_MAIN_STEP; + this.preStepEvent = EventType.PRECOMBAT_MAIN_STEP_PRE; + this.postStepEvent = EventType.PRECOMBAT_MAIN_STEP_POST; + } + +} diff --git a/Mage/src/mage/game/turn/Step.java b/Mage/src/mage/game/turn/Step.java index 3305f9ea4d..8534d4864e 100644 --- a/Mage/src/mage/game/turn/Step.java +++ b/Mage/src/mage/game/turn/Step.java @@ -32,61 +32,49 @@ import java.io.Serializable; import java.util.UUID; import mage.Constants.PhaseStep; import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; /** * * @author BetaSteward_at_googlemail.com */ -public class Step implements Serializable { +public abstract class Step implements Serializable { private PhaseStep type; + private boolean hasPriority; + protected EventType stepEvent; + protected EventType preStepEvent; + protected EventType postStepEvent; - public Step(PhaseStep type) { + public Step(PhaseStep type, boolean hasPriority) { this.type = type; + this.hasPriority = hasPriority; } public PhaseStep getType() { return type; } - public boolean play(Game game, UUID activePlayerId) { - switch(type) { - case UNTAP: - return game.playUntapStep(activePlayerId); - case UPKEEP: - return game.playUpkeepStep(activePlayerId); - case DRAW: - return game.playDrawStep(activePlayerId); - case PRECOMBAT_MAIN: - return game.playPreCombatMainStep(activePlayerId); - case BEGIN_COMBAT: - return game.playBeginCombatStep(activePlayerId); - case DECLARE_ATTACKERS: - if (game.getPlayer(activePlayerId).hasAvailableAttackers(game)) - return game.playDeclareAttackersStep(activePlayerId); - return false; - case DECLARE_BLOCKERS: - if (!game.getCombat().noAttackers()) - return game.playDeclareBlockersStep(activePlayerId); - return false; - case FIRST_COMBAT_DAMAGE: - if (!game.getCombat().noAttackers() && game.getCombat().hasFirstOrDoubleStrike(game)) - return game.playCombatDamageStep(activePlayerId, true); - return false; - case COMBAT_DAMAGE: - if (!game.getCombat().noAttackers()) - return game.playCombatDamageStep(activePlayerId, false); - return false; - case END_COMBAT: - return game.playEndCombatStep(activePlayerId); - case POSTCOMBAT_MAIN: - return game.playPostMainStep(activePlayerId); - case END_TURN: - return game.playEndStep(activePlayerId); - case CLEANUP: - return game.playCleanupStep(activePlayerId); - } - return false; + public void beginStep(Game game, UUID activePlayerId) { + game.fireEvent(new GameEvent(preStepEvent, null, null, activePlayerId)); + } + + public void priority(Game game, UUID activePlayerId) { + if (hasPriority) + game.playPriority(activePlayerId); + } + + public void endStep(Game game, UUID activePlayerId) { + game.fireEvent(new GameEvent(postStepEvent, null, null, activePlayerId)); + } + + public boolean skipStep(Game game, UUID activePlayerId) { + return game.replaceEvent(new GameEvent(stepEvent, null, null, activePlayerId)); + } + + public boolean getHasPriority() { + return this.hasPriority; } } diff --git a/Mage/src/mage/game/turn/Turn.java b/Mage/src/mage/game/turn/Turn.java index 44e694597f..fa73dc1860 100644 --- a/Mage/src/mage/game/turn/Turn.java +++ b/Mage/src/mage/game/turn/Turn.java @@ -54,12 +54,16 @@ public class Turn implements Serializable { phases.add(new EndPhase()); } - public TurnPhase getPhase() { + public TurnPhase getPhaseType() { if (currentPhase != null) return currentPhase.getType(); return null; } + public Phase getPhase() { + return currentPhase; + } + public Phase getPhase(TurnPhase turnPhase) { for (Phase phase: phases) { if (phase.getType() == turnPhase) { @@ -69,16 +73,29 @@ public class Turn implements Serializable { return null; } - public PhaseStep getStep() { + public void setPhase(Phase phase) { + this.currentPhase = phase; + } + + public Step getStep() { if (currentPhase != null) return currentPhase.getStep(); return null; } + public PhaseStep getStepType() { + if (currentPhase != null && currentPhase.getStep() != null) + return currentPhase.getStep().getType(); + return null; + } + public void play(Game game, UUID activePlayerId) { if (game.isGameOver()) return; + if (game.getState().getTurnMods().skipTurn(activePlayerId)) + return; + this.activePlayerId = activePlayerId; resetCounts(); game.getPlayer(activePlayerId).beginTurn(game); @@ -86,12 +103,14 @@ public class Turn implements Serializable { if (game.isGameOver()) return; currentPhase = phase; - if (phase.play(game, activePlayerId)) { - //20091005 - 500.4/703.4n - game.emptyManaPools(); - game.saveState(); - //20091005 - 500.8 - playExtraPhases(game, phase.getType()); + if (!game.getState().getTurnMods().skipPhase(activePlayerId, currentPhase.getType())) { + if (phase.play(game, activePlayerId)) { + //20091005 - 500.4/703.4n + game.emptyManaPools(); + game.saveState(); + //20091005 - 500.8 + playExtraPhases(game, phase.getType()); + } } } //20091005 - 500.7 diff --git a/Mage/src/mage/game/turn/TurnMod.java b/Mage/src/mage/game/turn/TurnMod.java index 6d68eb911f..ecff96b88e 100644 --- a/Mage/src/mage/game/turn/TurnMod.java +++ b/Mage/src/mage/game/turn/TurnMod.java @@ -42,14 +42,20 @@ public class TurnMod implements Serializable { private UUID playerId; private boolean extraTurn; + private boolean skipTurn; private TurnPhase extraPhase; - private PhaseStep extraStep; + private TurnPhase skipPhase; + private Step extraStep; + private PhaseStep skipStep; private TurnPhase afterPhase; private PhaseStep afterStep; - public TurnMod(UUID playerId) { + public TurnMod(UUID playerId, boolean skip) { this.playerId = playerId; - this.extraTurn = true; + if (skip) + this.skipTurn = true; + else + this.extraTurn = true; } /** @@ -58,9 +64,12 @@ public class TurnMod implements Serializable { * @param extraPhase * @param afterPhase - set to null if extraPhase is after the next phase */ - public TurnMod(UUID playerId, TurnPhase extraPhase, TurnPhase afterPhase) { + public TurnMod(UUID playerId, TurnPhase phase, TurnPhase afterPhase, boolean skip) { this.playerId = playerId; - this.extraPhase = extraPhase; + if (skip) + this.skipPhase = phase; + else + this.extraPhase = phase; this.afterPhase = afterPhase; } @@ -70,12 +79,17 @@ public class TurnMod implements Serializable { * @param extraStep * @param afterStep - set to null if extraStep is after the next step */ - public TurnMod(UUID playerId, PhaseStep extraStep, PhaseStep afterStep) { + public TurnMod(UUID playerId, Step step, PhaseStep afterStep) { this.playerId = playerId; - this.extraStep = extraStep; + this.extraStep = step; this.afterStep = afterStep; } + public TurnMod(UUID playerId, PhaseStep step) { + this.playerId = playerId; + this.skipStep = step; + } + public UUID getPlayerId() { return playerId; } @@ -84,14 +98,26 @@ public class TurnMod implements Serializable { return extraTurn; } + public boolean isSkipTurn() { + return skipTurn; + } + public TurnPhase getExtraPhase() { return extraPhase; } - public PhaseStep getExtraStep() { + public Step getExtraStep() { return extraStep; } + public TurnPhase getSkipPhase() { + return skipPhase; + } + + public PhaseStep getSkipStep() { + return skipStep; + } + public TurnPhase getAfterPhase() { return afterPhase; } diff --git a/Mage/src/mage/game/turn/TurnMods.java b/Mage/src/mage/game/turn/TurnMods.java index 26ba2efe9a..bcf8b8f3ef 100644 --- a/Mage/src/mage/game/turn/TurnMods.java +++ b/Mage/src/mage/game/turn/TurnMods.java @@ -52,7 +52,19 @@ public class TurnMods extends ArrayList { return false; } - public PhaseStep extraStep(UUID playerId, PhaseStep afterStep) { + public boolean skipTurn(UUID playerId) { + ListIterator it = this.listIterator(this.size()); + while (it.hasPrevious()) { + TurnMod turnMod = it.previous(); + if (turnMod.isSkipTurn() == true && turnMod.getPlayerId().equals(playerId)) { + it.remove(); + return true; + } + } + return false; + } + + public Step extraStep(UUID playerId, PhaseStep afterStep) { ListIterator it = this.listIterator(this.size()); while (it.hasPrevious()) { TurnMod turnMod = it.previous(); @@ -64,6 +76,18 @@ public class TurnMods extends ArrayList { return null; } + public boolean skipStep(UUID playerId, PhaseStep step) { + ListIterator it = this.listIterator(this.size()); + while (it.hasPrevious()) { + TurnMod turnMod = it.previous(); + if (turnMod.getSkipStep() != null && turnMod.getPlayerId().equals(playerId) && turnMod.getSkipStep() == step) { + it.remove(); + return true; + } + } + return false; + } + public TurnPhase extraPhase(UUID playerId, TurnPhase afterPhase) { ListIterator it = this.listIterator(this.size()); while (it.hasPrevious()) { @@ -76,4 +100,16 @@ public class TurnMods extends ArrayList { return null; } + public boolean skipPhase(UUID playerId, TurnPhase phase) { + ListIterator it = this.listIterator(this.size()); + while (it.hasPrevious()) { + TurnMod turnMod = it.previous(); + if (turnMod.getSkipPhase() != null && turnMod.getPlayerId().equals(playerId) && turnMod.getSkipPhase() == phase) { + it.remove(); + return true; + } + } + return false; + } + } diff --git a/Mage/src/mage/game/turn/UntapStep.java b/Mage/src/mage/game/turn/UntapStep.java new file mode 100644 index 0000000000..8e7d59bfda --- /dev/null +++ b/Mage/src/mage/game/turn/UntapStep.java @@ -0,0 +1,61 @@ +/* + * 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.turn; + +import java.util.UUID; +import mage.Constants.PhaseStep; +import mage.game.Game; +import mage.game.events.GameEvent.EventType; +import mage.players.Player; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class UntapStep extends Step { + + public UntapStep() { + super(PhaseStep.UNTAP, false); + this.stepEvent = EventType.UNTAP_STEP; + this.preStepEvent = EventType.UNTAP_STEP_PRE; + this.postStepEvent = EventType.UNTAP_STEP_POST; + } + + @Override + public void beginStep(Game game, UUID activePlayerId) { + super.beginStep(game, activePlayerId); + Player activePlayer = game.getPlayer(activePlayerId); + //20091005 - 502.1/703.4a + activePlayer.phasing(game); + //20091005 - 502.2/703.4b + activePlayer.untap(game); + } + + +} diff --git a/Mage/src/mage/game/turn/UpkeepStep.java b/Mage/src/mage/game/turn/UpkeepStep.java new file mode 100644 index 0000000000..3a96c9ba33 --- /dev/null +++ b/Mage/src/mage/game/turn/UpkeepStep.java @@ -0,0 +1,47 @@ +/* + * 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.turn; + +import mage.Constants.PhaseStep; +import mage.game.events.GameEvent.EventType; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class UpkeepStep extends Step { + + public UpkeepStep() { + super(PhaseStep.UPKEEP, true); + this.stepEvent = EventType.UPKEEP_STEP; + this.preStepEvent = EventType.UPKEEP_STEP_PRE; + this.postStepEvent = EventType.UPKEEP_STEP_POST; + } + +} diff --git a/Mage/src/mage/players/Library.java b/Mage/src/mage/players/Library.java index e0c8461a0a..d24090f48b 100644 --- a/Mage/src/mage/players/Library.java +++ b/Mage/src/mage/players/Library.java @@ -74,6 +74,13 @@ public class Library implements Serializable { } } + /** + * Removes the top card of the Library and returns it + * + * @param game + * @return Card + * @see Card + */ public Card removeFromTop(Game game) { Card card = library.pollFirst(); if (card == null) { @@ -82,6 +89,13 @@ public class Library implements Serializable { return card; } + /** + * Returns the top card of the Library without removing it + * + * @param game + * @return Card + * @see Card + */ public Card getFromTop(Game game) { return library.peekFirst(); } diff --git a/Mage/src/mage/players/Player.java b/Mage/src/mage/players/Player.java index 8c8aae0e91..b838318f84 100644 --- a/Mage/src/mage/players/Player.java +++ b/Mage/src/mage/players/Player.java @@ -35,7 +35,9 @@ import mage.Constants.Outcome; import mage.MageItem; import mage.MageObject; import mage.abilities.Abilities; +import mage.abilities.Ability; import mage.abilities.ActivatedAbility; +import mage.abilities.SpellAbility; import mage.abilities.TriggeredAbilities; import mage.abilities.TriggeredAbility; import mage.abilities.costs.mana.ManaCost; @@ -50,6 +52,7 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.Token; import mage.target.Target; +import mage.target.TargetAmount; import mage.target.TargetCard; import mage.target.common.TargetCardInLibrary; @@ -71,8 +74,10 @@ public interface Player extends MageItem { public void gainLife(int amount, Game game); public int damage(int damage, UUID sourceId, Game game); public Cards getHand(); + public int getLandsPlayed(); public boolean isPassed(); public boolean isEmptyDraw(); + public void pass(); public void resetPassed(); public boolean hasLost(); public boolean hasWon(); @@ -84,7 +89,7 @@ public interface Player extends MageItem { public void reset(); public void shuffleLibrary(Game game); public int drawCards(int num, Game game); - public boolean cast(Card card, Game game, boolean noMana); + public boolean cast(SpellAbility ability, Game game, boolean noMana); public boolean putInHand(Card card, Game game); public boolean removeFromHand(Card card, Game game); public boolean putOntoBattlefield(Card card, Game game); @@ -97,7 +102,7 @@ public interface Player extends MageItem { public boolean playLand(Card card, Game game); public boolean activateAbility(ActivatedAbility ability, Game game); public boolean triggerAbility(TriggeredAbility ability, Game game); - public boolean canTarget(MageObject source); + public boolean canBeTargetedBy(MageObject source); public void checkTriggers(GameEvent event, Game game); public void discard(int amount, Game game); public void discardToMax(Game game); @@ -109,7 +114,8 @@ public interface Player extends MageItem { public void abort(); public void revealCards(Cards cards, Game game); - + public void lookAtCards(Cards cards, Game game); + public Player copy(); public void restore(Player player); @@ -120,12 +126,13 @@ public interface Player extends MageItem { public abstract void priority(Game game); public abstract boolean chooseTarget(Outcome outcome, Target target, Game game); + public abstract boolean chooseTarget(Cards cards, TargetCard target, Game game); + public abstract boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Game game); public abstract boolean chooseMulligan(Game game); public abstract boolean chooseUse(Outcome outcome, String message, Game game); public abstract boolean choose(Outcome outcome, Choice choice, Game game); public abstract boolean playMana(ManaCost unpaid, Game game); public abstract boolean playXMana(VariableManaCost cost, Game game); - public abstract boolean searchCards(Cards cards, TargetCard target, Game game); public abstract int chooseEffect(List rEffects, Game game); public abstract TriggeredAbility chooseTriggeredAbility(TriggeredAbilities abilities, Game game); public abstract void selectAttackers(Game game); @@ -142,4 +149,7 @@ public interface Player extends MageItem { public void phasing(Game game); public void untap(Game game); + public List getPlayable(Game game, boolean hidden); + public List getPlayableOptions(Ability ability, Game game); + } diff --git a/Mage/src/mage/players/PlayerImpl.java b/Mage/src/mage/players/PlayerImpl.java index b813213b70..8f8d185266 100644 --- a/Mage/src/mage/players/PlayerImpl.java +++ b/Mage/src/mage/players/PlayerImpl.java @@ -41,8 +41,10 @@ import mage.Constants.Outcome; import mage.Constants.RangeOfInfluence; import mage.Constants.Zone; 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.PlayLandAbility; import mage.abilities.SpecialAction; @@ -52,6 +54,7 @@ import mage.abilities.keyword.KickerAbility; import mage.abilities.keyword.ProtectionAbility; import mage.abilities.keyword.ShroudAbility; import mage.abilities.mana.ManaAbility; +import mage.abilities.mana.ManaOptions; import mage.cards.Card; import mage.cards.Cards; import mage.cards.CardsImpl; @@ -106,6 +109,10 @@ public abstract class PlayerImpl implements Player, Serializable { library.addAll(deck.getCards()); } + protected PlayerImpl(UUID id) { + this.playerId = id; + } + @Override public void init(Game game) { this.hand.clear(); @@ -161,18 +168,18 @@ public abstract class PlayerImpl implements Player, Serializable { } else { inRange.add(playerId); - PlayerList players = game.getPlayerList(playerId); + PlayerList players = game.getState().getPlayerList(playerId); for (int i = 0; i < range.getRange(); i++) { - Player player = players.getNext(); + Player player = players.getNext(game); while (player.hasLeft()) - player = players.getNext(); + player = players.getNext(game); inRange.add(player.getId()); } - players = game.getPlayerList(playerId); + players = game.getState().getPlayerList(playerId); for (int i = 0; i < range.getRange(); i++) { - Player player = players.getPrevious(); + Player player = players.getPrevious(game); while (player.hasLeft()) - player = players.getPrevious(); + player = players.getPrevious(game); inRange.add(player.getId()); } } @@ -196,7 +203,7 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean canTarget(MageObject source) { + public boolean canBeTargetedBy(MageObject source) { if (this.hasLost() || this.hasLeft()) return false; if (source != null) { @@ -251,6 +258,8 @@ public abstract class PlayerImpl implements Player, Serializable { public boolean putInHand(Card card, Game game) { if (card.getOwnerId().equals(playerId)) { this.hand.add(card); + if (card.getSpellAbility() != null) + card.getSpellAbility().clear(); } else { return game.getPlayer(card.getOwnerId()).putInHand(card, game); } @@ -337,24 +346,25 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean cast(Card card, Game game, boolean noMana) { + public boolean cast(SpellAbility ability, Game game, boolean noMana) { //20091005 - 601.2a - if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, card.getId(), playerId))) { - game.bookmarkState(); - removeFromHand(card, game); - - game.getStack().push(new Spell(card, playerId)); - card.getSpellAbility().clear(); - if (card.getSpellAbility().activate(game, noMana)) { - for (KickerAbility ability: card.getAbilities().getKickerAbilities()) { - ability.copy().activate(game, false); + Card card = game.getCard(ability.getSourceId()); + if (card != null) { + if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, card.getId(), playerId))) { + game.bookmarkState(); + removeFromHand(card, game); + game.getStack().push(new Spell(card, ability, playerId)); + if (ability.activate(game, noMana)) { + for (KickerAbility kicker: card.getAbilities().getKickerAbilities()) { + kicker.activate(game, false); + } + game.fireEvent(GameEvent.getEvent(GameEvent.EventType.SPELL_CAST, card.getId(), playerId)); + game.fireInformEvent(name + " casts " + card.getName()); + game.removeLastBookmark(); + return true; } - game.fireEvent(GameEvent.getEvent(GameEvent.EventType.SPELL_CAST, card.getId(), playerId)); - game.fireInformEvent(name + " casts " + card.getName()); - game.removeLastBookmark(); - return true; + game.restoreState(); } - game.restoreState(); } return false; } @@ -437,7 +447,7 @@ public abstract class PlayerImpl implements Player, Serializable { result = playManaAbility((ManaAbility)ability.copy(), game); } else if (ability instanceof SpellAbility) { - result = cast(hand.get(ability.getSourceId()), game, false); + result = cast((SpellAbility)ability, game, false); } else { result = playAbility((ActivatedAbility)ability.copy(), game); @@ -455,10 +465,12 @@ public abstract class PlayerImpl implements Player, Serializable { game.saveState(); game.bookmarkState(); TriggeredAbility ability = (TriggeredAbility) source.copy(); - game.getStack().push(new StackAbility(ability, playerId)); - if (ability.activate(game, false)) { - game.removeLastBookmark(); - return true; + if (ability.getTargets().canChoose(ability.getSourceId(), playerId, game)) { + game.getStack().push(new StackAbility(ability, playerId)); + if (ability.activate(game, false)) { + game.removeLastBookmark(); + return true; + } } game.restoreState(); return false; @@ -473,6 +485,11 @@ public abstract class PlayerImpl implements Player, Serializable { return useable; } + @Override + public int getLandsPlayed() { + return landsPlayed; + } + @Override public boolean canPlayLand() { //20091005 - 114.2a @@ -493,6 +510,11 @@ public abstract class PlayerImpl implements Player, Serializable { game.fireRevealCardsEvent(this.name + " revealed", cards); } + @Override + public void lookAtCards(Cards cards, Game game) { + game.fireLookAtCardsEvent(playerId, this.name + " looking at", cards); + } + @Override public void phasing(Game game) { //20091005 - 502.1 @@ -630,6 +652,8 @@ public abstract class PlayerImpl implements Player, Serializable { this.manaPool = player.getManaPool(); this.life = player.getLife(); this.counters = player.getCounters(); + this.inRange = player.getInRange(); + this.landsPlayed = player.getLandsPlayed(); } @Override @@ -637,6 +661,11 @@ public abstract class PlayerImpl implements Player, Serializable { return passed; } + @Override + public void pass() { + this.passed = true; + } + @Override public boolean isEmptyDraw() { return library.isEmtpyDraw(); @@ -645,9 +674,9 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public void resetPassed() { if (!this.loses && !this.left) - passed = false; + this.passed = false; else - passed = true; + this.passed = true; } @Override @@ -668,6 +697,11 @@ public abstract class PlayerImpl implements Player, Serializable { for (Iterator it = game.getBattlefield().getAllPermanents().iterator(); it.hasNext();) { Permanent perm = it.next(); if (perm.getOwnerId().equals(playerId)) { + if (perm.getAttachedTo() != null) { + Permanent attachedTo = game.getPermanent(perm.getAttachedTo()); + if (attachedTo != null) + attachedTo.removeAttachment(perm.getId(), game); + } it.remove(); } } @@ -756,15 +790,15 @@ public abstract class PlayerImpl implements Player, Serializable { public boolean searchLibrary(TargetCardInLibrary target, Game game) { //20091005 - 701.14c if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.SEARCH_LIBRARY, playerId, playerId))) { - if (library.count(target.getFilter()) < target.getNumberOfTargets()) { - TargetCardInLibrary newTarget = new TargetCardInLibrary(library.count(target.getFilter()), target.getMaxNumberOfTargets(), target.getFilter()); - searchCards(new CardsImpl(Zone.LIBRARY, getLibrary().getCards()), newTarget, game); + TargetCardInLibrary newTarget; + if (library.count(target.getFilter()) < target.getNumberOfTargets()) + newTarget = new TargetCardInLibrary(library.count(target.getFilter()), target.getMaxNumberOfTargets(), target.getFilter()); + else + newTarget = target; + if (chooseTarget(new CardsImpl(Zone.LIBRARY, getLibrary().getCards()), newTarget, game)) { + game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LIBRARY_SEARCHED, playerId, playerId)); + return true; } - else { - searchCards(new CardsImpl(Zone.LIBRARY, getLibrary().getCards()), target, game); - } - game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LIBRARY_SEARCHED, playerId, playerId)); - return true; } return false; } @@ -781,4 +815,138 @@ public abstract class PlayerImpl implements Player, Serializable { return attackers; } + protected ManaOptions getManaAvailable(Game game) { + List manaPerms = this.getAvailableManaProducers(game); + + ManaOptions available = new ManaOptions(); + for (Permanent perm: manaPerms) { + available.addMana(perm.getAbilities().getManaAbilities(Zone.BATTLEFIELD), game); + } + return available; + } + + protected List getAvailableManaProducers(Game game) { + List result = new ArrayList(); + for (Permanent permanent: game.getBattlefield().getAllActivePermanents(playerId)) { + for (ManaAbility ability: permanent.getAbilities().getManaAbilities(Zone.BATTLEFIELD)) { + if (ability.canActivate(playerId, game)) { + result.add(permanent); + break; + } + } + } + return result; + } + + protected boolean canPlay(ActivatedAbility ability, ManaOptions available, Game game) { + if (!(ability instanceof ManaAbility) && ability.canActivate(playerId, game)) { + ManaOptions abilityOptions = ability.getManaCosts().getOptions(); + if (abilityOptions.size() == 0) { + return true; + } + else { + for (Mana mana: abilityOptions) { + for (Mana avail: available) { + if (mana.enough(avail)) { + return true; + } + } + } + } + + } + return false; + } + + @Override + public List getPlayable(Game game, boolean hidden) { + List playable = new ArrayList(); + + ManaOptions available = getManaAvailable(game); + available.addMana(manaPool.getMana()); + + if (hidden) { + for (Card card: hand.getUniqueCards()) { + for (ActivatedAbility ability: card.getAbilities().getActivatedAbilities(Zone.HAND)) { + if (canPlay(ability, available, game)) + playable.add(ability); + } + } + } + for (Card card: graveyard.getUniqueCards()) { + for (ActivatedAbility ability: card.getAbilities().getActivatedAbilities(Zone.GRAVEYARD)) { + if (canPlay(ability, available, game)) + playable.add(ability); + } + } + for (Permanent permanent: game.getBattlefield().getAllActivePermanents(playerId)) { + for (ActivatedAbility ability: permanent.getAbilities().getActivatedAbilities(Zone.BATTLEFIELD)) { + if (canPlay(ability, available, game)) + playable.add(ability); + } + } + return playable; + } + + @Override + public List getPlayableOptions(Ability ability, Game game) { + List options = new ArrayList(); + + if (ability.getTargets().size() > 0) + addTargetOptions(options, ability, 0, game); + else if (ability.getChoices().size() > 0) + addChoiceOptions(options, ability, 0, game); + else if (ability.getCosts().getTargets().size() > 0) + addCostTargetOptions(options, ability, 0, game); + + return options; + } + + private void addTargetOptions(List options, Ability option, int targetNum, Game game) { + for (UUID targetId: option.getTargets().get(targetNum).possibleTargets(option.getSourceId(), playerId, game)) { + Ability newOption = option.copy(); + newOption.getTargets().get(targetNum).addTarget(targetId, game); + if (targetNum < option.getTargets().size() - 1) { + addTargetOptions(options, newOption, targetNum + 1, game); + } + else { + if (option.getChoices().size() > 0) + addChoiceOptions(options, newOption, 0, game); + else if (option.getCosts().getTargets().size() > 0) + addCostTargetOptions(options, newOption, 0, game); + else + options.add(newOption); + } + } + } + + private void addChoiceOptions(List options, Ability option, int choiceNum, Game game) { + for (String choice: option.getChoices().get(choiceNum).getChoices()) { + Ability newOption = option.copy(); + newOption.getChoices().get(choiceNum).setChoice(choice); + if (choiceNum < option.getChoices().size() - 1) { + addChoiceOptions(options, newOption, choiceNum + 1, game); + } + else { + if (option.getCosts().getTargets().size() > 0) + addCostTargetOptions(options, newOption, 0, game); + else + options.add(newOption); + } + } + } + + private void addCostTargetOptions(List options, Ability option, int targetNum, Game game) { + for (UUID targetId: option.getCosts().getTargets().get(targetNum).possibleTargets(option.getSourceId(), playerId, game)) { + Ability newOption = option.copy(); + newOption.getCosts().getTargets().get(targetNum).addTarget(targetId, game); + if (targetNum < option.getCosts().getTargets().size() - 1) { + addCostTargetOptions(options, newOption, targetNum + 1, game); + } + else { + options.add(newOption); + } + } + } + } diff --git a/Mage/src/mage/players/PlayerList.java b/Mage/src/mage/players/PlayerList.java index fa0759cbe3..ce81d857f8 100644 --- a/Mage/src/mage/players/PlayerList.java +++ b/Mage/src/mage/players/PlayerList.java @@ -29,22 +29,39 @@ package mage.players; import java.util.UUID; +import mage.game.Game; import mage.util.CircularList; /** * * @author BetaSteward_at_googlemail.com */ -public class PlayerList extends CircularList { +public class PlayerList extends CircularList { - public boolean setCurrent(UUID playerId) { - for (int i = 0; i < list.size(); i++) { - if (list.get(i).getId().equals(playerId)) { - index = i; - return true; - } + public Player getNext(Game game) { + Player player; + UUID start = this.get(); + while (true) { + player = game.getPlayer(super.getNext()); + if (!player.hasLeft() && !player.hasLost()) + break; + if (player.getId().equals(start)) + return null; } - return false; + return player; + } + + public Player getPrevious(Game game) { + Player player; + UUID start = this.get(); + while (true) { + player = game.getPlayer(super.getPrevious()); + if (!player.hasLeft() && !player.hasLost()) + break; + if (player.getId().equals(start)) + return null; + } + return player; } } diff --git a/Mage/src/mage/target/Target.java b/Mage/src/mage/target/Target.java index c8b6c09c45..ddb933036c 100644 --- a/Mage/src/mage/target/Target.java +++ b/Mage/src/mage/target/Target.java @@ -47,15 +47,19 @@ public interface Target extends Serializable { public boolean doneChosing(); public void clearChosen(); public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game); + public List possibleTargets(UUID sourceId, UUID sourceControllerId, Game game); public boolean choose(Outcome outcome, Game game); public String getMessage(); public String getTargetName(); + public void setTargetName(String name); public String getTargetedName(Game game); public Zone getZone(); public boolean isLegal(Game game); public boolean canTarget(UUID id, Game game); public void addTarget(UUID id, Game game); + public void addTarget(UUID id, int amount, Game game); + public int getTargetAmount(UUID targetId); public int getNumberOfTargets(); public int getMaxNumberOfTargets(); public List getTargets(); @@ -66,6 +70,6 @@ public interface Target extends Serializable { public boolean isRequired(); public void setRequired(boolean required); - public UUID getLastTarget(); +// public UUID getLastTarget(); public UUID getFirstTarget(); } diff --git a/Mage/src/mage/target/TargetAmount.java b/Mage/src/mage/target/TargetAmount.java new file mode 100644 index 0000000000..dc2b4c8bc6 --- /dev/null +++ b/Mage/src/mage/target/TargetAmount.java @@ -0,0 +1,87 @@ +/* + * 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.target; + +import java.util.UUID; +import mage.Constants.Outcome; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public abstract class TargetAmount extends TargetImpl { + + int amount; + int remainingAmount; + + public TargetAmount(int amount) { + this.amount = amount; + this.remainingAmount = amount; + this.required = true; + } + + public int getAmountRemaining() { + return remainingAmount; + } + + @Override + public boolean doneChosing() { + return remainingAmount == 0; + } + + @Override + public void clearChosen() { + super.clearChosen(); + remainingAmount = amount; + } + + @Override + public void addTarget(UUID id, int amount, Game game) { + if (amount <= remainingAmount) { + super.addTarget(id, amount, game); + remainingAmount -= amount; + } + } + + @Override + public boolean choose(Outcome outcome, Game game) { + Player player = game.getPlayer(this.source.getControllerId()); + chosen = remainingAmount == 0; + while (remainingAmount > 0) { + if (!player.chooseTargetAmount(outcome, this, game)) { + return chosen; + } + chosen = remainingAmount == 0; + } + return chosen = true; + } + +} diff --git a/Mage/src/mage/target/TargetCard.java b/Mage/src/mage/target/TargetCard.java index 7df6afb901..fe7f118994 100644 --- a/Mage/src/mage/target/TargetCard.java +++ b/Mage/src/mage/target/TargetCard.java @@ -28,6 +28,8 @@ package mage.target; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; import mage.Constants.Zone; import mage.cards.Card; @@ -69,6 +71,23 @@ public class TargetCard extends TargetObject { return this.filter; } + public boolean choose(Cards cards, Game game) { + Player player = game.getPlayer(this.source.getControllerId()); + while (!isChosen() && !doneChosing()) { + chosen = targets.size() >= minNumberOfTargets; + if (!player.chooseTarget(cards, this, game)) { + return chosen; + } + chosen = targets.size() >= minNumberOfTargets; + } + while (!doneChosing()) { + if (!player.chooseTarget(cards, this, game)) { + break; + } + } + return chosen = true; + } + @Override public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { for (UUID playerId: game.getPlayer(sourceControllerId).getInRange()) { @@ -77,11 +96,15 @@ public class TargetCard extends TargetObject { if (player != null) { switch (zone) { case HAND: - if (player.getHand().getCards(filter).size() > this.minNumberOfTargets) + if (player.getHand().count(filter) >= this.minNumberOfTargets) return true; break; case GRAVEYARD: - if (player.getGraveyard().getCards(filter).size() > this.minNumberOfTargets) + if (player.getGraveyard().count(filter) >= this.minNumberOfTargets) + return true; + break; + case LIBRARY: + if (player.getLibrary().count(filter) >= this.minNumberOfTargets) return true; break; } @@ -91,6 +114,32 @@ public class TargetCard extends TargetObject { return false; } + @Override + public List possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + List possibleTargets = new ArrayList(); + for (UUID playerId: game.getPlayer(sourceControllerId).getInRange()) { + if (filter.matchOwner(playerId)) { + Player player = game.getPlayer(playerId); + if (player != null) { + switch (zone) { + case HAND: + for (Card card: player.getHand().getCards(filter)) { + possibleTargets.add(card.getId()); + } + break; + case GRAVEYARD: + for (Card card: player.getGraveyard().getCards(filter)) { + possibleTargets.add(card.getId()); + } + break; + } + } + } + } + return possibleTargets; + + } + public boolean canTarget(UUID id, Cards cards, Game game) { Card card = cards.get(id); if (card != null) diff --git a/Mage/src/mage/target/TargetImpl.java b/Mage/src/mage/target/TargetImpl.java index 4d2859cb42..4e226df297 100644 --- a/Mage/src/mage/target/TargetImpl.java +++ b/Mage/src/mage/target/TargetImpl.java @@ -29,7 +29,9 @@ package mage.target; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.UUID; import mage.Constants.Outcome; import mage.Constants.Zone; @@ -45,7 +47,7 @@ import mage.players.Player; */ public abstract class TargetImpl implements Target { - protected List targets = new ArrayList(); + protected Map targets = new HashMap(); protected String targetName; protected Zone zone; @@ -75,6 +77,11 @@ public abstract class TargetImpl implements Target { return targetName; } + @Override + public void setTargetName(String name) { + this.targetName = name; + } + @Override public Zone getZone() { return zone; @@ -114,14 +121,33 @@ public abstract class TargetImpl implements Target { */ @Override public void addTarget(UUID id, Game game) { + //20100423 - 113.3 + if (!targets.containsKey(id)) { + if (source != null) { + if (!game.replaceEvent(GameEvent.getEvent(EventType.TARGET, id, source.getSourceId(), source.getControllerId()))) { + targets.put(id, 0); + game.fireEvent(GameEvent.getEvent(EventType.TARGETED, id, source.getSourceId(), source.getControllerId())); + } + } + else { + targets.put(id, 0); + } + } + } + + @Override + public void addTarget(UUID id, int amount, Game game) { + if (targets.containsKey(id)) { + amount += targets.get(id); + } if (source != null) { if (!game.replaceEvent(GameEvent.getEvent(EventType.TARGET, id, source.getSourceId(), source.getControllerId()))) { - targets.add(id); + targets.put(id, amount); game.fireEvent(GameEvent.getEvent(EventType.TARGETED, id, source.getSourceId(), source.getControllerId())); } } else { - targets.add(id); + targets.put(id, amount); } } @@ -146,7 +172,7 @@ public abstract class TargetImpl implements Target { @Override public boolean isLegal(Game game) { - for (UUID targetId: targets) { + for (UUID targetId: targets.keySet()) { if (!canTarget(targetId, game)) return false; } @@ -155,20 +181,27 @@ public abstract class TargetImpl implements Target { @Override public List getTargets() { - return targets; + return new ArrayList(targets.keySet()); } @Override - public UUID getLastTarget() { - if (targets.size() > 0) - return targets.get(targets.size() - 1); - return null; + public int getTargetAmount(UUID targetId) { + if (targets.containsKey(targetId)) + return targets.get(targetId); + return 0; } +// @Override +// public UUID getLastTarget() { +// if (targets.size() > 0) +// return targets.keySet().iterator().next(); +// return null; +// } + @Override public UUID getFirstTarget() { if (targets.size() > 0) - return targets.get(0); + return targets.keySet().iterator().next(); return null; } diff --git a/Mage/src/mage/target/TargetPermanent.java b/Mage/src/mage/target/TargetPermanent.java index 7a78a58ed2..9ae229e8fd 100644 --- a/Mage/src/mage/target/TargetPermanent.java +++ b/Mage/src/mage/target/TargetPermanent.java @@ -28,11 +28,13 @@ package mage.target; +import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.UUID; import mage.Constants.TargetController; import mage.Constants.Zone; +import mage.MageObject; import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -116,17 +118,28 @@ public class TargetPermanent extends TargetObject { @Override public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - List permanents = game.getBattlefield().getActivePermanents(filter, sourceControllerId, game); - Iterator it = permanents.iterator(); - while(it.hasNext()) { - Permanent permanent = it.next(); - if (!permanent.canBeTargetedBy(game.getObject(sourceId))) { - it.remove(); + int count = 0; + MageObject targetSource = game.getObject(sourceId); + for (Permanent permanent: game.getBattlefield().getActivePermanents(filter, sourceControllerId, game)) { + if (permanent.canBeTargetedBy(targetSource)) { + count++; + if (count >= this.minNumberOfTargets) + return true; } } - if (permanents.size() >= this.minNumberOfTargets) - return true; return false; } + @Override + public List possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + List possibleTargets = new ArrayList(); + MageObject targetSource = game.getObject(sourceId); + for (Permanent permanent: game.getBattlefield().getActivePermanents(filter, sourceControllerId, game)) { + if (permanent.canBeTargetedBy(targetSource)) { + possibleTargets.add(permanent.getId()); + } + } + return possibleTargets; + } + } diff --git a/Mage/src/mage/target/TargetPlayer.java b/Mage/src/mage/target/TargetPlayer.java index c7e16a190d..4c2eaafef2 100644 --- a/Mage/src/mage/target/TargetPlayer.java +++ b/Mage/src/mage/target/TargetPlayer.java @@ -28,8 +28,11 @@ package mage.target; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; import mage.Constants.Zone; +import mage.MageObject; import mage.filter.FilterPlayer; import mage.game.Game; import mage.players.Player; @@ -65,21 +68,37 @@ public class TargetPlayer extends TargetImpl { @Override public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { int count = 0; + MageObject targetSource = game.getObject(sourceId); for (UUID playerId: game.getPlayer(sourceControllerId).getInRange()) { Player player = game.getPlayer(playerId); if (player != null && !player.hasLeft() && filter.match(player)) { - if (player.canTarget(game.getObject(sourceId))) + if (player.canBeTargetedBy(targetSource)) { count++; + if (count >= this.minNumberOfTargets) + return true; + } } } - if (count >= this.minNumberOfTargets) - return true; return false; } + @Override + public List possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + List possibleTargets = new ArrayList(); + MageObject targetSource = game.getObject(sourceId); + for (UUID playerId: game.getPlayer(sourceControllerId).getInRange()) { + Player player = game.getPlayer(playerId); + if (player != null && !player.hasLeft() && filter.match(player)) { + if (player.canBeTargetedBy(targetSource)) + possibleTargets.add(playerId); + } + } + return possibleTargets; + } + @Override public boolean isLegal(Game game) { - for (UUID playerId: targets) { + for (UUID playerId: targets.keySet()) { if (!canTarget(playerId, game)) return false; } @@ -91,7 +110,7 @@ public class TargetPlayer extends TargetImpl { Player player = game.getPlayer(id); if (player != null) { if (source != null) - return player.canTarget(game.getObject(this.source.getSourceId())) && filter.match(player); + return player.canBeTargetedBy(game.getObject(this.source.getSourceId())) && filter.match(player); else return filter.match(player); } diff --git a/Mage/src/mage/target/TargetSpell.java b/Mage/src/mage/target/TargetSpell.java index 6e4a006d59..af49aaaea7 100644 --- a/Mage/src/mage/target/TargetSpell.java +++ b/Mage/src/mage/target/TargetSpell.java @@ -28,6 +28,8 @@ package mage.target; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; import mage.Constants.Zone; import mage.filter.FilterSpell; @@ -83,9 +85,22 @@ public class TargetSpell extends TargetObject { for (StackObject stackObject: game.getStack()) { if (stackObject instanceof Spell && game.getPlayer(sourceControllerId).getInRange().contains(stackObject.getControllerId()) && filter.match((Spell)stackObject)) { count++; + if (count >= this.minNumberOfTargets) + return true; } } - return count >= this.minNumberOfTargets; + return false; + } + + @Override + public List possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + List possibleTargets = new ArrayList(); + for (StackObject stackObject: game.getStack()) { + if (stackObject instanceof Spell && game.getPlayer(sourceControllerId).getInRange().contains(stackObject.getControllerId()) && filter.match((Spell)stackObject)) { + possibleTargets.add(stackObject.getId()); + } + } + return possibleTargets; } } diff --git a/Mage/src/mage/target/Targets.java b/Mage/src/mage/target/Targets.java index b750189d3a..0f6dcb62b3 100644 --- a/Mage/src/mage/target/Targets.java +++ b/Mage/src/mage/target/Targets.java @@ -34,7 +34,6 @@ import java.util.UUID; import mage.Constants.Outcome; import mage.abilities.Ability; import mage.game.Game; -import mage.players.Player; /** * @@ -50,6 +49,9 @@ public class Targets extends ArrayList { public void setSource(Ability ability) { this.source = ability; + for (Target target: this) { + target.setAbility(ability); + } } @Override @@ -108,4 +110,11 @@ public class Targets extends ArrayList { } return true; } + + public UUID getFirstTarget() { + if (this.size() > 0) + return this.get(0).getFirstTarget(); + return null; + } + } diff --git a/Mage/src/mage/target/common/TargetSacrificePermanent.java b/Mage/src/mage/target/common/TargetControlledPermanent.java similarity index 88% rename from Mage/src/mage/target/common/TargetSacrificePermanent.java rename to Mage/src/mage/target/common/TargetControlledPermanent.java index fd52240a44..09a6663a29 100644 --- a/Mage/src/mage/target/common/TargetSacrificePermanent.java +++ b/Mage/src/mage/target/common/TargetControlledPermanent.java @@ -36,17 +36,17 @@ import mage.target.TargetPermanent; * * @author BetaSteward_at_googlemail.com */ -public class TargetSacrificePermanent extends TargetPermanent { +public class TargetControlledPermanent extends TargetPermanent { - public TargetSacrificePermanent() { + public TargetControlledPermanent() { this(1, 1, new FilterPermanent()); } - public TargetSacrificePermanent(int numTargets) { + public TargetControlledPermanent(int numTargets) { this(numTargets, numTargets, new FilterPermanent()); } - public TargetSacrificePermanent(int minNumTargets, int maxNumTargets, FilterPermanent filter) { + public TargetControlledPermanent(int minNumTargets, int maxNumTargets, FilterPermanent filter) { super(1, 1, filter, TargetController.YOU); this.targetName = filter.getMessage(); } diff --git a/Mage/src/mage/target/common/TargetCreatureOrPlayer.java b/Mage/src/mage/target/common/TargetCreatureOrPlayer.java index a95d0c93ab..f89b73dcd5 100644 --- a/Mage/src/mage/target/common/TargetCreatureOrPlayer.java +++ b/Mage/src/mage/target/common/TargetCreatureOrPlayer.java @@ -28,9 +28,11 @@ package mage.target.common; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; -import mage.Constants.CardType; import mage.Constants.Zone; +import mage.MageObject; import mage.filter.Filter; import mage.filter.common.FilterCreatureOrPlayer; import mage.filter.common.FilterCreaturePermanent; @@ -71,16 +73,17 @@ public class TargetCreatureOrPlayer extends TargetImpl { @Override public boolean canTarget(UUID id, Game game) { Permanent permanent = game.getPermanent(id); + MageObject targetSource = game.getObject(this.source.getSourceId()); if (permanent != null) { if (this.source != null) - return permanent.canBeTargetedBy(game.getObject(this.source.getSourceId())) && filter.match(permanent); + return permanent.canBeTargetedBy(targetSource) && filter.match(permanent); else return filter.match(permanent); } Player player = game.getPlayer(id); if (player != null) if (this.source != null) - return player.canTarget(game.getObject(this.source.getSourceId())) && filter.match(player); + return player.canBeTargetedBy(targetSource) && filter.match(player); else return filter.match(player); return false; @@ -89,18 +92,41 @@ public class TargetCreatureOrPlayer extends TargetImpl { @Override public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { int count = 0; + MageObject targetSource = game.getObject(sourceId); for (UUID playerId: game.getPlayer(sourceControllerId).getInRange()) { Player player = game.getPlayer(playerId); - if (player != null && player.canTarget(game.getObject(this.source.getSourceId())) && filter.match(player)) + if (player != null && player.canBeTargetedBy(targetSource) && filter.match(player)) { count++; + if (count >= this.minNumberOfTargets) + return true; + } } - if (count >= this.minNumberOfTargets) - return true; for (Permanent permanent: game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), sourceControllerId, game)) { - if (permanent.canBeTargetedBy(game.getObject(this.source.getSourceId())) && filter.match(permanent)) + if (permanent.canBeTargetedBy(targetSource) && filter.match(permanent)) { count++; + if (count >= this.minNumberOfTargets) + return true; + } } - return count >= this.minNumberOfTargets; + return false; + } + + @Override + public List possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + List possibleTargets = new ArrayList(); + MageObject targetSource = game.getObject(sourceId); + for (UUID playerId: game.getPlayer(sourceControllerId).getInRange()) { + Player player = game.getPlayer(playerId); + if (player != null && player.canBeTargetedBy(targetSource) && filter.match(player)) { + possibleTargets.add(playerId); + } + } + for (Permanent permanent: game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), sourceControllerId, game)) { + if (permanent.canBeTargetedBy(targetSource) && filter.match(permanent)) { + possibleTargets.add(permanent.getId()); + } + } + return possibleTargets; } @Override diff --git a/Mage/src/mage/target/common/TargetCreatureOrPlayerAmount.java b/Mage/src/mage/target/common/TargetCreatureOrPlayerAmount.java new file mode 100644 index 0000000000..11793500e7 --- /dev/null +++ b/Mage/src/mage/target/common/TargetCreatureOrPlayerAmount.java @@ -0,0 +1,139 @@ +/* +* 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.target.common; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import mage.Constants.Zone; +import mage.MageObject; +import mage.filter.Filter; +import mage.filter.common.FilterCreatureOrPlayer; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetAmount; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public class TargetCreatureOrPlayerAmount extends TargetAmount { + + protected FilterCreatureOrPlayer filter; + + public TargetCreatureOrPlayerAmount(int amount) { + super(amount); + this.zone = Zone.ALL; + this.filter = new FilterCreatureOrPlayer(); + this.targetName = filter.getMessage(); + } + + @Override + public Filter getFilter() { + return this.filter; + } + + @Override + public boolean canTarget(UUID id, Game game) { + Permanent permanent = game.getPermanent(id); + MageObject targetSource = game.getObject(this.source.getSourceId()); + if (permanent != null) { + if (this.source != null) + return permanent.canBeTargetedBy(targetSource) && filter.match(permanent); + else + return filter.match(permanent); + } + Player player = game.getPlayer(id); + if (player != null) + if (this.source != null) + return player.canBeTargetedBy(targetSource) && filter.match(player); + else + return filter.match(player); + return false; + } + + @Override + public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + int count = 0; + MageObject targetSource = game.getObject(sourceId); + for (UUID playerId: game.getPlayer(sourceControllerId).getInRange()) { + Player player = game.getPlayer(playerId); + if (player != null && player.canBeTargetedBy(targetSource) && filter.match(player)) { + count++; + if (count >= this.minNumberOfTargets) + return true; + } + } + for (Permanent permanent: game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), sourceControllerId, game)) { + if (permanent.canBeTargetedBy(targetSource) && filter.match(permanent)) { + count++; + if (count >= this.minNumberOfTargets) + return true; + } + } + return false; + } + + @Override + public List possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + List possibleTargets = new ArrayList(); + MageObject targetSource = game.getObject(sourceId); + for (UUID playerId: game.getPlayer(sourceControllerId).getInRange()) { + Player player = game.getPlayer(playerId); + if (player != null && player.canBeTargetedBy(targetSource) && filter.match(player)) { + possibleTargets.add(playerId); + } + } + for (Permanent permanent: game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), sourceControllerId, game)) { + if (permanent.canBeTargetedBy(targetSource) && filter.match(permanent)) { + possibleTargets.add(permanent.getId()); + } + } + return possibleTargets; + } + + @Override + public String getTargetedName(Game game) { + StringBuilder sb = new StringBuilder(); + for (UUID targetId: getTargets()) { + Permanent permanent = game.getPermanent(targetId); + if (permanent != null) { + sb.append(permanent.getName()).append(" "); + } + else { + Player player = game.getPlayer(targetId); + sb.append(player.getName()).append(" "); + } + } + return sb.toString(); + } + +} diff --git a/Mage/src/mage/target/common/TargetDefender.java b/Mage/src/mage/target/common/TargetDefender.java index a1de8e947b..71be373537 100644 --- a/Mage/src/mage/target/common/TargetDefender.java +++ b/Mage/src/mage/target/common/TargetDefender.java @@ -28,11 +28,13 @@ package mage.target.common; +import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.UUID; import mage.Constants.CardType; import mage.Constants.Zone; +import mage.MageObject; import mage.filter.Filter; import mage.filter.common.FilterPlaneswalkerOrPlayer; import mage.filter.common.FilterPlaneswalkerPermanent; @@ -75,18 +77,41 @@ public class TargetDefender extends TargetImpl { @Override public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { int count = 0; + MageObject targetSource = game.getObject(sourceId); for (UUID playerId: game.getPlayer(sourceControllerId).getInRange()) { Player player = game.getPlayer(playerId); - if (player != null && player.canTarget(game.getObject(this.source.getSourceId())) && filter.match(player)) + if (player != null && player.canBeTargetedBy(targetSource) && filter.match(player)) { count++; + if (count >= this.minNumberOfTargets) + return true; + } } - if (count >= this.minNumberOfTargets) - return true; for (Permanent permanent: game.getBattlefield().getActivePermanents(new FilterPlaneswalkerPermanent(), sourceControllerId, game)) { - if (permanent.canBeTargetedBy(game.getObject(this.source.getSourceId())) && filter.match(permanent)) + if (permanent.canBeTargetedBy(targetSource) && filter.match(permanent)) { count++; + if (count >= this.minNumberOfTargets) + return true; + } } - return count >= this.minNumberOfTargets; + return false; + } + + @Override + public List possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + List possibleTargets = new ArrayList(); + MageObject targetSource = game.getObject(sourceId); + for (UUID playerId: game.getPlayer(sourceControllerId).getInRange()) { + Player player = game.getPlayer(playerId); + if (player != null && player.canBeTargetedBy(targetSource) && filter.match(player)) { + possibleTargets.add(playerId); + } + } + for (Permanent permanent: game.getBattlefield().getActivePermanents(new FilterPlaneswalkerPermanent(), sourceControllerId, game)) { + if (permanent.canBeTargetedBy(targetSource) && filter.match(permanent)) { + possibleTargets.add(permanent.getId()); + } + } + return possibleTargets; } @Override @@ -108,12 +133,13 @@ public class TargetDefender extends TargetImpl { @Override public boolean canTarget(UUID id, Game game) { Player player = game.getPlayer(id); + MageObject targetSource = game.getObject(attackerId); if (player != null) { - return player.canTarget(game.getObject(attackerId)) && filter.match(player); + return player.canBeTargetedBy(targetSource) && filter.match(player); } Permanent permanent = game.getPermanent(id); if (permanent != null) { - return permanent.canBeTargetedBy(game.getObject(attackerId)) && filter.match(permanent); + return permanent.canBeTargetedBy(targetSource) && filter.match(permanent); } return false; } diff --git a/Mage/src/mage/target/common/TargetLandPermanent.java b/Mage/src/mage/target/common/TargetLandPermanent.java index ef935720b8..ef2cd8788f 100644 --- a/Mage/src/mage/target/common/TargetLandPermanent.java +++ b/Mage/src/mage/target/common/TargetLandPermanent.java @@ -42,6 +42,10 @@ public class TargetLandPermanent extends TargetPermanent { this(1, 1, new FilterLandPermanent(), TargetController.ANY); } + public TargetLandPermanent(FilterLandPermanent filter) { + this(1, 1, filter, TargetController.ANY); + } + public TargetLandPermanent(int numTargets, TargetController controller) { this(numTargets, numTargets, new FilterLandPermanent(), controller); } diff --git a/Mage/src/mage/util/CircularList.java b/Mage/src/mage/util/CircularList.java index 54df620d5e..f3d91556e1 100644 --- a/Mage/src/mage/util/CircularList.java +++ b/Mage/src/mage/util/CircularList.java @@ -98,7 +98,8 @@ public class CircularList implements List, Iterable, Serializable { } /** - * Returns the next element in the list + * Returns the next element in the list. Will loop around to the beginning + * of the list if the current element is the last. * * @return the next element in the list */ @@ -107,7 +108,8 @@ public class CircularList implements List, Iterable, Serializable { } /** - * Returns the previous element in the list + * Returns the previous element in the list. Will loop around to the end + * of the list if the current element is the first. * * @return the previous element in the list */ diff --git a/Mage/src/mage/util/Logging.java b/Mage/src/mage/util/Logging.java index d2b645d4f7..7b6b915c50 100644 --- a/Mage/src/mage/util/Logging.java +++ b/Mage/src/mage/util/Logging.java @@ -48,10 +48,10 @@ public class Logging { public static Logger getLogger(String name) { Logger logger = Logger.getLogger(name); - logger.setUseParentHandlers(false); ConsoleHandler handler = new ConsoleHandler(); handler.setFormatter(new LogFormatter()); logger.addHandler(handler); + logger.setUseParentHandlers(false); return logger; }