diff --git a/.classpath b/.classpath
index 486b09c..628a8ab 100644
--- a/.classpath
+++ b/.classpath
@@ -2,16 +2,35 @@
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/README.md b/README.md
index 9d66a63..7f5350a 100644
--- a/README.md
+++ b/README.md
@@ -11,21 +11,18 @@ Goals
Features
--------
-**SUBJECT TO CHANGE!**
-
- Randomly generated floors
-- Hybrid turn-based gameplay (lower and upper time limit)
-- Automatic turn-based combat
-- Health, hunger, experience meters; levels
-- Entities with basic AI (Monsters)
-- Items, weapons, armor
-- Treasure chests
-- Potions
-- Inventory system with 12 slots (+ armor)
+- Hybrid turn-based gameplay
+- Stats and leveling
+- Monsters
+- Collectable items
+- Potions, food
+- Simple inventory system
Used libraries
--------------
-- libGDX
-- mini2Dx
\ No newline at end of file
+- Slick2D
+- NiftyGUI
+- LWJGL
\ No newline at end of file
diff --git a/lib/OpenAL32.dll b/lib/OpenAL32.dll
new file mode 100644
index 0000000..6dd2600
Binary files /dev/null and b/lib/OpenAL32.dll differ
diff --git a/lib/OpenAL64.dll b/lib/OpenAL64.dll
new file mode 100644
index 0000000..00c98c0
Binary files /dev/null and b/lib/OpenAL64.dll differ
diff --git a/lib/gdx-backend-lwjgl-natives.jar b/lib/gdx-backend-lwjgl-natives.jar
deleted file mode 100644
index f7f2119..0000000
Binary files a/lib/gdx-backend-lwjgl-natives.jar and /dev/null differ
diff --git a/lib/gdx-backend-lwjgl-sources.jar b/lib/gdx-backend-lwjgl-sources.jar
deleted file mode 100644
index f1182f0..0000000
Binary files a/lib/gdx-backend-lwjgl-sources.jar and /dev/null differ
diff --git a/lib/gdx-backend-lwjgl.jar b/lib/gdx-backend-lwjgl.jar
deleted file mode 100644
index f6de13d..0000000
Binary files a/lib/gdx-backend-lwjgl.jar and /dev/null differ
diff --git a/lib/gdx-freetype-natives.jar b/lib/gdx-freetype-natives.jar
deleted file mode 100644
index 8cb1a79..0000000
Binary files a/lib/gdx-freetype-natives.jar and /dev/null differ
diff --git a/lib/gdx-freetype-sources.jar b/lib/gdx-freetype-sources.jar
deleted file mode 100644
index 9d19032..0000000
Binary files a/lib/gdx-freetype-sources.jar and /dev/null differ
diff --git a/lib/gdx-freetype.jar b/lib/gdx-freetype.jar
deleted file mode 100644
index 7df6d4b..0000000
Binary files a/lib/gdx-freetype.jar and /dev/null differ
diff --git a/lib/gdx-natives.jar b/lib/gdx-natives.jar
deleted file mode 100644
index 51953b1..0000000
Binary files a/lib/gdx-natives.jar and /dev/null differ
diff --git a/lib/gdx-sources.zip b/lib/gdx-sources.zip
deleted file mode 100644
index 1a88c12..0000000
Binary files a/lib/gdx-sources.zip and /dev/null differ
diff --git a/lib/gdx.jar b/lib/gdx.jar
deleted file mode 100644
index 6e9560a..0000000
Binary files a/lib/gdx.jar and /dev/null differ
diff --git a/lib/jinput-dx8.dll b/lib/jinput-dx8.dll
new file mode 100644
index 0000000..6d27ad5
Binary files /dev/null and b/lib/jinput-dx8.dll differ
diff --git a/lib/jinput-dx8_64.dll b/lib/jinput-dx8_64.dll
new file mode 100644
index 0000000..6730589
Binary files /dev/null and b/lib/jinput-dx8_64.dll differ
diff --git a/lib/jinput-raw.dll b/lib/jinput-raw.dll
new file mode 100644
index 0000000..ce1d162
Binary files /dev/null and b/lib/jinput-raw.dll differ
diff --git a/lib/jinput-raw_64.dll b/lib/jinput-raw_64.dll
new file mode 100644
index 0000000..3d2b3ad
Binary files /dev/null and b/lib/jinput-raw_64.dll differ
diff --git a/lib/jinput.jar b/lib/jinput.jar
new file mode 100644
index 0000000..7c2b6b0
Binary files /dev/null and b/lib/jinput.jar differ
diff --git a/lib/jogg-0.0.7.jar b/lib/jogg-0.0.7.jar
new file mode 100644
index 0000000..ecb0260
Binary files /dev/null and b/lib/jogg-0.0.7.jar differ
diff --git a/lib/jorbis-0.0.15.jar b/lib/jorbis-0.0.15.jar
new file mode 100644
index 0000000..4cf51f9
Binary files /dev/null and b/lib/jorbis-0.0.15.jar differ
diff --git a/lib/libjinput-linux.so b/lib/libjinput-linux.so
new file mode 100644
index 0000000..3cdc439
Binary files /dev/null and b/lib/libjinput-linux.so differ
diff --git a/lib/libjinput-linux64.so b/lib/libjinput-linux64.so
new file mode 100644
index 0000000..de1ee5f
Binary files /dev/null and b/lib/libjinput-linux64.so differ
diff --git a/lib/libjinput-osx.jnilib b/lib/libjinput-osx.jnilib
new file mode 100644
index 0000000..59a3eab
Binary files /dev/null and b/lib/libjinput-osx.jnilib differ
diff --git a/lib/liblwjgl.jnilib b/lib/liblwjgl.jnilib
new file mode 100644
index 0000000..cbb5b4c
Binary files /dev/null and b/lib/liblwjgl.jnilib differ
diff --git a/lib/liblwjgl.so b/lib/liblwjgl.so
new file mode 100644
index 0000000..5a02874
Binary files /dev/null and b/lib/liblwjgl.so differ
diff --git a/lib/liblwjgl64.so b/lib/liblwjgl64.so
new file mode 100644
index 0000000..4572589
Binary files /dev/null and b/lib/liblwjgl64.so differ
diff --git a/lib/libopenal.so b/lib/libopenal.so
new file mode 100644
index 0000000..7742faf
Binary files /dev/null and b/lib/libopenal.so differ
diff --git a/lib/libopenal64.so b/lib/libopenal64.so
new file mode 100644
index 0000000..d1e45e5
Binary files /dev/null and b/lib/libopenal64.so differ
diff --git a/lib/lwjgl-source-2.8.4.zip b/lib/lwjgl-source-2.8.4.zip
new file mode 100644
index 0000000..f48fd31
Binary files /dev/null and b/lib/lwjgl-source-2.8.4.zip differ
diff --git a/lib/lwjgl.dll b/lib/lwjgl.dll
new file mode 100644
index 0000000..6819404
Binary files /dev/null and b/lib/lwjgl.dll differ
diff --git a/lib/lwjgl.jar b/lib/lwjgl.jar
new file mode 100644
index 0000000..a0fb56d
Binary files /dev/null and b/lib/lwjgl.jar differ
diff --git a/lib/lwjgl64.dll b/lib/lwjgl64.dll
new file mode 100644
index 0000000..e66ab2a
Binary files /dev/null and b/lib/lwjgl64.dll differ
diff --git a/lib/lwjgl_util.jar b/lib/lwjgl_util.jar
new file mode 100644
index 0000000..9973b24
Binary files /dev/null and b/lib/lwjgl_util.jar differ
diff --git a/lib/mini2Dx-core-source.zip b/lib/mini2Dx-core-source.zip
deleted file mode 100644
index 204c444..0000000
Binary files a/lib/mini2Dx-core-source.zip and /dev/null differ
diff --git a/lib/mini2Dx-core.jar b/lib/mini2Dx-core.jar
deleted file mode 100644
index 68ca5e7..0000000
Binary files a/lib/mini2Dx-core.jar and /dev/null differ
diff --git a/lib/mini2Dx-dependency-injection-desktop-source.zip b/lib/mini2Dx-dependency-injection-desktop-source.zip
deleted file mode 100644
index 7de2dd5..0000000
Binary files a/lib/mini2Dx-dependency-injection-desktop-source.zip and /dev/null differ
diff --git a/lib/mini2Dx-dependency-injection-desktop.jar b/lib/mini2Dx-dependency-injection-desktop.jar
deleted file mode 100644
index 0e0101e..0000000
Binary files a/lib/mini2Dx-dependency-injection-desktop.jar and /dev/null differ
diff --git a/lib/mini2Dx-dependency-injection-source.zip b/lib/mini2Dx-dependency-injection-source.zip
deleted file mode 100644
index e3a0da9..0000000
Binary files a/lib/mini2Dx-dependency-injection-source.zip and /dev/null differ
diff --git a/lib/mini2Dx-dependency-injection.jar b/lib/mini2Dx-dependency-injection.jar
deleted file mode 100644
index e870ced..0000000
Binary files a/lib/mini2Dx-dependency-injection.jar and /dev/null differ
diff --git a/lib/mini2Dx-ecs-source.zip b/lib/mini2Dx-ecs-source.zip
deleted file mode 100644
index b8de3a9..0000000
Binary files a/lib/mini2Dx-ecs-source.zip and /dev/null differ
diff --git a/lib/mini2Dx-ecs.jar b/lib/mini2Dx-ecs.jar
deleted file mode 100644
index 91c5d54..0000000
Binary files a/lib/mini2Dx-ecs.jar and /dev/null differ
diff --git a/lib/mini2Dx-tiled-source.zip b/lib/mini2Dx-tiled-source.zip
deleted file mode 100644
index c0b8e5e..0000000
Binary files a/lib/mini2Dx-tiled-source.zip and /dev/null differ
diff --git a/lib/mini2Dx-tiled.jar b/lib/mini2Dx-tiled.jar
deleted file mode 100644
index 378c834..0000000
Binary files a/lib/mini2Dx-tiled.jar and /dev/null differ
diff --git a/lib/slick-util-src.zip b/lib/slick-util-src.zip
new file mode 100644
index 0000000..7ca6790
Binary files /dev/null and b/lib/slick-util-src.zip differ
diff --git a/lib/slick-util.jar b/lib/slick-util.jar
new file mode 100644
index 0000000..86a64a7
Binary files /dev/null and b/lib/slick-util.jar differ
diff --git a/src/mightypork/rogue/App.java b/src/mightypork/rogue/App.java
new file mode 100644
index 0000000..b3f18c6
--- /dev/null
+++ b/src/mightypork/rogue/App.java
@@ -0,0 +1,417 @@
+package mightypork.rogue;
+
+
+import static org.lwjgl.opengl.GL11.*;
+
+import java.io.File;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileLock;
+
+import javax.swing.JOptionPane;
+
+import mightypork.rogue.input.Keys;
+import mightypork.rogue.screens.ScreenSplash;
+import mightypork.rogue.sounds.SoundManager;
+import mightypork.rogue.threads.ThreadSaveScreenshot;
+import mightypork.rogue.threads.ThreadScreenshotTrigger;
+import mightypork.utils.logging.Log;
+import mightypork.utils.logging.LogInstance;
+import mightypork.utils.math.coord.Coord;
+import mightypork.utils.time.TimerDelta;
+import mightypork.utils.time.TimerInterpolating;
+
+import org.lwjgl.BufferUtils;
+import org.lwjgl.LWJGLException;
+import org.lwjgl.input.Keyboard;
+import org.lwjgl.input.Mouse;
+import org.lwjgl.openal.AL;
+import org.lwjgl.opengl.Display;
+import org.lwjgl.opengl.DisplayMode;
+
+
+public class App {
+
+ /** instance */
+ public static App inst;
+ /** Current delta time (secs since last render) */
+ public static double currentDelta = 0;
+
+ private static DisplayMode windowDisplayMode = null;
+
+ /** current screen */
+ public static Screen screen = null;
+
+ /** Flag that screenshot is scheduled to be taken next loop */
+ public static boolean scheduledScreenshot = false;
+
+
+ private static boolean lockInstance()
+ {
+ if (Config.SINGLE_INSTANCE == false) return true; // bypass lock
+
+ final File lockFile = new File(Paths.WORKDIR, ".lock");
+ try {
+ final RandomAccessFile randomAccessFile = new RandomAccessFile(lockFile, "rw");
+ final FileLock fileLock = randomAccessFile.getChannel().tryLock();
+ if (fileLock != null) {
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+
+ @Override
+ public void run()
+ {
+ try {
+ fileLock.release();
+ randomAccessFile.close();
+ lockFile.delete();
+ } catch (Exception e) {
+ System.out.println("Unable to remove lock file.");
+ e.printStackTrace();
+ }
+ }
+ });
+ return true;
+ }
+ } catch (Exception e) {
+ System.out.println("Unable to create and/or lock file.");
+ e.printStackTrace();
+ }
+ return false;
+ }
+
+
+ /**
+ * Is if FS
+ *
+ * @return is in fs
+ */
+ public static boolean isFullscreen()
+ {
+ return Display.isFullscreen();
+ }
+
+
+ /**
+ * @param args
+ */
+ public static void main(String[] args)
+ {
+ Thread.setDefaultUncaughtExceptionHandler(new CrashHandler());
+
+ inst = new App();
+
+ try {
+ inst.start();
+ } catch (Throwable t) {
+ onCrash(t);
+ }
+
+ }
+
+
+ /**
+ * Show crash report dialog with error stack trace.
+ *
+ * @param error
+ */
+ public static void onCrash(Throwable error)
+ {
+ Log.e("The game has crashed.");
+
+ Log.e(error);
+
+ try {
+ inst.deinit();
+ } catch (Throwable t) {
+ // ignore
+ }
+ }
+
+
+ /**
+ * Quit to OS
+ */
+ public void exit()
+ {
+ deinit();
+ System.exit(0);
+ }
+
+
+ /**
+ * Get current screen
+ *
+ * @return screen
+ */
+ public Screen getScreen()
+ {
+ return screen;
+ }
+
+
+ /**
+ * Get screen size
+ *
+ * @return size
+ */
+ public Coord getSize()
+ {
+ return new Coord(Display.getWidth(), Display.getHeight());
+ }
+
+
+ private void init() throws LWJGLException
+ {
+ // initialize main logger
+ LogInstance li = Log.create("runtime", Paths.LOGS, 10);
+ li.enable(Config.LOGGING_ENABLED);
+ li.enableSysout(Config.LOG_TO_STDOUT);
+
+ // initialize display
+ Display.setDisplayMode(windowDisplayMode = new DisplayMode(Const.WINDOW_SIZE_X, Const.WINDOW_SIZE_Y));
+ Display.setResizable(true);
+ Display.setVSyncEnabled(true);
+ Display.setTitle(Const.TITLEBAR);
+ Display.create();
+
+ if (Config.START_IN_FS) {
+ switchFullscreen();
+ Display.update();
+ }
+
+ // initialize inputs
+ Mouse.create();
+ Keyboard.create();
+ Keyboard.enableRepeatEvents(false);
+
+ // initialize sound system
+ SoundManager.get().setListener(Const.LISTENER_POS);
+ SoundManager.get().setMasterVolume(1F);
+
+ // start async screenshot trigger listener
+ (new ThreadScreenshotTrigger()).start();
+ }
+
+
+ private void start() throws LWJGLException
+ {
+
+ if (!lockInstance()) {
+ System.out.println("Working directory is locked.\nOnly one instance can run at a time.");
+
+ //@formatter:off
+ JOptionPane.showMessageDialog(
+ null,
+ "The game is already running.",
+ "Instance error",
+ JOptionPane.ERROR_MESSAGE
+ );
+ //@formatter:on
+
+ exit();
+ return;
+ }
+
+ init();
+ mainLoop();
+ deinit();
+ }
+
+
+ private void deinit()
+ {
+ Display.destroy();
+ Mouse.destroy();
+ Keyboard.destroy();
+ SoundManager.get().destroy();
+ AL.destroy();
+ }
+
+ /** timer */
+ private TimerDelta timerRender;
+ private TimerInterpolating timerGui;
+
+ private int timerAfterResize = 0;
+
+
+ private void mainLoop()
+ {
+ screen = new ScreenSplash();
+
+ screen.init();
+
+ timerRender = new TimerDelta();
+ timerGui = new TimerInterpolating(Const.FPS_GUI_UPDATE);
+
+ while (!Display.isCloseRequested()) {
+ glLoadIdentity();
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ timerGui.sync();
+
+ int ticks = timerGui.getSkipped();
+
+ if (ticks >= 1) {
+ screen.updateGui();
+ timerGui.startNewFrame();
+ }
+
+ currentDelta = timerRender.getDelta();
+
+ // RENDER
+ screen.render(currentDelta);
+ SoundManager.get().update(currentDelta);
+
+ Display.update();
+
+ if (scheduledScreenshot) {
+ takeScreenshot();
+ scheduledScreenshot = false;
+ }
+
+ if (Keys.justPressed(Keyboard.KEY_F11)) {
+ Log.f2("F11, toggle fullscreen.");
+ switchFullscreen();
+ screen.onFullscreenChange();
+ Keys.destroyChangeState(Keyboard.KEY_F11);
+ }
+
+ if (Keyboard.isKeyDown(Keyboard.KEY_LCONTROL)) {
+ if (Keyboard.isKeyDown(Keyboard.KEY_Q)) {
+ Log.f2("Ctrl+Q, force quit.");
+ Keys.destroyChangeState(Keyboard.KEY_Q);
+ exit();
+ return;
+ }
+
+// if (Keyboard.isKeyDown(Keyboard.KEY_M)) {
+// Log.f2("Ctrl+M, go to main menu.");
+// Keys.destroyChangeState(Keyboard.KEY_M);
+// replaceScreen(new ScreenMenuMain());
+// }
+
+ if (Keyboard.isKeyDown(Keyboard.KEY_F)) {
+ Log.f2("Ctrl+F, switch fullscreen.");
+ Keys.destroyChangeState(Keyboard.KEY_F);
+ switchFullscreen();
+ screen.onFullscreenChange();
+ }
+ }
+
+ if (Display.wasResized()) {
+ screen.onWindowResize();
+ timerAfterResize = 0;
+ } else { // ensure screen has even size
+ timerAfterResize++;
+ if (timerAfterResize > Const.FPS_GUI_UPDATE * 0.3) {
+ timerAfterResize = 0;
+ int x = Display.getX();
+ int y = Display.getY();
+
+ int w = Display.getWidth();
+ int h = Display.getHeight();
+ if (w % 2 != 0 || h % 2 != 0) {
+ try {
+ Display.setDisplayMode(windowDisplayMode = new DisplayMode(w - w % 2, h - h % 2));
+ screen.onWindowResize();
+ Display.setLocation(x, y);
+ } catch (LWJGLException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ try {
+ Display.sync(Const.FPS_RENDER);
+ } catch (Throwable t) {
+ Log.e("Your graphics card driver does not support fullscreen properly.", t);
+
+ try {
+ Display.setDisplayMode(windowDisplayMode);
+ } catch (LWJGLException e) {
+ Log.e("Error going back from corrupted fullscreen.");
+ onCrash(e);
+ }
+ }
+ }
+ }
+
+
+// UPDATE LOOP END
+
+ /**
+ * Do take a screenshot
+ */
+ public void takeScreenshot()
+ {
+ //Effects.play("gui.screenshot");
+
+ glReadBuffer(GL_FRONT);
+ int width = Display.getDisplayMode().getWidth();
+ int height = Display.getDisplayMode().getHeight();
+ int bpp = 4; // Assuming a 32-bit display with a byte each for red, green, blue, and alpha.
+ ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * bpp);
+ glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+
+ (new ThreadSaveScreenshot(buffer, width, height, bpp)).start();
+ }
+
+
+ /**
+ * Replace screen
+ *
+ * @param newScreen new screen
+ */
+ public void replaceScreen(Screen newScreen)
+ {
+ screen = newScreen;
+ screen.init();
+ }
+
+
+ /**
+ * Replace screen, don't init it
+ *
+ * @param newScreen new screen
+ */
+ public void replaceScreenNoInit(Screen newScreen)
+ {
+ screen = newScreen;
+ }
+
+
+ /**
+ * Toggle FS if possible
+ */
+ public void switchFullscreen()
+ {
+ try {
+ if (!Display.isFullscreen()) {
+ Log.f3("Entering fullscreen.");
+ // save window resize
+ windowDisplayMode = new DisplayMode(Display.getWidth(), Display.getHeight());
+
+ Display.setDisplayMode(Display.getDesktopDisplayMode());
+ Display.setFullscreen(true);
+ Display.update();
+//
+//
+// DisplayMode mode = Display.getDesktopDisplayMode(); //findDisplayMode(WIDTH, HEIGHT);
+// Display.setDisplayModeAndFullscreen(mode);
+ } else {
+ Log.f3("Leaving fullscreen.");
+ Display.setDisplayMode(windowDisplayMode);
+ Display.update();
+ }
+ } catch (Throwable t) {
+ Log.e("Failed to toggle fullscreen mode.", t);
+ try {
+ Display.setDisplayMode(windowDisplayMode);
+ Display.update();
+ } catch (Throwable t1) {
+ onCrash(t1);
+ }
+ }
+ }
+}
diff --git a/src/mightypork/rogue/Config.java b/src/mightypork/rogue/Config.java
new file mode 100644
index 0000000..deaf02a
--- /dev/null
+++ b/src/mightypork/rogue/Config.java
@@ -0,0 +1,81 @@
+package mightypork.rogue;
+
+
+import mightypork.utils.files.PropertyManager;
+import mightypork.utils.logging.Log;
+
+
+/**
+ * Main Config class
+ *
+ * @author MightyPork
+ */
+public class Config {
+
+ private static PropertyManager mgr;
+
+ // opts
+ public static final int def_LAST_RUN_VERSION = 0;
+ public static int LAST_RUN_VERSION;
+
+ public static final boolean def_START_IN_FS = false;
+ public static boolean START_IN_FS;
+
+ // property keys
+ private static final String PK_LAST_RUN_VERSION = "status.last_run_version";
+ private static final String PK_START_IN_FS = "cfg.start_in_fullscreen";
+
+
+ /**
+ * Prepare config manager and load user settings
+ */
+ public static void init()
+ {
+ Log.f2("Initializing configuration manager.");
+
+ String comment = Const.APP_NAME + " config file";
+
+ mgr = new PropertyManager(Paths.CONFIG, comment);
+
+ mgr.cfgNewlineBeforeComments(true);
+ mgr.cfgSeparateSections(true);
+
+ mgr.putInteger(PK_LAST_RUN_VERSION, def_LAST_RUN_VERSION);
+ mgr.putBoolean(PK_START_IN_FS, def_START_IN_FS);
+
+ load(); // load what has been "put"
+ }
+
+
+ /**
+ * Save changed fields to config file
+ */
+ public static void save()
+ {
+ mgr.setValue(PK_LAST_RUN_VERSION, Const.VERSION);
+ mgr.setValue(PK_START_IN_FS, START_IN_FS);
+
+ mgr.apply();
+ }
+
+
+ /**
+ * Load config file and assign values to fields
+ */
+ public static void load()
+ {
+ mgr.apply();
+
+ LAST_RUN_VERSION = mgr.getInteger(PK_LAST_RUN_VERSION);
+ START_IN_FS = mgr.getBoolean(PK_START_IN_FS);
+ }
+
+ // options that can't be configured via config file
+
+ public static boolean LOGGING_ENABLED = true;
+ public static boolean LOG_TO_STDOUT = true;
+ public static boolean SINGLE_INSTANCE = true;
+
+ public static boolean LOG_FONTS = false;
+
+}
diff --git a/src/mightypork/rogue/Const.java b/src/mightypork/rogue/Const.java
new file mode 100644
index 0000000..ca7da92
--- /dev/null
+++ b/src/mightypork/rogue/Const.java
@@ -0,0 +1,29 @@
+package mightypork.rogue;
+
+
+import mightypork.utils.math.coord.Coord;
+
+
+/**
+ * Application constants
+ *
+ * @author MightyPork
+ */
+public class Const {
+
+ // STRINGS
+ public static final int VERSION = 1;
+
+ public static final String APP_NAME = "Rogue";
+ public static final String TITLEBAR = APP_NAME + " v." + VERSION;
+
+ // AUDIO
+ public static final Coord LISTENER_POS = Coord.ZERO;
+
+ public static final int FPS_RENDER = 200; // max
+ public static final long FPS_GUI_UPDATE = 60;
+
+ // INITIAL WINDOW SIZE
+ public static final int WINDOW_SIZE_X = 1024;
+ public static final int WINDOW_SIZE_Y = 768;
+}
diff --git a/src/mightypork/rogue/CrashHandler.java b/src/mightypork/rogue/CrashHandler.java
new file mode 100644
index 0000000..fe9aa55
--- /dev/null
+++ b/src/mightypork/rogue/CrashHandler.java
@@ -0,0 +1,15 @@
+package mightypork.rogue;
+
+
+import java.lang.Thread.UncaughtExceptionHandler;
+
+
+public class CrashHandler implements UncaughtExceptionHandler {
+
+ @Override
+ public void uncaughtException(Thread t, Throwable e)
+ {
+ App.onCrash(e);
+ }
+
+}
diff --git a/src/mightypork/rogue/Paths.java b/src/mightypork/rogue/Paths.java
new file mode 100644
index 0000000..a171181
--- /dev/null
+++ b/src/mightypork/rogue/Paths.java
@@ -0,0 +1,22 @@
+package mightypork.rogue;
+
+
+import java.io.File;
+
+import mightypork.utils.files.OsUtils;
+
+
+public class Paths {
+
+ private static final String APPDIR_NAME = "rogue";
+
+ public static final File WORKDIR = OsUtils.getWorkDir(APPDIR_NAME);
+ public static final File LOGS = OsUtils.getWorkDir(APPDIR_NAME, "logs");
+ public static final File SCREENSHOTS = OsUtils.getWorkDir(APPDIR_NAME, "screenshots");
+ public static final File CONFIG = new File(WORKDIR, "config.ini");
+
+ public static final String DIR_EFFECTS = "res/sounds/effects/";
+ public static final String DIR_MUSIC = "res/sounds/music/";
+ public static final String DIR_LOOPS = "res/sounds/loops/";
+
+}
diff --git a/src/mightypork/rogue/Screen.java b/src/mightypork/rogue/Screen.java
new file mode 100644
index 0000000..e726810
--- /dev/null
+++ b/src/mightypork/rogue/Screen.java
@@ -0,0 +1,200 @@
+package mightypork.rogue;
+
+
+import static org.lwjgl.opengl.GL11.*;
+
+import java.util.Random;
+
+import mightypork.rogue.animations.GUIRenderer;
+import mightypork.rogue.input.InputHandler;
+import mightypork.rogue.input.Keys;
+import mightypork.utils.math.coord.Coord;
+import mightypork.utils.math.coord.Vec;
+
+import org.lwjgl.input.Keyboard;
+import org.lwjgl.input.Mouse;
+
+
+/**
+ * Screen class.
+ * Screen animates 3D world, while contained panels render 2D overlays, process
+ * inputs and run the game logic.
+ *
+ * @author MightyPork
+ */
+public abstract class Screen implements GUIRenderer, InputHandler {
+
+ /** RNG */
+ protected static Random rand = new Random();
+
+
+ /**
+ * handle fullscreen change
+ */
+ @Override
+ public final void onFullscreenChange()
+ {
+ onWindowResize();
+ onViewportChanged();
+ }
+
+
+ protected abstract void onViewportChanged();
+
+
+ /**
+ * handle window resize.
+ */
+ public final void onWindowResize()
+ {
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+
+ Coord s = App.inst.getSize();
+
+ glViewport(0, 0, s.xi(), s.yi());
+
+ glOrtho(0, s.x, 0, s.y, -1000, 1000);
+
+ glMatrixMode(GL_MODELVIEW);
+
+ glLoadIdentity();
+
+ glEnable(GL_BLEND);
+ //glDisable(GL_DEPTH_TEST);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_TEXTURE_2D);
+ }
+
+
+ /**
+ * Initialize screen
+ */
+ public void init()
+ {
+ onWindowResize();
+
+ initScreen();
+
+ // SETUP LIGHTS
+ glDisable(GL_LIGHTING);
+
+ // OTHER SETTINGS
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ glClearDepth(1f);
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LEQUAL);
+
+ glEnable(GL_NORMALIZE);
+
+ glShadeModel(GL_SMOOTH);
+ glDisable(GL_TEXTURE_2D);
+ }
+
+
+ /**
+ * Here you can initialize the screen.
+ */
+ public abstract void initScreen();
+
+
+ /**
+ * Update tick
+ */
+ @Override
+ public final void updateGui()
+ {
+ Mouse.poll();
+ Keyboard.poll();
+ checkInputEvents();
+
+ onGuiUpdate();
+ }
+
+
+ protected abstract void onGuiUpdate();
+
+
+ /**
+ * Render screen
+ *
+ * @param delta delta time (position between two update ticks, to allow
+ * super-smooth animations)
+ */
+ @Override
+ public final void render(double delta)
+ {
+ glPushAttrib(GL_ENABLE_BIT);
+
+ // draw the directly rendered 3D stuff
+ render3D();
+
+ glPopAttrib();
+ }
+
+
+ protected abstract void render3D();
+
+
+ /**
+ * Check input events and process them.
+ */
+ private final void checkInputEvents()
+ {
+ while (Keyboard.next()) {
+ int key = Keyboard.getEventKey();
+ boolean down = Keyboard.getEventKeyState();
+ char c = Keyboard.getEventCharacter();
+ Keys.onKey(key, down);
+ onKey(key, c, down);
+ }
+ while (Mouse.next()) {
+ int button = Mouse.getEventButton();
+ boolean down = Mouse.getEventButtonState();
+ Coord delta = new Coord(Mouse.getEventDX(), Mouse.getEventDY());
+ Coord pos = new Coord(Mouse.getEventX(), Mouse.getEventY());
+ int wheeld = Mouse.getEventDWheel();
+
+ onMouseButton(button, down, wheeld, pos, delta);
+ }
+
+ int xc = Mouse.getX();
+ int yc = Mouse.getY();
+ int xd = Mouse.getDX();
+ int yd = Mouse.getDY();
+ int wd = Mouse.getDWheel();
+
+ if (Math.abs(xd) > 0 || Math.abs(yd) > 0 || Math.abs(wd) > 0) {
+ onMouseMove(new Coord(xc, yc), new Vec(xd, yd), wd);
+ }
+
+ handleKeyStates();
+ }
+
+
+ @Override
+ public abstract void onKey(int key, char c, boolean down);
+
+
+ @Override
+ public abstract void onMouseButton(int button, boolean down, int wheeld, Coord pos, Coord delta);
+
+
+ @Override
+ public abstract void handleKeyStates();
+
+
+ @Override
+ public abstract void onMouseMove(Coord coord, Vec vec, int wd);
+
+
+ /**
+ * Render background 2D (all is ready for rendering)
+ *
+ * @param delta delta time
+ */
+ protected abstract void render2D(double delta);
+
+}
diff --git a/src/mightypork/rogue/animations/EmptyAnimator.java b/src/mightypork/rogue/animations/EmptyAnimator.java
new file mode 100644
index 0000000..feb9f75
--- /dev/null
+++ b/src/mightypork/rogue/animations/EmptyAnimator.java
@@ -0,0 +1,30 @@
+package mightypork.rogue.animations;
+
+
+/**
+ * Empty animation (no effect)
+ *
+ * @author MightyPork
+ */
+public class EmptyAnimator implements GUIRenderer {
+
+ /**
+ * New empty animation
+ */
+ public EmptyAnimator() {}
+
+
+ @Override
+ public void updateGui()
+ {}
+
+
+ @Override
+ public void render(double delta)
+ {}
+
+
+ @Override
+ public void onFullscreenChange()
+ {}
+}
diff --git a/src/mightypork/rogue/animations/GUIRenderer.java b/src/mightypork/rogue/animations/GUIRenderer.java
new file mode 100644
index 0000000..112c5cd
--- /dev/null
+++ b/src/mightypork/rogue/animations/GUIRenderer.java
@@ -0,0 +1,13 @@
+package mightypork.rogue.animations;
+
+
+public interface GUIRenderer {
+
+ public void updateGui();
+
+
+ public void render(double delta);
+
+
+ public void onFullscreenChange();
+}
diff --git a/src/mightypork/rogue/fonts/Align.java b/src/mightypork/rogue/fonts/Align.java
new file mode 100644
index 0000000..171e620
--- /dev/null
+++ b/src/mightypork/rogue/fonts/Align.java
@@ -0,0 +1,21 @@
+package mightypork.rogue.fonts;
+
+
+/**
+ * Alignment
+ *
+ * @author MightyPork
+ */
+@SuppressWarnings("javadoc")
+public class Align {
+
+ public static final int LEFT = -1;
+ public static final int RIGHT = 1;
+ public static final int TOP = 1;
+ public static final int BOTTOM = -1;
+ public static final int UP = 1;
+ public static final int DOWN = -1;
+ public static final int CENTER = 0;
+ public static final int MIDDLE = 0;
+
+}
diff --git a/src/mightypork/rogue/fonts/FontManager.java b/src/mightypork/rogue/fonts/FontManager.java
new file mode 100644
index 0000000..7185479
--- /dev/null
+++ b/src/mightypork/rogue/fonts/FontManager.java
@@ -0,0 +1,317 @@
+package mightypork.rogue.fonts;
+
+
+import java.awt.Font;
+import java.io.InputStream;
+import java.util.HashMap;
+
+import mightypork.rogue.Config;
+import mightypork.utils.logging.Log;
+import mightypork.utils.math.coord.Coord;
+
+import org.newdawn.slick.util.ResourceLoader;
+
+
+/**
+ * Remade universal font manager for Sector.
+ *
+ * @author MightyPork
+ */
+public class FontManager {
+
+ private static final boolean DEBUG = Config.LOG_FONTS;
+
+ /**
+ * Glyph tables.
+ *
+ * @author MightyPork
+ */
+ public static class Glyphs {
+
+ //@formatter:off
+ /** all glyphs */
+ public static final String all =
+ " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]" +
+ "^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ¡¢£¤" +
+ "¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäå" +
+ "æçèéêëìíîïðñòóôõö÷øùúûüýþÿ";
+
+ /** letters and numbers, sufficient for basic messages etc. NO SPACE */
+ public static final String alnum_nospace =
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+ /** letters and numbers, sufficient for basic messages etc. */
+ public static final String alnum =
+ " "+alnum_nospace;
+
+ /** letters and numbers with the most basic punctuation signs */
+ public static final String basic_text =
+ " .-,.?!:;_"+alnum_nospace;
+
+ /** letters */
+ public static final String alpha =
+ " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+ /** numbers */
+ public static final String numbers =
+ " 0123456789.-,:";
+
+ /** non-standard variants of alnum */
+ public static final String alnum_extra =
+ " ŒÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜŸÝßàáâãäåæçèéêëìíîïðñòóôõöøùúû" +
+ "üýþÿĚŠČŘŽŤŇĎŮěščřžťňďůŁłđ";
+
+ /** signs and punctuation */
+ public static final String signs =
+ " !\"#$%&§'()*+,-./:;<=>?@[\\]^_{|}~";
+
+ /** extra signs and punctuation */
+ public static final String signs_extra =
+ " ¥€£¢`ƒ„…†‡ˆ‰‹‘’“”•›¡¤¦¨ª«¬¯°±²³´µ¶·¸¹º»¼½¾¿÷™©®→↓←↑";
+
+
+ /** basic character set. */
+ public static final String basic = alnum + signs;
+ //@formatter:on
+ }
+
+ /**
+ * Font style
+ *
+ * @author MightyPork
+ */
+ public static enum Style
+ {
+ /** Normal */
+ NORMAL,
+ /** Italic */
+ ITALIC,
+ /** Stronger italic to left. */
+ LEFT,
+ /** Stronger italic to right */
+ RIGHT,
+ /** Monospace type */
+ MONO,
+ /** Bold */
+ BOLD,
+ /** Bold & Italic */
+ BOLD_I,
+ /** Bold & Left */
+ BOLD_L,
+ /** Bold & Right */
+ BOLD_R,
+ /** Heavy style, stronger than bold. */
+ HEAVY,
+ /** Light (lighter than normal) */
+ LIGHT,
+ /** narrow style, similar to Light */
+ NARROW,
+ /** Wide style, like Bold but with thinner lines */
+ WIDE,
+ /** Outline variant of normal */
+ OUTLINE;
+ }
+
+ /**
+ * Preloaded font identifier [name, size, style]
+ *
+ * @author MightyPork
+ */
+ public static class FontId {
+
+ /** font size (pt) */
+ public float size = 24;
+ /** font name, registered with registerFile */
+ public String name = "";
+ /** font style. The given style must be in a file. */
+ public Style style;
+
+ /** Set of glyphs in this ID */
+ public String glyphs = "";
+
+ /** Index for faster comparision of glyph ids. */
+ public int glyphset_id = 0;
+
+
+ /**
+ * Preloaded font identifier
+ *
+ * @param name font name (registerFile)
+ * @param size font size (pt)
+ * @param style font style
+ * @param glyphs glyphs to load
+ */
+ public FontId(String name, double size, Style style, String glyphs) {
+ this.name = name;
+ this.size = (float) size;
+ this.style = style;
+
+ if (glyphs.equals(Glyphs.basic)) {
+ glyphset_id = 1;
+ } else if (glyphs.equals(Glyphs.alnum)) {
+ glyphset_id = 2;
+ } else if (glyphs.equals(Glyphs.basic_text)) {
+ glyphset_id = 3;
+ } else if (glyphs.equals(Glyphs.numbers)) {
+ glyphset_id = 4;
+ } else if (glyphs.equals(Glyphs.alpha)) {
+ glyphset_id = 5;
+ } else if (glyphs.equals(Glyphs.all)) {
+ glyphset_id = 6;
+ } else if (glyphs.equals(Glyphs.alnum_extra)) {
+ glyphset_id = 7;
+ } else if (glyphs.equals(Glyphs.signs)) {
+ glyphset_id = 8;
+ } else if (glyphs.equals(Glyphs.signs_extra)) {
+ glyphset_id = 9;
+ } else {
+ this.glyphs = glyphs;
+ }
+ }
+
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (obj == null) return false;
+ if (!(obj.getClass().isAssignableFrom(getClass()))) return false;
+ if (obj instanceof FontId) {
+ if (obj == this) return true;
+ FontId id2 = ((FontId) obj);
+ boolean flag = true;
+ flag &= id2.size == size;
+ flag &= id2.name.equals(name);
+ flag &= id2.style == style;
+ flag &= ((id2.glyphset_id != -1 && id2.glyphset_id == glyphset_id) || id2.glyphs.equals(glyphs));
+ return flag;
+ }
+ return false;
+ }
+
+
+ @Override
+ public int hashCode()
+ {
+ return (new Float(size).hashCode()) ^ name.hashCode() ^ style.hashCode() ^ glyphset_id;
+ }
+
+
+ @Override
+ public String toString()
+ {
+ return "[" + name + ", " + size + ", " + style + (glyphset_id > 0 ? ", g=" + glyphset_id : ", g=custom") + "]";
+ }
+ }
+
+ /**
+ * Group of styles of one font.
+ *
+ * @author MightyPork
+ */
+ public static class FontFamily extends HashMap