X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fgame%2Flevel%2Flevel_editor.c;h=1c19018dbb4ac3839a70f7b86a1746abbb59b896;hb=2d51d8f1f734bbf7aa01cf93c81fd69cbd8af930;hp=ae938aa8350100d4e95a5baee3b57c62689067f2;hpb=9b798f9707ee983b0df7319600c9acaf5bbc88d3;p=nothing.git diff --git a/src/game/level/level_editor.c b/src/game/level/level_editor.c index ae938aa8..1c19018d 100644 --- a/src/game/level/level_editor.c +++ b/src/game/level/level_editor.c @@ -1,7 +1,7 @@ #include #include "game/camera.h" -#include "game/level_metadata.h" +#include "game/sound_samples.h" #include "game/level/boxes.h" #include "game/level/level_editor/color_picker.h" #include "game/level/level_editor/rect_layer.h" @@ -16,22 +16,26 @@ #include "system/lt_adapters.h" #include "system/log.h" #include "system/str.h" +#include "config.h" +#include "math/extrema.h" +#include "system/file.h" #include "level_editor.h" -#define LEVEL_LINE_MAX_LENGTH 512 +#define LEVEL_FOLDER_MAX_LENGTH 512 #define LEVEL_EDITOR_EDIT_FIELD_SIZE vec(5.0f, 5.0f) #define LEVEL_EDITOR_EDIT_FIELD_COLOR COLOR_BLACK #define LEVEL_EDITOR_NOTICE_SCALE vec(10.0f, 10.0f) #define LEVEL_EDITOR_NOTICE_DURATION 1.0f #define LEVEL_EDITOR_NOTICE_PADDING_TOP 100.0f +#define LEVEL_EDITOR_TMPMEM_CAPACITY (640 * KILO) static int level_editor_dump(LevelEditor *level_editor); // TODO(#994): too much duplicate code between create_level_editor and create_level_editor_from_file -LevelEditor *create_level_editor(void) +LevelEditor *create_level_editor(Cursor *cursor) { Lt *lt = create_lt(); LevelEditor *level_editor = PUSH_LT( @@ -43,97 +47,28 @@ LevelEditor *create_level_editor(void) } level_editor->lt = lt; - level_editor->edit_field_filename = PUSH_LT( - lt, - create_edit_field( - LEVEL_EDITOR_EDIT_FIELD_SIZE, - LEVEL_EDITOR_EDIT_FIELD_COLOR), - destroy_edit_field); - if (level_editor->edit_field_filename == NULL) { - RETURN_LT(lt, NULL); - } - - level_editor->metadata = PUSH_LT( - lt, - create_level_metadata("New Level"), - destroy_level_metadata); - if (level_editor->metadata == NULL) { - RETURN_LT(lt, NULL); - } + level_editor->edit_field_filename.font_size = LEVEL_EDITOR_EDIT_FIELD_SIZE; + level_editor->edit_field_filename.font_color = LEVEL_EDITOR_EDIT_FIELD_COLOR; level_editor->background_layer = create_background_layer(hexstr("fffda5")); - - level_editor->player_layer = - create_player_layer(vec(0.0f, 0.0f), hexstr("ff8080")); - - level_editor->platforms_layer = PUSH_LT( - lt, - create_rect_layer("platform"), - destroy_rect_layer); - if (level_editor->platforms_layer == NULL) { - RETURN_LT(lt, NULL); - } - - level_editor->goals_layer = PUSH_LT( - lt, - create_point_layer(), - destroy_point_layer); - if (level_editor->goals_layer == NULL) { - RETURN_LT(lt, NULL); - } - - level_editor->lava_layer = PUSH_LT( - lt, - create_rect_layer("lava"), - destroy_rect_layer); - if (level_editor->lava_layer == NULL) { - RETURN_LT(lt, NULL); - } - - level_editor->back_platforms_layer = PUSH_LT( - lt, - create_rect_layer("back_platform"), - destroy_rect_layer); - if (level_editor->back_platforms_layer == NULL) { - RETURN_LT(lt, NULL); - } - - level_editor->boxes_layer = PUSH_LT( - lt, - create_rect_layer("box"), - destroy_rect_layer); - if (level_editor->boxes_layer == NULL) { - RETURN_LT(lt, NULL); - } - - level_editor->label_layer = PUSH_LT( - lt, - create_label_layer(), - destroy_label_layer); - if (level_editor->label_layer == NULL) { - RETURN_LT(lt, NULL); - } - - level_editor->regions_layer = PUSH_LT( - lt, - create_rect_layer("region"), - destroy_rect_layer); - if (level_editor->regions_layer == NULL) { - RETURN_LT(lt, NULL); - } - - level_editor->supa_script_source = - PUSH_LT(lt, string_duplicate("", NULL), free); - - level_editor->layers[LAYER_PICKER_BOXES] = rect_layer_as_layer(level_editor->boxes_layer); - level_editor->layers[LAYER_PICKER_PLATFORMS] = rect_layer_as_layer(level_editor->platforms_layer); - level_editor->layers[LAYER_PICKER_BACK_PLATFORMS] = rect_layer_as_layer(level_editor->back_platforms_layer); - level_editor->layers[LAYER_PICKER_GOALS] = point_layer_as_layer(level_editor->goals_layer); + level_editor->player_layer = create_player_layer(vec(0.0f, 0.0f), hexstr("ff8080")); + level_editor->platforms_layer = create_rect_layer("platform", cursor); + level_editor->goals_layer = create_point_layer("goal"), + level_editor->lava_layer = create_rect_layer("lava", cursor); + level_editor->back_platforms_layer = create_rect_layer("back_platform", cursor); + level_editor->boxes_layer = create_rect_layer("box", cursor); + level_editor->label_layer = create_label_layer("label"); + level_editor->regions_layer = create_rect_layer("region", cursor), + + level_editor->layers[LAYER_PICKER_BOXES] = rect_layer_as_layer(&level_editor->boxes_layer); + level_editor->layers[LAYER_PICKER_PLATFORMS] = rect_layer_as_layer(&level_editor->platforms_layer); + level_editor->layers[LAYER_PICKER_BACK_PLATFORMS] = rect_layer_as_layer(&level_editor->back_platforms_layer); + level_editor->layers[LAYER_PICKER_GOALS] = point_layer_as_layer(&level_editor->goals_layer); level_editor->layers[LAYER_PICKER_PLAYER] = player_layer_as_layer(&level_editor->player_layer); - level_editor->layers[LAYER_PICKER_LAVA] = rect_layer_as_layer(level_editor->lava_layer); - level_editor->layers[LAYER_PICKER_REGIONS] = rect_layer_as_layer(level_editor->regions_layer); + level_editor->layers[LAYER_PICKER_LAVA] = rect_layer_as_layer(&level_editor->lava_layer); + level_editor->layers[LAYER_PICKER_REGIONS] = rect_layer_as_layer(&level_editor->regions_layer); level_editor->layers[LAYER_PICKER_BACKGROUND] = background_layer_as_layer(&level_editor->background_layer); - level_editor->layers[LAYER_PICKER_LABELS] = label_layer_as_layer(level_editor->label_layer); + level_editor->layers[LAYER_PICKER_LABELS] = label_layer_as_layer(&level_editor->label_layer); level_editor->notice = (FadingWigglyText) { .wiggly_text = { @@ -146,10 +81,12 @@ LevelEditor *create_level_editor(void) level_editor->camera_scale = 1.0f; + level_editor->undo_history = create_undo_history(); + return level_editor; } -LevelEditor *create_level_editor_from_file(const char *file_name) +LevelEditor *create_level_editor_from_file(const char *file_name, Cursor *cursor) { trace_assert(file_name); @@ -163,15 +100,8 @@ LevelEditor *create_level_editor_from_file(const char *file_name) } level_editor->lt = lt; - level_editor->edit_field_filename = PUSH_LT( - lt, - create_edit_field( - LEVEL_EDITOR_EDIT_FIELD_SIZE, - LEVEL_EDITOR_EDIT_FIELD_COLOR), - destroy_edit_field); - if (level_editor->edit_field_filename == NULL) { - RETURN_LT(lt, NULL); - } + level_editor->edit_field_filename.font_size = LEVEL_EDITOR_EDIT_FIELD_SIZE; + level_editor->edit_field_filename.font_color = LEVEL_EDITOR_EDIT_FIELD_COLOR; level_editor->file_name = PUSH_LT( @@ -179,114 +109,47 @@ LevelEditor *create_level_editor_from_file(const char *file_name) string_duplicate(file_name, NULL), free); - LineStream *level_stream = PUSH_LT( - lt, - create_line_stream( - file_name, - "r", - LEVEL_LINE_MAX_LENGTH), - destroy_line_stream); - if (level_stream == NULL) { - RETURN_LT(lt, NULL); - } - - level_editor->metadata = PUSH_LT( - lt, - create_level_metadata_from_line_stream(level_stream), - destroy_level_metadata); - if (level_editor->metadata == NULL) { - RETURN_LT(lt, NULL); - } - - if (background_layer_read_from_line_stream( - &level_editor->background_layer, - level_stream) < 0) { - RETURN_LT(lt, NULL); - } - - level_editor->player_layer = - create_player_layer_from_line_stream(level_stream); - - level_editor->platforms_layer = - PUSH_LT( - lt, - create_rect_layer_from_line_stream(level_stream, "platform"), - destroy_rect_layer); - if (level_editor->platforms_layer == NULL) { - RETURN_LT(lt, NULL); - } - - level_editor->goals_layer = PUSH_LT( - lt, - create_point_layer_from_line_stream(level_stream), - destroy_point_layer); - if (level_editor->goals_layer == NULL) { - RETURN_LT(lt, NULL); - } - - level_editor->lava_layer = - PUSH_LT( - lt, - create_rect_layer_from_line_stream(level_stream, "lava"), - destroy_rect_layer); - if (level_editor->lava_layer == NULL) { - RETURN_LT(lt, NULL); - } - - level_editor->back_platforms_layer = - PUSH_LT( - lt, - create_rect_layer_from_line_stream(level_stream, "back_platform"), - destroy_rect_layer); - if (level_editor->back_platforms_layer == NULL) { - RETURN_LT(lt, NULL); - } + Memory tmpmem = { + .capacity = LEVEL_EDITOR_TMPMEM_CAPACITY, + .buffer = malloc(LEVEL_EDITOR_TMPMEM_CAPACITY), + }; + trace_assert(tmpmem.buffer); - level_editor->boxes_layer = - PUSH_LT( - lt, - create_rect_layer_from_line_stream(level_stream, "box"), - destroy_rect_layer); - if (level_editor->boxes_layer == NULL) { - RETURN_LT(lt, NULL); - } + String input = read_whole_file(&tmpmem, file_name); + trace_assert(input.data); - level_editor->label_layer = - PUSH_LT( - lt, - create_label_layer_from_line_stream(level_stream), - destroy_label_layer); - if (level_editor->label_layer == NULL) { - RETURN_LT(lt, NULL); - } + String version = trim(chop_by_delim(&input, '\n')); - level_editor->regions_layer = - PUSH_LT( - lt, - create_rect_layer_from_line_stream(level_stream, "region"), - destroy_rect_layer); - if (level_editor->regions_layer == NULL) { + if (string_equal(version, STRING_LIT("1"))) { + chop_by_delim(&input, '\n'); + } else if (string_equal(version, STRING_LIT("2"))) { + // Nothing + } else { + log_fail("Version `%s` is not supported. Expected version `%s`.\n", + string_to_cstr(&tmpmem, version), + VERSION); RETURN_LT(lt, NULL); } - level_editor->supa_script_source = - PUSH_LT( - lt, - line_stream_collect_until_end(level_stream), - free); - if (level_editor->supa_script_source == NULL) { - RETURN_LT(lt, NULL); - } - - level_editor->layers[LAYER_PICKER_BOXES] = rect_layer_as_layer(level_editor->boxes_layer); - level_editor->layers[LAYER_PICKER_PLATFORMS] = rect_layer_as_layer(level_editor->platforms_layer); - level_editor->layers[LAYER_PICKER_BACK_PLATFORMS] = rect_layer_as_layer(level_editor->back_platforms_layer); - level_editor->layers[LAYER_PICKER_GOALS] = point_layer_as_layer(level_editor->goals_layer); + level_editor->background_layer = chop_background_layer(&input); + level_editor->player_layer = chop_player_layer(&tmpmem, &input); + level_editor->platforms_layer = chop_rect_layer(&tmpmem, &input, "platform", cursor); + level_editor->goals_layer = chop_point_layer(&tmpmem, &input, "goal"); + level_editor->lava_layer = chop_rect_layer(&tmpmem, &input, "lava", cursor); + level_editor->back_platforms_layer = chop_rect_layer(&tmpmem, &input, "back_platform", cursor); + level_editor->boxes_layer = chop_rect_layer(&tmpmem, &input, "box", cursor); + level_editor->label_layer = chop_label_layer(&tmpmem, &input, "label"); + level_editor->regions_layer = chop_rect_layer(&tmpmem, &input, "region", cursor), + + level_editor->layers[LAYER_PICKER_BOXES] = rect_layer_as_layer(&level_editor->boxes_layer); + level_editor->layers[LAYER_PICKER_PLATFORMS] = rect_layer_as_layer(&level_editor->platforms_layer); + level_editor->layers[LAYER_PICKER_BACK_PLATFORMS] = rect_layer_as_layer(&level_editor->back_platforms_layer); + level_editor->layers[LAYER_PICKER_GOALS] = point_layer_as_layer(&level_editor->goals_layer); level_editor->layers[LAYER_PICKER_PLAYER] = player_layer_as_layer(&level_editor->player_layer); - level_editor->layers[LAYER_PICKER_LAVA] = rect_layer_as_layer(level_editor->lava_layer); - level_editor->layers[LAYER_PICKER_REGIONS] = rect_layer_as_layer(level_editor->regions_layer); + level_editor->layers[LAYER_PICKER_LAVA] = rect_layer_as_layer(&level_editor->lava_layer); + level_editor->layers[LAYER_PICKER_REGIONS] = rect_layer_as_layer(&level_editor->regions_layer); level_editor->layers[LAYER_PICKER_BACKGROUND] = background_layer_as_layer(&level_editor->background_layer); - level_editor->layers[LAYER_PICKER_LABELS] = label_layer_as_layer(level_editor->label_layer); + level_editor->layers[LAYER_PICKER_LABELS] = label_layer_as_layer(&level_editor->label_layer); level_editor->drag = false; @@ -301,6 +164,10 @@ LevelEditor *create_level_editor_from_file(const char *file_name) level_editor->camera_scale = 1.0f; + level_editor->undo_history = create_undo_history(); + + free(tmpmem.buffer); + return level_editor; } @@ -308,7 +175,13 @@ void destroy_level_editor(LevelEditor *level_editor) { trace_assert(level_editor); destroy_undo_history(level_editor->undo_history); - RETURN_LT0(level_editor->lt); + destroy_rect_layer(level_editor->boxes_layer); + destroy_rect_layer(level_editor->platforms_layer); + destroy_rect_layer(level_editor->back_platforms_layer); + destroy_point_layer(level_editor->goals_layer); + destroy_rect_layer(level_editor->lava_layer); + destroy_rect_layer(level_editor->regions_layer); + destroy_label_layer(level_editor->label_layer); } int level_editor_render(const LevelEditor *level_editor, @@ -321,6 +194,19 @@ int level_editor_render(const LevelEditor *level_editor, return -1; } + const Rect world_viewport = camera_view_port(camera); + + if (PLAYER_DEATH_LEVEL < world_viewport.y + world_viewport.h) { + if (camera_fill_rect( + camera, + rect( + world_viewport.x, PLAYER_DEATH_LEVEL, + world_viewport.w, world_viewport.h + fmaxf(0.0f, world_viewport.y - PLAYER_DEATH_LEVEL)), + LEVEL_EDITOR_DETH_LEVEL_COLOR) < 0) { + return -1; + } + } + for (size_t i = 0; i < LAYER_PICKER_N; ++i) { if (layer_render( level_editor->layers[i], @@ -336,38 +222,34 @@ int level_editor_render(const LevelEditor *level_editor, if (level_editor->state == LEVEL_EDITOR_SAVEAS) { /* CSS */ - const Point size = LEVEL_EDITOR_EDIT_FIELD_SIZE; + const Vec2f size = LEVEL_EDITOR_EDIT_FIELD_SIZE; const char *save_as_text = "Save as: "; - const Point position = vec(200.0f, 200.0f); + const Vec2f position = vec(200.0f, 200.0f); const float save_as_width = (float) strlen(save_as_text) * FONT_CHAR_WIDTH * size.x; /* HTML */ - if (camera_render_text_screen( - camera, - save_as_text, - LEVEL_EDITOR_EDIT_FIELD_SIZE, - LEVEL_EDITOR_EDIT_FIELD_COLOR, - position) < 0) { - return -1; - } + camera_render_text_screen( + camera, + save_as_text, + LEVEL_EDITOR_EDIT_FIELD_SIZE, + LEVEL_EDITOR_EDIT_FIELD_COLOR, + position); if (edit_field_render_screen( - level_editor->edit_field_filename, + &level_editor->edit_field_filename, camera, vec(position.x + save_as_width, position.y)) < 0) { return -1; } } - const Rect viewport = camera_view_port_screen(camera); - const Vec text_size = fading_wiggly_text_size( - &level_editor->notice, - camera); + const Rect screen_viewport = camera_view_port_screen(camera); + const Vec2f text_size = fading_wiggly_text_size(&level_editor->notice); fading_wiggly_text_render( &level_editor->notice, camera, - vec(viewport.w * 0.5f - text_size.x * 0.5f, + vec(screen_viewport.w * 0.5f - text_size.x * 0.5f, LEVEL_EDITOR_NOTICE_PADDING_TOP)); return 0; @@ -386,12 +268,15 @@ int level_editor_saveas_event(LevelEditor *level_editor, case SDL_KEYDOWN: { if (event->key.keysym.sym == SDLK_RETURN) { trace_assert(level_editor->file_name == NULL); + char path[LEVEL_FOLDER_MAX_LENGTH]; + snprintf( + path, + LEVEL_FOLDER_MAX_LENGTH, + "./assets/levels/%s.txt", + edit_field_as_text(&level_editor->edit_field_filename)); level_editor->file_name = PUSH_LT( level_editor->lt, - string_duplicate( - edit_field_as_text( - level_editor->edit_field_filename), - NULL), + string_duplicate(path, NULL), free); level_editor_dump(level_editor); SDL_StopTextInput(); @@ -401,7 +286,7 @@ int level_editor_saveas_event(LevelEditor *level_editor, } break; } - return edit_field_event(level_editor->edit_field_filename, event); + return edit_field_event(&level_editor->edit_field_filename, event); } static @@ -430,7 +315,9 @@ int level_editor_idle_event(LevelEditor *level_editor, case SDLK_z: { if (event->key.keysym.mod & KMOD_CTRL) { - log_info("Undo\n"); + if (undo_history_empty(&level_editor->undo_history)) { + level_editor->bell = 1; + } undo_history_pop(&level_editor->undo_history); } } break; @@ -441,14 +328,14 @@ int level_editor_idle_event(LevelEditor *level_editor, int x, y; SDL_GetMouseState(&x, &y); - Vec position = camera_map_screen(camera, x, y); + Vec2f position = camera_map_screen(camera, x, y); if (event->wheel.y > 0) { level_editor->camera_scale += 0.1f; } else if (event->wheel.y < 0) { level_editor->camera_scale = fmaxf(0.1f, level_editor->camera_scale - 0.1f); } camera_scale(camera, level_editor->camera_scale); - Vec zoomed_position = camera_map_screen(camera, x, y); + Vec2f zoomed_position = camera_map_screen(camera, x, y); level_editor->camera_position = vec_sum( @@ -470,8 +357,8 @@ int level_editor_idle_event(LevelEditor *level_editor, case SDL_MOUSEMOTION: { if (level_editor->drag) { - const Vec next_position = camera_map_screen(camera, event->motion.x, event->motion.y); - const Vec prev_position = camera_map_screen( + const Vec2f next_position = camera_map_screen(camera, event->motion.x, event->motion.y); + const Vec2f prev_position = camera_map_screen( camera, event->motion.x + event->motion.xrel, event->motion.y + event->motion.yrel); @@ -501,6 +388,8 @@ int level_editor_idle_event(LevelEditor *level_editor, &level_editor->undo_history) < 0) { return -1; } + } else { + level_editor->click = 1; } @@ -534,6 +423,18 @@ int level_editor_focus_camera(LevelEditor *level_editor, return 0; } +static LayerPicker level_format_layer_order[LAYER_PICKER_N] = { + LAYER_PICKER_BACKGROUND, + LAYER_PICKER_PLAYER, + LAYER_PICKER_PLATFORMS, + LAYER_PICKER_GOALS, + LAYER_PICKER_LAVA, + LAYER_PICKER_BACK_PLATFORMS, + LAYER_PICKER_BOXES, + LAYER_PICKER_LABELS, + LAYER_PICKER_REGIONS +}; + /* TODO(#904): LevelEditor does not check that the saved level file is modified by external program */ static int level_editor_dump(LevelEditor *level_editor) { @@ -544,23 +445,22 @@ static int level_editor_dump(LevelEditor *level_editor) fopen(level_editor->file_name, "w"), fclose_lt); - if (fprintf(filedump, "%s\n", level_metadata_title(level_editor->metadata)) < 0) { + if (fprintf(filedump, "%s\n", VERSION) < 0) { return -1; } for (size_t i = 0; i < LAYER_PICKER_N; ++i) { if (layer_dump_stream( - level_editor->layers[i], + level_editor->layers[level_format_layer_order[i]], filedump) < 0) { return -1; } } - fprintf(filedump, "%s", level_editor->supa_script_source); - fclose(RELEASE_LT(level_editor->lt, filedump)); fading_wiggly_text_reset(&level_editor->notice); + level_editor->save = 1; return 0; } @@ -569,3 +469,25 @@ int level_editor_update(LevelEditor *level_editor, float delta_time) { return fading_wiggly_text_update(&level_editor->notice, delta_time); } + +void level_editor_sound(LevelEditor *level_editor, Sound_samples *sound_samples) +{ + trace_assert(sound_samples); + + if (level_editor) { + if (level_editor->bell) { + level_editor->bell = 0; + sound_samples_play_sound(sound_samples, 2); + } + + if (level_editor->click) { + level_editor->click = 0; + sound_samples_play_sound(sound_samples, 3); + } + + if (level_editor->save) { + level_editor->save = 0; + sound_samples_play_sound(sound_samples, 4); + } + } +}