Package com.drakulo.games.ais.ui.state

Source Code of com.drakulo.games.ais.ui.state.SectorState

package com.drakulo.games.ais.ui.state;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.newdawn.slick.Color;
import org.newdawn.slick.Font;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.geom.Rectangle;
import org.newdawn.slick.tiled.TiledMap;

import com.drakulo.games.ais.AloneInSpace;
import com.drakulo.games.ais.core.Colony;
import com.drakulo.games.ais.core.GameData;
import com.drakulo.games.ais.core.GameEngine;
import com.drakulo.games.ais.core.NumberHelper;
import com.drakulo.games.ais.core.Resource;
import com.drakulo.games.ais.core.ResourceHelper;
import com.drakulo.games.ais.core.Settings;
import com.drakulo.games.ais.core.building.Building;
import com.drakulo.games.ais.core.building.BuildingData;
import com.drakulo.games.ais.core.building.BuildingHelper;
import com.drakulo.games.ais.core.building.BuildingLevelData;
import com.drakulo.games.ais.core.building.BuildingType;
import com.drakulo.games.ais.core.delayed.BuildingAction;
import com.drakulo.games.ais.core.delayed.DelayedAction;
import com.drakulo.games.ais.core.delayed.MapAction;
import com.drakulo.games.ais.core.delayed.PreparationAction;
import com.drakulo.games.ais.core.delayed.ColonyAction;
import com.drakulo.games.ais.core.delayed.SpecialActionManager;
import com.drakulo.games.ais.core.io.BuildingIO;
import com.drakulo.games.ais.core.tech.TechnologyHelper;
import com.drakulo.games.ais.ui.FontHelper;
import com.drakulo.games.ais.ui.I18n;
import com.drakulo.games.ais.ui.ImageManager;
import com.drakulo.games.ais.ui.Style;
import com.drakulo.games.ais.ui.TileHelper;
import com.drakulo.games.ais.ui.UIHelper;
import com.drakulo.games.ais.ui.component.ActionHandler;
import com.drakulo.games.ais.ui.component.Minimap;
import com.drakulo.games.ais.ui.component.ProgressBar;
import com.drakulo.games.ais.ui.component.UIComponent;
import com.drakulo.games.ais.ui.component.button.Button;
import com.drakulo.games.ais.ui.component.button.ImageButton;
import com.drakulo.games.ais.ui.component.button.TextButton;
import com.drakulo.games.ais.ui.component.window.BuildWindow;
import com.drakulo.games.ais.ui.twlbridge.RootPane;

import de.matthiasmann.twl.Label;

public class SectorState extends GameState {

  /** -------------------------------------------- */
  /** TWL Widgets -------------------------------- */
  /** -------------------------------------------- */
  /**
   * Map of labels showing resource amounts, max space, space available and
   * modifiers
   */
  private Map<Resource, Label> inStoreLabels;
  private Map<Resource, Label> maxStoreLabels;
  private Map<Resource, Label> availableSpaceLabels;
  private Map<Resource, Label> modifiersLabels;
  /** Rows labels of resource extended mode */
  private Label storeTitle;
  private Label maxStoreTitle;
  private Label availableSpaceTitle;
  private Label modifierTitle;
  /** Game menu buttons */
  private List<Button> gameMenuButtons;
  /** Selected building labels displaying it's attributes */
  private Map<Resource, Label> buildingProdLabels;
  private Map<Resource, Label> buildingConsLabels;
  private Map<Resource, Label> buildingStoreLabels;
  private Label[] buildingColLabels;
  private Map<Resource, Label> buildingRowLabels;
  /** Upgrade overview labels */
  private Map<Resource, Label> upgradeLabels;

  /** -------------------------------------------- */
  /** Other properties --------------------------- */
  /** -------------------------------------------- */
  /** Height of the bottom bar */
  private static final int BOTTOM_BAR_HEIGHT = Minimap.HEIGHT.intValue() + 20;
  /** Padding */
  private static final int PADDING = 10;
  /** The top resource zone width */
  private static final int TOP_BAR_WIDTH = 653;
  /** The toggle button zone */
  private static final int TOGGLE_BUTTON_ZONE_WIDTH = 24;
  /** The map viewport width */
  public static final int VIEWPORT_WIDTH = Settings.WIDTH;
  /** The map viewport height */
  public static final int VIEWPORT_HEIGHT = Settings.HEIGHT
      - BOTTOM_BAR_HEIGHT - TOP_BAR_HEIGHT;

  /** The minimap */
  private Minimap minimap;
  /** Top scroll zone */
  private Rectangle topScrollZone;
  /** Bottom scroll zone */
  private Rectangle bottomScrollZone;
  /** Left scroll zone */
  private Rectangle leftScrollZone;
  /** Right scroll zone */
  private Rectangle rightScrollZone;
  /** The building selected by the player */
  private Building selectedBuilding;
  /** A map of Progress bar, one for each resource */
  private Map<Resource, ProgressBar> resourceBars;
  /** Progress bar for robots use */
  private ProgressBar robotBar;
  /** Current research progress bar */
  private ProgressBar researchBar;
  /** Resource zone extended display */
  private boolean extendedResourceDisplay;
  /** The game menu display flag */
  private boolean showGameMenu;
  /** The building action Window */
  private BuildWindow buildWindow;
  /** The building action window display flag */
  private boolean showActionWindow;
  /** The selected map action */
  private MapAction selectedAction;
  /** Current X coordinate of the mouse on the screen */
  private int mouseX;
  /** Current Y coordinate of the mouse on the screen */
  private int mouseY;
  /** Current X coordinate of the square hovered on screen */
  private int squareXOnScreen;
  /** Current Y coordinate of the square hovered on screen */
  private int squareYOnScreen;
  /** Current X coordinate of the square hovered on map */
  private int squareXOnMap;
  /** Current Y coordinate of the square hovered on map */
  private int squareYOnMap;
  /** The selected building current action progress bar */
  private ProgressBar selectedBuildingPB;
  /** The Develop button */
  private ImageButton developButton;
  /** The research button */
  private ImageButton researchVisionButton;
  /** The planet button */
  private ImageButton planetVisionButton;
  /** This button cancels the selected building current action */
  private ImageButton cancelButton;
  /** Building buttons array */
  private ImageButton[][] buildingButtons;
  /** The list of UIComponents to render and update */
  private List<UIComponent> components;

  public SectorState(int id) {
    super(id);
    this.extendedResourceDisplay = false;
    this.showGameMenu = false;
    this.components = new ArrayList<UIComponent>();
  }

  @Override
  protected RootPane createRootPane() {
    this.rootPane = super.createRootPane();

    // final int startX = Settings.WIDTH - Minimap.WIDTH.intValue() -
    // PADDING
    // + 5;
    // final int startY = Settings.HEIGHT - Minimap.HEIGHT.intValue()
    // - PADDING + 5;

    int width = TOP_BAR_WIDTH + TOGGLE_BUTTON_ZONE_WIDTH;
    int x = Settings.WIDTH / 2 - width / 2 + 3;
    int y = PADDING + 3;

    this.inStoreLabels = new HashMap<Resource, Label>();
    this.maxStoreLabels = new HashMap<Resource, Label>();
    this.availableSpaceLabels = new HashMap<Resource, Label>();
    this.modifiersLabels = new HashMap<Resource, Label>();
    Resource[] resources = Resource.values();
    for (Resource r : resources) {
      this.inStoreLabels.put(r, createAndAddResourceLabel(null));
      this.maxStoreLabels.put(r, createAndAddResourceLabel(null));
      this.availableSpaceLabels.put(r, createAndAddResourceLabel(null));
      this.modifiersLabels.put(r, createAndAddResourceLabel(null));
    }
    this.storeTitle = createAndAddResourceLabel(I18n
        .get("resource.stored_quantity"));
    this.maxStoreTitle = createAndAddResourceLabel(I18n
        .get("resource.max_space"));
    this.availableSpaceTitle = createAndAddResourceLabel(I18n
        .get("resource.available_space"));
    this.modifierTitle = createAndAddResourceLabel(I18n
        .get("resource.modifier"));

    // Selected building attributes labels
    this.buildingProdLabels = new HashMap<Resource, Label>();
    this.buildingConsLabels = new HashMap<Resource, Label>();
    this.buildingStoreLabels = new HashMap<Resource, Label>();
    this.buildingRowLabels = new HashMap<Resource, Label>();
    this.upgradeLabels = new HashMap<Resource, Label>();
    for (Resource r : resources) {
      this.buildingProdLabels.put(r,
          createAndAddResourceLabel(null, 80, "resourceLabel"));
      this.buildingConsLabels.put(r,
          createAndAddResourceLabel(null, 80, "resourceLabel"));
      this.buildingStoreLabels.put(r,
          createAndAddResourceLabel(null, 80, "resourceLabel"));
      this.buildingRowLabels.put(
          r,
          createAndAddResourceLabel(
              FontHelper.firstToUpper(r.getI18n()), 80,
              "resourceLabel"));
      this.upgradeLabels.put(r,
          createAndAddResourceLabel(null, 80, "resourceLabel"));
    }

    this.buildingColLabels = new Label[3];
    this.buildingColLabels[0] = createAndAddResourceLabel(
        I18n.get("resource.income.short"), 80, "titleResourceLabel");
    this.buildingColLabels[1] = createAndAddResourceLabel(
        I18n.get("resource.consumption.short"), 80,
        "titleResourceLabel");
    this.buildingColLabels[2] = createAndAddResourceLabel(
        I18n.get("resource.store"), 80, "titleResourceLabel");

    return this.rootPane;
  }

  private Label createAndAddResourceLabel(String title, int width,
      String theme) {
    Label l;
    if (title == null) {
      l = new Label();
    } else {
      l = new Label(title);
    }
    l.setVisible(false);
    l.setSize(width, 15);
    l.setTheme(theme);
    this.rootPane.add(l);
    return l;
  }

  /**
   * @return A themed label for extended resources display
   */
  private Label createAndAddResourceLabel(String title) {
    return this.createAndAddResourceLabel(title, 122, "resourceLabel");
  }

  @Override
  public void initState() throws SlickException {

    // TODO externalize this part
    // Load the tiledmap
    TiledMap tiledMap = new TiledMap("data/testmap.tmx");

    Colony c = new Colony();
    c.setAvailableRobots(3);
    c.setTotalRobots(3);
    c.setMap(tiledMap);
    c.setName("Anthem Base");

    Resource[] resources = Resource.values();
    for (Resource r : resources) {
      c.setResource(r, BigDecimal.valueOf(1000));
    }

    c.setResearchCenterBuilt(false);
    GameData.addColony(c);
    GameData.setSelectedColony(c);
    // /////////////////////////

    // End of to externalize zone

    final int pad = 10;
    final int minimapX = pad;
    final int minimapY = Settings.HEIGHT - pad - Minimap.HEIGHT.intValue();
    this.minimap = new Minimap(minimapX, minimapY);

    // Initialization of border scroll zones
    initializeScrollZones();

    // Progress bars
    this.resourceBars = new HashMap<Resource, ProgressBar>();
    for (Resource r : resources) {
      ProgressBar pb = UIHelper.createBar(r.getI18n(), r.getColor(),
          false);
      this.resourceBars.put(r, pb);
    }
    this.robotBar = UIHelper.createBar("Robots", Color.white, true);

    this.selectedBuildingPB = new ProgressBar();
    this.selectedBuildingPB.setHeight(10);
    this.selectedBuildingPB.setWidth(202);
    this.selectedBuildingPB.setEmptyColor(Color.darkGray);
    this.selectedBuildingPB.setFilledColor(Color.magenta);

    int x = Settings.WIDTH / 2 - ImageButton.IB_DEFAULT_SIZE / 2;
    int y = Settings.HEIGHT - 116 - PADDING - ImageButton.IB_DEFAULT_SIZE
        - PADDING;
    this.developButton = new ImageButton("cog", x, y);
    developButton.setTitle(I18n.get("ui.build_panel"));
    this.developButton.setActionHandler(new ActionHandler() {

      @Override
      public void run() {
        showBuildWindow(!SectorState.this.showActionWindow);
      }
    });
    add(developButton);

    x -= PADDING + ImageButton.IB_DEFAULT_SIZE;
    this.researchVisionButton = new ImageButton("lightbulb", x, y);
    researchVisionButton.setTitle(I18n.get("vision.research"));
    this.researchVisionButton.disable();
    this.researchVisionButton.setActionHandler(new ActionHandler() {

      @Override
      public void run() {
        GameData.getGame().enterState(AloneInSpace.RESEARCH_STATE);
      }
    });
    add(researchVisionButton);

    x -= PADDING + ImageButton.IB_DEFAULT_SIZE;
    this.planetVisionButton = new ImageButton("globe_3", x, y);
    planetVisionButton.setTitle(I18n.get("vision.planet"));
    this.planetVisionButton.disable();
    this.planetVisionButton.setActionHandler(new ActionHandler() {

      @Override
      public void run() {
        SectorState.this.selectedAction = null;
        SectorState.this.selectedBuilding = null;
        GameData.getGame().enterState(AloneInSpace.PLANET_STATE);
      }
    });
    add(planetVisionButton);

    // Cancel button

    final int startX = Settings.WIDTH - Minimap.WIDTH.intValue() - PADDING
        + 10;
    final int startY = Settings.HEIGHT - Minimap.HEIGHT.intValue()
        - PADDING + 9;
    this.buildingButtons = new ImageButton[3][3];
    for (int col = 0; col < 3; col++) {
      for (int row = 0; row < 3; row++) {
        this.buildingButtons[col][row] = new ImageButton(null, startX
            + col * 46, startY + row * 46);
        this.buildingButtons[col][row].disable();
        this.buildingButtons[col][row].hide();

      }
    }

    this.cancelButton = this.buildingButtons[2][2];
    this.cancelButton.setImageRef("cancel");
    this.cancelButton.setActionHandler(new ActionHandler() {

      @Override
      public void run() {
        stopSelectedBuildingAction();
      }
    });

    this.buildingButtons[0][2].setImageRef("upgrade");
    this.buildingButtons[0][2].setActionHandler(new ActionHandler() {

      @Override
      public void run() {
        hideUpgradeLabels();
        upgradeBuilding(SectorState.this.selectedBuilding);
      }
    });

    int width = TOP_BAR_WIDTH + TOGGLE_BUTTON_ZONE_WIDTH;
    x = Settings.WIDTH / 2 - width / 2 + 4;
    y = PADDING + 3;
    final TextButton resourceTogglerButton = new TextButton("+");
    resourceTogglerButton.setPosition(x, y);
    resourceTogglerButton.setSize(21, 21);
    resourceTogglerButton.setActionHandler(new ActionHandler() {

      @Override
      public void run() {
        SectorState.this.extendedResourceDisplay = !SectorState.this.extendedResourceDisplay;
        Resource[] resources = Resource.values();
        for (Resource r : resources) {
          boolean show = SectorState.this.extendedResourceDisplay;
          SectorState.this.inStoreLabels.get(r).setVisible(show);
          SectorState.this.maxStoreLabels.get(r).setVisible(show);
          SectorState.this.availableSpaceLabels.get(r).setVisible(
              show);
          SectorState.this.modifiersLabels.get(r).setVisible(show);
          SectorState.this.storeTitle.setVisible(show);
          SectorState.this.maxStoreTitle.setVisible(show);
          SectorState.this.availableSpaceTitle.setVisible(show);
          SectorState.this.modifierTitle.setVisible(show);

          if (show) {
            resourceTogglerButton.setText("-");
          } else {
            resourceTogglerButton.setText("+");
          }
        }
      }
    });
    add(resourceTogglerButton);

    width = 270;
    int height = 300;
    x = Settings.WIDTH / 2 - width / 2;
    y = Settings.HEIGHT - BOTTOM_BAR_HEIGHT - height;
    this.buildWindow = new BuildWindow(this, width, height, x, y);
  }

  @Override
  public void renderState(Graphics g) throws SlickException {
    // Render the tiled map view port
    Colony c = GameData.getSelectedColony();
    GameData.getCurrentMap().render(c.getViewportX(), c.getViewportY(),
        TileHelper.DECO_LAYER);

    // Render the buildings
    renderBuildings(g);

    // Render the robots
    renderRobots(g);

    // If an action is selected, a shadow rendering is done
    if (this.selectedAction != null) {
      Image gfx = ImageManager.getGfx(this.selectedAction.getGfxKey());

      final int tileX = this.squareXOnMap;
      final int tileY = this.squareYOnMap;
      if (this.selectedAction instanceof PreparationAction) {
        // Preparation action
        if (TileHelper.tileIsPreparable(tileX, tileY)) {
          gfx.draw(this.squareXOnScreen, this.squareYOnScreen);
        } else {
          gfx.draw(this.squareXOnScreen, this.squareYOnScreen,
              Color.red);
        }

      } else if (this.selectedAction instanceof BuildingAction) {
        // Building action
        BuildingAction ba = (BuildingAction) this.selectedAction;
        if (BuildingType.COMMAND_CENTER.equals(ba.getBuilding()
            .getType())) {
          // Render the effect zone around the command center
          if (TileHelper.isValidCommandCenterTile(tileX, tileY)) {
            g.setColor(Style.FILTER_GREEN);
          } else {
            // The zone is not correct for Command Center
            // construction.
            g.setColor(Style.FILTER_RED);
          }

          int x = getScreenX(tileX - 1);
          int y = getScreenY(tileY - 1);
          g.fillRect(x, y, Settings.TILE_SIZE * 3,
              Settings.TILE_SIZE * 3);
          gfx.draw(this.squareXOnScreen, this.squareYOnScreen);
          // The command center construction is an exception
        } else if (TileHelper.tileIsBuildable(tileX, tileY, ba
            .getBuilding().getType())) {
          // Can build here
          gfx.draw(this.squareXOnScreen, this.squareYOnScreen);
        } else {
          // Cannot build here
          gfx.draw(this.squareXOnScreen, this.squareYOnScreen,
              Color.red);
        }
      }
    }

    // The UI rendering is done in last order
    renderUI(g);

    // DEBUG Data
    // final int tileX = this.squareXOnMap;
    // final int tileY = this.squareYOnMap;
    // Font debugFont = FontHelper
    // .getFont(FontHelper.ANONYMOUS, Color.red, 20);
    // debugFont.drawString(0, 50, "[" + tileX + "," + tileY + "]");
  }

  /**
   * Renders the user interface
   *
   * @param g
   *            The graphics canvas
   * @throws SlickException
   */
  private void renderUI(Graphics g) throws SlickException {
    int x = 0;
    int y = Settings.HEIGHT - Minimap.HEIGHT.intValue() - PADDING * 2;
    UIHelper.drawBox(g, x, y, Settings.WIDTH, Settings.HEIGHT - y);

    // The minimap
    this.minimap.render(g);

    // The action zone
    y = Settings.HEIGHT - Minimap.HEIGHT.intValue() - PADDING;
    x = Settings.WIDTH - Minimap.WIDTH.intValue() - PADDING;
    g.setColor(Style.BORDER_COLOR);
    UIHelper.drawBox(g, x, y, 150, 150);

    final int startX = Settings.WIDTH - Minimap.WIDTH.intValue() - PADDING
        + 7;
    final int startY = Settings.HEIGHT - Minimap.HEIGHT.intValue()
        - PADDING + 7;
    for (int i = 0; i < 3; i++) {
      for (int j = 0; j < 3; j++) {
        UIHelper.drawDarkBox(g, startX + i * 46, startY + j * 46, 43,
            43);
      }
    }

    // The game menu
    if (this.showGameMenu) {
      int menuHeight = 35 + this.gameMenuButtons.size() * 25;
      UIHelper.drawDarkBox(g, PADDING / 2, PADDING / 2, 120, menuHeight);
    }

    // The action window
    this.buildWindow.render(g);

    // Attributes Background
    int ox = 150 + PADDING * 2;
    int oy = Settings.HEIGHT - 116 - PADDING;
    UIHelper.drawDarkBox(g, ox, oy, 368, 116);

    // Overview background
    ox = 150 + PADDING * 2 + 368 + PADDING;
    oy = Settings.HEIGHT - Minimap.HEIGHT.intValue() - PADDING;
    UIHelper.drawDarkBox(g, ox, oy, 306, 150);

    if (this.selectedBuilding != null) {
      renderBuildingAttributes(g);
      renderBuildingOverview(g);
    }

    // Rendering of building buttons
    for (int col = 0; col < 3; col++) {
      for (int row = 0; row < 3; row++) {
        this.buildingButtons[col][row].render(g);
      }
    }

    // Upgrade button
    if (this.selectedBuilding != null) {
      BuildingLevelData data = BuildingIO.getBuildingData(
          this.selectedBuilding.getType()).getLevelData(
          this.selectedBuilding.getLevel());
      if (this.buildingButtons[0][2].isHovered()) {
        // The upgrade button is hovered : show the resources needed
        showUpgradeCost(data.getUpgradeCost(), g,
            this.buildingButtons[0][2]);
      } else {
        hideUpgradeLabels();
      }

      // Rendering of special building actions
      if (data.getSpecialActions() != null) {
        // There id some special action to show
        int col = 0;
        int row = 0;
        for (String name : data.getSpecialActions()) {
          final ColonyAction sa = SpecialActionManager.get(
              GameData.getSelectedColony(), name);
          ImageButton btn = this.buildingButtons[col][row];
          btn.setImageRef(sa.getGfxKey());
          btn.setActionHandler(new ActionHandler() {

            @Override
            public void run() {
              if (ResourceHelper.enoughResourcesFor(sa
                  .getCostMap())) {
                sa.setLinkedBuilding(SectorState.this.selectedBuilding);
                final Colony cc = GameData.getSelectedColony();
                for (Resource r : Resource.values()) {
                  BigDecimal d = sa.getCostMap().get(r);
                  if (d == null) {
                    continue;
                  }
                  cc.updateResource(r, d.negate());
                }
                GameData.getSelectedColony().addSpecialAction(
                    sa);
              } else {
                // TODO Play error sound
              }
            }
          });
          btn.show();
          if (getSelectedBuildingAction() == null) {
            btn.enable();
          } else {
            btn.disable();
          }
          if (btn.isHovered()) {
            showUpgradeCost(sa.getCostMap(), g, btn);
          }
          col++;
          if (col == 3) {
            col = 0;
            row++;
          }
        }
      }
    }

    // Render the UIComponents
    for (UIComponent comp : this.components) {
      comp.render(g);
    }
  }

  @Override
  public void updateState(Input input, int time) throws SlickException {
    this.mouseX = input.getMouseX();
    this.mouseY = input.getMouseY();
    this.squareXOnScreen = getHoveredSquareX(getMouseXOnMap(input
        .getMouseX()));
    this.squareYOnScreen = getHoveredSquareY(getMouseYOnMap(input
        .getMouseY()));
    this.squareXOnMap = getMouseXOnMap(this.squareXOnScreen)
        / Settings.TILE_SIZE;
    this.squareYOnMap = getMouseYOnMap(this.squareYOnScreen)
        / Settings.TILE_SIZE;

    // Map scroll update
    handleScrollUpdate(input);

    // Minimap update
    this.minimap.update(input);

    // Resource progress bars updates
    Resource[] resources = Resource.values();
    for (Resource r : resources) {
      ProgressBar pb = this.resourceBars.get(r);
      pb.update(input);
    }
    this.robotBar.update(input);

    if (GameData.getSelectedColony().isCommandCenterBuilt()) {
      SectorState.this.buildWindow.setCommandCenterBuilt(true);
    } else {
      if (GameData.getSelectedColony().isCommandCenterUnderConstruction()) {
        this.developButton.enable();
      }
      if(selectedAction != null){
        if(selectedAction instanceof BuildingAction){
          BuildingAction ba = (BuildingAction) selectedAction;
          if(!BuildingType.COMMAND_CENTER.equals(ba.getBuilding().getType())){
            // The selected action is not a command center construction
            selectedAction = null;
          }
        }else{
          // The action is not allowed yet
          selectedAction = null;
        }
      }
      this.buildWindow.setCommandCenterBuilt(false);
    }

    this.buildWindow.update(input);

    // Handle action drop
    if (this.selectedAction != null) {
      if (input.isMousePressed(Input.MOUSE_LEFT_BUTTON)
          && this.mouseY > TOP_BAR_HEIGHT
          && this.mouseY < Settings.HEIGHT - BOTTOM_BAR_HEIGHT) {
        final int tileX = this.squareXOnMap;
        final int tileY = this.squareYOnMap;
        if (this.selectedAction instanceof PreparationAction) {
          // Preparation action
          PreparationAction pa = (PreparationAction) this.selectedAction;
          boolean canBuild = false;
          if (TileHelper.tileIsPreparable(tileX, tileY)) {
            // Tile is OK
            if (ResourceHelper
                .enoughResourcesFor(SectorState.this.selectedAction
                    .getCostMap())) {
              // Resources are OK
              if (GameData.getSelectedColony()
                  .getAvailableRobots() > 0) {
                canBuild = true;
              }
            }
          }
          if (canBuild) {
            // Preparation can be done
            pa.setX(tileX);
            pa.setY(tileY);
            Map<Resource, BigDecimal> map = pa.getCostMap();
            for (Resource r : resources) {
              if (map.get(r) == null) {
                // No value defined for this resource
                continue;
              }
              GameData.getSelectedColony().updateResource(r,
                  map.get(r).negate());
            }

            GameData.getSelectedColony().addPreparationAction(
                pa.clone());
          } else {
            // TODO play an error sound
          }

        } else if (this.selectedAction instanceof BuildingAction) {
          BuildingAction ba = (BuildingAction) this.selectedAction;
          if (BuildingType.COMMAND_CENTER.equals(ba.getBuilding()
              .getType())) {
            // Command center construction is handled in a submethod
            handleCommandCenterConstruction(ba, tileX, tileY);
          } else if (TileHelper.tileIsBuildable(tileX, tileY, ba
              .getBuilding().getType())) {
            // Is there already a building there?
            List<Building> buildings = GameData.getSelectedColony()
                .getBuildings();
            boolean canBuild = true;
            for (Building b : buildings) {
              if (b.getX() == tileX && b.getY() == tileY) {
                // Oops, there is already a building here.
                // Construction is impossible
                canBuild = false;
                break;
              }
            }
            // No building, but is there a building under
            // construction?
            List<BuildingAction> bactions = GameData
                .getSelectedColony().getBuildingActions();
            for (BuildingAction cba : bactions) {
              Building cb = cba.getBuilding();
              if (cb.getX() == tileX && cb.getY() == tileY) {
                // Construction is impossible
                canBuild = false;
                break;
              }
            }
            if (!ResourceHelper
                .enoughResourcesFor(SectorState.this.selectedAction
                    .getCostMap())) {
              canBuild = false;
            }
            if (canBuild) {
              ba.getBuilding().setX(tileX);
              ba.getBuilding().setY(tileY);
              final BuildingAction nba = ba.clone();
              if (!BuildingType.ROAD.equals(nba.getBuilding()
                  .getType())) {
                nba.setCallback(new Runnable() {

                  @Override
                  public void run() {
                    if (nba.getBuilding()
                        .equals(SectorState.this.selectedBuilding)) {
                      SectorState.this.selectBuilding(nba
                          .getBuilding());
                    }
                  }
                });
              }
              GameData.getSelectedColony().addBuildingAction(nba);
              // Remove from the stock the building cost
              BuildingData data = BuildingIO.getBuildingData(nba
                  .getBuilding().getType());
              Map<Resource, BigDecimal> map = data
                  .getLevelData(0).getUpgradeCost();
              for (Resource r : resources) {
                GameData.getSelectedColony().updateResource(r,
                    map.get(r).negate());
              }
            } else {
              // TODO play an error sound
            }
          } else {
            // Cannot build here
          }
        }
      } else if (input.isMousePressed(Input.MOUSE_RIGHT_BUTTON)) {
        // Right clic when a building action is selected = deselect
        // building mode
        this.selectedAction = null;
      }
    }

    // Handle building selection
    handleBuildingSelection(input);

    // Building buttons
    for (int col = 0; col < 3; col++) {
      for (int row = 0; row < 3; row++) {
        this.buildingButtons[col][row].update(input);
      }
    }

    // Update the UIComponents
    for (UIComponent comp : this.components) {
      comp.update(input);
    }

    // Shortcuts handling
    handleShortcuts(input);

    //
    if (GameData.getSelectedColony().isResearchCenterBuilt()) {
      this.researchVisionButton.enable();
    } else {
      this.researchVisionButton.disable();
    }

    // If the Planet Exploration technology is researched, the Planet vision
    // is enabled
    if (GameData.getTechnologyMap().get("planet_exploration").isOwned()) {
      this.planetVisionButton.enable();
    } else {
      this.planetVisionButton.disable();
    }

    // Game logic update
    GameEngine.run(time);
  }

  private void handleShortcuts(Input input) {
    // Defined shortcuts :
    // - U : Upgrade the selected building
    // - B : Open the building panel
    // -
    // -
    // -
    if (this.selectedBuilding != null) {
      // Shortcut for building
      if (input.isKeyPressed(Input.KEY_U)) {
        // Upgrade wanted
        upgradeBuilding(this.selectedBuilding);
      }
    }

    if (!this.showActionWindow) {
      if (input.isKeyPressed(Input.KEY_B)) {
        showBuildWindow(true);
      }
    } else {
      // Building window is shown : handle building shortcuts
      if (input.isKeyPressed(Input.KEY_ESCAPE)) {
        showBuildWindow(false);
      } else {
        // Building shortcuts are defined in buildings
        for (BuildingType t : BuildingType.values()) {
          if (t.getShortcut() != -1
              && input.isKeyPressed(t.getShortcut())) {
            // Building selected
            BuildingData data = BuildingIO.getBuildingData(t);
            BuildingAction ba = BuildingHelper.createAction(
                GameData.getSelectedColony(), t, data
                    .getLevelData(0).getUpgradeCost());
            setSelectedAction(ba);
            showBuildWindow(false);
            break;
          }
        }
        // May be a robot shortcut?
        if (input.isKeyPressed(Input.KEY_A)) {
          // Robot action
          setSelectedAction(BuildingHelper.create(GameData
              .getSelectedColony()));
          showBuildWindow(false);
        }
      }
    }
  }

  private void showBuildWindow(boolean show) {
    this.showActionWindow = show;
    if (show) {
      this.buildWindow.show();
    } else {
      this.buildWindow.hide();
    }
  }

  /**
   * This method create the scroll zones. Those zones will be used in the
   * update method in order to trigger the scrolls.
   */
  private void initializeScrollZones() {
    // Top zone
    int x = -1;
    int y = 0;
    int width = Settings.WIDTH + 2;
    int height = Settings.MAP_SCROLL_SENSITIVITY;
    this.topScrollZone = new Rectangle(x, y, width, height);

    // Bottom zone
    x = -1;
    y = Settings.HEIGHT - Settings.MAP_SCROLL_SENSITIVITY + 1;
    width = Settings.WIDTH + 2;
    height = Settings.MAP_SCROLL_SENSITIVITY + 1;
    this.bottomScrollZone = new Rectangle(x, y, width, height);

    // Left zone
    x = -1;
    y = 0;
    width = Settings.MAP_SCROLL_SENSITIVITY;
    height = Settings.HEIGHT + 2;
    this.leftScrollZone = new Rectangle(x, y, width, height);

    // Right zone
    x = Settings.WIDTH - Settings.MAP_SCROLL_SENSITIVITY;
    y = 0;
    width = Settings.MAP_SCROLL_SENSITIVITY + 1;
    height = Settings.HEIGHT + 2;
    this.rightScrollZone = new Rectangle(x, y, width, height);
  }

  /**
   * Handle the scroll on the map
   *
   * @param input
   *            the player input
   */
  private void handleScrollUpdate(Input input) {
    final int mouseX = input.getMouseX();
    final int mouseY = input.getMouseY();
    Colony c = GameData.getSelectedColony();
    // Vertical scroll
    if (this.topScrollZone.contains(mouseX, mouseY)) {
      c.setViewportY(c.getViewportY() + Settings.MAP_SCROLL_SPEED);
    } else if (this.bottomScrollZone.contains(mouseX, mouseY)) {
      c.setViewportY(c.getViewportY() - Settings.MAP_SCROLL_SPEED);
    }

    // Horizontal scroll
    if (this.leftScrollZone.contains(mouseX, mouseY)) {
      c.setViewportX(c.getViewportX() + Settings.MAP_SCROLL_SPEED);
    } else if (this.rightScrollZone.contains(mouseX, mouseY)) {
      c.setViewportX(c.getViewportX() - Settings.MAP_SCROLL_SPEED);
    }
  }

  /**
   * Render the buildings on the map
   *
   * @param g
   *            the graphic canvas
   * @throws SlickException
   */
  private void renderBuildings(Graphics g) throws SlickException {
    // Built constructions
    List<Building> buildings = GameData.getSelectedColony().getBuildings();
    for (Building b : buildings) {
      Image gfx = null;
      if (BuildingType.ROAD.equals(b.getType())) {
        // Road are rendered according to the neighbors buildings
        gfx = UIHelper.getRoadGfx(b);
        gfx.draw(getScreenX(b.getX()), getScreenY(b.getY()));
      } else {
        gfx = ImageManager.getGfx(b.getType().toString());
        gfx.draw(getScreenX(b.getX()), getScreenY(b.getY()));
        if (b.equals(this.selectedBuilding)) {
          highlightBuilding(g, b);
        }
      }

    }

    // Constructions in progress
    List<BuildingAction> actions = GameData.getSelectedColony()
        .getBuildingActions();
    for (BuildingAction action : actions) {
      Building b = action.getBuilding();
      Image gfx = null;
      if (BuildingType.ROAD.equals(b.getType())) {
        // Road are rendered according to the neighbors buildings
        gfx = UIHelper.getRoadGfx(b);
      } else {
        gfx = ImageManager.getGfx(b.getType().toString());
      }
      gfx.draw(getScreenX(b.getX()), getScreenY(b.getY()), new Color(
          0.5F, 0.5F, 0.5F, 0.5F));

      // Render the construction progress bar
      int progress = action.getProgression();
      int x = getScreenX(b.getX());
      int y = getScreenY(b.getY());
      int width = NumberHelper.ruleOf3(100, Settings.TILE_SIZE, progress);

      if (action.isUpgrade()) {
        // Update : yellow
        g.setColor(Color.magenta);
      } else {
        // Creation : red
        g.setColor(Color.red);
      }
      g.drawLine(x, y, x + width, y);
      g.drawLine(x, y + 1, x + width, y + 1);
      g.drawLine(x, y + 2, x + width, y + 2);

      if (b.equals(this.selectedBuilding)) {
        highlightBuilding(g, b);
      }
    }

    // Robots
    List<PreparationAction> robotActions = GameData.getSelectedColony()
        .getPreparationActions();
    for (PreparationAction a : robotActions) {
      Image gfx = ImageManager.getGfx(a.getGfxKey());
      gfx.draw(getScreenX(a.getX()), getScreenY(a.getY()));

      // Render the construction progress bar
      int progress = a.getProgression();
      int x = getScreenX(a.getX());
      int y = getScreenY(a.getY());
      int width = NumberHelper.ruleOf3(100, Settings.TILE_SIZE, progress);

      g.setColor(Color.red);
      g.drawLine(x, y, x + width, y);
      g.drawLine(x, y + 1, x + width, y + 1);
      g.drawLine(x, y + 2, x + width, y + 2);
    }
  }

  /**
   * Transform a screen coordinate to a map coordinate
   *
   * @param mouseXOnScreen
   *            The X coordinate of the mouse on the screen
   * @return the X coordinate of the mouse on the map
   */
  private int getMouseXOnMap(int mouseXOnScreen) {
    return -GameData.getSelectedColony().getViewportX() + mouseXOnScreen;
  }

  /**
   * Transform a screen coordinate to a map coordinate
   *
   * @param mouseYOnScreen
   *            The Y coordinate of the mouse on the screen
   * @return the Y coordinate of the mouse on the map
   */
  private int getMouseYOnMap(int mouseYOnScreen) {
    return -GameData.getSelectedColony().getViewportY() + mouseYOnScreen;
  }

  /**
   * Take a coordinate from the map and convert it to screen coordinate
   *
   * @param mapX
   *            the X coordinate
   * @return the screen X coordinate
   */
  private int getScreenX(int mapX) {
    return mapX * Settings.TILE_SIZE
        + GameData.getSelectedColony().getViewportX();
  }

  /**
   * Take a coordinate from the map and convert it to screen coordinate
   *
   * @param mapY
   *            the Y coordinate
   * @return the screen Y coordinate
   */
  private int getScreenY(int mapY) {
    return mapY * Settings.TILE_SIZE
        + GameData.getSelectedColony().getViewportY();
  }

  /**
   * Render a highligh on the given building
   *
   * @param g
   *            The graphic canvas
   * @param b
   *            The building to highlight
   */
  private void highlightBuilding(Graphics g, Building b) {
    final int tileSize = Settings.TILE_SIZE - 1;
    g.setColor(Color.red);
    g.drawRect(getScreenX(b.getX()), getScreenY(b.getY()), tileSize,
        tileSize);
  }

  /**
   * Render robots currently preparing the ground
   *
   * @param g
   *            the graphic canvas
   * @throws SlickException
   */
  private void renderRobots(Graphics g) throws SlickException {
    List<PreparationAction> actions = GameData.getSelectedColony()
        .getPreparationActions();
    for (PreparationAction a : actions) {
      Image gfx = ImageManager.getGfx("terrabot");
      gfx.draw(getScreenX(a.getX()), getScreenY(a.getY()));
    }
  }

  /**
   * This method handles resource rendering. For each resource, a progress bar
   * will be rendered representing the store space used. The last modifier
   * applyed on the resource will also be rendered
   *
   * @param g
   *            the graphic canvas
   * @param ox
   *            the x origin for the render of this area
   * @param oy
   *            the y origin for the render of this area
   * @throws SlickException
   */
  private void renderProgressBars(Graphics g, int ox, int oy)
      throws SlickException {
    final int padding = 3;
    int pitch = 106 + 24;
    int x = ox;
    BigDecimal inStore;
    BigDecimal max;
    StringBuilder builder = new StringBuilder();
    Resource[] resources = Resource.values();
    ProgressBar pb;
    Map<Resource, BigDecimal> modifiers = GameData.getSelectedColony()
        .getLastModifiers();
    BigDecimal modifier;

    // Progress bar of robots use
    UIHelper.drawDarkBox(g, x + padding, oy + padding, 24, 20);
    Image img = ImageManager.getGfx("robot-small");
    img.draw(x + padding + 2, oy + padding);
    BigDecimal maxVal = BigDecimal.valueOf(GameData.getSelectedColony()
        .getTotalRobots());
    BigDecimal curVal = BigDecimal.valueOf(GameData.getSelectedColony()
        .getAvailableRobots());
    this.robotBar.setMaxValue(maxVal);
    this.robotBar.setValue(curVal);
    this.robotBar.setX(x + padding + 24);
    this.robotBar.setY(oy + padding);
    this.robotBar.render(g);

    // Rendering values
    // builder.setLength(0);
    // builder.append(curVal).append("/").append(maxVal);
    // font.drawString(x + padding, oy + 22, builder.toString());
    final int padd = 18;

    // Rendering of the rows titles
    int y = oy + 25;
    this.storeTitle.setPosition(x, y);
    y += padd;
    this.modifierTitle.setPosition(x, y);
    y += padd;
    this.availableSpaceTitle.setPosition(x, y);
    y += padd;
    this.maxStoreTitle.setPosition(x, y);

    x += pitch;
    for (Resource r : resources) {
      // Retreiving data
      inStore = GameData.getSelectedColony().getResource(r);
      max = GameData.getSelectedColony().getStorSpace(r);
      final int availableSpace = max.subtract(inStore).intValue();

      UIHelper.drawDarkBox(g, x + padding, oy + padding, 24, 20);
      img = ImageManager.getGfx(r.getGfxBase() + "-small");
      img.draw(x + padding + 2, oy + padding);
      // Creating and rendering the progress bar
      pb = this.resourceBars.get(r);
      pb.setX(x + padding + 24);
      pb.setY(oy + padding);
      pb.setMaxValue(max);
      pb.setValue(inStore);
      pb.render(g);

      // Rendering the resource amount, max and modifier
      if (this.extendedResourceDisplay) {
        y = oy + 25;

        // Currently in store
        String temp = inStore.setScale(0, BigDecimal.ROUND_FLOOR)
            .toString();
        Label current = this.inStoreLabels.get(r);
        drawResourceData(g, x + padding, y + 2, temp, current);
        y += padd;

        // Modifiers
        builder.setLength(0);
        modifier = modifiers.get(r);
        if (modifier.signum() == -1) {
          // Negative value
          builder.append("-");
        } else if (modifier.signum() == 1) {
          // Positive value
          builder.append("+");
        }
        builder.append(modifier);
        Label modifierLabel = this.modifiersLabels.get(r);
        drawResourceData(g, x + padding, y + 2, modifier.toString(),
            modifierLabel);
        y += padd;

        // Available space
        Label availableLabel = this.availableSpaceLabels.get(r);
        drawResourceData(g, x + padding, y + 2,
            String.valueOf(availableSpace), availableLabel);
        y += padd;

        // Max
        temp = max.toString();
        Label maxLabel = this.maxStoreLabels.get(r);
        drawResourceData(g, x + padding, y + 2, temp, maxLabel);
      }

      x += pitch;
    }
  }

  /**
   * Draws the black box behind resources values and move the label at the
   * right position
   *
   * @param g
   *            The graphic canvas
   * @param x
   *            The X coordinate
   * @param y
   *            The Y coordinate
   * @param value
   *            The string representation of the resource value
   * @param label
   *            The label
   * @throws SlickException
   */
  private void drawResourceData(Graphics g, int x, int y, String value,
      Label label) throws SlickException {
    final int zoneHeight = 15;
    UIHelper.drawDarkBox(g, x, y, label.getWidth() + 4, zoneHeight);
    label.setPosition(x, y);
    label.setText(value);
    label.setVisible(true);
  }

  /**
   *
   * @param action
   */
  public void setSelectedAction(MapAction action) {
    this.selectedAction = action;
    showBuildWindow(false);
  }

  /**
   * According to the last mouse position on screen, get the X coordinate of
   * the hovered square on the map
   *
   * @param mouseXOnMap
   *            X coordinate of the mouse on the map
   * @return X coordinate of the hovered square on the map
   */
  private int getHoveredSquareX(int mouseXOnMap) {
    return mouseXOnMap - (mouseXOnMap % 32)
        + GameData.getSelectedColony().getViewportX();
  }

  /**
   * According to the last mouse position on screen, get the Y coordinate of
   * the hovered square on the map
   *
   * @param mouseYOnMap
   *            Y coordinate of the mouse on the map
   * @return Y coordinate of the hovered square on the map
   */
  private int getHoveredSquareY(int mouseYOnMap) {
    return mouseYOnMap - (mouseYOnMap % 32)
        + GameData.getSelectedColony().getViewportY();
  }

  /**
   * Handle the building selected area with the proper data
   *
   * @param input
   *            The player input
   */
  private void handleBuildingSelection(Input input) {
    // Handle the building selection on the map only if the mouse is on the
    // viewport
    Rectangle zone = new Rectangle(0, TOP_BAR_HEIGHT, Settings.WIDTH,
        Settings.HEIGHT - TOP_BAR_HEIGHT - BOTTOM_BAR_HEIGHT);
    if (input.isMousePressed(Input.MOUSE_LEFT_BUTTON)
        && zone.contains(this.mouseX, this.mouseY)) {
      selectBuilding(GameData.getSelectedColony().getBuildingAt(
          this.squareXOnMap, this.squareYOnMap));

      if (this.selectedBuilding != null) {
        if (BuildingType.ROAD.equals(this.selectedBuilding.getType())) {
          // For now, road are not selectable.
          // TODO Handle selectable buildings properly
          selectBuilding(null);
        } else {
          // The center button must be updated with the building gfx
          // this.buildCenterButton.setImageRef(this.selectedBuilding
          // .getType().toString());
          // this.buildCenterButton
          // .setActionHandler(new ActionHandler() {
          //
          // @Override
          // public void run() {
          // Move the viewport to the building
          // centerVieportOn(
          // PlayState.this.selectedBuilding
          // .getX()
          // * Settings.TILE_SIZE,
          // PlayState.this.selectedBuilding
          // .getY()
          // * Settings.TILE_SIZE);
          // }
          // });
        }
      }
    }
  }

  /**
   * Render the selected building's attributes
   *
   * @param g
   *            The graphic canvas
   * @throws SlickException
   */
  private void renderBuildingAttributes(Graphics g) throws SlickException {
    final int ox = 150 + PADDING * 2;
    final int oy = Settings.HEIGHT - 116 - PADDING;

    // Building stats
    final int pitchX = 88;
    final int pitchY = 22;
    final int startX = ox + PADDING;
    int x = ox + pitchX;
    int y = oy;

    // Columns labels
    for (int col = 0; col < 3; col++) {
      Label lbl = this.buildingColLabels[col];
      lbl.setVisible(true);
      lbl.setPosition(x, y);
      x += pitchX;
    }

    y += 25;
    x = startX;

    BuildingData data = BuildingIO.getBuildingData(this.selectedBuilding
        .getType());
    BuildingLevelData levelData = data.getLevelData(this.selectedBuilding
        .getLevel());
    Map<Resource, BigDecimal> prod = levelData.getProduction();
    Map<Resource, BigDecimal> cons = levelData.getConsumption();
    Map<Resource, BigDecimal> store = levelData.getStoreCapacity();
    Resource[] resources = Resource.values();
    for (Resource r : resources) {
      // TODO Row label
      Label rowLabel = this.buildingRowLabels.get(r);
      rowLabel.setVisible(true);
      rowLabel.setPosition(x, y);
      x += pitchX;

      // Production
      Label prodLabel = this.buildingProdLabels.get(r);
      String prodValue = prod.get(r).toString();
      drawResourceData(g, x, y, prodValue, prodLabel);

      // Consumption
      Label consLabel = this.buildingConsLabels.get(r);
      String consValue = cons.get(r).toString();
      drawResourceData(g, x += pitchX, y, consValue, consLabel);

      // Store provided
      Label storeLabel = this.buildingStoreLabels.get(r);
      String storeValue = store.get(r).toString();
      drawResourceData(g, x += pitchX, y, storeValue, storeLabel);

      y += pitchY;
      x = startX;
    }
  }

  /**
   * Render the building overview
   *
   * @param g
   *            The graphic canvas
   * @throws SlickException
   */
  private void renderBuildingOverview(Graphics g) throws SlickException {
    final int ox = 150 + PADDING * 2 + 368 + PADDING;
    final int oy = Settings.HEIGHT - Minimap.HEIGHT.intValue() - PADDING;

    UIHelper.drawDarkBox(g, ox + PADDING, oy + PADDING * 2 + 32, 33, 33);

    Image gfx = ImageManager.getGfx(this.selectedBuilding.getType()
        .toString().toLowerCase());
    gfx.draw(ox + PADDING + 1, oy + PADDING * 2 + 32);

    // Building name
    Font fontBig = FontHelper
        .getFont(FontHelper.HEMI_HEAD, Color.white, 30);
    Font fontNormal = FontHelper.getFont(FontHelper.HEMI_HEAD, Color.white,
        20);

    int x = ox + PADDING * 2 + 32;
    int y = oy + PADDING * 2;
    fontBig.drawString(x - 40, y, FontHelper.firstToUpper(I18n
        .get(this.selectedBuilding.getI18n())));

    // Building level
    String temp = I18n.get("global.level") + " : "
        + this.selectedBuilding.getLevel();
    fontNormal.drawString(x, y += 40, FontHelper.firstToUpper(temp));

    // Current action
    String title = null;
    BigDecimal maxValue = null;
    BigDecimal value = null;
    DelayedAction a = getSelectedBuildingAction();
    this.selectedBuildingPB.setFilledColor(Color.red);
    if (a instanceof BuildingAction) {
      BuildingAction ba = (BuildingAction) a;
      if (ba.isUpgrade()) {
        // Upgrade process
        title = FontHelper.firstToUpper(I18n.get("global.upgrading"))
            + "...";
        this.selectedBuildingPB.setFilledColor(Color.magenta);
      } else if (!ba.isUpgrade()) {
        // Building process
        title = FontHelper.firstToUpper(I18n.get("global.building"))
            + "...";
      }
      maxValue = BigDecimal.valueOf(ba.getDuration());
      value = BigDecimal.valueOf(ba.getCurrentValue());
    } else if (a instanceof ColonyAction) {
      ColonyAction sa = (ColonyAction) a;
      title = FontHelper.firstToUpper(I18n.get(sa.getI18nKey())) + "...";
      this.selectedBuildingPB.setFilledColor(Color.red);
      maxValue = BigDecimal.valueOf(sa.getDuration());
      value = BigDecimal.valueOf(sa.getCurrentValue());
    }

    if (a != null) {
      fontNormal.drawString(x, y += 35, title);

      // Action progress
      this.selectedBuildingPB.setMaxValue(maxValue);
      this.selectedBuildingPB.setValue(value);
      this.selectedBuildingPB.setOX(x);
      this.selectedBuildingPB.setOY(y += 20);
      this.selectedBuildingPB.render(g);
    }

  }

  /**
   * Select a building. By selecting a building (or unselecting one), the
   * attributes labels will be shown or hidden
   *
   * @param b
   *            The building to select or null
   */
  private void selectBuilding(Building b) {
    // Manage buttons visibility
    // Default buttons :
    // - Upgrade [0,2]
    // - Destroy [1,2]
    // - Cancel [2,2]
    // All buttons are hidden and disabled first, then, only useful buttons
    // are shown
    for (int col = 0; col < 3; col++) {
      for (int row = 0; row < 3; row++) {
        this.buildingButtons[col][row].hide();
        this.buildingButtons[col][row].disable();
      }
    }

    this.selectedBuilding = b;
    if (b == null) {
      // No building selected : hide buttons and labels
      Resource[] resources = Resource.values();
      for (Resource r : resources) {
        this.buildingConsLabels.get(r).setVisible(false);
        this.buildingProdLabels.get(r).setVisible(false);
        this.buildingStoreLabels.get(r).setVisible(false);
        this.buildingRowLabels.get(r).setVisible(false);
      }
      for (int i = 0; i < 3; i++) {
        this.buildingColLabels[i].setVisible(false);
      }
      return;
    }

    final boolean actionOngoing = this.getSelectedBuildingAction() != null;

    // Show useful buttons
    // Upgrade button is shown if there is another level for the building
    BuildingData data = BuildingIO.getBuildingData(this.selectedBuilding
        .getType());
    BuildingLevelData nextLevel = data.getLevelData(this.selectedBuilding
        .getLevel() + 1);
    if (nextLevel != null) {
      // There is a level
      this.buildingButtons[0][2].show();
      // Is it OK with technologies?
      if (TechnologyHelper.technologiesAreOwned(nextLevel
          .getTechnologiesNeeded())) {
        // OK but... Is there an action ongoing?
        if (!actionOngoing) {
          this.buildingButtons[0][2].enable();
        }
      }
    } else {
      // No more level : button stay hidden
    }

    // Cancel button is always shown but only enabled if an action is
    // currently being done
    this.buildingButtons[2][2].show();
    if (actionOngoing) {
      // There is an action to stop : enable the cancel button
      this.buildingButtons[2][2].enable();
    }
  }

  /**
   * Stops the selected building action
   */
  private void stopSelectedBuildingAction() {
    DelayedAction a = getSelectedBuildingAction();

    // Robot release
    GameData.getSelectedColony().releaseRobots(a.getRobotsUsed());

    // Deletion of the action in the GameData
    if (a instanceof BuildingAction) {
      BuildingAction ba = (BuildingAction) a;
      GameData.getSelectedColony().getBuildingActions().remove(ba);

      // If the action was a building then unselect the building
      if (ba.getBuilding().isUnderConstruction()) {
        // Call to selectBuilding method to handle buttons state
        // properly
        this.selectBuilding(null);

        // TODO Play destruction sound
      } else {
        // Call to selectBuilding method to handle buttons state
        // properly
        this.selectBuilding(this.selectedBuilding);
      }
    }

  }

  /**
   * @return the action currently done by the building
   */
  private DelayedAction getSelectedBuildingAction() {
    // Searching for building or upgrading action...
    List<BuildingAction> baList = GameData.getSelectedColony()
        .getBuildingActions();
    for (BuildingAction ba : baList) {
      if (ba.getBuilding().equals(this.selectedBuilding)) {
        return ba;
      }
    }

    // Searching for special action
    List<ColonyAction> saList = GameData.getSelectedColony()
        .getSpecialActions();
    for (ColonyAction sa : saList) {
      if (sa.getLinkedBuilding() != null
          && sa.getLinkedBuilding().equals(this.selectedBuilding)) {
        return sa;
      }
    }
    return null;
  }

  /**
   * Upgrade a building to it's next level. Checks resources first and then
   * lunch an upgrade action
   *
   * @param b
   *            the building to upgrade
   */
  private void upgradeBuilding(final Building b) {
    // Check resources
    BuildingLevelData levelData = BuildingIO.getBuildingData(b.getType())
        .getLevelData(b.getLevel());
    Map<Resource, BigDecimal> costMap = levelData.getUpgradeCost();
    // Enough resources ?
    if (ResourceHelper.enoughResourcesFor(costMap)) {
      Resource[] resources = Resource.values();
      for (Resource r : resources) {
        if (costMap.get(r) == null) {
          // No value defined for this resource
          continue;
        }
        GameData.getSelectedColony().updateResource(r,
            costMap.get(r).negate());
      }

      // Enough robots?
      if (GameData.getSelectedColony().getAvailableRobots() == 0) {
        // TODO Play error sound
        return;
      }

      // Create the action
      int duration = 5; // TODO extract into building config file
      BuildingAction ba = new BuildingAction(
          GameData.getSelectedColony(), costMap, b, duration, 1, true);
      ba.setCallback(new Runnable() {

        @Override
        public void run() {
          if (b.equals(SectorState.this.selectedBuilding)) {
            SectorState.this.selectBuilding(b);
          }
        }
      });

      GameData.getSelectedColony().addBuildingAction(ba);

      // Call to selectBuilding method to handle buttons state properly
      selectBuilding(b);
    } else {
      // TODO Play error sound
    }
  }

  /**
   * Render a window with upgrade informations
   *
   * @param costMap
   *            The cost map of the upgrade
   * @param g
   *            The graphic canvas
   * @throws SlickException
   */
  protected void showUpgradeCost(Map<Resource, BigDecimal> costMap,
      Graphics g, ImageButton btn) throws SlickException {
    // Draw the BG
    final int width = 120;
    final int height = 101;
    final int box = btn.getOX();
    final int boy = btn.getOY();
    int x = box + btn.getWidth() / 2 - width / 2;
    int y = Settings.HEIGHT - BOTTOM_BAR_HEIGHT - height;
    UIHelper.drawBox(g, x, y, width, height);
    UIHelper.drawDarkBox(g, x += 3, y += 3, width - 6, height - 6);

    Resource[] resources = Resource.values();
    Image img;
    x += 3;
    for (Resource r : resources) {
      UIHelper.drawDarkBox(g, x, y += 3, 24, 20);
      img = ImageManager.getGfx(r.getGfxBase() + "-small");
      img.draw(x + 3, y, r.getColor());

      String value = costMap.get(r).toString();
      Label lbl = this.upgradeLabels.get(r);
      drawResourceData(g, x + 24, y, value, lbl);

      y += 20;
    }
  }

  /**
   * Hide the labels in the upgrade overview window
   */
  private void hideUpgradeLabels() {
    // Hide the labels
    Resource[] resources = Resource.values();
    for (Resource r : resources) {
      this.upgradeLabels.get(r).setVisible(false);
    }
  }

  private void handleCommandCenterConstruction(BuildingAction ba,
      final int tileX, final int tileY) {
    // If there is already a command center under construction, no mode
    // build action is handled (prevents from creating more than one command
    // center)
    if (GameData.getSelectedColony().isCommandCenterBuilt()) {
      return;
    }
    List<BuildingAction> actions = GameData.getSelectedColony()
        .getBuildingActions();
    for (BuildingAction a : actions) {
      if (BuildingType.COMMAND_CENTER.equals(a.getBuilding().getType())) {
        // There is already a command center under construction
        return;
      }
    }
    TiledMap map = GameData.getSelectedColony().getMap();
    final int mapWidth = map.getWidth();
    final int mapHeight = map.getHeight();

    if (!TileHelper.isValidCommandCenterTile(tileX, tileY)) {
      // TODO Play error sound
      // The zone is not correct for Command Center construction.
      return;
    }

    ba.getBuilding().setX(tileX);
    ba.getBuilding().setY(tileY);
    final BuildingAction nba = ba.clone();
    final Colony c = GameData.getSelectedColony();
    nba.setCallback(new Runnable() {

      @Override
      public void run() {
        BuildingHelper.createCMConstructionCallback(tileX, tileY, c);
      }
    });

    TileHelper.setTile(tileX, tileY, TileHelper.BUILDABLE_TILE,
        GameData.getSelectedColony());
    c.addBuildingAction(nba);

    // Construction is disabled until command center is fully built
    this.developButton.disable();

    // By the way the Command Center is unselected automatically when built
    this.selectedAction = null;
    GameData.getSelectedColony().setCommandCenterUnderConstruction(true);
  }

  @Override
  protected void renderTopZone(Graphics g) throws SlickException {
    int width = TOP_BAR_WIDTH + TOGGLE_BUTTON_ZONE_WIDTH;
    int height;
    if (this.extendedResourceDisplay) {
      height = 100;
    } else {
      height = 26;
    }
    int x = Settings.WIDTH / 2 - width / 2;
    int y = PADDING;
    UIHelper.drawWindow(g, x - 10, y - 10, width + 20, height + 20, 5);
    // UIHelper.drawBlackBox(g, x, y, width, height);

    renderProgressBars(g, x + TOGGLE_BUTTON_ZONE_WIDTH, y);

    // Render the colony name
    UIHelper.drawWindow(g, Settings.WIDTH - 140, 0, 140, 46, 5);
    Font font = FontHelper.getFont(FontHelper.HEMI_HEAD, Color.white, 20);
    font.drawString(Settings.WIDTH - 130, 15, GameData.getSelectedColony()
        .getName());
  }
}
TOP

Related Classes of com.drakulo.games.ais.ui.state.SectorState

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.