This commit is contained in:
igoudt 2017-06-06 09:32:52 +02:00
commit 352637d411
62 changed files with 2785 additions and 58565 deletions

View file

@ -48,6 +48,7 @@ public class Deck implements Serializable {
private DeckCardLayout cardsLayout;
private DeckCardLayout sideboardLayout;
private long deckHashCode = 0;
private long deckCompleteHashCode = 0;
public static Deck load(DeckCardLists deckCardLists) throws GameException {
return Deck.load(deckCardLists, false);
@ -56,10 +57,10 @@ public class Deck implements Serializable {
public static Deck load(DeckCardLists deckCardLists, boolean ignoreErrors) throws GameException {
return Deck.load(deckCardLists, ignoreErrors, true);
}
public static Deck append(Deck deckToAppend, Deck currentDeck) throws GameException {
List<String> deckCardNames = new ArrayList<>();
for (Card card : deckToAppend.getCards()) {
if (card != null) {
currentDeck.cards.add(card);
@ -72,7 +73,7 @@ public class Deck implements Serializable {
currentDeck.sideboard.add(card);
deckCardNames.add(card.getName());
}
}
}
Collections.sort(deckCardNames);
Collections.sort(sbCardNames);
String deckString = deckCardNames.toString() + sbCardNames.toString();
@ -90,11 +91,13 @@ public class Deck implements Serializable {
for (DeckCardInfo deckCardInfo : deckCardLists.getCards()) {
Card card = createCard(deckCardInfo, mockCards);
if (card != null) {
if (totalCards < 1000) {
deck.cards.add(card);
deckCardNames.add(card.getName());
totalCards++;
if (totalCards > 1000) {
break;
}
deck.cards.add(card);
deckCardNames.add(card.getName());
totalCards++;
} else if (!ignoreErrors) {
throw createCardNotFoundGameException(deckCardInfo, deckCardLists.getName());
}
@ -103,11 +106,12 @@ public class Deck implements Serializable {
for (DeckCardInfo deckCardInfo : deckCardLists.getSideboard()) {
Card card = createCard(deckCardInfo, mockCards);
if (card != null) {
if (totalCards < 1000) {
deck.sideboard.add(card);
sbCardNames.add(card.getName());
totalCards++;
if (totalCards > 1000) {
break;
}
deck.sideboard.add(card);
sbCardNames.add(card.getName());
totalCards++;
} else if (!ignoreErrors) {
throw createCardNotFoundGameException(deckCardInfo, deckCardLists.getName());
}
@ -116,6 +120,15 @@ public class Deck implements Serializable {
Collections.sort(sbCardNames);
String deckString = deckCardNames.toString() + sbCardNames.toString();
deck.setDeckHashCode(DeckUtil.fixedHash(deckString));
if (sbCardNames.isEmpty()) {
deck.setDeckCompleteHashCode(deck.getDeckHashCode());
} else {
List<String> deckAllCardNames = new ArrayList<>();
deckAllCardNames.addAll(deckCardNames);
deckAllCardNames.addAll(sbCardNames);
Collections.sort(deckAllCardNames);
deck.setDeckCompleteHashCode(DeckUtil.fixedHash(deckAllCardNames.toString()));
}
return deck;
}
@ -206,6 +219,14 @@ public class Deck implements Serializable {
this.deckHashCode = deckHashCode;
}
public long getDeckCompleteHashCode() {
return deckCompleteHashCode;
}
public void setDeckCompleteHashCode(long deckHashCode) {
this.deckCompleteHashCode = deckHashCode;
}
public void clearLayouts() {
this.cardsLayout = null;
this.sideboardLayout = null;

View file

@ -28,7 +28,7 @@ public enum ExpansionRepository {
private static final String JDBC_URL = "jdbc:h2:file:./db/cards.h2;AUTO_SERVER=TRUE";
private static final String VERSION_ENTITY_NAME = "expansion";
private static final long EXPANSION_DB_VERSION = 5;
private static final long EXPANSION_CONTENT_VERSION = 12;
private static final long EXPANSION_CONTENT_VERSION = 13;
private Dao<ExpansionInfo, Object> expansionDao;

View file

@ -177,6 +177,8 @@ public abstract class GameImpl implements Game, Serializable {
protected PlayerList playerList;
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 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<>();
@ -1289,7 +1291,6 @@ public abstract class GameImpl implements Game, Serializable {
}
if (allPassed()) {
if (!state.getStack().isEmpty()) {
checkInfiniteLoop();
//20091005 - 115.4
resolve();
applyEffects();
@ -1298,7 +1299,6 @@ public abstract class GameImpl implements Game, Serializable {
resetShortLivingLKI();
break;
} else {
infiniteLoopCounter = 0;
resetLKI();
return;
}
@ -1346,6 +1346,7 @@ public abstract class GameImpl implements Game, Serializable {
if (top != null) {
state.getStack().remove(top); // seems partly redundant because move card from stack to grave is already done and the stack removed
rememberLKI(top.getSourceId(), Zone.STACK, top);
checkInfiniteLoop(top.getSourceId());
if (!getTurn().isEndTurnRequested()) {
while (state.hasSimultaneousEvents()) {
state.handleSimultaneousEvent(this);
@ -1357,40 +1358,44 @@ public abstract class GameImpl implements Game, Serializable {
/**
* This checks if the stack gets filled iterated, without ever getting empty
* If the defined number of iterations is reached, the players in range of
* the stackObject get asked to confirm a draw. If they do, all confirming
* players get set to a draw.
* If the defined number of iterations with not more than 4 different
* sourceIds for the removed stack Objects is reached, the players in range
* of the stackObject get asked to confirm a draw. If they do, all
* confirming players get set to a draw.
*
* Possible to improve: check that always the same set of stackObjects are
* again aand again on the stack
* @param removedStackObjectSourceId
*/
protected void checkInfiniteLoop() {
if (getStack().size() < 4) { // to prevent that this also pops up, if e.g. 20 triggers resolve at once
protected void checkInfiniteLoop(UUID removedStackObjectSourceId) {
if (stackObjectsCheck.contains(removedStackObjectSourceId)
&& getStack().size() >= lastNumberOfAbilitiesOnTheStack) {
infiniteLoopCounter++;
if (infiniteLoopCounter > 15) {
StackObject stackObject = getStack().getFirst();
if (stackObject != null) {
Player controller = getPlayer(stackObject.getControllerId());
if (controller != null) {
for (UUID playerId : getState().getPlayersInRange(controller.getId(), this)) {
Player player = getPlayer(playerId);
if (!player.chooseUse(Outcome.Detriment, "Draw game because of infinite looping?", null, this)) {
informPlayers(controller.getLogName() + " has NOT confirmed that the game is a draw because of infinite looping.");
infiniteLoopCounter = 0;
return;
}
informPlayers(controller.getLogName() + " has confirmed that the game is a draw because of infinite looping.");
Player controller = getPlayer(getControllerId(removedStackObjectSourceId));
if (controller != null) {
for (UUID playerId : getState().getPlayersInRange(controller.getId(), this)) {
Player player = getPlayer(playerId);
if (!player.chooseUse(Outcome.Detriment, "Draw game because of infinite looping?", null, this)) {
informPlayers(controller.getLogName() + " has NOT confirmed that the game is a draw because of infinite looping.");
infiniteLoopCounter = 0;
return;
}
for (UUID playerId : getState().getPlayersInRange(controller.getId(), this)) {
Player player = getPlayer(playerId);
if (player != null) {
player.drew(this);
}
informPlayers(controller.getLogName() + " has confirmed that the game is a draw because of infinite looping.");
}
for (UUID playerId : getState().getPlayersInRange(controller.getId(), this)) {
Player player = getPlayer(playerId);
if (player != null) {
player.drew(this);
}
}
}
}
} else {
stackObjectsCheck.add(removedStackObjectSourceId);
if (stackObjectsCheck.size() > 4) {
stackObjectsCheck.removeFirst();
}
}
lastNumberOfAbilitiesOnTheStack = getStack().size();
}
protected boolean allPassed() {
@ -2618,6 +2623,8 @@ public abstract class GameImpl implements Game, Serializable {
public void resetLKI() {
lki.clear();
lkiExtended.clear();
infiniteLoopCounter = 0;
stackObjectsCheck.clear();
}
@Override

View file

@ -1,8 +1,11 @@
package mage.game;
import java.io.Serializable;
import mage.constants.PhaseStep;
import java.io.Serializable;
import java.util.Collections;
import java.util.Set;
/**
* Game options for Mage game. Mainly used in tests to configure
* {@link GameImpl} with specific params.
@ -42,4 +45,10 @@ public class GameOptions implements Serializable {
* If true, players can rollback turn if all players agree
*/
public boolean rollbackTurnsAllowed = true;
/**
* Names of users banned from participating in the game
*/
public Set<String> bannedUsers = Collections.emptySet();
}

View file

@ -1,16 +1,16 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
@ -20,26 +20,24 @@
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.game.match;
import mage.cards.decks.Deck;
import mage.game.Game;
import mage.game.GameException;
import mage.game.events.Listener;
import mage.game.events.TableEvent;
import mage.players.Player;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import mage.cards.decks.Deck;
import mage.game.Game;
import mage.game.GameException;
import mage.game.GameInfo;
import mage.game.events.Listener;
import mage.game.events.TableEvent;
import mage.game.result.ResultProtos.MatchProto;
import mage.players.Player;
/**
*
@ -50,52 +48,79 @@ public interface Match {
int SIDEBOARD_TIME = 180;
UUID getId();
String getName();
boolean hasEnded();
boolean hasStarted();
boolean checkIfMatchEnds();
List<MatchPlayer> getPlayers();
MatchPlayer getPlayer(UUID playerId);
void addPlayer(Player player, Deck deck);
boolean quitMatch(UUID playerId);
void submitDeck(UUID playerId, Deck deck);
void updateDeck(UUID playerId, Deck deck);
boolean updateDeck(UUID playerId, Deck deck);
void startMatch();
void startGame() throws GameException;
void sideboard();
void endGame();
Game getGame();
List<Game> getGames();
int getWinsNeeded();
int getFreeMulligans();
void addDraw();
int getDraws();
int getNumGames();
void addGame();
boolean isDoneSideboarding();
UUID getChooser();
MatchOptions getOptions();
void addTableEventListener(Listener<TableEvent> listener);
void fireSideboardEvent(UUID playerId, Deck deck);
// match times
Date getStartTime();
Date getEndTime();
/**
* Can the games of the match be replayed
*
*
* @return
*/
boolean isReplayAvailable();
void setReplayAvailable(boolean replayAvailable);
/**
* Free resources no longer needed if match ended and only exists for
* information purpose.
*
*
* @param isSaveGameActivated
* @param isTournament
*/
@ -111,6 +136,7 @@ public interface Match {
List<GameInfo> getGamesInfo();
void setTableId(UUID tableId);
void setTournamentRound(int round);
MatchProto toProto();

View file

@ -409,11 +409,18 @@ public abstract class MatchImpl implements Match {
}
@Override
public void updateDeck(UUID playerId, Deck deck) {
public boolean updateDeck(UUID playerId, Deck deck) {
boolean validDeck = true;
MatchPlayer player = getPlayer(playerId);
if (player != null) {
// Check if the cards included in the deck are the same as in the original deck
validDeck = (player.getDeck().getDeckCompleteHashCode() == deck.getDeckCompleteHashCode());
if (validDeck == false) {
deck.getCards().clear(); // Clear the deck so the player cheating looses the game
}
player.updateDeck(deck);
}
return validDeck;
}
protected String createGameStartMessage() {
@ -502,10 +509,10 @@ public abstract class MatchImpl implements Match {
.setMatchOptions(this.getOptions().toProto())
.setEndTimeMs((this.getEndTime() != null ? this.getEndTime() : new Date()).getTime());
for (MatchPlayer matchPlayer : this.getPlayers()) {
MatchQuitStatus status = !matchPlayer.hasQuit() ? MatchQuitStatus.NO_MATCH_QUIT :
matchPlayer.getPlayer().hasTimerTimeout() ? MatchQuitStatus.TIMER_TIMEOUT :
matchPlayer.getPlayer().hasIdleTimeout() ? MatchQuitStatus.IDLE_TIMEOUT :
MatchQuitStatus.QUIT;
MatchQuitStatus status = !matchPlayer.hasQuit() ? MatchQuitStatus.NO_MATCH_QUIT
: matchPlayer.getPlayer().hasTimerTimeout() ? MatchQuitStatus.TIMER_TIMEOUT
: matchPlayer.getPlayer().hasIdleTimeout() ? MatchQuitStatus.IDLE_TIMEOUT
: MatchQuitStatus.QUIT;
builder.addPlayersBuilder()
.setName(matchPlayer.getName())
.setHuman(matchPlayer.getPlayer().isHuman())

View file

@ -98,6 +98,7 @@ public class MatchPlayer implements Serializable {
if (this.deck != null) {
// preserver deck name, important for Tiny Leaders format
deck.setName(this.getDeck().getName());
// preserve the original deck hash code before sideboarding to give no information if cards were swapped
deck.setDeckHashCode(this.getDeck().getDeckHashCode());
}
this.deck = deck;

View file

@ -42,7 +42,7 @@ public class BeastToken extends Token {
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("C14", "LRW", "M15", "M14", "DDL", "M13", "M12", "DD3GVL", "NPH", "M11", "M10", "EVE", "MM3"));
tokenImageSets.addAll(Arrays.asList("C14", "LRW", "M15", "M14", "DDL", "M13", "M12", "DD3GVL", "NPH", "M11", "M10", "EVE", "MM3", "CMA", "E01"));
}
public BeastToken() {

View file

@ -42,7 +42,7 @@ public class BeastToken2 extends Token {
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("ZEN", "C14", "DDD", "C15", "DD3GVL", "MM3"));
tokenImageSets.addAll(Arrays.asList("ZEN", "C14", "DDD", "C15", "DD3GVL", "MM3", "CMA", "E01"));
}
public BeastToken2() {

View file

@ -43,7 +43,7 @@ public class DragonToken2 extends Token {
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("WWK", "10E", "BFZ", "C15", "CN2"));
tokenImageSets.addAll(Arrays.asList("WWK", "10E", "BFZ", "C15", "CN2", "CMA"));
}
public DragonToken2() {

View file

@ -43,7 +43,7 @@ public class ElephantToken extends Token {
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("C14", "CNS", "DDD", "MM2", "WWK", "OGW", "C15", "DD3GVL", "MM3"));
tokenImageSets.addAll(Arrays.asList("C14", "CNS", "DDD", "MM2", "WWK", "OGW", "C15", "DD3GVL", "MM3", "CMA"));
}
public ElephantToken() {

View file

@ -27,6 +27,9 @@
*/
package mage.game.permanent.token;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import mage.constants.CardType;
import mage.MageInt;
import mage.ObjectColor;
@ -38,9 +41,24 @@ import mage.abilities.mana.GreenManaAbility;
*/
public class FreyaliseLlanowarsFuryToken extends Token {
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("C14", "CMA"));
}
public FreyaliseLlanowarsFuryToken() {
this(null, 0);
}
public FreyaliseLlanowarsFuryToken(String setCode) {
this(setCode, 0);
}
public FreyaliseLlanowarsFuryToken(String setCode, int tokenType) {
super("Elf Druid", "1/1 green Elf Druid creature token with \"{T}: Add {G} to your mana pool.\"");
this.setOriginalExpansionSetCode("C14");
availableImageSetCodes = tokenImageSets;
setOriginalExpansionSetCode(setCode);
this.cardType.add(CardType.CREATURE);
this.color = ObjectColor.GREEN;
this.subtype.add("Elf");

View file

@ -16,7 +16,7 @@ public class KnightToken extends Token {
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("ORI", "RTR", "C15"));
tokenImageSets.addAll(Arrays.asList("ORI", "RTR", "C15", "CMA"));
}
public KnightToken() {

View file

@ -27,6 +27,9 @@
*/
package mage.game.permanent.token;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import mage.constants.CardType;
import mage.MageInt;
import mage.abilities.keyword.FlyingAbility;
@ -37,8 +40,24 @@ import mage.abilities.keyword.FlyingAbility;
*/
public class LeafdrakeRoostDrakeToken extends Token {
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("C13", "CMA"));
}
public LeafdrakeRoostDrakeToken() {
this(null, 0);
}
public LeafdrakeRoostDrakeToken(String setCode) {
this(setCode, 0);
}
public LeafdrakeRoostDrakeToken(String setCode, int tokenType) {
super("Drake", "2/2 green and blue Drake creature token with flying");
availableImageSetCodes = tokenImageSets;
setOriginalExpansionSetCode(setCode);
cardType.add(CardType.CREATURE);
color.setGreen(true);
color.setBlue(true);

View file

@ -44,7 +44,7 @@ public class SaprolingToken extends Token {
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("10E", "ALA", "DDE", "DDH", "DDJ", "M12", "M13", "M14", "MM2", "MMA", "RTR", "C15", "MM3", "C16"));
tokenImageSets.addAll(Arrays.asList("10E", "ALA", "DDE", "DDH", "DDJ", "M12", "M13", "M14", "MM2", "MMA", "RTR", "C15", "MM3", "C16", "CMA"));
}
public SaprolingToken() {

View file

@ -44,7 +44,7 @@ public class SoldierToken extends Token {
static {
tokenImageSets.addAll(Arrays.asList("10E", "M15", "C14", "ORI", "ALA", "DDF", "THS", "M12", "M13", "MM2", "MMA", "RTR",
"SOM", "DDO", "M10", "ORI", "EMN", "EMA", "CN2", "C16", "MM3"));
"SOM", "DDO", "M10", "ORI", "EMN", "EMA", "CN2", "C16", "MM3", "E01"));
}
public SoldierToken() {

View file

@ -42,7 +42,7 @@ public class SpiritWhiteToken extends Token {
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("AVR", "C14", "CNS", "DDC", "DDK", "FRF", "ISD", "KTK", "M15", "MM2", "SHM", "SOI", "EMA", "C16", "MM3"));
tokenImageSets.addAll(Arrays.asList("AVR", "C14", "CNS", "DDC", "DDK", "FRF", "ISD", "KTK", "M15", "MM2", "SHM", "SOI", "EMA", "C16", "MM3", "CMA", "E01"));
}
public SpiritWhiteToken() {

View file

@ -27,6 +27,9 @@
*/
package mage.game.permanent.token;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import mage.constants.CardType;
import mage.MageInt;
import mage.ObjectColor;
@ -37,13 +40,27 @@ import mage.ObjectColor;
*/
public class TitaniaProtectorOfArgothElementalToken extends Token {
final static private List<String> tokenImageSets = new ArrayList<>();
static {
tokenImageSets.addAll(Arrays.asList("C14", "CMA"));
}
public TitaniaProtectorOfArgothElementalToken() {
this(null, 0);
}
public TitaniaProtectorOfArgothElementalToken(String setCode) {
this(setCode, 0);
}
public TitaniaProtectorOfArgothElementalToken(String setCode, int tokenType) {
super("Elemental", "5/3 green Elemental creature token");
this.setOriginalExpansionSetCode("C14");
availableImageSetCodes = tokenImageSets;
this.setOriginalExpansionSetCode(setCode);
this.cardType.add(CardType.CREATURE);
this.color = ObjectColor.GREEN;
this.subtype.add("Elemental");
this.power = new MageInt(5);
this.toughness = new MageInt(3);
}

View file

@ -45,7 +45,7 @@ public class ZombieToken extends Token {
static {
tokenImageSets.addAll(Arrays.asList("10E", "M10", "M11", "M12", "M13", "M14", "M15", "MBS", "ALA", "ISD", "C14", "C15", "C16", "CNS",
"MMA", "BNG", "KTK", "DTK", "ORI", "OGW", "SOI", "EMN", "EMA", "MM3", "AKH"));
"MMA", "BNG", "KTK", "DTK", "ORI", "OGW", "SOI", "EMN", "EMA", "MM3", "AKH", "CMA", "E01"));
}
public ZombieToken() {

View file

@ -27,6 +27,10 @@
*/
package mage.game.tournament;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import mage.cards.ExpansionSet;
import mage.cards.decks.Deck;
import mage.game.draft.Draft;
@ -37,11 +41,6 @@ import mage.game.result.ResultProtos.TourneyProto;
import mage.players.Player;
import mage.players.PlayerType;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.UUID;
/**
*
* @author BetaSteward_at_googlemail.com
@ -76,7 +75,7 @@ public interface Tournament {
void submitDeck(UUID playerId, Deck deck);
void updateDeck(UUID playerId, Deck deck);
boolean updateDeck(UUID playerId, Deck deck);
void autoSubmit(UUID playerId, Deck deck);

View file

@ -27,6 +27,8 @@
*/
package mage.game.tournament;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import mage.cards.ExpansionSet;
import mage.cards.decks.Deck;
import mage.constants.TournamentPlayerState;
@ -37,14 +39,16 @@ import mage.game.events.TableEvent.EventType;
import mage.game.match.Match;
import mage.game.match.MatchPlayer;
import mage.game.result.ResultProtos.*;
import mage.game.result.ResultProtos.MatchPlayerProto;
import mage.game.result.ResultProtos.MatchProto;
import mage.game.result.ResultProtos.MatchQuitStatus;
import mage.game.result.ResultProtos.TourneyProto;
import mage.game.result.ResultProtos.TourneyRoundProto;
import mage.players.Player;
import mage.players.PlayerType;
import mage.util.RandomUtil;
import org.apache.log4j.Logger;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
/**
*
* @author BetaSteward_at_googlemail.com
@ -168,10 +172,11 @@ public abstract class TournamentImpl implements Tournament {
}
@Override
public void updateDeck(UUID playerId, Deck deck) {
public boolean updateDeck(UUID playerId, Deck deck) {
if (players.containsKey(playerId)) {
players.get(playerId).updateDeck(deck);
return players.get(playerId).updateDeck(deck);
}
return false;
}
protected Round createRoundRandom() {
@ -246,12 +251,12 @@ public abstract class TournamentImpl implements Tournament {
}
updateResults();
}
protected void playMultiplayerRound(MultiplayerRound round) {
playMultiPlayerMatch(round);
updateResults(); // show points from byes
}
}
protected List<TournamentPlayer> getActivePlayers() {
List<TournamentPlayer> activePlayers = new ArrayList<>();
@ -442,7 +447,7 @@ public abstract class TournamentImpl implements Tournament {
options.getMatchOptions().getPlayerTypes().add(pair.getPlayer2().getPlayerType());
tableEventSource.fireTableEvent(EventType.START_MATCH, pair, options.getMatchOptions());
}
public void playMultiPlayerMatch(MultiplayerRound round) {
tableEventSource.fireTableEvent(EventType.START_MULTIPLAYER_MATCH, round, options.getMatchOptions());
}
@ -588,10 +593,10 @@ public abstract class TournamentImpl implements Tournament {
private MatchPlayerProto matchToProto(Match match, TournamentPlayer player) {
MatchPlayer matchPlayer = match.getPlayer(player.getPlayer().getId());
MatchQuitStatus quit = !matchPlayer.hasQuit() ? MatchQuitStatus.NO_MATCH_QUIT :
matchPlayer.getPlayer().hasIdleTimeout() ? MatchQuitStatus.IDLE_TIMEOUT :
matchPlayer.getPlayer().hasTimerTimeout() ? MatchQuitStatus.TIMER_TIMEOUT :
MatchQuitStatus.QUIT;
MatchQuitStatus quit = !matchPlayer.hasQuit() ? MatchQuitStatus.NO_MATCH_QUIT
: matchPlayer.getPlayer().hasIdleTimeout() ? MatchQuitStatus.IDLE_TIMEOUT
: matchPlayer.getPlayer().hasTimerTimeout() ? MatchQuitStatus.TIMER_TIMEOUT
: MatchQuitStatus.QUIT;
return MatchPlayerProto.newBuilder()
.setName(player.getPlayer().getName())
.setHuman(player.getPlayer().isHuman())

View file

@ -1,16 +1,16 @@
/*
* Copyright 2011 BetaSteward_at_googlemail.com. All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
@ -20,14 +20,14 @@
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.game.tournament;
import java.util.Set;
import mage.cards.decks.Deck;
import mage.constants.TournamentPlayerState;
import mage.game.result.ResultProtos.TourneyPlayerProto;
@ -36,8 +36,6 @@ import mage.players.Player;
import mage.players.PlayerType;
import mage.util.TournamentUtil;
import java.util.Set;
/**
*
* @author BetaSteward_at_googlemail.com
@ -117,8 +115,14 @@ public class TournamentPlayer {
this.setState(TournamentPlayerState.WAITING);
}
public void updateDeck(Deck deck) {
public boolean updateDeck(Deck deck) {
// Check if the cards included in the deck are the same as in the original deck
boolean validDeck = (getDeck().getDeckCompleteHashCode() == deck.getDeckCompleteHashCode());
if (validDeck == false) {
deck.getCards().clear(); // Clear the deck so the player cheating looses the game
}
this.deck = deck;
return validDeck;
}
public Deck generateDeck() {
@ -137,15 +141,13 @@ public class TournamentPlayer {
deck.getCards().addAll(TournamentUtil.getLands("Swamp", landsPerType, landSets));
deck.getCards().addAll(TournamentUtil.getLands("Forest", landsPerType, landSets));
deck.getCards().addAll(TournamentUtil.getLands("Island", landsPerType, landSets));
this.doneConstructing = true;
this.setState(TournamentPlayerState.WAITING);
return deck;
}
public boolean isDoneConstructing() {
return this.doneConstructing;
}
@ -201,7 +203,7 @@ public class TournamentPlayer {
/**
* Free resources no longer needed if tournament has ended
*
*
*/
public void CleanUpOnTournamentEnd() {
this.deck = null;
@ -216,7 +218,7 @@ public class TournamentPlayer {
this.setState(TournamentPlayerState.FINISHED);
}
}
public boolean isInTournament() {
return !(this.getState() == TournamentPlayerState.CANCELED)
&& !(this.getState() == TournamentPlayerState.ELIMINATED)
@ -239,4 +241,3 @@ public class TournamentPlayer {
.build();
}
}

View file

@ -0,0 +1,89 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.watchers.common;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import mage.constants.WatcherScope;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.watchers.Watcher;
import mage.players.PlayerList;
/**
* @author spjspj
*/
public class PlayersAttackedLastTurnWatcher extends Watcher {
// Store how many players each player attacked in their last turn
private final Map<UUID, PlayerList> playersAttackedInLastTurn = new HashMap<>();
public PlayersAttackedLastTurnWatcher() {
super(PlayersAttackedLastTurnWatcher.class.getSimpleName(), WatcherScope.GAME);
}
public PlayersAttackedLastTurnWatcher(final PlayersAttackedLastTurnWatcher watcher) {
super(watcher);
for (Map.Entry<UUID, PlayerList> entry : watcher.playersAttackedInLastTurn.entrySet()) {
this.playersAttackedInLastTurn.put(entry.getKey(), entry.getValue());
}
}
@Override
public PlayersAttackedLastTurnWatcher copy() {
return new PlayersAttackedLastTurnWatcher(this);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.BEGINNING_PHASE_PRE) {
playersAttackedInLastTurn.remove(event.getPlayerId());
}
if (event.getType() == GameEvent.EventType.ATTACKER_DECLARED) {
PlayerList playersAttacked = playersAttackedInLastTurn.get(event.getPlayerId());
if (playersAttacked == null) {
playersAttacked = new PlayerList();
}
UUID defender = game.getCombat().getDefendingPlayerId(event.getSourceId(), game);
if (defender != null) {
playersAttacked.add(defender);
}
playersAttackedInLastTurn.put(event.getPlayerId(), playersAttacked);
}
}
public boolean attackedLastTurn(UUID playerId, UUID otherPlayerId) {
if (playersAttackedInLastTurn.get(playerId) != null) {
return playersAttackedInLastTurn.get(playerId).contains(otherPlayerId);
}
return false;
}
}