Finished keys externalization, improved keystroke system, bugfixes

v5stable
ondra 10 years ago
parent d2b83a89b4
commit 6dad9c2302
  1. 107
      src/mightypork/gamecore/Config.java
  2. 3
      src/mightypork/gamecore/core/BaseApp.java
  3. 11
      src/mightypork/gamecore/core/MainLoop.java
  4. 17
      src/mightypork/gamecore/input/KeyBinding.java
  5. 68
      src/mightypork/gamecore/input/KeyStroke.java
  6. 5
      src/mightypork/gamecore/render/DisplaySystem.java
  7. 2
      src/mightypork/gamecore/render/TaskTakeScreenshot.java
  8. 30
      src/mightypork/gamecore/util/files/config/PropertyManager.java
  9. 8
      src/mightypork/rogue/Const.java
  10. 4
      src/mightypork/rogue/RogueApp.java
  11. 53
      src/mightypork/rogue/RogueKeys.java
  12. 93
      src/mightypork/rogue/screens/game/InventoryLayer.java
  13. 6
      src/mightypork/rogue/screens/game/ScreenGame.java

@ -12,7 +12,7 @@ import mightypork.gamecore.util.files.config.PropertyManager;
/**
* Static application config file accessor
* Static application configuration
*
* @author MightyPork
*/
@ -31,14 +31,24 @@ public class Config {
*/
public static class KeyOpts {
private KeyOpts() {
}
public void add(String cfgKey, String dataString)
{
KeyProperty kprop = new KeyProperty(prefixKey(cfgKey), KeyStroke.createFromDataString(dataString), null);
add(cfgKey, dataString, null);
}
public void add(String cfgKey, String dataString, String comment)
{
KeyProperty kprop = new KeyProperty(prefixKey(cfgKey), KeyStroke.createFromDataString(dataString), comment);
strokes.put(prefixKey(cfgKey), kprop);
cfg.putProperty(kprop);
}
}
/**
* Key configurator
*/
@ -46,7 +56,7 @@ public class Config {
public void addKeys(KeyOpts keys);
}
/**
* Key property.<br>
* The stored value must be invariant ({@link KeyStroke} is mutable).
@ -55,8 +65,7 @@ public class Config {
*/
public static class KeyProperty extends Property<KeyStroke> {
public KeyProperty(String key, KeyStroke defaultValue, String comment)
{
public KeyProperty(String key, KeyStroke defaultValue, String comment) {
super(key, defaultValue, comment);
}
@ -94,75 +103,135 @@ public class Config {
getValue().setTo(((KeyStroke) value).getKey(), ((KeyStroke) value).getMod());
}
}
public static Config.KeyOpts keyOpts = new Config.KeyOpts();
public static Map<String, Config.KeyProperty> strokes = new HashMap<>();
public static Map<String, KeyProperty> strokes = new HashMap<>();
private static PropertyManager cfg;
/**
* Initialize property manger for a file
*
* @param file config file
* @param comment file comment
*/
public static void init(File file, String comment)
{
cfg = new PropertyManager(file, comment);
cfg.cfgNewlineBeforeComments(false);
cfg.cfgSeparateSections(true);
}
public static void registerKeys(KeySetup layout)
/**
* populate config with keys from a key setup
*
* @param keys key setup to add
*/
public static void registerKeys(KeySetup keys)
{
layout.addKeys(keyOpts);
keys.addKeys(Config.keyOpts);
}
public static void registerOptions(ConfigSetup cfgl)
/**
* Populate config with options from a config setup
*
* @param conf config setup to add
*/
public static void registerOptions(ConfigSetup conf)
{
cfgl.addOptions(cfg);
conf.addOptions(Config.cfg);
}
/**
* Load config from file
*/
public static void load()
{
cfg.load();
}
/**
* Save config to file
*/
public static void save()
{
cfg.save();
}
/**
* Get an option for key
*
* @param key
* @return option value
*/
public static <T> T getOption(String key)
{
if (cfg.getProperty(key) == null) {
throw new IllegalArgumentException("No such property: " + key);
}
return cfg.getValue(key);
}
/**
* Set option to a value
*
* @param key option key
* @param value value to set
*/
public static <T> void setOption(String key, T value)
{
if (cfg.getProperty(key) == null) {
throw new IllegalArgumentException("No such property: " + key);
}
cfg.setValue(key, value);
}
private static String prefixKey(String cfgKey)
{
return "key." + cfgKey;
}
/**
* Get keystroke for name
*
* @param cfgKey stroke identifier in config file
* @return the stroke
*/
public static KeyStroke getKey(String cfgKey)
{
final Config.KeyProperty kp = strokes.get(prefixKey(cfgKey));
if (kp == null) throw new IllegalArgumentException("No such stroke: " + cfgKey);
final KeyProperty kp = strokes.get(prefixKey(cfgKey));
if (kp == null) {
throw new IllegalArgumentException("No such stroke: " + cfgKey);
}
return kp.getValue();
}
/**
* Set a keystroke for name
*
* @param cfgKey stroke identifier in config file
* @param key stroke key
* @param mod stroke modifiers
*/
public static void setKey(String cfgKey, int key, int mod)
{
final Config.KeyProperty kp = strokes.get(prefixKey(cfgKey));
if (kp == null) throw new IllegalArgumentException("No such stroke: " + cfgKey);
if (kp == null) {
throw new IllegalArgumentException("No such stroke: " + cfgKey);
}
kp.getValue().setTo(key, mod);
}

@ -71,7 +71,7 @@ public abstract class BaseApp implements AppAccess, UncaughtExceptionHandler {
public boolean sigleInstance;
public void setConfigFile(BaseApp baseApp, String filename, String comment)
public void setConfigFile(String filename, String comment)
{
configFile = filename;
configComment = comment;
@ -201,6 +201,7 @@ public abstract class BaseApp implements AppAccess, UncaughtExceptionHandler {
for (final RouteSetup rs : opt.routeLists) {
WorkDir.registerRoutes(rs);
}
WorkDir.addPath("_screenshot_dir", opt.screenshotDir);
// apply configurations
Config.init(WorkDir.getFile(opt.configFile), opt.configComment);

@ -9,6 +9,7 @@ import mightypork.gamecore.gui.screens.ScreenRegistry;
import mightypork.gamecore.render.Renderable;
import mightypork.gamecore.render.TaskTakeScreenshot;
import mightypork.gamecore.render.events.ScreenshotRequestListener;
import mightypork.gamecore.util.Utils;
import mightypork.gamecore.util.annot.DefaultImpl;
import mightypork.gamecore.util.math.timing.TimerDelta;
@ -113,7 +114,15 @@ public class MainLoop extends AppModule implements ScreenshotRequestListener {
@Override
public void onScreenshotRequest()
{
queueTask(new TaskTakeScreenshot());
// ensure it's started in main thread
queueTask(new Runnable() {
@Override
public void run()
{
Utils.runAsThread(new TaskTakeScreenshot());
}
});
}
}

@ -17,6 +17,7 @@ public class KeyBinding implements KeyEventHandler, InputReadyListener {
private final KeyStroke keystroke;
private Runnable handler;
private final Edge edge;
private boolean wasDown = false;
/**
@ -24,13 +25,12 @@ public class KeyBinding implements KeyEventHandler, InputReadyListener {
* @param stroke trigger keystroke
* @param handler action
*/
public KeyBinding(KeyStroke stroke, Edge edge, Runnable handler)
{
public KeyBinding(KeyStroke stroke, Edge edge, Runnable handler) {
this.keystroke = stroke;
this.handler = handler;
this.edge = edge;
if (InputSystem.isReady()) keystroke.poll();
if (InputSystem.isReady()) wasDown = stroke.isDown();
}
@ -58,8 +58,15 @@ public class KeyBinding implements KeyEventHandler, InputReadyListener {
@Override
public void receive(KeyEvent event)
{
boolean nowDown = keystroke.isDown();
boolean trigger = false;
trigger |= (edge == Edge.FALLING && (!wasDown && nowDown));
trigger |= (edge == Edge.RISING && (wasDown && !nowDown));
wasDown = nowDown;
// run handler when event was met
if (keystroke.tryTrigger(edge)) {
if (trigger) {
handler.run();
}
}
@ -68,7 +75,7 @@ public class KeyBinding implements KeyEventHandler, InputReadyListener {
@Override
public void onInputReady()
{
keystroke.poll();
wasDown = keystroke.isDown();
}
}

@ -12,7 +12,7 @@ import org.lwjgl.input.Keyboard;
*
* @author MightyPork
*/
public class KeyStroke implements Pollable {
public class KeyStroke { //implements Pollable
public static enum Edge
{
@ -22,7 +22,7 @@ public class KeyStroke implements Pollable {
private int mod;
private int key;
private boolean wasDown;
// private boolean wasDown;
/**
@ -64,41 +64,41 @@ public class KeyStroke implements Pollable {
{
this.key = key;
this.mod = mod_mask | Keys.keyToMod(key); // for mods alone
this.wasDown = (InputSystem.isReady() ? isDown() : false);
// this.wasDown = (InputSystem.isReady() ? isDown() : false);
}
/**
* Set current state as the last state (ignore it on next trigger event)
*/
@Override
public void poll()
{
wasDown = isDown();
}
public boolean tryTrigger(Edge edge)
{
final boolean down = isDown() && !wasDown;
final boolean up = !isDown() && wasDown;
boolean retval = false;
switch (edge) {
case FALLING:
retval = !wasDown && down;
break;
case RISING:
retval = wasDown && up;
break;
}
wasDown = isDown();
return retval;
}
// /**
// * Set current state as the last state (ignore it on next trigger event)
// */
// @Override
// public void poll()
// {
// wasDown = isDown();
// }
// public boolean tryTrigger(Edge edge)
// {
// final boolean down = isDown() && !wasDown;
// final boolean up = !isDown() && wasDown;
//
// boolean retval = false;
//
// switch (edge) {
// case FALLING:
// retval = !wasDown && down;
// break;
//
// case RISING:
// retval = wasDown && up;
// break;
// }
//
// wasDown = isDown();
//
// return retval;
// }
public String toDataString()

@ -246,7 +246,10 @@ public class DisplaySystem extends AppModule implements RectBound {
getEventBus().send(new ViewportChangeEvent(getSize()));
}
if (fullscreenSwitchRequested) doSwitchFullscreen();
if (fullscreenSwitchRequested) {
fullscreenSwitchRequested = false;
doSwitchFullscreen();
}
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

@ -35,7 +35,7 @@ public class TaskTakeScreenshot implements Runnable {
File file;
int index = 0;
while (true) {
file = new File(WorkDir.getDir("screenshots"), fname + (index > 0 ? "-" + index : "") + ".png");
file = new File(WorkDir.getDir("_screenshot_dir"), fname + (index > 0 ? "-" + index : "") + ".png");
if (!file.exists()) break;
index++;
}

@ -13,9 +13,7 @@ import mightypork.gamecore.util.objects.Convert;
/**
* Property manager with advanced formatting and value checking.<br>
* Methods starting with put are for filling. Most of the others are shortcuts
* to getters.
* Property manager with advanced formatting and value checking.
*
* @author MightyPork
*/
@ -83,10 +81,9 @@ public class PropertyManager {
/** put newline before entry comments */
private boolean cfgNewlineBeforeComments = true;
/** Put newline between sections. */
private boolean cfgSeparateSections = true;
/** Force save, even if nothing changed (used to save changed comments) */
private boolean cfgForceSave;
private final File file;
private String fileComment = "";
@ -116,7 +113,6 @@ public class PropertyManager {
*/
public void load()
{
boolean needsSave = false;
if (!file.getParentFile().mkdirs()) {
if (!file.getParentFile().exists()) {
throw new RuntimeException("Cound not create config file.");
@ -126,7 +122,6 @@ public class PropertyManager {
try(FileInputStream fis = new FileInputStream(file)) {
props.load(fis);
} catch (final IOException e) {
needsSave = true;
props = new SortedProperties();
}
@ -144,7 +139,6 @@ public class PropertyManager {
props.remove(entry.getKey());
props.setProperty(entry.getValue(), pr);
needsSave = true;
}
// validate entries one by one, replace with default when needed
@ -161,8 +155,6 @@ public class PropertyManager {
if (propOrig == null || !entry.toString().equals(propOrig)) {
props.setProperty(entry.getKey(), entry.toString());
needsSave = true;
}
}
@ -170,15 +162,9 @@ public class PropertyManager {
for (final String propname : props.keySet().toArray(new String[props.size()])) {
if (!keyList.contains(propname)) {
props.remove(propname);
needsSave = true;
}
}
// save if needed
if (needsSave || cfgForceSave) {
save();
}
renameTable.clear();
}
@ -211,22 +197,13 @@ public class PropertyManager {
}
/**
* @param forceSave save even if unchanged.
*/
public void cfgForceSave(boolean forceSave)
{
this.cfgForceSave = forceSave;
}
/**
* Get a property entry (rarely used)
*
* @param k key
* @return the entry
*/
private Property<?> getProperty(String k)
public Property<?> getProperty(String k)
{
try {
return entries.get(k);
@ -356,7 +333,6 @@ public class PropertyManager {
/**
* Add a range property
*
* @param n key
* @param prop property to put
*/
public <T> void putProperty(Property<T> prop)

@ -11,15 +11,15 @@ public final class Const {
// STRINGS
public static final int VERSION = 4;
public static final String APP_NAME = "Rogue";
public static final String TITLEBAR = APP_NAME + " v." + VERSION;
public static final String APP_NAME = "Rogue: Savage Rats";
public static final String TITLEBAR = APP_NAME + ", v" + VERSION;
// AUDIO
public static final int FPS_RENDER = 120; // max
// INITIAL WINDOW SIZE
public static final int WINDOW_W = 1024;
public static final int WINDOW_H = 768;
public static final int WINDOW_W = 640;
public static final int WINDOW_H = 480;
/** Render dark in unknown area & skip invisible stuff */
public static boolean RENDER_UFOG = true;

@ -43,8 +43,8 @@ public final class RogueApp extends BaseApp {
opt().addKeys(new RogueKeys());
opt().addConfig(new RogueConfig());
opt().setConfigFile(this, "config.ini", "Rogue config file");
opt().setLogOptions("/", "runtime", 5, java.util.logging.Level.ALL);
opt().setConfigFile("config.ini", "Rogue config file");
opt().setLogOptions("logs", "runtime", 5, java.util.logging.Level.ALL);
}

@ -9,30 +9,37 @@ import mightypork.gamecore.Config.KeySetup;
public class RogueKeys implements Config.KeySetup {
@Override
public void addKeys(Config.KeyOpts keys)
public void addKeys(KeyOpts keys)
{
keys.add("global.quit", "CTRL+Q");
keys.add("global.menu", "CTRL+M");
keys.add("global.screenshot", "F2");
keys.add("global.fullscreen", "F11");
keys.add("global.fps_meter", "F3");
keys.add("general.back", "ESC"); // leave a dialog / screen
keys.add("general.cancel", "ESC"); // cancel operation
keys.add("general.confirm", "ENTER"); // confirm default option
keys.add("general.yes", "Y"); // answer YES
keys.add("general.no", "N"); // answer NO
keys.add("global.quit", "CTRL+Q", "Quit the game");
keys.add("global.menu", "CTRL+M", "Direct jump to main menu");
keys.add("global.screenshot", "F2", "Take screenshot (save into working directory)");
keys.add("global.fullscreen", "F11", "Toggle fullscreen");
keys.add("global.fps_meter", "F3", "Toggle FPS meter overlay");
keys.add("general.back", "ESC", "Leave a dialog or screen");
keys.add("general.cancel", "ESC", "\"Cancel\" option in dialogs");
keys.add("general.confirm", "ENTER", "\"Confirm\" option in dialogs");
keys.add("general.yes", "Y", "\"Yes\" option in dialogs");
keys.add("general.no", "N", "\"No\" option in dialogs");
keys.add("game.quit", "ESC", "Quit to menu");
keys.add("game.save", "CTRL+S", "Save to file");
keys.add("game.load", "CTRL+L", "Load from file");
keys.add("game.zoom", "Z", "Toggle zoom");
keys.add("game.minimap", "M", "Toggle minimap");
keys.add("game.eat", "E", "Eat smallest food item");
keys.add("game.drop", "D", "Drop last picked item");
keys.add("game.inventory", "I", "Toggle inventory view");
keys.add("game.pause", "P", "Pause the game");
keys.add("game.cheat.xray", "CTRL+SHIFT+X", "Cheat to see unexplored tiles");
keys.add("game.quit", "ESC");
keys.add("game.save", "CTRL+S");
keys.add("game.load", "CTRL+L");
keys.add("game.zoom", "Z");
keys.add("game.minimap", "M");
keys.add("game.eat", "E");
keys.add("game.drop", "D");
keys.add("game.inventory", "I");
keys.add("game.pause", "P");
keys.add("game.pause2", "SPACE");
keys.add("game.cheat.xray", "CTRL+SHIFT+X");
keys.add("game.inv.use", "E", "Use (eat or equip) the selected item");
keys.add("game.inv.drop", "D", "Drop the selected item");
keys.add("game.inv.move.left", "LEFT", "Move inventory cursor left");
keys.add("game.inv.move.right", "RIGHT", "Move inventory cursor right");
keys.add("game.inv.move.up", "UP", "Move inventory cursor up");
keys.add("game.inv.move.down", "DOWN", "Move inventory cursor down");
}
}

@ -1,6 +1,7 @@
package mightypork.rogue.screens.game;
import mightypork.gamecore.Config;
import mightypork.gamecore.gui.AlignX;
import mightypork.gamecore.gui.components.layout.ConstraintLayout;
import mightypork.gamecore.gui.components.layout.FlowColumnLayout;
@ -28,12 +29,16 @@ public class InventoryLayer extends ScreenLayer {
private static final int SLOT_COUNT = 8;
private static final int SLOT_ROW = 4;
private final KeyStroke keyUse = Config.getKey("game.inv.use");
private final KeyStroke keyDrop = Config.getKey("game.inv.drop");
private final KeyStroke keyClose = Config.getKey("general.back");
private final StringProvider contextStrProv = new StringProvider() {
@Override
public String getString()
{
String s = "ESC-close";
String s = keyClose+"-close";
final int selected = getSelectedSlot();
if (selected != -1) {
@ -42,14 +47,14 @@ public class InventoryLayer extends ScreenLayer {
final Item itm = pl.getInventory().getItem(selected);
if (itm != null && !itm.isEmpty()) {
s = "D-drop," + s;
s = keyDrop+"-drop," + s;
if (itm.getType() == ItemType.FOOD) {
s = "E-eat," + s;
s = keyUse+"-eat," + s;
}
if (itm.getType() == ItemType.WEAPON) {
s = "E-equip," + s;
s = keyUse+"-equip," + s;
}
}
} else {
@ -140,18 +145,20 @@ public class InventoryLayer extends ScreenLayer {
gl.put(txp2, pos, 0, 1, 1);
txp2.setVPaddingPercent(25);
bindKey(new KeyStroke(Keys.ESCAPE), Edge.RISING, new Runnable() {
bindKey(keyClose, Edge.RISING, new Runnable() {
@Override
public void run()
{
System.out.println("test1");
if (isEnabled()) {
System.out.println("test2");
screen.actionToggleInv.run();
}
}
});
bindKey(new KeyStroke(Keys.E), Edge.RISING, new Runnable() {
bindKey(keyUse, Edge.RISING, new Runnable() {
@Override
public void run()
@ -160,39 +167,11 @@ public class InventoryLayer extends ScreenLayer {
if (WorldProvider.get().getPlayer().isDead()) return;
final int selected = getSelectedSlot();
if (selected != -1) {
final World world = WorldProvider.get().getWorld();
final PlayerFacade pl = WorldProvider.get().getPlayer();
final Item itm = pl.getInventory().getItem(selected);
if (itm != null && !itm.isEmpty()) {
final ItemType type = itm.getType();
if (type == ItemType.FOOD) {
if (pl.eatFood(itm)) {
pl.getInventory().clean();
}
} else if (type == ItemType.WEAPON) {
if (pl.getSelectedWeaponIndex() == selected) {
pl.selectWeapon(-1);
} else {
pl.selectWeapon(selected);
}
world.getConsole().msgEquipWeapon(pl.getSelectedWeapon());
}
}
}
useSelectedItem();
}
});
bindKey(new KeyStroke(Keys.D), Edge.RISING, new Runnable() {
bindKey(keyDrop, Edge.RISING, new Runnable() {
@Override
public void run()
@ -210,10 +189,44 @@ public class InventoryLayer extends ScreenLayer {
}
protected void useSelectedItem()
{
final int selected = getSelectedSlot();
if (selected != -1) {
final World world = WorldProvider.get().getWorld();
final PlayerFacade pl = WorldProvider.get().getPlayer();
final Item itm = pl.getInventory().getItem(selected);
if (itm != null && !itm.isEmpty()) {
final ItemType type = itm.getType();
if (type == ItemType.FOOD) {
if (pl.eatFood(itm)) {
pl.getInventory().clean();
}
} else if (type == ItemType.WEAPON) {
if (pl.getSelectedWeaponIndex() == selected) {
pl.selectWeapon(-1);
} else {
pl.selectWeapon(selected);
}
world.getConsole().msgEquipWeapon(pl.getSelectedWeapon());
}
}
}
}
private void setupGridWalkKeys()
{
bindKey(new KeyStroke(Keys.LEFT), Edge.RISING, new Runnable() {
bindKey(Config.getKey("game.inv.move.left"), Edge.RISING, new Runnable() {
@Override
public void run()
@ -230,7 +243,7 @@ public class InventoryLayer extends ScreenLayer {
};
});
bindKey(new KeyStroke(Keys.RIGHT), Edge.RISING, new Runnable() {
bindKey(Config.getKey("game.inv.move.right"), Edge.RISING, new Runnable() {
@Override
public void run()
@ -247,7 +260,7 @@ public class InventoryLayer extends ScreenLayer {
};
});
bindKey(new KeyStroke(Keys.UP), Edge.RISING, new Runnable() {
bindKey(Config.getKey("game.inv.move.up"), Edge.RISING, new Runnable() {
@Override
public void run()
@ -264,7 +277,7 @@ public class InventoryLayer extends ScreenLayer {
};
});
bindKey(new KeyStroke(Keys.DOWN), Edge.RISING, new Runnable() {
bindKey(Config.getKey("game.inv.move.down"), Edge.RISING, new Runnable() {
@Override
public void run()

@ -64,9 +64,11 @@ public class ScreenGame extends RogueScreen implements PlayerDeathHandler {
public Action actionToggleInv = new Action() {
@Override
public void execute()
{
System.out.println("Toggle inv action");
setState(getState() == GScrState.INV ? GScrState.WORLD : GScrState.INV);
}
};
@ -242,8 +244,6 @@ public class ScreenGame extends RogueScreen implements PlayerDeathHandler {
addLayer(worldLayer = new WorldLayer(this));
addLayer(askSaveLayer = new AskSaveLayer(this));
//pause key
bindKey(Config.getKey("game.pause2"), Edge.RISING, actionTogglePause);
bindKey(Config.getKey("game.pause"), Edge.RISING, actionTogglePause);
bindKey(Config.getKey("game.inventory"), Edge.RISING, actionToggleInv);
@ -268,7 +268,7 @@ public class ScreenGame extends RogueScreen implements PlayerDeathHandler {
worldActions.add(actionSave);
worldActions.add(actionLoad);
worldActions.add(actionMenu);
worldActions.add(actionQuit);
// worldActions.add(actionQuit);
worldActions.add(actionDropLastPickedItem);
worldActions.setEnabled(true);

Loading…
Cancel
Save