Support retrying if you lose a game in Planar Conquest

This commit is contained in:
drdev
2016-01-10 17:52:51 +00:00
parent 65a49d7e41
commit 64723e431e
6 changed files with 95 additions and 172 deletions

View File

@@ -28,12 +28,12 @@ public class ConquestWinLose extends ControlWinLose {
@Override @Override
public final void showRewards() { public final void showRewards() {
FModel.getConquest().showGameRewards(lastGame, getView()); FModel.getConquest().showGameOutcome(lastGame, getView());
} }
@Override @Override
public final void actionOnQuit() { public final void actionOnQuit() {
FModel.getConquest().finishEvent();
super.actionOnQuit(); super.actionOnQuit();
FModel.getConquest().onGameFinished(lastGame);
} }
} }

View File

@@ -3,14 +3,11 @@ package forge.screens.planarconquest;
import forge.Forge; import forge.Forge;
import forge.model.FModel; import forge.model.FModel;
import forge.planarconquest.ConquestEvent; import forge.planarconquest.ConquestEvent;
import forge.planarconquest.ConquestController.GameRunner;
import forge.planarconquest.ConquestEvent.IConquestEventLauncher;
import forge.screens.LaunchScreen; import forge.screens.LaunchScreen;
import forge.screens.LoadingOverlay; import forge.screens.LoadingOverlay;
import forge.toolbox.FOptionPane; import forge.toolbox.FOptionPane;
import forge.util.ThreadUtil;
public class ConquestEventScreen extends LaunchScreen implements IConquestEventLauncher { public class ConquestEventScreen extends LaunchScreen {
protected static final float PADDING = FOptionPane.PADDING; protected static final float PADDING = FOptionPane.PADDING;
private final ConquestEvent event; private final ConquestEvent event;
@@ -37,22 +34,12 @@ public class ConquestEventScreen extends LaunchScreen implements IConquestEventL
@Override @Override
protected void startMatch() { protected void startMatch() {
if (launchedEvent) { return; } //avoid launching event more than once if (launchedEvent) { return; } //avoid launching event more than once
launchedEvent = true; launchedEvent = true;
ThreadUtil.invokeInGameThread(new Runnable() {
@Override
public void run() {
FModel.getConquest().launchEvent(ConquestEventScreen.this, FModel.getConquest().getModel().getSelectedCommander(), event);
}
});
}
@Override LoadingOverlay.show("Starting battle...", new Runnable() {
public void startGame(final GameRunner gameRunner) {
LoadingOverlay.show("Loading new game...", new Runnable() {
@Override @Override
public void run() { public void run() {
gameRunner.finishStartingGame(); FModel.getConquest().launchEvent(FModel.getConquest().getModel().getSelectedCommander(), event);
} }
}); });
} }

View File

@@ -53,6 +53,7 @@ public class ConquestPrefsScreen extends FScreen {
scroller.add(new PrefsOption("Base Card Value", CQPref.AETHER_BASE_VALUE, PrefsGroup.AETHER)); scroller.add(new PrefsOption("Base Card Value", CQPref.AETHER_BASE_VALUE, PrefsGroup.AETHER));
scroller.add(new PrefsOption("Markup Percentage", CQPref.AETHER_MARKUP, PrefsGroup.AETHER)); scroller.add(new PrefsOption("Markup Percentage", CQPref.AETHER_MARKUP, PrefsGroup.AETHER));
scroller.add(new PrefsOption("Starting Shards", CQPref.AETHER_START_SHARDS, PrefsGroup.AETHER)); scroller.add(new PrefsOption("Starting Shards", CQPref.AETHER_START_SHARDS, PrefsGroup.AETHER));
scroller.add(new PrefsOption("Chaos Wheel Shard Value", CQPref.AETHER_WHEEL_SHARDS, PrefsGroup.AETHER));
scroller.add(new PrefsHeader("Booster Packs", FSkinImage.PACK, PrefsGroup.BOOSTER)); scroller.add(new PrefsHeader("Booster Packs", FSkinImage.PACK, PrefsGroup.BOOSTER));
scroller.add(new PrefsOption("Commons", CQPref.BOOSTER_COMMONS, PrefsGroup.BOOSTER)); scroller.add(new PrefsOption("Commons", CQPref.BOOSTER_COMMONS, PrefsGroup.BOOSTER));

View File

@@ -39,7 +39,6 @@ import forge.interfaces.IWinLoseView;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.match.HostedMatch; import forge.match.HostedMatch;
import forge.model.FModel; import forge.model.FModel;
import forge.planarconquest.ConquestEvent.IConquestEventLauncher;
import forge.planarconquest.ConquestPlane.AwardPool; import forge.planarconquest.ConquestPlane.AwardPool;
import forge.planarconquest.ConquestPreferences.CQPref; import forge.planarconquest.ConquestPreferences.CQPref;
import forge.player.GamePlayerUtil; import forge.player.GamePlayerUtil;
@@ -56,7 +55,7 @@ import forge.util.storage.StorageImmediatelySerialized;
public class ConquestController { public class ConquestController {
private ConquestData model; private ConquestData model;
private IStorage<Deck> decks; private IStorage<Deck> decks;
private GameRunner gameRunner; private ConquestEvent activeEvent;
private LobbyPlayerHuman humanPlayer; private LobbyPlayerHuman humanPlayer;
public ConquestController() { public ConquestController() {
@@ -82,171 +81,116 @@ public class ConquestController {
return decks; return decks;
} }
public void launchEvent(final IConquestEventLauncher launcher0, final ConquestCommander commander0, final ConquestEvent event0) { public void launchEvent(ConquestCommander commander, ConquestEvent event) {
if (gameRunner != null) { return; } //prevent running multiple games at once if (activeEvent != null) { return; }
gameRunner = new GameRunner(launcher0, commander0, event0); //determine game variants
gameRunner.invokeAndWait(); Set<GameType> variants = new HashSet<GameType>();
gameRunner = null; event.addVariants(variants);
final RegisteredPlayer humanStart = new RegisteredPlayer(commander.getDeck());
final RegisteredPlayer aiStart = new RegisteredPlayer(event.getOpponentDeck());
if (variants.contains(GameType.Commander)) { //add 10 starting life for both players if playing a Commander game
humanStart.setStartingLife(humanStart.getStartingLife() + 10);
aiStart.setStartingLife(aiStart.getStartingLife() + 10);
humanStart.assignCommander();
aiStart.assignCommander();
}
if (variants.contains(GameType.Planechase)) { //generate planar decks if planechase variant being applied
humanStart.setPlanes(generatePlanarPool());
aiStart.setPlanes(generatePlanarPool());
}
String humanPlayerName = commander.getPlayerName();
String aiPlayerName = event.getOpponentName();
if (humanPlayerName.equals(aiPlayerName)) {
aiPlayerName += " (AI)"; //ensure player names are distinct
}
final List<RegisteredPlayer> starter = new ArrayList<RegisteredPlayer>();
humanPlayer = new LobbyPlayerHuman(humanPlayerName);
humanPlayer.setAvatarCardImageKey(commander.getCard().getImageKey(false));
starter.add(humanStart.setPlayer(humanPlayer));
final LobbyPlayer aiPlayer = GamePlayerUtil.createAiPlayer(aiPlayerName, -1);
aiPlayer.setAvatarCardImageKey(event.getAvatarImageKey());
starter.add(aiStart.setPlayer(aiPlayer));
final boolean useRandomFoil = FModel.getPreferences().getPrefBoolean(FPref.UI_RANDOM_FOIL);
for (final RegisteredPlayer rp : starter) {
rp.setRandomFoil(useRandomFoil);
}
final GameRules rules = new GameRules(GameType.PlanarConquest);
rules.setGamesPerMatch(1); //only play one game at a time
rules.setManaBurn(FModel.getPreferences().getPrefBoolean(FPref.UI_MANABURN));
rules.setCanCloneUseTargetsImage(FModel.getPreferences().getPrefBoolean(FPref.UI_CLONE_MODE_SOURCE));
final HostedMatch hostedMatch = GuiBase.getInterface().hostMatch();
FThreads.invokeInEdtNowOrLater(new Runnable(){
@Override
public void run() {
hostedMatch.startMatch(rules, null, starter, humanStart, GuiBase.getInterface().getNewGuiGame());
}
});
activeEvent = event;
} }
public class GameRunner { private List<PaperCard> generatePlanarPool() {
private class Lock { String planeName = model.getCurrentPlane().getName();
} List<PaperCard> pool = new ArrayList<PaperCard>();
private final Lock lock = new Lock(); List<PaperCard> otherPlanes = new ArrayList<PaperCard>();
List<PaperCard> phenomenons = new ArrayList<PaperCard>();
private final IConquestEventLauncher launcher; for (PaperCard c : FModel.getMagicDb().getVariantCards().getAllCards()) {
private final ConquestCommander commander; CardType type = c.getRules().getType();
private final ConquestEvent event; if (type.isPlane()) {
if (type.hasSubtype(planeName)) {
private GameRunner(final IConquestEventLauncher launcher0, final ConquestCommander commander0, final ConquestEvent event0) { pool.add(c); //always include card in pool if it matches the current plane
launcher = launcher0;
commander = commander0;
event = event0;
}
public final void invokeAndWait() {
FThreads.assertExecutedByEdt(false); //not supported if on UI thread
FThreads.invokeInEdtLater(new Runnable() {
@Override
public void run() {
launcher.startGame(GameRunner.this);
} }
}); else {
try { otherPlanes.add(c);
synchronized(lock) {
lock.wait();
} }
} }
catch (InterruptedException e) { else if (type.isPhenomenon()) {
e.printStackTrace(); phenomenons.add(c);
} }
} }
public void finishStartingGame() { //add between 0 and 2 phenomenons (where 2 is the most supported)
//determine game variants int numPhenomenons = Aggregates.randomInt(0, 2);
Set<GameType> variants = new HashSet<GameType>(); for (int i = 0; i < numPhenomenons; i++) {
event.addVariants(variants); pool.add(Aggregates.removeRandom(phenomenons));
final RegisteredPlayer humanStart = new RegisteredPlayer(commander.getDeck());
final RegisteredPlayer aiStart = new RegisteredPlayer(event.getOpponentDeck());
if (variants.contains(GameType.Commander)) { //add 10 starting life for both players if playing a Commander game
humanStart.setStartingLife(humanStart.getStartingLife() + 10);
aiStart.setStartingLife(aiStart.getStartingLife() + 10);
humanStart.assignCommander();
aiStart.assignCommander();
}
if (variants.contains(GameType.Planechase)) { //generate planar decks if planechase variant being applied
humanStart.setPlanes(generatePlanarPool());
aiStart.setPlanes(generatePlanarPool());
}
String humanPlayerName = commander.getPlayerName();
String aiPlayerName = event.getOpponentName();
if (humanPlayerName.equals(aiPlayerName)) {
aiPlayerName += " (AI)"; //ensure player names are distinct
}
final List<RegisteredPlayer> starter = new ArrayList<RegisteredPlayer>();
humanPlayer = new LobbyPlayerHuman(humanPlayerName);
humanPlayer.setAvatarCardImageKey(commander.getCard().getImageKey(false));
starter.add(humanStart.setPlayer(humanPlayer));
final LobbyPlayer aiPlayer = GamePlayerUtil.createAiPlayer(aiPlayerName, -1);
aiPlayer.setAvatarCardImageKey(event.getAvatarImageKey());
starter.add(aiStart.setPlayer(aiPlayer));
final boolean useRandomFoil = FModel.getPreferences().getPrefBoolean(FPref.UI_RANDOM_FOIL);
for (final RegisteredPlayer rp : starter) {
rp.setRandomFoil(useRandomFoil);
}
final GameRules rules = new GameRules(GameType.PlanarConquest);
rules.setGamesPerMatch(1); //only play one game at a time
rules.setManaBurn(FModel.getPreferences().getPrefBoolean(FPref.UI_MANABURN));
rules.setCanCloneUseTargetsImage(FModel.getPreferences().getPrefBoolean(FPref.UI_CLONE_MODE_SOURCE));
final HostedMatch hostedMatch = GuiBase.getInterface().hostMatch();
FThreads.invokeInEdtNowOrLater(new Runnable(){
@Override
public void run() {
hostedMatch.startMatch(rules, null, starter, humanStart, GuiBase.getInterface().getNewGuiGame());
}
});
} }
private void finish() { //add enough additional plane cards to reach a minimum 10 card deck
synchronized(lock) { //release game lock once game finished while (pool.size() < 10) {
lock.notify(); pool.add(Aggregates.removeRandom(otherPlanes));
}
}
private List<PaperCard> generatePlanarPool() {
String planeName = model.getCurrentPlane().getName();
List<PaperCard> pool = new ArrayList<PaperCard>();
List<PaperCard> otherPlanes = new ArrayList<PaperCard>();
List<PaperCard> phenomenons = new ArrayList<PaperCard>();
for (PaperCard c : FModel.getMagicDb().getVariantCards().getAllCards()) {
CardType type = c.getRules().getType();
if (type.isPlane()) {
if (type.hasSubtype(planeName)) {
pool.add(c); //always include card in pool if it matches the current plane
}
else {
otherPlanes.add(c);
}
}
else if (type.isPhenomenon()) {
phenomenons.add(c);
}
}
//add between 0 and 2 phenomenons (where 2 is the most supported)
int numPhenomenons = Aggregates.randomInt(0, 2);
for (int i = 0; i < numPhenomenons; i++) {
pool.add(Aggregates.removeRandom(phenomenons));
}
//add enough additional plane cards to reach a minimum 10 card deck
while (pool.size() < 10) {
pool.add(Aggregates.removeRandom(otherPlanes));
}
return pool;
} }
return pool;
} }
public void showGameRewards(final GameView game, final IWinLoseView<? extends IButton> view) { public void showGameOutcome(final GameView game, final IWinLoseView<? extends IButton> view) {
if (game.isMatchWonBy(humanPlayer)) { if (game.isMatchWonBy(humanPlayer)) {
view.getBtnRestart().setVisible(false);
view.getBtnQuit().setText("Great!"); view.getBtnQuit().setText("Great!");
model.addWin(activeEvent);
//give controller a chance to run remaining logic on a separate thread
view.showRewards(new Runnable() {
@Override
public void run() {
awardBooster(view);
}
});
} }
else { else {
view.getBtnQuit().setText("OK"); view.getBtnRestart().setVisible(true);
} view.getBtnRestart().setText("Retry");
} view.getBtnQuit().setText("Quit");
model.addLoss(activeEvent);
public void onGameFinished(final GameView game) {
if (game.isMatchWonBy(humanPlayer)) {
model.addWin(gameRunner.event);
}
else {
model.addLoss(gameRunner.event);
} }
model.saveData(); model.saveData();
FModel.getConquestPreferences().save(); FModel.getConquestPreferences().save();
gameRunner.finish();
} }
private void awardBooster(final IWinLoseView<? extends IButton> view) { public void finishEvent() {
activeEvent = null;
}
public List<ConquestReward> awardBooster() {
AwardPool pool = FModel.getConquest().getModel().getCurrentPlane().getAwardPool(); AwardPool pool = FModel.getConquest().getModel().getCurrentPlane().getAwardPool();
ConquestPreferences prefs = FModel.getConquestPreferences(); ConquestPreferences prefs = FModel.getConquestPreferences();
List<PaperCard> rewards = new ArrayList<PaperCard>(); List<PaperCard> rewards = new ArrayList<PaperCard>();
@@ -289,14 +233,9 @@ public class ConquestController {
allRewards.add(new ConquestReward(card, replacementShards)); allRewards.add(new ConquestReward(card, replacementShards));
} }
FThreads.invokeInEdtNowOrLater(new Runnable() {
@Override
public void run() {
view.showConquestRewards("Booster Awarded", allRewards);
}
});
model.unlockCards(rewards); model.unlockCards(rewards);
model.rewardAEtherShards(shards); model.rewardAEtherShards(shards);
return allRewards;
} }
public int calculateShardCost(ItemPool<PaperCard> filteredCards, int unfilteredCount) { public int calculateShardCost(ItemPool<PaperCard> filteredCards, int unfilteredCount) {

View File

@@ -4,7 +4,6 @@ import java.util.Set;
import forge.deck.Deck; import forge.deck.Deck;
import forge.game.GameType; import forge.game.GameType;
import forge.planarconquest.ConquestController.GameRunner;
import forge.util.XmlReader; import forge.util.XmlReader;
import forge.util.XmlWriter; import forge.util.XmlWriter;
import forge.util.XmlWriter.IXmlWritable; import forge.util.XmlWriter.IXmlWritable;
@@ -40,10 +39,6 @@ public abstract class ConquestEvent {
public abstract String getOpponentName(); public abstract String getOpponentName();
public abstract String getAvatarImageKey(); public abstract String getAvatarImageKey();
public static interface IConquestEventLauncher {
void startGame(GameRunner gameRunner);
}
public static class ConquestEventRecord implements IXmlWritable { public static class ConquestEventRecord implements IXmlWritable {
private final ConquestRecord[] tiers = new ConquestRecord[4]; private final ConquestRecord[] tiers = new ConquestRecord[4];

View File

@@ -31,7 +31,8 @@ public class ConquestPreferences extends PreferencesStore<ConquestPreferences.CQ
AETHER_BASE_VALUE("100"), AETHER_BASE_VALUE("100"),
AETHER_MARKUP("50"), AETHER_MARKUP("50"),
AETHER_START_SHARDS("1000"), AETHER_START_SHARDS("3000"),
AETHER_WHEEL_SHARDS("1000"),
BOOSTER_COMMONS("11"), BOOSTER_COMMONS("11"),
BOOSTER_UNCOMMONS("3"), BOOSTER_UNCOMMONS("3"),