/** * Copyright (c) 2012, Andy Janata * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted * provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of conditions * and the following disclaimer. * * 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 THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER 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. */ package net.socialgamer.cah.data; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import net.socialgamer.cah.Constants.GameOptionData; import net.socialgamer.cah.JsonWrapper; /** * Options for an individual game. * * @author Gavin Lambert (uecasm) */ public class GameOptions { // TODO move these out to pyx.properties public static final int MIN_SCORE_LIMIT = 4; public static final int DEFAULT_SCORE_LIMIT = 8; public static final int MAX_SCORE_LIMIT = 69; public static final int MIN_PLAYER_LIMIT = 3; public static final int DEFAULT_PLAYER_LIMIT = 10; public static final int MAX_PLAYER_LIMIT = 20; public static final int MIN_SPECTATOR_LIMIT = 0; public static final int DEFAULT_SPECTATOR_LIMIT = 10; public static final int MAX_SPECTATOR_LIMIT = 20; public static final int MIN_BLANK_CARD_LIMIT = 0; public static final int DEFAULT_BLANK_CARD_LIMIT = 0; public static final int MAX_BLANK_CARD_LIMIT = 30; // These are the default values new games get. public int blanksInDeck = DEFAULT_BLANK_CARD_LIMIT; public int playerLimit = DEFAULT_PLAYER_LIMIT; public int spectatorLimit = DEFAULT_SPECTATOR_LIMIT; public int scoreGoal = DEFAULT_SCORE_LIMIT; public final Set<Integer> cardSetIds = new HashSet<Integer>(); public String password = ""; public String timerMultiplier = "1.0x"; /** * Update the options in-place (so that the Game doesn't need more locks). * * @param newOptions * The new options to use. */ public void update(final GameOptions newOptions) { this.scoreGoal = newOptions.scoreGoal; this.playerLimit = newOptions.playerLimit; this.spectatorLimit = newOptions.spectatorLimit; synchronized (this.cardSetIds) { this.cardSetIds.clear(); this.cardSetIds.addAll(newOptions.cardSetIds); } this.blanksInDeck = newOptions.blanksInDeck; this.password = newOptions.password; this.timerMultiplier = newOptions.timerMultiplier; } /** * Get the options in a form that can be sent to clients. * * @param includePassword * Include the actual password with the information. This should only be * sent to people in the game. * @return This game's general information: ID, host, state, player list, etc. */ public Map<GameOptionData, Object> serialize(final boolean includePassword) { final Map<GameOptionData, Object> info = new HashMap<GameOptionData, Object>(); info.put(GameOptionData.CARD_SETS, cardSetIds); info.put(GameOptionData.BLANKS_LIMIT, blanksInDeck); info.put(GameOptionData.PLAYER_LIMIT, playerLimit); info.put(GameOptionData.SPECTATOR_LIMIT, spectatorLimit); info.put(GameOptionData.SCORE_LIMIT, scoreGoal); info.put(GameOptionData.TIMER_MULTIPLIER, timerMultiplier); if (includePassword) { info.put(GameOptionData.PASSWORD, password); } return info; } public static GameOptions deserialize(final String text) { final GameOptions options = new GameOptions(); if (text == null || text.isEmpty()) { return options; } final JsonWrapper json = new JsonWrapper(text); final String[] cardSetsParsed = json.getString(GameOptionData.CARD_SETS, "").split(","); for (final String cardSetId : cardSetsParsed) { if (!cardSetId.isEmpty()) { options.cardSetIds.add(Integer.parseInt(cardSetId)); } } options.blanksInDeck = Math.max(MIN_BLANK_CARD_LIMIT, Math.min(MAX_BLANK_CARD_LIMIT, json.getInteger(GameOptionData.BLANKS_LIMIT, options.blanksInDeck))); options.playerLimit = Math.max(MIN_PLAYER_LIMIT, Math.min(MAX_PLAYER_LIMIT, json.getInteger(GameOptionData.PLAYER_LIMIT, options.playerLimit))); options.spectatorLimit = Math.max(MIN_SPECTATOR_LIMIT, Math.min(MAX_SPECTATOR_LIMIT, json.getInteger(GameOptionData.SPECTATOR_LIMIT, options.spectatorLimit))); options.scoreGoal = Math.max(MIN_SCORE_LIMIT, Math.min(MAX_SCORE_LIMIT, json.getInteger(GameOptionData.SCORE_LIMIT, options.scoreGoal))); options.timerMultiplier = json.getString(GameOptionData.TIMER_MULTIPLIER, options.timerMultiplier); options.password = json.getString(GameOptionData.PASSWORD, options.password); return options; } /** * @return Selected card set IDs which are local to PYX, for querying the database. */ public Set<Integer> getPyxCardSetIds() { final Set<Integer> pyxCardSetIds = new HashSet<Integer>(); for (final Integer cardSetId : cardSetIds) { if (cardSetId > 0) { pyxCardSetIds.add(cardSetId); } } return pyxCardSetIds; } }