1
0
Fork 0
mirror of https://github.com/correl/mage.git synced 2025-04-11 17:00:08 -09:00

fixes + optimizations + allow games to be paused and resumed

This commit is contained in:
BetaSteward 2011-11-02 21:39:03 -04:00
parent 8fd03a5bb5
commit 7c69bc6f30
44 changed files with 430 additions and 331 deletions

View file

@ -95,15 +95,9 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
this.currentScore = player.currentScore;
if (player.combat != null)
this.combat = player.combat.copy();
for (Ability ability: player.actions) {
actions.add(ability);
}
for (UUID targetId: player.targets) {
targets.add(targetId);
}
for (String choice: player.choices) {
choices.add(choice);
}
this.actions.addAll(player.actions);
this.targets.addAll(player.targets);
this.choices.addAll(player.choices);
}
@Override
@ -773,7 +767,7 @@ public class ComputerPlayer6 extends ComputerPlayer<ComputerPlayer6> implements
Game sim = game.copy();
for (Player copyPlayer: sim.getState().getPlayers().values()) {
Player origPlayer = game.getState().getPlayers().get(copyPlayer.getId());
Player origPlayer = game.getState().getPlayers().get(copyPlayer.getId()).copy();
SimulatedPlayer2 newPlayer = new SimulatedPlayer2(copyPlayer.getId(), copyPlayer.getId().equals(playerId), suggested);
newPlayer.restore(origPlayer);
sim.getState().getPlayers().put(copyPlayer.getId(), newPlayer);

View file

@ -180,7 +180,7 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> i
}
if (target instanceof TargetControlledPermanent) {
List<Permanent> targets;
targets = threats(playerId, ((TargetControlledPermanent)target).getFilter(), game);
targets = threats(playerId, ((TargetControlledPermanent)target).getFilter(), game, target.getTargets());
if (!outcome.isGood())
Collections.reverse(targets);
for (Permanent permanent: targets) {
@ -193,10 +193,10 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> i
if (target instanceof TargetPermanent) {
List<Permanent> targets;
if (outcome.isGood()) {
targets = threats(playerId, ((TargetPermanent)target).getFilter(), game);
targets = threats(playerId, ((TargetPermanent)target).getFilter(), game, target.getTargets());
}
else {
targets = threats(opponentId, ((TargetPermanent)target).getFilter(), game);
targets = threats(opponentId, ((TargetPermanent)target).getFilter(), game, target.getTargets());
}
for (Permanent permanent: targets) {
if (((TargetPermanent)target).canTarget(playerId, permanent.getId(), null, game) && !target.getTargets().contains(permanent.getId())) {
@ -268,7 +268,7 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> i
}
if (target instanceof TargetControlledPermanent) {
List<Permanent> targets;
targets = threats(playerId, ((TargetControlledPermanent)target).getFilter(), game);
targets = threats(playerId, ((TargetControlledPermanent)target).getFilter(), game, target.getTargets());
if (!outcome.isGood())
Collections.reverse(targets);
for (Permanent permanent: targets) {
@ -282,10 +282,10 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> i
if (target instanceof TargetPermanent) {
List<Permanent> targets;
if (outcome.isGood()) {
targets = threats(playerId, ((TargetPermanent)target).getFilter(), game);
targets = threats(playerId, ((TargetPermanent)target).getFilter(), game, target.getTargets());
}
else {
targets = threats(opponentId, ((TargetPermanent)target).getFilter(), game);
targets = threats(opponentId, ((TargetPermanent)target).getFilter(), game, target.getTargets());
}
for (Permanent permanent: targets) {
if (((TargetPermanent)target).canTarget(playerId, permanent.getId(), source, game)) {
@ -299,10 +299,10 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> i
List<Permanent> targets;
TargetCreatureOrPlayer t = ((TargetCreatureOrPlayer)target);
if (outcome.isGood()) {
targets = threats(playerId, ((FilterCreatureOrPlayer)t.getFilter()).getCreatureFilter(), game);
targets = threats(playerId, ((FilterCreatureOrPlayer)t.getFilter()).getCreatureFilter(), game, target.getTargets());
}
else {
targets = threats(opponentId, ((FilterCreatureOrPlayer)t.getFilter()).getCreatureFilter(), game);
targets = threats(opponentId, ((FilterCreatureOrPlayer)t.getFilter()).getCreatureFilter(), game, target.getTargets());
}
for (Permanent permanent: targets) {
List<UUID> alreadyTargetted = target.getTargets();
@ -395,10 +395,10 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> i
}
List<Permanent> targets;
if (outcome.isGood()) {
targets = threats(playerId, new FilterCreaturePermanent(), game);
targets = threats(playerId, new FilterCreaturePermanent(), game, target.getTargets());
}
else {
targets = threats(opponentId, new FilterCreaturePermanent(), game);
targets = threats(opponentId, new FilterCreaturePermanent(), game, target.getTargets());
}
for (Permanent permanent: targets) {
if (target.canTarget(permanent.getId(), source, game)) {
@ -1301,8 +1301,14 @@ public class ComputerPlayer<T extends ComputerPlayer<T>> extends PlayerImpl<T> i
return worst;
}
protected List<Permanent> threats(UUID playerId, FilterPermanent filter, Game game) {
protected List<Permanent> threats(UUID playerId, FilterPermanent filter, Game game, List<UUID> targets) {
List<Permanent> threats = game.getBattlefield().getAllActivePermanents(filter, playerId);
Iterator<Permanent> it = threats.iterator();
while (it.hasNext()) { // remove permanents already targetted
Permanent test = it.next();
if (targets.contains(test.getId()))
it.remove();
}
Collections.sort(threats, new PermanentComparator(game));
return threats;
}

View file

@ -120,15 +120,9 @@ public class ComputerPlayer2 extends ComputerPlayer<ComputerPlayer2> implements
this.currentScore = player.currentScore;
if (player.combat != null)
this.combat = player.combat.copy();
for (Ability ability: player.actions) {
actions.add(ability);
}
for (UUID targetId: player.targets) {
targets.add(targetId);
}
for (String choice: player.choices) {
choices.add(choice);
}
this.actions.addAll(player.actions);
this.targets.addAll(player.targets);
this.choices.addAll(player.choices);
}
@Override
@ -731,7 +725,7 @@ public class ComputerPlayer2 extends ComputerPlayer<ComputerPlayer2> implements
Game sim = game.copy();
for (Player copyPlayer: sim.getState().getPlayers().values()) {
Player origPlayer = game.getState().getPlayers().get(copyPlayer.getId());
Player origPlayer = game.getState().getPlayers().get(copyPlayer.getId()).copy();
SimulatedPlayer newPlayer = new SimulatedPlayer(copyPlayer.getId(), copyPlayer.getId().equals(playerId), maxDepth);
newPlayer.restore(origPlayer);
sim.getState().getPlayers().put(copyPlayer.getId(), newPlayer);

View file

@ -113,8 +113,8 @@ public class Sets extends HashMap<String, ExpansionSet> {
private void addSet(ExpansionSet set) {
this.put(set.getCode(), set);
cards.addAll(set.getCards());
for (Card card: set.getCards()) {
cards.add(card);
names.add(card.getName());
if (card.getCardType().contains(CardType.CREATURE)) {
for (String type : card.getSubtype()) {

View file

@ -82,15 +82,9 @@ public abstract class MageObjectImpl<T extends MageObjectImpl<T>> implements Mag
power = object.power.copy();
toughness = object.toughness.copy();
abilities = object.abilities.copy();
for (CardType cType: object.cardType) {
cardType.add(cType);
}
for (String subType: object.subtype) {
this.subtype.add(subType);
}
for (String superType: object.supertype) {
this.supertype.add(superType);
}
this.cardType.addAll(object.cardType);
this.subtype.addAll(object.subtype);
this.supertype.addAll(object.supertype);
}
@Override

View file

@ -34,6 +34,7 @@ import mage.Constants.TimingRule;
import mage.Constants.Zone;
import mage.abilities.costs.Cost;
import mage.abilities.costs.Costs;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.costs.mana.PhyrexianManaCost;
@ -100,8 +101,8 @@ public abstract class ActivatedAbilityImpl<T extends ActivatedAbilityImpl<T>> ex
if (cost != null) {
if (cost instanceof PhyrexianManaCost) {
this.addManaCost((PhyrexianManaCost)cost);
} else if (cost instanceof ManaCostsImpl) {
this.addManaCost((ManaCostsImpl) cost);
} else if (cost instanceof ManaCost) {
this.addManaCost((ManaCost) cost);
} else {
this.addCost(cost);
}
@ -164,7 +165,7 @@ public abstract class ActivatedAbilityImpl<T extends ActivatedAbilityImpl<T>> ex
return true;
else {
Card card = (Card)game.getObject(this.sourceId);
if (card != null && game.getZone(this.sourceId) != Zone.BATTLEFIELD)
if (card != null && game.getState().getZone(this.sourceId) != Zone.BATTLEFIELD)
return card.getOwnerId().equals(playerId);
}
return false;

View file

@ -53,7 +53,7 @@ public class FlashbackCost extends AlternativeCostImpl<FlashbackCost> {
@Override
public boolean isAvailable(Game game, Ability source) {
Constants.Zone zone = game.getZone(source.getSourceId());
Constants.Zone zone = game.getState().getZone(source.getSourceId());
if (zone != null) {
return zone.equals(Constants.Zone.GRAVEYARD);
}

View file

@ -77,9 +77,7 @@ public abstract class ContinuousEffectImpl<T extends ContinuousEffectImpl<T>> ex
this.timestamp = new Date(effect.timestamp.getTime());
this.used = effect.used;
this.affectedObjectsSet = effect.affectedObjectsSet;
for (UUID objectId: effect.objects) {
this.objects.add(objectId);
}
this.objects.addAll(effect.objects);
}
@Override

View file

@ -60,13 +60,13 @@ import mage.players.Player;
public class ContinuousEffects implements Serializable {
//transient Continuous effects
private final List<ContinuousEffect> layeredEffects = new ArrayList<ContinuousEffect>();
private final List<ReplacementEffect> replacementEffects = new ArrayList<ReplacementEffect>();
private final List<PreventionEffect> preventionEffects = new ArrayList<PreventionEffect>();
private final List<RequirementEffect> requirementEffects = new ArrayList<RequirementEffect>();
private final List<RestrictionEffect> restrictionEffects = new ArrayList<RestrictionEffect>();
private final List<AsThoughEffect> asThoughEffects = new ArrayList<AsThoughEffect>();
private final List<CostModificationEffect> costModificationEffects = new ArrayList<CostModificationEffect>();
private final ArrayList<ContinuousEffect> layeredEffects = new ArrayList<ContinuousEffect>();
private final ArrayList<ReplacementEffect> replacementEffects = new ArrayList<ReplacementEffect>();
private final ArrayList<PreventionEffect> preventionEffects = new ArrayList<PreventionEffect>();
private final ArrayList<RequirementEffect> requirementEffects = new ArrayList<RequirementEffect>();
private final ArrayList<RestrictionEffect> restrictionEffects = new ArrayList<RestrictionEffect>();
private final ArrayList<AsThoughEffect> asThoughEffects = new ArrayList<AsThoughEffect>();
private final ArrayList<CostModificationEffect> costModificationEffects = new ArrayList<CostModificationEffect>();
//map Abilities to Continuous effects
private final Map<UUID, Ability> abilityMap = new HashMap<UUID, Ability>();
@ -82,24 +82,31 @@ public class ContinuousEffects implements Serializable {
public ContinuousEffects(final ContinuousEffects effect) {
this.applyCounters = effect.applyCounters.copy();
this.planeswalkerRedirectionEffect = effect.planeswalkerRedirectionEffect.copy();
layeredEffects.ensureCapacity(effect.layeredEffects.size());
for (ContinuousEffect entry: effect.layeredEffects) {
layeredEffects.add((ContinuousEffect) entry.copy());
}
replacementEffects.ensureCapacity(effect.replacementEffects.size());
for (ReplacementEffect entry: effect.replacementEffects) {
replacementEffects.add((ReplacementEffect)entry.copy());
}
preventionEffects.ensureCapacity(effect.preventionEffects.size());
for (PreventionEffect entry: effect.preventionEffects) {
preventionEffects.add((PreventionEffect)entry.copy());
}
requirementEffects.ensureCapacity(effect.requirementEffects.size());
for (RequirementEffect entry: effect.requirementEffects) {
requirementEffects.add((RequirementEffect)entry.copy());
}
restrictionEffects.ensureCapacity(effect.restrictionEffects.size());
for (RestrictionEffect entry: effect.restrictionEffects) {
restrictionEffects.add((RestrictionEffect)entry.copy());
}
asThoughEffects.ensureCapacity(effect.asThoughEffects.size());
for (AsThoughEffect entry: effect.asThoughEffects) {
asThoughEffects.add((AsThoughEffect)entry.copy());
}
costModificationEffects.ensureCapacity(effect.costModificationEffects.size());
for ( CostModificationEffect entry : effect.costModificationEffects ) {
costModificationEffects.add(entry);
}
@ -209,7 +216,7 @@ public class ContinuousEffects implements Serializable {
private List<ContinuousEffect> getLayeredEffects(Game game) {
List<ContinuousEffect> layerEffects = new ArrayList<ContinuousEffect>(layeredEffects);
for (Card card: game.getCards()) {
Zone zone = game.getZone(card.getId());
Zone zone = game.getState().getZone(card.getId());
if (zone == Zone.HAND || zone == Zone.GRAVEYARD) {
for (Entry<Effect, Ability> entry: card.getAbilities().getEffects(zone, EffectType.CONTINUOUS).entrySet()) {
layerEffects.add((ContinuousEffect)entry.getKey());
@ -284,7 +291,7 @@ public class ContinuousEffects implements Serializable {
replaceEffects.add(planeswalkerRedirectionEffect);
//get all applicable Replacement effects in each players hand and graveyard
for (Card card: game.getCards()) {
Zone zone = game.getZone(card.getId());
Zone zone = game.getState().getZone(card.getId());
if (zone == Zone.HAND || zone == Zone.GRAVEYARD) {
for (Entry<ReplacementEffect, Ability> entry: card.getAbilities().getReplacementEffects(zone).entrySet()) {
if (entry.getKey().applies(event, entry.getValue(), game)) {

View file

@ -66,7 +66,7 @@ public class PutOnLibraryTargetEffect extends OneShotEffect<PutOnLibraryTargetEf
public boolean apply(Game game, Ability source) {
boolean result = false;
for (UUID targetId : targetPointer.getTargets(source)) {
switch (game.getZone(targetId)) {
switch (game.getState().getZone(targetId)) {
case BATTLEFIELD:
Permanent permanent = game.getPermanent(targetId);
if (permanent != null) {

View file

@ -59,7 +59,7 @@ public class ReturnToHandSourceEffect extends OneShotEffect<ReturnToHandSourceEf
public boolean apply(Game game, Ability source) {
Card card = game.getCard(source.getSourceId());
if (card != null) {
switch (game.getZone(card.getId())) {
switch (game.getState().getZone(card.getId())) {
case BATTLEFIELD:
Permanent p = game.getPermanent(source.getSourceId());
if (p != null) {

View file

@ -61,7 +61,7 @@ public class ReturnToHandTargetEffect extends OneShotEffect<ReturnToHandTargetEf
public boolean apply(Game game, Ability source) {
boolean result = false;
for (UUID id : targetPointer.getTargets(source)) {
switch (game.getZone(id)) {
switch (game.getState().getZone(id)) {
case BATTLEFIELD:
Permanent permanent = game.getPermanent(id);
if (permanent != null) {

View file

@ -38,6 +38,7 @@ import mage.Constants.CardType;
import mage.Constants.Outcome;
import mage.Constants.Rarity;
import mage.Constants.Zone;
import mage.MageException;
import mage.MageObjectImpl;
import mage.Mana;
import mage.abilities.Ability;
@ -46,6 +47,7 @@ import mage.abilities.SpellAbility;
import mage.abilities.TriggeredAbility;
import mage.abilities.mana.ManaAbility;
import mage.game.Game;
import mage.game.GameException;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.PermanentCard;
@ -226,7 +228,7 @@ public abstract class CardImpl<T extends CardImpl<T>> extends MageObjectImpl<T>
@Override
public boolean moveToZone(Zone toZone, UUID sourceId, Game game, boolean flag) {
Zone fromZone = game.getZone(objectId);
Zone fromZone = game.getState().getZone(objectId);
ZoneChangeEvent event = new ZoneChangeEvent(this.objectId, sourceId, ownerId, fromZone, toZone);
if (!game.replaceEvent(event)) {
if (event.getFromZone() != null) {
@ -243,8 +245,11 @@ public abstract class CardImpl<T extends CardImpl<T>> extends MageObjectImpl<T>
case EXILED:
game.getExile().removeCard(this, game);
break;
case STACK:
break;
default:
//logger.warning("moveToZone, not fully implemented: from="+event.getFromZone() + ", to="+event.getToZone());
logger.fatal("invalid zone for card - " + fromZone);
return false;
}
game.rememberLKI(objectId, event.getFromZone(), this);
}
@ -278,7 +283,7 @@ public abstract class CardImpl<T extends CardImpl<T>> extends MageObjectImpl<T>
}
game.setZone(objectId, event.getToZone());
game.fireEvent(event);
return game.getZone(objectId) == toZone;
return game.getState().getZone(objectId) == toZone;
}
return false;
}
@ -309,14 +314,14 @@ public abstract class CardImpl<T extends CardImpl<T>> extends MageObjectImpl<T>
game.getStack().push(new Spell(this, ability.copy(), controllerId));
game.setZone(objectId, event.getToZone());
game.fireEvent(event);
return game.getZone(objectId) == Zone.STACK;
return game.getState().getZone(objectId) == Zone.STACK;
}
return false;
}
@Override
public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game) {
Zone fromZone = game.getZone(objectId);
Zone fromZone = game.getState().getZone(objectId);
ZoneChangeEvent event = new ZoneChangeEvent(this.objectId, sourceId, ownerId, fromZone, Zone.EXILED);
if (!game.replaceEvent(event)) {
if (fromZone != null) {

View file

@ -61,14 +61,12 @@ public class CardsImpl extends LinkedHashSet<UUID> implements Cards, Serializabl
public CardsImpl(Zone zone, List<Card> cards) {
this(zone);
for (Card card: cards) {
add(card);
this.add(card.getId());
}
}
public CardsImpl(final CardsImpl cards) {
for (UUID cardId: cards) {
this.add(cardId);
}
this.addAll(cards);
this.ownerId = cards.ownerId;
this.zone = cards.zone;
}
@ -163,7 +161,7 @@ public class CardsImpl extends LinkedHashSet<UUID> implements Cards, Serializabl
@Override
public void addAll(List<Card> cards) {
for (Card card: cards) {
add(card);
add(card.getId());
}
}

View file

@ -57,9 +57,7 @@ public class ChoiceImpl<T extends ChoiceImpl<T>> implements Choice, Serializable
this.chosen = choice.chosen;
this.required = choice.required;
this.message = choice.message;
for (String c: choice.choices) {
this.choices.add(c);
}
this.choices.addAll(choice.choices);
}
@Override

View file

@ -67,13 +67,9 @@ public class FilterCard<T extends FilterCard<T>> extends FilterObject<Card, Filt
public FilterCard(FilterCard<T> filter) {
super(filter);
for (UUID oId: filter.ownerId) {
this.ownerId.add(oId);
}
this.ownerId.addAll(filter.ownerId);
this.notOwner = filter.notOwner;
for (String code: filter.expansionSetCode) {
this.expansionSetCode.add(code);
}
this.expansionSetCode.addAll(filter.expansionSetCode);
this.notExpansionSetCode = filter.notExpansionSetCode;
this.owner = filter.owner;
}

View file

@ -91,12 +91,8 @@ public class FilterObject<E extends MageObject, T extends FilterObject<E, T>> ex
super(filter);
this.abilities = filter.abilities.copy();
this.notAbilities = filter.notAbilities;
for (CardType cType: (List<CardType>)filter.cardType) {
this.cardType.add(cType);
}
for (CardType cType: (List<CardType>)filter.notCardTypeList) {
this.notCardTypeList.add(cType);
}
this.cardType.addAll(filter.cardType);
this.notCardTypeList.addAll(filter.notCardTypeList);
this.scopeCardType = filter.scopeCardType;
this.notCardType = filter.notCardType;
this.notScopeCardType = filter.notScopeCardType;
@ -106,18 +102,12 @@ public class FilterObject<E extends MageObject, T extends FilterObject<E, T>> ex
this.color = filter.color.copy();
this.scopeColor = filter.scopeColor;
this.notColor = filter.notColor;
for (String fName: (List<String>)filter.name) {
this.name.add(fName);
}
this.name.addAll(filter.name);
this.notName = filter.notName;
for (String fSubtype: (List<String>)filter.subtype) {
this.subtype.add(fSubtype);
}
this.subtype.addAll(filter.subtype);
this.scopeSubtype = filter.scopeSubtype;
this.notSubtype = filter.notSubtype;
for (String fSupertype: (List<String>)filter.supertype) {
this.supertype.add(fSupertype);
}
this.supertype.addAll(filter.supertype);
this.scopeSupertype = filter.scopeSupertype;
this.notSupertype = filter.notSupertype;
this.convertedManaCost = filter.convertedManaCost;

View file

@ -61,13 +61,9 @@ public class FilterPermanent<T extends FilterPermanent<T>> extends FilterObject<
public FilterPermanent(final FilterPermanent<T> filter) {
super(filter);
for (UUID oId: filter.ownerId) {
this.ownerId.add(oId);
}
this.ownerId = new ArrayList<UUID>(filter.ownerId);
this.notOwner = filter.notOwner;
for (UUID oId: filter.controllerId) {
this.controllerId.add(oId);
}
this.controllerId = new ArrayList<UUID>(filter.controllerId);
this.notController = filter.notController;
this.useTapped = filter.useTapped;
this.tapped = filter.tapped;

View file

@ -52,9 +52,7 @@ public class FilterPlayer extends FilterImpl<Player, FilterPlayer> implements Fi
public FilterPlayer(FilterPlayer filter) {
super(filter);
for (UUID pId: filter.playerId) {
this.playerId.add(pId);
}
this.playerId.addAll(filter.playerId);
this.notPlayer = filter.notPlayer;
this.playerTarget = filter.playerTarget;
}

View file

@ -55,9 +55,7 @@ public class FilterStackObject<T extends FilterStackObject<T>> extends FilterObj
public FilterStackObject(final FilterStackObject<T> filter) {
super(filter);
for (UUID cId: filter.controllerId) {
this.controllerId.add(cId);
}
this.controllerId.addAll(filter.controllerId);
this.notController = filter.notController;
this.controller = filter.controller;
}

View file

@ -145,6 +145,8 @@ public interface Game extends MageItem, Serializable {
public void start(UUID choosingPlayerId);
public void start(UUID choosingPlayerId, GameOptions options);
public void resume();
public void pause();
public boolean isPaused();
public void end();
public void mulligan(UUID playerId);
public void quit(UUID playerId);

View file

@ -77,6 +77,7 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
private final static transient Logger logger = Logger.getLogger(GameImpl.class);
private static FilterAura filterAura = new FilterAura();
private static FilterLegendaryPermanent filterLegendary = new FilterLegendaryPermanent();
private static FilterEquipment filterEquipment = new FilterEquipment();
private static FilterFortification filterFortification = new FilterFortification();
private static Random rnd = new Random();
@ -125,6 +126,7 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
this.gameCards = game.gameCards;
this.simulation = game.simulation;
this.gameOptions = game.gameOptions;
this.lki.putAll(game.lki);
}
@Override
@ -355,27 +357,44 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
@Override
public void resume() {
play(state.getActivePlayerId());
}
protected void play(UUID nextPlayerId) {
PlayerList players = state.getPlayerList(nextPlayerId);
PlayerList players = state.getPlayerList(state.getActivePlayerId());
Player player = getPlayer(players.get());
while (!isGameOver()) {
state.setTurnNum(state.getTurnNum() + 1);
state.resume();
if (!isGameOver()) {
if (simulation)
logger.info("Turn " + Integer.toString(state.getTurnNum()));
fireInformEvent("Turn " + Integer.toString(state.getTurnNum()));
if (checkStopOnTurnOption()) return;
state.setActivePlayerId(player.getId());
state.getTurn().play(this, player.getId());
if (isGameOver())
break;
endOfTurn();
player = players.getNext(this);
state.getTurn().resumePlay(this);
if (!isPaused() && !isGameOver()) {
endOfTurn();
player = players.getNext(this);
state.setTurnNum(state.getTurnNum() + 1);
}
}
winnerId = findWinnersAndLosers();
play(player.getId());
}
protected void play(UUID nextPlayerId) {
if (!isPaused() && !isGameOver()) {
PlayerList players = state.getPlayerList(nextPlayerId);
Player player = getPlayer(players.get());
while (!isPaused() && !isGameOver()) {
// if (simulation)
// logger.info("Turn " + Integer.toString(state.getTurnNum()));
fireInformEvent("Turn " + Integer.toString(state.getTurnNum()));
if (checkStopOnTurnOption()) return;
state.setActivePlayerId(player.getId());
state.getTurn().play(this, player.getId());
if (isPaused() || isGameOver())
break;
endOfTurn();
player = players.getNext(this);
state.setTurnNum(state.getTurnNum() + 1);
}
}
if (isGameOver())
winnerId = findWinnersAndLosers();
}
private boolean checkStopOnTurnOption() {
@ -501,6 +520,16 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
return playerId;
}
@Override
public void pause() {
state.pause();
}
@Override
public boolean isPaused() {
return state.isPaused();
}
@Override
public void end() {
state.endGame();
@ -547,25 +576,25 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
public void playPriority(UUID activePlayerId) {
int bookmark = 0;
try {
while (!isGameOver()) {
while (!isPaused() && !isGameOver()) {
state.getPlayers().resetPassed();
state.getPlayerList().setCurrent(activePlayerId);
Player player;
while (!isGameOver()) {
while (!isPaused() && !isGameOver()) {
try {
if (bookmark == 0)
bookmark = bookmarkState();
player = getPlayer(state.getPlayerList().get());
state.setPriorityPlayerId(player.getId());
while (!player.isPassed() && !player.hasLost() && !player.hasLeft() && !isGameOver()) {
while (!player.isPassed() && !player.hasLost() && !player.hasLeft() && !isPaused() && !isGameOver()) {
checkStateAndTriggered();
if (isGameOver()) return;
if (isPaused() || isGameOver()) return;
// resetPassed should be called if player performs any action
player.priority(this);
if (isGameOver()) return;
if (isPaused() || isGameOver()) return;
applyEffects();
}
if (isGameOver()) return;
if (isPaused() || isGameOver()) return;
if (allPassed()) {
if (!state.getStack().isEmpty()) {
//20091005 - 115.4
@ -669,9 +698,9 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
public boolean checkStateAndTriggered() {
boolean somethingHappened = false;
//20091005 - 115.5
while (!this.isGameOver()) {
while (!isPaused() && !this.isGameOver()) {
if (!checkStateBasedActions() ) {
if (this.isGameOver() || !checkTriggered()) {
if (isPaused() || this.isGameOver() || !checkTriggered()) {
break;
}
}
@ -711,28 +740,127 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
player.lost(this);
}
}
for (Permanent perm: getBattlefield().getAllActivePermanents(CardType.CREATURE)) {
//20091005 - 704.5f
if (perm.getToughness().getValue() == 0) {
if (perm.moveToZone(Zone.GRAVEYARD, null, this, false))
somethingHappened = true;
List<Permanent> planeswalkers = new ArrayList<Permanent>();
List<Permanent> legendary = new ArrayList<Permanent>();
for (Permanent perm: getBattlefield().getAllActivePermanents()) {
if (perm.getCardType().contains(CardType.CREATURE)) {
//20091005 - 704.5f
if (perm.getToughness().getValue() == 0) {
if (perm.moveToZone(Zone.GRAVEYARD, null, this, false)) {
somethingHappened = true;
continue;
}
}
//20091005 - 704.5g/704.5h
else if (perm.getToughness().getValue() <= perm.getDamage() || perm.isDeathtouched()) {
if (perm.destroy(null, this, false)) {
somethingHappened = true;
continue;
}
}
}
if (perm.getCardType().contains(CardType.PLANESWALKER)) {
//20091005 - 704.5i
if (perm.getCounters().getCount(CounterType.LOYALTY) == 0) {
if (perm.moveToZone(Zone.GRAVEYARD, null, this, false)) {
somethingHappened = true;
continue;
}
}
planeswalkers.add(perm);
}
if (filterAura.match(perm)) {
//20091005 - 704.5n, 702.14c
if (perm.getAttachedTo() == null) {
if (perm.moveToZone(Zone.GRAVEYARD, null, this, false))
somethingHappened = true;
}
else {
Target target = perm.getSpellAbility().getTargets().get(0);
if (target instanceof TargetPermanent) {
Permanent attachedTo = getPermanent(perm.getAttachedTo());
if (attachedTo == null) {
if (perm.moveToZone(Zone.GRAVEYARD, null, this, false))
somethingHappened = true;
}
else {
Filter auraFilter = perm.getSpellAbility().getTargets().get(0).getFilter();
if (!auraFilter.match(attachedTo) || attachedTo.hasProtectionFrom(perm)) {
if (perm.moveToZone(Zone.GRAVEYARD, null, this, false))
somethingHappened = true;
}
}
}
else if (target instanceof TargetPlayer) {
Player attachedTo = getPlayer(perm.getAttachedTo());
if (attachedTo == null) {
if (perm.moveToZone(Zone.GRAVEYARD, null, this, false))
somethingHappened = true;
}
else {
Filter auraFilter = perm.getSpellAbility().getTargets().get(0).getFilter();
if (!auraFilter.match(attachedTo) || attachedTo.hasProtectionFrom(perm)) {
if (perm.moveToZone(Zone.GRAVEYARD, null, this, false))
somethingHappened = true;
}
}
}
}
}
if (filterLegendary.match(perm))
legendary.add(perm);
if (filterEquipment.match(perm)) {
//20091005 - 704.5p, 702.14d
if (perm.getAttachedTo() != null) {
Permanent creature = getPermanent(perm.getAttachedTo());
if (creature == null) {
perm.attachTo(null, this);
}
else if (!creature.getCardType().contains(CardType.CREATURE) || creature.hasProtectionFrom(perm)) {
if (creature.removeAttachment(perm.getId(), this))
somethingHappened = true;
}
}
}
if (filterFortification.match(perm)) {
if (perm.getAttachedTo() != null) {
Permanent land = getPermanent(perm.getAttachedTo());
if (land == null) {
perm.attachTo(null, this);
}
else if (!land.getCardType().contains(CardType.LAND) || land.hasProtectionFrom(perm)) {
if (land.removeAttachment(perm.getId(), this))
somethingHappened = true;
}
}
}
//20091005 - 704.5q
if (perm.getAttachments().size() > 0) {
for (UUID attachmentId: perm.getAttachments()) {
Permanent attachment = getPermanent(attachmentId);
if (attachment != null && !(attachment.getSubtype().contains("Aura") ||
attachment.getSubtype().contains("Equipment") ||
attachment.getSubtype().contains("Fortification"))) {
if (perm.removeAttachment(attachment.getId(), this))
somethingHappened = true;
}
}
}
//20091005 - 704.5g/704.5h
else if (perm.getToughness().getValue() <= perm.getDamage() || perm.isDeathtouched()) {
if (perm.destroy(null, this, false))
somethingHappened = true;
//20110501 - 704.5r
if (perm.getCounters().containsKey(CounterType.P1P1) && perm.getCounters().containsKey(CounterType.M1M1)) {
int p1p1 = perm.getCounters().getCount(CounterType.P1P1);
int m1m1 = perm.getCounters().getCount(CounterType.M1M1);
int min = Math.min(p1p1, m1m1);
perm.getCounters().removeCounter(CounterType.P1P1, min);
perm.getCounters().removeCounter(CounterType.M1M1, min);
}
}
//20091005 - 704.5i
for (Permanent perm: getBattlefield().getAllActivePermanents(CardType.PLANESWALKER)) {
if (perm.getCounters().getCount(CounterType.LOYALTY) == 0) {
if (perm.moveToZone(Zone.GRAVEYARD, null, this, false))
return true;
}
}
}
//20091005 - 704.5j, 801.14
if (getBattlefield().contains(new FilterPlaneswalkerPermanent(), 2)) { //don't bother checking if less than 2 planeswalkers in play
for (Permanent planeswalker: getBattlefield().getAllActivePermanents(CardType.PLANESWALKER)) {
if (planeswalkers.size() > 1) { //don't bother checking if less than 2 planeswalkers in play
for (Permanent planeswalker: planeswalkers) {
for (String planeswalkertype: planeswalker.getSubtype()) {
FilterPlaneswalkerPermanent filterPlaneswalker = new FilterPlaneswalkerPermanent();
filterPlaneswalker.getSubtype().add(planeswalkertype);
@ -746,48 +874,9 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
}
}
}
//20091005 - 704.5n, 702.14c
for (Permanent perm: getBattlefield().getAllActivePermanents(filterAura)) {
if (perm.getAttachedTo() == null) {
if (perm.moveToZone(Zone.GRAVEYARD, null, this, false))
somethingHappened = true;
}
else {
Target target = perm.getSpellAbility().getTargets().get(0);
if (target instanceof TargetPermanent) {
Permanent attachedTo = getPermanent(perm.getAttachedTo());
if (attachedTo == null) {
if (perm.moveToZone(Zone.GRAVEYARD, null, this, false))
somethingHappened = true;
}
else {
Filter auraFilter = perm.getSpellAbility().getTargets().get(0).getFilter();
if (!auraFilter.match(attachedTo) || attachedTo.hasProtectionFrom(perm)) {
if (perm.moveToZone(Zone.GRAVEYARD, null, this, false))
somethingHappened = true;
}
}
}
else if (target instanceof TargetPlayer) {
Player attachedTo = getPlayer(perm.getAttachedTo());
if (attachedTo == null) {
if (perm.moveToZone(Zone.GRAVEYARD, null, this, false))
somethingHappened = true;
}
else {
Filter auraFilter = perm.getSpellAbility().getTargets().get(0).getFilter();
if (!auraFilter.match(attachedTo) || attachedTo.hasProtectionFrom(perm)) {
if (perm.moveToZone(Zone.GRAVEYARD, null, this, false))
somethingHappened = true;
}
}
}
}
}
FilterLegendaryPermanent filterLegendary = new FilterLegendaryPermanent();
//20091005 - 704.5k, 801.12
if (getBattlefield().contains(filterLegendary, 2)) { //don't bother checking if less than 2 legends in play
for (Permanent legend: getBattlefield().getAllActivePermanents(filterLegendary)) {
if (legendary.size() > 1) { //don't bother checking if less than 2 legends in play
for (Permanent legend: legendary) {
FilterLegendaryPermanent filterLegendName = new FilterLegendaryPermanent();
filterLegendName.getName().add(legend.getName());
if (getBattlefield().contains(filterLegendName, legend.getControllerId(), this, 2)) {
@ -798,55 +887,6 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
}
}
}
//20091005 - 704.5p, 702.14d
for (Permanent perm: getBattlefield().getAllActivePermanents(filterEquipment)) {
if (perm.getAttachedTo() != null) {
Permanent creature = getPermanent(perm.getAttachedTo());
if (creature == null) {
perm.attachTo(null, this);
}
else if (!creature.getCardType().contains(CardType.CREATURE) || creature.hasProtectionFrom(perm)) {
if (creature.removeAttachment(perm.getId(), this))
somethingHappened = true;
}
}
}
for (Permanent perm: getBattlefield().getAllActivePermanents(filterFortification)) {
if (perm.getAttachedTo() != null) {
Permanent land = getPermanent(perm.getAttachedTo());
if (land == null) {
perm.attachTo(null, this);
}
else if (!land.getCardType().contains(CardType.LAND) || land.hasProtectionFrom(perm)) {
if (land.removeAttachment(perm.getId(), this))
somethingHappened = true;
}
}
}
//20091005 - 704.5q
for (Permanent perm: getBattlefield().getAllActivePermanents()) {
if (perm.getAttachments().size() > 0) {
for (UUID attachmentId: perm.getAttachments()) {
Permanent attachment = getPermanent(attachmentId);
if (attachment != null && !(attachment.getSubtype().contains("Aura") ||
attachment.getSubtype().contains("Equipment") ||
attachment.getSubtype().contains("Fortification"))) {
if (perm.removeAttachment(attachment.getId(), this))
return true;
}
}
}
}
//20110501 - 704.5r
for (Permanent perm: getBattlefield().getAllActivePermanents()) {
if (perm.getCounters().containsKey(CounterType.P1P1) && perm.getCounters().containsKey(CounterType.M1M1)) {
int p1p1 = perm.getCounters().getCount(CounterType.P1P1);
int m1m1 = perm.getCounters().getCount(CounterType.M1M1);
int min = Math.min(p1p1, m1m1);
perm.getCounters().removeCounter(CounterType.P1P1, min);
perm.getCounters().removeCounter(CounterType.M1M1, min);
}
}
//TODO: implement the rest

View file

@ -85,8 +85,9 @@ public class GameState implements Serializable, Copyable<GameState> {
private Revealed revealed;
private Map<UUID, LookedAt> lookedAt = new HashMap<UUID, LookedAt>();
private Battlefield battlefield;
private int turnNum;
private int turnNum = 1;
private boolean gameOver;
private boolean paused;
// private List<String> messages = new ArrayList<String>();
private ContinuousEffects effects;
private TriggeredAbilities triggers;
@ -128,9 +129,7 @@ public class GameState implements Serializable, Copyable<GameState> {
this.command = state.command.copy();
this.exile = state.exile.copy();
this.revealed = state.revealed.copy();
for (Map.Entry<UUID, LookedAt> entry: state.lookedAt.entrySet()) {
lookedAt.put(entry.getKey(), entry.getValue());
}
this.lookedAt.putAll(state.lookedAt);
this.battlefield = state.battlefield.copy();
this.turnNum = state.turnNum;
this.gameOver = state.gameOver;
@ -141,13 +140,8 @@ public class GameState implements Serializable, Copyable<GameState> {
this.combat = state.combat.copy();
this.turnMods = state.turnMods.copy();
this.watchers = state.watchers.copy();
for (Map.Entry<String, Object> entry : state.values.entrySet()) {
values.put(entry.getKey(), entry.getValue());
//TODO: might have to change value to Copyable
}
for (Map.Entry<UUID, Zone> entry: state.zones.entrySet()) {
zones.put(entry.getKey(), entry.getValue());
}
this.values.putAll(state.values);
this.zones.putAll(state.zones);
for (Map.Entry<UUID, Abilities<ActivatedAbility>> entry: state.otherAbilities.entrySet()) {
otherAbilities.put(entry.getKey(), entry.getValue().copy());
}
@ -457,4 +451,16 @@ public class GameState implements Serializable, Copyable<GameState> {
zones.clear();
}
public void pause() {
this.paused = true;
}
public void resume() {
this.paused = false;
}
public boolean isPaused() {
return this.paused;
}
}

View file

@ -66,9 +66,7 @@ public class Combat implements Serializable, Copyable<Combat> {
for (CombatGroup group : combat.groups) {
groups.add(group.copy());
}
for (UUID defenderId : combat.defenders) {
defenders.add(defenderId);
}
defenders.addAll(combat.defenders);
for (Map.Entry<UUID, CombatGroup> group : combat.blockingGroups.entrySet()) {
blockingGroups.put(group.getKey(), group.getValue());
}
@ -128,6 +126,8 @@ public class Combat implements Serializable, Copyable<Combat> {
//20101001 - 508.1d
checkAttackRequirements(player, game);
player.selectAttackers(game);
if (game.isPaused() || game.isGameOver())
return;
for (CombatGroup group: groups) {
for (UUID attacker: group.getAttackers()) {
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.ATTACKER_DECLARED, group.defenderId, attacker, attackerId));
@ -169,6 +169,8 @@ public class Combat implements Serializable, Copyable<Combat> {
checkBlockRequirements(player, game);
for (UUID defenderId : getPlayerDefenders(game)) {
game.getPlayer(defenderId).selectBlockers(game);
if (game.isPaused() || game.isGameOver())
return;
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.DECLARED_BLOCKERS, defenderId, defenderId));
}
}

View file

@ -67,21 +67,11 @@ public class CombatGroup implements Serializable, Copyable<CombatGroup> {
this.blocked = group.blocked;
this.defenderId = group.defenderId;
this.defenderIsPlaneswalker = group.defenderIsPlaneswalker;
for (UUID attackerId: group.attackers) {
this.attackers.add(attackerId);
}
for (UUID blockerId: group.blockers) {
this.blockers.add(blockerId);
}
for (UUID orderId: group.blockerOrder) {
this.blockerOrder.add(orderId);
}
for (UUID orderId: group.attackerOrder) {
this.attackerOrder.add(orderId);
}
for (Map.Entry<UUID, UUID> entry : group.players.entrySet()) {
players.put(entry.getKey(), entry.getValue());
}
this.attackers.addAll(group.attackers);
this.blockers.addAll(group.blockers);
this.blockerOrder.addAll(group.blockerOrder);
this.attackerOrder.addAll(group.attackerOrder);
this.players.putAll(group.players);
}
protected String getValue(Game game) {

View file

@ -157,7 +157,7 @@ public class PermanentCard extends PermanentImpl<PermanentCard> {
@Override
public boolean moveToZone(Zone toZone, UUID sourceId, Game game, boolean flag) {
Zone fromZone = game.getZone(objectId);
Zone fromZone = game.getState().getZone(objectId);
Player controller = game.getPlayer(controllerId);
if (controller != null && controller.removeFromBattlefield(this, game)) {
ZoneChangeEvent event = new ZoneChangeEvent(this, sourceId, controllerId, fromZone, toZone);
@ -187,7 +187,7 @@ public class PermanentCard extends PermanentImpl<PermanentCard> {
}
game.setZone(objectId, event.getToZone());
game.fireEvent(event);
return game.getZone(objectId) == toZone;
return game.getState().getZone(objectId) == toZone;
}
}
}
@ -197,7 +197,7 @@ public class PermanentCard extends PermanentImpl<PermanentCard> {
@Override
public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game) {
Zone fromZone = game.getZone(objectId);
Zone fromZone = game.getState().getZone(objectId);
Player controller = game.getPlayer(controllerId);
if (controller != null && controller.removeFromBattlefield(this, game)) {
ZoneChangeEvent event = new ZoneChangeEvent(this, sourceId, ownerId, fromZone, Zone.EXILED);

View file

@ -112,20 +112,11 @@ public abstract class PermanentImpl<T extends PermanentImpl<T>> extends CardImpl
this.loyaltyUsed = permanent.loyaltyUsed;
this.deathtouched = permanent.deathtouched;
this.counters = permanent.counters.copy();
for (UUID attachmentId : permanent.attachments) {
this.attachments.add(attachmentId);
}
for (UUID imprintedId : permanent.imprinted) {
this.imprinted.add(imprintedId);
}
for (UUID connectedCardId : permanent.connectedCards) {
this.connectedCards.add(connectedCardId);
}
this.attachments.addAll(permanent.attachments);
this.imprinted.addAll(permanent.imprinted);
this.connectedCards.addAll(permanent.connectedCards);
if (permanent.dealtDamageByThisTurn != null) {
dealtDamageByThisTurn = new ArrayList<UUID>();
for (UUID sourceId : permanent.dealtDamageByThisTurn) {
this.dealtDamageByThisTurn.add(sourceId);
}
dealtDamageByThisTurn = new ArrayList<UUID>(permanent.dealtDamageByThisTurn);
if (permanent.markedDamage != null) {
markedDamage = new ArrayList<Counter>();
for (Counter counter : permanent.markedDamage) {

View file

@ -135,16 +135,18 @@ public class Spell<T extends Spell<T>> implements StackObject, Card {
*/
private void updateOptionalCosts() {
Ability abilityOrig = card.getAbilities().get(ability.getId());
for (Object object : ability.getOptionalCosts()) {
Cost cost = (Cost) object;
for (Cost costOrig : abilityOrig.getOptionalCosts()) {
if (cost.getId().equals(costOrig.getId())) {
if (cost.isPaid()) {
costOrig.setPaid();
} else {
costOrig.clearPaid();
if (abilityOrig != null) {
for (Object object : ability.getOptionalCosts()) {
Cost cost = (Cost) object;
for (Cost costOrig : abilityOrig.getOptionalCosts()) {
if (cost.getId().equals(costOrig.getId())) {
if (cost.isPaid()) {
costOrig.setPaid();
} else {
costOrig.clearPaid();
}
break;
}
break;
}
}
}

View file

@ -32,13 +32,12 @@ import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Stack;
import java.util.UUID;
import mage.Constants.Zone;
import mage.abilities.Ability;
import mage.abilities.effects.Effect;
import mage.abilities.effects.ReplacementEffect;
import mage.cards.Card;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.players.Player;
@ -105,15 +104,9 @@ public class SpellStack extends Stack<StackObject> {
boolean caught = false;
Map<ReplacementEffect, Ability> rEffects = new LinkedHashMap<ReplacementEffect, Ability>();
for (StackObject stackObject: this) {
for (Ability ability: stackObject.getAbilities()) {
if (ability.getZone() == Zone.STACK) {
for (Effect effect: ability.getEffects()) {
if (effect instanceof ReplacementEffect) {
if (((ReplacementEffect)effect).applies(event, ability, game))
rEffects.put((ReplacementEffect) effect, ability);
}
}
}
for (Entry<ReplacementEffect, Ability> entry: stackObject.getAbilities().getReplacementEffects(Zone.STACK).entrySet()) {
if (entry.getKey().applies(event, entry.getValue(), game))
rEffects.put(entry.getKey(), entry.getValue());
}
}
if (rEffects.size() > 0) {

View file

@ -54,16 +54,16 @@ public class EndPhase extends Phase<EndPhase> {
}
@Override
protected void playStep(Game game, UUID activePlayerId) {
protected void playStep(Game game) {
if (currentStep.getType() == PhaseStep.CLEANUP) {
currentStep.beginStep(game, activePlayerId);
if (game.checkStateAndTriggered()) {
playStep(game, activePlayerId);
playStep(game);
}
currentStep.endStep(game, activePlayerId);
}
else
super.playStep(game, activePlayerId);
super.playStep(game);
}
@Override

View file

@ -30,6 +30,7 @@ package mage.game.turn;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import mage.Constants.PhaseStep;
@ -93,7 +94,7 @@ public abstract class Phase<T extends Phase<T>> implements Serializable {
}
public boolean play(Game game, UUID activePlayerId) {
if (game.isGameOver())
if (game.isPaused() || game.isGameOver())
return false;
this.activePlayerId = activePlayerId;
@ -101,12 +102,14 @@ public abstract class Phase<T extends Phase<T>> implements Serializable {
if (beginPhase(game, activePlayerId)) {
for (Step step: steps) {
if (game.isGameOver())
if (game.isPaused() || game.isGameOver())
return false;
currentStep = step;
if (!game.getState().getTurnMods().skipStep(activePlayerId, currentStep.getType()))
playStep(game, activePlayerId);
playStep(game);
}
if (game.isPaused() || game.isGameOver())
return false;
count++;
endPhase(game, activePlayerId);
return true;
@ -114,6 +117,34 @@ public abstract class Phase<T extends Phase<T>> implements Serializable {
return false;
}
public boolean resumePlay(Game game, PhaseStep stepType) {
if (game.isPaused() || game.isGameOver())
return false;
this.activePlayerId = game.getActivePlayerId();
Iterator<Step> it = steps.iterator();
Step step;
do {
step = it.next();
currentStep = step;
} while (step.getType() != stepType);
resumeStep(game);
while (it.hasNext()) {
step = it.next();
if (game.isPaused() || game.isGameOver())
return false;
currentStep = step;
if (!game.getState().getTurnMods().skipStep(activePlayerId, currentStep.getType()))
playStep(game);
}
if (game.isPaused() || game.isGameOver())
return false;
count++;
endPhase(game, activePlayerId);
return true;
}
public boolean beginPhase(Game game, UUID activePlayerId) {
if (!game.replaceEvent(new GameEvent(event, null, null, activePlayerId))) {
game.fireEvent(new GameEvent(preEvent, null, null, activePlayerId));
@ -138,21 +169,36 @@ public abstract class Phase<T extends Phase<T>> implements Serializable {
playExtraSteps(game, currentStep.getType());
}
protected void playStep(Game game, UUID activePlayerId) {
protected void playStep(Game game) {
if (!currentStep.skipStep(game, activePlayerId)) {
prePriority(game, activePlayerId);
currentStep.priority(game, activePlayerId);
postPriority(game, activePlayerId);
if (!game.isPaused() && !game.isGameOver())
currentStep.priority(game, activePlayerId);
if (!game.isPaused() && !game.isGameOver())
postPriority(game, activePlayerId);
}
}
protected void resumeStep(Game game) {
switch (currentStep.getStepPart()) {
case PRE:
prePriority(game, activePlayerId);
case PRIORITY:
if (!game.isPaused() && !game.isGameOver())
currentStep.priority(game, activePlayerId);
case POST:
if (!game.isPaused() && !game.isGameOver())
postPriority(game, activePlayerId);
}
}
private void playExtraSteps(Game game, PhaseStep afterStep) {
while (true) {
Step extraStep = game.getState().getTurnMods().extraStep(activePlayerId, afterStep);
if (extraStep == null)
return;
currentStep = extraStep;
playStep(game, activePlayerId);
playStep(game);
}
}

View file

@ -46,6 +46,11 @@ public abstract class Step<T extends Step<T>> implements Serializable {
protected EventType stepEvent;
protected EventType preStepEvent;
protected EventType postStepEvent;
protected StepPart stepPart;
public enum StepPart {
PRE, PRIORITY, POST;
}
public abstract T copy();
@ -60,6 +65,7 @@ public abstract class Step<T extends Step<T>> implements Serializable {
this.stepEvent = step.stepEvent;
this.preStepEvent = step.preStepEvent;
this.postStepEvent = step.postStepEvent;
this.stepPart = step.stepPart;
}
public PhaseStep getType() {
@ -67,15 +73,19 @@ public abstract class Step<T extends Step<T>> implements Serializable {
}
public void beginStep(Game game, UUID activePlayerId) {
stepPart = StepPart.PRE;
game.fireEvent(new GameEvent(preStepEvent, null, null, activePlayerId));
}
public void priority(Game game, UUID activePlayerId) {
if (hasPriority)
if (hasPriority) {
stepPart = StepPart.PRIORITY;
game.playPriority(activePlayerId);
}
}
public void endStep(Game game, UUID activePlayerId) {
stepPart = StepPart.POST;
game.fireEvent(new GameEvent(postStepEvent, null, null, activePlayerId));
}
@ -87,4 +97,8 @@ public abstract class Step<T extends Step<T>> implements Serializable {
return this.hasPriority;
}
public StepPart getStepPart() {
return stepPart;
}
}

View file

@ -30,6 +30,7 @@ package mage.game.turn;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import mage.Constants.PhaseStep;
@ -100,8 +101,8 @@ public class Turn implements Serializable {
return null;
}
public void play(Game game, UUID activePlayerId) {
if (game.isGameOver())
public void play(Game game, UUID activePlayerId) {
if (game.isPaused() || game.isGameOver())
return;
if (game.getState().getTurnMods().skipTurn(activePlayerId))
@ -113,7 +114,7 @@ public class Turn implements Serializable {
resetCounts();
game.getPlayer(activePlayerId).beginTurn(game);
for (Phase phase: phases) {
if (game.isGameOver())
if (game.isPaused() || game.isGameOver())
return;
currentPhase = phase;
if (!game.getState().getTurnMods().skipPhase(activePlayerId, currentPhase.getType())) {
@ -132,6 +133,44 @@ public class Turn implements Serializable {
playExtraTurns(game);
}
public void resumePlay(Game game) {
activePlayerId = game.getActivePlayerId();
UUID priorityPlayerId = game.getPriorityPlayerId();
TurnPhase phaseType = game.getPhase().getType();
PhaseStep stepType = game.getStep().getType();
Iterator<Phase> it = phases.iterator();
Phase phase;
do {
phase = it.next();
currentPhase = phase;
} while (phase.type != phaseType);
if (phase.resumePlay(game, stepType)) {
//20091005 - 500.4/703.4n
game.emptyManaPools();
game.saveState();
//20091005 - 500.8
playExtraPhases(game, phase.getType());
}
while (it.hasNext()) {
phase = it.next();
if (game.isPaused() || game.isGameOver())
return;
currentPhase = phase;
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());
}
}
if (!currentPhase.equals(phase)) // phase was changed from the card
break;
}
}
private void checkTurnIsControlledByOtherPlayer(Game game, UUID activePlayerId) {
UUID newControllerId = game.getState().getTurnMods().controlsTurn(activePlayerId);
if (newControllerId != null && !newControllerId.equals(activePlayerId)) {

View file

@ -154,9 +154,8 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
this.range = player.range;
this.canGainLife = player.canGainLife;
this.canLoseLife = player.canLoseLife;
for (UUID id: player.inRange) {
this.inRange.add(id);
}
this.attachments.addAll(player.attachments);
this.inRange.addAll(player.inRange);
this.userData = player.userData;
}
@ -504,7 +503,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
if (card != null) {
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, ability.getId(), ability.getSourceId(), playerId))) {
int bookmark = game.bookmarkState();
Zone fromZone = game.getZone(card.getId());
Zone fromZone = game.getState().getZone(card.getId());
card.cast(game, fromZone, ability, playerId);
Ability spellAbility = game.getStack().getSpell(ability.getId()).getSpellAbility();
@ -530,7 +529,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
//20091005 - 305.1
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, card.getId(), playerId))) {
int bookmark = game.bookmarkState();
Zone zone = game.getZone(card.getId());
Zone zone = game.getState().getZone(card.getId());
switch (zone) {
case HAND:
removeFromHand(card, game);
@ -541,6 +540,9 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
case GRAVEYARD:
removeFromGraveyard(card, game);
break;
default:
// invalid zone for play land
return false;
}
if (card.putOntoBattlefield(game, zone, null, playerId)) {

View file

@ -76,9 +76,7 @@ public abstract class TargetImpl<T extends TargetImpl<T>> implements Target {
this.minNumberOfTargets = target.minNumberOfTargets;
this.required = target.required;
this.chosen = target.chosen;
for (Entry<UUID, Integer> entry: target.targets.entrySet()) {
targets.put(entry.getKey(), entry.getValue());
}
this.targets.putAll(target.targets);
}
@Override

View file

@ -74,7 +74,7 @@ public abstract class TargetObject<T extends TargetObject<T>> extends TargetImpl
@Override
public boolean canTarget(UUID id, Game game) {
MageObject object = game.getObject(id);
if (object != null && game.getZone(id).match(zone))
if (object != null && game.getState().getZone(id).match(zone))
return getFilter().match(object);
return false;
}

View file

@ -146,7 +146,8 @@ public class TargetPermanent<T extends TargetPermanent<T>> extends TargetObject<
int remainingTargets = this.minNumberOfTargets - targets.size();
if (remainingTargets == 0) {
// if we return true, then AnowonTheRuinSage will hang for AI when no targets in play
return false;
// TODO: retest Anowon the Ruin Sage
return true;
}
int count = 0;
for (Permanent permanent: game.getBattlefield().getActivePermanents(filter, sourceControllerId, game)) {

View file

@ -62,7 +62,7 @@ public class TargetCardInExile extends TargetCard<TargetCardInExile> {
@Override
public boolean canTarget(UUID id, Ability source, Game game) {
Card card = game.getCard(id);
if (card != null && game.getZone(card.getId()) == Zone.EXILED) {
if (card != null && game.getState().getZone(card.getId()) == Zone.EXILED) {
ExileZone exile;
if (zoneId != null) {
exile = game.getExile().getExileZone(zoneId);

View file

@ -66,7 +66,7 @@ public class TargetCardInGraveyard extends TargetCard<TargetCardInGraveyard> {
@Override
public boolean canTarget(UUID id, Ability source, Game game) {
Card card = game.getCard(id);
if (card != null && game.getZone(card.getId()) == Zone.GRAVEYARD)
if (card != null && game.getState().getZone(card.getId()) == Zone.GRAVEYARD)
return filter.match(card);
return false;
}

View file

@ -28,7 +28,7 @@ public class TargetCardInOpponentsGraveyard extends TargetCard<TargetCardInOppon
@Override
public boolean canTarget(UUID id, Ability source, Game game) {
Card card = game.getCard(id);
if (card != null && game.getZone(card.getId()) == Constants.Zone.GRAVEYARD) {
if (card != null && game.getState().getZone(card.getId()) == Constants.Zone.GRAVEYARD) {
if (game.getOpponents(source.getControllerId()).contains(card.getOwnerId())) {
return filter.match(card);
}

View file

@ -66,7 +66,7 @@ public class TargetCardInYourGraveyard extends TargetCard<TargetCardInYourGravey
@Override
public boolean canTarget(UUID id, Ability source, Game game) {
Card card = game.getCard(id);
if (card != null && game.getZone(card.getId()) == Zone.GRAVEYARD)
if (card != null && game.getState().getZone(card.getId()) == Zone.GRAVEYARD)
if (game.getPlayer(source.getControllerId()).getGraveyard().contains(id))
return filter.match(card);
return false;