mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 04:08:01 +00:00
Support retrying if you lose a game in Planar Conquest
This commit is contained in:
@@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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];
|
||||||
|
|
||||||
|
|||||||
@@ -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"),
|
||||||
|
|||||||
Reference in New Issue
Block a user