This commit is contained in:
BetaSteward 2010-06-29 01:08:50 +00:00
parent 805f20264e
commit 69e219c7c6
107 changed files with 3238 additions and 616 deletions

View file

@ -214,6 +214,7 @@ public final class Constants {
DrawCard(true),
Discard(false),
Sacrifice(false),
ReturnToHand(false),
Exile(false),
Protect(true),
PutManaInPool(true),

View file

@ -61,7 +61,7 @@ public class AbilitiesImpl extends ArrayList<Ability> implements Abilities, Seri
public List<ActivatedAbility> getActivatedAbilities(Zone zone) {
List<ActivatedAbility> zonedAbilities = new ArrayList<ActivatedAbility>();
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<Ability> implements Abilities, Seri
public List<ManaAbility> getManaAbilities(Zone zone) {
List<ManaAbility> abilities = new ArrayList<ManaAbility>();
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<Ability> implements Abilities, Seri
public List<EvasionAbility> getEvasionAbilities() {
List<EvasionAbility> abilities = new ArrayList<EvasionAbility>();
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<Ability> implements Abilities, Seri
public List<StaticAbility> getStaticAbilities(Zone zone) {
List<StaticAbility> zonedAbilities = new ArrayList<StaticAbility>();
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<Ability> implements Abilities, Seri
public List<TriggeredAbility> getTriggeredAbilities(Zone zone) {
List<TriggeredAbility> zonedAbilities = new ArrayList<TriggeredAbility>();
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<Ability> implements Abilities, Seri
public List<ProtectionAbility> getProtectionAbilities() {
List<ProtectionAbility> abilities = new ArrayList<ProtectionAbility>();
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<Ability> implements Abilities, Seri
public List<KickerAbility> getKickerAbilities() {
List<KickerAbility> abilities = new ArrayList<KickerAbility>();
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<Ability> 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<Ability> 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<Ability> implements Abilities, Seri
return false;
}
@Override
public Ability get(UUID abilityId) {
for (Ability ability: this) {
if (ability.getId().equals(abilityId))

View file

@ -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);

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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) {
// }
//}

View file

@ -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.";
}
}

View file

@ -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);

View file

@ -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

View file

@ -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<T extends Cost> extends ArrayList<T> implements Costs<T>
return null;
}
@Override
public Targets getTargets() {
Targets targets = new Targets(ability);
for (Cost cost: this) {
targets.addAll(cost.getTargets());
}
return targets;
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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:

View file

@ -76,6 +76,7 @@ public class MonoHybridManaCost extends ManaCostImpl implements ManaCost {
return this;
}
@Override
public boolean testPay(Mana testMana) {
switch (mana) {
case B:

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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();
}
}

View file

@ -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";
}
}

View file

@ -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

View file

@ -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();

View file

@ -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();
}
}

View file

@ -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) {

View file

@ -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();
}
}

View file

@ -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();
}

View file

@ -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;
}

View file

@ -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

View file

@ -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";
}
}

View file

@ -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

View file

@ -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;
}

View file

@ -0,0 +1,73 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.effects.common;
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();
}
}

View file

@ -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";
}
}

View file

@ -0,0 +1,90 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.effects.common;
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);
}
}

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -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();
}
}

View file

@ -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());
}
}

View file

@ -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();
}
}

View file

@ -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();
}
}

View file

@ -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;
}

View file

@ -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";
}
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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";
}
}

View file

@ -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();
}
}

View file

@ -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() {

View file

@ -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;
}
}

View file

@ -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<Mana> {
public void addMana(List<ManaAbility> abilities) {
public void addMana(List<ManaAbility> 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<Mana> {
for (Mana mana: copy) {
Mana newMana = new Mana();
newMana.add(mana);
newMana.add(ability.getNetMana());
newMana.add(ability.getNetMana(game));
this.add(newMana);
}
}

View file

@ -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<UUID, Card>, Serializable {
public void setOwner(UUID ownerId);
public void addAll(List<Card> createCards);
public List<Card> getCards(FilterCard filter);
public Collection<Card> getUniqueCards();
public Card getRandom();
public int count(FilterCard filter);

View file

@ -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<UUID, Card> implements Cards, Seria
}
}
@Override
public Collection<Card> getUniqueCards() {
Map<String, Card> cards = new HashMap<String, Card>();
for(Card card: this.values()) {
if (!cards.containsKey(card.getName())) {
cards.put(card.getName(), card);
}
}
return cards.values();
}
}

View file

@ -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();
}
}

View file

@ -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;
}
}

View file

@ -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<UUID> getOpponents(UUID controllerId);
public PlayerList getPlayerList();
public Set<UUID> 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();

View file

@ -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<Integer> savedStates = new Stack<Integer>();
private transient Stack<Integer> savedStates = new Stack<Integer>();
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<PlayerQueryEvent> 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<Integer>();
tableEventSource = new TableEventSource();
playerQueryEventSource = new PlayerQueryEventSource();
gameStates = new GameStates();
}
}

View file

@ -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<String, Object> values = new HashMap<String, Object>();
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);
}
}

View file

@ -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<GameState>().uncompressCopy(states.get(index - 1));
}
return new Copier<GameState>().uncompressCopy(states.get(index - 1));
return null;
}
public GameState get(int index) {

View file

@ -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;

View file

@ -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;
}

View file

@ -68,6 +68,10 @@ public class PlayerQueryEventSource implements EventSource<PlayerQueryEvent>, 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));
}

View file

@ -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;

View file

@ -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<Permanent> getAllPermanents(UUID controllerId) {
List<Permanent> perms = new ArrayList<Permanent>();
for (Permanent perm: field.values()) {
if (perm.getControllerId().equals(controllerId))
perms.add(perm);
}
return perms;
}
public List<Permanent> getAllActivePermanents() {
List<Permanent> active = new ArrayList<Permanent>();
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<Permanent> getAllActivePermanents(UUID controllerId) {
List<Permanent> active = new ArrayList<Permanent>();
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<Permanent> getAllActivePermanents(CardType type) {
List<Permanent> active = new ArrayList<Permanent>();
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<Permanent> getAllActivePermanents(FilterPermanent filter) {
List<Permanent> active = new ArrayList<Permanent>();
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<Permanent> getAllActivePermanents(FilterPermanent filter, UUID controllerId) {
List<Permanent> active = new ArrayList<Permanent>();
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<Permanent> 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<Permanent> 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<Permanent> getMatches(FilterPermanent filter) {
// List<Permanent> matches = new ArrayList<Permanent>();
// for (Permanent perm: field.values()) {
// if (filter.match(perm))
// matches.add(perm);
// }
// return matches;
// }
}

View file

@ -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

View file

@ -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);
}
}

View file

@ -56,10 +56,12 @@ public class Spell implements StackObject, Card {
// private static final transient Copier<Spell> copier = new Copier<Spell>();
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);

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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());
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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());
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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();
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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());
}
}

View file

@ -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;
}
}

View file

@ -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());
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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

View file

@ -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;
}

View file

@ -52,7 +52,19 @@ public class TurnMods extends ArrayList<TurnMod> {
return false;
}
public PhaseStep extraStep(UUID playerId, PhaseStep afterStep) {
public boolean skipTurn(UUID playerId) {
ListIterator<TurnMod> 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<TurnMod> it = this.listIterator(this.size());
while (it.hasPrevious()) {
TurnMod turnMod = it.previous();
@ -64,6 +76,18 @@ public class TurnMods extends ArrayList<TurnMod> {
return null;
}
public boolean skipStep(UUID playerId, PhaseStep step) {
ListIterator<TurnMod> 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<TurnMod> it = this.listIterator(this.size());
while (it.hasPrevious()) {
@ -76,4 +100,16 @@ public class TurnMods extends ArrayList<TurnMod> {
return null;
}
public boolean skipPhase(UUID playerId, TurnPhase phase) {
ListIterator<TurnMod> 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;
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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();
}

View file

@ -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<ReplacementEffect> 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<Ability> getPlayable(Game game, boolean hidden);
public List<Ability> getPlayableOptions(Ability ability, Game game);
}

View file

@ -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<Permanent> 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<Permanent> manaPerms = this.getAvailableManaProducers(game);
ManaOptions available = new ManaOptions();
for (Permanent perm: manaPerms) {
available.addMana(perm.getAbilities().getManaAbilities(Zone.BATTLEFIELD), game);
}
return available;
}
protected List<Permanent> getAvailableManaProducers(Game game) {
List<Permanent> result = new ArrayList<Permanent>();
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<Ability> getPlayable(Game game, boolean hidden) {
List<Ability> playable = new ArrayList<Ability>();
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<Ability> getPlayableOptions(Ability ability, Game game) {
List<Ability> options = new ArrayList<Ability>();
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<Ability> 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<Ability> 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<Ability> 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);
}
}
}
}

View file

@ -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<Player> {
public class PlayerList extends CircularList<UUID> {
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;
}
}

View file

@ -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<UUID> 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<UUID> 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();
}

View file

@ -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;
}
}

View file

@ -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<UUID> possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) {
List<UUID> possibleTargets = new ArrayList<UUID>();
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)

View file

@ -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<UUID> targets = new ArrayList<UUID>();
protected Map<UUID, Integer> targets = new HashMap<UUID, Integer>();
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<UUID> 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;
}

View file

@ -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<Permanent> permanents = game.getBattlefield().getActivePermanents(filter, sourceControllerId, game);
Iterator<Permanent> 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<UUID> possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) {
List<UUID> possibleTargets = new ArrayList<UUID>();
MageObject targetSource = game.getObject(sourceId);
for (Permanent permanent: game.getBattlefield().getActivePermanents(filter, sourceControllerId, game)) {
if (permanent.canBeTargetedBy(targetSource)) {
possibleTargets.add(permanent.getId());
}
}
return possibleTargets;
}
}

View file

@ -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<UUID> possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) {
List<UUID> possibleTargets = new ArrayList<UUID>();
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);
}

View file

@ -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<UUID> possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) {
List<UUID> possibleTargets = new ArrayList<UUID>();
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;
}
}

View file

@ -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<Target> {
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<Target> {
}
return true;
}
public UUID getFirstTarget() {
if (this.size() > 0)
return this.get(0).getFirstTarget();
return null;
}
}

Some files were not shown because too many files have changed in this diff Show more