]> git.lizzy.rs Git - nothing.git/commitdiff
Merge pull request #1121 from tsoding/411
authorAlexey Kutepov <reximkut@gmail.com>
Sat, 9 Nov 2019 17:41:40 +0000 (00:41 +0700)
committerGitHub <noreply@github.com>
Sat, 9 Nov 2019 17:41:40 +0000 (00:41 +0700)
(#411) Command handling in console

src/game.c
src/game.h
src/game/level.c
src/ui/console.c
src/ui/console.h
src/ui/console_log.c
src/ui/console_log.h

index e7fb23480cfaf681d4749efd982a2e48ecd4bbcb..413c7f9df209a812a016d29f80255b03e6c91aef 100644 (file)
@@ -40,6 +40,8 @@ typedef struct Game {
     Camera camera;
     SDL_Renderer *renderer;
     SDL_Texture *texture_cursor;
+    Console *console;
+    int console_enabled;
     int cursor_x;
     int cursor_y;
 } Game;
@@ -114,6 +116,16 @@ Game *create_game(const char *level_folder,
                 SDL_BLENDOPERATION_ADD)) < 0) {
         log_warn("SDL error: %s\n", SDL_GetError());
     }
+
+    game->console = PUSH_LT(
+        lt,
+        create_console(game),
+        destroy_console);
+    if (game->console == NULL) {
+        RETURN_LT(lt, NULL);
+    }
+    game->console_enabled = 0;
+
     game->cursor_x = 0;
     game->cursor_y = 0;
 
@@ -158,6 +170,12 @@ int game_render(const Game *game)
     case GAME_STATE_QUIT: break;
     }
 
+    if (game->console_enabled) {
+        if (console_render(game->console, &game->camera) < 0) {
+            return -1;
+        }
+    }
+
     if (game_render_cursor(game) < 0) {
         return -1;
     }
@@ -187,6 +205,12 @@ int game_update(Game *game, float delta_time)
     trace_assert(game);
     trace_assert(delta_time > 0.0f);
 
+    if (game->console_enabled) {
+        if (console_update(game->console, delta_time) < 0) {
+            return -1;
+        }
+    }
+
     switch (game->state) {
     case GAME_STATE_LEVEL: {
         if (level_update(game->level, delta_time) < 0) {
@@ -211,43 +235,10 @@ int game_update(Game *game, float delta_time)
         const char *level_filename = level_picker_selected_level(game->level_picker);
 
         if (level_filename != NULL) {
-            if (game->level_editor == NULL) {
-                game->level_editor = PUSH_LT(
-                    game->lt,
-                    create_level_editor_from_file(level_filename),
-                    destroy_level_editor);
-            } else {
-                game->level_editor = RESET_LT(
-                    game->lt,
-                    game->level_editor,
-                    create_level_editor_from_file(level_filename));
-            }
-
-            if (game->level_editor == NULL) {
+            if (game_load_level(game, level_filename) < 0) {
                 return -1;
             }
-
-            if (game->level == NULL) {
-                game->level = PUSH_LT(
-                    game->lt,
-                    create_level_from_level_editor(
-                        game->level_editor),
-                    destroy_level);
-            } else {
-                game->level = RESET_LT(
-                    game->lt,
-                    game->level,
-                    create_level_from_level_editor(
-                        game->level_editor));
-            }
-
-            if (game->level == NULL) {
-                return -1;
-            }
-
-            game_switch_state(game, GAME_STATE_LEVEL);
         }
-
     } break;
 
     case GAME_STATE_LEVEL_EDITOR: {
@@ -395,6 +386,7 @@ int game_event(Game *game, const SDL_Event *event)
     trace_assert(game);
     trace_assert(event);
 
+    // Global event handling
     switch (event->type) {
     case SDL_QUIT: {
         game_switch_state(game, GAME_STATE_QUIT);
@@ -414,6 +406,38 @@ int game_event(Game *game, const SDL_Event *event)
     } break;
     }
 
+    // Console event handling
+    if (game->console_enabled) {
+        switch (event->type) {
+        case SDL_KEYDOWN:
+            switch (event->key.keysym.sym) {
+            case SDLK_ESCAPE:
+                SDL_StopTextInput();
+                game->console_enabled = 0;
+                return 0;
+            default: {}
+            }
+
+        default: {}
+        }
+
+        return console_handle_event(game->console, event);
+    } else {
+        switch (event->type) {
+        case SDL_KEYUP: {
+            switch (event->key.keysym.sym) {
+            case SDLK_BACKQUOTE:
+            case SDLK_c: {
+                SDL_StartTextInput();
+                game->console_enabled = 1;
+                console_slide_down(game->console);
+            } break;
+            }
+        } break;
+        }
+    }
+
+    // State event handling
     switch (game->state) {
     case GAME_STATE_LEVEL:
         return game_event_running(game, event);
@@ -455,6 +479,10 @@ int game_input(Game *game,
     trace_assert(game);
     trace_assert(keyboard_state);
 
+    if (game->console_enabled) {
+        return 0;
+    }
+
     switch (game->state) {
     case GAME_STATE_SETTINGS:
     case GAME_STATE_QUIT:
@@ -490,3 +518,47 @@ static int game_render_cursor(const Game *game)
 
     return 0;
 }
+
+int game_load_level(Game *game, const char *level_filename)
+{
+    trace_assert(game);
+    trace_assert(level_filename);
+
+    if (game->level_editor == NULL) {
+        game->level_editor = PUSH_LT(
+            game->lt,
+            create_level_editor_from_file(level_filename),
+            destroy_level_editor);
+    } else {
+        game->level_editor = RESET_LT(
+            game->lt,
+            game->level_editor,
+            create_level_editor_from_file(level_filename));
+    }
+
+    if (game->level_editor == NULL) {
+        return -1;
+    }
+
+    if (game->level == NULL) {
+        game->level = PUSH_LT(
+            game->lt,
+            create_level_from_level_editor(
+                game->level_editor),
+            destroy_level);
+    } else {
+        game->level = RESET_LT(
+            game->lt,
+            game->level,
+            create_level_from_level_editor(
+                game->level_editor));
+    }
+
+    if (game->level == NULL) {
+        return -1;
+    }
+
+    game_switch_state(game, GAME_STATE_LEVEL);
+
+    return 0;
+}
index 4082a28caec7c2bae7b71f849994b73deabe29d8..b1141320efb9a411c26a38328382fd5bcd962956 100644 (file)
@@ -24,4 +24,6 @@ int game_input(Game *game,
 
 int game_over_check(const Game *game);
 
+int game_load_level(Game *game, const char *filepath);
+
 #endif  // GAME_H_
index 860638393202881e4c1fab1d0793017f35e11304..47da3c9f2f0e26da1b1c18595f6a540204599ccd 100644 (file)
@@ -51,8 +51,6 @@ struct Level
     Boxes *boxes;
     Labels *labels;
     Regions *regions;
-    Console *console;
-    int console_enabled;
 };
 
 Level *create_level_from_level_editor(const LevelEditor *level_editor)
@@ -148,14 +146,6 @@ Level *create_level_from_level_editor(const LevelEditor *level_editor)
         RETURN_LT(lt, NULL);
     }
 
-    level->console = PUSH_LT(
-        lt,
-        create_console(),
-        destroy_console);
-    if (level->console == NULL) {
-        RETURN_LT(lt, NULL);
-    }
-
     return level;
 }
 
@@ -205,12 +195,6 @@ int level_render(const Level *level, const Camera *camera)
         return -1;
     }
 
-    if (level->console_enabled) {
-        if (console_render(level->console, camera) < 0) {
-            return -1;
-        }
-    }
-
     return 0;
 }
 
@@ -219,12 +203,6 @@ int level_update(Level *level, float delta_time)
     trace_assert(level);
     trace_assert(delta_time > 0);
 
-    if (level->console_enabled) {
-        if (console_update(level->console, delta_time) < 0) {
-            return -1;
-        }
-    }
-
     if (level->state == LEVEL_STATE_PAUSE) {
         return 0;
     }
@@ -306,56 +284,12 @@ int level_event_pause(Level *level, const SDL_Event *event,
     return 0;
 }
 
-static
-int level_event_console(Level *level, const SDL_Event *event)
-{
-    trace_assert(level);
-    trace_assert(event);
-
-    if (level->console_enabled) {
-        switch (event->type) {
-        case SDL_KEYDOWN:
-            switch (event->key.keysym.sym) {
-            case SDLK_ESCAPE:
-                SDL_StopTextInput();
-                level->console_enabled = 0;
-                return 0;
-
-            default: {}
-            }
-
-        default: {}
-        }
-    } else {
-        switch (event->type) {
-        case SDL_KEYUP: {
-            switch (event->key.keysym.sym) {
-            case SDLK_BACKQUOTE:
-            case SDLK_c: {
-                SDL_StartTextInput();
-                level->console_enabled = 1;
-                console_slide_down(level->console);
-            } break;
-            }
-        } break;
-        }
-    }
-
-    return console_handle_event(level->console, event);
-}
-
 int level_event(Level *level, const SDL_Event *event,
                 Camera *camera, Sound_samples *sound_samples)
 {
     trace_assert(level);
     trace_assert(event);
 
-    level_event_console(level, event);
-
-    if (level->console_enabled) {
-        return 0;
-    }
-
     switch (level->state) {
     case LEVEL_STATE_IDLE: {
         return level_event_idle(level, event, camera, sound_samples);
@@ -376,10 +310,6 @@ int level_input(Level *level,
     trace_assert(level);
     trace_assert(keyboard_state);
 
-    if (level->console_enabled) {
-        return 0;
-    }
-
     if (level->state == LEVEL_STATE_PAUSE) {
         return 0;
     }
index 263a2f16a9984c585ea9906a23aa40caf797c92f..7040e313d6eeb03eecc53882ad5cb618ea3c945f 100644 (file)
@@ -1,5 +1,9 @@
+#include <ctype.h>
+#include <math.h>
+
 #include "system/stacktrace.h"
 
+#include "game.h"
 #include "game/level.h"
 #include "sdl/renderer.h"
 #include "system/log.h"
@@ -9,6 +13,7 @@
 #include "ui/console_log.h"
 #include "ui/edit_field.h"
 #include "ui/history.h"
+#include "math/extrema.h"
 
 #define FONT_WIDTH_SCALE 3.0f
 #define FONT_HEIGHT_SCALE 3.0f
 #define CONSOLE_ALPHA (0.80f)
 #define CONSOLE_BACKGROUND (rgba(0.20f, 0.20f, 0.20f, CONSOLE_ALPHA))
 #define CONSOLE_FOREGROUND (rgba(0.80f, 0.80f, 0.80f, CONSOLE_ALPHA))
+#define CONSOLE_ERROR (rgba(0.80f, 0.50f, 0.50f, CONSOLE_ALPHA))
+
+typedef struct {
+    const char *begin;
+    const char *end;
+} Token;
+
+
+static inline
+Token token(const char *begin, const char *end)
+{
+    Token t = {begin, end};
+    return t;
+}
+
+static inline
+int token_equals_str(Token t, const char *s)
+{
+    trace_assert(t.begin <= t.end);
+    size_t n1 = (size_t) (t.end - t.begin);
+    size_t n2 = strlen(s);
+    if (n1 != n2) return 0;
+    return memcmp(t.begin, s, n1) == 0;
+}
+
+static inline
+Token token_nt(const char *s)
+{
+    return token(s, s + strlen(s));
+}
+
+static inline
+void ltrim(Token *t)
+{
+    while (t->begin < t->end && isspace(*t->begin)) {
+        t->begin++;
+    }
+}
+
+static inline
+Token chop_word(Token *t)
+{
+    ltrim(t);
+    const char *end = t->begin;
+    while (end < t->end && !isspace(*end)) {
+        end++;
+    }
+    Token result = token(t->begin, end);
+    t->begin = end;
+    return result;
+}
 
 struct Console
 {
@@ -32,13 +88,14 @@ struct Console
     Edit_field *edit_field;
     Console_Log *console_log;
     History *history;
+    Game *game;
     float a;
 };
 
 /* TODO(#356): Console does not support autocompletion */
 /* TODO(#358): Console does not support copy, cut, paste operations */
 
-Console *create_console(void)
+Console *create_console(Game *game)
 {
     Lt *lt = create_lt();
 
@@ -75,6 +132,8 @@ Console *create_console(void)
         RETURN_LT(lt, NULL);
     }
 
+    console->game = game;
+
     return console;
 }
 
@@ -93,10 +152,28 @@ static int console_eval_input(Console *console)
         return -1;
     }
 
-    if (console_log_push_line(console->console_log, source_code, CONSOLE_FOREGROUND) < 0) {
+    if (console_log_push_line(console->console_log, source_code, NULL, CONSOLE_FOREGROUND) < 0) {
         return -1;
     }
 
+    Token input = token_nt(source_code);
+
+    Token command = chop_word(&input);
+    if (token_equals_str(command, "load")) {
+        Token level = chop_word(&input);
+        console_log_push_line(console->console_log, "Loading level:", NULL, CONSOLE_FOREGROUND);
+        console_log_push_line(console->console_log, level.begin, level.end, CONSOLE_FOREGROUND);
+        char level_name[256];
+        memset(level_name, 0, 256);
+        memcpy(level_name, level.begin, min_size_t((size_t)(level.end - level.begin), 255));
+
+        if (game_load_level(console->game, level_name) < 0) {
+            console_log_push_line(console->console_log, "Could not load level", NULL, CONSOLE_ERROR);
+        }
+    } else {
+        console_log_push_line(console->console_log, "Unknown command", NULL, CONSOLE_ERROR);
+    }
+
     edit_field_clean(console->edit_field);
 
     return 0;
index ff25e08af6ed91f32cccdf24163dafe11194e2dc..648fe33a551c02f0975ca70fe0072fd0de3db47c 100644 (file)
@@ -5,8 +5,9 @@
 
 typedef struct Console Console;
 typedef struct Sprite_font Sprite_font;
+typedef struct Game Game;
 
-Console *create_console(void);
+Console *create_console(Game *game);
 void destroy_console(Console *console);
 
 int console_handle_event(Console *console,
index 261968a0958b2e5cf61e25a1961b10a95e20e4a9..fdd8b77a72f859befa400c708c7d2dbebad776b0 100644 (file)
@@ -85,7 +85,10 @@ int console_log_render(const Console_Log *console_log,
     return 0;
 }
 
-int console_log_push_line(Console_Log *console_log, const char *line, Color color)
+int console_log_push_line(Console_Log *console_log,
+                          const char *line,
+                          const char *line_end,
+                          Color color)
 {
     trace_assert(console_log);
     trace_assert(line);
@@ -96,7 +99,7 @@ int console_log_push_line(Console_Log *console_log, const char *line, Color colo
         free(console_log->buffer[console_log->cursor]);
     }
 
-    console_log->buffer[console_log->cursor] = string_duplicate(line, NULL);
+    console_log->buffer[console_log->cursor] = string_duplicate(line, line_end);
     console_log->colors[console_log->cursor] = color;
 
     if (console_log->buffer[console_log->cursor] == NULL) {
index 2700d2f93d3befc80a26db25245a0d3410866a7f..c14ec5ccc54e68e5bf821c6169afc875cd8f4f9b 100644 (file)
@@ -16,6 +16,7 @@ int console_log_render(const Console_Log *console_log,
 
 int console_log_push_line(Console_Log *console_log,
                           const char *line,
+                          const char *line_end,
                           Color color);
 
 #endif  // CONSOLE_LOG_H_