package com.drakulo.games.ais.ui.state;
import java.util.ArrayList;
import java.util.List;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.state.StateBasedGame;
import com.drakulo.games.ais.AloneInSpace;
import com.drakulo.games.ais.core.GameData;
import com.drakulo.games.ais.core.Settings;
import com.drakulo.games.ais.ui.FontHelper;
import com.drakulo.games.ais.ui.I18n;
import com.drakulo.games.ais.ui.UIHelper;
import com.drakulo.games.ais.ui.component.ActionHandler;
import com.drakulo.games.ais.ui.component.Bindable;
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.TextButton;
import com.drakulo.games.ais.ui.component.window.Window;
import com.drakulo.games.ais.ui.twlbridge.BasicTWLGameState;
import de.matthiasmann.twl.Widget;
/**
* This class is a global wrapper for all in-game states. It renders the basic
* top bar with menu and handle game engine updates.
*
* @author Drakulo
*
*/
public abstract class GameState extends BasicTWLGameState {
/** The top zone height */
public static final int TOP_BAR_HEIGHT = 36;
/** The game menu window height when the menu is not shown */
private static final int MENU_SMALL_HEIGHT = 46;
/** The game menu window height when the menu is shown */
private static final int MENU_FULL_HEIGHT = 195;
/** The state ID */
private int stateId;
/** The components of the state */
private List<UIComponent> components;
/** The game menu buttons */
private List<Button> gameMenuButtons;
/** The mouse last X coordinate */
//private int mx;
/** The mouse Y last coordinate */
//private int my;
/** The game menu background */
private Window gameMenuWindow;
/** componentsToRemove */
private List<UIComponent> componentsToRemove;
/**
* Constructor
*
* @param id
* - the state ID
*/
public GameState(int id) {
stateId = id;
components = new ArrayList<UIComponent>();
gameMenuButtons = new ArrayList<Button>();
componentsToRemove = new ArrayList<UIComponent>();
}
@Override
public void init(GameContainer gc, StateBasedGame game)
throws SlickException {
GameData.setGame(game);
GameData.setGameContainer(gc);
createGameMenu();
initState();
}
@Override
public void render(GameContainer gc, StateBasedGame game, Graphics g)
throws SlickException {
renderState(g);
// Top zone
UIHelper.drawDarkBox(g, 0, 0, Settings.WIDTH, TOP_BAR_HEIGHT + 5);
// Render the top zone data
renderTopZone(g);
gameMenuWindow.render(g);
// Render the components
for (UIComponent c : components) {
c.render(g);
}
// String mouseData = "[" + mx + ", " + my + "]";
// Font font = FontHelper.getDefaultFont();
// font.drawString(0, 0, mouseData);
}
@Override
public void update(GameContainer gc, StateBasedGame game,
int timeSinceLastUpdate) throws SlickException {
// Remove unused components
safeRemove();
final Input input = gc.getInput();
// mx = input.getMouseX();
// my = input.getMouseY();
updateState(input, timeSinceLastUpdate);
gameMenuWindow.update(input);
// Update the components
List<UIComponent> deletedComponents = new ArrayList<UIComponent>();
for (UIComponent c : components) {
if(c != null){
c.update(input);
}else{
deletedComponents.add(c);
}
}
components.removeAll(deletedComponents);
// Special handling for the game menu : if the game menu is shown and
// the player move the mouse outside of the game menu, it is
// automatically closed
if (!gameMenuWindow.isHovered()
&& gameMenuWindow.getHeight() == MENU_FULL_HEIGHT) {
toggleGameMenu();
}
}
@Override
public int getID() {
return stateId;
}
/**
* Adds a component to the handling process. By adding a component to the
* GameState, the given component will automatically be updated and
* rendered.
*
* @param component
* - the component to add
*/
public void add(UIComponent component) {
components.add(component);
if (component instanceof Bindable) {
Bindable b = (Bindable) component;
if (getRootPane().getChildIndex(b.getBindable()) == -1) {
b.bindTo(getRootPane());
}
}
}
public void add(Widget w){
if (getRootPane().getChildIndex(w) == -1) {
getRootPane().add(w);
}
}
public void remove(UIComponent comp) {
componentsToRemove.add(comp);
}
public void removeAll(List<? extends UIComponent> list) {
componentsToRemove.addAll(list);
}
private void safeRemove() {
List<UIComponent> toRemove = new ArrayList<UIComponent>();
for (UIComponent c : componentsToRemove) {
components.remove(c);
toRemove.add(c);
if (c instanceof Bindable) {
Bindable b = (Bindable) c;
getRootPane().removeChild(b.getBindable());
}
}
components.removeAll(toRemove);
}
/**
* Create the game menu
*/
private void createGameMenu() {
final int screenPadding = 10;
final int buttonWidth = 120;
final int buttonHeight = 26;
final int vPadding = 30;
int x = screenPadding + 1;
int y = screenPadding;
String label;
// Button for open the game menu
label = FontHelper.firstToUpper(I18n.get("global.game_menu"));
TextButton gameMenuButton = new TextButton(label, x, y);
gameMenuButton.setSize(buttonWidth, buttonHeight);
gameMenuButton.setActionHandler(new ActionHandler() {
@Override
public void run() {
toggleGameMenu();
}
});
add(gameMenuButton);
// Load button
y += vPadding;
label = FontHelper.firstToUpper(I18n.get("global.load"));
Button loadButton = new TextButton(label, x, y);
loadButton.setSize(buttonWidth, buttonHeight);
loadButton.disable();
loadButton.hide();
loadButton.setActionHandler(new ActionHandler() {
@Override
public void run() {
// TODO
}
});
gameMenuButtons.add(loadButton);
add(loadButton);
// Save button
y += vPadding;
label = FontHelper.firstToUpper(I18n.get("global.save"));
Button saveButton = new TextButton(label, x, y);
saveButton.hide();
saveButton.setSize(buttonWidth, buttonHeight);
saveButton.disable();
saveButton.setActionHandler(new ActionHandler() {
@Override
public void run() {
// TODO
}
});
gameMenuButtons.add(saveButton);
add(saveButton);
// Settings button
y += vPadding;
label = FontHelper.firstToUpper(I18n.get("global.settings"));
Button settingsButton = new TextButton(label, x, y);
settingsButton.setSize(buttonWidth, buttonHeight);
settingsButton.disable();
settingsButton.hide();
settingsButton.setActionHandler(new ActionHandler() {
@Override
public void run() {
// TODO
}
});
gameMenuButtons.add(settingsButton);
add(settingsButton);
// Main menu button
y += vPadding;
label = FontHelper.firstToUpper(I18n.get("global.main_menu"));
Button mainMenu = new TextButton(label, x, y);
mainMenu.setSize(buttonWidth, buttonHeight);
mainMenu.hide();
mainMenu.setActionHandler(new ActionHandler() {
@Override
public void run() {
GameData.getGame().enterState(AloneInSpace.MAIN_MENU_STATE);
}
});
gameMenuButtons.add(mainMenu);
add(mainMenu);
// Exit button
y += vPadding;
label = FontHelper.firstToUpper(I18n.get("global.exit"));
Button exitButton = new TextButton(label, x, y);
exitButton.setSize(buttonWidth, buttonHeight);
exitButton.hide();
exitButton.setActionHandler(new ActionHandler() {
@Override
public void run() {
GameData.getGameContainer().exit();
}
});
gameMenuButtons.add(exitButton);
add(exitButton);
// The game menu background
gameMenuWindow = new Window(0, 0, buttonWidth + 20, MENU_SMALL_HEIGHT);
gameMenuWindow.show();
}
protected void toggleGameMenu() {
for (Button b : gameMenuButtons) {
b.toggleDisplay();
}
if (gameMenuWindow.getHeight() == MENU_SMALL_HEIGHT) {
gameMenuWindow.setHeight(MENU_FULL_HEIGHT);
} else {
gameMenuWindow.setHeight(MENU_SMALL_HEIGHT);
}
}
/**
* Initialize the state
*
* @throws SlickException
*/
protected abstract void initState() throws SlickException;
/**
* Render the state
*
* @param g
* - the graphic canvas
* @throws SlickException
*/
protected abstract void renderState(Graphics g) throws SlickException;
/**
* Update the state
*
* @param input
* - the player input
* @param timeSinceLastUpdate
* - the time elapsed since the last update call
* @throws SlickException
*/
protected abstract void updateState(Input input, int timeSinceLastUpdate)
throws SlickException;
/**
* Render the state specifi data in the top area
*
* @param g
* - the graphic canvas
* @throws SlickException
*/
protected void renderTopZone(Graphics g) throws SlickException {
// Render nothing by default. Must be overridden in subclass
}
}