- Added the capability to play Challenges vs predetermined decks (along with a few other related options to disallow specific quest mode things)

- Added Sorin vs Tibalt, and Tibalt vs Sorin as examples of Challenges that force you to use a specific Deck. (They seemed to be the best duel deck compatibility for the AI).
This commit is contained in:
Sol
2013-05-22 03:12:54 +00:00
parent 30454f3cab
commit 695b446c60
8 changed files with 239 additions and 11 deletions

2
.gitattributes vendored
View File

@@ -12816,12 +12816,14 @@ res/quest/challenges/Private[!!-~]Domain.dck -text
res/quest/challenges/Quest[!!-~]for[!!-~]Ula's[!!-~]Temple.dck -text res/quest/challenges/Quest[!!-~]for[!!-~]Ula's[!!-~]Temple.dck -text
res/quest/challenges/Reactor[!!-~]Meltdown.dck -text res/quest/challenges/Reactor[!!-~]Meltdown.dck -text
res/quest/challenges/Repressed[!!-~]Magic.dck -text res/quest/challenges/Repressed[!!-~]Magic.dck -text
res/quest/challenges/Sorin[!!-~]vs[!!-~]Tibalt.dck -text
res/quest/challenges/The[!!-~]Backlash[!!-~]Machine.dck -text res/quest/challenges/The[!!-~]Backlash[!!-~]Machine.dck -text
res/quest/challenges/The[!!-~]Court[!!-~]Jester.dck -text res/quest/challenges/The[!!-~]Court[!!-~]Jester.dck -text
res/quest/challenges/The[!!-~]Desert[!!-~]Caravan.dck -text res/quest/challenges/The[!!-~]Desert[!!-~]Caravan.dck -text
res/quest/challenges/The[!!-~]King's[!!-~]Contest.dck -text res/quest/challenges/The[!!-~]King's[!!-~]Contest.dck -text
res/quest/challenges/The[!!-~]Pied[!!-~]Piper.dck -text res/quest/challenges/The[!!-~]Pied[!!-~]Piper.dck -text
res/quest/challenges/The[!!-~]Torpor[!!-~]Orb.dck -text res/quest/challenges/The[!!-~]Torpor[!!-~]Orb.dck -text
res/quest/challenges/Tibalt[!!-~]vs[!!-~]Sorin.dck -text
res/quest/challenges/Zombie[!!-~]Attack!.dck -text res/quest/challenges/Zombie[!!-~]Attack!.dck -text
res/quest/duels/Abraham[!!-~]Lincoln[!!-~]3.dck -text res/quest/duels/Abraham[!!-~]Lincoln[!!-~]3.dck -text
res/quest/duels/Air-Walker[!!-~]2.dck -text res/quest/duels/Air-Walker[!!-~]2.dck -text

View File

@@ -0,0 +1,56 @@
[quest]
id=29
AILife=20
HumanLife=20
HumanDeck=Tibalt vs Sorin.dck
UseBazaar=False
ForceAnte=False
Repeat=false
Wins=20
Card Reward=2 random rares
Credit Reward=200
[metadata]
Name=quest29
Title=Tibalt (vs Sorin)
Difficulty=hard
Description=Play as Sorin vs Tibalt the Pain Mage. NOTE: This challenge uses a preselected deck and ignores specific Bazaar settings.
Icon=Tibalt.jpg
Deck Type=constructed
[main]
14 Mountain
6 Swamp
2 Ashmouth Hound
1 Coal Stoker
1 Corpse Connoisseur
1 Gang of Devils
1 Goblin Arsonist
1 Hellrider
2 Hellspark Elemental
1 Lavaborn Muse
1 Mad Prophet
1 Reassembling Skeleton
1 Scorched Rusalka
1 Scourge Devil
1 Shambling Remains
1 Skirsdag Cultist
2 Vithian Stinger
1 Sulfuric Vortex
1 Blazing Salvo
1 Flame Javelin
1 Geistflame
1 Strangling Soot
1 Terminate
2 Akoum Refuge
2 Rakdos Carnarium
1 Tibalt, the Fiend-Blooded
1 Blightning
1 Breaking Point
2 Browbeat
1 Bump in the Night
1 Devil's Play
1 Faithless Looting
1 Flame Slash
1 Pyroclasm
1 Recoup
1 Torrent of Souls
[sideboard]

View File

@@ -0,0 +1,56 @@
[quest]
id=28
AILife=20
HumanLife=20
HumanDeck=Sorin vs Tibalt.dck
UseBazaar=False
ForceAnte=False
Repeat=false
Wins=20
Card Reward=2 random rares
Credit Reward=200
[metadata]
Name=quest28
Title=Sorin (vs Tibalt)
Difficulty=medium
Description=Play as Tibalt vs Sorin, Lord of Innistrad. NOTE: This challenge uses a preselected deck and ignores specific Bazaar settings.
Icon=Sorin.jpg
Deck Type=constructed
[main]
9 Plains
12 Swamp
1 Bloodrage Vampire
1 Butcher of Malakir
1 Child of Night
2 Doomed Traveler
2 Duskhunter Bat
1 Fiend Hunter
1 Gatekeeper of Malakir
1 Mausoleum Guard
1 Mesmeric Fiend
1 Phantom General
1 Revenant Patriarch
1 Sengir Vampire
1 Twilight Drover
1 Vampire Lacerator
1 Vampire Nighthawk
1 Vampire Outcasts
1 Wall of Omens
1 Field of Souls
1 Mark of the Vampire
1 Mortify
1 Sorin's Thirst
1 Unmake
1 Urge to Feed
1 Vampire's Bite
1 Zealous Persecution
2 Evolving Wilds
2 Tainted Field
1 Sorin, Lord of Innistrad
1 Absorb Vis
1 Ancient Craving
1 Death Grasp
1 Decompose
1 Lingering Souls
2 Spectral Procession
[sideboard]

View File

@@ -215,8 +215,9 @@ public class GameNew {
* *
* TODO: Accept something like match state as parameter. Match should be aware of players, * TODO: Accept something like match state as parameter. Match should be aware of players,
* their decks and other special starting conditions. * their decks and other special starting conditions.
* @param forceAnte Forces ante on or off no matter what your preferences
*/ */
public static void newGame(final GameState game, final boolean canRandomFoil) { public static void newGame(final GameState game, final boolean canRandomFoil, Boolean forceAnte) {
Card.resetUniqueNumber(); Card.resetUniqueNumber();
// need this code here, otherwise observables fail // need this code here, otherwise observables fail
@@ -225,7 +226,7 @@ public class GameNew {
trigHandler.clearDelayedTrigger(); trigHandler.clearDelayedTrigger();
// friendliness // friendliness
boolean useAnte = preferences.getPrefBoolean(FPref.UI_ANTE); boolean useAnte = forceAnte != null ? forceAnte : preferences.getPrefBoolean(FPref.UI_ANTE);
final Set<CardPrinted> rAICards = new HashSet<CardPrinted>(); final Set<CardPrinted> rAICards = new HashSet<CardPrinted>();
Map<Player, Set<CardPrinted>> removedAnteCards = new HashMap<Player, Set<CardPrinted>>(); Map<Player, Set<CardPrinted>> removedAnteCards = new HashMap<Player, Set<CardPrinted>>();

View File

@@ -51,6 +51,8 @@ public class MatchController {
private int gamesPerMatch = 3; private int gamesPerMatch = 3;
private int gamesToWinMatch = 2; private int gamesToWinMatch = 2;
private Boolean forceAnte = false;
private GameState currentGame = null; private GameState currentGame = null;
private final List<GameOutcome> gamesPlayed = new ArrayList<GameOutcome>(); private final List<GameOutcome> gamesPlayed = new ArrayList<GameOutcome>();
@@ -67,6 +69,11 @@ public class MatchController {
gameType = type; gameType = type;
} }
public MatchController(GameType type, Map<LobbyPlayer, PlayerStartConditions> map, Boolean forceAnte) {
this(type, map);
this.forceAnte = forceAnte;
}
/** /**
* Gets the games played. * Gets the games played.
* *
@@ -145,7 +152,7 @@ public class MatchController {
attachUiToMatch(this, FControl.SINGLETON_INSTANCE.getLobby().getGuiPlayer()); attachUiToMatch(this, FControl.SINGLETON_INSTANCE.getLobby().getGuiPlayer());
final boolean canRandomFoil = Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_RANDOM_FOIL) && gameType == GameType.Constructed; final boolean canRandomFoil = Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_RANDOM_FOIL) && gameType == GameType.Constructed;
GameNew.newGame(currentGame, canRandomFoil); GameNew.newGame(currentGame, canRandomFoil, this.forceAnte);
currentGame.setAge(GameAge.Mulligan); currentGame.setAge(GameAge.Mulligan);
} catch (Exception e) { } catch (Exception e) {

View File

@@ -353,7 +353,15 @@ public class SSubmenuQuestUtil {
} }
final QuestController qData = Singletons.getModel().getQuest(); final QuestController qData = Singletons.getModel().getQuest();
Deck deck = SSubmenuQuestUtil.getCurrentDeck(); Deck deck = null;
if (event instanceof QuestEventChallenge) {
// Predefined HumanDeck
deck = ((QuestEventChallenge) event).getHumanDeck();
}
if (deck == null) {
// If no predefined Deck, use the Player's Deck
deck = SSubmenuQuestUtil.getCurrentDeck();
}
if (deck == null) { if (deck == null) {
String msg = "Please select a Quest Deck."; String msg = "Please select a Quest Deck.";
JOptionPane.showMessageDialog(null, msg, "No Deck", JOptionPane.ERROR_MESSAGE); JOptionPane.showMessageDialog(null, msg, "No Deck", JOptionPane.ERROR_MESSAGE);
@@ -393,22 +401,36 @@ public class SSubmenuQuestUtil {
worker.execute(); worker.execute();
int extraLifeHuman = 0; int extraLifeHuman = 0;
Integer lifeHuman = null;
boolean useBazaar = true;
Boolean forceAnte = false;
int lifeAI = 20; int lifeAI = 20;
if (event instanceof QuestEventChallenge) { if (event instanceof QuestEventChallenge) {
lifeAI = ((QuestEventChallenge) event).getAILife(); lifeAI = ((QuestEventChallenge) event).getAILife();
lifeHuman = ((QuestEventChallenge) event).getHumanLife();
if (qData.getAssets().hasItem(QuestItemType.ZEPPELIN)) { if (qData.getAssets().hasItem(QuestItemType.ZEPPELIN)) {
extraLifeHuman = 3; extraLifeHuman = 3;
} }
useBazaar = ((QuestEventChallenge) event).isUseBazaar();
forceAnte = ((QuestEventChallenge) event).isForceAnte();
} }
PlayerStartConditions humanStart = new PlayerStartConditions(SSubmenuQuestUtil.getCurrentDeck()); PlayerStartConditions humanStart = new PlayerStartConditions(deck);
humanStart.setStartingLife(qData.getAssets().getLife(qData.getMode()) + extraLifeHuman);
humanStart.setCardsOnBattlefield(QuestUtil.getHumanStartingCards(qData, event));
PlayerStartConditions aiStart = new PlayerStartConditions(event.getEventDeck()); PlayerStartConditions aiStart = new PlayerStartConditions(event.getEventDeck());
aiStart.setStartingLife(lifeAI);
aiStart.setCardsOnBattlefield(QuestUtil.getComputerStartingCards(event)); if (lifeHuman != null) {
humanStart.setStartingLife(lifeHuman);
} else {
humanStart.setStartingLife(qData.getAssets().getLife(qData.getMode()) + extraLifeHuman);
}
if (useBazaar) {
humanStart.setCardsOnBattlefield(QuestUtil.getHumanStartingCards(qData, event));
aiStart.setStartingLife(lifeAI);
aiStart.setCardsOnBattlefield(QuestUtil.getComputerStartingCards(event));
}
MatchStartHelper msh = new MatchStartHelper(); MatchStartHelper msh = new MatchStartHelper();
msh.addPlayer(Singletons.getControl().getLobby().getQuestPlayer(), humanStart); msh.addPlayer(Singletons.getControl().getLobby().getQuestPlayer(), humanStart);
@@ -417,7 +439,7 @@ public class SSubmenuQuestUtil {
aiPlayer.setIconImageKey(event.getIconImageKey()); aiPlayer.setIconImageKey(event.getIconImageKey());
msh.addPlayer(aiPlayer, aiStart); msh.addPlayer(aiPlayer, aiStart);
final MatchController mc = new MatchController(GameType.Quest, msh.getPlayerMap()); final MatchController mc = new MatchController(GameType.Quest, msh.getPlayerMap(), forceAnte);
FThreads.invokeInEdtLater(new Runnable(){ FThreads.invokeInEdtLater(new Runnable(){
@Override @Override
public void run() { public void run() {

View File

@@ -22,6 +22,8 @@ import java.util.List;
import com.google.common.base.Function; import com.google.common.base.Function;
import forge.deck.Deck;
/** /**
* <p> * <p>
* QuestQuest class. * QuestQuest class.
@@ -47,12 +49,18 @@ public class QuestEventChallenge extends QuestEvent {
/** The ai life. */ /** The ai life. */
private int aiLife = 25; private int aiLife = 25;
private Integer humanLife = null;
/** The credits reward. */ /** The credits reward. */
private int creditsReward = 100; private int creditsReward = 100;
/** The repeatable. */ /** The repeatable. */
private boolean repeatable = false; private boolean repeatable = false;
private boolean useBazaar = true;
private Boolean forceAnte = null;
/** The wins reqd. */ /** The wins reqd. */
private int winsReqd = 20; private int winsReqd = 20;
@@ -63,6 +71,8 @@ public class QuestEventChallenge extends QuestEvent {
/** The ai extra cards. */ /** The ai extra cards. */
private List<String> aiExtraCards = new ArrayList<String>(); private List<String> aiExtraCards = new ArrayList<String>();
private Deck humanDeck = null;
/** /**
* Instantiates a new quest challenge. * Instantiates a new quest challenge.
*/ */
@@ -248,4 +258,60 @@ public class QuestEventChallenge extends QuestEvent {
public void setHumanExtraCards(final List<String> humanExtraCards0) { public void setHumanExtraCards(final List<String> humanExtraCards0) {
this.humanExtraCards = 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

@@ -9,6 +9,7 @@ import java.util.Map;
import forge.ImageCache; import forge.ImageCache;
import forge.deck.Deck; import forge.deck.Deck;
import forge.deck.io.DeckSerializer; import forge.deck.io.DeckSerializer;
import forge.properties.NewConstants;
import forge.quest.QuestEventChallenge; import forge.quest.QuestEventChallenge;
import forge.quest.QuestEventDifficulty; import forge.quest.QuestEventDifficulty;
import forge.util.FileSection; import forge.util.FileSection;
@@ -38,6 +39,23 @@ public class QuestChallengeReader extends StorageReaderFolder<QuestEventChalleng
qc.setCardReward(sectionQuest.get("Card Reward")); qc.setCardReward(sectionQuest.get("Card Reward"));
qc.setHumanExtraCards(Arrays.asList(TextUtil.split(sectionQuest.get("HumanExtras", ""), '|'))); qc.setHumanExtraCards(Arrays.asList(TextUtil.split(sectionQuest.get("HumanExtras", ""), '|')));
qc.setAiExtraCards(Arrays.asList(TextUtil.split(sectionQuest.get("AIExtras", ""), '|'))); 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", qc.isUseBazaar()));
String force = sectionQuest.get("ForceAnte", null);
if (force != null) {
qc.setForceAnte(Boolean.valueOf(force));
}
String humanDeck = sectionQuest.get("HumanDeck", null);
if (humanDeck != null) {
File humanFile = new File(NewConstants.DEFAULT_CHALLENGES_DIR, humanDeck);
qc.setHumanDeck(Deck.fromFile(humanFile));
}
// Common properties // Common properties
FileSection sectionMeta = FileSection.parse(contents.get("metadata"), "="); FileSection sectionMeta = FileSection.parse(contents.get("metadata"), "=");