Ver código fonte

new titlescreen, savegames and config separated, savegames splitted into 3 slots, changeable key bindings

Kajetan Johannes Hammerle 6 anos atrás
pai
commit
8ce530f903

+ 9 - 0
options.txt

@@ -0,0 +1,9 @@
+key.down="Down"
+key.enter="Enter"
+key.escape="Esc"
+key.jump="Space"
+key.left="Left"
+key.right="Right"
+key.run="Shift"
+key.up="Up"
+sound=true

+ 0 - 7
savegame.txt

@@ -1,7 +0,0 @@
-jump=12
-level.00=true
-level.00-Tech Demo=true
-level.01-Parabola=true
-level.02-Out of Reach=true
-level.04-Like Ice=true
-sound=false

+ 1 - 0
slot1.txt

@@ -0,0 +1 @@
+level.01-Parabola=true

+ 1 - 0
slot2.txt

@@ -0,0 +1 @@
+level.00-Tech Demo=true

+ 2 - 3
src/me/hammerle/supersnuvi/entity/EntityBuilder.java

@@ -15,7 +15,6 @@ import me.hammerle.supersnuvi.entity.components.ai.HumanController;
 import me.hammerle.supersnuvi.entity.components.animator.DefaultAnimator;
 import me.hammerle.supersnuvi.entity.components.animator.EntityAnimator;
 import me.hammerle.supersnuvi.gamelogic.Level;
-import me.hammerle.supersnuvi.gamelogic.StateRenderer;
 
 public final class EntityBuilder 
 {
@@ -53,7 +52,7 @@ public final class EntityBuilder
                     }
                 }, 100.0);
         hero.energy = new DefaultEnergy(hero, 100.0);
-        hero.move = new DefaultMovement(hero, ent -> StateRenderer.CONFIG.getDouble("jump", 10));
+        hero.move = new DefaultMovement(hero, ent -> level.getData().getInt("jump", 12));
         hero.itemCollector = new HeroItemCollector(hero);
         hero.movePenalty = new LandMovement(hero);
         return hero;
@@ -75,7 +74,7 @@ public final class EntityBuilder
         //hero.controller = new HumanController(hero);
         hero.health = new DefaultHealth(hero, Death.NULL, 100.0);
         hero.energy = new DefaultEnergy(hero, 100.0);
-        hero.move = new DefaultMovement(hero, ent -> StateRenderer.CONFIG.getDouble("jump", 10));
+        hero.move = new DefaultMovement(hero, ent -> level.getData().getInt("jump", 12));
         //hero.itemCollector = new HeroItemCollector(hero);
         hero.movePenalty = new LandMovement(hero);
         return hero;

+ 5 - 0
src/me/hammerle/supersnuvi/gamelogic/Level.java

@@ -157,6 +157,11 @@ public final class Level
         souls++;
     }
     
+    public LevelData getData()
+    {
+        return data;
+    }
+    
     // -------------------------------------------------------------------------
     // tick
     // -------------------------------------------------------------------------

+ 1 - 1
src/me/hammerle/supersnuvi/gamelogic/LevelData.java

@@ -116,7 +116,7 @@ public class LevelData
                     writeString(out, e.getKey(), false);
                     if(e.getValue() instanceof Integer)
                     {
-                        writeInt(out, (Integer) e.getValue(),true);
+                        writeInt(out, (Integer) e.getValue(), true);
                     }
                     else
                     {

+ 423 - 89
src/me/hammerle/supersnuvi/gamelogic/StateRenderer.java

@@ -3,6 +3,7 @@ package me.hammerle.supersnuvi.gamelogic;
 import java.io.File;
 import java.util.Arrays;
 import java.util.HashMap;
+import me.hammerle.supersnuvi.javafx.IKeyBinding;
 import me.hammerle.supersnuvi.javafx.KeyHandler;
 import me.hammerle.supersnuvi.savegame.SimpleConfig;
 import me.hammerle.supersnuvi.tiles.*;
@@ -24,12 +25,29 @@ public class StateRenderer
     private Level currentLevel;
     private final Level[] levels;
     private int levelIndex;
-    public static final SimpleConfig CONFIG = new SimpleConfig("savegame.txt");
+    
+    public static final SimpleConfig CONFIG = new SimpleConfig("options.txt", true);
+    private static final SimpleConfig[] SAVE_SLOTS = new SimpleConfig[] 
+    {
+        new SimpleConfig("slot1.txt", true), new SimpleConfig("slot2.txt", true), new SimpleConfig("slot3.txt", true)
+    };
+    
+    private int screen = 0;
+    private int startScreenIndex = 0;
+    private int optionScreenIndex = 0;
+    private int slotScreenIndex = 0;
+    
+    private boolean optionsDirty = false;
+    
+    // sound
+    private static boolean sound = CONFIG.getBoolean("sound", false);
+    public static boolean isSoundEnabled()
+    {
+        return sound;
+    }   
 
     public StateRenderer(IRenderer renderer)
     {
-        CONFIG.load();
-        
         this.renderer = renderer;
         this.registeredTiles = new HashMap<>();
         
@@ -153,14 +171,6 @@ public class StateRenderer
         return renderer;
     }
     
-    private static final int MENU_WIDTH = 26;
-    private static final int MENU_MAX = 5;
-    private static final char[] TABLE_TOP = getCharLine((char) 131, (char) 136, (char) 133, (char) 136);
-    private static final char[] TABLE_HEADING = getCharLine((char) 134, "Wähle ein Level ...", (char) 134, ' ');
-    private static final char[] TABLE_MID = getCharLine((char) 130, (char) 136, (char) 132, (char) 129);
-    private static final char[] TABLE_BOTTOM = getCharLine((char) 137, (char) 136, (char) 138, (char) 135);
-    private static final char[] TABLE_MORE = getCharLine((char) 134, "...", (char) 134, (char) 134);
-            
     private static char[] getCharLine(char start, char mid, char end, char spacer)
     {
         char[] c = new char[MENU_WIDTH];
@@ -185,6 +195,106 @@ public class StateRenderer
         return chars;
     }
     
+    private static final int MENU_WIDTH = 26;
+    private static final int MENU_MAX = 5;
+    private static final char[] TABLE_TOP = getCharLine((char) 131, (char) 136, (char) 133, (char) 136);
+    private static final char[] TABLE_HEADING = getCharLine((char) 134, "Wähle ein Level ...", (char) 134, ' ');
+    private static final char[] TABLE_MID = getCharLine((char) 130, (char) 136, (char) 132, (char) 129);
+    private static final char[] TABLE_BOTTOM = getCharLine((char) 137, (char) 136, (char) 138, (char) 135);
+    private static final char[] TABLE_MORE = getCharLine((char) 134, "...", (char) 134, (char) 134);
+    
+    private static final char[][] START_UP = new char[][] 
+    {
+        getCharLine((char) 131, (char) 136, (char) 133, (char) 136),
+        getCharLine((char) 134, "Super Snuvi", (char) 134, ' '),
+        getCharLine((char) 130, (char) 136, (char) 132, (char) 136),
+        getCharLine((char) 134, "Spiel starten", (char) 134, ' '),
+        getCharLine((char) 134, "Optionen", (char) 134, ' '),
+        getCharLine((char) 134, "Spiel beenden", (char) 134, ' '),
+        getCharLine((char) 137, (char) 136, (char) 138, (char) 136)
+    };
+    
+    private static final char[][] SLOTS = new char[][] 
+    {
+        getCharLine((char) 131, (char) 136, (char) 133, (char) 136),
+        getCharLine((char) 134, "Wähle einen Spielstand", (char) 134, ' '),
+        getCharLine((char) 130, (char) 136, (char) 132, (char) 136),
+        getCharLine((char) 134, "Slot 1", (char) 134, ' '),
+        getCharLine((char) 134, "Slot 2", (char) 134, ' '),
+        getCharLine((char) 134, "Slot 3", (char) 134, ' '),
+        getCharLine((char) 134, "Zurück", (char) 134, ' '),
+        getCharLine((char) 137, (char) 136, (char) 138, (char) 136)
+    };
+    
+    private static final char[][] OPTIONS = new char[][] 
+    {
+        getCharLine((char) 131, (char) 136, (char) 133, (char) 136),
+        getCharLine((char) 134, "Optionen", (char) 134, ' '),
+        getCharLine((char) 130, (char) 136, (char) 132, (char) 136),
+        getCharLine((char) 134, "Sound", (char) 134, ' '),  
+        getCharLine((char) 134, "K: Auf", (char) 134, ' '),
+        getCharLine((char) 134, "K: Ab", (char) 134, ' '),
+        getCharLine((char) 134, "K: Links", (char) 134, ' '),
+        getCharLine((char) 134, "K: Rechts", (char) 134, ' '),
+        getCharLine((char) 134, "K: Sprung", (char) 134, ' '),
+        getCharLine((char) 134, "K: Rennen", (char) 134, ' '),
+        getCharLine((char) 134, "K: Zurück", (char) 134, ' '),
+        getCharLine((char) 134, "K: Bestätigen", (char) 134, ' '),
+        getCharLine((char) 134, "", (char) 134, ' '), // save
+        getCharLine((char) 134, "Zurück", (char) 134, ' '),
+        getCharLine((char) 137, (char) 136, (char) 138, (char) 136)
+    };
+    
+    private static final char[] SAVE_OVERLAY = getCharLine(' ', "Speichern", ' ', ' ');
+    
+            
+    private static final int OPTION_OFFSET = 11;
+            
+    static
+    {
+        int pos = OPTIONS[0].length - OPTION_OFFSET;
+        OPTIONS[2][pos] = (char) 129;
+        for(int i = 0; i < 11; i++)
+        {
+            OPTIONS[3 + i][pos] = (char) 134;
+        }
+        OPTIONS[14][pos] = (char) 135;
+    }
+    
+    private void menuMove(Runnable esc, Runnable enter, Runnable down, Runnable up, Runnable end)
+    {
+        if(KeyHandler.ESCAPE.wasJustReleased())
+        {
+            esc.run();
+            return;
+        }
+        if(KeyHandler.ENTER.wasJustReleased())
+        {
+            enter.run();
+            return;
+        }
+
+        if(KeyHandler.DOWN.getDownTime() > 16)
+        {
+            KeyHandler.DOWN.resetTime();
+            down.run();
+        }
+        else if(KeyHandler.UP.getDownTime() > 16)
+        {
+            KeyHandler.UP.resetTime();
+            up.run();
+        }
+        else if(KeyHandler.DOWN.wasJustReleased())
+        {
+            down.run();
+        }
+        else if(KeyHandler.UP.wasJustReleased())
+        {
+            up.run();
+        }
+        end.run();
+    }
+    
     public void update()
     {
         if(currentLevel != null)
@@ -198,9 +308,9 @@ public class StateRenderer
             if(currentLevel.shouldFinish())
             {
                 currentLevel.resetLevel();
-                CONFIG.set("level." + currentLevel.getName(), true);
+                SAVE_SLOTS[slotScreenIndex].set("level." + currentLevel.getName(), true);
                 currentLevel = null;
-                CONFIG.save();
+                SAVE_SLOTS[slotScreenIndex].save();
                 return;
             }
             
@@ -216,43 +326,131 @@ public class StateRenderer
         }
         else
         {
-            SoundUtils.playSound(SoundUtils.Sound.MENU_MUSIC);
-            SoundUtils.stopSound(SoundUtils.Sound.SONG_1);
-            
-            if(KeyHandler.ENTER.wasJustReleased())
-            {
-                currentLevel = levels[levelIndex];
-                return;
-            }
-
-            if(KeyHandler.DOWN.getDownTime() > 16)
-            {
-                KeyHandler.DOWN.resetTime();
-                levelIndex++;
-            }
-            else if(KeyHandler.UP.getDownTime() > 16)
-            {
-                KeyHandler.UP.resetTime();
-                levelIndex--;
-            }
-            else if(KeyHandler.DOWN.wasJustReleased())
-            {
-                levelIndex++;
-            }
-            else if(KeyHandler.UP.wasJustReleased())
-            {
-                levelIndex--;
-            }
-            if(levelIndex < 0)
-            {
-                levelIndex = 0;
-            }
-            else if(levelIndex >= levels.length)
+            switch(screen)
             {
-                levelIndex = levels.length - 1;
+                case 0: // start screen
+                {
+                    menuMove(() -> 
+                    {
+                        // do nothing on escape in start screen
+                    }, () -> 
+                    {
+                        switch(startScreenIndex)
+                        { 
+                            case 0:
+                                screen = 1;
+                                break;
+                            case 1:
+                                screen = 2;
+                                break;
+                            case 2:
+                                System.exit(0);
+                                break;
+                        }
+                    }, () -> startScreenIndex++, () -> startScreenIndex--, () -> 
+                    {
+                        if(startScreenIndex < 0)
+                        {
+                            startScreenIndex = 0;
+                        }
+                        else if(startScreenIndex >= 3)
+                        {
+                            startScreenIndex = 2;
+                        }
+                    });
+                    break;
+                }
+                case 1: // slot screen
+                {
+                    menuMove(() -> 
+                    {
+                        screen = 0;
+                    }, () -> 
+                    {
+                        if(slotScreenIndex == 3)
+                        {
+                            screen = 0;
+                            return;
+                        }
+                        screen = 3;
+                    }, () -> slotScreenIndex++, () -> slotScreenIndex--, () -> 
+                    {
+                        if(slotScreenIndex < 0)
+                        {
+                            slotScreenIndex = 0;
+                        }
+                        else if(slotScreenIndex >= 4)
+                        {
+                            slotScreenIndex = 3;
+                        }
+                    });
+                    break;
+                }
+                case 2: // option screen
+                {
+                    menuMove(() -> 
+                    {
+                        screen = 0;
+                    }, () -> 
+                    {
+                        switch(optionScreenIndex)
+                        {
+                            case 0: // toggle sound
+                                sound = !sound;
+                                optionsDirty = true;
+                                break;
+                            case 9: // save options
+                                for(IKeyBinding binding : KeyHandler.ARRAY)
+                                {
+                                    CONFIG.set(binding.getName(), binding.getKeyName());
+                                }
+                                CONFIG.set("sound", sound);
+                                CONFIG.save();
+                                optionsDirty = false;
+                                break;
+                            case 10: // go back
+                                screen = 0;
+                                break;
+                            default: // rebind keys
+                                KeyHandler.rebindKey(KeyHandler.ARRAY[optionScreenIndex - 1]);
+                                optionsDirty = true;
+                                break;
+                        }
+                    }, () -> optionScreenIndex++, () -> optionScreenIndex--, () -> 
+                    {
+                        if(optionScreenIndex < 0)
+                        {
+                            optionScreenIndex = 0;
+                        }
+                        else if(optionScreenIndex >= OPTIONS.length - 4)
+                        {
+                            optionScreenIndex = OPTIONS.length - 5;
+                        }
+                    });
+                    break;
+                }
+                case 3: // level choose screen
+                {
+                    SoundUtils.playSound(SoundUtils.Sound.MENU_MUSIC);
+                    SoundUtils.stopSound(SoundUtils.Sound.SONG_1);
+                    menuMove(() -> 
+                    {
+                        screen = 1;
+                    }, () -> currentLevel = levels[levelIndex], () -> levelIndex++, () -> levelIndex--, () -> 
+                    {
+                        if(levelIndex < 0)
+                        {
+                            levelIndex = 0;
+                        }
+                        else if(levelIndex >= levels.length)
+                        {
+                            levelIndex = levels.length - 1;
+                        }
+                    });
+                    break;
+                }
             }
         }
-        
         SoundUtils.playSounds();
     }
     
@@ -263,58 +461,194 @@ public class StateRenderer
             currentLevel.render();
             return;
         }
-        
-        // level screen rendering
-        renderer.prepareTextDrawing(255, 255, 255, 1.0, MENU_WIDTH * 3 / 2);
-        
-        int listLength = Math.min(levels.length, MENU_MAX);
-        double x = (renderer.getWidth() - renderer.getTextWidth(MENU_WIDTH)) * 0.5;
-        double y = (renderer.getHeight() - renderer.getTextHeight(listLength + 4)) * 0.5;
-        double line = renderer.getTextHeight(1);
-        
-        renderer.drawText(x, y, TABLE_TOP);
-        y += line;
-        renderer.drawText(x, y, TABLE_HEADING);
-        y += line;
-        renderer.drawText(x, y, TABLE_MID);
-        y += line;
-
-        if(levels.length > MENU_MAX)
+        switch(screen)
         {
-            int upperHalf = MENU_MAX / 2;
-            int downHalf = levels.length - upperHalf;
-            if(levelIndex < upperHalf)
+            case 0:
             {
-                paintStringMarking(x, y, line, levelIndex);
-                y = paintLevelName(x, y, line, 0, MENU_MAX - 1);
-                renderer.drawText(x, y, TABLE_MORE);
-                y += line;
+                renderer.prepareTextDrawing(255, 255, 255, 1.0, MENU_WIDTH * 3 / 2);
+                double x = (renderer.getWidth() - renderer.getTextWidth(MENU_WIDTH)) * 0.5;
+                double y = (renderer.getHeight() - renderer.getTextHeight(7)) * 0.5;
+                double line = renderer.getTextHeight(1);
+                
+                renderer.save();
+                renderer.setFillColor(128, 128, 128, 1.0);
+                renderer.fillRectangle(
+                        x + renderer.getTextWidth(1),
+                        y + renderer.getTextHeight(startScreenIndex + 3) - 1, 
+                        renderer.getTextWidth(MENU_WIDTH - 2), 
+                        line);
+                renderer.restore();
+                
+                for(char[] c : START_UP)
+                {
+                    renderer.drawText(x, y, c);
+                    y += line;
+                }
+                break;
+            }
+            case 1:
+            {
+                renderer.prepareTextDrawing(255, 255, 255, 1.0, MENU_WIDTH * 3 / 2);
+                double x = (renderer.getWidth() - renderer.getTextWidth(MENU_WIDTH)) * 0.5;
+                double y = (renderer.getHeight() - renderer.getTextHeight(7)) * 0.5;
+                double line = renderer.getTextHeight(1);
+                
+                renderer.save();
+                renderer.setFillColor(128, 128, 128, 1.0);
+                renderer.fillRectangle(
+                        x + renderer.getTextWidth(1),
+                        y + renderer.getTextHeight(slotScreenIndex + 3) - 1, 
+                        renderer.getTextWidth(MENU_WIDTH - 2), 
+                        line);
+                renderer.restore();
+                
+                for(char[] c : SLOTS)
+                {
+                    renderer.drawText(x, y, c);
+                    y += line;
+                }
+                break;
             }
-            else if(levelIndex >= downHalf)
+            case 2:
             {
-                paintStringMarking(x, y, line, levelIndex - downHalf + upperHalf + ((MENU_MAX & 1) != 0 ? 1 : 0));
-                renderer.drawText(x, y, TABLE_MORE);
+                renderer.prepareTextDrawing(255, 255, 255, 1.0, MENU_WIDTH * 3 / 2);
+                double x = (renderer.getWidth() - renderer.getTextWidth(MENU_WIDTH)) * 0.5;
+                double y = (renderer.getHeight() - renderer.getTextHeight(OPTIONS.length)) * 0.5;
+                double line = renderer.getTextHeight(1);
+                
+                renderer.save();
+                renderer.setFillColor(128, 128, 128, 1.0);
+                renderer.fillRectangle(
+                        x + renderer.getTextWidth(1),
+                        y + renderer.getTextHeight(optionScreenIndex + 3) - 1, 
+                        renderer.getTextWidth(MENU_WIDTH - 12), 
+                        line);               
+                renderer.fillRectangle(
+                        x + renderer.getTextWidth(MENU_WIDTH - 10),
+                        y + renderer.getTextHeight(optionScreenIndex + 3) - 1, 
+                        renderer.getTextWidth(9), 
+                        line);
+                renderer.restore();
+                
+                // option top
+                for(int i = 0; i < 3; i++)
+                {
+                    renderer.drawText(x, y, OPTIONS[i]);
+                    y += line;
+                }
+                
+                // sound option
+                if(sound)
+                {
+                    int pos = OPTIONS[3].length - OPTION_OFFSET + 1;
+                    OPTIONS[3][pos] = 'j';
+                    OPTIONS[3][pos + 1] = 'a';
+                    OPTIONS[3][pos + 2] = ' ';
+                    OPTIONS[3][pos + 3] = ' ';
+                }
+                else
+                {
+                    int pos = OPTIONS[3].length - OPTION_OFFSET + 1;
+                    OPTIONS[3][pos] = 'n';
+                    OPTIONS[3][pos + 1] = 'e';
+                    OPTIONS[3][pos + 2] = 'i';
+                    OPTIONS[3][pos + 3] = 'n';
+                }
+                renderer.drawText(x, y, OPTIONS[3]);
                 y += line;
-                y = paintLevelName(x, y, line, levels.length - MENU_MAX + 1, MENU_MAX - 1);
+                
+                // key binding options
+                int end = 4 + KeyHandler.ARRAY.length;
+                for(int i = 4; i < end; i++)
+                {
+                    String name = KeyHandler.ARRAY[i - 4].toString();
+                    System.arraycopy(name.toCharArray(), 0, OPTIONS[i], 
+                            OPTIONS[i].length - OPTION_OFFSET + 1, Math.min(OPTION_OFFSET - 2, name.length()));
+                    renderer.drawText(x, y, OPTIONS[i]);
+                    y += line;
+                }
+                
+                // save
+                renderer.drawText(x, y, OPTIONS[end]);
+                if(optionsDirty)
+                {
+                    renderer.save();
+                    renderer.setFillColor(180, 0, 0, 1);
+                    renderer.setStrokeColor(180, 0, 0, 1);
+                    renderer.drawText(x, y, SAVE_OVERLAY);
+                    renderer.restore();
+                }
+                else
+                {
+                    renderer.drawText(x, y, SAVE_OVERLAY);
+                }
+                y += line;
+                
+                // left over option table
+                for(int i = end + 1; i < OPTIONS.length; i++)
+                {
+                    renderer.drawText(x, y, OPTIONS[i]);
+                    y += line;
+                }
+                
+                break;
             }
-            else
+            case 3:
             {
-                paintStringMarking(x, y, line, upperHalf);
-                renderer.drawText(x, y, TABLE_MORE);
+                // level screen rendering
+                renderer.prepareTextDrawing(255, 255, 255, 1.0, MENU_WIDTH * 3 / 2);
+
+                int listLength = Math.min(levels.length, MENU_MAX);
+                double x = (renderer.getWidth() - renderer.getTextWidth(MENU_WIDTH)) * 0.5;
+                double y = (renderer.getHeight() - renderer.getTextHeight(listLength + 4)) * 0.5;
+                double line = renderer.getTextHeight(1);
+
+                renderer.drawText(x, y, TABLE_TOP);
+                y += line;
+                renderer.drawText(x, y, TABLE_HEADING);
                 y += line;
-                y = paintLevelName(x, y, line, levelIndex - upperHalf + 1, MENU_MAX - 2);
-                renderer.drawText(x, y, TABLE_MORE);
+                renderer.drawText(x, y, TABLE_MID);
                 y += line;
+
+                if(levels.length > MENU_MAX)
+                {
+                    int upperHalf = MENU_MAX / 2;
+                    int downHalf = levels.length - upperHalf;
+                    if(levelIndex < upperHalf)
+                    {
+                        paintStringMarking(x, y, line, levelIndex);
+                        y = paintLevelName(x, y, line, 0, MENU_MAX - 1);
+                        renderer.drawText(x, y, TABLE_MORE);
+                        y += line;
+                    }
+                    else if(levelIndex >= downHalf)
+                    {
+                        paintStringMarking(x, y, line, levelIndex - downHalf + upperHalf + ((MENU_MAX & 1) != 0 ? 1 : 0));
+                        renderer.drawText(x, y, TABLE_MORE);
+                        y += line;
+                        y = paintLevelName(x, y, line, levels.length - MENU_MAX + 1, MENU_MAX - 1);
+                    }
+                    else
+                    {
+                        paintStringMarking(x, y, line, upperHalf);
+                        renderer.drawText(x, y, TABLE_MORE);
+                        y += line;
+                        y = paintLevelName(x, y, line, levelIndex - upperHalf + 1, MENU_MAX - 2);
+                        renderer.drawText(x, y, TABLE_MORE);
+                        y += line;
+                    }
+                }
+                else
+                {
+                    paintStringMarking(x, y, line, levelIndex);
+                    y = paintLevelName(x, y, line, 0, levels.length);
+                }
+
+                renderer.drawText(x, y, TABLE_BOTTOM);
+                renderer.stopTextDrawing();
+                break;
             }
         }
-        else
-        {
-            paintStringMarking(x, y, line, levelIndex);
-            y = paintLevelName(x, y, line, 0, levels.length);
-        }
-
-        renderer.drawText(x, y, TABLE_BOTTOM);
-        renderer.stopTextDrawing();
     }
     
     private double paintLevelName(double x, double y, double line, int from, int length)
@@ -334,7 +668,7 @@ public class StateRenderer
             }
             Arrays.fill(chars, border + 1, MENU_WIDTH - 1, (char) 0);
             chars[chars.length - 3] = 134;
-            if(CONFIG.getBoolean("level." + s, false))
+            if(SAVE_SLOTS[slotScreenIndex].getBoolean("level." + s, false))
             {
                 chars[chars.length - 2] = 'x';
             }

+ 3 - 0
src/me/hammerle/supersnuvi/javafx/IKeyBinding.java

@@ -6,4 +6,7 @@ public interface IKeyBinding
     public int getDownTime();
     public boolean wasJustReleased();
     public void resetTime();
+    
+    public String getName();
+    public String getKeyName();
 }

+ 53 - 1
src/me/hammerle/supersnuvi/javafx/KeyBinding.java

@@ -1,15 +1,51 @@
 package me.hammerle.supersnuvi.javafx;
 
+import javafx.scene.input.KeyCode;
+
 public class KeyBinding implements IKeyBinding
 {
     private boolean isDown;
     private boolean justReleased;
     private int downTime;
     
-    public KeyBinding()
+    private KeyCode code;
+    private boolean isEdited;
+    
+    private final String name;
+    
+    public KeyBinding(String name, KeyCode code)
     {
         downTime = 0;
         justReleased = false;
+        this.code = code;
+        this.name = name;
+    }
+    
+    @Override
+    public String getName() 
+    {
+        return name;
+    }
+    
+    @Override
+    public String getKeyName() 
+    {
+        return code.getName();
+    }
+    
+    public void setEditStatus(boolean b)
+    {
+        isEdited = b;
+    }
+    
+    public KeyCode getKeyCode()
+    {
+        return code;
+    }
+    
+    public void setKeyCode(KeyCode code)
+    {
+        this.code = code; 
     }
     
     public void press()
@@ -62,4 +98,20 @@ public class KeyBinding implements IKeyBinding
     {
         downTime = 0;
     }
+
+    @Override
+    public String toString() 
+    {
+        if(isEdited)
+        {
+            return "[...]    ";
+        }
+        StringBuilder sb = new StringBuilder();
+        sb.append(code.getName());
+        if(sb.length() < 9)
+        {
+            sb.append("         ".substring(sb.length()));
+        }
+        return sb.toString();
+    }
 }

+ 64 - 14
src/me/hammerle/supersnuvi/javafx/KeyHandler.java

@@ -2,6 +2,7 @@ package me.hammerle.supersnuvi.javafx;
 
 import java.util.EnumMap;
 import javafx.scene.input.KeyCode;
+import me.hammerle.supersnuvi.gamelogic.StateRenderer;
 
 public class KeyHandler
 {
@@ -11,28 +12,77 @@ public class KeyHandler
     
     private final static EnumMap<KeyCode, KeyBinding> BINDINGS = new EnumMap(KeyCode.class);
     
-    private static KeyBinding registerBinding(KeyCode key)
+    private static KeyBinding registerBinding(String name, KeyCode error)
     {
-        KeyBinding binding = new KeyBinding();
-        BINDINGS.put(key, binding);
+        String s = StateRenderer.CONFIG.getString(name);
+        KeyCode code;
+        if(s == null)
+        {
+            code = error;
+        }
+        else
+        {
+            code = KeyCode.getKeyCode(s);
+            if(code == null)
+            {
+                System.out.println("cant find key '" + s + "'");
+                code = error;
+            }
+        }
+        KeyBinding binding = new KeyBinding(name, code);
+        BINDINGS.put(code, binding);
         return binding;
     }
     
-    public final static IKeyBinding UP = registerBinding(KeyCode.UP);
-    public final static IKeyBinding DOWN = registerBinding(KeyCode.DOWN);
-    public final static IKeyBinding LEFT = registerBinding(KeyCode.LEFT);
-    public final static IKeyBinding RIGHT = registerBinding(KeyCode.RIGHT);
-    public final static IKeyBinding JUMP = registerBinding(KeyCode.SPACE);
-    public final static IKeyBinding RUN = registerBinding(KeyCode.SHIFT);
-    public final static IKeyBinding ESCAPE = registerBinding(KeyCode.ESCAPE);
-    public final static IKeyBinding ENTER = registerBinding(KeyCode.ENTER);
+    public final static IKeyBinding UP = registerBinding("key.up", KeyCode.UP);
+    public final static IKeyBinding DOWN = registerBinding("key.down", KeyCode.DOWN);
+    public final static IKeyBinding LEFT = registerBinding("key.left", KeyCode.LEFT);
+    public final static IKeyBinding RIGHT = registerBinding("key.right", KeyCode.RIGHT);
+    public final static IKeyBinding JUMP = registerBinding("key.jump", KeyCode.SPACE);
+    public final static IKeyBinding RUN = registerBinding("key.run", KeyCode.SHIFT);
+    public final static IKeyBinding ESCAPE = registerBinding("key.escape", KeyCode.ESCAPE);
+    public final static IKeyBinding ENTER = registerBinding("key.enter", KeyCode.ENTER);
+    
+    public final static IKeyBinding[] ARRAY = new IKeyBinding[] 
+    {
+        UP, DOWN, LEFT,  RIGHT, JUMP, RUN, ESCAPE, ENTER
+    };
+    
+    private static KeyBinding rebind = null;
+    
+    public static void rebindKey(IKeyBinding binding)
+    {
+        rebind = (KeyBinding) binding;
+        rebind.setEditStatus(true);
+    }
            
     protected static void pressKey(KeyCode key) 
     {
-        KeyBinding binding = BINDINGS.get(key);
-        if(binding != null)
+        if(rebind == null)
+        {
+            KeyBinding binding = BINDINGS.get(key);
+            if(binding != null)
+            {
+                binding.press();
+            }
+        }
+        else
         {
-            binding.press();
+            for(IKeyBinding b : ARRAY)
+            {
+                if(((KeyBinding) b).getKeyCode() == key)
+                {
+                    rebind.setEditStatus(false);
+                    rebind = null;
+                    return;
+                }
+            }
+                
+            BINDINGS.remove(rebind.getKeyCode());
+            rebind.setKeyCode(key);
+            BINDINGS.put(key, rebind);
+            rebind.setEditStatus(false);
+            rebind = null;
         }
     }
 

+ 11 - 2
src/me/hammerle/supersnuvi/savegame/SimpleConfig.java

@@ -14,10 +14,14 @@ public class SimpleConfig
     protected final TreeMap<String, Object> conf;
     private final File file;
     
-    public SimpleConfig(String path)
+    public SimpleConfig(String path, boolean load)
     {    
         file = new File(path);
         conf = new TreeMap<>();
+        if(load)
+        {
+            load();
+        }
     }
     
     private Object convertInput(String s)
@@ -176,7 +180,12 @@ public class SimpleConfig
     
     public final String getString(String key, String error)
     {
-        return get(key, String.class, error);
+        String s = get(key, String.class, error);
+        if(s != null && !s.isEmpty() && s.charAt(0) == '"' && s.charAt(s.length() - 1) == '"')
+        {
+            s = s.substring(1, s.length() - 1);
+        }
+        return s;
     }
     
     public final String getString(String key)

+ 1 - 2
src/me/hammerle/supersnuvi/util/SoundUtils.java

@@ -5,7 +5,6 @@ import java.util.Arrays;
 import javafx.scene.media.Media;
 import javafx.scene.media.MediaPlayer;
 import me.hammerle.supersnuvi.gamelogic.StateRenderer;
-import me.hammerle.supersnuvi.javafx.JavaRenderer;
 
 public class SoundUtils 
 {
@@ -13,7 +12,7 @@ public class SoundUtils
             
     public static void initSounds()
     {
-        soundPlayer = new SoundPlayer(!StateRenderer.CONFIG.getBoolean("sound", false));
+        soundPlayer = new SoundPlayer(!StateRenderer.isSoundEnabled());
         //new Thread(soundPlayer).start();
     }