3 #include "game/level.h"
4 #include "game/level/player/rigid_rect.h"
6 #include "script/interpreter.h"
7 #include "script/parser.h"
8 #include "script/scope.h"
9 #include "sdl/renderer.h"
10 #include "system/error.h"
11 #include "system/lt.h"
12 #include "ui/console.h"
13 #include "ui/edit_field.h"
16 #define FONT_WIDTH_SCALE 3.0f
17 #define FONT_HEIGHT_SCALE 3.0f
19 #define LOG_CAPACITY 10
20 #define PROMPT_HEIGHT (FONT_HEIGHT_SCALE * FONT_CHAR_HEIGHT)
21 #define LOG_HEIGHT (FONT_HEIGHT_SCALE * FONT_CHAR_HEIGHT * LOG_CAPACITY)
23 #define CONSOLE_HEIGHT (LOG_HEIGHT + PROMPT_HEIGHT)
25 #define SLIDE_DOWN_TIME 0.1f
26 #define SLIDE_DOWN_SPEED (CONSOLE_HEIGHT / SLIDE_DOWN_TIME)
28 #define CONSOLE_BACKGROUND (color(0.20f, 0.20f, 0.20f, 1.0f))
29 #define CONSOLE_FOREGROUND (color(0.80f, 0.80f, 0.80f, 1.0f))
30 #define CONSOLE_ERROR (color(0.80f, 0.50f, 0.50f, 1.0f))
37 Edit_field *edit_field;
43 /* TODO(#354): Console does not allow to travel the history by pressing up and down */
44 /* TODO(#355): Console does not support Emacs keybindings */
45 /* TODO(#356): Console does not support autocompletion */
46 /* TODO(#357): Console does not show the state of the GC of the script */
47 /* TODO(#358): Console does not support copy, cut, paste operations */
49 static struct EvalResult rect_apply_force(void *param, Gc *gc, struct Scope *scope, struct Expr args)
55 Level *level = (Level*) param;
56 const char *rect_id = CAR(args).atom->str;
57 struct Expr vector_force_expr = CAR(CDR(args));
58 const float force_x = (float) CAR(vector_force_expr).atom->num;
59 const float force_y = (float) CDR(vector_force_expr).atom->num;
61 print_expr_as_sexpr(args); printf("\n");
63 Rigid_rect *rigid_rect = level_rigid_rect(level, rect_id);
64 if (rigid_rect != NULL) {
65 printf("Found rect `%s`\n", rect_id);
66 printf("Applying force (%f, %f)\n", force_x, force_y);
67 rigid_rect_apply_force(rigid_rect, vec(force_x, force_y));
69 fprintf(stderr, "Couldn't find rigid_rect `%s`", rect_id);
72 return eval_success(NIL(gc));
75 Console *create_console(Level *level,
76 const Sprite_font *font)
84 Console *console = PUSH_LT(lt, malloc(sizeof(Console)), free);
85 if (console == NULL) {
86 throw_error(ERROR_TYPE_LIBC);
91 console->gc = PUSH_LT(lt, create_gc(), destroy_gc);
92 if (console->gc == NULL) {
96 console->scope.expr = CONS(console->gc,
102 SYMBOL(console->gc, "rect-apply-force"),
103 NATIVE(console->gc, rect_apply_force, level));
105 console->edit_field = PUSH_LT(
109 vec(FONT_WIDTH_SCALE, FONT_HEIGHT_SCALE),
112 if (console->edit_field == NULL) {
116 console->log = PUSH_LT(
120 vec(FONT_WIDTH_SCALE, FONT_HEIGHT_SCALE),
124 console->level = level;
125 console->y = -CONSOLE_HEIGHT;
130 void destroy_console(Console *console)
133 RETURN_LT0(console->lt);
136 int console_handle_event(Console *console,
137 const SDL_Event *event)
139 switch(event->type) {
141 switch(event->key.keysym.sym) {
143 const char *source_code = edit_field_as_text(console->edit_field);
144 struct ParseResult parse_result = read_expr_from_string(console->gc,
146 if (parse_result.is_error) {
147 if (log_push_line(console->log, source_code, CONSOLE_ERROR) < 0) {
151 if (log_push_line(console->log, parse_result.error_message, CONSOLE_ERROR)) {
155 edit_field_clean(console->edit_field);
160 struct EvalResult eval_result = eval(
165 if (eval_result.is_error) {
166 /* TODO(#360): Console doesn't report any eval errors visually */
168 print_expr_as_sexpr(eval_result.expr);
172 gc_collect(console->gc, console->scope.expr);
174 if (log_push_line(console->log,
175 edit_field_as_text(console->edit_field),
176 CONSOLE_FOREGROUND) < 0) {
179 edit_field_clean(console->edit_field);
186 return edit_field_handle_event(console->edit_field, event);
189 int console_render(const Console *console,
190 SDL_Renderer *renderer)
192 /* TODO(#364): console doesn't have any padding around the edit fields */
194 SDL_RenderGetViewport(renderer, &view_port);
196 if (fill_rect(renderer,
197 rect(0.0f, console->y,
200 CONSOLE_BACKGROUND) < 0) {
204 if (log_render(console->log,
206 vec(0.0f, console->y)) < 0) {
210 if (edit_field_render(console->edit_field,
212 vec(0.0f, console->y + LOG_HEIGHT)) < 0) {
219 int console_update(Console *console, float delta_time)
223 /* TODO(#366): console slide down animation doesn't have any easing */
225 if (console->y < 0.0f) {
226 console->y += SLIDE_DOWN_SPEED * delta_time;
228 if (console->y > 0.0f) {
236 void console_slide_down(Console *console)
239 console->y = -CONSOLE_HEIGHT;