Add quest classes to mobile game

This commit is contained in:
drdev
2014-04-06 20:23:03 +00:00
parent 2df3525918
commit 8de3157cbe
58 changed files with 7319 additions and 140 deletions

49
.gitattributes vendored
View File

@@ -16224,6 +16224,54 @@ forge-m-base/src/forge/player/HumanPlaySpellAbility.java -text
forge-m-base/src/forge/player/LobbyPlayerHuman.java -text forge-m-base/src/forge/player/LobbyPlayerHuman.java -text
forge-m-base/src/forge/player/PlayerControllerHuman.java -text forge-m-base/src/forge/player/PlayerControllerHuman.java -text
forge-m-base/src/forge/player/TargetSelection.java -text forge-m-base/src/forge/player/TargetSelection.java -text
forge-m-base/src/forge/quest/BoosterUtils.java -text
forge-m-base/src/forge/quest/IQuestRewardCard.java -text
forge-m-base/src/forge/quest/QuestController.java -text
forge-m-base/src/forge/quest/QuestDeckMap.java -text
forge-m-base/src/forge/quest/QuestEvent.java -text
forge-m-base/src/forge/quest/QuestEventChallenge.java -text
forge-m-base/src/forge/quest/QuestEventDifficulty.java -text
forge-m-base/src/forge/quest/QuestEventDuel.java -text
forge-m-base/src/forge/quest/QuestEventDuelManager.java -text
forge-m-base/src/forge/quest/QuestMode.java -text
forge-m-base/src/forge/quest/QuestRewardCard.java -text
forge-m-base/src/forge/quest/QuestRewardCardChooser.java -text
forge-m-base/src/forge/quest/QuestRewardCardDuplicate.java -text
forge-m-base/src/forge/quest/QuestRewardCardFiltered.java -text
forge-m-base/src/forge/quest/QuestUtil.java -text
forge-m-base/src/forge/quest/QuestUtilCards.java -text
forge-m-base/src/forge/quest/QuestUtilUnlockSets.java -text
forge-m-base/src/forge/quest/QuestWorld.java -text
forge-m-base/src/forge/quest/SellRules.java -text
forge-m-base/src/forge/quest/StartingPoolPreferences.java -text
forge-m-base/src/forge/quest/StartingPoolType.java -text
forge-m-base/src/forge/quest/bazaar/IQuestBazaarItem.java -text
forge-m-base/src/forge/quest/bazaar/QuestBazaarManager.java -text
forge-m-base/src/forge/quest/bazaar/QuestItemBasic.java -text
forge-m-base/src/forge/quest/bazaar/QuestItemCharmOfVigor.java -text
forge-m-base/src/forge/quest/bazaar/QuestItemElixir.java -text
forge-m-base/src/forge/quest/bazaar/QuestItemEstates.java -text
forge-m-base/src/forge/quest/bazaar/QuestItemPoundFlesh.java -text
forge-m-base/src/forge/quest/bazaar/QuestItemType.java -text
forge-m-base/src/forge/quest/bazaar/QuestItemZeppelin.java -text
forge-m-base/src/forge/quest/bazaar/QuestPetController.java -text
forge-m-base/src/forge/quest/bazaar/QuestPetStats.java -text
forge-m-base/src/forge/quest/bazaar/QuestPetStorage.java -text
forge-m-base/src/forge/quest/bazaar/QuestStallDefinition.java -text
forge-m-base/src/forge/quest/bazaar/package-info.java -text
forge-m-base/src/forge/quest/data/GameFormatQuest.java -text
forge-m-base/src/forge/quest/data/QuestAchievements.java -text
forge-m-base/src/forge/quest/data/QuestAssets.java -text
forge-m-base/src/forge/quest/data/QuestData.java -text
forge-m-base/src/forge/quest/data/QuestItemCondition.java -text
forge-m-base/src/forge/quest/data/QuestPreferences.java -text
forge-m-base/src/forge/quest/data/package-info.java -text
forge-m-base/src/forge/quest/io/QuestChallengeReader.java -text
forge-m-base/src/forge/quest/io/QuestDataIO.java -text
forge-m-base/src/forge/quest/io/QuestDuelReader.java -text
forge-m-base/src/forge/quest/io/ReadPriceList.java -text
forge-m-base/src/forge/quest/io/package-info.java -text
forge-m-base/src/forge/quest/package-info.java -text
forge-m-base/src/forge/screens/FScreen.java -text forge-m-base/src/forge/screens/FScreen.java -text
forge-m-base/src/forge/screens/LaunchScreen.java -text forge-m-base/src/forge/screens/LaunchScreen.java -text
forge-m-base/src/forge/screens/SplashScreen.java -text forge-m-base/src/forge/screens/SplashScreen.java -text
@@ -16322,6 +16370,7 @@ forge-m-base/src/forge/utils/PhysicsObject.java -text
forge-m-base/src/forge/utils/Preferences.java -text forge-m-base/src/forge/utils/Preferences.java -text
forge-m-base/src/forge/utils/PreferencesStore.java -text forge-m-base/src/forge/utils/PreferencesStore.java -text
forge-m-base/src/forge/utils/Utils.java -text forge-m-base/src/forge/utils/Utils.java -text
forge-m-base/src/forge/utils/XmlUtil.java -text
forge-m-desktop/.classpath -text forge-m-desktop/.classpath -text
forge-m-desktop/.project -text forge-m-desktop/.project -text
forge-m-desktop/.settings/org.eclipse.jdt.core.prefs -text forge-m-desktop/.settings/org.eclipse.jdt.core.prefs -text

View File

@@ -19,6 +19,8 @@ import forge.item.InventoryItem;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.item.PreconDeck; import forge.item.PreconDeck;
import forge.model.FModel; import forge.model.FModel;
import forge.quest.QuestController;
import forge.quest.QuestEvent;
import forge.util.IHasName; import forge.util.IHasName;
import forge.util.storage.IStorage; import forge.util.storage.IStorage;
import forge.util.storage.StorageImmediatelySerialized; import forge.util.storage.StorageImmediatelySerialized;
@@ -324,7 +326,7 @@ public class DeckProxy implements InventoryItem {
return decks; return decks;
} }
/* public static Iterable<DeckProxy> getAllQuestEventAndChallenges() { public static Iterable<DeckProxy> getAllQuestEventAndChallenges() {
ArrayList<DeckProxy> decks = new ArrayList<DeckProxy>(); ArrayList<DeckProxy> decks = new ArrayList<DeckProxy>();
QuestController quest = FModel.getQuest(); QuestController quest = FModel.getQuest();
for (QuestEvent e : quest.getDuelsManager().getAllDuels()) { for (QuestEvent e : quest.getDuelsManager().getAllDuels()) {
@@ -334,7 +336,7 @@ public class DeckProxy implements InventoryItem {
decks.add(new DeckProxy(e.getEventDeck(), "Quest Event", null, null)); decks.add(new DeckProxy(e.getEventDeck(), "Quest Event", null, null));
} }
return decks; return decks;
}*/ }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static Iterable<DeckProxy> getAllSealedDecks(IStorage<DeckGroup> sealed) { public static Iterable<DeckProxy> getAllSealedDecks(IStorage<DeckGroup> sealed) {

View File

@@ -15,6 +15,10 @@ import forge.deck.generation.*;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.itemmanager.DeckManager; import forge.itemmanager.DeckManager;
import forge.model.FModel; import forge.model.FModel;
import forge.quest.QuestController;
import forge.quest.QuestEvent;
import forge.quest.QuestEventChallenge;
import forge.quest.QuestEventDuel;
import forge.toolbox.FOptionPane; import forge.toolbox.FOptionPane;
import forge.util.Aggregates; import forge.util.Aggregates;
import forge.util.Lang; import forge.util.Lang;
@@ -82,7 +86,7 @@ public class DeckgenUtil {
return deck; return deck;
} }
/*public static QuestEvent getQuestEvent(final String name) { public static QuestEvent getQuestEvent(final String name) {
QuestController qCtrl = FModel.getQuest(); QuestController qCtrl = FModel.getQuest();
for (QuestEventChallenge challenge : qCtrl.getChallenges()) { for (QuestEventChallenge challenge : qCtrl.getChallenges()) {
if (challenge.getTitle().equals(name)) { if (challenge.getTitle().equals(name)) {
@@ -94,7 +98,7 @@ public class DeckgenUtil {
@Override public boolean apply(QuestEventDuel in) { return in.getName().equals(name); } @Override public boolean apply(QuestEventDuel in) { return in.getName().equals(name); }
}); });
return duel; return duel;
}*/ }
/** @return {@link forge.deck.Deck} */ /** @return {@link forge.deck.Deck} */
public static Deck getRandomColorDeck(boolean forAi) { public static Deck getRandomColorDeck(boolean forAi) {
@@ -116,7 +120,7 @@ public class DeckgenUtil {
return allDecks.get(name); return allDecks.get(name);
} }
/*public static Deck getRandomQuestDeck() { public static Deck getRandomQuestDeck() {
final List<Deck> allQuestDecks = new ArrayList<Deck>(); final List<Deck> allQuestDecks = new ArrayList<Deck>();
QuestController qCtrl = FModel.getQuest(); QuestController qCtrl = FModel.getQuest();
@@ -130,7 +134,7 @@ public class DeckgenUtil {
final int rand = (int) (Math.floor(Math.random() * allQuestDecks.size())); final int rand = (int) (Math.floor(Math.random() * allQuestDecks.size()));
return allQuestDecks.get(rand); return allQuestDecks.get(rand);
}*/ }
public static void randomSelectColors(final DeckManager deckManager) { public static void randomSelectColors(final DeckManager deckManager) {
final int size = deckManager.getItemCount(); final int size = deckManager.getItemCount();

View File

@@ -6,6 +6,10 @@ import forge.game.player.RegisteredPlayer;
import forge.itemmanager.DeckManager; import forge.itemmanager.DeckManager;
import forge.itemmanager.ItemManagerConfig; import forge.itemmanager.ItemManagerConfig;
import forge.model.FModel; import forge.model.FModel;
import forge.quest.QuestController;
import forge.quest.QuestEvent;
import forge.quest.QuestEventChallenge;
import forge.quest.QuestUtil;
import forge.screens.FScreen; import forge.screens.FScreen;
import forge.toolbox.FComboBox; import forge.toolbox.FComboBox;
import forge.toolbox.FEvent; import forge.toolbox.FEvent;
@@ -57,6 +61,25 @@ public class FDeckChooser extends FScreen {
public void initialize(FPref savedStateSetting, DeckType defaultDeckType) { public void initialize(FPref savedStateSetting, DeckType defaultDeckType) {
stateSetting = savedStateSetting; stateSetting = savedStateSetting;
selectedDeckType = defaultDeckType; selectedDeckType = defaultDeckType;
if (decksComboBox == null) { //initialize components with delayed initialization the first time this is populated
decksComboBox = new FComboBox<DeckType>();
restoreSavedState();
decksComboBox.setChangedHandler(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
refreshDecksList(decksComboBox.getSelectedItem(), false, e);
}
});
}
else {
clear();
restoreSavedState(); //ensure decks refreshed and state restored in case any deleted or added since last loaded
}
add(decksComboBox);
add(lstDecks);
add(btnViewDeck);
add(btnRandom);
} }
public DeckType getSelectedDeckType() { return selectedDeckType; } public DeckType getSelectedDeckType() { return selectedDeckType; }
@@ -125,7 +148,6 @@ public class FDeckChooser extends FScreen {
public boolean isGeneratedDeck() { public boolean isGeneratedDeck() {
return true; return true;
} }
} }
private void updateColors() { private void updateColors() {
@@ -173,7 +195,7 @@ public class FDeckChooser extends FScreen {
private void updatePrecons() { private void updatePrecons() {
lstDecks.setAllowMultipleSelections(false); lstDecks.setAllowMultipleSelections(false);
//lstDecks.setPool(DeckProxy.getAllPreconstructedDecks(QuestController.getPrecons())); lstDecks.setPool(DeckProxy.getAllPreconstructedDecks(QuestController.getPrecons()));
lstDecks.setup(ItemManagerConfig.PRECON_DECKS); lstDecks.setup(ItemManagerConfig.PRECON_DECKS);
btnRandom.setText("Random Deck"); btnRandom.setText("Random Deck");
@@ -190,7 +212,7 @@ public class FDeckChooser extends FScreen {
private void updateQuestEvents() { private void updateQuestEvents() {
lstDecks.setAllowMultipleSelections(false); lstDecks.setAllowMultipleSelections(false);
//lstDecks.setPool(DeckProxy.getAllQuestEventAndChallenges()); lstDecks.setPool(DeckProxy.getAllQuestEventAndChallenges());
lstDecks.setup(ItemManagerConfig.QUEST_EVENT_DECKS); lstDecks.setup(ItemManagerConfig.QUEST_EVENT_DECKS);
btnRandom.setText("Random Deck"); btnRandom.setText("Random Deck");
@@ -215,39 +237,18 @@ public class FDeckChooser extends FScreen {
// Special branch for quest events // Special branch for quest events
if (selectedDeckType == DeckType.QUEST_OPPONENT_DECK) { if (selectedDeckType == DeckType.QUEST_OPPONENT_DECK) {
/*QuestEvent event = DeckgenUtil.getQuestEvent(lstDecks.getSelectedItem().getName()); QuestEvent event = DeckgenUtil.getQuestEvent(lstDecks.getSelectedItem().getName());
RegisteredPlayer result = new RegisteredPlayer(event.getEventDeck()); RegisteredPlayer result = new RegisteredPlayer(event.getEventDeck());
if (event instanceof QuestEventChallenge) { if (event instanceof QuestEventChallenge) {
result.setStartingLife(((QuestEventChallenge) event).getAiLife()); result.setStartingLife(((QuestEventChallenge) event).getAiLife());
} }
result.setCardsOnBattlefield(QuestUtil.getComputerStartingCards(event)); result.setCardsOnBattlefield(QuestUtil.getComputerStartingCards(event));
return result;*/ return result;
} }
return new RegisteredPlayer(getDeck()); return new RegisteredPlayer(getDeck());
} }
public void populate() {
if (decksComboBox == null) { //initialize components with delayed initialization the first time this is populated
decksComboBox = new FComboBox<DeckType>();
restoreSavedState();
decksComboBox.setChangedHandler(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
refreshDecksList(decksComboBox.getSelectedItem(), false, e);
}
});
}
else {
clear();
restoreSavedState(); //ensure decks refreshed and state restored in case any deleted or added since last loaded
}
add(decksComboBox);
add(lstDecks);
add(btnViewDeck);
add(btnRandom);
}
public final boolean isAi() { public final boolean isAi() {
return isAi; return isAi;
} }
@@ -263,6 +264,8 @@ public class FDeckChooser extends FScreen {
if (e == null) { if (e == null) {
decksComboBox.setSelectedItem(deckType); decksComboBox.setSelectedItem(deckType);
} }
if (deckType == null) { return; }
lstDecks.setCaption(deckType.toString()); lstDecks.setCaption(deckType.toString());
switch (deckType) { switch (deckType) {

View File

@@ -52,7 +52,7 @@ public final class ItemListView<T extends InventoryItem> extends ItemView<T> {
private final ItemTable table = new ItemTable(); private final ItemTable table = new ItemTable();
private final ItemTableModel tableModel; private final ItemTableModel tableModel;
private boolean allowMultipleSelections; private boolean allowMultipleSelections;
private List<Integer> selectedIndices; private List<Integer> selectedIndices = new ArrayList<Integer>();
public ItemTableModel getTableModel() { public ItemTableModel getTableModel() {
return tableModel; return tableModel;

View File

@@ -25,6 +25,9 @@ import forge.game.GameFormat;
import forge.game.card.CardUtil; import forge.game.card.CardUtil;
import forge.guantlet.GauntletData; import forge.guantlet.GauntletData;
import forge.limited.GauntletMini; import forge.limited.GauntletMini;
import forge.quest.QuestController;
import forge.quest.QuestWorld;
import forge.quest.data.QuestPreferences;
import forge.toolbox.FProgressBar; import forge.toolbox.FProgressBar;
import forge.util.FileUtil; import forge.util.FileUtil;
import forge.util.storage.IStorage; import forge.util.storage.IStorage;
@@ -55,19 +58,19 @@ public class FModel {
private static PrintStream oldSystemErr; private static PrintStream oldSystemErr;
private static OutputStream logFileStream; private static OutputStream logFileStream;
//private final QuestPreferences questPreferences; private static QuestPreferences questPreferences;
private static ForgePreferences preferences; private static ForgePreferences preferences;
// Someone should take care of 2 gauntlets here // Someone should take care of 2 gauntlets here
private static GauntletData gauntletData; private static GauntletData gauntletData;
private static GauntletMini gauntlet; private static GauntletMini gauntlet;
//private static QuestController quest; private static QuestController quest;
private static CardCollections decks; private static CardCollections decks;
private static IStorage<CardBlock> blocks; private static IStorage<CardBlock> blocks;
private static IStorage<CardBlock> fantasyBlocks; private static IStorage<CardBlock> fantasyBlocks;
//private static IStorage<QuestWorld> worlds; private static IStorage<QuestWorld> worlds;
private static GameFormat.Collection formats; private static GameFormat.Collection formats;
public static void initialize(final FProgressBar progressBar) { public static void initialize(final FProgressBar progressBar) {
@@ -145,25 +148,25 @@ public class FModel {
formats = new GameFormat.Collection(new GameFormat.Reader(new File(Constants.BLOCK_DATA_DIR + "formats.txt"))); formats = new GameFormat.Collection(new GameFormat.Reader(new File(Constants.BLOCK_DATA_DIR + "formats.txt")));
blocks = new StorageBase<CardBlock>("Block definitions", new CardBlock.Reader(Constants.BLOCK_DATA_DIR + "blocks.txt", magicDb.getEditions())); blocks = new StorageBase<CardBlock>("Block definitions", new CardBlock.Reader(Constants.BLOCK_DATA_DIR + "blocks.txt", magicDb.getEditions()));
//questPreferences = new QuestPreferences(); questPreferences = new QuestPreferences();
gauntletData = new GauntletData(); gauntletData = new GauntletData();
fantasyBlocks = new StorageBase<CardBlock>("Custom blocks", new CardBlock.Reader(Constants.BLOCK_DATA_DIR + "fantasyblocks.txt", magicDb.getEditions())); fantasyBlocks = new StorageBase<CardBlock>("Custom blocks", new CardBlock.Reader(Constants.BLOCK_DATA_DIR + "fantasyblocks.txt", magicDb.getEditions()));
//worlds = new StorageBase<QuestWorld>("Quest worlds", new QuestWorld.Reader(Constants.QUEST_WORLD_DIR + "worlds.txt")); worlds = new StorageBase<QuestWorld>("Quest worlds", new QuestWorld.Reader(Constants.QUEST_WORLD_DIR + "worlds.txt"));
loadDynamicGamedata(); loadDynamicGamedata();
progressBar.setDescription("Loading decks"); progressBar.setDescription("Loading decks");
decks = new CardCollections(); decks = new CardCollections();
//quest = new QuestController(); quest = new QuestController();
//preload AI profiles //preload AI profiles
AiProfileUtil.loadAllProfiles(Constants.AI_PROFILE_DIR); AiProfileUtil.loadAllProfiles(Constants.AI_PROFILE_DIR);
} }
/*public static QuestController getQuest() { public static QuestController getQuest() {
return quest; return quest;
}*/ }
private static boolean keywordsLoaded = false; private static boolean keywordsLoaded = false;
@@ -282,9 +285,9 @@ public class FModel {
return blocks; return blocks;
} }
/*public static QuestPreferences getQuestPreferences() { public static QuestPreferences getQuestPreferences() {
return questPreferences; return questPreferences;
}*/ }
public static GauntletData getGauntletData() { public static GauntletData getGauntletData() {
return gauntletData; return gauntletData;
@@ -305,9 +308,9 @@ public class FModel {
return decks; return decks;
} }
/*public static IStorage<QuestWorld> getWorlds() { public static IStorage<QuestWorld> getWorlds() {
return worlds; return worlds;
}*/ }
public static GameFormat.Collection getFormats() { public static GameFormat.Collection getFormats() {
return formats; return formats;

View File

@@ -0,0 +1,324 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.card.CardRules;
import forge.card.CardRulesPredicates;
import forge.card.MagicColor;
import forge.card.PrintSheet;
import forge.item.*;
import forge.model.FModel;
import forge.quest.data.QuestPreferences.QPref;
import forge.util.Aggregates;
import forge.util.MyRandom;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
// The BoosterPack generates cards for the Card Pool in Quest Mode
/**
* <p>
* QuestBoosterPack class.
* </p>
*
* @author Forge
* @version $Id: BoosterUtils.java 24769 2014-02-09 13:56:04Z Hellfish $
*/
public final class BoosterUtils {
/**
* Gets the quest starter deck.
*
* @param filter
* the filter
* @param numCommon
* the num common
* @param numUncommon
* the num uncommon
* @param numRare
* the num rare
* @param userPrefs
* the starting pool preferences
* @return the quest starter deck
*/
public static List<PaperCard> getQuestStarterDeck(final Predicate<PaperCard> filter, final int numCommon,
final int numUncommon, final int numRare, final StartingPoolPreferences userPrefs) {
final ArrayList<PaperCard> cards = new ArrayList<PaperCard>();
// Each color should have around the same amount of monocolored cards
// There should be 3 Colorless cards for every 4 cards in a single color
// There should be 1 Multicolor card for every 4 cards in a single color
final List<Predicate<CardRules>> colorFilters = new ArrayList<Predicate<CardRules>>();
final boolean preferred = (userPrefs != null && userPrefs.getPreferredColor() != MagicColor.ALL_COLORS);
final boolean randomized = userPrefs != null && userPrefs.useRandomPool();
final int colorBias = (preferred && !randomized) ? FModel.getQuestPreferences().getPrefInt(QPref.STARTING_POOL_COLOR_BIAS) : 0;
final int biasAdjustedCommons = (((colorBias * numCommon) / 25) > 0 ? numCommon - (colorBias * numCommon) / 25 : numCommon);
final int biasAdjustedUncommons = (((colorBias * numUncommon) / 25) > 0 ? numUncommon - (colorBias * numUncommon) / 25 : numUncommon);
final int biasAdjustedRares = (((colorBias * numRare) / 25) > 0 ? numRare - (colorBias * numRare) / 25 : numRare);
if (!randomized) {
colorFilters.add(CardRulesPredicates.Presets.IS_MULTICOLOR);
// extra filters of the preferred color if chosen
if (preferred) {
for (int i = 0; i < colorBias + (colorBias > 6 ? (2 * (colorBias - 6 + (colorBias / 10))) : 0); i++) {
colorFilters.add(CardRulesPredicates.isMonoColor(userPrefs.getPreferredColor()));
}
}
for (int i = 0; i < (preferred ? 3 : 4); i++) {
if (i != 2) {
colorFilters.add(CardRulesPredicates.Presets.IS_COLORLESS);
}
colorFilters.add(CardRulesPredicates.isMonoColor(MagicColor.WHITE));
colorFilters.add(CardRulesPredicates.isMonoColor(MagicColor.RED));
colorFilters.add(CardRulesPredicates.isMonoColor(MagicColor.BLUE));
colorFilters.add(CardRulesPredicates.isMonoColor(MagicColor.BLACK));
colorFilters.add(CardRulesPredicates.isMonoColor(MagicColor.GREEN));
}
}
// This will save CPU time when sets are limited
final List<PaperCard> cardpool = Lists.newArrayList(Iterables.filter(FModel.getMagicDb().getCommonCards().getAllCards(), filter));
final Predicate<PaperCard> pCommon = IPaperCard.Predicates.Presets.IS_COMMON;
cards.addAll(BoosterUtils.generateDefinetlyColouredCards(cardpool, pCommon, biasAdjustedCommons, colorFilters));
final Predicate<PaperCard> pUncommon = IPaperCard.Predicates.Presets.IS_UNCOMMON;
cards.addAll(BoosterUtils.generateDefinetlyColouredCards(cardpool, pUncommon, biasAdjustedUncommons, colorFilters));
int nRares = biasAdjustedRares, nMythics = 0;
final Predicate<PaperCard> filterMythics = IPaperCard.Predicates.Presets.IS_MYTHIC_RARE;
final boolean haveMythics = Iterables.any(cardpool, filterMythics);
for (int iSlot = 0; haveMythics && (iSlot < numRare); iSlot++) {
if (MyRandom.getRandom().nextInt(10) < 1) {
// 10% chance of upgrading a Rare into a Mythic
nRares--;
nMythics++;
}
}
final Predicate<PaperCard> pRare = IPaperCard.Predicates.Presets.IS_RARE;
cards.addAll(BoosterUtils.generateDefinetlyColouredCards(cardpool, pRare, nRares, colorFilters));
if (nMythics > 0) {
cards.addAll(BoosterUtils.generateDefinetlyColouredCards(cardpool, filterMythics, nMythics, colorFilters));
}
return cards;
}
/**
* Create the list of card names at random from the given pool.
*
* @param source
* an Iterable<CardPrinted>
* @param filter
* Predicate<CardPrinted>
* @param cntNeeded
* an int
* @param allowedColors
* a List<Predicate<CardRules>>
* @return a list of card names
*/
private static ArrayList<PaperCard> generateDefinetlyColouredCards(final Iterable<PaperCard> source,
final Predicate<PaperCard> filter, final int cntNeeded, final List<Predicate<CardRules>> allowedColors) {
// If color is null, use colorOrder progression to grab cards
final ArrayList<PaperCard> result = new ArrayList<PaperCard>();
final int size = allowedColors == null ? 0 : allowedColors.size();
Collections.shuffle(allowedColors);
int cntMade = 0, iAttempt = 0;
// This will prevent endless loop @ wh
int allowedMisses = (2 + size + 2) * cntNeeded; // lol, 2+2 is not magic
// constant!
while ((cntMade < cntNeeded) && (allowedMisses > 0)) {
PaperCard card = null;
if (size > 0) {
final Predicate<CardRules> color2 = allowedColors.get(iAttempt % size);
if (color2 != null) {
Predicate<PaperCard> color2c = Predicates.compose(color2, PaperCard.FN_GET_RULES);
card = Aggregates.random(Iterables.filter(source, Predicates.and(filter, color2c)));
}
}
if (card == null) {
// We can't decide on a color, so just pick a card.
card = Aggregates.random(Iterables.filter(source, filter));
}
if ((card != null) && !result.contains(card)) {
result.add(card);
cntMade++;
} else {
allowedMisses--;
}
iAttempt++;
}
return result;
}
/**
* Parse a limitation for a reward or chosen card.
* @param input
* String, the limitation as text.
* @return Predicate<CardRules> the text parsed into a CardRules predicate.
*
*/
public static Predicate<CardRules> parseRulesLimitation(final String input) {
if (null == input || "random".equalsIgnoreCase(input)) {
return Predicates.alwaysTrue();
}
if (input.equalsIgnoreCase("black")) return CardRulesPredicates.Presets.IS_BLACK;
if (input.equalsIgnoreCase("blue")) return CardRulesPredicates.Presets.IS_BLUE;
if (input.equalsIgnoreCase("green")) return CardRulesPredicates.Presets.IS_GREEN;
if (input.equalsIgnoreCase("red")) return CardRulesPredicates.Presets.IS_RED;
if (input.equalsIgnoreCase("white")) return CardRulesPredicates.Presets.IS_WHITE;
if (input.equalsIgnoreCase("colorless")) return CardRulesPredicates.Presets.IS_COLORLESS;
if (input.equalsIgnoreCase("multicolor")) return CardRulesPredicates.Presets.IS_MULTICOLOR;
if (input.equalsIgnoreCase("land")) return CardRulesPredicates.Presets.IS_LAND;
if (input.equalsIgnoreCase("creature")) return CardRulesPredicates.Presets.IS_CREATURE;
if (input.equalsIgnoreCase("artifact")) return CardRulesPredicates.Presets.IS_ARTIFACT;
if (input.equalsIgnoreCase("planeswalker")) return CardRulesPredicates.Presets.IS_PLANESWALKER;
if (input.equalsIgnoreCase("instant")) return CardRulesPredicates.Presets.IS_INSTANT;
if (input.equalsIgnoreCase("sorcery")) return CardRulesPredicates.Presets.IS_SORCERY;
if (input.equalsIgnoreCase("enchantment")) return CardRulesPredicates.Presets.IS_ENCHANTMENT;
throw new IllegalArgumentException("No CardRules limitations could be parsed from: " + input);
}
/**
* parseReward - used internally to parse individual items in a challenge reward definition.
* @param s
* String, the reward to parse
* @return List<CardPrinted>
*/
private static List<InventoryItem> parseReward(final String s) {
String[] temp = s.split(" ");
List<InventoryItem> rewards = new ArrayList<InventoryItem>();
// last word starts with 'rare' ignore case
if (temp.length > 1 && temp[temp.length - 1].regionMatches(true, 0, "rare", 0, 4)) {
// Type 1: 'n [color] rares'
final int qty = Integer.parseInt(temp[0]);
List<Predicate<PaperCard>> preds = new ArrayList<Predicate<PaperCard>>();
preds.add(IPaperCard.Predicates.Presets.IS_RARE_OR_MYTHIC); // Determine rarity
if (temp.length > 2) {
Predicate<CardRules> cr = parseRulesLimitation(temp[1]);
if (Predicates.alwaysTrue() != (Object) cr) { // guava has a single instance for always-const predicates
preds.add(Predicates.compose(cr, PaperCard.FN_GET_RULES));
}
}
if (FModel.getQuest().getFormat() != null) {
preds.add(FModel.getQuest().getFormat().getFilterPrinted());
}
PrintSheet ps = new PrintSheet("Quest rewards");
Predicate<PaperCard> predicate = preds.size() == 1 ? preds.get(0) : Predicates.and(preds);
ps.addAll(Iterables.filter(FModel.getMagicDb().getCommonCards().getAllCards(), predicate));
rewards.addAll(ps.random(qty, true));
} else if (temp.length == 2 && temp[0].equalsIgnoreCase("duplicate") && temp[1].equalsIgnoreCase("card")) {
// Type 2: a duplicate card of the players choice
rewards.add(new QuestRewardCardDuplicate());
} else if (temp.length >= 2 && temp[0].equalsIgnoreCase("chosen") && temp[1].equalsIgnoreCase("card")) {
// Type 3: a duplicate card of the players choice
rewards.add(new QuestRewardCardFiltered(temp));
} else if (temp.length >= 3 && temp[0].equalsIgnoreCase("booster") && temp[1].equalsIgnoreCase("pack")) {
// Type 4: a predetermined extra booster pack
rewards.add(BoosterPack.FN_FROM_SET.apply(FModel.getMagicDb().getEditions().get(temp[2])));
} else if (temp.length >= 3 && temp[0].equalsIgnoreCase("tournament") && temp[1].equalsIgnoreCase("pack")) {
// Type 5: a predetermined extra tournament ("starter") pack
rewards.add(TournamentPack.FN_FROM_SET.apply(FModel.getMagicDb().getEditions().get(temp[2])));
}
else if (temp.length > 0) {
// default: assume we are asking for a single copy of a specific card
final PaperCard specific = FModel.getMagicDb().getCommonCards().getCard(s);
if (specific != null) {
rewards.add(specific);
}
}
// Return the duplicate, a specified card, or an empty list
return rewards;
}
/**
* <p>
* generateCardRewardList.
* </p>
* Takes a reward list string, parses, and returns list of cards rewarded.
*
* @param s
* Properties string of reward (97 multicolor rares)
* @return List<CardPrinted>
*/
public static List<InventoryItem> generateCardRewardList(final String s) {
if (StringUtils.isBlank(s)) {
return null;
}
final String[] items = s.split(";");
final List<InventoryItem> rewards = new ArrayList<InventoryItem>();
for (final String item : items) {
String input = null;
if (item.contains("%")) {
String[] tmp = item.split("%");
final int chance = Integer.parseInt(tmp[0].trim());
if (chance > 0 && tmp.length > 1 && MyRandom.percentTrue(chance)) {
input = tmp[1].trim();
}
} else {
input = item;
}
if (input != null) {
List<InventoryItem> reward = parseReward(input);
if (reward != null) {
rewards.addAll(reward);
}
}
}
return rewards;
}
}

View File

@@ -0,0 +1,22 @@
package forge.quest;
import forge.item.InventoryItem;
import forge.item.PaperCard;
import java.util.List;
/**
* Various card rewards that may be awarded during the Quest.
* Classes that implement this interface should be able to build
* and return a list of card choices for the player to choose
* from.
*/
public interface IQuestRewardCard extends InventoryItem {
/**
* Returns an unmodifiable list of card choices.
* @return List<CardPrinted>, an umodifiable list of cards.
*/
List<PaperCard> getChoices();
}

View File

@@ -0,0 +1,505 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Nate
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.eventbus.Subscribe;
import forge.deck.Deck;
import forge.game.GameFormat;
import forge.game.event.GameEvent;
import forge.game.event.GameEventMulligan;
import forge.item.PaperCard;
import forge.item.PreconDeck;
import forge.model.FModel;
import forge.net.FServer;
import forge.quest.bazaar.QuestBazaarManager;
import forge.quest.bazaar.QuestItemType;
import forge.quest.bazaar.QuestPetStorage;
import forge.quest.data.GameFormatQuest;
import forge.quest.data.QuestAchievements;
import forge.quest.data.QuestAssets;
import forge.quest.data.QuestData;
import forge.quest.data.QuestPreferences.DifficultyPrefs;
import forge.quest.io.QuestChallengeReader;
import forge.util.storage.IStorage;
import forge.util.storage.StorageBase;
import forge.utils.Constants;
import java.io.File;
import java.util.*;
/**
* TODO: Write javadoc for this type.
*
*/
public class QuestController {
private QuestData model;
// gadgets
// Utility class to access cards, has access to private fields
// Moved some methods there that otherwise would make this class even more
// complex
private QuestUtilCards myCards;
private GameFormatQuest questFormat;
private QuestEvent currentEvent;
/** The decks. */
private transient IStorage<Deck> decks;
private QuestEventDuelManager duelManager = null;
private IStorage<QuestEventChallenge> allChallenges = null;
private QuestBazaarManager bazaar = null;
private QuestPetStorage pets = null;
// This is used by shop. Had no idea where else to place this
private static transient IStorage<PreconDeck> preconManager = null;
/** The Constant RANK_TITLES. */
public static final String[] RANK_TITLES = new String[] { "Level 0 - Confused Wizard", "Level 1 - Mana Mage",
"Level 2 - Death by Megrim", "Level 3 - Shattered the Competition", "Level 4 - Black Knighted",
"Level 5 - Shockingly Good", "Level 6 - Regressed into Timmy", "Level 7 - Loves Blue Control",
"Level 8 - Immobilized by Fear", "Level 9 - Lands = Friends", "Level 10 - Forging new paths",
"Level 11 - Infect-o-tron", "Level 12 - Great Balls of Fire", "Level 13 - Artifact Schmartifact",
"Level 14 - Mike Mulligan's The Name", "Level 15 - Fresh Air: Good For The Health",
"Level 16 - In It For The Love", "Level 17 - Sticks, Stones, Bones", "Level 18 - Credits For Breakfast",
"Level 19 - Millasaurus", "Level 20 - One-turn Wonder", "Teaching Gandalf a Lesson",
"What Do You Do With The Other Hand?", "Freelance Sorcerer, Works Weekends",
"Should We Hire Commentators?", "Saltblasted For Your Talent", "Serra Angel Is Your Girlfriend", };
/** */
public static final int MAX_PET_SLOTS = 2;
/**
*
* TODO: Write javadoc for this method.
* @param slot &emsp; int
* @param name &emsp; String
*/
public void selectPet(Integer slot, String name) {
if (this.model != null) {
this.model.getPetSlots().put(slot, name);
}
}
public void setCharmState(boolean active) {
if (this.model != null) {
this.model.setCharmActive(active);
}
}
public boolean getCharmState() {
return this.model == null ? false : this.model.isCharmActive();
}
/**
*
* @param slot &emsp; int
* @return String
*/
public String getSelectedPet(Integer slot) {
return this.model == null ? null : this.model.getPetSlots().get(slot);
}
// Cards - class uses data from here
/**
* Gets the cards.
*
* @return the cards
*/
public QuestUtilCards getCards() {
return this.myCards;
}
/**
* Gets the my decks.
*
* @return the myDecks
*/
public IStorage<Deck> getMyDecks() {
return this.decks;
}
/**
* Gets the current format if any.
*
* @return GameFormatQuest, the game format (if persistent).
*/
public GameFormatQuest getFormat() {
return (getWorldFormat() == null ? this.questFormat : getWorldFormat());
}
/**
* Gets the custom format for the main world, if any.
*/
public GameFormatQuest getMainFormat() {
return this.questFormat;
}
/**
* Gets the current event.
*
* @return the current event
*/
public QuestEvent getCurrentEvent() {
return this.currentEvent;
}
/**
* Sets the current event.
*
* @param currentEvent the new current event
*/
public void setCurrentEvent(final QuestEvent currentEvent) {
this.currentEvent = currentEvent;
}
public static IStorage<PreconDeck> getPrecons() {
if (null == preconManager) {
// read with a special class, that will fill sell rules as it processes each PreconDeck
preconManager = new StorageBase<PreconDeck>("Quest shop decks", new PreconDeck.Reader(new File(Constants.QUEST_PRECON_DIR)){
@Override
protected PreconDeck getPreconDeckFromSections(java.util.Map<String,java.util.List<String>> sections) {
PreconDeck result = super.getPreconDeckFromSections(sections);
preconDeals.put(result.getName(), new SellRules(sections.get("shop")));
return result;
};
});
}
return QuestController.preconManager;
}
private final static Map<String, SellRules> preconDeals = new TreeMap<String, SellRules>();
public static SellRules getPreconDeals(PreconDeck deck) {
return preconDeals.get(deck.getName());
}
/**
* TODO: Write javadoc for this method.
*
* @param selectedQuest the selected quest
*/
public void load(final QuestData selectedQuest) {
this.model = selectedQuest;
// These are helper classes that hold no data.
this.decks = this.model == null ? null : this.model.getAssets().getDeckStorage();
this.myCards = this.model == null ? null : new QuestUtilCards(this);
this.questFormat = this.model == null ? null : this.model.getFormat();
this.currentEvent = null;
this.resetDuelsManager();
this.resetChallengesManager();
this.getDuelsManager().randomizeOpponents();
}
/**
* TODO: Write javadoc for this method.
*/
public void save() {
if (this.model != null) {
this.model.saveData();
}
}
/**
* New game.
*
* @param name the name
* @param difficulty
* the difficulty
* @param mode the mode
* @param formatPrizes
* prize boosters format
* @param allowSetUnlocks
* allow unlocking of sets
* @param startingCards
* the starting deck
* @param formatStartingPool
* format used for the starting pool
* @param startingWorld
* starting world
* @param userPrefs
* user preferences
*/
public void newGame(final String name, final int difficulty, final QuestMode mode,
final GameFormat formatPrizes, final boolean allowSetUnlocks,
final Deck startingCards, final GameFormat formatStartingPool,
final String startingWorld, final StartingPoolPreferences userPrefs) {
this.load(new QuestData(name, difficulty, mode, formatPrizes, allowSetUnlocks, startingWorld)); // pass awards and unlocks here
if (startingCards != null) {
this.myCards.addDeck(startingCards);
}
else {
Predicate<PaperCard> filter = Predicates.alwaysTrue();
if (formatStartingPool != null) {
filter = formatStartingPool.getFilterPrinted();
}
this.myCards.setupNewGameCardPool(filter, difficulty, userPrefs);
}
this.getAssets().setCredits(FModel.getQuestPreferences().getPrefInt(DifficultyPrefs.STARTING_CREDITS, difficulty));
}
/**
* Gets the rank.
*
* @return the rank
*/
public String getRank() {
int level = this.model.getAchievements().getLevel();
if (level >= QuestController.RANK_TITLES.length) {
level = QuestController.RANK_TITLES.length - 1;
}
return QuestController.RANK_TITLES[level];
}
/**
* TODO: Write javadoc for this method.
*
* @return the assets
*/
public QuestAssets getAssets() {
return this.model == null ? null : this.model.getAssets();
}
/**
* Gets the QuestWorld, if any.
*
* @return QuestWorld or null, if using regular duels and challenges.
*/
public QuestWorld getWorld() {
return this.model == null || this.model.getWorldId() == null ? null : FModel.getWorlds().get(this.model.getWorldId());
}
/**
* Sets a new QuestWorld.
*
* @param newWorld
* string, the new world id
*/
public void setWorld(final QuestWorld newWorld) {
if (this.model == null) {
return;
}
this.model.setWorldId(newWorld == null ? null : newWorld.getName());
}
/**
* Gets the QuestWorld Format, if any.
*
* @return GameFormatQuest or null.
*/
public GameFormatQuest getWorldFormat() {
if (this.model == null || this.model.getWorldId() == null) {
return null;
}
final QuestWorld curQw = FModel.getWorlds().get(this.model.getWorldId());
if (curQw == null) {
return null;
}
return curQw.getFormat();
}
/**
* TODO: Write javadoc for this method.
*
* @return the name
*/
public String getName() {
return this.model == null ? null : this.model.getName();
}
/**
* TODO: Write javadoc for this method.
*
* @return the achievements
*/
public QuestAchievements getAchievements() {
return this.model == null ? null : this.model.getAchievements();
}
/**
* TODO: Write javadoc for this method.
*
* @return the mode
*/
public QuestMode getMode() {
return this.model.getMode();
}
/**
* Gets the bazaar.
*
* @return the bazaar
*/
public final QuestBazaarManager getBazaar() {
if (null == this.bazaar) {
this.bazaar = new QuestBazaarManager(new File(Constants.BAZAAR_FILE));
}
return this.bazaar;
}
/**
* Gets the event manager.
*
* @return the event manager
*/
public QuestEventDuelManager getDuelsManager() {
if (this.duelManager == null) {
resetDuelsManager();
}
return this.duelManager;
}
/**
*
* TODO: Write javadoc for this method.
* @return QuestEventManager
*/
public IStorage<QuestEventChallenge> getChallenges() {
if (this.allChallenges == null) {
resetChallengesManager();
}
return this.allChallenges;
}
/**
*
* Reset the duels manager.
*/
public void resetDuelsManager() {
QuestWorld world = getWorld();
String path = world == null || world.getDuelsDir() == null ? Constants.DEFAULT_DUELS_DIR : "res/quest/world/" + world.getDuelsDir();
this.duelManager = new QuestEventDuelManager(new File(path));
}
/**
*
* Reset the challenges manager.
*/
public void resetChallengesManager() {
QuestWorld world = getWorld();
String path = world == null || world.getChallengesDir() == null ? Constants.DEFAULT_CHALLENGES_DIR : "res/quest/world/" + world.getChallengesDir();
this.allChallenges = new StorageBase<QuestEventChallenge>("Quest Challenges", new QuestChallengeReader(new File(path)));
}
/**
*
* TODO: Write javadoc for this method.
* @return QuestPetStorage
*/
public QuestPetStorage getPetsStorage() {
if (this.pets == null) {
this.pets = new QuestPetStorage(new File(Constants.BAZAAR_FILE));
}
return this.pets;
}
/**
* Quest format has unlockable sets available at the moment.
* @return int number of unlockable sets.
*/
public int getUnlocksTokens() {
if (this.questFormat == null || !this.questFormat.canUnlockSets()) {
return 0;
}
final int wins = this.model.getAchievements().getWin();
int cntLocked = this.questFormat.getLockedSets().size();
int unlocksAvaliable = wins / 20;
int unlocksSpent = this.questFormat.getUnlocksUsed();
return unlocksAvaliable > unlocksSpent ? Math.min(unlocksAvaliable - unlocksSpent, cntLocked) : 0;
}
@Subscribe
public void receiveGameEvent(GameEvent ev) { // Receives events only during quest games
if (ev instanceof GameEventMulligan) {
GameEventMulligan mev = (GameEventMulligan) ev;
// First mulligan is free
if (mev.player.getLobbyPlayer() == FServer.getLobby().getQuestPlayer()
&& getAssets().hasItem(QuestItemType.SLEIGHT) && mev.player.getStats().getMulliganCount() == 0) {
mev.player.drawCard();
}
}
}
public int getTurnsToUnlockChallenge() {
if (FModel.getQuest().getAssets().hasItem(QuestItemType.ZEPPELIN)) {
return 8;
}
// User may have MAP and ZEPPELIN, so MAP must be tested second.
else if (FModel.getQuest().getAssets().hasItem(QuestItemType.MAP)) {
return 9;
}
return 10;
}
public final void regenerateChallenges() {
final QuestAchievements achievements = model.getAchievements();
final List<String> unlockedChallengeIds = new ArrayList<String>();
final List<String> availableChallengeIds = achievements.getCurrentChallenges();
int maxChallenges = achievements.getWin() / getTurnsToUnlockChallenge() - achievements.getChallengesPlayed();
if (maxChallenges > 5) {
maxChallenges = 5;
}
// Generate IDs as needed.
if (achievements.getCurrentChallenges().size() < maxChallenges) {
for (final QuestEventChallenge qc : allChallenges) {
if (qc.getWinsReqd() > achievements.getWin()) {
continue;
}
if (!qc.isRepeatable() && achievements.getLockedChallenges().contains(qc.getId())) {
continue;
}
if (!availableChallengeIds.contains(qc.getId())) {
unlockedChallengeIds.add(qc.getId());
}
}
Collections.shuffle(unlockedChallengeIds);
maxChallenges = Math.min(maxChallenges, unlockedChallengeIds.size());
for (int i = availableChallengeIds.size(); i < maxChallenges; i++) {
availableChallengeIds.add(unlockedChallengeIds.get(i));
}
}
achievements.setCurrentChallenges(availableChallengeIds);
save();
}
}

View File

@@ -0,0 +1,59 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest;
import forge.deck.Deck;
import forge.util.storage.StorageBase;
import java.util.Map;
/**
* TODO: Write javadoc for this type.
*
*/
public class QuestDeckMap extends StorageBase<Deck> {
/**
* Instantiates a new quest deck map.
*/
public QuestDeckMap(Map<String, Deck> in) {
super("Quest decks", in);
}
/*
* (non-Javadoc)
*
* @see forge.util.IFolderMap#add(forge.util.IHasName)
*/
@Override
public void add(final Deck deck) {
this.map.put(deck.getName(), deck);
}
/*
* (non-Javadoc)
*
* @see forge.util.IFolderMap#delete(java.lang.String)
*/
@Override
public void delete(final String deckName) {
this.map.remove(deckName);
}
}

View File

@@ -0,0 +1,131 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest;
import com.google.common.base.Function;
import forge.deck.Deck;
import forge.game.player.IHasIcon;
import forge.item.InventoryItem;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* <p>
* QuestEvent.
* </p>
*
* MODEL - A basic event instance in Quest mode. Can be extended for use in
* unique event types: battles, quests, and others.
*/
public abstract class QuestEvent implements IHasIcon {
// Default vals if none provided in the event file.
private Deck eventDeck = null;
private String title = "Mystery Event";
private String description = "";
private QuestEventDifficulty difficulty = QuestEventDifficulty.MEDIUM;
private String imageKey = "";
private String name = "Noname";
private String cardReward = null;
private List<InventoryItem> cardRewardList = null;
public static final Function<QuestEvent, String> FN_GET_NAME = new Function<QuestEvent, String>() {
@Override public final String apply(QuestEvent qe) { return qe.name; }
};
public final String getTitle() {
return this.title;
}
/**
* Returns null for standard quest events, may return something different for challenges.
*/
public String getOpponent() {
return null;
}
public final QuestEventDifficulty getDifficulty() {
return this.difficulty;
}
public final String getDescription() {
return this.description;
}
public final Deck getEventDeck() {
return this.eventDeck;
}
@Override
public final String getIconImageKey() {
return this.imageKey;
}
public final String getName() {
return this.name;
}
public void setName(final String name0) {
this.name = name0;
}
public void setTitle(final String title0) {
this.title = title0;
}
public void setDifficulty(final QuestEventDifficulty difficulty0) {
this.difficulty = difficulty0;
}
public void setDescription(final String description0) {
this.description = description0;
}
public void setEventDeck(final Deck eventDeck0) {
this.eventDeck = eventDeck0;
}
@Override
public void setIconImageKey(final String s0) {
this.imageKey = s0;
}
public final List<InventoryItem> getCardRewardList() {
if (cardReward == null) {
return null;
}
if (cardRewardList == null) {
this.cardRewardList = new ArrayList<InventoryItem>(BoosterUtils.generateCardRewardList(cardReward));
}
return this.cardRewardList;
}
public void setCardReward(final String cardReward0) {
this.cardReward = cardReward0;
}
public List<String> getHumanExtraCards() {
return Collections.emptyList();
}
public List<String> getAiExtraCards() {
return Collections.emptyList();
}
}

View File

@@ -0,0 +1,315 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest;
import com.google.common.base.Function;
import forge.deck.Deck;
import java.util.ArrayList;
import java.util.List;
/**
* <p>
* QuestQuest class.
* </p>
*
* MODEL - A single quest event data instance, including meta, deck, and
* quest-specific properties.
*
*/
public class QuestEventChallenge extends QuestEvent {
public static final Function<QuestEventChallenge, String> FN_GET_ID = new Function<QuestEventChallenge, String>() {
@Override public final String apply(QuestEventChallenge qe) { return qe.id; }
};
// ID (default -1, should be explicitly set at later time.)
/** The id. */
private String id = "-1";
// Opponent name if different from the challenge name
private String opponentName = null;
// Default vals if none provided for this ID
/** The ai life. */
private int aiLife = 25;
private Integer humanLife = null;
/** The credits reward. */
private int creditsReward = 100;
/** The repeatable. */
private boolean repeatable = false;
private boolean useBazaar = true;
private Boolean forceAnte = null;
/** The wins reqd. */
private int winsReqd = 20;
// Other cards used in assignment: starting, and reward.
/** The human extra cards. */
private List<String> humanExtraCards = new ArrayList<String>();
/** The ai extra cards. */
private List<String> aiExtraCards = new ArrayList<String>();
private Deck humanDeck = null;
/**
* Instantiates a new quest challenge.
*/
public QuestEventChallenge() {
super();
setCardReward("1 colorless rare"); // Guaranteed extra reward for challenges if not specified
}
/**
* <p>
* getAILife.
* </p>
*
* @return {@link java.lang.Integer}.
*/
public final int getAILife() {
return this.getAiLife();
}
/**
* <p>
* getCreditsReward.
* </p>
*
* @return {@link java.lang.Integer}.
*/
public final int getCreditsReward() {
return this.creditsReward;
}
/**
* <p>
* getId.
* </p>
*
* @return {@link java.lang.Integer}.
*/
public final String getId() {
return this.id;
}
/**
* <p>
* get the opponent's name, or null if not explicitly set.
*
* </p>
*
* @return {@link java.lang.String}.
*/
@Override
public final String getOpponent() {
return this.opponentName;
}
/**
* <p>
* getWinsReqd.
* </p>
*
* @return {@link java.lang.Integer}.
*/
public final int getWinsReqd() {
return this.winsReqd;
}
/**
* <p>
* getHumanExtraCards.
* </p>
* Retrieves list of cards human has in play at the beginning of this quest.
*
* @return the human extra cards
*/
@Override
public final List<String> getHumanExtraCards() {
return this.humanExtraCards;
}
/**
* Gets the ai extra cards.
*
* @return the aiExtraCards
*/
@Override
public List<String> getAiExtraCards() {
return this.aiExtraCards;
}
/**
* Sets the ai extra cards.
*
* @param aiExtraCards0
* the aiExtraCards to set
*/
public void setAiExtraCards(final List<String> aiExtraCards0) {
this.aiExtraCards = aiExtraCards0;
}
/**
* Sets the id.
*
* @param id0
* the id to set
*/
public void setId(final String id0) {
this.id = id0;
}
/**
* Sets the opponent's name.
*
* @param newName
* the name to set
*/
public void setOpponent(final String newName) {
this.opponentName = newName;
}
/**
* Checks if is repeatable.
*
* @return the repeatable
*/
public boolean isRepeatable() {
return this.repeatable;
}
/**
* Sets the repeatable.
*
* @param repeatable0
* the repeatable to set
*/
public void setRepeatable(final boolean repeatable0) {
this.repeatable = repeatable0;
}
/**
* Gets the ai life.
*
* @return the aiLife
*/
public int getAiLife() {
return this.aiLife;
}
/**
* Sets the ai life.
*
* @param aiLife0
* the aiLife to set
*/
public void setAiLife(final int aiLife0) {
this.aiLife = aiLife0;
}
/**
* Sets the wins reqd.
*
* @param winsReqd0
* the winsReqd to set
*/
public void setWinsReqd(final int winsReqd0) {
this.winsReqd = winsReqd0;
}
/**
* Sets the credits reward.
*
* @param creditsReward0
* the creditsReward to set
*/
public void setCreditsReward(final int creditsReward0) {
this.creditsReward = creditsReward0;
}
/**
* Sets the human extra cards.
*
* @param humanExtraCards0
* the humanExtraCards to set
*/
public void setHumanExtraCards(final List<String> humanExtraCards0) {
this.humanExtraCards = humanExtraCards0;
}
/**
* @return the humanLife
*/
public Integer getHumanLife() {
return humanLife;
}
/**
* @param humanLife the humanLife to set
*/
public void setHumanLife(Integer humanLife) {
this.humanLife = humanLife;
}
/**
* @return the useBazaar
*/
public boolean isUseBazaar() {
return useBazaar;
}
/**
* @param useBazaar the useBazaar to set
*/
public void setUseBazaar(boolean useBazaar) {
this.useBazaar = useBazaar;
}
/**
* @return the forceAnte
*/
public Boolean isForceAnte() {
return forceAnte;
}
/**
* @param forceAnte the forceAnte to set
*/
public void setForceAnte(Boolean forceAnte) {
this.forceAnte = forceAnte;
}
/**
* @return the humanDeck
*/
public Deck getHumanDeck() {
return humanDeck;
}
/**
* @param humanDeck the humanDeck to set
*/
public void setHumanDeck(Deck humanDeck) {
this.humanDeck = humanDeck;
}
}

View File

@@ -0,0 +1,35 @@
package forge.quest;
import org.apache.commons.lang3.StringUtils;
/**
* TODO: Write javadoc for this type.
*
*/
public enum QuestEventDifficulty {
EASY("easy"),
MEDIUM("medium"),
HARD("hard"),
EXPERT("very hard");
String inFile;
private QuestEventDifficulty(String storedInFile) {
inFile = storedInFile;
}
public final String getTitle() {
return inFile;
}
public static QuestEventDifficulty fromString(String src) {
if ( StringUtils.isBlank(src) )
return MEDIUM; // player have custom files, that didn't specify a valid difficulty
for(QuestEventDifficulty qd : QuestEventDifficulty.values()) {
if( src.equalsIgnoreCase(qd.inFile) || src.equalsIgnoreCase(qd.name()) )
return qd;
}
return null;
}
}

View File

@@ -0,0 +1,37 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest;
/**
* <p>
* QuestDuel class.
* </p>
* MODEL - A single duel event data instance, including meta and deck.
*
*/
public class QuestEventDuel extends QuestEvent {
/**
* Instantiates a new quest duel.
*/
public QuestEventDuel() {
super();
}
}

View File

@@ -0,0 +1,158 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest;
import forge.model.FModel;
import forge.quest.data.QuestPreferences;
import forge.quest.data.QuestPreferences.DifficultyPrefs;
import forge.quest.io.QuestDuelReader;
import forge.util.CollectionSuppliers;
import forge.util.maps.EnumMapOfLists;
import forge.util.maps.MapOfLists;
import forge.util.storage.IStorage;
import forge.util.storage.StorageBase;
import java.io.File;
import java.util.*;
/**
* QuestEventManager.
*
* @author Forge
* @version $Id: QuestEventManager.java 20404 2013-03-17 05:34:13Z myk $
*/
public class QuestEventDuelManager {
private final MapOfLists<QuestEventDifficulty, QuestEventDuel> sortedDuels = new EnumMapOfLists<QuestEventDifficulty, QuestEventDuel>(QuestEventDifficulty.class, CollectionSuppliers.<QuestEventDuel>arrayLists());
private final IStorage<QuestEventDuel> allDuels;
/** Instantiate all events and difficulty lists.
* @param dir &emsp; File object */
public QuestEventDuelManager(final File dir) {
allDuels = new StorageBase<QuestEventDuel>("Quest duels", new QuestDuelReader(dir));
assembleDuelDifficultyLists();
} // End assembleAllEvents()
/** @return List<QuestEventDuel> */
public Iterable<QuestEventDuel> getAllDuels() {
return allDuels;
}
// define fallback orders if there aren't enough opponents defined for a particular difficultly level
private static List<QuestEventDifficulty> _easyOrder = Arrays.asList(QuestEventDifficulty.EASY, QuestEventDifficulty.MEDIUM, QuestEventDifficulty.HARD, QuestEventDifficulty.EXPERT);
private static List<QuestEventDifficulty> _mediumOrder = Arrays.asList(QuestEventDifficulty.MEDIUM, QuestEventDifficulty.HARD, QuestEventDifficulty.EASY, QuestEventDifficulty.EXPERT);
private static List<QuestEventDifficulty> _hardOrder = Arrays.asList(QuestEventDifficulty.HARD, QuestEventDifficulty.MEDIUM, QuestEventDifficulty.EASY, QuestEventDifficulty.EXPERT);
private static List<QuestEventDifficulty> _expertOrder = Arrays.asList(QuestEventDifficulty.EXPERT, QuestEventDifficulty.HARD, QuestEventDifficulty.MEDIUM, QuestEventDifficulty.EASY);
private void _addDuel(List<QuestEventDuel> outList, QuestEventDifficulty targetDifficulty, int toAdd) {
// if there's no way we can satisfy the request, return now
if (allDuels.size() <= toAdd) {
return;
}
final List<QuestEventDifficulty> difficultyOrder;
switch (targetDifficulty) {
case EASY: difficultyOrder = _easyOrder; break;
case MEDIUM: difficultyOrder = _mediumOrder; break;
case HARD: difficultyOrder = _hardOrder; break;
case EXPERT: difficultyOrder = _expertOrder; break;
default:
throw new RuntimeException("unhandled difficulty: " + targetDifficulty);
}
for (QuestEventDifficulty d : difficultyOrder) { // will add duels from preferred difficulty, will use others if the former has too few options.
for( QuestEventDuel duel : sortedDuels.get(d)) {
if(toAdd <= 0)
return;
if (!outList.contains(duel)) {
outList.add(duel);
toAdd--;
}
}
}
}
/** Generates an array of new duel opponents based on current win conditions.
*
* @return an array of {@link java.lang.String} objects.
*/
public final List<QuestEventDuel> generateDuels() {
final QuestPreferences qpref = FModel.getQuestPreferences();
if (FModel.getQuest().getAchievements() == null) {
return null;
}
final QuestController qCtrl = FModel.getQuest();
final int cntWins = qCtrl.getAchievements().getWin();
final int index = qCtrl.getAchievements().getDifficulty();
final List<QuestEventDuel> duelOpponents = new ArrayList<QuestEventDuel>();
if (cntWins < qpref.getPrefInt(DifficultyPrefs.WINS_MEDIUMAI, index)) {
_addDuel(duelOpponents, QuestEventDifficulty.EASY, 3);
} else if (cntWins == qpref.getPrefInt(DifficultyPrefs.WINS_MEDIUMAI, index)) {
_addDuel(duelOpponents, QuestEventDifficulty.EASY, 1);
_addDuel(duelOpponents, QuestEventDifficulty.MEDIUM, 2);
} else if (cntWins < qpref.getPrefInt(DifficultyPrefs.WINS_HARDAI, index)) {
_addDuel(duelOpponents, QuestEventDifficulty.MEDIUM, 3);
} else if (cntWins == qpref.getPrefInt(DifficultyPrefs.WINS_HARDAI, index)) {
_addDuel(duelOpponents, QuestEventDifficulty.MEDIUM, 1);
_addDuel(duelOpponents, QuestEventDifficulty.HARD, 2);
} else if (cntWins < qpref.getPrefInt(DifficultyPrefs.WINS_EXPERTAI, index)) {
_addDuel(duelOpponents, QuestEventDifficulty.HARD, 3);
} else {
_addDuel(duelOpponents, QuestEventDifficulty.HARD, 2);
_addDuel(duelOpponents, QuestEventDifficulty.EXPERT, 1);
}
return duelOpponents;
}
/**
* <p>
* assembleDuelDifficultyLists.
* </p>
* Assemble duel deck difficulty lists
*/
private void assembleDuelDifficultyLists() {
sortedDuels.clear();
sortedDuels.put(QuestEventDifficulty.EASY, new ArrayList<QuestEventDuel>());
sortedDuels.put(QuestEventDifficulty.MEDIUM, new ArrayList<QuestEventDuel>());
sortedDuels.put(QuestEventDifficulty.HARD, new ArrayList<QuestEventDuel>());
sortedDuels.put(QuestEventDifficulty.EXPERT, new ArrayList<QuestEventDuel>());
for (final QuestEventDuel qd : allDuels) {
sortedDuels.add(qd.getDifficulty(), qd);
}
}
/** */
public void randomizeOpponents() {
final long seed = new Random().nextLong();
final Random r = new Random(seed);
for(QuestEventDifficulty qd : sortedDuels.keySet()) {
List<QuestEventDuel> list = (List<QuestEventDuel>) sortedDuels.get(qd);
Collections.shuffle(list, r);
}
}
}

View File

@@ -0,0 +1,34 @@
package forge.quest;
/**
* TODO: Write javadoc for this type.
*
*/
public enum QuestMode {
// Do not apply checkstyle here, to maintain compatibility with old saves
Fantasy,
Classic,
Gauntlet;
/**
* TODO: Write javadoc for this method.
* @param value
* @param classic2
* @return
*/
public static QuestMode smartValueOf(String value, QuestMode defaultValue) {
if (null == value) {
return defaultValue;
}
final String valToCompate = value.trim();
for (final QuestMode v : QuestMode.values()) {
if (v.name().compareToIgnoreCase(valToCompate) == 0) {
return v;
}
}
return QuestMode.Classic;
}
}

View File

@@ -0,0 +1,123 @@
package forge.quest;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import forge.card.CardRules;
import forge.item.IPaperCard;
import forge.item.InventoryItem;
import forge.item.PaperCard;
import forge.model.FModel;
import java.util.ArrayList;
import java.util.List;
public abstract class QuestRewardCard implements InventoryItem, IQuestRewardCard {
protected String buildDescription(final String [] input) {
final String defaultDescription = "a card";
if (input == null || input.length < 1) {
return defaultDescription;
}
String buildDesc = null;
for (String s : input) {
if (s.startsWith("desc:") || s.startsWith("Desc:")) {
String[] tmp = s.split(":");
if (tmp.length > 1) {
buildDesc = new String(tmp[1]);
} else {
buildDesc = new String();
}
} else if (buildDesc != null) {
if (s.contains(":")) {
return buildDesc;
} else {
buildDesc = buildDesc + " " + s;
}
}
}
if (buildDesc != null) {
return buildDesc;
}
return defaultDescription;
}
protected Predicate<PaperCard> buildPredicates(final String [] input) {
if (input == null || input.length < 1) {
return null;
}
Predicate<PaperCard> filters = FModel.getQuest().getFormat().getFilterPrinted();
Predicate<CardRules> filterRules = null;
Predicate<PaperCard> filterRarity = null;
for (String s : input) {
if (s.startsWith("sets:") || s.startsWith("Sets:")) {
final String[] tmp = s.split(":");
if (tmp.length > 1) {
String [] setcodes = tmp[1].split(",");
if (setcodes.length > 0) {
List<String> sets = new ArrayList<String>();
for (String code : setcodes) {
if (FModel.getMagicDb().getEditions().contains(code)) {
// System.out.println("Set " + code + " was found!");
sets.add(code);
}
// else { System.out.println("Unknown set code " + code); }
}
if (sets.size() > 0) {
filters = IPaperCard.Predicates.printedInSets(sets, true);
}
}
}
} else if (s.startsWith("rules:") || s.startsWith("Rules:")) {
final String[] tmp = s.split(":");
if (tmp.length > 1) {
String [] ruleCodes = tmp[1].split(",");
if (ruleCodes.length > 0) {
for (String rule : ruleCodes) {
final Predicate<CardRules> newRule = BoosterUtils.parseRulesLimitation(rule);
if (newRule != null) {
filterRules = (filterRules == null ? newRule : Predicates.and(filterRules, newRule));
}
}
}
}
} else if (s.startsWith("rarity:") || s.startsWith("Rarity:")) {
final String[] tmp = s.split(":");
if (tmp.length > 1) {
String [] rarityCodes = tmp[1].split(",");
if (rarityCodes.length > 0) {
for (String rarity : rarityCodes) {
if (rarity.startsWith("C") || rarity.startsWith("c")) {
filterRarity = (filterRarity == null ? IPaperCard.Predicates.Presets.IS_COMMON : Predicates.or(filterRarity, IPaperCard.Predicates.Presets.IS_COMMON));
} else if (rarity.startsWith("U") || rarity.startsWith("u")) {
filterRarity = (filterRarity == null ? IPaperCard.Predicates.Presets.IS_UNCOMMON : Predicates.or(filterRarity, IPaperCard.Predicates.Presets.IS_UNCOMMON));
} else if (rarity.startsWith("R") || rarity.startsWith("r")) {
filterRarity = (filterRarity == null ? IPaperCard.Predicates.Presets.IS_RARE : Predicates.or(filterRarity, IPaperCard.Predicates.Presets.IS_RARE));
} else if (rarity.startsWith("M") || rarity.startsWith("m")) {
filterRarity = (filterRarity == null ? IPaperCard.Predicates.Presets.IS_MYTHIC_RARE : Predicates.or(filterRarity, IPaperCard.Predicates.Presets.IS_MYTHIC_RARE));
}
}
}
}
}
}
if (filterRules != null) {
final Predicate<PaperCard> rulesPrinted = Predicates.compose(filterRules, PaperCard.FN_GET_RULES);
filters = Predicates.and(filters, rulesPrinted);
}
if (filterRarity != null) {
filters = Predicates.and(filters, filterRarity);
}
return filters;
}
public abstract List<PaperCard> getChoices();
}

View File

@@ -0,0 +1,125 @@
package forge.quest;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import forge.item.InventoryItem;
import forge.item.PaperCard;
import forge.model.FModel;
import forge.util.ItemPool;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* Resolves a card chooser InventoryItem into a CardPrinted.
* The initial version includes "duplicate", other type may be added later.
*
*/
public class QuestRewardCardChooser extends QuestRewardCard implements InventoryItem {
/**
* Possible types for this object.
*/
public enum poolType {
/** The player's own cardpool (duplicate card). */
playerCards,
/** Filtered by a predicate that will be parsed. */
predicateFilter
}
private poolType type;
private final String description;
private final Predicate<PaperCard> predicates;
/**
* The constructor.
* The parameter indicates the more specific type.
* @param setType String, the type of the choosable card.
* @param creationParameters String, used to build the predicates and description for the predicateFilter type
*/
public QuestRewardCardChooser(final poolType setType, final String[] creationParameters) {
type = setType;
if (type == poolType.playerCards) {
description = "a duplicate card";
predicates = null;
} else {
description = buildDescription(creationParameters);
predicates = buildPredicates(creationParameters);
}
}
/**
* The name.
*
* @return the name
*/
@Override
public String getName() {
return description;
}
@Override
public String toString() {
return description;
}
/**
* The item type.
*
* @return item type
*/
@Override
public String getItemType() {
switch (type) {
case playerCards:
return "duplicate card";
case predicateFilter: default:
return "chosen card";
}
}
/**
* Get type as enum.
* @return enum, item type.
*/
public poolType getType() {
return type;
}
/**
* Produces a list of options to choose from.
*
* @return a List<CardPrinted> or null if could not create a list.
*/
@Override
public final List<PaperCard> getChoices() {
if (type == poolType.playerCards) {
final ItemPool<PaperCard> playerCards = FModel.getQuest().getAssets().getCardPool();
if (!playerCards.isEmpty()) { // Maybe a redundant check since it's hard to win a duel without any cards...
List<PaperCard> cardChoices = new ArrayList<PaperCard>();
for (final Map.Entry<PaperCard, Integer> card : playerCards) {
cardChoices.add(card.getKey());
}
Collections.sort(cardChoices);
return Collections.unmodifiableList(cardChoices);
}
} else if (type == poolType.predicateFilter) {
List<PaperCard> cardChoices = new ArrayList<PaperCard>();
for (final PaperCard card : Iterables.filter(FModel.getMagicDb().getCommonCards().getAllCards(), predicates)) {
cardChoices.add(card);
}
Collections.sort(cardChoices);
return Collections.unmodifiableList(cardChoices);
} else {
throw new RuntimeException("Unknown QuestRewardCardType: " + type);
}
return null;
}
}

View File

@@ -0,0 +1,72 @@
package forge.quest;
import forge.item.PaperCard;
import forge.model.FModel;
import forge.util.ItemPool;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* Allows the player to choose a duplicate copy of a currently owned card.
*
*/
public class QuestRewardCardDuplicate implements IQuestRewardCard {
private final String description;
/**
*
* The constructor. No parameters.
*/
public QuestRewardCardDuplicate() {
description = "a duplicate card";
}
/**
* The name.
*
* @return the name
*/
@Override
public String getName() {
return description;
}
/**
* The item type.
*
* @return item type
*/
@Override
public String getItemType() {
return "duplicate card";
}
@Override
public String toString() {
return description;
}
/**
* Produces a list of options to choose from, in this case,
* the player's current cards.
*
* @return a List<CardPrinted> or null if could not create a list.
*/
public final List<PaperCard> getChoices() {
final ItemPool<PaperCard> playerCards = FModel.getQuest().getAssets().getCardPool();
if (!playerCards.isEmpty()) { // Maybe a redundant check since it's hard to win a duel without any cards...
List<PaperCard> cardChoices = new ArrayList<PaperCard>();
for (final Map.Entry<PaperCard, Integer> card : playerCards) {
cardChoices.add(card.getKey());
}
Collections.sort(cardChoices);
return Collections.unmodifiableList(cardChoices);
}
return null;
}
}

View File

@@ -0,0 +1,71 @@
package forge.quest;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import forge.item.PaperCard;
import forge.model.FModel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Allows the player to choose a card from a predicate-filtered list of cards.
*
*/
public class QuestRewardCardFiltered extends QuestRewardCard implements IQuestRewardCard {
private final String description;
private final Predicate<PaperCard> predicates;
/**
* The constructor.
* @param creationParameters String, used to build the predicates and description for the predicateFilter type
*/
public QuestRewardCardFiltered(final String[] creationParameters) {
description = buildDescription(creationParameters);
predicates = buildPredicates(creationParameters);
}
/**
* The name.
*
* @return the name
*/
@Override
public String getName() {
return description;
}
@Override
public String toString() {
return description;
}
/**
* The item type.
*
* @return item type
*/
@Override
public String getItemType() {
return "chosen card";
}
/**
* Produces a list of options to choose from.
*
* @return a List<CardPrinted> or null if could not create a list.
*/
@Override
public final List<PaperCard> getChoices() {
List<PaperCard> cardChoices = new ArrayList<PaperCard>();
for (final PaperCard card : Iterables.filter(FModel.getMagicDb().getCommonCards().getAllCards(), predicates)) {
cardChoices.add(card);
}
Collections.sort(cardChoices);
return Collections.unmodifiableList(cardChoices);
}
}

View File

@@ -0,0 +1,174 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest;
import forge.card.CardDb.SetPreference;
import forge.card.CardEdition;
import forge.card.CardRules;
import forge.game.card.Card;
import forge.item.IPaperCard;
import forge.item.PaperToken;
import forge.model.FModel;
import forge.quest.bazaar.QuestPetController;
import java.util.ArrayList;
import java.util.List;
/**
* <p>
* QuestUtil class.
* </p>
* MODEL - Static utility methods to help with minor tasks around Quest.
*
* @author Forge
* @version $Id: QuestUtil.java 24769 2014-02-09 13:56:04Z Hellfish $
*/
public class QuestUtil {
/**
* <p>
* getComputerStartingCards.
* </p>
*
* @param qd
* a {@link forge.quest.data.QuestData} object.
* @return a {@link forge.CardList} object.
*/
public static List<Card> getComputerStartingCards() {
return new ArrayList<Card>();
}
/**
* <p>
* getComputerStartingCards.
* </p>
* Returns new card instances of extra AI cards in play at start of event.
*
* @param qd
* a {@link forge.quest.data.QuestData} object.
* @param qe
* a {@link forge.quest.QuestEvent} object.
* @return a {@link forge.CardList} object.
*/
public static List<IPaperCard> getComputerStartingCards(final QuestEvent qe) {
final List<IPaperCard> list = new ArrayList<IPaperCard>();
for (final String s : qe.getAiExtraCards()) {
list.add(QuestUtil.readExtraCard(s));
}
return list;
}
/**
* <p>
* getHumanStartingCards.
* </p>
* Returns list of current plant/pet configuration only.
* @param human
*
* @param qd
* a {@link forge.quest.data.QuestData} object.
* @return a {@link forge.CardList} object.
*/
public static List<IPaperCard> getHumanStartingCards(final QuestController qc) {
final List<IPaperCard> list = new ArrayList<IPaperCard>();
for (int iSlot = 0; iSlot < QuestController.MAX_PET_SLOTS; iSlot++) {
String petName = qc.getSelectedPet(iSlot);
QuestPetController pet = qc.getPetsStorage().getPet(petName);
if (pet != null) {
IPaperCard c = pet.getPetCard(qc.getAssets());
if (c != null) {
list.add(c);
}
}
}
return list;
}
/**
* <p>
* getHumanStartingCards.
* </p>
* Returns new card instances of extra human cards, including current
* plant/pet configuration, and cards in play at start of quest.
*
* @param qd
* a {@link forge.quest.data.QuestData} object.
* @param qe
* a {@link forge.quest.QuestEvent} object.
* @return a {@link forge.CardList} object.
*/
public static List<IPaperCard> getHumanStartingCards(final QuestController qc, final QuestEvent qe) {
final List<IPaperCard> list = QuestUtil.getHumanStartingCards(qc);
for (final String s : qe.getHumanExtraCards()) {
list.add(QuestUtil.readExtraCard(s));
}
return list;
}
/**
* <p>
* createToken.
* </p>
* Creates a card instance for token defined by property string.
*
* @param s
* Properties string of token
* (TOKEN;W;1;1;sheep;type;type;type...)
* @return token Card
*/
public static PaperToken createToken(final String s) {
final String[] properties = s.split(";", 6);
List<String> script = new ArrayList<String>();
script.add("Name:" + properties[4]);
script.add("Colors:" + properties[1]);
script.add("PT:"+ properties[2] + "/" + properties[3]);
script.add("Types:" + properties[5].replace(';', ' '));
script.add("Oracle:"); // tokens don't have texts yet
String fileName = PaperToken.makeTokenFileName(properties[1], properties[2], properties[3], properties[4]);
final PaperToken c = new PaperToken(CardRules.fromScript(script), CardEdition.UNKNOWN, fileName);
return c;
}
/**
* <p>
* readExtraCard.
* </p>
* Creates single card for a string read from unique event properties.
*
* @param name
* the name
* @param owner
* the owner
* @return the card
*/
public static IPaperCard readExtraCard(final String name) {
// Token card creation
IPaperCard tempcard;
if (name.startsWith("TOKEN")) {
tempcard = QuestUtil.createToken(name);
return tempcard;
}
// Standard card creation
return FModel.getMagicDb().getCommonCards().getCardFromEdition(name, SetPreference.Latest);
}
} // QuestUtil

View File

@@ -0,0 +1,708 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.card.*;
import forge.deck.Deck;
import forge.deck.DeckSection;
import forge.game.GameFormat;
import forge.item.*;
import forge.model.FModel;
import forge.quest.bazaar.QuestItemType;
import forge.quest.data.GameFormatQuest;
import forge.quest.data.QuestAssets;
import forge.quest.data.QuestPreferences;
import forge.quest.data.QuestPreferences.DifficultyPrefs;
import forge.quest.data.QuestPreferences.QPref;
import forge.util.Aggregates;
import forge.util.ItemPool;
import forge.util.MyRandom;
import forge.utils.ForgePreferences.FPref;
import org.apache.commons.lang3.tuple.Pair;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
/**
* This is a helper class to execute operations on QuestData. It has been
* created to decrease complexity of questData class
*/
public final class QuestUtilCards {
private final QuestController qc;
private final QuestPreferences qpref;
private final QuestAssets qa;
/**
* Instantiates a new quest util cards.
*
* @param qd
* the qd
*/
public QuestUtilCards(final QuestController qd) {
this.qc = qd;
this.qa = qc.getAssets();
this.qpref = FModel.getQuestPreferences();
}
/**
* Adds the basic lands (from random sets as limited by the format).
*
* @param nBasic the n basic
* @param nSnow the n snow
* @param usedFormat currently enforced game format, if any
* @return the item pool view
*/
public static ItemPool<PaperCard> generateBasicLands(final int nBasic, final int nSnow, final GameFormatQuest usedFormat) {
final ICardDatabase db = FModel.getMagicDb().getCommonCards();
final ItemPool<PaperCard> pool = new ItemPool<PaperCard>(PaperCard.class);
List<String> landCodes = new ArrayList<String>();
List<String> snowLandCodes = new ArrayList<String>();
if (usedFormat != null) {
List<String> availableEditions = usedFormat.getAllowedSetCodes();
for (String edCode : availableEditions) {
CardEdition ed = FModel.getMagicDb().getEditions().get(edCode);
// Duel decks might have only 2 types of basic lands
if (CardEdition.Predicates.hasBasicLands.apply(ed)) {
landCodes.add(edCode);
}
}
if (usedFormat.isSetLegal("ICE")) {
snowLandCodes.add("ICE");
}
if (usedFormat.isSetLegal("CSP")) {
snowLandCodes.add("CSP");
}
} else {
Iterable<CardEdition> allEditions = FModel.getMagicDb().getEditions();
for (CardEdition edition : Iterables.filter(allEditions, CardEdition.Predicates.hasBasicLands)) {
landCodes.add(edition.getCode());
}
snowLandCodes.add("ICE");
snowLandCodes.add("CSP");
}
String landCode = Aggregates.random(landCodes);
if (null == landCode) {
landCode = "M10";
}
final boolean isZendikarSet = landCode.equals("ZEN"); // we want to generate one kind of Zendikar lands at a time only
final boolean zendikarSetMode = MyRandom.getRandom().nextBoolean();
for (String landName : MagicColor.Constant.BASIC_LANDS) {
int artCount = db.getArtCount(landName, landCode);
if (FModel.getPreferences().getPrefBoolean(FPref.UI_RANDOM_ART_IN_POOLS)) {
int[] artGroups = MyRandom.splitIntoRandomGroups(nBasic, isZendikarSet ? 4 : artCount);
for (int i = 1; i <= artGroups.length; i++) {
pool.add(db.getCard(landName, landCode, isZendikarSet ? (zendikarSetMode ? i : i + 4) : i), artGroups[i - 1]);
}
} else {
pool.add(db.getCard(landName, landCode, artCount > 1 ? MyRandom.getRandom().nextInt(artCount) + 1 : 1), nBasic);
}
}
if (!snowLandCodes.isEmpty()) {
String snowLandCode = Aggregates.random(snowLandCodes);
for (String landName : MagicColor.Constant.SNOW_LANDS) {
pool.add(db.getCard(landName, snowLandCode), nSnow);
}
}
return pool;
}
/**
* <p>
* addCards.
* </p>
*
* @param fSets
* the f sets
* @return the array list
*/
public List<PaperCard> generateQuestBooster(final Predicate<PaperCard> fSets) {
UnOpenedProduct unopened = new UnOpenedProduct(getBoosterTemplate(), fSets);
return unopened.get();
}
/**
* Adds the all cards.
*
* @param newCards
* the new cards
*/
public void addAllCards(final Iterable<PaperCard> newCards) {
for (final PaperCard card : newCards) {
this.addSingleCard(card, 1);
}
}
/**
* Adds the single card.
*
* @param card
* the card
* @param qty
* quantity
*/
public void addSingleCard(final PaperCard card, int qty) {
this.qa.getCardPool().add(card, qty);
// register card into that list so that it would appear as a new one.
this.qa.getNewCardList().add(card, qty);
}
private static final Predicate<PaperCard> RARE_PREDICATE = IPaperCard.Predicates.Presets.IS_RARE_OR_MYTHIC;
/**
* A predicate that takes into account the Quest Format (if any).
* @param source
* the predicate to be added to the format predicate.
* @return the composite predicate.
*/
public Predicate<PaperCard> applyFormatFilter(Predicate<PaperCard> source) {
return qc.getFormat() == null ? source : Predicates.and(source, qc.getFormat().getFilterPrinted());
}
/**
* Adds the random rare.
*
* @return the card printed
*/
public PaperCard addRandomRare() {
final Predicate<PaperCard> myFilter = applyFormatFilter(QuestUtilCards.RARE_PREDICATE);
final PaperCard card = Aggregates.random(Iterables.filter(FModel.getMagicDb().getCommonCards().getAllCards(), myFilter));
this.addSingleCard(card, 1);
return card;
}
/**
* Adds the random rare.
*
* @param n
* the n
* @return the list
*/
public List<PaperCard> addRandomRare(final int n) {
final Predicate<PaperCard> myFilter = applyFormatFilter(QuestUtilCards.RARE_PREDICATE);
final List<PaperCard> newCards = Aggregates.random(Iterables.filter(FModel.getMagicDb().getCommonCards().getAllCards(), myFilter), n);
this.addAllCards(newCards);
return newCards;
}
/**
* Setup new game card pool.
*
* @param filter
* the filter
* @param idxDifficulty
* the idx difficulty
* @param userPrefs
* user preferences
*/
public void setupNewGameCardPool(final Predicate<PaperCard> filter, final int idxDifficulty, final StartingPoolPreferences userPrefs) {
final int nC = this.qpref.getPrefInt(DifficultyPrefs.STARTING_COMMONS, idxDifficulty);
final int nU = this.qpref.getPrefInt(DifficultyPrefs.STARTING_UNCOMMONS, idxDifficulty);
final int nR = this.qpref.getPrefInt(DifficultyPrefs.STARTING_RARES, idxDifficulty);
this.addAllCards(BoosterUtils.getQuestStarterDeck(filter, nC, nU, nR, userPrefs));
}
/**
* Buy card.
*
* @param card
* the card
* @param qty
* quantity
* @param value
* the value
*/
public void buyCard(final PaperCard card, int qty, final int value) {
int totalCost = qty * value;
if (this.qa.getCredits() >= totalCost) {
this.qa.setCredits(this.qa.getCredits() - totalCost);
this.qa.getShopList().remove(card, qty);
this.addSingleCard(card, qty);
}
}
/**
* Buy booster.
*
* @param booster
* the booster
* @param value
* the value
*/
public void buyPack(final SealedProduct booster, final int value) {
if (this.qa.getCredits() >= value) {
this.qa.setCredits(this.qa.getCredits() - value);
this.qa.getShopList().remove(booster);
this.addAllCards(booster.getCards());
}
}
/**
* Buy precon deck.
*
* @param precon
* the precon
* @param value
* the value
*/
public void buyPreconDeck(final PreconDeck precon, final int value) {
if (this.qa.getCredits() >= value) {
this.qa.setCredits(this.qa.getCredits() - value);
this.qa.getShopList().remove(precon);
this.addDeck(precon.getDeck());
}
}
/**
* Import an existing deck.
*
* @param fromDeck
* Deck, deck to import
*/
void addDeck(final Deck fromDeck) {
if (fromDeck == null) {
return;
}
this.qc.getMyDecks().add(fromDeck);
this.addAllCards(fromDeck.getMain().toFlatList());
if (fromDeck.has(DeckSection.Sideboard)) {
this.addAllCards(fromDeck.get(DeckSection.Sideboard).toFlatList());
}
}
/**
* Sell card.
*
* @param card
* the card
* @param qty
* quantity
* @param pricePerCard
* the price per card
*/
public void sellCard(final PaperCard card, int qty, final int pricePerCard) {
this.sellCard(card, qty, pricePerCard, true);
}
/**
* lose card.
*
* @param card
* the card
* @param qty
* quantity
*/
public void loseCards(final List<PaperCard> cards) {
for(PaperCard pc: cards)
this.sellCard(pc, 1, 0, this.qc.getAssets().getItemLevel(QuestItemType.CASH_STAKES) > 0);
}
/**
* Sell card.
*
* @param card
* the card
* @param price
* the price
* @param addToShop
* true if this card should be added to the shop, false otherwise
*/
private void sellCard(final PaperCard card, int qty, final int pricePerCard, final boolean addToShop) {
if (pricePerCard > 0) {
this.qa.setCredits(this.qa.getCredits() + (qty * pricePerCard));
}
this.qa.getCardPool().remove(card, qty);
if (addToShop) {
this.qa.getShopList().add(card, qty);
}
// remove card being sold from all decks
final int leftInPool = this.qa.getCardPool().count(card);
// remove sold cards from all decks:
for (final Deck deck : this.qc.getMyDecks()) {
int cntInMain = deck.getMain().count(card);
int cntInSb = deck.has(DeckSection.Sideboard) ? deck.get(DeckSection.Sideboard).count(card) : 0;
int nToRemoveFromThisDeck = cntInMain + cntInSb - leftInPool;
if (nToRemoveFromThisDeck <= 0) {
continue; // this is not the deck you are looking for
}
int nToRemoveFromSb = Math.min(cntInSb, nToRemoveFromThisDeck);
if (nToRemoveFromSb > 0) {
deck.get(DeckSection.Sideboard).remove(card, nToRemoveFromSb);
nToRemoveFromThisDeck -= nToRemoveFromSb;
if (0 >= nToRemoveFromThisDeck) {
continue; // done here
}
}
deck.getMain().remove(card, nToRemoveFromThisDeck);
}
}
/**
* Clear shop list.
*/
public void clearShopList() {
if (null != this.qa.getShopList()) {
this.qa.getShopList().clear();
}
}
/**
* Gets the sell mutliplier.
*
* @return the sell mutliplier
*/
public double getSellMultiplier() {
double multi = 0.20 + (0.001 * this.qc.getAchievements().getWin());
if (multi > 0.6) {
multi = 0.6;
}
final int lvlEstates = this.qc.getMode() == QuestMode.Fantasy ? this.qa.getItemLevel(QuestItemType.ESTATES) : 0;
switch (lvlEstates) {
case 1:
multi += 0.01;
break;
case 2:
multi += 0.0175;
break;
case 3:
multi += 0.025;
break;
default:
break;
}
return multi;
}
/**
* Gets the sell price limit.
*
* @return the sell price limit
*/
public int getSellPriceLimit() {
return this.qc.getAchievements().getWin() <= 50 ? 1000 : Integer.MAX_VALUE;
}
/**
* Generate cards in shop.
*/
private final GameFormat.Collection formats = FModel.getFormats();
private final Predicate<CardEdition> filterExt = this.formats.getExtended().editionLegalPredicate;
/** The filter t2booster. */
private final Predicate<CardEdition> filterT2booster = Predicates.and(CardEdition.Predicates.CAN_MAKE_BOOSTER,
this.formats.getStandard().editionLegalPredicate);
/** The filter ext but t2. */
private final Predicate<CardEdition> filterExtButT2 = Predicates.and(
CardEdition.Predicates.CAN_MAKE_BOOSTER,
Predicates.and(this.filterExt, this.formats.getStandard().editionLegalPredicate));
/** The filter not ext. */
private final Predicate<CardEdition> filterNotExt = Predicates.and(CardEdition.Predicates.CAN_MAKE_BOOSTER,
Predicates.not(this.filterExt));
/**
* Helper predicate for shops: is legal in quest format.
*
* @param qFormat
* the quest format
* @return the predicate
*/
public static Predicate<CardEdition> isLegalInQuestFormat(final GameFormatQuest qFormat) {
return GameFormatQuest.Predicates.isLegalInFormatQuest(qFormat);
}
/**
* Generate boosters in shop.
*
* @param count
* the count
*/
private void generateBoostersInShop(final int count) {
for (int i = 0; i < count; i++) {
final int rollD100 = MyRandom.getRandom().nextInt(100);
Predicate<CardEdition> filter = rollD100 < 40 ? this.filterT2booster
: (rollD100 < 75 ? this.filterExtButT2 : this.filterNotExt);
if (qc.getFormat() != null) {
filter = Predicates.and(CardEdition.Predicates.CAN_MAKE_BOOSTER, isLegalInQuestFormat(qc.getFormat()));
}
Iterable<CardEdition> rightEditions = Iterables.filter(FModel.getMagicDb().getEditions(), filter);
this.qa.getShopList().add(BoosterPack.FN_FROM_SET.apply(Aggregates.random(rightEditions)));
}
}
/**
* Generate precons in shop.
*
* @param count
* the count
*/
private void generateTournamentsInShop(final int count) {
Predicate<CardEdition> formatFilter = CardEdition.Predicates.HAS_TOURNAMENT_PACK;
if (qc.getFormat() != null) {
formatFilter = Predicates.and(formatFilter, isLegalInQuestFormat(qc.getFormat()));
}
Iterable<CardEdition> rightEditions = Iterables.filter(FModel.getMagicDb().getEditions(), formatFilter);
this.qa.getShopList().addAllFlat(Aggregates.random(Iterables.transform(rightEditions, TournamentPack.FN_FROM_SET), count));
}
/**
* Generate precons in shop.
*
* @param count
* the count
*/
private void generateFatPacksInShop(final int count) {
Predicate<CardEdition> formatFilter = CardEdition.Predicates.HAS_FAT_PACK;
if (qc.getFormat() != null) {
formatFilter = Predicates.and(formatFilter, isLegalInQuestFormat(qc.getFormat()));
}
Iterable<CardEdition> rightEditions = Iterables.filter(FModel.getMagicDb().getEditions(), formatFilter);
this.qa.getShopList().addAllFlat(Aggregates.random(Iterables.transform(rightEditions, FatPack.FN_FROM_SET), count));
}
/**
* Generate precons in shop.
*
* @param count
* the count
*/
private void generatePreconsInShop(final int count) {
final List<PreconDeck> meetRequirements = new ArrayList<PreconDeck>();
for (final PreconDeck deck : QuestController.getPrecons()) {
if (QuestController.getPreconDeals(deck).meetsRequiremnts(this.qc.getAchievements())
&& (null == qc.getFormat() || qc.getFormat().isSetLegal(deck.getEdition()))) {
meetRequirements.add(deck);
}
}
this.qa.getShopList().addAllFlat(Aggregates.random(meetRequirements, count));
}
@SuppressWarnings("unchecked")
private SealedProduct.Template getShopBoosterTemplate() {
return new SealedProduct.Template(Lists.newArrayList(
Pair.of(BoosterSlots.COMMON, this.qpref.getPrefInt(QPref.SHOP_SINGLES_COMMON)),
Pair.of(BoosterSlots.UNCOMMON, this.qpref.getPrefInt(QPref.SHOP_SINGLES_UNCOMMON)),
Pair.of(BoosterSlots.RARE_MYTHIC, this.qpref.getPrefInt(QPref.SHOP_SINGLES_RARE))
));
}
@SuppressWarnings("unchecked")
private SealedProduct.Template getBoosterTemplate() {
return new SealedProduct.Template(Lists.newArrayList(
Pair.of(BoosterSlots.COMMON, this.qpref.getPrefInt(QPref.BOOSTER_COMMONS)),
Pair.of(BoosterSlots.UNCOMMON, this.qpref.getPrefInt(QPref.BOOSTER_UNCOMMONS)),
Pair.of(BoosterSlots.RARE_MYTHIC, this.qpref.getPrefInt(QPref.BOOSTER_RARES))
));
}
/**
* Generate cards in shop.
*/
private void generateCardsInShop() {
// Preferences
final int startPacks = this.qpref.getPrefInt(QPref.SHOP_STARTING_PACKS);
final int winsForPack = this.qpref.getPrefInt(QPref.SHOP_WINS_FOR_ADDITIONAL_PACK);
final int maxPacks = this.qpref.getPrefInt(QPref.SHOP_MAX_PACKS);
int level = this.qc.getAchievements().getLevel();
final int levelPacks = level > 0 ? startPacks / level : startPacks;
final int winPacks = this.qc.getAchievements().getWin() / winsForPack;
final int totalPacks = Math.min(levelPacks + winPacks, maxPacks);
SealedProduct.Template tpl = getShopBoosterTemplate();
UnOpenedProduct unopened = qc.getFormat() == null ? new UnOpenedProduct(tpl) : new UnOpenedProduct(tpl, qc.getFormat().getFilterPrinted());
for (int i = 0; i < totalPacks; i++) {
this.qa.getShopList().addAllFlat(unopened.get());
}
this.generateBoostersInShop(totalPacks);
this.generatePreconsInShop(totalPacks);
this.generateTournamentsInShop(totalPacks);
this.generateFatPacksInShop(totalPacks);
int numberSnowLands = 5;
if (qc.getFormat() != null && !qc.getFormat().hasSnowLands()) {
numberSnowLands = 0;
}
this.qa.getShopList().addAll(QuestUtilCards.generateBasicLands(10, numberSnowLands, qc.getFormat()));
}
/**
* Gets the cardpool.
*
* @return the cardpool
*/
public ItemPool<PaperCard> getCardpool() {
return this.qa.getCardPool();
}
/**
* Gets the shop list.
*
* @return the shop list
*/
public ItemPool<InventoryItem> getShopList() {
if (this.qa.getShopList().isEmpty()) {
this.generateCardsInShop();
}
return this.qa.getShopList();
}
/**
* Gets the new cards.
*
* @return the new cards
*/
public ItemPool<InventoryItem> getNewCards() {
return this.qa.getNewCardList();
}
/**
* Reset new list.
*/
public void resetNewList() {
this.qa.getNewCardList().clear();
}
public Function<Entry<InventoryItem, Integer>, Comparable<?>> getFnNewCompare() {
return this.fnNewCompare;
}
public Function<Entry<? extends InventoryItem, Integer>, Object> getFnNewGet() {
return this.fnNewGet;
}
// These functions provide a way to sort and compare cards in a table
// according to their new-ness
// It might be a good idea to store them in a base class for both quest-mode
// deck editors
// Maybe we should consider doing so later
/** The fn new compare. */
private final Function<Entry<InventoryItem, Integer>, Comparable<?>> fnNewCompare =
new Function<Entry<InventoryItem, Integer>, Comparable<?>>() {
@Override
public Comparable<?> apply(final Entry<InventoryItem, Integer> from) {
return QuestUtilCards.this.qa.getNewCardList().contains(from.getKey()) ? Integer.valueOf(1) : Integer
.valueOf(0);
}
};
/** The fn new get. */
private final Function<Entry<? extends InventoryItem, Integer>, Object> fnNewGet =
new Function<Entry<? extends InventoryItem, Integer>, Object>() {
@Override
public Object apply(final Entry<? extends InventoryItem, Integer> from) {
return QuestUtilCards.this.qa.getNewCardList().contains(from.getKey()) ? "NEW" : "";
}
};
public Function<Entry<InventoryItem, Integer>, Comparable<?>> getFnOwnedCompare() {
return this.fnOwnedCompare;
}
public Function<Entry<? extends InventoryItem, Integer>, Object> getFnOwnedGet() {
return this.fnOwnedGet;
}
public int getCompletionPercent(String edition) {
// get all cards in the specified edition
Predicate<PaperCard> filter = IPaperCard.Predicates.printedInSet(edition);
Iterable<PaperCard> editionCards = Iterables.filter(FModel.getMagicDb().getCommonCards().getAllCards(), filter);
ItemPool<PaperCard> ownedCards = qa.getCardPool();
// 100% means at least one of every basic land and at least 4 of every other card in the set
int completeCards = 0;
int numOwnedCards = 0;
for (PaperCard card : editionCards) {
final int target = CardRarity.BasicLand == card.getRarity() ? 1 : 4;
completeCards += target;
numOwnedCards += Math.min(target, ownedCards.count(card));
}
return (numOwnedCards * 100) / completeCards;
}
// These functions provide a way to sort and compare items in the spell shop according to how many are already owned
private final Function<Entry<InventoryItem, Integer>, Comparable<?>> fnOwnedCompare =
new Function<Entry<InventoryItem, Integer>, Comparable<?>>() {
@Override
public Comparable<?> apply(final Entry<InventoryItem, Integer> from) {
InventoryItem i = from.getKey();
if (i instanceof PaperCard) {
return QuestUtilCards.this.qa.getCardPool().count((PaperCard) i);
} else if (i instanceof PreconDeck) {
PreconDeck pDeck = (PreconDeck) i;
return FModel.getQuest().getMyDecks().contains(pDeck.getName()) ? -1 : -2;
} else if (i instanceof SealedProduct) {
SealedProduct oPack = (SealedProduct) i;
return getCompletionPercent(oPack.getEdition()) - 103;
}
return null;
}
};
private final Function<Entry<? extends InventoryItem, Integer>, Object> fnOwnedGet =
new Function<Entry<? extends InventoryItem, Integer>, Object>() {
@Override
public Object apply(final Entry<? extends InventoryItem, Integer> from) {
InventoryItem i = from.getKey();
if (i instanceof PaperCard) {
return QuestUtilCards.this.qa.getCardPool().count((PaperCard) i);
} else if (i instanceof PreconDeck) {
PreconDeck pDeck = (PreconDeck) i;
return FModel.getQuest().getMyDecks().contains(pDeck.getName()) ? "YES" : "NO";
} else if (i instanceof SealedProduct) {
SealedProduct oPack = (SealedProduct) i;
return String.format("%d%%", getCompletionPercent(oPack.getEdition()));
}
return null;
}
};
}

View File

@@ -0,0 +1,202 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Nate
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.card.CardEdition;
import forge.card.UnOpenedProduct;
import forge.deck.Deck;
import forge.deck.FDeckViewer;
import forge.item.PaperCard;
import forge.item.SealedProduct;
import forge.model.FModel;
import forge.quest.io.ReadPriceList;
import forge.toolbox.FOptionPane;
import forge.toolbox.GuiChoose;
import forge.util.storage.IStorage;
import org.apache.commons.lang3.tuple.ImmutablePair;
import java.util.*;
/**
* This is a helper class for unlocking new sets during a format-limited
* quest.
*
*/
public class QuestUtilUnlockSets {
private static int UNLOCK_COST = 4000;
/**
* Consider unlocking a new expansion in limited quest format.
* @param qData the QuestController for the current quest
* @param freeUnlock this unlock is free (e.g., a challenge reward), NOT IMPLEMENTED YET
* @param presetChoices List<CardEdition> a pregenerated list of options, NOT IMPLEMENTED YET
* @return CardEdition, the unlocked edition if any.
*/
public static ImmutablePair<CardEdition, Integer> chooseSetToUnlock(final QuestController qData, final boolean freeUnlock,
List<CardEdition> presetChoices) {
if (qData.getFormat() == null || !qData.getFormat().canUnlockSets()) {
return null;
}
final ReadPriceList prices = new ReadPriceList();
final Map<String, Integer> mapPrices = prices.getPriceList();
final List<ImmutablePair<CardEdition, Integer>> setPrices = new ArrayList<ImmutablePair<CardEdition, Integer>>();
for (CardEdition ed : getUnlockableEditions(qData)) {
int price = UNLOCK_COST;
if (mapPrices.containsKey(ed.getName() + " Booster Pack")) {
price = Math.max(new Double(30 * Math.pow(Math.sqrt(mapPrices.get(ed.getName()
+ " Booster Pack")), 1.70)).intValue(), UNLOCK_COST);
}
setPrices.add(ImmutablePair.of(ed, price));
}
final String setPrompt = "You have " + qData.getAssets().getCredits() + " credits. Unlock:";
List<String> options = new ArrayList<String>();
for (ImmutablePair<CardEdition, Integer> ee : setPrices) {
options.add(String.format("%s [PRICE: %d credits]", ee.left.getName(), ee.right));
}
int index = options.indexOf(GuiChoose.oneOrNone(setPrompt, options));
if (index < 0 || index >= options.size()) {
return null;
}
ImmutablePair<CardEdition, Integer> toBuy = setPrices.get(index);
int price = toBuy.right;
CardEdition choosenEdition = toBuy.left;
if (qData.getAssets().getCredits() < price) {
FOptionPane.showMessageDialog("Unfortunately, you cannot afford that set yet.\n"
+ "To unlock " + choosenEdition.getName() + ", you need " + price + " credits.\n"
+ "You have only " + qData.getAssets().getCredits() + " credits.",
"Failed to unlock " + choosenEdition.getName(),
null);
return null;
}
if (!FOptionPane.showConfirmDialog(
"Unlocking " + choosenEdition.getName() + " will cost you " + price + " credits.\n"
+ "You have " + qData.getAssets().getCredits() + " credits.\n\n"
+ "Are you sure you want to unlock " + choosenEdition.getName() + "?",
"Confirm Unlocking " + choosenEdition.getName())) {
return null;
}
return toBuy;
}
/**
* Helper function for unlockSet().
*
* @return unmodifiable list, assorted sets that are not currently in the format.
*/
private static final List<CardEdition> emptyEditions = ImmutableList.<CardEdition>of();
private static final EnumSet<CardEdition.Type> unlockableSetTypes =
EnumSet.of(CardEdition.Type.CORE, CardEdition.Type.EXPANSION, CardEdition.Type.REPRINT, CardEdition.Type.STARTER);
private static List<CardEdition> getUnlockableEditions(final QuestController qData) {
if (qData.getFormat() == null || !qData.getFormat().canUnlockSets()) {
return emptyEditions;
}
if (qData.getUnlocksTokens() < 1) { // Should never happen if we made it this far but better safe than sorry...
throw new RuntimeException("BUG? Could not find unlockable sets even though we should.");
}
List<CardEdition> options = new ArrayList<CardEdition>();
// Sort current sets by date
List<CardEdition> allowedSets = Lists.newArrayList(Iterables.transform(qData.getFormat().getAllowedSetCodes(), FModel.getMagicDb().getEditions().FN_EDITION_BY_CODE));
Collections.sort(allowedSets);
// Sort unlockable sets by date
List<CardEdition> excludedSets = Lists.newArrayList(Iterables.transform(qData.getFormat().getLockedSets(), FModel.getMagicDb().getEditions().FN_EDITION_BY_CODE));
Collections.sort(excludedSets);
// get a number of sets between an excluded and any included set
List<ImmutablePair<CardEdition, Long>> excludedWithDistances = new ArrayList<ImmutablePair<CardEdition, Long>>();
for (CardEdition ex : excludedSets) {
if (!unlockableSetTypes.contains(ex.getType())) // don't add non-traditional sets
continue;
long distance = Long.MAX_VALUE;
for (CardEdition in : allowedSets) {
long d = (Math.abs(ex.getDate().getTime() - in.getDate().getTime()));
if (d < distance) {
distance = d;
}
}
excludedWithDistances.add(ImmutablePair.of(ex, distance));
}
// sort by distance, then by code desc
Collections.sort(excludedWithDistances, new Comparator<ImmutablePair<CardEdition, Long>>() {
@Override
public int compare(ImmutablePair<CardEdition, Long> o1, ImmutablePair<CardEdition, Long> o2) {
long delta = o2.right - o1.right;
return delta < 0 ? -1 : delta == 0 ? 0 : 1;
}
});
for (ImmutablePair<CardEdition, Long> set : excludedWithDistances) {
options.add(set.left);
// System.out.println("Padded with: " + fillers.get(i).getName());
}
Collections.reverse(options);
return options.subList(0, Math.min(options.size(), Math.min(8, 2 + ((qData.getAchievements().getWin()) / 50))));
}
/**
*
* Unlock a set and get some free cards, if a tournament pack or boosters are available.
* @param qData the quest controller
* @param unlockedSet the edition to unlock
*/
public static void doUnlock(QuestController qData, final CardEdition unlockedSet) {
IStorage<SealedProduct.Template> starters = FModel.getMagicDb().getTournamentPacks();
IStorage<SealedProduct.Template> boosters = FModel.getMagicDb().getBoosters();
qData.getFormat().unlockSet(unlockedSet.getCode());
List<PaperCard> cardsWon = new ArrayList<PaperCard>();
if (starters.contains(unlockedSet.getCode())) {
UnOpenedProduct starter = new UnOpenedProduct(starters.get(unlockedSet.getCode()));
cardsWon.addAll(starter.get());
}
else if (boosters.contains(unlockedSet.getCode())) {
UnOpenedProduct booster = new UnOpenedProduct(boosters.get(unlockedSet.getCode()));
cardsWon.addAll(booster.get());
cardsWon.addAll(booster.get());
cardsWon.addAll(booster.get());
}
qData.getCards().addAllCards(cardsWon);
Deck deck = new Deck(unlockedSet.getName() + " - You get the following bonus cards:");
deck.getMain().addAllFlat(cardsWon);
FDeckViewer.show(deck);
qData.save();
}
}

View File

@@ -0,0 +1,184 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Nate
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest;
import com.google.common.base.Function;
import forge.quest.data.GameFormatQuest;
import forge.util.storage.StorageReaderFile;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* This function holds the "world info" for the current quest.
*
*/
public class QuestWorld implements Comparable<QuestWorld>{
private final String name;
private final String dir;
private final GameFormatQuest format;
/**
* Instantiate a new quest world.
* @param useIdx int, the quest world internal identifier
* @param useName String, the display name for the world
* @param useDir String, the basedir that contains the duels and challenges for the quest world
* @param useFormat GameFormatQuest that contains the initial format for the world
*/
public QuestWorld(final String useName, final String useDir, final GameFormatQuest useFormat) {
name = useName;
dir = useDir;
format = useFormat;
}
/**
* The quest world display name.
* @return String, the display name
*/
public String getName() {
return name;
}
/**
* The quest world duels directory.
* @return String, the duels directory
*/
public String getDuelsDir() {
return dir == null ? null : dir + "/duels";
}
/**
* The quest world challenges directory.
* @return String, the challenges directory
*/
public String getChallengesDir() {
return dir == null ? null : dir + "/challenges";
}
/**
* The quest world format if specified.
* @return GameFormatQuest, the format
*/
public GameFormatQuest getFormat() {
return format;
}
/**
* <p>
* toString.
* </p>
*
* @return a {@link java.lang.String} object.
*/
@Override
public final String toString() {
return this.getName();
}
/**
* FN_GET_NAME for reader.
*/
public static final Function<QuestWorld, String> FN_GET_NAME = new Function<QuestWorld, String>() {
@Override
public String apply(QuestWorld arg1) {
return arg1.getName();
}
};
/**
* Class for reading world definitions.
*/
public static class Reader extends StorageReaderFile<QuestWorld> {
/**
* TODO: Write javadoc for Constructor.
* @param file0
* @param keySelector0
*/
public Reader(String file0) {
super(file0, QuestWorld.FN_GET_NAME);
}
/* (non-Javadoc)
* @see forge.util.StorageReaderFile#read(java.lang.String)
*/
@Override
protected QuestWorld read(String line, int i) {
String useName = null;
String useDir = null;
GameFormatQuest useFormat = null;
final List<String> sets = new ArrayList<String>();
final List<String> bannedCards = new ArrayList<String>(); // if both empty, no format
// This is what you need to use here =>
// FileSection.parse(line, ":", "|");
final String[] sParts = line.trim().split("\\|");
for (final String sPart : sParts) {
final String[] kv = sPart.split(":", 2);
final String key = kv[0].toLowerCase();
if ("name".equals(key)) {
useName = kv[1];
} else if ("dir".equals(key)) {
useDir = kv[1];
} else if ("sets".equals(key)) {
sets.addAll(Arrays.asList(kv[1].split(", ")));
} else if ("banned".equals(key)) {
bannedCards.addAll(Arrays.asList(kv[1].split("; ")));
}
}
if (useName == null) {
throw new RuntimeException("A Quest World must have a name! Check worlds.txt file");
}
if (!sets.isEmpty() || !bannedCards.isEmpty()) {
useFormat = new GameFormatQuest(useName, sets, bannedCards);
}
// System.out.println("Creating quest world " + useName + " (index " + useIdx + ", dir: " + useDir);
// if (useFormat != null) { System.out.println("SETS: " + sets + "\nBANNED: " + bannedCards); }
return new QuestWorld(useName, useDir, useFormat);
}
}
/* (non-Javadoc)
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
@Override
public int compareTo(QuestWorld other) {
if (null == other) {
return 1;
}
if (name == other.name) {
return 0;
}
if (null == name) {
return -1;
}
return name.compareTo(other.name);
}
}

View File

@@ -0,0 +1,88 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest;
import forge.quest.data.QuestAchievements;
import forge.util.FileSection;
import java.util.List;
/**
* TODO: Write javadoc for this type.
*
*/
public class SellRules {
private int minWins = 0;
private int cost = 250;
private int minDifficulty = 0;
private int maxDifficulty = 5;
/**
* Instantiates a new sell rules.
*
* @param questShop the quest shop
*/
public SellRules(List<String> questShop) {
if (null == questShop || questShop.isEmpty()) {
return;
}
FileSection section = FileSection.parse(questShop, "=");
minWins = section.getInt("WinsToUnlock");
cost = section.getInt("Credits", 250);
maxDifficulty = section.getInt("MaxDifficulty", 5);
minDifficulty = section.getInt("MinDifficulty", 0);
}
/**
* Meets requiremnts.
*
* @param quest the quest
* @return true, if successful
*/
public boolean meetsRequiremnts(QuestAchievements quest) {
if (quest.getWin() < minWins) {
return false;
}
if (quest.getDifficulty() < minDifficulty || quest.getDifficulty() > maxDifficulty) {
return false;
}
return true;
}
/**
* Gets the cost.
*
* @return the cost
*/
public final int getCost() {
return cost;
}
/**
* Gets the minWins.
*
* @return the minWins
*/
public final int getMinWins() {
return minWins;
}
}

View File

@@ -0,0 +1,61 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Nate
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest;
/**
* This class is used to store the Quest starting pool preferences.
* (It could be expanded to store other Quest starting preferences as well,
* in order to reduce the number of parameters that need to be passed to
* QuestController.newGame from CSubmenuQuestData)
*
*/
public final class StartingPoolPreferences {
private final boolean randomPool;
private final byte preferredColor;
/**
* The constructor.
* @param random
* true = use completely random pool without filter restrictions
* (Note that this does NOT bypass card rarity restrictions!)
* @param preference
* preferred color/COLORLESS (ALL_COLORS = no preference)
*/
public StartingPoolPreferences(final boolean random, final byte preference) {
randomPool = random;
preferredColor = preference;
}
/**
* Is the starting pool completely random?
* @return boolean, true if the starting pool is completely random (except for rarity)
*/
public boolean useRandomPool() {
return randomPool;
}
/**
* Get the preferred starting pool color.
* Return ALL_COLORS if no preference set.
* @return MagicColor
*/
public byte getPreferredColor() {
return preferredColor;
}
}

View File

@@ -0,0 +1,25 @@
package forge.quest;
public enum StartingPoolType {
Complete("Unrestricted"),
Rotating("Sanctioned format"),
CustomFormat("Custom format"),
Precon("Event or starter deck"),
SealedDeck("My sealed deck"),
DraftDeck("My draft deck"),
Cube("Predefined cube");
private final String caption;
private StartingPoolType(String caption0) {
caption = caption0;
}
/* (non-Javadoc)
* @see java.lang.Enum#toString()
*/
@Override
public String toString() {
return caption;
}
}

View File

@@ -0,0 +1,89 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest.bazaar;
import forge.assets.FImage;
import forge.quest.data.QuestAssets;
/**
* This interface defines a thing that can be sold at the Bazaar.
*
* @author Forge
* @version $Id: IQuestBazaarItem.java 23229 2013-09-16 08:18:19Z drdev $
*/
public interface IQuestBazaarItem extends Comparable<Object> {
/**
* <p>
* getPurchaseName.
* </p>
*
* @return The Name of the item
*/
String getPurchaseName();
/**
* <p>
* getPurchaseDescription.
* </p>
*
* @return an HTML formatted item description
*/
String getPurchaseDescription(QuestAssets qA);
/**
* <p>
* getIcon.
* </p>
*
* @return the icon that is displayed in the bazaar
*/
FImage getIcon(QuestAssets qA);
/**
* <p>
* getPrice.
* </p>
*
* @return the buying cost of the item in credits
*/
int getBuyingPrice(QuestAssets qA);
/**
* <p>
* getPrice.
* </p>
*
* @return the selling cost of the item in credits
*/
int getSellingPrice(QuestAssets qA);
/**
* Returns if the item is available for purchase;.
*
* @return <code>true</code> if the item can be displayed in a store
* <code>false</code> if the item should not be displayed in store
* since, for example, prerequisites are not met
*/
boolean isAvailableForPurchase(QuestAssets questAssets);
/**
* Executed when the item is bought.
* @param questAssets
*/
void onPurchase(QuestAssets questAssets);
}

View File

@@ -0,0 +1,185 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest.bazaar;
import com.thoughtworks.xstream.XStream;
import forge.model.FModel;
import forge.quest.QuestController;
import forge.quest.data.QuestAssets;
import forge.utils.IgnoringXStream;
import forge.utils.XmlUtil;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.util.*;
/**
* <p>
* QuestStallManager class.
* </p>
*
* @author Forge
* @version $Id: QuestBazaarManager.java 24769 2014-02-09 13:56:04Z Hellfish $
*/
public class QuestBazaarManager {
private final File xmlFile;
public QuestBazaarManager(File xmlFile0) {
xmlFile = xmlFile0;
}
public void load() {
DocumentBuilder builder;
try {
builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
final Document document = builder.parse(xmlFile);
XStream xs = new IgnoringXStream();
xs.autodetectAnnotations(true);
NodeList xmlStalls = document.getElementsByTagName("stalls").item(0).getChildNodes();
for (int iN = 0; iN < xmlStalls.getLength(); iN++) {
Node n = xmlStalls.item(iN);
if (n.getNodeType() != Node.ELEMENT_NODE) { continue; }
Attr att = document.createAttribute("resolves-to");
att.setValue(QuestStallDefinition.class.getCanonicalName());
n.getAttributes().setNamedItem(att);
QuestStallDefinition stall = (QuestStallDefinition) xs.fromXML(XmlUtil.nodeToString(n));
stalls.put(stall.getName(), stall);
}
NodeList xmlQuestItems = document.getElementsByTagName("questItems").item(0).getChildNodes();
for (int iN = 0; iN < xmlQuestItems.getLength(); iN++) {
Node n = xmlQuestItems.item(iN);
if (n.getNodeType() != Node.ELEMENT_NODE) { continue; }
NamedNodeMap attrs = n.getAttributes();
String sType = attrs.getNamedItem("itemType").getTextContent();
String name = attrs.getNamedItem("name").getTextContent();
QuestItemType qType = QuestItemType.smartValueOf(sType);
Attr att = document.createAttribute("resolves-to");
att.setValue(qType.getBazaarControllerClass().getCanonicalName());
attrs.setNamedItem(att);
QuestItemBasic ctrl = (QuestItemBasic) xs.fromXML(XmlUtil.nodeToString(n));
items.put(name, ctrl);
}
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
}
/** Constant <code>stalls</code>. */
private final Map<String, QuestStallDefinition> stalls = new TreeMap<String, QuestStallDefinition>();
/** Constant <code>items</code>. */
private final Map<String, SortedSet<IQuestBazaarItem>> itemsOnStalls = new TreeMap<String, SortedSet<IQuestBazaarItem>>(String.CASE_INSENSITIVE_ORDER);
private final Map<String, IQuestBazaarItem> items = new TreeMap<String, IQuestBazaarItem>();
/**
* <p>
* getStall.
* </p>
*
* @param stallName
* a {@link java.lang.String} object.
* @return a {@link forge.quest.bazaar.QuestStallDefinition} object.
*/
public QuestStallDefinition getStall(final String stallName) {
if (stalls.isEmpty()) {
load();
}
return stalls.get(stallName);
}
/**
* Retrieves all creatures and items, iterates through them,
* and maps to appropriate merchant.
*/
public void buildItems(final QuestController qCtrl) {
final Map<String, IQuestBazaarItem> itemSet = new HashMap<String, IQuestBazaarItem>();
for (int iSlot = 0; iSlot < QuestController.MAX_PET_SLOTS; iSlot++) {
for (QuestPetController pet : qCtrl.getPetsStorage().getAllPets(iSlot)) {
//System.out.println("Pet: " + pet.getName());
itemSet.put(pet.getName(), pet);
}
}
itemSet.putAll(items);
itemsOnStalls.clear();
for (QuestStallDefinition thisStall : stalls.values()) {
TreeSet<IQuestBazaarItem> set = new TreeSet<IQuestBazaarItem>();
for (String itemName : thisStall.getItems()) {
IQuestBazaarItem item = itemSet.get(itemName);
//System.out.println(itemName);
set.add(item);
}
itemsOnStalls.put(thisStall.getName(), set);
}
}
/**
* Returns <i>purchasable</i> items available for a particular stall.
*
* @param stallName &emsp; {@link java.lang.String}
* @return {@link java.util.List}.
*/
public List<IQuestBazaarItem> getItems(final QuestController qCtrl, final String stallName) {
buildItems(qCtrl);
final List<IQuestBazaarItem> ret = new ArrayList<IQuestBazaarItem>();
QuestAssets qA = FModel.getQuest().getAssets();
for (final IQuestBazaarItem purchasable : itemsOnStalls.get(stallName)) {
if (purchasable.isAvailableForPurchase(qA)) {
ret.add(purchasable);
}
}
return ret;
}
/**
* TODO: Write javadoc for this method.
* @return
*/
public Set<String> getStallNames() {
if (stalls.isEmpty()) {
load();
}
return stalls.keySet();
}
}

View File

@@ -0,0 +1,194 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest.bazaar;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import forge.assets.FImage;
import forge.quest.data.QuestAssets;
import org.apache.commons.lang3.StringUtils;
/**
* <p>
* Abstract QuestItemAbstract class.
* </p>
*
* @author Forge
* @version $Id: QuestItemBasic.java 24769 2014-02-09 13:56:04Z Hellfish $
*/
public class QuestItemBasic implements IQuestBazaarItem {
@XStreamAsAttribute
private QuestItemType itemType;
/**
* Gets the item type.
*
* @return the item type
*/
public final QuestItemType getItemType() {
return this.itemType;
}
@XStreamAsAttribute
private int maxLevel = 1;
@XStreamAsAttribute
private String purchaseName = null;
private String description = "Read from XML";
@XStreamAsAttribute
private int basePrice = 1000;
/**
* Gets the base price.
*
* @return the base price
*/
protected final int getBasePrice() {
return this.basePrice;
}
@XStreamAsAttribute
private final FImage icon = null;
/**
* <p>
* Constructor for QuestItemAbstract.
* </p>
*
* @param type0 the type0
*/
protected QuestItemBasic(final QuestItemType type0) {
this.itemType = type0;
}
/**
* This is the name shared across all item levels e.g., "Estates".
*
* @return a {@link java.lang.String} object.
*/
public final String getName() {
return this.itemType.getKey();
}
/**
* This is the name used in purchasing the item e.g.,"Estates Training 1".
*
* @return a {@link java.lang.String} object.
*/
@Override
public String getPurchaseName() {
return StringUtils.isBlank(this.purchaseName) ? this.getName() : this.purchaseName;
}
/**
* This method will be invoked when an item is bought in a shop.
*
* @param qA the q a
*/
@Override
public void onPurchase(final QuestAssets qA) {
final int currentLevel = qA.getItemLevel(this.itemType);
qA.setItemLevel(this.itemType, currentLevel + 1);
}
/**
* <p>
* isAvailableForPurchase.
* </p>
*
* @param qA the q a
* @return a boolean.
*/
@Override
public boolean isAvailableForPurchase(final QuestAssets qA) {
return qA.getItemLevel(this.itemType) < this.maxLevel;
}
/**
* <p>
* Getter for the field <code>maxLevel</code>.
* </p>
*
* @return a int.
*/
public final int getMaxLevel() {
return this.maxLevel;
}
/**
* <p>
* isLeveledItem.
* </p>
*
* @return a boolean.
*/
public final boolean isLeveledItem() {
return this.maxLevel == 1;
}
/**
* <p>
* getPurchaseDescription.
* </p>
*
* @param qA the q a
* @return a {@link java.lang.String} object.
*/
@Override
public String getPurchaseDescription(final QuestAssets qA) {
return this.description;
}
@Override
public FImage getIcon(QuestAssets qA) {
return this.icon;
}
/**
* Gets the buying price.
*
* @param qA the q a
* @return a int.
*/
@Override
public int getBuyingPrice(final QuestAssets qA) {
return this.basePrice;
}
/**
* Gets the selling price.
*
* @param qA the q a
* @return a int.
*/
@Override
public int getSellingPrice(final QuestAssets qA) {
return 0;
}
/** {@inheritDoc} */
@Override
public final int compareTo(final Object o) {
final IQuestBazaarItem q = (IQuestBazaarItem) o;
return this.getPurchaseName().compareTo(q.getPurchaseName());
}
}

View File

@@ -0,0 +1,47 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest.bazaar;
import forge.quest.data.QuestAssets;
/**
* <p>
* QuestItemAmuletOfEndurance class.
* </p>
*
* @author Forge
* @version $Id: QuestItemZeppelin.java 14797 2012-03-18 18:09:02Z Max mtg $
*/
public class QuestItemCharmOfVigor extends QuestItemBasic {
/**
* <p>
* Constructor for QuestItemAmuletOfEndurance.
* </p>
*/
QuestItemCharmOfVigor() {
super(QuestItemType.CHARM); // , QuestStallManager.GEAR
}
/** {@inheritDoc} */
@Override
public final boolean isAvailableForPurchase(QuestAssets qA) {
return super.isAvailableForPurchase(qA);
}
}

View File

@@ -0,0 +1,53 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest.bazaar;
import forge.quest.data.QuestAssets;
/**
* This item has special coding.
*
* @author Forge
* @version $Id$
*/
public class QuestItemElixir extends QuestItemBasic {
/**
* <p>
* Constructor for QuestItemElixir.
* </p>
*/
QuestItemElixir() {
super(QuestItemType.ELIXIR_OF_LIFE); // QuestStallManager.ALCHEMIST,
}
/** {@inheritDoc} */
@Override
public final int getBuyingPrice(QuestAssets qA) {
int level = qA.getItemLevel(this.getItemType());
if (level < 5) {
return super.getBasePrice();
} else if (level < 10) {
return super.getBasePrice() * 2;
} else if (level <= this.getMaxLevel()) {
return super.getBasePrice() * 3;
} else {
return 0;
}
}
}

View File

@@ -0,0 +1,54 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest.bazaar;
import forge.quest.data.QuestAssets;
/**
* <p>
* QuestItemEstates class.
* </p>
*
* @author Forge
* @version $Id: QuestItemEstates.java 14797 2012-03-18 18:09:02Z Max mtg $
*/
public class QuestItemEstates extends QuestItemBasic {
/**
* <p>
* Constructor for QuestItemEstates.
* </p>
*/
QuestItemEstates() {
super(QuestItemType.ESTATES); // QuestStallManager.BANKER,
}
/** {@inheritDoc} */
@Override
public final String getPurchaseDescription(QuestAssets qA) {
return String.format(super.getPurchaseDescription(qA),
(10 + (qA.getItemLevel(this.getItemType()) * 5)),
(1 + (qA.getItemLevel(this.getItemType()) * 0.75)));
}
/** {@inheritDoc} */
@Override
public final int getBuyingPrice(QuestAssets qA) {
int level = qA.getItemLevel(this.getItemType());
return getBasePrice() * (2 + level);
}
}

View File

@@ -0,0 +1,66 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest.bazaar;
import forge.quest.QuestMode;
import forge.quest.data.QuestAssets;
/**
* This item has special coding.
*
* @author Forge
* @version $Id: QuestItemElixir.java 13728 2012-02-01 11:13:34Z moomarc $
*/
public class QuestItemPoundFlesh extends QuestItemBasic {
/**
* <p>
* Constructor for QuestItemElixir.
* </p>
*/
QuestItemPoundFlesh() {
super(QuestItemType.POUND_FLESH); // QuestStallManager.ALCHEMIST,
}
/** {@inheritDoc} */
@Override
public final String getPurchaseDescription(QuestAssets qA) {
return String.format(super.getPurchaseDescription(qA), getSellingPrice(qA));
}
/** {@inheritDoc} */
@Override
public final int getBuyingPrice(QuestAssets qA) {
return 0;
}
/** {@inheritDoc} */
@Override
public final int getSellingPrice(QuestAssets qA) {
int level = qA.getItemLevel(this.getItemType());
if (qA.getLife(QuestMode.Fantasy) < 2) {
return 0;
} else if (level < 5) {
return this.getBasePrice();
} else if (level < 10) {
return this.getBasePrice() * 2;
} else {
return this.getBasePrice() * 3;
}
}
}

View File

@@ -0,0 +1,129 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Nate
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest.bazaar;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import forge.quest.data.QuestItemCondition;
/**
* TODO: Write javadoc for this type.
*
*/
@XStreamAlias(value = "forge.quest.data.item.QuestItemType")
public enum QuestItemType {
/** The SLEIGHT. */
SLEIGHT("Sleight", QuestItemBasic.class, QuestItemCondition.class),
/** The ESTATES. */
ESTATES("Estates", QuestItemEstates.class, QuestItemCondition.class),
/** The LUCKY_COIN. */
LUCKY_COIN("Lucky Coin", QuestItemBasic.class, QuestItemCondition.class),
/** The MAP. */
MAP("Map", QuestItemBasic.class, QuestItemCondition.class),
/** The ZEPPELIN. */
ZEPPELIN("Zeppelin", QuestItemZeppelin.class, QuestItemCondition.class),
/** The ELIXIR_OF_LIFE. */
ELIXIR_OF_LIFE("Elixir of Life", QuestItemElixir.class, QuestItemCondition.class),
/** The POUND_FLESH. */
POUND_FLESH("Pound of Flesh", QuestItemPoundFlesh.class, QuestItemCondition.class),
/** The AMULET. */
CHARM("Charm of Vigor", QuestItemCharmOfVigor.class, QuestItemCondition.class),
CASH_STAKES("Cash Stakes", QuestItemBasic.class, QuestItemCondition.class);
private final String saveFileKey;
private final Class<? extends QuestItemBasic> bazaarControllerClass;
private final Class<? extends QuestItemCondition> modelClass;
private QuestItemType(final String key, final Class<? extends QuestItemBasic> controllerClass0,
final Class<? extends QuestItemCondition> modelClass0) {
this.saveFileKey = key;
this.bazaarControllerClass = controllerClass0;
this.modelClass = modelClass0;
}
/**
* TODO: Write javadoc for this method.
*
* @return the key
*/
public String getKey() {
return this.saveFileKey;
}
/**
* Gets the bazaar controller class.
*
* @return the bazaar controller class
*/
public Class<? extends QuestItemBasic> getBazaarControllerClass() {
return this.bazaarControllerClass;
}
/**
* Gets the model class.
*
* @return the model class
*/
public Class<? extends QuestItemCondition> getModelClass() {
return this.modelClass;
}
/**
* Smart value of.
*
* @param value the value
* @return the quest item type
*/
public static QuestItemType smartValueOf(final String value) {
if (value == null) {
return null;
}
if ("All".equals(value)) {
return null;
}
final String valToCompate = value.trim();
for (final QuestItemType v : QuestItemType.values()) {
if (v.name().compareToIgnoreCase(valToCompate) == 0) {
return v;
}
}
throw new IllegalArgumentException("No element named " + value + " in enum QuestItemType");
}
/**
* Value from save key.
*
* @param name the name
* @return the quest item type
*/
public static QuestItemType valueFromSaveKey(final String name) {
if (name == null) {
return null;
}
final String valToCompate = name.trim();
for (final QuestItemType v : QuestItemType.values()) {
if (v.getKey().compareToIgnoreCase(valToCompate) == 0) {
return v;
}
}
throw new IllegalArgumentException("No element keyed " + name + " in enum QuestItemType");
}
}

View File

@@ -0,0 +1,47 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest.bazaar;
import forge.quest.data.QuestAssets;
/**
* <p>
* QuestItemZeppelin class.
* </p>
*
* @author Forge
* @version $Id: QuestItemZeppelin.java 14797 2012-03-18 18:09:02Z Max mtg $
*/
public class QuestItemZeppelin extends QuestItemBasic {
/**
* <p>
* Constructor for QuestItemZeppelin.
* </p>
*/
QuestItemZeppelin() {
super(QuestItemType.ZEPPELIN); // , QuestStallManager.GEAR
}
/** {@inheritDoc} */
@Override
public final boolean isAvailableForPurchase(QuestAssets qA) {
return super.isAvailableForPurchase(qA) && qA.hasItem(QuestItemType.MAP);
}
}

View File

@@ -0,0 +1,277 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest.bazaar;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import forge.assets.FImage;
import forge.assets.FTextureImage;
import forge.item.PaperToken;
import forge.quest.data.QuestAssets;
import forge.utils.Constants;
import java.util.ArrayList;
import java.util.List;
/**
* <p>
* Abstract QuestPetAbstract class.
* </p>
* It's not good to store in a single class pets properties and bazaar sellable
* - such is a tradeoff for speed of development
*
* @author Forge
* @version $Id: QuestPetController.java 24769 2014-02-09 13:56:04Z Hellfish $
*/
public class QuestPetController implements IQuestBazaarItem {
/** The level. */
@XStreamAsAttribute()
private final int maxLevel;
private final List<QuestPetStats> levels = new ArrayList<QuestPetStats>();
@XStreamAsAttribute()
private final String name;
@XStreamAlias(value = "desc")
private final String description;
@XStreamAsAttribute()
private final String saveFileKey;
@XStreamAsAttribute()
private int slot;
/**
*
* TODO: Write javadoc for this method.
* @param qA quest assets
* @return int
*/
protected int getPetLevel(final QuestAssets qA) {
final int level = qA.getPetLevel(this.saveFileKey);
return level < 0 ? 0 : level > this.maxLevel ? this.maxLevel : level;
}
/**
* <p>
* getPetCard.
* </p>
* @param qA quest assets
* @return a {@link forge.game.card.Card} object.
*/
public PaperToken getPetCard(final QuestAssets qA) {
return this.levels.get(this.getPetLevel(qA)).getCard();
}
/**
* <p>
* getPrice.
* </p>
* @param qA quest assets
* @return a int.
*/
@Override
public final int getBuyingPrice(final QuestAssets qA) {
final int level = this.getPetLevel(qA);
// we'll buy next level
return level >= this.maxLevel ? -1 /* cannot buy */ : this.levels.get(level + 1).getCost();
}
/** {@inheritDoc} */
@Override
public final int getSellingPrice(final QuestAssets qA) {
return 0;
}
/**
* <p>
* getUpgradeDescription.
* </p>
* @param qA quest assets
* @return a {@link java.lang.String} object.
*/
public final String getUpgradeDescription(final QuestAssets qA) {
return this.levels.get(this.getPetLevel(qA)).getNextLevel();
}
/**
* <p>
* getIcon.
* </p>
* @param qA quest assets
*/
@Override
public final FImage getIcon(final QuestAssets qA) {
final String path = Constants.CACHE_TOKEN_PICS_DIR;
final int level = this.getPetLevel(qA);
Texture texture = new Texture(Gdx.files.absolute(path + this.levels.get(level < this.maxLevel ? level + 1 : level).getPicture() + ".jpg"));
return new FTextureImage(texture);
}
/**
* <p>
* getStats.
* </p>
* @param qA quest assets
* @return a {@link java.lang.String} object.
*/
public final String getStats(final QuestAssets qA) {
return this.levels.get(this.getPetLevel(qA)).getStats();
}
/**
* <p>
* getUpgradedStats.
* </p>
* @param qA quest assets
* @return a {@link java.lang.String} object.
*/
public final String getUpgradedStats(final QuestAssets qA) {
final int level = this.getPetLevel(qA);
return level >= this.maxLevel ? "N/A" : this.levels.get(level + 1).getStats();
}
/**
* <p>
* Getter for the field <code>maxLevel</code>.
* </p>
*
* @return a int.
*/
public final int getMaxLevel() {
return this.maxLevel;
}
// Never to be called, instances will be read from xml
private QuestPetController() {
this.description = null;
this.name = null;
this.maxLevel = 0;
this.saveFileKey = null;
}
/**
* <p>
* getPurchaseDescription.
* </p>
* @param qA quest assets
* @return a {@link java.lang.String} object.
*/
@Override
public final String getPurchaseDescription(final QuestAssets qA) {
return this.getDescription() + "\n\nCurrent stats: " + this.getStats(qA) + "\nUpgraded stats: "
+ this.getUpgradedStats(qA);
}
/**
* <p>
* Getter for the field <code>description</code>.
* </p>
*
* @return a {@link java.lang.String} object.
*/
public final String getDescription() {
return this.description;
}
/**
* <p>
* Getter for the field <code>name</code>.
* </p>
*
* @return a {@link java.lang.String} object.
*/
public final String getName() {
return this.name;
}
/** {@inheritDoc} */
@Override
public final String toString() {
return this.name;
}
/** {@inheritDoc} */
@Override
public final int compareTo(final Object o) {
return this.name.compareTo(o.toString());
}
/**
* <p>
* getPurchaseName.
* </p>
*
* @return a {@link java.lang.String} object.
*/
@Override
public final String getPurchaseName() {
return this.name;
}
// @Override
// public String getStallName() {
// return QuestStallManager.PET_SHOP;
// }
/**
* <p>
* isAvailableForPurchase.
* </p>
* @param qA quest assets
* @return a boolean.
*/
@Override
public boolean isAvailableForPurchase(final QuestAssets qA) {
return this.getPetLevel(qA) < this.getMaxLevel();
}
/**
* <p>
* onPurchase.
* </p>
* @param qA quest assets
*/
@Override
public void onPurchase(final QuestAssets qA) {
qA.setPetLevel(this.saveFileKey, this.getPetLevel(qA) + 1);
}
/**
*
* TODO: Write javadoc for this method.
* @return String
*/
public String getSaveFileKey() {
return this.saveFileKey;
}
/**
* TODO: Write javadoc for this method.
*
* @return int
*/
public int getSlot() {
return this.slot;
}
}

View File

@@ -0,0 +1,71 @@
package forge.quest.bazaar;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import forge.card.CardEdition;
import forge.card.CardRules;
import forge.item.PaperToken;
import forge.util.FileUtil;
import forge.utils.Constants;
import java.io.File;
import java.util.List;
@XStreamAlias(value = "level")
public class QuestPetStats {
@XStreamAsAttribute()
@XStreamAlias(value = "value")
private int levelValue;
@XStreamAsAttribute()
@XStreamAlias(value = "pic")
private String picture;
@XStreamAsAttribute()
private String stats;
@XStreamAsAttribute()
private String cardFile;
@XStreamAsAttribute()
private int cost;
@XStreamAsAttribute()
private String nextLevel;
private transient PaperToken petCard = null;
private QuestPetStats() { }
public final int getLevelValue() {
return levelValue;
}
public final String getPicture() {
return picture;
}
public final String getStats() {
return stats;
}
public final PaperToken getCard() {
if (null == petCard) {
List<String> cardLines = FileUtil.readFile(new File(Constants.CARD_DATA_PETS_DIR, cardFile));
CardRules rules = CardRules.fromScript(cardLines);
petCard = new PaperToken(rules, CardEdition.UNKNOWN, picture);
}
return petCard;
}
public final int getCost() {
return cost;
}
public final String getNextLevel() {
return nextLevel;
}
}

View File

@@ -0,0 +1,134 @@
package forge.quest.bazaar;
import com.thoughtworks.xstream.XStream;
import forge.quest.data.QuestAssets;
import forge.utils.IgnoringXStream;
import forge.utils.XmlUtil;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class QuestPetStorage {
private Map<Integer, List<QuestPetController>> petsBySlot = new HashMap<Integer, List<QuestPetController>>();
private Map<String, QuestPetController> petsByName = new HashMap<String, QuestPetController>();
/**
* TODO: Write javadoc for Constructor.
*
* @param file File
*/
public QuestPetStorage(final File file) {
DocumentBuilder builder;
try {
builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
final Document document = builder.parse(file);
final XStream xs = new IgnoringXStream();
xs.autodetectAnnotations(true);
final NodeList xmlPets = document.getElementsByTagName("pets").item(0).getChildNodes();
for (int iN = 0; iN < xmlPets.getLength(); iN++) {
final Node n = xmlPets.item(iN);
if (n.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
final Attr att = document.createAttribute("resolves-to");
att.setValue(QuestPetController.class.getCanonicalName());
n.getAttributes().setNamedItem(att);
final String sXml = XmlUtil.nodeToString(n);
final QuestPetController petCtrl = (QuestPetController) xs.fromXML(sXml);
this.addToMap(petCtrl);
}
} catch (final SAXException e) {
e.printStackTrace();
} catch (final IOException e) {
e.printStackTrace();
} catch (final ParserConfigurationException e) {
e.printStackTrace();
}
}
/**
* TODO: Write javadoc for this method.
*
* @param petCtrl
*/
private void addToMap(final QuestPetController petCtrl) {
final int iSlot = petCtrl.getSlot();
List<QuestPetController> list = this.petsBySlot.get(Integer.valueOf(iSlot));
if (null == list) {
list = new ArrayList<QuestPetController>();
this.petsBySlot.put(Integer.valueOf(iSlot), list);
}
this.petsByName.put(petCtrl.getName(), petCtrl);
list.add(petCtrl);
}
/**
* TODO: Write javadoc for this method.
*
* @param petName String
* @return QuestPetController
*/
public QuestPetController getPet(final String petName) {
return this.petsByName.get(petName);
}
/**
* TODO: Write javadoc for this method.
*
* @param iSlot int
* @param qA QuestAssets
* @return List
*/
public List<QuestPetController> getAvaliablePets(final int iSlot, final QuestAssets qA) {
final List<QuestPetController> result = new ArrayList<QuestPetController>();
final List<QuestPetController> allPossible = this.petsBySlot.get(Integer.valueOf(iSlot));
if (null != allPossible) {
for (final QuestPetController c : allPossible) {
if (qA.getPetLevel(c.getSaveFileKey()) > 0) {
result.add(c);
}
}
}
return result;
}
/**
*
* TODO: Write javadoc for this method.
* @param iSlot int
* @return List<QuestPetController>
*/
public List<QuestPetController> getAllPets(final int iSlot) {
final List<QuestPetController> result = new ArrayList<QuestPetController>();
final List<QuestPetController> allPossible = this.petsBySlot.get(Integer.valueOf(iSlot));
if (null != allPossible) {
for (final QuestPetController c : allPossible) {
result.add(c);
}
}
return result;
}
}

View File

@@ -0,0 +1,115 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest.bazaar;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import forge.assets.FImage;
import java.util.ArrayList;
import java.util.List;
/**
* <p>
* QuestStallDefinition class.
* </p>
*
* @author Forge
* @version $Id: QuestStallDefinition.java 24769 2014-02-09 13:56:04Z Hellfish $
*/
@XStreamAlias("stall")
public class QuestStallDefinition {
/** The name. */
@XStreamAsAttribute
private final String name;
/** The display name. */
@XStreamAsAttribute
private final String displayName;
@XStreamAsAttribute
private final FImage icon;
private final String description;
private final List<String> items;
/**
* <p>
* Constructor for QuestStallDefinition.
* </p> Not used anyway
*
* @param name
* a {@link java.lang.String} object.
* @param displayName
* a {@link java.lang.String} object.
* @param description
* a {@link java.lang.String} object.
* @param icon0
* a {@link javax.swing.ImageIcon} object.
*/
private QuestStallDefinition() {
name = null;
displayName = null;
description = null;
items = new ArrayList<String>();
icon = null;
}
/**
* Gets the fluff.
*
* @return the fluff
*/
public String getFluff() {
return this.description;
}
/**
* Gets the icon.
*
* @return the icon
*/
public FImage getIcon() {
return icon;
}
/**
* Gets the display name.
*
* @return the displayName
*/
public String getDisplayName() {
return this.displayName;
}
/**
* Gets the name.
*
* @return the name
*/
public String getName() {
return this.name;
}
public List<String> getItems() {
return items;
}
}

View File

@@ -0,0 +1,3 @@
/** Forge Card Game. */
package forge.quest.bazaar;

View File

@@ -0,0 +1,153 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest.data;
import com.google.common.base.Predicate;
import forge.card.CardEdition;
import forge.game.GameFormat;
import forge.model.FModel;
import java.util.ArrayList;
import java.util.List;
/**
* This is an alternate game format type, the main difference is that this
* is not immutable. This class is necessary because we may wish to update
* its contents in certain circumstances, and it was safer to create a new
* class than to make the preset game formats modifiable.
*/
public final class GameFormatQuest extends GameFormat {
private final boolean allowUnlocks;
private int unlocksUsed = 0;
/**
* Instantiates a new game format based on two lists.
*
* @param newName
* String, the name
* @param setsToAllow
* List<String>, these are the allowed sets
* @param cardsToBan
* List<String>, these will be the banned cards
*/
public GameFormatQuest(final String newName, final List<String> setsToAllow, final List<String> cardsToBan) {
super(newName, setsToAllow, cardsToBan);
allowUnlocks = false;
}
public GameFormatQuest(final String newName, final List<String> setsToAllow, final List<String> cardsToBan, boolean allowSetUnlocks) {
super(newName, setsToAllow, cardsToBan);
allowUnlocks = allowSetUnlocks;
}
/**
* Instantiates a new game format based on an existing format.
*
* @param toCopy
* an existing format
* @param allowSetUnlocks
*/
public GameFormatQuest(final GameFormat toCopy, boolean allowSetUnlocks) {
super(toCopy.getName(), toCopy.getAllowedSetCodes(), toCopy.getBannedCardNames(), toCopy.getRestrictedCards(), toCopy.getIndex());
allowUnlocks = allowSetUnlocks;
}
/**
* Get the list of excluded sets.
*
* @return unmodifiable list of excluded sets.
*/
public List<String> getLockedSets() {
List<String> exSets = new ArrayList<String>();
if (this.allowedSetCodes.isEmpty()) {
return exSets;
}
for (CardEdition ce : FModel.getMagicDb().getEditions()) {
if (!isSetLegal(ce.getCode())) {
exSets.add(ce.getCode());
}
}
return exSets;
}
/**
* Add a set to allowed set codes.
*
* @param setCode String, set code.
*/
public void unlockSet(final String setCode) {
if (!canUnlockSets() || this.allowedSetCodes_ro.isEmpty() || this.allowedSetCodes_ro.contains(setCode)) {
return;
}
this.allowedSetCodes.add(setCode);
unlocksUsed++;
}
/**
* Checks if the current format contains sets with snow-land (horrible hack...).
* @return boolean, contains snow-land sets.
*
*/
public boolean hasSnowLands() {
return (this.isSetLegal("ICE") || this.isSetLegal("CSP"));
}
public boolean canUnlockSets() {
return allowUnlocks;
}
public int getUnlocksUsed() {
return unlocksUsed;
}
/**
* The Class Predicates.
*/
public abstract static class Predicates {
/**
* Checks if is legal in quest format.
*
* @param qFormat the format
* @return the predicate
*/
public static Predicate<CardEdition> isLegalInFormatQuest(final GameFormatQuest qFormat) {
return new LegalInFormatQuest(qFormat);
}
private static class LegalInFormatQuest implements Predicate<CardEdition> {
private final GameFormatQuest qFormat;
public LegalInFormatQuest(final GameFormatQuest fmt) {
this.qFormat = fmt;
}
@Override
public boolean apply(final CardEdition subject) {
return this.qFormat.isSetLegal(subject.getCode());
}
}
}
}

View File

@@ -0,0 +1,176 @@
package forge.quest.data;
import forge.model.FModel;
import forge.quest.data.QuestPreferences.DifficultyPrefs;
import java.util.ArrayList;
import java.util.List;
public class QuestAchievements {
// Challenge history
/** The challenges played. */
private int challengesPlayed = 0;
private List<String> completedChallenges = new ArrayList<String>();
private List<String> currentChallenges = new ArrayList<String>();
private int win;
private int winstreakBest = 0;
private int winstreakCurrent = 0;
private int lost;
// Difficulty - will store only index from now.
private int difficulty;
/**
* TODO: Write javadoc for Constructor.
* @param diff &emsp; int
*/
public QuestAchievements(int diff) {
difficulty = diff;
}
/**
* TODO: Write javadoc for Constructor.
* @param mode
*/
/**
* Adds the win.
*/
public void addWin() { // changes getRank()
this.win++;
this.winstreakCurrent++;
if (this.winstreakCurrent > this.winstreakBest) {
this.winstreakBest = this.winstreakCurrent;
}
}
// Challenge performance
/**
* Gets the challenges played.
*
* @return the challenges played
*/
public int getChallengesPlayed() {
return this.challengesPlayed;
}
/**
* Adds the challenges played.
*/
public void addChallengesPlayed() {
this.challengesPlayed++;
}
/**
* Returns stored list of non-repeatable challenge IDs.
*
* @return List<Integer>
*/
public List<String> getLockedChallenges() {
return this.completedChallenges;
}
/**
* <p>
* addCompletedChallenge.
* </p>
* Add non-repeatable challenge ID to list.
*
* @param i
* the i
*/
public void addLockedChallenge(final String i) {
this.completedChallenges.add(i);
}
/**
* Stores a list of current challenges.
*
* @return List<Integer>
*/
public List<String> getCurrentChallenges() {
if (this.currentChallenges == null) {
this.currentChallenges = new ArrayList<String>();
}
return this.currentChallenges;
}
/**
* Returns the stored list of current challenges.
*
* @param lst0 List<Integer>
*/
public void setCurrentChallenges(final List<String> lst0) {
this.currentChallenges = lst0;
}
/**
* Adds the lost.
*/
public void addLost() {
this.lost++;
this.winstreakCurrent = 0;
}
// Level, read-only ( note: it increments in addWin() )
/**
* Gets the level.
*
* @return the level
*/
public int getLevel() {
final int winsToLvlUp = FModel.getQuestPreferences().getPrefInt(DifficultyPrefs.WINS_RANKUP, difficulty);
return this.win / winsToLvlUp;
}
// Wins & Losses
/**
* Gets the lost.
*
* @return the lost
*/
public int getLost() {
return this.lost;
}
/**
* Gets the win.
*
* @return the win
*/
public int getWin() {
return win;
}
/**
* Gets the win streak best.
*
* @return int
*/
public int getWinStreakBest() {
return winstreakBest;
}
/**
* Gets the win streak current.
*
* @return int
*/
public int getWinStreakCurrent() {
return winstreakCurrent;
}
/**
* Gets the difficulty index.
*
* @return the difficulty index
*/
public int getDifficulty() {
return this.difficulty;
}
}

View File

@@ -0,0 +1,266 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Nate
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest.data;
import forge.deck.Deck;
import forge.item.InventoryItem;
import forge.item.PaperCard;
import forge.model.FModel;
import forge.quest.QuestDeckMap;
import forge.quest.QuestMode;
import forge.quest.QuestUtilCards;
import forge.quest.bazaar.QuestItemType;
import forge.quest.data.QuestPreferences.QPref;
import forge.util.ItemPool;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
/** */
public class QuestAssets {
// Cards associated with quest
/** The card pool. */
private final ItemPool<PaperCard> cardPool = new ItemPool<PaperCard>(PaperCard.class); // player's
/** The credits. */
private long credits; // this money is good for all modes
// game
// with
// Decks collected by player
/** The my decks. */
private final HashMap<String, Deck> myDecks = new HashMap<String, Deck>();
// current
// shop
// list
/** The new card list. */
private final ItemPool<InventoryItem> newCardList = new ItemPool<InventoryItem>(InventoryItem.class); // cards
// belonging
/** The shop list. */
private final ItemPool<InventoryItem> shopList = new ItemPool<InventoryItem>(InventoryItem.class); // the
// gadgets
/** The inventory items. */
private final Map<QuestItemType, QuestItemCondition> inventoryItems = new EnumMap<QuestItemType, QuestItemCondition>(
QuestItemType.class);
// Much the same like other map, but keyed by string (to support a lot of custom pets)
private final Map<String, QuestItemCondition> combatPets = new HashMap<String, QuestItemCondition>();
/**
* Checks for item.
*
* @param itemType the item type
* @return true, if successful
*/
public final boolean hasItem(final QuestItemType itemType) {
return this.inventoryItems.containsKey(itemType) && (this.inventoryItems.get(itemType).getLevel() > 0);
}
/**
* Gets the item level.
*
* @param itemType the item type
* @return the item level
*/
public final int getItemLevel(final QuestItemType itemType) {
final QuestItemCondition state = this.inventoryItems.get(itemType);
return state == null ? 0 : state.getLevel();
}
/**
* Gets the item condition.
*
* @param itemType the item type
* @param <T> extends QuestItemCondition
* @return T the item condition
*/
@SuppressWarnings("unchecked")
public final <T extends QuestItemCondition> T getItemCondition(final QuestItemType itemType) {
QuestItemCondition current = this.inventoryItems.get(itemType);
if (!current.getClass().equals(itemType.getModelClass())) {
try {
QuestItemCondition modern = itemType.getModelClass().newInstance();
modern.takeDataFrom(current);
current = modern;
inventoryItems.put(itemType, modern);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return (T) current;
}
/**
* Sets the item level.
*
* @param itemType the item type
* @param level the level
*/
public final void setItemLevel(final QuestItemType itemType, final int level) {
QuestItemCondition cond = this.inventoryItems.get(itemType);
if (null == cond) {
try { // care to set appropriate state class here
cond = itemType.getModelClass().newInstance();
} catch (final Exception e) {
e.printStackTrace();
cond = new QuestItemCondition();
}
this.inventoryItems.put(itemType, cond);
}
cond.setLevel(level);
}
/**
* @param name String
* @return int
*/
public final int getPetLevel(final String name) {
final QuestItemCondition state = this.combatPets.get(name);
return state == null ? 0 : state.getLevel();
}
/**
* @param name &emsp; String
* @param <T> extends QuestItemCondition
* @return <T>
*/
@SuppressWarnings("unchecked")
public final <T extends QuestItemCondition> T getPetCondition(final String name) {
return (T) this.combatPets.get(name);
}
/**
* @param name String
* @param level int
*/
public final void setPetLevel(final String name, final int level) {
QuestItemCondition cond = this.combatPets.get(name);
if (null == cond) {
cond = new QuestItemCondition(); // pets have only level that should be serialized for now
this.combatPets.put(name, cond);
}
cond.setLevel(level);
}
/**
* Instantiates a new quest assets.
*/
public QuestAssets(GameFormatQuest useFormat) {
final QuestPreferences prefs = FModel.getQuestPreferences();
int snowLands = prefs.getPrefInt(QPref.STARTING_SNOW_LANDS);
if (useFormat != null && !useFormat.hasSnowLands()) {
snowLands = 0;
}
final ItemPool<PaperCard> lands = QuestUtilCards.generateBasicLands(
prefs.getPrefInt(QPref.STARTING_BASIC_LANDS), snowLands, useFormat);
this.getCardPool().addAll(lands);
}
/**
* Gets the credits.
*
* @return the credits
*/
public long getCredits() {
return this.credits;
}
// Life (only fantasy)
/**
* Gets the life.
*
* @param mode the mode
* @return the life
*/
public int getLife(final QuestMode mode) {
final int base = mode.equals(QuestMode.Fantasy) ? 15 : 20;
return (base + this.getItemLevel(QuestItemType.ELIXIR_OF_LIFE)) - this.getItemLevel(QuestItemType.POUND_FLESH);
}
/**
* Gets the new card list.
*
* @return the newCardList
*/
public ItemPool<InventoryItem> getNewCardList() {
return this.newCardList;
}
/**
* Gets the shop list.
*
* @return the shopList
*/
public ItemPool<InventoryItem> getShopList() {
return this.shopList;
}
/**
* Sets the credits.
*
* @param credits0
* the credits to set
*/
public void setCredits(final long credits0) {
this.credits = credits0;
}
// Credits
/**
* Adds the credits.
*
* @param c
* the c
*/
public void addCredits(final long c) {
this.setCredits(this.getCredits() + c);
}
/**
* Gets the card pool.
*
* @return the cardPool
*/
public ItemPool<PaperCard> getCardPool() {
return this.cardPool;
}
/**
* Subtract credits.
*
* @param c
* the c
*/
public void subtractCredits(final long c) {
this.setCredits(this.getCredits() > c ? this.getCredits() - c : 0);
}
/**
* @return the deck storage
*/
public QuestDeckMap getDeckStorage() {
return new QuestDeckMap(this.myDecks);
}
}

View File

@@ -0,0 +1,217 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest.data;
import forge.game.GameFormat;
import forge.model.FModel;
import forge.quest.QuestMode;
import forge.quest.io.QuestDataIO;
import forge.utils.Constants;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
//when you create QuestDataOld and AFTER you copy the AI decks over
//you have to call one of these two methods below
//see Gui_QuestOptions for more details
/**
* <p>
* QuestData class.
* </p>
*
* @author Forge
* @version $Id: QuestData.java 24769 2014-02-09 13:56:04Z Hellfish $
*/
public final class QuestData {
/** Holds the latest version of the Quest Data. */
public static final int CURRENT_VERSION_NUMBER = 8;
// This field places the version number into QD instance,
// but only when the object is created through the constructor
// DO NOT RENAME THIS FIELD
/** The version number. */
private int versionNumber = QuestData.CURRENT_VERSION_NUMBER;
private GameFormatQuest format;
private String name;
// Quest mode - there should be an enum :(
/** The mode. */
private QuestMode mode;
// Quest world ID, if any
private String worldId;
// gadgets
private final QuestAssets assets;
private final QuestAchievements achievements;
private final Map<Integer, String> petSlots = new HashMap<Integer, String>();
private boolean isCharmActive = false;
/**
* Instantiates a new quest data.
* @param mode2
* quest mode
* @param diff
* achievement diff
* @param name2
* quest name
* @param userFormat
* user-defined format, if any (null if none).
* @param allowSetUnlocks
* allow set unlocking during quest
* @param startingWorld
* starting world
*/
public QuestData(String name0, int diff, QuestMode mode0, GameFormat userFormat,
boolean allowSetUnlocks, final String startingWorld) {
this.name = name0;
if (userFormat != null) {
this.format = new GameFormatQuest(userFormat, allowSetUnlocks);
}
this.mode = mode0;
this.achievements = new QuestAchievements(diff);
this.assets = new QuestAssets(format);
this.worldId = startingWorld;
}
/**
* Gets the mode.
*
* @return the mode
*/
public QuestMode getMode() {
return this.mode;
}
/**
* Gets the persistent format, null if not assigned.
*
* @return GameFormatQuest, the persistent format
*/
public GameFormatQuest getFormat() {
return this.format;
}
// SERIALIZATION - related things
// This must be called by XML-serializer via reflection
/**
* Read resolve.
*
* @return the object
*/
public Object readResolve() {
return this;
}
/**
* Save data.
*/
public void saveData() {
QuestDataIO.saveData(this);
}
/**
* Gets the version number.
*
* @return the versionNumber
*/
public int getVersionNumber() {
return this.versionNumber;
}
/**
* Sets the version number.
*
* @param versionNumber0
* the versionNumber to set
*/
public void setVersionNumber(final int versionNumber0) {
this.versionNumber = versionNumber0;
}
/**
* Gets the name.
*
* @return {@link java.lang.String}
*/
public String getName() {
return this.name;
}
/**
* Rename this quest the name.
*
* @param newName
* the new name to set
*/
public void rename(final String newName) {
File newpath = new File(Constants.QUEST_SAVE_DIR, newName + ".dat");
File oldpath = new File(Constants.QUEST_SAVE_DIR, this.name + ".dat");
oldpath.renameTo(newpath);
this.name = newName;
QuestDataIO.saveData(this);
}
public QuestAssets getAssets() {
return assets;
}
public Map<Integer, String> getPetSlots() {
return petSlots;
}
public QuestAchievements getAchievements() {
return achievements;
}
public String getWorldId() {
return worldId;
}
/**
* Sets the world id to null or a legal world id.
* @param newId
* String, the world id to set (must be null or legal).
*/
public void setWorldId(final String newId) {
if (newId != null && FModel.getWorlds().get(newId) == null) {
throw new RuntimeException("Tried to set illegal (unknown) world id: " + newId);
}
worldId = newId;
}
/**
* @return the isCharmActive
*/
public boolean isCharmActive() {
return isCharmActive;
}
/**
* @param isCharmActive the isCharmActive to set
*/
public void setCharmActive(boolean isCharmActive) {
this.isCharmActive = isCharmActive;
}
}

View File

@@ -0,0 +1,27 @@
package forge.quest.data;
/**
* This class should store the quest items' properties that are to be serialized.
*
*/
public class QuestItemCondition {
private int level;
/** @return int */
public int getLevel() {
return level;
}
/** @param level int */
public void setLevel(int level) {
this.level = level;
}
/**
* Copy data from the parameter instance to 'this' instance.
* @param source QuestItemCondition
*/
public void takeDataFrom(QuestItemCondition source) {
this.level = source.level;
}
}

View File

@@ -0,0 +1,261 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest.data;
import java.io.Serializable;
import forge.utils.Constants;
import forge.utils.PreferencesStore;
@SuppressWarnings("serial")
public class QuestPreferences extends PreferencesStore<QuestPreferences.QPref> implements Serializable {
/**
* Preference identifiers, and their default values.
*/
public static enum QPref {
// How many of each rarity comes in a won booster pack
BOOSTER_COMMONS("11"),
BOOSTER_UNCOMMONS("3"),
BOOSTER_RARES("1"),
// The preferred format of the won booster pack
BOOSTER_FORMAT("Standard"),
// How many credits are lost for losing a match
PENALTY_LOSS("15"),
// Currently chosen quest and deck
CURRENT_QUEST("DEFAULT"),
CURRENT_DECK("DEFAULT"),
// All of the rewards given out End of Match
// Awarded to every match winner
REWARDS_BASE("25"),
// Didn't lose a game in the match
REWARDS_UNDEFEATED("25"),
// For each of your previous wins gain a small multiplier
// This is here to award long quests with more money for buying expensive cards
REWARDS_WINS_MULTIPLIER("0.3"),
// Winning each game by other means "Poison", "Milling" or "Alternative" Win
REWARDS_POISON("50"),
REWARDS_MILLED("40"),
REWARDS_ALTERNATIVE("100"),
// If you Mulligan to 0 to start a game
REWARDS_MULLIGAN0("500"),
// How many turns it took you to win the game
REWARDS_TURN15("5"),
REWARDS_TURN10("50"),
REWARDS_TURN5("250"),
REWARDS_TURN1("1500"),
// How many basic your starting pool has (if appropriate)
STARTING_BASIC_LANDS("20"),
STARTING_SNOW_LANDS("5"),
// Starting pool color bias effect
STARTING_POOL_COLOR_BIAS("6"),
// Commons in your starting pool, by difficulty
STARTING_COMMONS_EASY("82"),
STARTING_COMMONS_MEDIUM("80"),
STARTING_COMMONS_HARD("78"),
STARTING_COMMONS_EXPERT("76"),
// Uncommons in your starting pool, by difficulty
STARTING_UNCOMMONS_EASY("40"),
STARTING_UNCOMMONS_MEDIUM("36"),
STARTING_UNCOMMONS_HARD("32"),
STARTING_UNCOMMONS_EXPERT("28"),
// Rares in your starting pool, by difficulty
STARTING_RARES_EASY("20"),
STARTING_RARES_MEDIUM("18"),
STARTING_RARES_HARD("16"),
STARTING_RARES_EXPERT("15"),
// Credits you start the quest with, by difficulty
STARTING_CREDITS_EASY("250"),
STARTING_CREDITS_MEDIUM("200"),
STARTING_CREDITS_HARD("150"),
STARTING_CREDITS_EXPERT("100"),
// Matches won per booster award, by difficulty
WINS_BOOSTER_EASY("1"),
WINS_BOOSTER_MEDIUM("1"),
WINS_BOOSTER_HARD("2"),
WINS_BOOSTER_EXPERT("2"),
// Matches won per increased rank, by difficulty
// Rank affects how many packs are opened for singles in the spell shop
WINS_RANKUP_EASY("3"),
WINS_RANKUP_MEDIUM("4"),
WINS_RANKUP_HARD("5"),
WINS_RANKUP_EXPERT("6"),
// Matches won to unlock Medium Opponents, by difficulty
WINS_MEDIUMAI_EASY("10"),
WINS_MEDIUMAI_MEDIUM("9"),
WINS_MEDIUMAI_HARD("8"),
WINS_MEDIUMAI_EXPERT("7"),
// Matches won to unlock Hard Opponents, by difficulty
WINS_HARDAI_EASY("20"),
WINS_HARDAI_MEDIUM("18"),
WINS_HARDAI_HARD("16"),
WINS_HARDAI_EXPERT("14"),
// Matches won to unlock Expert Opponents, by difficulty
WINS_EXPERTAI_EASY("40"),
WINS_EXPERTAI_MEDIUM("36"),
WINS_EXPERTAI_HARD("32"),
WINS_EXPERTAI_EXPERT("28"),
// Maximum amount of "Packs" opened by the Shop and available as singles
SHOP_MAX_PACKS("6"),
// Rarity distribution of Singles in an Opened Shop Pack
SHOP_SINGLES_COMMON("7"),
SHOP_SINGLES_UNCOMMON("3"),
SHOP_SINGLES_RARE("1"),
// How many wins it takes to open an additional pack in the shop
SHOP_WINS_FOR_ADDITIONAL_PACK("10"),
// How many packs the shop start with.
SHOP_STARTING_PACKS("4");
private final String strDefaultVal;
/**
* Instantiates a new q pref.
*
* @param s0
* &emsp; {@link java.lang.String}
*/
QPref(final String s0) {
this.strDefaultVal = s0;
}
/**
* Gets the default.
*
* @return {@link java.lang.String}
*/
public String getDefault() {
return this.strDefaultVal;
}
}
public static enum DifficultyPrefs {
STARTING_COMMONS,
STARTING_UNCOMMONS,
STARTING_RARES,
STARTING_CREDITS,
WINS_BOOSTER,
WINS_RANKUP,
WINS_MEDIUMAI,
WINS_HARDAI,
WINS_EXPERTAI
}
/** Instantiates a QuestPreferences object. */
public QuestPreferences() {
super(Constants.QUEST_PREFS_FILE, QPref.class);
}
protected QPref[] getEnumValues() {
return QPref.values();
}
protected QPref valueOf(String name) {
try {
return QPref.valueOf(name);
}
catch (Exception e) {
return null;
}
}
protected String getPrefDefault(QPref key) {
return key.getDefault();
}
/**
* Returns a preference value according to a difficulty index.
*/
public String getPref(DifficultyPrefs pref, int difficultyIndex) {
String newQPref = pref.toString();
switch (difficultyIndex) {
case 0:
newQPref += "_EASY";
break;
case 1:
newQPref += "_MEDIUM";
break;
case 2:
newQPref += "_HARD";
break;
case 3:
newQPref += "_EXPERT";
break;
default:
try {
throw new Exception();
} catch (final Exception e1) {
System.err.println("Difficulty index out of bounds: " + difficultyIndex);
e1.printStackTrace();
}
}
return getPref(QPref.valueOf(newQPref));
}
/**
* Returns a difficulty-indexed preference value, as an int.
*/
public int getPrefInt(DifficultyPrefs pref, int difficultyIndex) {
return Integer.parseInt(this.getPref(pref, difficultyIndex));
}
/**
* Gets the difficulty.
*/
public static String getDifficulty(int difficultyIndex) {
String s;
switch (difficultyIndex) {
case 1:
s = "EASY";
break;
case 2:
s = "MEDIUM";
break;
case 3:
s = "HARD";
break;
case 4:
s = "EXPERT";
break;
default:
s = "UNKNOWN";
}
return s;
}
}

View File

@@ -0,0 +1,3 @@
/** Forge Card Game. */
package forge.quest.data;

View File

@@ -0,0 +1,73 @@
package forge.quest.io;
import forge.ImageKeys;
import forge.deck.io.DeckSerializer;
import forge.deck.io.DeckStorage;
import forge.quest.QuestEventChallenge;
import forge.quest.QuestEventDifficulty;
import forge.util.FileSection;
import forge.util.FileUtil;
import forge.util.TextUtil;
import forge.util.storage.StorageReaderFolder;
import forge.utils.Constants;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class QuestChallengeReader extends StorageReaderFolder<QuestEventChallenge> {
public QuestChallengeReader(File deckDir0) {
super(deckDir0, QuestEventChallenge.FN_GET_ID);
// TODO Auto-generated constructor stub
}
@Override
protected QuestEventChallenge read(File file) {
final Map<String, List<String>> contents = FileSection.parseSections(FileUtil.readFile(file));
final QuestEventChallenge qc = new QuestEventChallenge();
// Unique properties
FileSection sectionQuest = FileSection.parse(contents.get("quest"), "=");
qc.setId(sectionQuest.get("ID", "-1"));
qc.setOpponent(sectionQuest.get("OpponentName"));
qc.setRepeatable(sectionQuest.getBoolean("Repeat", false));
qc.setAiLife(sectionQuest.getInt("AILife", 25));
qc.setWinsReqd(sectionQuest.getInt("Wins", 20));
qc.setCreditsReward(sectionQuest.getInt("Credit Reward", 100));
qc.setCardReward(sectionQuest.get("Card Reward"));
qc.setHumanExtraCards(Arrays.asList(TextUtil.split(sectionQuest.get("HumanExtras", ""), '|')));
qc.setAiExtraCards(Arrays.asList(TextUtil.split(sectionQuest.get("AIExtras", ""), '|')));
// Less common properties
int humanLife = sectionQuest.getInt("HumanLife", 0);
if (humanLife != 0) {
qc.setHumanLife(humanLife);
}
qc.setUseBazaar(sectionQuest.getBoolean("UseBazaar", true));
qc.setForceAnte(sectionQuest.contains("ForceAnte") ? sectionQuest.getBoolean("ForceAnte") : null);
String humanDeck = sectionQuest.get("HumanDeck", null);
if (humanDeck != null) {
File humanFile = new File(Constants.DEFAULT_CHALLENGES_DIR, humanDeck); // Won't work in other worlds!
qc.setHumanDeck(DeckSerializer.fromFile(humanFile));
}
// Common properties
FileSection sectionMeta = FileSection.parse(contents.get("metadata"), "=");
qc.setTitle(sectionMeta.get("Title"));
qc.setName(qc.getTitle()); // Challenges have unique titles
qc.setDifficulty(QuestEventDifficulty.fromString(sectionMeta.get("Difficulty")));
qc.setDescription(sectionMeta.get("Description"));
qc.setIconImageKey(ImageKeys.ICON_PREFIX + sectionMeta.get("Icon"));
// Deck
qc.setEventDeck(DeckSerializer.fromSections(contents));
return qc;
}
@Override
protected FilenameFilter getFileFilter() {
return DeckStorage.DCK_FILE_FILTER;
}
}

View File

@@ -0,0 +1,673 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest.io;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import forge.card.CardEdition;
import forge.deck.CardPool;
import forge.deck.Deck;
import forge.deck.DeckSection;
import forge.error.BugReporter;
import forge.item.*;
import forge.model.FModel;
import forge.quest.QuestController;
import forge.quest.QuestMode;
import forge.quest.bazaar.QuestItemType;
import forge.quest.data.*;
import forge.util.ItemPool;
import forge.utils.Constants;
import forge.utils.IgnoringXStream;
import forge.utils.XmlUtil;
import org.apache.commons.lang3.StringUtils;
import org.w3c.dom.*;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
/**
* <p>
* QuestDataIO class.
* </p>
*
* @author Forge
* @version $Id: QuestDataIO.java 24769 2014-02-09 13:56:04Z Hellfish $
*/
public class QuestDataIO {
/**
* Gets the serializer.
*
* @param isIgnoring the is ignoring
* @return the serializer
*/
protected static XStream getSerializer(final boolean isIgnoring) {
final XStream xStream = isIgnoring ? new IgnoringXStream() : new XStream();
xStream.registerConverter(new ItemPoolToXml());
xStream.registerConverter(new DeckToXml());
xStream.registerConverter(new GameFormatQuestToXml());
xStream.registerConverter(new QuestModeToXml());
xStream.autodetectAnnotations(true);
xStream.alias("CardPool", ItemPool.class);
xStream.alias("DeckSection", CardPool.class);
return xStream;
}
/**
* <p>
* loadData.
* </p>
*
* @param xmlSaveFile
* &emsp; {@link java.io.File}
* @return {@link forge.quest.data.QuestData}
*/
public static QuestData loadData(final File xmlSaveFile) {
try {
QuestData data = null;
final GZIPInputStream zin = new GZIPInputStream(new FileInputStream(xmlSaveFile));
final StringBuilder xml = new StringBuilder();
final char[] buf = new char[1024];
final InputStreamReader reader = new InputStreamReader(zin);
while (reader.ready()) {
final int len = reader.read(buf);
if (len == -1) {
break;
} // when end of stream was reached
xml.append(buf, 0, len);
}
zin.close();
String bigXML = xml.toString();
data = (QuestData) QuestDataIO.getSerializer(true).fromXML(bigXML);
if (data.getVersionNumber() != QuestData.CURRENT_VERSION_NUMBER) {
try {
QuestDataIO.updateSaveFile(data, bigXML, xmlSaveFile.getName().replace(".dat", ""));
} catch (final Exception e) {
forge.error.BugReporter.reportException(e);
}
}
return data;
}
catch (final Exception ex) {
BugReporter.reportException(ex, "Error loading Quest Data");
throw new RuntimeException(ex);
}
}
private static <T> void setFinalField(final Class<T> clasz, final String fieldName, final T instance,
final Object newValue) throws IllegalAccessException, NoSuchFieldException {
final Field field = clasz.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(instance, newValue); // no difference here (used only to set
// initial lives)
}
/**
* <p>
* updateSaveFile.
* </p>
*
* @param newData
* a {@link forge.quest.data.QuestData} object.
* @param input
* a {@link java.lang.String} object.
* @throws ParserConfigurationException
* @throws IOException
* @throws SAXException
* @throws NoSuchFieldException
* @throws IllegalAccessException
*/
private static void updateSaveFile(final QuestData newData, final String input, String filename) throws ParserConfigurationException, SAXException, IOException, IllegalAccessException, NoSuchFieldException {
final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
final InputSource is = new InputSource();
is.setCharacterStream(new StringReader(input));
final Document document = builder.parse(is);
final int saveVersion = newData.getVersionNumber();
if (saveVersion < 3) {
QuestDataIO.setFinalField(QuestData.class, "assets", newData, new QuestAssets(null));
final int diffIdx = Integer.parseInt(document.getElementsByTagName("diffIndex").item(0).getTextContent());
QuestDataIO.setFinalField(QuestData.class, "achievements", newData, new QuestAchievements(diffIdx));
}
if (saveVersion < 4) {
QuestDataIO.setFinalField(QuestAssets.class, "inventoryItems", newData.getAssets(), new EnumMap<QuestItemType, Integer>(QuestItemType.class));
}
if (saveVersion < 5) {
QuestDataIO.setFinalField(QuestAssets.class, "combatPets", newData.getAssets(), new HashMap<String, QuestItemCondition>());
}
if (saveVersion < 6) {
QuestDataIO.setFinalField(QuestData.class, "petSlots", newData, new HashMap<Integer, String>());
}
if(saveVersion < 8) {
QuestDataIO.setFinalField(QuestData.class, "isCharmActive", newData, false);
}
final QuestAssets qS = newData.getAssets();
final QuestAchievements qA = newData.getAchievements();
switch (saveVersion) {
// There should be a fall-through between the cases so that each
// version's changes get applied progressively
case 0:
// First beta release with new file format,
// inventory needs to be migrated
QuestDataIO.setFinalField(QuestAssets.class, "inventoryItems", newData.getAssets(), new EnumMap<QuestItemType, Integer>(QuestItemType.class));
qS.setItemLevel(QuestItemType.ESTATES, Integer.parseInt(document.getElementsByTagName("estatesLevel").item(0).getTextContent()));
qS.setItemLevel(QuestItemType.LUCKY_COIN, Integer.parseInt(document.getElementsByTagName("luckyCoinLevel").item(0).getTextContent()));
qS.setItemLevel(QuestItemType.SLEIGHT, Integer.parseInt(document.getElementsByTagName("sleightOfHandLevel").item(0).getTextContent()));
final int gearLevel = Integer.parseInt(document.getElementsByTagName("gearLevel").item(0).getTextContent());
if (gearLevel >= 1) {
newData.getAssets().setItemLevel(QuestItemType.MAP, 1);
}
if (gearLevel == 2) {
newData.getAssets().setItemLevel(QuestItemType.ZEPPELIN, 1);
}
// fall-through
case 1:
// nothing to do here, everything is managed by CardPoolToXml
// deserializer
case 2:
// questdata was divided into assets and achievements
if (StringUtils.isBlank(newData.getName())) {
QuestDataIO.setFinalField(QuestData.class, "name", newData, filename);
}
QuestDataIO.setFinalField(QuestAchievements.class, "win", qA, Integer.parseInt(document.getElementsByTagName("win").item(0).getTextContent()));
QuestDataIO.setFinalField(QuestAchievements.class, "lost", qA, Integer.parseInt(document.getElementsByTagName("lost").item(0).getTextContent()));
Node nw;
if ((nw = document.getElementsByTagName("winstreakBest").item(0)) != null) {
QuestDataIO.setFinalField(QuestAchievements.class, "winstreakBest", qA, Integer.parseInt(nw.getTextContent()));
}
if ((nw = document.getElementsByTagName("winstreakCurrent").item(0)) != null) {
QuestDataIO.setFinalField(QuestAchievements.class, "winstreakCurrent", qA, Integer.parseInt(nw.getTextContent()));
}
QuestDataIO.setFinalField(QuestAchievements.class, "challengesPlayed", qA, Integer.parseInt(document.getElementsByTagName("challengesPlayed").item(0).getTextContent()));
final ArrayList<Integer> completedChallenges = new ArrayList<Integer>();
QuestDataIO.setFinalField(QuestAchievements.class, "completedChallenges", qA, completedChallenges);
if ((nw = document.getElementsByTagName("completedChallenges").item(0)) != null) {
final NodeList ccs = nw.getChildNodes();
for (int iN = 0; iN < ccs.getLength(); iN++) {
final Node n0 = ccs.item(iN);
if (n0.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
completedChallenges.add(Integer.parseInt(n0.getTextContent()));
}
}
final XStream xs = QuestDataIO.getSerializer(true);
QuestDataIO.setFinalField(QuestAssets.class, "credits", qS, Integer.parseInt(document.getElementsByTagName("credits").item(0).getTextContent()));
QuestDataIO.setFinalField(QuestAssets.class, "cardPool", qS, QuestDataIO.readAsset(xs, document, "cardPool", ItemPool.class));
QuestDataIO.setFinalField(QuestAssets.class, "myDecks", qS, QuestDataIO.readAsset(xs, document, "myDecks", HashMap.class));
QuestDataIO.setFinalField(QuestAssets.class, "shopList", qS, QuestDataIO.readAsset(xs, document, "shopList", ItemPool.class));
QuestDataIO.setFinalField(QuestAssets.class, "newCardList", qS, QuestDataIO.readAsset(xs, document, "newCardList", ItemPool.class));
case 3:
// QuestInventory class no longer exists - KV pairs of
// QuestItemPair => level moved to assets
final Node oldInventory = saveVersion > 0 ? document.getElementsByTagName("inventory").item(1) : null;
if (null != oldInventory) {
for (int iN = 0; iN < oldInventory.getChildNodes().getLength(); iN++) {
final Node _n = oldInventory.getChildNodes().item(iN);
if (_n.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
final Element n = (Element) _n;
final String name = n.getElementsByTagName("string").item(0).getTextContent();
final QuestItemType qType = QuestItemType.valueFromSaveKey(name);
int level = 0;
for (int iX = 0; iX < n.getChildNodes().getLength(); iX++) {
final Node _x = n.getChildNodes().item(iX);
if (_x.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
final Element x = (Element) _x;
if (!x.getTagName().startsWith("forge.quest.data.")) {
continue;
}
final String sLevel = x.getElementsByTagName("level").item(0).getTextContent();
if (StringUtils.isNotBlank(sLevel)) {
level = Integer.parseInt(sLevel);
}
}
qS.setItemLevel(qType, level);
}
}
case 4:
if (saveVersion > 0) {
NodeList pets = document.getElementsByTagName("pets").item(0).getChildNodes();
for (int i = 0; i < pets.getLength(); i++) {
if (pets.item(i).getNodeType() != Node.ELEMENT_NODE) {
continue;
}
final Element entry = (Element) pets.item(i);
String name = entry.getElementsByTagName("string").item(0).getTextContent();
String sLevel = entry.getElementsByTagName("level").item(0).getTextContent();
qS.setPetLevel(name, Integer.parseInt(sLevel));
}
}
// pet manager will be re-engineered here
case 6:
// have to convert completed challenges list members to strings.
for(int i = qA.getLockedChallenges().size()-1; i >= 0; i-- ) {
Object lc = qA.getLockedChallenges().get(i);
if (!(lc instanceof String))
qA.getLockedChallenges().set(i, lc.toString());
}
for(int i = qA.getCurrentChallenges().size()-1; i >= 0; i-- ) {
Object lc = qA.getCurrentChallenges().get(i);
if (!(lc instanceof String))
qA.getCurrentChallenges().set(i, lc.toString());
}
default:
break;
}
// mark the QD as the latest version
newData.setVersionNumber(QuestData.CURRENT_VERSION_NUMBER);
}
@SuppressWarnings("unchecked")
private static <T> T readAsset(final XStream xs, final Document doc, final String tagName, final Class<T> clasz)
throws IllegalAccessException, NoSuchFieldException {
final NodeList nn = doc.getElementsByTagName(tagName);
final Node n = nn.item(0);
final Attr att = doc.createAttribute("resolves-to");
att.setValue(clasz.getCanonicalName());
n.getAttributes().setNamedItem(att);
final String xmlData = XmlUtil.nodeToString(n);
return (T) xs.fromXML(xmlData);
}
/**
* <p>
* saveData.
* </p>
*
* @param qd
* a {@link forge.quest.data.QuestData} object.
*/
public static synchronized void saveData(final QuestData qd) {
try {
final XStream xStream = QuestDataIO.getSerializer(false);
final File f = new File(Constants.QUEST_SAVE_DIR, qd.getName());
QuestDataIO.savePacked(f + ".dat", xStream, qd);
// QuestDataIO.saveUnpacked(f + ".xml", xStream, qd);
}
catch (final Exception ex) {
BugReporter.reportException(ex, "Error saving Quest Data.");
throw new RuntimeException(ex);
}
}
private static void savePacked(final String f, final XStream xStream, final QuestData qd) throws IOException {
final BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(f));
final GZIPOutputStream zout = new GZIPOutputStream(bout);
xStream.toXML(qd, zout);
zout.flush();
zout.close();
}
@SuppressWarnings("unused") // used only for debug purposes
private static void saveUnpacked(final String f, final XStream xStream, final QuestData qd) throws IOException {
final BufferedOutputStream boutUnp = new BufferedOutputStream(new FileOutputStream(f));
xStream.toXML(qd, boutUnp);
boutUnp.flush();
boutUnp.close();
}
private static class GameFormatQuestToXml implements Converter {
@SuppressWarnings("rawtypes")
@Override
public boolean canConvert(final Class clasz) {
return clasz.equals(GameFormatQuest.class);
}
@Override
public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) {
writer.startNode("format");
GameFormatQuest format = (GameFormatQuest) source;
writer.addAttribute("name", format.getName());
writer.addAttribute("unlocksUsed", Integer.toString(format.getUnlocksUsed()));
writer.addAttribute("canUnlock", format.canUnlockSets() ? "1" : "0");
writer.endNode();
for (String set : format.getAllowedSetCodes()) {
writer.startNode("set");
writer.addAttribute("s", set);
writer.endNode();
}
for (String ban : format.getBannedCardNames()) {
writer.startNode("ban");
writer.addAttribute("s", ban);
writer.endNode();
}
}
@Override
public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) {
reader.moveDown();
String name = reader.getAttribute("name");
String unlocksUsed = reader.getAttribute("unlocksUsed");
boolean canUnlock = !("0".equals(reader.getAttribute("canUnlock")));
List<String> allowedSets = new ArrayList<String>();
List<String> bannedCards = new ArrayList<String>();
reader.moveUp();
while (reader.hasMoreChildren()) {
reader.moveDown();
final String nodename = reader.getNodeName();
if (nodename.equals("ban")) {
bannedCards.add(reader.getAttribute("s"));
// System.out.println("Added + " + toBan + " to banned cards");
}
else if (nodename.equals("set")) {
allowedSets.add(reader.getAttribute("s"));
// System.out.println("Added + " + toSets + " to legal sets");
}
reader.moveUp();
}
GameFormatQuest res = new GameFormatQuest(name, allowedSets, bannedCards);
try {
if (StringUtils.isNotEmpty(unlocksUsed)) {
setFinalField(GameFormatQuest.class, "unlocksUsed", res, Integer.parseInt(unlocksUsed));
}
setFinalField(GameFormatQuest.class, "allowUnlocks", res, canUnlock);
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return res;
}
}
private static class QuestModeToXml implements Converter {
@SuppressWarnings("rawtypes")
@Override
public boolean canConvert(final Class clasz) {
return clasz.equals(QuestMode.class);
}
@Override
public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) {
QuestMode mode = (QuestMode) source;
String sMode = mode.toString();
writer.setValue(sMode);
}
@Override
public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) {
final String value = reader.getValue();
return QuestMode.smartValueOf(value, QuestMode.Classic);
}
}
private static class DeckToXml extends ItemPoolToXml {
/* (non-Javadoc)
* @see com.thoughtworks.xstream.converters.ConverterMatcher#canConvert(java.lang.Class)
*/
@SuppressWarnings("rawtypes")
@Override
public boolean canConvert(Class type) {
return type.equals(Deck.class);
}
/* (non-Javadoc)
* @see com.thoughtworks.xstream.converters.Converter#marshal(java.lang.Object, com.thoughtworks.xstream.io.HierarchicalStreamWriter, com.thoughtworks.xstream.converters.MarshallingContext)
*/
@Override
public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
Deck d = (Deck)source;
writer.startNode("name");
writer.setValue(d.getName());
writer.endNode();
for( Entry<DeckSection, CardPool> ds : d ) {
writer.startNode(ds.getKey().toString());
for (final Entry<PaperCard, Integer> e : ds.getValue()) {
this.write(e.getKey(), e.getValue(), writer);
}
writer.endNode();
}
}
/* (non-Javadoc)
* @see com.thoughtworks.xstream.converters.Converter#unmarshal(com.thoughtworks.xstream.io.HierarchicalStreamReader, com.thoughtworks.xstream.converters.UnmarshallingContext)
*/
@Override
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
reader.moveDown(); // <name> tag MUST be at first position at all times
String deckName = reader.getValue();
reader.moveUp();
final Deck result = new Deck(deckName);
while (reader.hasMoreChildren()) {
reader.moveDown();
DeckSection section = DeckSection.smartValueOf(reader.getNodeName());
if ( null == section )
throw new RuntimeException("Quest deck has unknown section: " + reader.getNodeName());
CardPool pool = result.getOrCreate(section);
while (reader.hasMoreChildren()) {
reader.moveDown();
final String sCnt = reader.getAttribute("n");
final int cnt = StringUtils.isNumeric(sCnt) ? Integer.parseInt(sCnt) : 1;
final String nodename = reader.getNodeName();
if ("string".equals(nodename)) {
pool.add(FModel.getMagicDb().getCommonCards().getCard(reader.getValue()));
} else if ("card".equals(nodename)) { // new format
pool.add(this.readCardPrinted(reader), cnt);
}
reader.moveUp();
}
reader.moveUp();
}
return result;
}
}
private static class ItemPoolToXml implements Converter {
@SuppressWarnings("rawtypes")
@Override
public boolean canConvert(final Class clasz) {
return clasz.equals(ItemPool.class);
}
protected void write(final PaperCard cref, final Integer count, final HierarchicalStreamWriter writer) {
writer.startNode("card");
writer.addAttribute("c", cref.getName());
writer.addAttribute("s", cref.getEdition());
if (cref.isFoil()) {
writer.addAttribute("foil", "1");
}
writer.addAttribute("i", Integer.toString(cref.getArtIndex()));
writer.addAttribute("n", count.toString());
writer.endNode();
}
protected void write(final BoosterPack booster, final Integer count, final HierarchicalStreamWriter writer) {
writer.startNode("booster");
writer.addAttribute("s", booster.getEdition());
writer.addAttribute("n", count.toString());
writer.endNode();
}
protected void write(final FatPack fatpack, final Integer count, final HierarchicalStreamWriter writer) {
writer.startNode("fpack");
writer.addAttribute("s", fatpack.getEdition());
writer.addAttribute("n", count.toString());
writer.endNode();
}
protected void write(final TournamentPack booster, final Integer count, final HierarchicalStreamWriter writer) {
writer.startNode("tpack");
writer.addAttribute("s", booster.getEdition());
writer.addAttribute("n", count.toString());
writer.endNode();
}
protected void write(final PreconDeck deck, final Integer count, final HierarchicalStreamWriter writer) {
writer.startNode("precon");
writer.addAttribute("name", deck.getName());
writer.addAttribute("n", count.toString());
writer.endNode();
}
@Override
public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) {
@SuppressWarnings("unchecked")
final ItemPool<InventoryItem> pool = (ItemPool<InventoryItem>) source;
for (final Entry<InventoryItem, Integer> e : pool) {
final InventoryItem item = e.getKey();
final Integer count = e.getValue();
if (item instanceof PaperCard) {
this.write((PaperCard) item, count, writer);
} else if (item instanceof BoosterPack) {
this.write((BoosterPack) item, count, writer);
} else if (item instanceof TournamentPack) {
this.write((TournamentPack) item, count, writer);
} else if (item instanceof FatPack) {
this.write((FatPack) item, count, writer);
} else if (item instanceof PreconDeck) {
this.write((PreconDeck) item, count, writer);
}
}
}
@Override
public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) {
final ItemPool<InventoryItem> result = new ItemPool<InventoryItem>(InventoryItem.class);
while (reader.hasMoreChildren()) {
reader.moveDown();
final String sCnt = reader.getAttribute("n");
final int cnt = StringUtils.isNumeric(sCnt) ? Integer.parseInt(sCnt) : 1;
final String nodename = reader.getNodeName();
if ("string".equals(nodename)) {
result.add(FModel.getMagicDb().getCommonCards().getCard(reader.getValue()));
} else if ("card".equals(nodename)) { // new format
result.add(this.readCardPrinted(reader), cnt);
} else if ("booster".equals(nodename)) {
result.add(this.readBooster(reader), cnt);
} else if ("tpack".equals(nodename)) {
result.add(this.readTournamentPack(reader), cnt);
} else if ("fpack".equals(nodename)) {
result.add(this.readFatPack(reader), cnt);
} else if ("precon".equals(nodename)) {
final PreconDeck toAdd = this.readPreconDeck(reader);
if (null != toAdd) {
result.add(toAdd, cnt);
}
}
reader.moveUp();
}
return result;
}
protected PreconDeck readPreconDeck(final HierarchicalStreamReader reader) {
String name = reader.getAttribute("name");
if (name == null) {
name = reader.getAttribute("s");
}
return QuestController.getPrecons().get(name);
}
protected BoosterPack readBooster(final HierarchicalStreamReader reader) {
final CardEdition ed = FModel.getMagicDb().getEditions().get(reader.getAttribute("s"));
return BoosterPack.FN_FROM_SET.apply(ed);
}
protected TournamentPack readTournamentPack(final HierarchicalStreamReader reader) {
final CardEdition ed = FModel.getMagicDb().getEditions().get(reader.getAttribute("s"));
return TournamentPack.FN_FROM_SET.apply(ed);
}
protected FatPack readFatPack(final HierarchicalStreamReader reader) {
final CardEdition ed = FModel.getMagicDb().getEditions().get(reader.getAttribute("s"));
return FatPack.FN_FROM_SET.apply(ed);
}
protected PaperCard readCardPrinted(final HierarchicalStreamReader reader) {
final String name = reader.getAttribute("c");
final String set = reader.getAttribute("s");
final String sIndex = reader.getAttribute("i");
final short index = StringUtils.isNumeric(sIndex) ? Short.parseShort(sIndex) : 0;
final boolean foil = "1".equals(reader.getAttribute("foil"));
PaperCard c = FModel.getMagicDb().getCommonCards().getCard(name, set, index);
if ( null == c ) c = FModel.getMagicDb().getCommonCards().getCard(name);
return foil ? FModel.getMagicDb().getCommonCards().getFoiled(c) : c;
}
}
}

View File

@@ -0,0 +1,47 @@
package forge.quest.io;
import forge.ImageKeys;
import forge.deck.io.DeckSerializer;
import forge.deck.io.DeckStorage;
import forge.quest.QuestEvent;
import forge.quest.QuestEventDifficulty;
import forge.quest.QuestEventDuel;
import forge.util.FileSection;
import forge.util.FileUtil;
import forge.util.storage.StorageReaderFolder;
import java.io.File;
import java.io.FilenameFilter;
import java.util.List;
import java.util.Map;
public class QuestDuelReader extends StorageReaderFolder<QuestEventDuel> {
public QuestDuelReader(File deckDir0) {
super(deckDir0, QuestEvent.FN_GET_NAME);
// TODO Auto-generated constructor stub
}
@Override
protected QuestEventDuel read(File file) {
final Map<String, List<String>> contents = FileSection.parseSections(FileUtil.readFile(file));
final QuestEventDuel qc = new QuestEventDuel();
// Common properties
FileSection sectionMeta = FileSection.parse(contents.get("metadata"), "=");
qc.setTitle(sectionMeta.get("Title"));
qc.setName(sectionMeta.get("Name")); // Challenges have unique titles
qc.setDifficulty(QuestEventDifficulty.fromString(sectionMeta.get("Difficulty")));
qc.setDescription(sectionMeta.get("Description"));
qc.setCardReward(sectionMeta.get("Card Reward"));
qc.setIconImageKey(ImageKeys.ICON_PREFIX + sectionMeta.get("Icon"));
// Deck
qc.setEventDeck(DeckSerializer.fromSections(contents));
return qc;
}
@Override
protected FilenameFilter getFileFilter() {
return DeckStorage.DCK_FILE_FILTER;
}
}

View File

@@ -0,0 +1,132 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.quest.io;
import forge.card.MagicColor;
import forge.error.BugReporter;
import forge.util.FileUtil;
import forge.util.MyRandom;
import forge.utils.Constants;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
/**
* <p>
* ReadPriceList class.
* </p>
*
* @author Forge
* @version $Id: ReadPriceList.java 24769 2014-02-09 13:56:04Z Hellfish $
*/
public class ReadPriceList {
/** Constant <code>comment="//"</code>. */
private static final String COMMENT = "//";
private HashMap<String, Integer> priceMap;
/**
* <p>
* Constructor for ReadPriceList.
* </p>
*/
public ReadPriceList() {
this.setup();
}
/**
* <p>
* setup.
* </p>
*/
private void setup() {
this.priceMap = this.readFile(Constants.QUEST_CARD_PRICE_FILE);
this.priceMap.putAll(this.readFile(Constants.PRICES_BOOSTER_FILE));
} // setup()
/**
* <p>
* readFile.
* </p>
*
* @param file
* a {@link java.io.File} object.
* @return a {@link java.util.HashMap} object.
*/
private HashMap<String, Integer> readFile(String file) {
final HashMap<String, Integer> map = new HashMap<String, Integer>();
final Random r = MyRandom.getRandom();
List<String> lines = FileUtil.readFile(file);
for (String line : lines) {
if (line.trim().length() == 0) {
break;
}
if (line.startsWith(ReadPriceList.COMMENT)) {
continue;
}
final String[] s = line.split("=");
final String name = s[0].trim();
final String price = s[1].trim();
try {
int val = Integer.parseInt(price.trim());
if (!(MagicColor.Constant.BASIC_LANDS.contains(name) || MagicColor.Constant.SNOW_LANDS.contains(name))) {
float ff = 0;
if (r.nextInt(100) < 90) {
ff = r.nextInt(10) * (float) .01;
} else {
// +/- 50%
ff = r.nextInt(50) * (float) .01;
}
if (r.nextInt(100) < 50) {
val = (int) (val * (1 - ff));
} else {
// +ff%
val = (int) (val * (1 + ff));
}
}
map.put(name, val);
}
catch (final NumberFormatException nfe) {
BugReporter.reportBug("NumberFormatException: " + nfe.getMessage());
}
}
return map;
} // readFile()
/**
* <p>
* getPriceList.
* </p>
*
* @return a {@link java.util.Map} object.
*/
public final Map<String, Integer> getPriceList() {
return this.priceMap;
}
}

View File

@@ -0,0 +1,3 @@
/** Forge Card Game. */
package forge.quest.io;

View File

@@ -0,0 +1,3 @@
/** Forge Card Game. */
package forge.quest;

View File

@@ -1,21 +1,13 @@
package forge.screens.constructed; package forge.screens.constructed;
import java.awt.event.ActionEvent; import java.util.*;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.Vector;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment; import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import forge.Forge;
import forge.Forge.Graphics; import forge.Forge.Graphics;
import forge.assets.FSkin; import forge.assets.FSkin;
import forge.assets.FSkinColor; import forge.assets.FSkinColor;
@@ -24,17 +16,20 @@ import forge.assets.FSkinImage;
import forge.assets.FTextureRegionImage; import forge.assets.FTextureRegionImage;
import forge.deck.CardPool; import forge.deck.CardPool;
import forge.deck.Deck; import forge.deck.Deck;
import forge.deck.DeckProxy;
import forge.deck.DeckSection; import forge.deck.DeckSection;
import forge.deck.DeckType;
import forge.deck.DeckgenUtil; import forge.deck.DeckgenUtil;
import forge.deck.FDeckChooser; import forge.deck.FDeckChooser;
import forge.game.GameType; import forge.game.GameType;
import forge.game.player.LobbyPlayer; import forge.game.player.LobbyPlayer;
import forge.game.player.RegisteredPlayer; import forge.game.player.RegisteredPlayer;
import forge.game.player.LobbyPlayer.PlayerType;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.model.CardCollections;
import forge.model.FModel; import forge.model.FModel;
import forge.net.FServer; import forge.net.FServer;
import forge.net.Lobby; import forge.net.Lobby;
import forge.screens.FScreen;
import forge.screens.LaunchScreen; import forge.screens.LaunchScreen;
import forge.toolbox.FCheckBox; import forge.toolbox.FCheckBox;
import forge.toolbox.FComboBox; import forge.toolbox.FComboBox;
@@ -48,6 +43,7 @@ import forge.toolbox.FOptionPane;
import forge.toolbox.FScrollPane; import forge.toolbox.FScrollPane;
import forge.toolbox.FTextField; import forge.toolbox.FTextField;
import forge.util.Aggregates; import forge.util.Aggregates;
import forge.util.Lang;
import forge.util.MyRandom; import forge.util.MyRandom;
import forge.util.NameGenerator; import forge.util.NameGenerator;
import forge.util.storage.IStorage; import forge.util.storage.IStorage;
@@ -94,15 +90,10 @@ public class ConstructedScreen extends LaunchScreen {
private final List<FLabel> closePlayerBtnList = new ArrayList<FLabel>(6); private final List<FLabel> closePlayerBtnList = new ArrayList<FLabel>(6);
private final FLabel addPlayerBtn = new FLabel.ButtonBuilder().fontSize(14).text("Add a Player").build(); private final FLabel addPlayerBtn = new FLabel.ButtonBuilder().fontSize(14).text("Add a Player").build();
private final List<FDeckChooser> deckChoosers = new ArrayList<FDeckChooser>(8);
private final FCheckBox cbSingletons = new FCheckBox("Singleton Mode"); private final FCheckBox cbSingletons = new FCheckBox("Singleton Mode");
private final FCheckBox cbArtifacts = new FCheckBox("Remove Artifacts"); private final FCheckBox cbArtifacts = new FCheckBox("Remove Artifacts");
// Variants // Variants
private final List<DeckList> schemeDeckLists = new ArrayList<DeckList>();
private final List<DeckList> commanderDeckLists = new ArrayList<DeckList>();
private final List<DeckList> planarDeckLists = new ArrayList<DeckList>();
private final List<DeckList> vgdAvatarLists = new ArrayList<DeckList>();
private final List<PaperCard> vgdAllAvatars = new ArrayList<PaperCard>(); private final List<PaperCard> vgdAllAvatars = new ArrayList<PaperCard>();
private final List<PaperCard> vgdAllAiAvatars = new ArrayList<PaperCard>(); private final List<PaperCard> vgdAllAiAvatars = new ArrayList<PaperCard>();
private final List<PaperCard> nonRandomHumanAvatars = new ArrayList<PaperCard>(); private final List<PaperCard> nonRandomHumanAvatars = new ArrayList<PaperCard>();
@@ -160,13 +151,36 @@ public class ConstructedScreen extends LaunchScreen {
add(playersScroll); add(playersScroll);
addPlayerBtn.setCommand(new FEventHandler() { getDeckChooser(0).initialize(FPref.CONSTRUCTED_P1_DECK_STATE, DeckType.PRECONSTRUCTED_DECK);
getDeckChooser(1).initialize(FPref.CONSTRUCTED_P2_DECK_STATE, DeckType.COLOR_DECK);
getDeckChooser(2).initialize(FPref.CONSTRUCTED_P3_DECK_STATE, DeckType.COLOR_DECK);
getDeckChooser(3).initialize(FPref.CONSTRUCTED_P4_DECK_STATE, DeckType.COLOR_DECK);
getDeckChooser(4).initialize(FPref.CONSTRUCTED_P5_DECK_STATE, DeckType.COLOR_DECK);
getDeckChooser(5).initialize(FPref.CONSTRUCTED_P6_DECK_STATE, DeckType.COLOR_DECK);
getDeckChooser(6).initialize(FPref.CONSTRUCTED_P7_DECK_STATE, DeckType.COLOR_DECK);
getDeckChooser(7).initialize(FPref.CONSTRUCTED_P8_DECK_STATE, DeckType.COLOR_DECK);
// Checkbox event handling
cbSingletons.setCommand(new FEventHandler() {
@Override @Override
public void handleEvent(FEvent e) { public void handleEvent(FEvent e) {
addPlayer(); prefs.setPref(FPref.DECKGEN_SINGLETONS, String.valueOf(cbSingletons.isSelected()));
prefs.save();
} }
}); });
add(addPlayerBtn); cbArtifacts.setCommand(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
prefs.setPref(FPref.DECKGEN_ARTIFACTS, String.valueOf(cbArtifacts.isSelected()));
prefs.save();
}
});
// Pre-select checkboxes
cbSingletons.setSelected(prefs.getPrefBoolean(FPref.DECKGEN_SINGLETONS));
cbArtifacts.setSelected(prefs.getPrefBoolean(FPref.DECKGEN_ARTIFACTS));
updatePlayersFromPrefs();
} }
@Override @Override
@@ -203,35 +217,13 @@ public class ConstructedScreen extends LaunchScreen {
} }
public final FDeckChooser getDeckChooser(int playernum) { public final FDeckChooser getDeckChooser(int playernum) {
return deckChoosers.get(playernum); return playerPanels.get(playernum).deckChooser;
}
private class DeckList extends FList<Object> {
Object selectedValue;
public Object getSelectedValue() {
return selectedValue;
}
}
public boolean isPlayerAI(int playernum) {
return playerPanels.get(playernum).getPlayerType() == PlayerType.COMPUTER;
} }
public int getNumPlayers() { public int getNumPlayers() {
return activePlayersNum; return activePlayersNum;
} }
public final List<Integer> getParticipants() {
final List<Integer> participants = new ArrayList<Integer>(activePlayersNum);
for (final PlayerPanel panel : playerPanels) {
if (panel.isVisible()) {
participants.add(playerPanels.indexOf(panel));
}
}
return participants;
}
@Override @Override
protected boolean buildLaunchParams(LaunchParams launchParams) { protected boolean buildLaunchParams(LaunchParams launchParams) {
launchParams.gameType = GameType.Constructed; launchParams.gameType = GameType.Constructed;
@@ -241,7 +233,7 @@ public class ConstructedScreen extends LaunchScreen {
return false; return false;
} }
for (final int i : getParticipants()) { for (int i = 0; i < activePlayersNum; i++) {
if (getDeckChooser(i).getPlayer() == null) { if (getDeckChooser(i).getPlayer() == null) {
FOptionPane.showMessageDialog("Please specify a deck for " + getPlayerName(i)); FOptionPane.showMessageDialog("Please specify a deck for " + getPlayerName(i));
return false; return false;
@@ -253,7 +245,7 @@ public class ConstructedScreen extends LaunchScreen {
boolean checkLegality = FModel.getPreferences().getPrefBoolean(FPref.ENFORCE_DECK_LEGALITY); boolean checkLegality = FModel.getPreferences().getPrefBoolean(FPref.ENFORCE_DECK_LEGALITY);
if (checkLegality && !variantTypes.contains(GameType.Commander)) { //Commander deck replaces regular deck and is checked later if (checkLegality && !variantTypes.contains(GameType.Commander)) { //Commander deck replaces regular deck and is checked later
for (final int i : getParticipants()) { for (int i = 0; i < activePlayersNum; i++) {
String name = getPlayerName(i); String name = getPlayerName(i);
String errMsg = GameType.Constructed.getDecksFormat().getDeckConformanceProblem(getDeckChooser(i).getPlayer().getDeck()); String errMsg = GameType.Constructed.getDecksFormat().getDeckConformanceProblem(getDeckChooser(i).getPlayer().getDeck());
if (errMsg != null) { if (errMsg != null) {
@@ -265,11 +257,12 @@ public class ConstructedScreen extends LaunchScreen {
Lobby lobby = FServer.getLobby(); Lobby lobby = FServer.getLobby();
List<RegisteredPlayer> players = new ArrayList<RegisteredPlayer>(); List<RegisteredPlayer> players = new ArrayList<RegisteredPlayer>();
for (final int i : getParticipants()) { for (int i = 0; i < activePlayersNum; i++) {
PlayerPanel playerPanel = playerPanels.get(i);
String name = getPlayerName(i); String name = getPlayerName(i);
LobbyPlayer lobbyPlayer = isPlayerAI(i) ? lobby.getAiPlayer(name, LobbyPlayer lobbyPlayer = playerPanel.isPlayerAI() ? lobby.getAiPlayer(name,
getPlayerAvatar(i)) : lobby.getGuiPlayer(); getPlayerAvatar(i)) : lobby.getGuiPlayer();
RegisteredPlayer rp = getDeckChooser(i).getPlayer(); RegisteredPlayer rp = playerPanel.deckChooser.getPlayer();
if (variantTypes.isEmpty()) { if (variantTypes.isEmpty()) {
rp.setTeamNumber(getTeam(i)); rp.setTeamNumber(getTeam(i));
@@ -279,7 +272,7 @@ public class ConstructedScreen extends LaunchScreen {
Deck deck = null; Deck deck = null;
boolean isCommanderMatch = variantTypes.contains(GameType.Commander); boolean isCommanderMatch = variantTypes.contains(GameType.Commander);
if (isCommanderMatch) { if (isCommanderMatch) {
Object selected = commanderDeckLists.get(i).getSelectedValue(); Object selected = playerPanel.commanderDeckList.getSelectedValue();
if (selected instanceof String) { if (selected instanceof String) {
String sel = (String) selected; String sel = (String) selected;
IStorage<Deck> comDecks = FModel.getDecks().getCommander(); IStorage<Deck> comDecks = FModel.getDecks().getCommander();
@@ -312,7 +305,7 @@ public class ConstructedScreen extends LaunchScreen {
//Archenemy //Archenemy
if (variantTypes.contains(GameType.ArchenemyRumble) if (variantTypes.contains(GameType.ArchenemyRumble)
|| (variantTypes.contains(GameType.Archenemy) && playerIsArchenemy)) { || (variantTypes.contains(GameType.Archenemy) && playerIsArchenemy)) {
Object selected = schemeDeckLists.get(i).getSelectedValue(); Object selected = playerPanel.schemeDeckList.getSelectedValue();
CardPool schemePool = null; CardPool schemePool = null;
if (selected instanceof String) { if (selected instanceof String) {
String sel = (String) selected; String sel = (String) selected;
@@ -347,7 +340,7 @@ public class ConstructedScreen extends LaunchScreen {
//Planechase //Planechase
if (variantTypes.contains(GameType.Planechase)) { if (variantTypes.contains(GameType.Planechase)) {
Object selected = planarDeckLists.get(i).getSelectedValue(); Object selected = playerPanel.planarDeckList.getSelectedValue();
CardPool planePool = null; CardPool planePool = null;
if (selected instanceof String) { if (selected instanceof String) {
String sel = (String) selected; String sel = (String) selected;
@@ -381,7 +374,7 @@ public class ConstructedScreen extends LaunchScreen {
//Vanguard //Vanguard
if (variantTypes.contains(GameType.Vanguard)) { if (variantTypes.contains(GameType.Vanguard)) {
Object selected = vgdAvatarLists.get(i).getSelectedValue(); Object selected = playerPanel.vgdAvatarList.getSelectedValue();
if (selected instanceof String) { if (selected instanceof String) {
String sel = (String) selected; String sel = (String) selected;
if (sel.contains("Use deck's default avatar") && deck.has(DeckSection.Avatar)) { if (sel.contains("Use deck's default avatar") && deck.has(DeckSection.Avatar)) {
@@ -448,10 +441,26 @@ public class ConstructedScreen extends LaunchScreen {
private final FLabel vgdSelectorBtn = new FLabel.ButtonBuilder().text("Select a Vanguard avatar").build(); private final FLabel vgdSelectorBtn = new FLabel.ButtonBuilder().text("Select a Vanguard avatar").build();
private final FLabel vgdLabel = newLabel("Vanguard:"); private final FLabel vgdLabel = newLabel("Vanguard:");
private final FDeckChooser deckChooser;
private final DeckList schemeDeckList, commanderDeckList, planarDeckList, vgdAvatarList;
public PlayerPanel(final int index0) { public PlayerPanel(final int index0) {
super(); super();
index = index0; index = index0;
playerIsArchenemy = index == 0; playerIsArchenemy = index == 0;
deckChooser = new FDeckChooser(isPlayerAI());
deckChooser.initialize();
deckChooser.getLstDecks().setSelectCommand(new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
String text = deckChooser.getSelectedDeckType().toString() + ": " + Lang.joinHomogenous(deckChooser.getLstDecks().getSelectedItems(), DeckProxy.FN_GET_NAME);
setDeckSelectorButtonText(text);
}
});
schemeDeckList = new DeckList();
commanderDeckList = new DeckList();
planarDeckList = new DeckList();
vgdAvatarList = new DeckList();
// Add a button to players 3+ to remove them from the setup // Add a button to players 3+ to remove them from the setup
if (index >= 2) { if (index >= 2) {
@@ -502,6 +511,39 @@ public class ConstructedScreen extends LaunchScreen {
addHandlersToVariantsControls(); addHandlersToVariantsControls();
updateVariantControlsVisibility(); updateVariantControlsVisibility();
final CardCollections decks = FModel.getDecks();
commanderDeckList.list.addItem("Generate");
if (decks.getCommander().size() > 0) {
commanderDeckList.list.addItem("Random");
for (Deck comDeck : decks.getCommander()) {
commanderDeckList.list.addItem(comDeck);
}
}
commanderDeckList.setSelectedIndex(0);
schemeDeckList.list.addItem("Use deck's scheme section (random if unavailable)");
schemeDeckList.list.addItem("Generate");
if (decks.getScheme().size() > 0) {
schemeDeckList.list.addItem("Random");
for (Deck schemeDeck : decks.getScheme()) {
schemeDeckList.list.addItem(schemeDeck);
}
}
schemeDeckList.setSelectedIndex(0);
planarDeckList.list.addItem("Use deck's planes section (random if unavailable)");
planarDeckList.list.addItem("Generate");
if (decks.getPlane().size() > 0) {
planarDeckList.list.addItem("Random");
for (Deck planarDeck : decks.getPlane()) {
planarDeckList.list.addItem(planarDeck);
}
}
planarDeckList.setSelectedIndex(0);
updateVanguardList();
} }
@Override @Override
@@ -557,7 +599,7 @@ public class ConstructedScreen extends LaunchScreen {
private final FEventHandler humanAiSwitched = new FEventHandler() { private final FEventHandler humanAiSwitched = new FEventHandler() {
@Override @Override
public void handleEvent(FEvent e) { public void handleEvent(FEvent e) {
updateVanguardList(index); updateVanguardList();
} }
}; };
@@ -634,8 +676,8 @@ public class ConstructedScreen extends LaunchScreen {
vgdLabel.setVisible(appliedVariants.contains(GameType.Vanguard)); vgdLabel.setVisible(appliedVariants.contains(GameType.Vanguard));
} }
public PlayerType getPlayerType() { public boolean isPlayerAI() {
return humanAiSwitch.isToggled() ? PlayerType.COMPUTER : PlayerType.HUMAN; return humanAiSwitch.isToggled();
} }
public void setVanguardButtonText(String text) { public void setVanguardButtonText(String text) {
@@ -871,6 +913,79 @@ public class ConstructedScreen extends LaunchScreen {
public String getPlayerName() { public String getPlayerName() {
return txtPlayerName.getText(); return txtPlayerName.getText();
} }
private void changeDeck(final GameType forGameType) {
switch (forGameType) {
case Constructed:
Forge.openScreen(deckChooser);
break;
case Archenemy:
case ArchenemyRumble:
if (playerIsArchenemy) {
Forge.openScreen(schemeDeckList);
}
else {
Forge.openScreen(deckChooser);
}
break;
case Commander:
Forge.openScreen(commanderDeckList);
break;
case Planechase:
Forge.openScreen(planarDeckList);
break;
case Vanguard:
updateVanguardList();
Forge.openScreen(vgdAvatarList);
break;
default:
break;
}
}
/** update vanguard list. */
public void updateVanguardList() {
Object lastSelection = vgdAvatarList.getSelectedValue();
vgdAvatarList.setSelectedIndex(-1);
vgdAvatarList.list.setListData(isPlayerAI() ? aiListData : humanListData);
if (lastSelection != null) {
vgdAvatarList.setSelectedValue(lastSelection);
}
if (vgdAvatarList.getSelectedIndex() == -1) {
vgdAvatarList.setSelectedIndex(0);
}
}
private class DeckList extends FScreen {
private final FList<Object> list;
private int selectedIndex;
private DeckList() {
super(true, "", false);
list = new FList<Object>();
}
public int getSelectedIndex() {
return selectedIndex;
}
public void setSelectedIndex(int index) {
selectedIndex = index;
}
public Object getSelectedValue() {
return list.getItemAt(selectedIndex);
}
public void setSelectedValue(Object value) {
selectedIndex = list.getIndexOf(value);
}
@Override
protected void doLayout(float startY, float width, float height) {
list.setBounds(0, startY, width, height - startY);
}
}
} }
/** Saves avatar prefs for players one and two. */ /** Saves avatar prefs for players one and two. */
@@ -961,7 +1076,7 @@ public class ConstructedScreen extends LaunchScreen {
int lastTeam = -1; int lastTeam = -1;
final List<Integer> teamList = appliedVariants.contains(GameType.Archenemy) ? archenemyTeams : teams; final List<Integer> teamList = appliedVariants.contains(GameType.Archenemy) ? archenemyTeams : teams;
for (final int i : getParticipants()) { for (int i = 0; i < activePlayersNum; i++) {
if (lastTeam == -1) { if (lastTeam == -1) {
lastTeam = teamList.get(i); lastTeam = teamList.get(i);
} }
@@ -977,7 +1092,7 @@ public class ConstructedScreen extends LaunchScreen {
/** This listener unlocks the relevant buttons for players /** This listener unlocks the relevant buttons for players
* and enables/disables archenemy combobox as appropriate. */ * and enables/disables archenemy combobox as appropriate. */
private ItemListener iListenerVariants = new ItemListener() { /*private ItemListener iListenerVariants = new ItemListener() {
@Override @Override
public void itemStateChanged(ItemEvent arg0) { public void itemStateChanged(ItemEvent arg0) {
FCheckBox cb = (FCheckBox) arg0.getSource(); FCheckBox cb = (FCheckBox) arg0.getSource();
@@ -1043,7 +1158,7 @@ public class ConstructedScreen extends LaunchScreen {
//This listener will look for a vanguard avatar being selected in the lists //This listener will look for a vanguard avatar being selected in the lists
//and update the corresponding detail panel. //and update the corresponding detail panel.
/*private ListSelectionListener vgdLSListener = new ListSelectionListener() { private ListSelectionListener vgdLSListener = new ListSelectionListener() {
@Override @Override
public void valueChanged(ListSelectionEvent e) { public void valueChanged(ListSelectionEvent e) {
int index = vgdAvatarLists.indexOf(e.getSource()); int index = vgdAvatarLists.indexOf(e.getSource());
@@ -1075,22 +1190,10 @@ public class ConstructedScreen extends LaunchScreen {
return appliedVariants.contains(GameType.Archenemy) ? archenemyTeams.get(playerIndex) : teams.get(playerIndex); return appliedVariants.contains(GameType.Archenemy) ? archenemyTeams.get(playerIndex) : teams.get(playerIndex);
} }
/*public List<FList<Object>> getPlanarDeckLists() { public boolean isPlayerAI(final int playernum) {
return planarDeckLists; return playerPanels.get(playernum).isPlayerAI();
} }
public List<FList<Object>> getCommanderDeckLists() {
return commanderDeckLists;
}
public List<FList<Object>> getSchemeDeckLists() {
return schemeDeckLists;
}
public List<FList<Object>> getVanguardLists() {
return vgdAvatarLists;
}*/
public boolean isPlayerArchenemy(final int playernum) { public boolean isPlayerArchenemy(final int playernum) {
return playerPanels.get(playernum).playerIsArchenemy; return playerPanels.get(playernum).playerIsArchenemy;
} }
@@ -1142,18 +1245,4 @@ public class ConstructedScreen extends LaunchScreen {
} }
} }
} }
/** update vanguard list. */
public void updateVanguardList(int playerIndex) {
/*FList<Object> vgdList = getVanguardLists().get(playerIndex);
Object lastSelection = vgdList.getSelectedValue();
vgdList.setListData(isPlayerAI(playerIndex) ? aiListData : humanListData);
if (null != lastSelection) {
vgdList.setSelectedValue(lastSelection, true);
}
if (-1 == vgdList.getSelectedIndex()) {
vgdList.setSelectedIndex(0);
}*/
}
} }

View File

@@ -31,8 +31,17 @@ public class FComboBox<E> extends FTextField {
initialize(); initialize();
} }
private void initialize() {
if (!items.isEmpty()) {
setSelectedItem(items.get(0)); //select first item by default
}
}
public void addItem(E item) { public void addItem(E item) {
items.add(item); items.add(item);
if (items.size() == 1) {
setSelectedItem(item); //select first item by default
}
} }
public boolean removeItem(E item) { public boolean removeItem(E item) {
@@ -81,6 +90,7 @@ public class FComboBox<E> extends FTextField {
selectedItem = item; selectedItem = item;
super.setText(item.toString()); super.setText(item.toString());
} }
else { return; }
} }
else { else {
selectedItem = null; selectedItem = null;
@@ -104,12 +114,6 @@ public class FComboBox<E> extends FTextField {
setText(text0); setText(text0);
} }
private void initialize() {
if (!items.isEmpty()) {
setSelectedItem(items.get(0)); //select first item by default
}
}
@Override @Override
public boolean tap(float x, float y, int count) { public boolean tap(float x, float y, int count) {
dropDown.setVisible(!dropDown.isVisible()); dropDown.setVisible(!dropDown.isVisible());

View File

@@ -83,6 +83,13 @@ public class FList<E> extends FScrollPane {
groups.clear(); groups.clear();
} }
public void setListData(Iterable<E> items0) {
clear();
for (E item : items0) {
addItem(item);
}
}
public boolean isEmpty() { public boolean isEmpty() {
return groups.isEmpty(); return groups.isEmpty();
} }
@@ -95,7 +102,7 @@ public class FList<E> extends FScrollPane {
return count; return count;
} }
public Object getItemAt(int index) { public E getItemAt(int index) {
int count = 0; int count = 0;
for (ListGroup group : groups) { for (ListGroup group : groups) {
for (ListItem item : group.items) { for (ListItem item : group.items) {
@@ -108,6 +115,19 @@ public class FList<E> extends FScrollPane {
return null; return null;
} }
public int getIndexOf(E value) {
int count = 0;
for (ListGroup group : groups) {
for (ListItem item : group.items) {
if (item.value == value) {
return count;
}
count++;
}
}
return -1;
}
public void setListItemRenderer(ListItemRenderer<E> renderer0) { public void setListItemRenderer(ListItemRenderer<E> renderer0) {
renderer = renderer0; renderer = renderer0;
} }

View File

@@ -0,0 +1,54 @@
/*
* Forge: Play Magic: the Gathering.
* Copyright (C) 2011 Forge Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package forge.utils;
import org.w3c.dom.Node;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;
/**
* TODO: Write javadoc for this type.
*
*/
public class XmlUtil {
/**
* Node to string.
*
* @param node the node
* @return the string
*/
public static String nodeToString(final Node node) {
final StringWriter sw = new StringWriter();
try {
final Transformer t = TransformerFactory.newInstance().newTransformer();
t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
t.setOutputProperty(OutputKeys.INDENT, "yes");
t.transform(new DOMSource(node), new StreamResult(sw));
} catch (final TransformerException te) {
System.out.println("nodeToString Transformer Exception");
}
return sw.toString();
}
}