/*
* Copyright (c) 2003-onwards Shaven Puppy Ltd
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'Shaven Puppy' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.puppygames.applet.screens;
import java.util.LinkedList;
import java.util.List;
import net.puppygames.applet.*;
import net.puppygames.applet.effects.SFX;
import org.lwjgl.input.*;
import org.lwjgl.util.Point;
import org.w3c.dom.Element;
import com.shavenpuppy.jglib.Resources;
import com.shavenpuppy.jglib.resources.Feature;
import com.shavenpuppy.jglib.sprites.ImageBank;
import com.shavenpuppy.jglib.sprites.Sprite;
import com.shavenpuppy.jglib.util.XMLUtil;
/**
* $Id: BindingsScreen.java,v 1.2 2010/05/20 21:17:33 foo Exp $
* Redefine keys
* @author $Author: foo $
* @version $Revision: 1.2 $
*/
public class BindingsScreen extends Screen {
private static final long serialVersionUID = 1L;
/*
* Static data
*/
/** Singleton */
private static BindingsScreen instance;
/** Phases */
private static final int PHASE_NORMAL = 0;
private static final int PHASE_WAIT = 1;
/*
* Areas
*/
private static final String OK = "ok";
private static final String CANCEL = "cancel";
private static final String INSTRUCTIONS = "instructions";
private static final String KEY_PREFIX = "bindingarea.";
private static final String BINDINGS_GROUP = "bindingarea";
private static final String RESET = "reset";
/*
* Resource data
*/
/** An imagebank of keys */
private String keys;
/** An imagebank of mousebuttons */
private String mouse;
/** An imagebank of controller buttons */
private String controller;
/** An imagebank of dpad buttons */
private String dpad;
/** Character offset */
private Point offset = new Point(0, 0);
/** Key areas */
private List<KeyArea> keyAreas;
/** Allow mouse bindings */
private boolean allowMouse = true;
/** Allow keyboard bindings */
private boolean allowKeyboard = true;
/** Allow controller bindings */
private boolean allowController = true;
/**
* Keys
*/
private static class KeyArea extends Feature {
private static final long serialVersionUID = 1L;
/** Binding we're linked to */
private String binding;
/** Location */
private Point location;
/** Text location */
private Point textLocation;
/** Glyph sprite */
private transient Sprite glyphSprite;
/** Screen */
private transient BindingsScreen screen;
/**
* C'tor
*/
public KeyArea() {
setAutoCreated();
setSubResource(true);
}
void init(BindingsScreen screen) {
this.screen = screen;
glyphSprite = screen.allocateSprite(this);
glyphSprite.setLocation(location.getX(), location.getY());
glyphSprite.setOffset(screen.offset.getX(), screen.offset.getY());
glyphSprite.setLayer(1);
update();
}
void cleanup() {
if (glyphSprite != null) {
glyphSprite.deallocate();
glyphSprite = null;
}
}
void update() {
Binding b;
try {
b = (Binding) Resources.get(binding);
if (b.getType() == null) {
System.out.println("No binding for "+binding);
glyphSprite.setVisible(false);
} else {
glyphSprite.setVisible(true);
if (b.getType().equals(Binding.KEYBOARD)) {
glyphSprite.setAppearance(screen.keysImageBank.getImage(b.getIndex()));
} else if (b.getType().equals(Binding.KEYBOARD)) {
glyphSprite.setAppearance(screen.mouseImageBank.getImage(b.getIndex()));
} else if (b.getType().equals(Binding.CONTROLLER)) {
glyphSprite.setAppearance(screen.controllerImageBank.getImage(b.getIndex()));
} else if (b.getType().equals(Binding.DPAD)) {
glyphSprite.setAppearance(screen.dpadImageBank.getImage(b.getIndex()));
}
}
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
}
/*
* Transient data
*/
private transient ImageBank keysImageBank, mouseImageBank, controllerImageBank, dpadImageBank;
/** Current phase */
private transient int phase;
/** Which binding we're setting */
private transient String binding;
/**
* @param name
*/
public BindingsScreen(String name) {
super(name);
}
/* (non-Javadoc)
* @see com.shavenpuppy.jglib.resources.Feature#doRegister()
*/
@Override
protected void doRegister() {
instance = this;
}
/* (non-Javadoc)
* @see com.shavenpuppy.jglib.resources.Feature#doDeregister()
*/
@Override
protected void doDeregister() {
instance = null;
}
/**
* Show the redefine keys screnn if there is one
*/
public static void show() {
if (instance != null) {
if (!instance.isCreated()) {
try {
instance.create();
} catch (Exception e) {
e.printStackTrace(System.err);
instance = null;
return;
}
}
instance.open();
}
}
/* (non-Javadoc)
* @see net.puppygames.applet.Screen#onClicked(java.lang.String)
*/
@Override
protected void onClicked(String id) {
GenericButtonHandler.onClicked(id);
if (OK.equals(id)) {
// Save the bindings
Game.saveBindings();
TitleScreen.show();
} else if (CANCEL.equals(id)) {
if (phase == PHASE_NORMAL) {
Game.loadBindings();
TitleScreen.show();
} else {
doneBinding();
}
} else if (RESET.equals(id)) {
Binding.resetToDefaults();
updateBindingsDisplay();
} else if (id.startsWith(KEY_PREFIX)) {
waitForInput(id.substring(KEY_PREFIX.length()));
}
}
/**
* Wait for a keypress or mouse button to assign to a particular binding.
*/
public void waitForInput(String binding) {
phase = PHASE_WAIT;
setEnabled(OK, false);
setEnabled(RESET, false);
setVisible(INSTRUCTIONS, true);
this.binding = binding;
setKeyboardNavigationEnabled(false);
setGroupEnabled(BINDINGS_GROUP, false);
Game.setPauseEnabled(false);
SFX.keyTyped();
}
/* (non-Javadoc)
* @see net.puppygames.applet.Screen#doTick()
*/
@Override
protected void doTick() {
if (phase == PHASE_NORMAL) {
return;
}
// Check for a keypress
if (Game.wasKeyPressed(Keyboard.KEY_ESCAPE)) {
doneBinding();
return;
}
if (allowKeyboard) {
for (int i = 0; i < Keyboard.KEYBOARD_SIZE; i ++) {
if (Keyboard.isKeyDown(i) && i != Keyboard.KEY_ESCAPE && i != Keyboard.KEY_P) {
Binding.setBinding(binding, Binding.KEYBOARD, i);
doneBinding();
}
}
}
// Check for a mouse button
if (allowMouse) {
for (int i = 0; i < Mouse.getButtonCount(); i ++) {
if (Mouse.isButtonDown(i)) {
Binding.setBinding(binding, Binding.MOUSE, i);
doneBinding();
}
}
}
// Check for controllers
if (allowController) {
if (Controllers.getControllerCount() > 0) {
Controller c = Controllers.getController(0);
for (int i = 0; i < c.getButtonCount(); i ++) {
if (c.isButtonPressed(i)) {
Binding.setBinding(binding, Binding.CONTROLLER, i);
doneBinding();
}
}
if (c.getPovX() < -0.5f) {
Binding.setBinding(binding, Binding.DPAD, Binding.DPAD_LEFT_INDEX);
doneBinding();
}
if (c.getPovX() > 0.5f) {
Binding.setBinding(binding, Binding.DPAD, Binding.DPAD_RIGHT_INDEX);
doneBinding();
}
if (c.getPovY() < -0.5f) {
Binding.setBinding(binding, Binding.DPAD, Binding.DPAD_UP_INDEX);
doneBinding();
}
if (c.getPovY() > 0.5f) {
Binding.setBinding(binding, Binding.DPAD, Binding.DPAD_DOWN_INDEX);
doneBinding();
}
}
}
}
/* (non-Javadoc)
* @see net.puppygames.applet.Screen#doCleanup()
*/
@Override
protected void doCleanup() {
// Cleanup the key areas
for (KeyArea keyArea : keyAreas) {
keyArea.cleanup();
}
}
/* (non-Javadoc)
* @see net.puppygames.applet.Screen#onOpen()
*/
@Override
protected void onOpen() {
GenericButtonHandler.onOpen(this);
// Init the key areas
for (KeyArea keyArea : keyAreas) {
keyArea.init(this);
}
}
/**
* Called when we're done with a new binding assignment
*/
public void doneBinding() {
SFX.textEntered();
phase = PHASE_NORMAL;
setEnabled(OK, true);
setEnabled(RESET, true);
setVisible(INSTRUCTIONS, false);
setKeyboardNavigationEnabled(true);
setGroupEnabled(BINDINGS_GROUP, true);
Game.setPauseEnabled(true);
updateBindingsDisplay();
}
/**
* Update bindings display
*/
private void updateBindingsDisplay() {
// Update the binding display
for (KeyArea keyArea : keyAreas) {
keyArea.update();
}
}
/* (non-Javadoc)
* @see com.shavenpuppy.jglib.resources.Feature#load(org.w3c.dom.Element, com.shavenpuppy.jglib.Resource.Loader)
*/
@Override
public void load(Element element, Loader loader) throws Exception {
super.load(element, loader);
List<Element> children = XMLUtil.getChildren(element, "key");
keyAreas = new LinkedList<KeyArea>();
for (Element child : children) {
KeyArea section = new KeyArea();
section.load(child, loader);
keyAreas.add(section);
}
}
/* (non-Javadoc)
* @see com.shavenpuppy.jglib.resources.Feature#doCreate()
*/
@Override
protected void doCreateScreen() {
for (KeyArea section : keyAreas) {
section.create();
}
}
/* (non-Javadoc)
* @see com.shavenpuppy.jglib.resources.Feature#doDestroy()
*/
@Override
protected void doDestroyScreen() {
for (KeyArea section : keyAreas) {
section.destroy();
}
}
}