package net.demilich.metastone.gui.gameconfig; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.scene.control.CheckBox; import javafx.scene.control.ComboBox; import javafx.scene.control.Label; import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.layout.VBox; import net.demilich.metastone.game.behaviour.GreedyOptimizeMove; import net.demilich.metastone.game.behaviour.IBehaviour; import net.demilich.metastone.game.behaviour.NoAggressionBehaviour; import net.demilich.metastone.game.behaviour.PlayRandomBehaviour; import net.demilich.metastone.game.behaviour.heuristic.WeightedHeuristic; import net.demilich.metastone.game.behaviour.human.HumanBehaviour; import net.demilich.metastone.game.behaviour.threat.GameStateValueBehaviour; import net.demilich.metastone.game.behaviour.FlatMonteCarlo; import net.demilich.metastone.game.cards.Card; import net.demilich.metastone.game.cards.CardCatalogue; import net.demilich.metastone.game.cards.HeroCard; import net.demilich.metastone.game.decks.Deck; import net.demilich.metastone.game.decks.DeckFactory; import net.demilich.metastone.game.decks.DeckFormat; import net.demilich.metastone.game.entities.heroes.HeroClass; import net.demilich.metastone.game.entities.heroes.MetaHero; import net.demilich.metastone.game.gameconfig.PlayerConfig; import net.demilich.metastone.gui.IconFactory; import net.demilich.metastone.gui.common.BehaviourStringConverter; import net.demilich.metastone.gui.common.DeckStringConverter; import net.demilich.metastone.gui.common.HeroStringConverter; import net.demilich.metastone.gui.playmode.config.PlayerConfigType; public class PlayerConfigView extends VBox { @FXML protected Label heroNameLabel; @FXML protected ImageView heroIcon; @FXML protected ComboBox<IBehaviour> behaviourBox; @FXML protected ComboBox<HeroCard> heroBox; @FXML protected ComboBox<Deck> deckBox; @FXML protected CheckBox hideCardsCheckBox; private final PlayerConfig playerConfig = new PlayerConfig(); private List<Deck> decks = new ArrayList<Deck>(); private PlayerConfigType selectionHint; private DeckFormat deckFormat; public PlayerConfigView(PlayerConfigType selectionHint) { this.selectionHint = selectionHint; FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/PlayerConfigView.fxml")); fxmlLoader.setRoot(this); fxmlLoader.setController(this); try { fxmlLoader.load(); } catch (IOException exception) { throw new RuntimeException(exception); } heroBox.setConverter(new HeroStringConverter()); deckBox.setConverter(new DeckStringConverter()); behaviourBox.setConverter(new BehaviourStringConverter()); setupHideCardsBox(selectionHint); setupHeroes(); setupBehaviours(); deckBox.valueProperty().addListener((ChangeListener<Deck>) (observableProperty, oldDeck, newDeck) -> { getPlayerConfig().setDeck(newDeck); }); } private void filterDecks() { HeroClass heroClass = getPlayerConfig().getHeroCard().getHeroClass(); ObservableList<Deck> deckList = FXCollections.observableArrayList(); if (heroClass == HeroClass.DECK_COLLECTION) { for (Deck deck : decks) { if (deck.getHeroClass() != HeroClass.DECK_COLLECTION) { continue; } if (deckFormat != null && deckFormat.isInFormat(deck)) { deckList.add(deck); } } } else { Deck randomDeck = DeckFactory.getRandomDeck(heroClass, deckFormat); deckList.add(randomDeck); for (Deck deck : decks) { if (deck.getHeroClass() == HeroClass.DECK_COLLECTION) { continue; } if (deck.getHeroClass() == heroClass || deck.getHeroClass() == HeroClass.ANY) { if (deckFormat != null && deckFormat.isInFormat(deck)) { deckList.add(deck); } } } } deckBox.setItems(deckList); deckBox.getSelectionModel().selectFirst(); } public PlayerConfig getPlayerConfig() { return playerConfig; } public void injectDecks(List<Deck> decks) { this.decks = decks; heroBox.getSelectionModel().selectFirst(); behaviourBox.getSelectionModel().selectFirst(); } private void onBehaviourChanged(ObservableValue<? extends IBehaviour> ov, IBehaviour oldBehaviour, IBehaviour newBehaviour) { getPlayerConfig().setBehaviour(newBehaviour); boolean humanBehaviourSelected = newBehaviour instanceof HumanBehaviour; hideCardsCheckBox.setDisable(humanBehaviourSelected); if (humanBehaviourSelected) { hideCardsCheckBox.setSelected(false); } } private void onHideCardBoxChanged(ObservableValue<? extends Boolean> ov, Boolean oldValue, Boolean newValue) { playerConfig.setHideCards(newValue); } private void selectHero(HeroCard heroCard) { Image heroPortrait = new Image(IconFactory.getHeroIconUrl(heroCard.getHeroClass())); heroIcon.setImage(heroPortrait); heroNameLabel.setText(heroCard.getName()); getPlayerConfig().setHeroCard(heroCard); filterDecks(); } public void setupBehaviours() { ObservableList<IBehaviour> behaviourList = FXCollections.observableArrayList(); if (selectionHint == PlayerConfigType.HUMAN || selectionHint == PlayerConfigType.SANDBOX) { behaviourList.add(new HumanBehaviour()); } behaviourList.add(new GameStateValueBehaviour()); if (selectionHint == PlayerConfigType.OPPONENT) { behaviourList.add(new HumanBehaviour()); } behaviourList.add(new PlayRandomBehaviour()); behaviourList.add(new GreedyOptimizeMove(new WeightedHeuristic())); behaviourList.add(new NoAggressionBehaviour()); behaviourList.add(new FlatMonteCarlo(100)); behaviourBox.setItems(behaviourList); behaviourBox.valueProperty().addListener(this::onBehaviourChanged); } public void setupHeroes() { ObservableList<HeroCard> heroList = FXCollections.observableArrayList(); for (Card card : CardCatalogue.getHeroes()) { heroList.add((HeroCard) card); } heroList.add(new MetaHero()); heroBox.setItems(heroList); heroBox.valueProperty().addListener((ChangeListener<HeroCard>) (observableValue, oldHero, newHero) -> { selectHero(newHero); }); } private void setupHideCardsBox(PlayerConfigType configType) { hideCardsCheckBox.selectedProperty().addListener(this::onHideCardBoxChanged); hideCardsCheckBox.setSelected(selectionHint == PlayerConfigType.OPPONENT); if (configType == PlayerConfigType.SIMULATION || configType == PlayerConfigType.SANDBOX) { hideCardsCheckBox.setVisible(false); } } public void setDeckFormat(DeckFormat newDeckFormat) { deckFormat = newDeckFormat; filterDecks(); } }