mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 02:30:08 -08:00
Fixed miss copy code in Game object (lki, cards), removed unused code. Possible fixes:
* simulated games was able to change objects from another games (ConcurrentModificationException, related tod202278ccd, details in3a6cdd2615); * AI: fixed cards disappear in multiplayer games with computer (details in #6738);
This commit is contained in:
parent
9f882824a0
commit
1664ee01cf
39 changed files with 201 additions and 125 deletions
|
|
@ -15,8 +15,8 @@ public class TwoPlayerDuel extends GameImpl {
|
||||||
this(attackOption, range, mulligan, startLife, 60);
|
this(attackOption, range, mulligan, startLife, 60);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TwoPlayerDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife, int startingSize) {
|
public TwoPlayerDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startingLife, int startingHandSize) {
|
||||||
super(attackOption, range, mulligan, startLife, startingSize);
|
super(attackOption, range, mulligan, startingLife, startingHandSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TwoPlayerDuel(final TwoPlayerDuel game) {
|
public TwoPlayerDuel(final TwoPlayerDuel game) {
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ class AjaniStrengthOfThePrideEffect extends OneShotEffect {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Player player = game.getPlayer(source.getControllerId());
|
Player player = game.getPlayer(source.getControllerId());
|
||||||
if (player == null || player.getLife() < game.getLife() + 15) {
|
if (player == null || player.getLife() < game.getStartingLife() + 15) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
new ExileSourceEffect().apply(game, source);
|
new ExileSourceEffect().apply(game, source);
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ enum AngelOfDestinyCondition implements Condition {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Player player = game.getPlayer(source.getControllerId());
|
Player player = game.getPlayer(source.getControllerId());
|
||||||
return player != null && player.getLife() >= game.getLife() + 15;
|
return player != null && player.getLife() >= game.getStartingLife() + 15;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ enum AnyaMercilessAngelDynamicValue implements DynamicValue {
|
||||||
if (controller == null) {
|
if (controller == null) {
|
||||||
return 3 * opponentCount;
|
return 3 * opponentCount;
|
||||||
}
|
}
|
||||||
int startingLifeTotal = game.getLife();
|
int startingLifeTotal = game.getStartingLife();
|
||||||
for (UUID opponentId : game.getOpponents(controller.getId())) {
|
for (UUID opponentId : game.getOpponents(controller.getId())) {
|
||||||
Player opponent = game.getPlayer(opponentId);
|
Player opponent = game.getPlayer(opponentId);
|
||||||
if (opponent != null && opponent.getLife() < startingLifeTotal / 2) {
|
if (opponent != null && opponent.getLife() < startingLifeTotal / 2) {
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ class AyliEternalPilgrimCondition implements Condition {
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Player player = game.getPlayer(source.getControllerId());
|
Player player = game.getPlayer(source.getControllerId());
|
||||||
if(player != null) {
|
if(player != null) {
|
||||||
return player.getLife() >= game.getLife() + 10;
|
return player.getLife() >= game.getStartingLife() + 10;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ class ChaliceOfLifeEffect extends OneShotEffect {
|
||||||
player.gainLife(1, game, source);
|
player.gainLife(1, game, source);
|
||||||
|
|
||||||
// if you have at least 10 life more than your starting life total, transform Chalice of Life.
|
// if you have at least 10 life more than your starting life total, transform Chalice of Life.
|
||||||
if (player.getLife() >= game.getLife() + 10) {
|
if (player.getLife() >= game.getStartingLife() + 10) {
|
||||||
permanent.transform(game);
|
permanent.transform(game);
|
||||||
game.informPlayers(permanent.getName() + " transforms into " + permanent.getSecondCardFace().getName());
|
game.informPlayers(permanent.getName() + " transforms into " + permanent.getSecondCardFace().getName());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,6 @@ enum CosmosElixirCondition implements Condition {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Player player = game.getPlayer(source.getControllerId());
|
Player player = game.getPlayer(source.getControllerId());
|
||||||
return player != null && player.getLife() > game.getLife();
|
return player != null && player.getLife() > game.getStartingLife();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ class ExquisiteArchangelEffect extends ReplacementEffectImpl {
|
||||||
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
|
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
|
||||||
if (player != null && sourcePermanent != null) {
|
if (player != null && sourcePermanent != null) {
|
||||||
new ExileSourceEffect().apply(game, source);
|
new ExileSourceEffect().apply(game, source);
|
||||||
player.setLife(game.getLife(), game, source);
|
player.setLife(game.getStartingLife(), game, source);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ enum GyrudaDoomOfDepthsCompanionCondition implements CompanionCondition {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLegal(Set<Card> deck, int startingSize) {
|
public boolean isLegal(Set<Card> deck, int startingHandSize) {
|
||||||
return deck
|
return deck
|
||||||
.stream()
|
.stream()
|
||||||
.mapToInt(MageObject::getManaValue)
|
.mapToInt(MageObject::getManaValue)
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ enum HappilyEverAfterCondition implements Condition {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Player player = game.getPlayer(source.getControllerId());
|
Player player = game.getPlayer(source.getControllerId());
|
||||||
if (player == null || player.getLife() < game.getLife()) {
|
if (player == null || player.getLife() < game.getStartingLife()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ObjectColor color = new ObjectColor("");
|
ObjectColor color = new ObjectColor("");
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ enum JeganthaTheWellspringCompanionCondition implements CompanionCondition {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLegal(Set<Card> deck, int startingSize) {
|
public boolean isLegal(Set<Card> deck, int startingHandSize) {
|
||||||
return deck.stream().noneMatch(JeganthaTheWellspringCompanionCondition::checkCard);
|
return deck.stream().noneMatch(JeganthaTheWellspringCompanionCondition::checkCard);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ enum KaheeraTheOrphanguardCompanionCondition implements CompanionCondition {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLegal(Set<Card> deck, int startingSize) {
|
public boolean isLegal(Set<Card> deck, int startingHandSize) {
|
||||||
return deck.stream()
|
return deck.stream()
|
||||||
.filter(card -> card.hasCardTypeForDeckbuilding(CardType.CREATURE))
|
.filter(card -> card.hasCardTypeForDeckbuilding(CardType.CREATURE))
|
||||||
.allMatch(KaheeraTheOrphanguardCompanionCondition::isCardLegal);
|
.allMatch(KaheeraTheOrphanguardCompanionCondition::isCardLegal);
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ enum KerugaCondition implements CompanionCondition {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLegal(Set<Card> deck, int startingSize) {
|
public boolean isLegal(Set<Card> deck, int startingHandSize) {
|
||||||
return deck.stream().allMatch(card -> card.isLand() || card.getManaValue() >= 3);
|
return deck.stream().allMatch(card -> card.isLand() || card.getManaValue() >= 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -125,7 +125,7 @@ class LongRestEffect extends OneShotEffect {
|
||||||
if (numCards > 0) {
|
if (numCards > 0) {
|
||||||
controller.moveCards(cardsToHand, Zone.HAND, source, game);
|
controller.moveCards(cardsToHand, Zone.HAND, source, game);
|
||||||
if (numCards >= 8) {
|
if (numCards >= 8) {
|
||||||
controller.setLife(game.getLife(), game, source);
|
controller.setLife(game.getStartingLife(), game, source);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ enum LurrusOfTheDreamDenCompanionCondition implements CompanionCondition {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLegal(Set<Card> deck, int startingSize) {
|
public boolean isLegal(Set<Card> deck, int startingHandSize) {
|
||||||
return deck.stream()
|
return deck.stream()
|
||||||
.filter(card -> card.isPermanent())
|
.filter(card -> card.isPermanent())
|
||||||
.mapToInt(MageObject::getManaValue)
|
.mapToInt(MageObject::getManaValue)
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ enum LutriTheSpellchaserCompanionCondition implements CompanionCondition {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLegal(Set<Card> deck, int startingSize) {
|
public boolean isLegal(Set<Card> deck, int startingHandSize) {
|
||||||
Map<String, Integer> cardMap = new HashMap<>();
|
Map<String, Integer> cardMap = new HashMap<>();
|
||||||
deck.stream()
|
deck.stream()
|
||||||
.filter(card -> !card.isLand())
|
.filter(card -> !card.isLand())
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ enum OboshThePreypiercerCompanionCondition implements CompanionCondition {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLegal(Set<Card> deck, int startingSize) {
|
public boolean isLegal(Set<Card> deck, int startingHandSize) {
|
||||||
return deck
|
return deck
|
||||||
.stream()
|
.stream()
|
||||||
.filter(card -> !card.isLand())
|
.filter(card -> !card.isLand())
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ class OketrasLastMercyEffect extends OneShotEffect {
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Player controller = game.getPlayer(source.getControllerId());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
if (controller != null) {
|
if (controller != null) {
|
||||||
controller.setLife(game.getLife(), game, source);
|
controller.setLife(game.getStartingLife(), game, source);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ enum LifeCondition implements Condition {
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Player you = game.getPlayer(source.getControllerId());
|
Player you = game.getPlayer(source.getControllerId());
|
||||||
if (you != null) {
|
if (you != null) {
|
||||||
return you.getLife() >= game.getLife();
|
return you.getLife() >= game.getStartingLife();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ class ResoluteArchangelEffect extends OneShotEffect {
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Player controller = game.getPlayer(source.getControllerId());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
if (controller != null) {
|
if (controller != null) {
|
||||||
controller.setLife(game.getLife(), game, source);
|
controller.setLife(game.getStartingLife(), game, source);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -82,7 +82,7 @@ enum ControllerLifeLowerThanStrtingLife implements Condition {
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Player controller = game.getPlayer(source.getControllerId());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
if (controller != null) {
|
if (controller != null) {
|
||||||
return controller.getLife() < game.getLife();
|
return controller.getLife() < game.getStartingLife();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,6 @@ enum RighteousValkyrieCondition implements Condition {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Player player = game.getPlayer(source.getControllerId());
|
Player player = game.getPlayer(source.getControllerId());
|
||||||
return player != null && player.getLife() >= game.getLife() + 7;
|
return player != null && player.getLife() >= game.getStartingLife() + 7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ enum SpeakerOfTheHeavensCondition implements Condition {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Player player = game.getPlayer(source.getControllerId());
|
Player player = game.getPlayer(source.getControllerId());
|
||||||
if (player == null || player.getLife() < game.getLife() + 7) {
|
if (player == null || player.getLife() < game.getStartingLife() + 7) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ class TorgaarFamineIncarnateEffect extends OneShotEffect {
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source));
|
Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source));
|
||||||
if (targetPlayer != null) {
|
if (targetPlayer != null) {
|
||||||
int startingLifeTotal = game.getLife();
|
int startingLifeTotal = game.getStartingLife();
|
||||||
targetPlayer.setLife(startingLifeTotal / 2, game, source);
|
targetPlayer.setLife(startingLifeTotal / 2, game, source);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ enum UmoriCondition implements CompanionCondition {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLegal(Set<Card> deck, int startingSize) {
|
public boolean isLegal(Set<Card> deck, int startingHandSize) {
|
||||||
Set<CardType> cardTypes = new HashSet<>();
|
Set<CardType> cardTypes = new HashSet<>();
|
||||||
for (Card card : deck) {
|
for (Card card : deck) {
|
||||||
// Lands are fine.
|
// Lands are fine.
|
||||||
|
|
|
||||||
|
|
@ -72,8 +72,8 @@ enum YorionSkyNomadCompanionCondition implements CompanionCondition {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLegal(Set<Card> deck, int startingSize) {
|
public boolean isLegal(Set<Card> deck, int startingHandSize) {
|
||||||
return deck.size() >= startingSize + 20;
|
return deck.size() >= startingHandSize + 20;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ enum ZirdaTheDawnwakerCompanionCondition implements CompanionCondition {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLegal(Set<Card> deck, int startingSize) {
|
public boolean isLegal(Set<Card> deck, int startingHandSize) {
|
||||||
return deck
|
return deck
|
||||||
.stream()
|
.stream()
|
||||||
.filter(card -> card.isPermanent())
|
.filter(card -> card.isPermanent())
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import mage.constants.SubTypeSet;
|
||||||
import mage.constants.SuperType;
|
import mage.constants.SuperType;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.ZoneChangeEvent;
|
import mage.game.events.ZoneChangeEvent;
|
||||||
|
import mage.util.Copyable;
|
||||||
import mage.util.SubTypes;
|
import mage.util.SubTypes;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
@ -21,7 +22,7 @@ import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public interface MageObject extends MageItem, Serializable {
|
public interface MageObject extends MageItem, Serializable, Copyable<MageObject> {
|
||||||
|
|
||||||
String getName();
|
String getName();
|
||||||
|
|
||||||
|
|
@ -136,6 +137,7 @@ public interface MageObject extends MageItem, Serializable {
|
||||||
void adjustTargets(Ability ability, Game game);
|
void adjustTargets(Ability ability, Game game);
|
||||||
|
|
||||||
// memory object copy (not mtg)
|
// memory object copy (not mtg)
|
||||||
|
@Override
|
||||||
MageObject copy();
|
MageObject copy();
|
||||||
|
|
||||||
// copied card info (mtg)
|
// copied card info (mtg)
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,8 @@ public class CompanionAbility extends SpecialAction {
|
||||||
return "Companion — " + companionCondition.getRule();
|
return "Companion — " + companionCondition.getRule();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isLegal(Set<Card> cards, int startingSize) {
|
public boolean isLegal(Set<Card> cards, int startingHandSize) {
|
||||||
return companionCondition.isLegal(cards, startingSize);
|
return companionCondition.isLegal(cards, startingHandSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ public interface CompanionCondition extends Serializable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param deck The set of cards to check.
|
* @param deck The set of cards to check.
|
||||||
* @param startingSize
|
* @param startingHandSize
|
||||||
* @return Whether the companion is valid for that deck.
|
* @return Whether the companion is valid for that deck.
|
||||||
*/
|
*/
|
||||||
boolean isLegal(Set<Card> deck, int startingSize);
|
boolean isLegal(Set<Card> deck, int startingHandSize);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,9 +64,7 @@ public class MageDrawAction extends MageAction {
|
||||||
if (!player.isTopCardRevealed() && numDrawn > 0) {
|
if (!player.isTopCardRevealed() && numDrawn > 0) {
|
||||||
game.fireInformEvent(player.getLogName() + " draws " + CardUtil.numberToText(numDrawn, "a") + " card" + (numDrawn > 1 ? "s" : ""));
|
game.fireInformEvent(player.getLogName() + " draws " + CardUtil.numberToText(numDrawn, "a") + " card" + (numDrawn > 1 ? "s" : ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
setScore(player, score);
|
setScore(player, score);
|
||||||
game.setStateCheckRequired();
|
|
||||||
}
|
}
|
||||||
return numDrawn;
|
return numDrawn;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,9 @@ public abstract class MeldCard extends CardImpl {
|
||||||
this.halves = new CardsImpl(card.halves);
|
this.halves = new CardsImpl(card.halves);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract MeldCard copy();
|
||||||
|
|
||||||
public void setMelded(boolean isMelded, Game game) {
|
public void setMelded(boolean isMelded, Game game) {
|
||||||
game.getState().getCardState(getId()).setMelded(isMelded);
|
game.getState().getCardState(getId()).setMelded(isMelded);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ import mage.constants.SubType;
|
||||||
import mage.constants.SuperType;
|
import mage.constants.SuperType;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.ZoneChangeEvent;
|
import mage.game.events.ZoneChangeEvent;
|
||||||
import mage.util.Copyable;
|
|
||||||
import mage.util.GameLog;
|
import mage.util.GameLog;
|
||||||
import mage.util.SubTypes;
|
import mage.util.SubTypes;
|
||||||
|
|
||||||
|
|
@ -28,7 +27,7 @@ import java.util.UUID;
|
||||||
/**
|
/**
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
*/
|
*/
|
||||||
public abstract class Designation implements MageObject, Copyable<Designation> {
|
public abstract class Designation implements MageObject {
|
||||||
|
|
||||||
private static final List<CardType> emptySet = new ArrayList<>();
|
private static final List<CardType> emptySet = new ArrayList<>();
|
||||||
private static final ObjectColor emptyColor = new ObjectColor();
|
private static final ObjectColor emptyColor = new ObjectColor();
|
||||||
|
|
@ -69,6 +68,9 @@ public abstract class Designation implements MageObject, Copyable<Designation> {
|
||||||
this.unique = designation.unique;
|
this.unique = designation.unique;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract Designation copy();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FrameStyle getFrameStyle() {
|
public FrameStyle getFrameStyle() {
|
||||||
return frameStyle;
|
return frameStyle;
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,13 @@ import mage.abilities.AbilitiesImpl;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.counters.Counter;
|
import mage.counters.Counter;
|
||||||
import mage.counters.Counters;
|
import mage.counters.Counters;
|
||||||
|
import mage.util.Copyable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author BetaSteward
|
* @author BetaSteward
|
||||||
*/
|
*/
|
||||||
public class CardState implements Serializable {
|
public class CardState implements Serializable, Copyable<CardState> {
|
||||||
|
|
||||||
protected boolean faceDown;
|
protected boolean faceDown;
|
||||||
protected Map<String, String> info;
|
protected Map<String, String> info;
|
||||||
|
|
@ -50,6 +51,7 @@ public class CardState implements Serializable {
|
||||||
this.melded = state.melded;
|
this.melded = state.melded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public CardState copy() {
|
public CardState copy() {
|
||||||
return new CardState(this);
|
return new CardState(this);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ public interface Game extends MageItem, Serializable, Copyable<Game> {
|
||||||
|
|
||||||
int getNumPlayers();
|
int getNumPlayers();
|
||||||
|
|
||||||
int getLife();
|
int getStartingLife();
|
||||||
|
|
||||||
RangeOfInfluence getRangeOfInfluence();
|
RangeOfInfluence getRangeOfInfluence();
|
||||||
|
|
||||||
|
|
@ -244,10 +244,6 @@ public interface Game extends MageItem, Serializable, Copyable<Game> {
|
||||||
|
|
||||||
Player getLosingPlayer();
|
Player getLosingPlayer();
|
||||||
|
|
||||||
void setStateCheckRequired();
|
|
||||||
|
|
||||||
boolean getStateCheckRequired();
|
|
||||||
|
|
||||||
//client event methods
|
//client event methods
|
||||||
void addTableEventListener(Listener<TableEvent> listener);
|
void addTableEventListener(Listener<TableEvent> listener);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,8 @@ public abstract class GameCommanderImpl extends GameImpl {
|
||||||
|
|
||||||
protected boolean startingPlayerSkipsDraw = true;
|
protected boolean startingPlayerSkipsDraw = true;
|
||||||
|
|
||||||
public GameCommanderImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife, int startingSize) {
|
public GameCommanderImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startingLife, int startingHandSize) {
|
||||||
super(attackOption, range, mulligan, startLife, startingSize);
|
super(attackOption, range, mulligan, startingLife, startingHandSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameCommanderImpl(final GameCommanderImpl game) {
|
public GameCommanderImpl(final GameCommanderImpl game) {
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,10 @@ import mage.target.Target;
|
||||||
import mage.target.TargetCard;
|
import mage.target.TargetCard;
|
||||||
import mage.target.TargetPermanent;
|
import mage.target.TargetPermanent;
|
||||||
import mage.target.TargetPlayer;
|
import mage.target.TargetPlayer;
|
||||||
import mage.util.*;
|
import mage.util.CardUtil;
|
||||||
|
import mage.util.GameLog;
|
||||||
|
import mage.util.MessageToClient;
|
||||||
|
import mage.util.RandomUtil;
|
||||||
import mage.util.functions.CopyApplier;
|
import mage.util.functions.CopyApplier;
|
||||||
import mage.watchers.Watcher;
|
import mage.watchers.Watcher;
|
||||||
import mage.watchers.common.*;
|
import mage.watchers.common.*;
|
||||||
|
|
@ -71,14 +74,23 @@ import java.util.*;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Game object. It must contain static data (e.g. no changeable in the game like game settings)
|
||||||
|
* <p>
|
||||||
|
* "transient field" logic uses for serialization/replays (mark temporary fields as transient,
|
||||||
|
* also look for non restored fields in copy constructor for details)
|
||||||
|
* <p>
|
||||||
|
* WARNING, if you add new fields then don't forget to add it to copy constructor (deep copy, not ref).
|
||||||
|
* If it's a temporary/auto-generated data then mark that field as transient and comment in copy constructor.
|
||||||
|
*/
|
||||||
public abstract class GameImpl implements Game {
|
public abstract class GameImpl implements Game {
|
||||||
|
|
||||||
private static final int ROLLBACK_TURNS_MAX = 4;
|
private static final int ROLLBACK_TURNS_MAX = 4;
|
||||||
private static final String UNIT_TESTS_ERROR_TEXT = "Error in unit tests";
|
private static final String UNIT_TESTS_ERROR_TEXT = "Error in unit tests";
|
||||||
private static final Logger logger = Logger.getLogger(GameImpl.class);
|
private static final Logger logger = Logger.getLogger(GameImpl.class);
|
||||||
|
|
||||||
private transient Object customData;
|
private transient Object customData; // temporary data, used in AI simulations
|
||||||
|
private transient Player losingPlayer; // temporary data, used in AI simulations
|
||||||
protected boolean simulation = false;
|
protected boolean simulation = false;
|
||||||
protected boolean checkPlayableState = false;
|
protected boolean checkPlayableState = false;
|
||||||
|
|
||||||
|
|
@ -95,18 +107,21 @@ public abstract class GameImpl implements Game {
|
||||||
protected Map<Zone, Map<UUID, CardState>> lkiCardState = new EnumMap<>(Zone.class);
|
protected Map<Zone, Map<UUID, CardState>> lkiCardState = new EnumMap<>(Zone.class);
|
||||||
protected Map<UUID, Map<Integer, MageObject>> lkiExtended = new HashMap<>();
|
protected Map<UUID, Map<Integer, MageObject>> lkiExtended = new HashMap<>();
|
||||||
// Used to check if an object was moved by the current effect in resolution (so Wrath like effect can be handled correctly)
|
// Used to check if an object was moved by the current effect in resolution (so Wrath like effect can be handled correctly)
|
||||||
protected Map<Zone, Set<UUID>> shortLivingLKI = new EnumMap<>(Zone.class);
|
protected Map<Zone, Set<UUID>> lkiShortLiving = new EnumMap<>(Zone.class);
|
||||||
|
|
||||||
// Permanents entering the Battlefield while handling replacement effects before they are added to the battlefield
|
// Permanents entering the Battlefield while handling replacement effects before they are added to the battlefield
|
||||||
protected Map<UUID, Permanent> permanentsEntering = new HashMap<>();
|
protected Map<UUID, Permanent> permanentsEntering = new HashMap<>();
|
||||||
|
// used to set the counters a permanent adds the battlefield (if no replacement effect is used e.g. Persist)
|
||||||
|
protected Map<UUID, Counters> enterWithCounters = new HashMap<>();
|
||||||
|
|
||||||
protected GameState state;
|
protected GameState state;
|
||||||
private transient Stack<Integer> savedStates = new Stack<>();
|
private transient Stack<Integer> savedStates = new Stack<>();
|
||||||
protected transient GameStates gameStates = new GameStates();
|
protected transient GameStates gameStates = new GameStates();
|
||||||
|
|
||||||
// game states to allow player rollback
|
// game states to allow player rollback
|
||||||
protected transient Map<Integer, GameState> gameStatesRollBack = new HashMap<>();
|
protected transient Map<Integer, GameState> gameStatesRollBack = new HashMap<>();
|
||||||
protected boolean executingRollback;
|
protected transient boolean executingRollback;
|
||||||
protected int turnToGoToForRollback;
|
protected transient int turnToGoToForRollback;
|
||||||
|
|
||||||
protected Date startTime;
|
protected Date startTime;
|
||||||
protected Date endTime;
|
protected Date endTime;
|
||||||
|
|
@ -121,73 +136,126 @@ public abstract class GameImpl implements Game {
|
||||||
protected GameOptions gameOptions;
|
protected GameOptions gameOptions;
|
||||||
protected String startMessage;
|
protected String startMessage;
|
||||||
|
|
||||||
// private final transient LinkedList<MageAction> actions;
|
private boolean scopeRelevant = false; // replacement effects: used to indicate that currently applied replacement effects have to check for scope relevance (614.12 13/01/18)
|
||||||
private Player scorePlayer;
|
private boolean saveGame = false; // replay code, not done
|
||||||
// private int score = 0;
|
private int priorityTime; // match time limit
|
||||||
private Player losingPlayer;
|
private final int startingLife;
|
||||||
private boolean stateCheckRequired = false;
|
private final int startingHandSize;
|
||||||
|
protected transient PlayerList playerList; // auto-generated from state, don't copy
|
||||||
|
|
||||||
// used to indicate that currently applied replacement effects have to check for scope relevance (614.12 13/01/18)
|
// infinite loop check (temporary data, do not copy)
|
||||||
private boolean scopeRelevant = false;
|
private transient int infiniteLoopCounter; // used to check if the game is in an infinite loop
|
||||||
private boolean saveGame = false;
|
private transient int lastNumberOfAbilitiesOnTheStack; // used to check how long no new ability was put to stack
|
||||||
private int priorityTime;
|
private transient List<Integer> lastPlayersLifes = null; // if life is going down, it's no infinite loop
|
||||||
|
private transient final LinkedList<UUID> stackObjectsCheck = new LinkedList<>(); // used to check if different sources used the stack
|
||||||
private final int startLife;
|
|
||||||
private final int startingSize;
|
|
||||||
protected PlayerList playerList; // auto-generated from state, don't copy
|
|
||||||
|
|
||||||
// infinite loop check (no copy of this attributes neccessary)
|
|
||||||
private int infiniteLoopCounter; // used to check if the game is in an infinite loop
|
|
||||||
private int lastNumberOfAbilitiesOnTheStack; // used to check how long no new ability was put to stack
|
|
||||||
private List<Integer> lastPlayersLifes = null; // if life is going down, it's no infinite loop
|
|
||||||
private final LinkedList<UUID> stackObjectsCheck = new LinkedList<>(); // used to check if different sources used the stack
|
|
||||||
|
|
||||||
// used to set the counters a permanent adds the battlefield (if no replacement effect is used e.g. Persist)
|
|
||||||
protected Map<UUID, Counters> enterWithCounters = new HashMap<>();
|
|
||||||
|
|
||||||
// temporary store for income concede commands, don't copy
|
// temporary store for income concede commands, don't copy
|
||||||
private final LinkedList<UUID> concedingPlayers = new LinkedList<>();
|
private final LinkedList<UUID> concedingPlayers = new LinkedList<>();
|
||||||
|
|
||||||
public GameImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife, int startingSize) {
|
public GameImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startingLife, int startingHandSize) {
|
||||||
this.id = UUID.randomUUID();
|
this.id = UUID.randomUUID();
|
||||||
this.range = range;
|
this.range = range;
|
||||||
this.mulligan = mulligan;
|
this.mulligan = mulligan;
|
||||||
this.attackOption = attackOption;
|
this.attackOption = attackOption;
|
||||||
this.state = new GameState();
|
this.state = new GameState();
|
||||||
this.startLife = startLife;
|
this.startingLife = startingLife;
|
||||||
this.executingRollback = false;
|
this.executingRollback = false;
|
||||||
this.startingSize = startingSize;
|
this.startingHandSize = startingHandSize;
|
||||||
initGameDefaultWatchers();
|
initGameDefaultWatchers();
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameImpl(final GameImpl game) {
|
public GameImpl(final GameImpl game) {
|
||||||
this.id = game.id;
|
//this.customData = game.customData; // temporary data, no need on game copy
|
||||||
this.ready = game.ready;
|
//this.losingPlayer = game.losingPlayer; // temporary data, no need on game copy
|
||||||
this.startingPlayerId = game.startingPlayerId;
|
|
||||||
this.winnerId = game.winnerId;
|
|
||||||
this.range = game.range;
|
|
||||||
this.mulligan = game.getMulligan().copy();
|
|
||||||
this.attackOption = game.attackOption;
|
|
||||||
this.state = game.state.copy();
|
|
||||||
this.gameCards = game.gameCards;
|
|
||||||
this.simulation = game.simulation;
|
this.simulation = game.simulation;
|
||||||
this.checkPlayableState = game.checkPlayableState;
|
this.checkPlayableState = game.checkPlayableState;
|
||||||
this.gameOptions = game.gameOptions;
|
|
||||||
this.lki.putAll(game.lki);
|
|
||||||
this.lkiExtended.putAll(game.lkiExtended);
|
|
||||||
this.lkiCardState.putAll(game.lkiCardState);
|
|
||||||
this.shortLivingLKI.putAll(game.shortLivingLKI);
|
|
||||||
this.permanentsEntering.putAll(game.permanentsEntering);
|
|
||||||
|
|
||||||
this.stateCheckRequired = game.stateCheckRequired;
|
this.id = game.id;
|
||||||
this.scorePlayer = game.scorePlayer;
|
|
||||||
this.scopeRelevant = game.scopeRelevant;
|
this.ready = game.ready;
|
||||||
this.priorityTime = game.priorityTime;
|
//this.tableEventSource = game.tableEventSource; // client-server part, not need on copy/simulations
|
||||||
this.saveGame = game.saveGame;
|
//this.playerQueryEventSource = game.playerQueryEventSource; // client-server part, not need on copy/simulations
|
||||||
this.startLife = game.startLife;
|
|
||||||
this.enterWithCounters.putAll(game.enterWithCounters);
|
for (Entry<UUID, Card> entry : game.gameCards.entrySet()) {
|
||||||
this.startingSize = game.startingSize;
|
this.gameCards.put(entry.getKey(), entry.getValue().copy());
|
||||||
|
}
|
||||||
|
for (Entry<UUID, MeldCard> entry : game.meldCards.entrySet()) {
|
||||||
|
this.meldCards.put(entry.getKey(), entry.getValue().copy());
|
||||||
|
}
|
||||||
|
|
||||||
|
// lki
|
||||||
|
for (Entry<Zone, Map<UUID, MageObject>> entry : game.lki.entrySet()) {
|
||||||
|
Map<UUID, MageObject> lkiMap = new HashMap<>();
|
||||||
|
for (Entry<UUID, MageObject> entryMap : entry.getValue().entrySet()) {
|
||||||
|
lkiMap.put(entryMap.getKey(), entryMap.getValue().copy());
|
||||||
|
}
|
||||||
|
this.lki.put(entry.getKey(), lkiMap);
|
||||||
|
}
|
||||||
|
// lkiCardState
|
||||||
|
for (Entry<Zone, Map<UUID, CardState>> entry : game.lkiCardState.entrySet()) {
|
||||||
|
Map<UUID, CardState> lkiMap = new HashMap<>();
|
||||||
|
for (Entry<UUID, CardState> entryMap : entry.getValue().entrySet()) {
|
||||||
|
lkiMap.put(entryMap.getKey(), entryMap.getValue().copy());
|
||||||
|
}
|
||||||
|
this.lkiCardState.put(entry.getKey(), lkiMap);
|
||||||
|
}
|
||||||
|
// lkiExtended
|
||||||
|
for (Entry<UUID, Map<Integer, MageObject>> entry : game.lkiExtended.entrySet()) {
|
||||||
|
Map<Integer, MageObject> lkiMap = new HashMap<>();
|
||||||
|
for (Entry<Integer, MageObject> entryMap : entry.getValue().entrySet()) {
|
||||||
|
lkiMap.put(entryMap.getKey(), entryMap.getValue().copy());
|
||||||
|
}
|
||||||
|
this.lkiExtended.put(entry.getKey(), lkiMap);
|
||||||
|
}
|
||||||
|
// lkiShortLiving
|
||||||
|
for (Entry<Zone, Set<UUID>> entry : game.lkiShortLiving.entrySet()) {
|
||||||
|
this.lkiShortLiving.put(entry.getKey(), new HashSet<>(entry.getValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Entry<UUID, Permanent> entry : game.permanentsEntering.entrySet()) {
|
||||||
|
this.permanentsEntering.put(entry.getKey(), entry.getValue().copy());
|
||||||
|
}
|
||||||
|
for (Entry<UUID, Counters> entry : game.enterWithCounters.entrySet()) {
|
||||||
|
this.enterWithCounters.put(entry.getKey(), entry.getValue().copy());
|
||||||
|
}
|
||||||
|
|
||||||
|
this.state = game.state.copy();
|
||||||
|
// client-server part, not need on copy/simulations:
|
||||||
|
/*
|
||||||
|
this.savedStates = game.savedStates;
|
||||||
|
this.gameStates = game.gameStates;
|
||||||
|
this.gameStatesRollBack = game.gameStatesRollBack;
|
||||||
|
this.executingRollback = game.executingRollback;
|
||||||
|
this.turnToGoToForRollback = game.turnToGoToForRollback;
|
||||||
|
*/
|
||||||
|
|
||||||
|
this.startTime = game.startTime;
|
||||||
|
this.endTime = game.endTime;
|
||||||
|
this.startingPlayerId = game.startingPlayerId;
|
||||||
|
this.winnerId = game.winnerId;
|
||||||
this.gameStopped = game.gameStopped;
|
this.gameStopped = game.gameStopped;
|
||||||
|
|
||||||
|
this.range = game.range;
|
||||||
|
this.mulligan = game.mulligan.copy();
|
||||||
|
|
||||||
|
this.attackOption = game.attackOption;
|
||||||
|
this.gameOptions = game.gameOptions.copy();
|
||||||
|
this.startMessage = game.startMessage;
|
||||||
|
|
||||||
|
this.scopeRelevant = game.scopeRelevant;
|
||||||
|
this.saveGame = game.saveGame;
|
||||||
|
this.priorityTime = game.priorityTime;
|
||||||
|
this.startingLife = game.startingLife;
|
||||||
|
this.startingHandSize = game.startingHandSize;
|
||||||
|
//this.playerList = game.playerList; // auto-generated list, don't copy
|
||||||
|
|
||||||
|
// loop check code, no need to copy
|
||||||
|
/*
|
||||||
|
this.infiniteLoopCounter = game.infiniteLoopCounter;
|
||||||
|
this.lastNumberOfAbilitiesOnTheStack = game.lastNumberOfAbilitiesOnTheStack;
|
||||||
|
this.lastPlayersLifes = game.lastPlayersLifes;
|
||||||
|
this.stackObjectsCheck = game.stackObjectsCheck;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -605,7 +673,7 @@ public abstract class GameImpl implements Game {
|
||||||
// copied cards removes, but delayed triggered possible from it, see https://github.com/magefree/mage/issues/5437
|
// copied cards removes, but delayed triggered possible from it, see https://github.com/magefree/mage/issues/5437
|
||||||
// TODO: remove that workround after LKI rework, see GameState.copyCard
|
// TODO: remove that workround after LKI rework, see GameState.copyCard
|
||||||
if (card == null) {
|
if (card == null) {
|
||||||
card = (Card) state.getValue(GameState.COPIED_CARD_KEY + cardId.toString());
|
card = (Card) state.getValue(GameState.COPIED_CARD_KEY + cardId);
|
||||||
}
|
}
|
||||||
return card;
|
return card;
|
||||||
}
|
}
|
||||||
|
|
@ -845,7 +913,6 @@ public abstract class GameImpl implements Game {
|
||||||
public void start(UUID choosingPlayerId) {
|
public void start(UUID choosingPlayerId) {
|
||||||
startTime = new Date();
|
startTime = new Date();
|
||||||
if (state.getPlayers().values().iterator().hasNext()) {
|
if (state.getPlayers().values().iterator().hasNext()) {
|
||||||
scorePlayer = state.getPlayers().values().iterator().next();
|
|
||||||
init(choosingPlayerId);
|
init(choosingPlayerId);
|
||||||
play(startingPlayerId);
|
play(startingPlayerId);
|
||||||
}
|
}
|
||||||
|
|
@ -1039,7 +1106,7 @@ public abstract class GameImpl implements Game {
|
||||||
for (Ability ability : card.getAbilities(this)) {
|
for (Ability ability : card.getAbilities(this)) {
|
||||||
if (ability instanceof CompanionAbility) {
|
if (ability instanceof CompanionAbility) {
|
||||||
CompanionAbility companionAbility = (CompanionAbility) ability;
|
CompanionAbility companionAbility = (CompanionAbility) ability;
|
||||||
if (companionAbility.isLegal(new HashSet<>(player.getLibrary().getCards(this)), startingSize)) {
|
if (companionAbility.isLegal(new HashSet<>(player.getLibrary().getCards(this)), startingHandSize)) {
|
||||||
potentialCompanions.add(card);
|
potentialCompanions.add(card);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -1123,7 +1190,7 @@ public abstract class GameImpl implements Game {
|
||||||
for (UUID playerId : state.getPlayerList(startingPlayerId)) {
|
for (UUID playerId : state.getPlayerList(startingPlayerId)) {
|
||||||
Player player = getPlayer(playerId);
|
Player player = getPlayer(playerId);
|
||||||
if (!gameOptions.testMode || player.getLife() == 0) {
|
if (!gameOptions.testMode || player.getLife() == 0) {
|
||||||
player.initLife(this.getLife());
|
player.initLife(this.getStartingLife());
|
||||||
}
|
}
|
||||||
if (!gameOptions.testMode) {
|
if (!gameOptions.testMode) {
|
||||||
player.drawCards(startingHandSize, null, this);
|
player.drawCards(startingHandSize, null, this);
|
||||||
|
|
@ -3128,7 +3195,7 @@ public abstract class GameImpl implements Game {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getShortLivingLKI(UUID objectId, Zone zone) {
|
public boolean getShortLivingLKI(UUID objectId, Zone zone) {
|
||||||
Set<UUID> idSet = shortLivingLKI.get(zone);
|
Set<UUID> idSet = lkiShortLiving.get(zone);
|
||||||
if (idSet != null) {
|
if (idSet != null) {
|
||||||
return idSet.contains(objectId);
|
return idSet.contains(objectId);
|
||||||
}
|
}
|
||||||
|
|
@ -3153,7 +3220,7 @@ public abstract class GameImpl implements Game {
|
||||||
// remembers if a object was in a zone during the resolution of an effect
|
// remembers if a object was in a zone during the resolution of an effect
|
||||||
// e.g. Wrath destroys all and you the question is is the replacement effect to apply because the source was also moved by the same effect
|
// e.g. Wrath destroys all and you the question is is the replacement effect to apply because the source was also moved by the same effect
|
||||||
// because it happens all at the same time the replacement effect has still to be applied
|
// because it happens all at the same time the replacement effect has still to be applied
|
||||||
Set<UUID> idSet = shortLivingLKI.computeIfAbsent(zone, k -> new HashSet<>());
|
Set<UUID> idSet = lkiShortLiving.computeIfAbsent(zone, k -> new HashSet<>());
|
||||||
idSet.add(objectId);
|
idSet.add(objectId);
|
||||||
if (object instanceof Permanent) {
|
if (object instanceof Permanent) {
|
||||||
Map<Integer, MageObject> lkiExtendedMap = lkiExtended.computeIfAbsent(objectId, k -> new HashMap<>());
|
Map<Integer, MageObject> lkiExtendedMap = lkiExtended.computeIfAbsent(objectId, k -> new HashMap<>());
|
||||||
|
|
@ -3184,7 +3251,7 @@ public abstract class GameImpl implements Game {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resetShortLivingLKI() {
|
public void resetShortLivingLKI() {
|
||||||
shortLivingLKI.clear();
|
lkiShortLiving.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -3336,16 +3403,6 @@ public abstract class GameImpl implements Game {
|
||||||
playerQueryEventSource.informPlayer(player.getId(), message);
|
playerQueryEventSource.informPlayer(player.getId(), message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean getStateCheckRequired() {
|
|
||||||
return stateCheckRequired;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setStateCheckRequired() {
|
|
||||||
stateCheckRequired = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If true, only self scope replacement effects are applied
|
* If true, only self scope replacement effects are applied
|
||||||
*
|
*
|
||||||
|
|
@ -3420,8 +3477,8 @@ public abstract class GameImpl implements Game {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getLife() {
|
public int getStartingLife() {
|
||||||
return startLife;
|
return startingLife;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package mage.game;
|
package mage.game;
|
||||||
|
|
||||||
import mage.constants.PhaseStep;
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.util.Copyable;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
@ -12,7 +13,7 @@ import java.util.Set;
|
||||||
*
|
*
|
||||||
* @author ayratn
|
* @author ayratn
|
||||||
*/
|
*/
|
||||||
public class GameOptions implements Serializable {
|
public class GameOptions implements Serializable, Copyable<GameOptions> {
|
||||||
|
|
||||||
private static final GameOptions deinstance = new GameOptions();
|
private static final GameOptions deinstance = new GameOptions();
|
||||||
|
|
||||||
|
|
@ -50,10 +51,28 @@ public class GameOptions implements Serializable {
|
||||||
* Names of users banned from participating in the game
|
* Names of users banned from participating in the game
|
||||||
*/
|
*/
|
||||||
public Set<String> bannedUsers = Collections.emptySet();
|
public Set<String> bannedUsers = Collections.emptySet();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use planechase variant
|
* Use planechase variant
|
||||||
*/
|
*/
|
||||||
public boolean planeChase = false;
|
public boolean planeChase = false;
|
||||||
|
|
||||||
|
public GameOptions() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
private GameOptions(final GameOptions options) {
|
||||||
|
this.testMode = options.testMode;
|
||||||
|
this.stopOnTurn = options.stopOnTurn;
|
||||||
|
this.stopAtStep = options.stopAtStep;
|
||||||
|
this.skipInitShuffling = options.skipInitShuffling;
|
||||||
|
this.rollbackTurnsAllowed = options.rollbackTurnsAllowed;
|
||||||
|
this.bannedUsers.addAll(options.bannedUsers);
|
||||||
|
this.planeChase = options.planeChase;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GameOptions copy() {
|
||||||
|
return new GameOptions(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -440,7 +440,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
this.canLoseLife = true;
|
this.canLoseLife = true;
|
||||||
this.topCardRevealed = false;
|
this.topCardRevealed = false;
|
||||||
this.payManaMode = false;
|
this.payManaMode = false;
|
||||||
this.setLife(game.getLife(), game, null);
|
this.setLife(game.getStartingLife(), game, null);
|
||||||
this.setReachedNextTurnAfterLeaving(false);
|
this.setReachedNextTurnAfterLeaving(false);
|
||||||
|
|
||||||
this.clearCastSourceIdManaCosts();
|
this.clearCastSourceIdManaCosts();
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,6 @@
|
||||||
|
|
||||||
|
|
||||||
package mage.util;
|
package mage.util;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author BetaSteward_at_googlemail.com
|
* @author BetaSteward_at_googlemail.com
|
||||||
*/
|
*/
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue