package com.galvarez.ttw.screens.overworld; import static com.galvarez.ttw.utils.Colors.markup; import static java.lang.Math.min; import static java.lang.String.format; import java.util.List; import com.artemis.Entity; import com.artemis.World; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input.Buttons; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.scenes.scene2d.InputEvent; import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.ui.Button; import com.badlogic.gdx.scenes.scene2d.ui.Label.LabelStyle; import com.badlogic.gdx.scenes.scene2d.ui.Skin; import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; import com.badlogic.gdx.utils.Align; import com.badlogic.gdx.utils.IntIntMap; import com.badlogic.gdx.utils.ObjectIntMap.Entry; import com.galvarez.ttw.model.DiplomaticSystem; import com.galvarez.ttw.model.DiplomaticSystem.Action; import com.galvarez.ttw.model.EventsSystem.EventHandler; import com.galvarez.ttw.model.InfluenceSystem; import com.galvarez.ttw.model.components.ArmyCommand; import com.galvarez.ttw.model.components.Diplomacy; import com.galvarez.ttw.model.components.EventsCount; import com.galvarez.ttw.model.components.InfluenceSource; import com.galvarez.ttw.model.components.Score; import com.galvarez.ttw.model.data.Empire; import com.galvarez.ttw.model.map.GameMap; import com.galvarez.ttw.model.map.Influence; import com.galvarez.ttw.model.map.MapPosition; import com.galvarez.ttw.model.map.Terrain; import com.galvarez.ttw.rendering.NotificationsSystem; import com.galvarez.ttw.rendering.NotificationsSystem.Notification; import com.galvarez.ttw.rendering.components.Description; import com.galvarez.ttw.rendering.components.Name; import com.galvarez.ttw.rendering.components.Sprite; import com.galvarez.ttw.rendering.ui.FramedDialog; import com.galvarez.ttw.rendering.ui.FramedMenu; import com.galvarez.ttw.screens.overworld.controls.InputManager; public class MenuBuilder { private static final int MENU_PADDING = 15; private final Stage stage; private final Skin skin; private final FramedMenu turnMenu, indicationMenu, empireMenu, notifMenu; private final FramedMenu selectionMenu; private final FramedMenu eventsMenu; private FramedMenu actionMenu, mapMenu; private final World world; private final GameMap map; private final OverworldScreen screen; private final InputManager inputManager; private final NotificationsSystem notifications; public MenuBuilder(Stage stage, World world, GameMap map, OverworldScreen screen, InputManager inputManager) { this.stage = stage; this.world = world; this.map = map; this.screen = screen; this.inputManager = inputManager; this.notifications = world.getSystem(NotificationsSystem.class); skin = new Skin(Gdx.files.internal("uiskin/uiskin.json")); turnMenu = new FramedMenu(skin, 256, 256); indicationMenu = new FramedMenu(skin, 512, 512); empireMenu = new FramedMenu(skin, 256, 256).nbColumns(1); selectionMenu = new FramedMenu(skin, 256, 512); eventsMenu = new FramedMenu(skin, 256, 1024); notifMenu = new FramedMenu(skin, 400, 512); } public void clearSubMenus() { if (mapMenu != null) { mapMenu.clear(); mapMenu = null; } if (actionMenu != null) { actionMenu.clear(); actionMenu = null; } } public void buildTurnMenu() { turnMenu.clear(); // EndTurn button turnMenu.addButton("End turn (year " + screen.getCurrentYear() + ")",// null, screen::endTurn, screen.canFinishTurn()); // Access to score ladder Score score = screen.player.getComponent(Score.class); turnMenu.addButton("#" + score.rank + " " + score.totalScore + " (+" + score.lastTurnPoints + ")", screen::scoresMenu); // access to map options turnMenu.addButton("Map options", () -> displayMapMenu(turnMenu)); turnMenu.addToStage(stage, MENU_PADDING, stage.getHeight() - MENU_PADDING, false); } private void displayMapMenu(FramedMenu parent) { if (mapMenu == null) { mapMenu = new FramedMenu(skin, 256, 128, turnMenu); mapMenu.clear(); mapMenu.addCheckBox("Display colored influence?", screen.displayColoredInfluence(), screen::displayColoredInfluence); mapMenu.addToStage(stage, parent.getX() + parent.getWidth(), parent.getY() + 10, true); } else { mapMenu.clear(); mapMenu = null; } } public void buildIndicationMenu() { indicationMenu.clear(); List<String> indications = screen.getIndications(); if (indications != null && !indications.isEmpty()) { // set width before for better layout indicationMenu.setWidth(stage.getWidth() - (turnMenu.getWidth() + eventsMenu.getWidth() + MENU_PADDING * 3)); for (String i : indications) indicationMenu.addLabel(i); indicationMenu.addToStage(stage, MENU_PADDING + turnMenu.getX() + turnMenu.getWidth(), stage.getHeight() - MENU_PADDING, false); } } public void buildEmpireMenu() { empireMenu.clear(); empireMenu.addLabel("- " + screen.player.getComponent(Name.class).name + " -"); // here present a new screen with diplomatic relations empireMenu.addButton("Diplomacy", screen::diplomacyMenu); // here present a new screen with army preferences ArmyCommand command = screen.player.getComponent(ArmyCommand.class); empireMenu.addButton("Army (power=" + (command.militaryPower - command.usedPower) + "/" + command.militaryPower + ")", screen::armiesMenu); // here present a sub-menu to see current discovery and be able to change it empireMenu.addButton("Discoveries", screen::discoveryMenu); // here present a new screen to choose policies int instability = screen.revoltSystem.getInstability(screen.player); if (instability <= 0) empireMenu.addButton("Policies (instability " + instability + ")", screen::policiesMenu); else { empireMenu.addButton(empireMenu.getSkin().get("colored", LabelStyle.class), // "[BLACK]Policies (instability [RED]" + instability + "[])", // null, screen::policiesMenu, true); } empireMenu.addToStage(stage, MENU_PADDING, turnMenu.getY() - MENU_PADDING, false); } public void buildSelectionMenu(final MapPosition tile, Entity e) { selectionMenu.clear(); addTileDescription(tile); Influence influence = addInfluences(tile); if (e != null) { addDescription(e); InfluenceSource source = e.getComponent(InfluenceSource.class); if (source != null) selectionMenu.addLabel("Power: " + source.power() + " (" + number(source.growth / 10f) + "%/turn, health=" + source.health + ")"); } Entity source = influence.getMainInfluenceSource(world); if (source != null) { if (source != screen.player && screen.player != null) addEmpire(screen.player, source); } selectionMenu.addToStage(stage, MENU_PADDING, empireMenu.getY() - MENU_PADDING, true); } private static String number(int i) { return i >= 0 ? "+" + Integer.toString(i) : Integer.toString(i); } private static String number(float f) { return f >= 0 ? "+" + Float.toString(f) : Float.toString(f); } private Influence addInfluences(MapPosition tile) { Influence influence = map.getInfluenceAt(tile); int mainSource = influence.getMainInfluenceSource(); StringBuilder sb = new StringBuilder("[BLACK]Influence: "); for (IntIntMap.Entry e : influence) { Entity source = world.getEntity(e.key); Empire empire = source.getComponent(Empire.class); sb.append("\n ").append(markup(empire.color)).append(source.getComponent(Name.class).name).append("[]: ") .append(100 * e.value / InfluenceSystem.INITIAL_POWER).append('%').append(' ') .append(number(100 * influence.getDelta(source) / InfluenceSystem.INITIAL_POWER)).append('%'); // ignore == 0 if (e.key == mainSource) sb.append(" (main)"); } selectionMenu.addColoredLabel(sb.toString()); return influence; } private void addTileDescription(MapPosition tile) { Terrain terrain = map.getTerrainAt(tile); selectionMenu.addLabelSprite(terrain.getDesc() + " (" + tile.x + ", " + tile.y + ")", screen.mapRenderer.getTexture(terrain), Color.WHITE); } private void addDescription(Entity e) { Description desc = e.getComponent(Description.class); if (desc != null) { if (desc.texture != null) { selectionMenu.addLabelSprite(desc.desc, desc.texture, Color.WHITE); } else { Sprite sprite = e.getComponent(Sprite.class); if (sprite != null) selectionMenu.addLabelSprite(desc.desc, sprite.region, sprite.color); else selectionMenu.addLabel(desc.desc); } } } private void addEmpire(Entity player, Entity selected) { selectionMenu.addLabel("Empire: " + selected.getComponent(Name.class).name); Diplomacy playerDiplo = player.getComponent(Diplomacy.class); Diplomacy selectedDiplo = selected.getComponent(Diplomacy.class); selectionMenu.addLabel(" relations are " + playerDiplo.getRelationWith(selected)); selectionMenu.addButton(" we want ", playerDiplo.getProposalTo(selected).str, () -> displayDiplomaticActionMenu(selectionMenu, playerDiplo, selected), true); selectionMenu.addLabel(" they want " + selectedDiplo.getProposalTo(player).str); } private void displayDiplomaticActionMenu(FramedMenu parent, Diplomacy diplo, Entity target) { if (actionMenu == null) { actionMenu = new FramedMenu(skin, 256, 128, parent); boolean hasActions = false; for (Action action : world.getSystem(DiplomaticSystem.class).getPossibleActions(diplo, target)) { hasActions = true; actionMenu.addButton(action.str, () -> { if (action != Action.NO_CHANGE) diplo.proposals.put(target, action); actionMenu.clear(); inputManager.reloadMenus(); }); } if (!hasActions) actionMenu.addLabel("No possible actions!"); actionMenu.addToStage(stage, parent.getX() + parent.getWidth(), parent.getY() + 10, true); } else { actionMenu.clear(); actionMenu = null; } } public void buildEventsMenu(Entity e) { eventsMenu.clear(); if (e == null || e.getComponent(EventsCount.class) == null) e = screen.player; EventsCount events = e.getComponent(EventsCount.class); if (events != null) { eventsMenu.addLabel("Possible events in " + e.getComponent(Name.class)); for (Entry<EventHandler> evt : events.display) eventsMenu.addLabel(format(" %s: %d (+%d)", evt.key.getType(), evt.value, events.increment.get(evt.key, 0))); eventsMenu.addToStage(stage, stage.getWidth() - 256, stage.getHeight() - MENU_PADDING, false); } } public void buildNotificationMenu() { List<Notification> notifs = notifications.getNotifications(); notifMenu.clear(); if (notifs.isEmpty()) notifMenu.addLabel("No notifications"); else for (Notification n : notifs) { Button b = notifMenu.addButtonSprite(n.type, n.msg, () -> { inputManager.reloadMenus(); if (n.action != null) n.action.run(); }, true); b.addListener(new ClickListener(Buttons.RIGHT) { @Override public void clicked(InputEvent event, float x, float y) { notifications.discard(n); inputManager.reloadMenus(); } }); } notifMenu.addToStage(stage, Gdx.graphics.getWidth() - 400, min(512, notifMenu.getTable().getPrefHeight()), false); } public void buildDialog(String title, int minWidth, int minHeight, String message, Button ... buttons) { FramedDialog fd = new FramedDialog(skin, title, message); for (Button b : buttons) { b.align(Align.center); fd.addButton(b); } fd.addToStage(stage, minWidth, minHeight); } public TextButton getTextButton(String text, ChangeListener listener) { TextButton button = new TextButton(text, skin); if (listener != null) button.addListener(listener); return button; } }