diff --git a/CMakeLists.txt b/CMakeLists.txt index 88e5b2662b..d9894579d9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -349,6 +349,7 @@ set(GAME_FILES ${PROJECT_SOURCE_DIR}/src/game/file.c ${PROJECT_SOURCE_DIR}/src/game/file_editor.c ${PROJECT_SOURCE_DIR}/src/game/file_io.c + ${PROJECT_SOURCE_DIR}/src/game/file_minimap.c ${PROJECT_SOURCE_DIR}/src/game/game.c ${PROJECT_SOURCE_DIR}/src/game/mission.c ${PROJECT_SOURCE_DIR}/src/game/orientation.c @@ -468,7 +469,6 @@ set(WIDGET_FILES ${PROJECT_SOURCE_DIR}/src/widget/map_editor.c ${PROJECT_SOURCE_DIR}/src/widget/map_editor_tool.c ${PROJECT_SOURCE_DIR}/src/widget/minimap.c - ${PROJECT_SOURCE_DIR}/src/widget/scenario_minimap.c ${PROJECT_SOURCE_DIR}/src/widget/top_menu.c ${PROJECT_SOURCE_DIR}/src/widget/top_menu_editor.c ${PROJECT_SOURCE_DIR}/src/widget/sidebar/city.c diff --git a/src/game/file.c b/src/game/file.c index ba749cc6cd..3c943647fd 100644 --- a/src/game/file.c +++ b/src/game/file.c @@ -188,6 +188,26 @@ static void initialize_scenario_data(const uint8_t *scenario_name) game_state_unpause(); } +static void load_empire_data(int is_custom_scenario, int empire_id) +{ + empire_load(is_custom_scenario, empire_id); + scenario_distant_battle_set_roman_travel_months(); + scenario_distant_battle_set_enemy_travel_months(); +} + +static int load_scenario_data(const char *scenario_file) +{ + if (!game_file_io_read_scenario(scenario_file)) { + return 0; + } + + trade_prices_reset(); + load_empire_data(1, scenario_empire_id()); + city_view_reset_orientation(); + return 1; +} + + static int load_custom_scenario(const uint8_t *scenario_name, const char *scenario_file) { if (!file_exists(scenario_file, NOT_LOCALIZED)) { @@ -195,18 +215,13 @@ static int load_custom_scenario(const uint8_t *scenario_name, const char *scenar } clear_scenario_data(); - game_file_load_scenario_data(scenario_file); + if (!load_scenario_data(scenario_file)) { + return 0; + } initialize_scenario_data(scenario_name); return 1; } -static void load_empire_data(int is_custom_scenario, int empire_id) -{ - empire_load(is_custom_scenario, empire_id); - scenario_distant_battle_set_roman_travel_months(); - scenario_distant_battle_set_enemy_travel_months(); -} - static void initialize_saved_game(void) { load_empire_data(scenario_is_custom(), scenario_empire_id()); @@ -332,21 +347,10 @@ int game_file_start_scenario(const char *scenario_file) uint8_t scenario_name[FILE_NAME_MAX]; encoding_from_utf8(scenario_file, scenario_name, FILE_NAME_MAX); file_remove_extension(scenario_name); + scenario_set_custom(2); return start_scenario(scenario_name, scenario_file); } -int game_file_load_scenario_data(const char *scenario_file) -{ - if (!game_file_io_read_scenario(scenario_file)) { - return 0; - } - - trade_prices_reset(); - load_empire_data(1, scenario_empire_id()); - city_view_reset_orientation(); - return 1; -} - int game_file_load_saved_game(const char *filename) { if (!game_file_io_read_saved_game(filename, 0)) { @@ -359,8 +363,6 @@ int game_file_load_saved_game(const char *filename) return 1; } - - int game_file_write_saved_game(const char *filename) { return game_file_io_write_saved_game(filename); diff --git a/src/game/file.h b/src/game/file.h index 1535b94b3c..1b4e7f90a0 100644 --- a/src/game/file.h +++ b/src/game/file.h @@ -17,13 +17,6 @@ int game_file_start_scenario_by_name(const uint8_t *scenario_name); */ int game_file_start_scenario(const char *scenario_file); -/** - * Load scenario data only, without starting it - * @param scenario_file File to load - * @return Boolean true on success, false on failure - */ -int game_file_load_scenario_data(const char *scenario_file); - /** * Load saved game * @param filename File to load diff --git a/src/game/file_io.c b/src/game/file_io.c index 6e43a52286..2da7b51ce4 100644 --- a/src/game/file_io.c +++ b/src/game/file_io.c @@ -22,6 +22,7 @@ #include "figure/name.h" #include "figure/route.h" #include "figure/trader.h" +#include "game/file_minimap.h" #include "game/time.h" #include "game/tutorial.h" #include "map/aqueduct.h" @@ -43,7 +44,6 @@ #include "scenario/invasion.h" #include "scenario/scenario.h" #include "sound/city.h" -#include "widget/scenario_minimap.h" #include #include @@ -528,6 +528,55 @@ int game_file_io_read_scenario(const char *filename) return 1; } +int game_file_io_read_scenario_info(const char *filename, scenario_info *info) +{ + init_scenario_data(); + FILE *fp = file_open(dir_get_file(filename, NOT_LOCALIZED), "rb"); + if (!fp) { + return 0; + } + for (int i = 0; i < scenario_data.num_pieces; i++) { + size_t read_size = fread(scenario_data.pieces[i].buf.data, 1, scenario_data.pieces[i].buf.size, fp); + if (read_size != scenario_data.pieces[i].buf.size) { + log_error("Unable to load scenario", filename, 0); + file_close(fp); + return 0; + } + } + file_close(fp); + + const scenario_state *state = &scenario_data.state; + + scenario_description_from_buffer(state->scenario, info->description); + info->image_id = scenario_image_id_from_buffer(state->scenario); + info->climate = scenario_climate_from_buffer(state->scenario); + info->total_invasions = scenario_invasions_from_buffer(state->scenario); + info->player_rank = scenario_rank_from_buffer(state->scenario); + info->start_year = scenario_start_year_from_buffer(state->scenario); + scenario_open_play_info_from_buffer(state->scenario, &info->is_open_play, &info->open_play_id); + + if (!info->is_open_play) { + scenario_objectives_from_buffer(state->scenario, &info->win_criteria); + } + + file_buffers minimap_buffers; + minimap_buffers.buildings = 0; + minimap_buffers.map_building = 0; + minimap_buffers.map_bitfields = state->bitfields; + minimap_buffers.map_terrain = state->terrain; + minimap_buffers.map_edge = state->edge; + minimap_buffers.map_random = state->random; + minimap_buffers.climate = info->climate; + + scenario_map_data_from_buffer(state->scenario, &minimap_buffers.grid_width, &minimap_buffers.grid_height, + &minimap_buffers.grid_start, &minimap_buffers.grid_border_size); + + info->minimap_image = game_file_minimap_create(&minimap_buffers); + info->map_size = minimap_buffers.grid_width; + + return 1; +} + int game_file_io_write_scenario(const char *filename) { log_info("Saving scenario", filename, 0); @@ -688,7 +737,7 @@ static int savegame_read_file_info(FILE *fp, saved_game_info *info) init_file_piece(&building_grid, 52488, 0); init_file_piece(&buildings, 256000, 0); - minimap_save_buffers minimap_buffers; + file_buffers minimap_buffers; minimap_buffers.map_terrain = &terrain_grid.buf; minimap_buffers.map_random = &random_grid.buf; minimap_buffers.map_edge = &edge_grid.buf; @@ -793,8 +842,7 @@ static int savegame_read_file_info(FILE *fp, saved_game_info *info) scenario_map_data_from_buffer(&scenario.buf, &minimap_buffers.grid_width, &minimap_buffers.grid_height, &minimap_buffers.grid_start, &minimap_buffers.grid_border_size); - info->minimap_image = widget_scenario_minimap_draw_from_save(&minimap_buffers, - &info->minimap_image_width, &info->minimap_image_height); + info->minimap_image = game_file_minimap_create(&minimap_buffers); free_file_piece(&city_data); free_file_piece(&game_time); diff --git a/src/game/file_io.h b/src/game/file_io.h index 471b464ebe..ea245db43f 100644 --- a/src/game/file_io.h +++ b/src/game/file_io.h @@ -2,6 +2,7 @@ #define GAME_FILE_IO_H #include "graphics/color.h" +#include "scenario/data.h" typedef struct { int mission; @@ -11,12 +12,26 @@ typedef struct { int month; int year; const color_t *minimap_image; - int minimap_image_width; - int minimap_image_height; } saved_game_info; +typedef struct { + uint8_t description[MAX_BRIEF_DESCRIPTION]; + int image_id; + int start_year; + int climate; + int map_size; + int total_invasions; + int player_rank; + int is_open_play; + int open_play_id; + scenario_win_criteria win_criteria; + const color_t *minimap_image; +} scenario_info; + int game_file_io_read_scenario(const char *filename); +int game_file_io_read_scenario_info(const char *filename, scenario_info *info); + int game_file_io_write_scenario(const char *filename); int game_file_io_read_saved_game(const char *filename, int offset); diff --git a/src/widget/scenario_minimap.c b/src/game/file_minimap.c similarity index 54% rename from src/widget/scenario_minimap.c rename to src/game/file_minimap.c index 0151d6de49..6d882e6e3c 100644 --- a/src/widget/scenario_minimap.c +++ b/src/game/file_minimap.c @@ -1,4 +1,4 @@ -#include "scenario_minimap.h" +#include "file_minimap.h" #include "building/building.h" #include "city/view.h" @@ -12,8 +12,7 @@ #include "map/terrain.h" #include "scenario/property.h" -#define MINIMAP_SAVE_WIDTH 266 -#define MINIMAP_SAVE_HEIGHT 272 +#include typedef struct { color_t left; @@ -29,8 +28,6 @@ typedef struct { tile_color road; } tile_color_set; -static const minimap_save_buffers *minimap_buffers; - // Since the minimap tiles are only 25 color sets per climate, we just hardcode them. // This "hack" is necessary to avoid reloading the climate graphics when selecting // a scenario with another climate in the CCK selection screen, which is expensive. @@ -73,110 +70,46 @@ const tile_color_set MINIMAP_COLOR_SETS[3] = { } }; +#define MINIMAP_WIDTH_TILES (FILE_MINIMAP_IMAGE_WIDTH / 2) +#define MINIMAP_HEIGHT_TILES FILE_MINIMAP_IMAGE_HEIGHT +#define MINIMAP_X_OFFSET ((VIEW_X_MAX - MINIMAP_WIDTH_TILES) / 2) +#define MINIMAP_Y_OFFSET (((VIEW_Y_MAX - MINIMAP_HEIGHT_TILES) / 2) & ~1) // ensure even height + static struct { - int absolute_x; - int absolute_y; - int width_tiles; - int height_tiles; - int x_offset; - int y_offset; + color_t screen[FILE_MINIMAP_IMAGE_WIDTH * FILE_MINIMAP_IMAGE_HEIGHT]; + color_t dst[FILE_MINIMAP_IMAGE_WIDTH * FILE_MINIMAP_IMAGE_HEIGHT]; + const file_buffers *buffers; } data; -static void foreach_map_tile(map_callback *callback) -{ - city_view_foreach_minimap_tile( - data.x_offset, data.y_offset, data.absolute_x, data.absolute_y, - data.width_tiles, data.height_tiles, callback); -} - -static void set_bounds(int x_offset, int y_offset, int width, int height) -{ - data.width_tiles = width / 2; - data.height_tiles = height; - data.x_offset = x_offset; - data.y_offset = y_offset; - data.absolute_x = (VIEW_X_MAX - data.width_tiles) / 2; - data.absolute_y = (VIEW_Y_MAX - data.height_tiles) / 2; - - // ensure even height - data.absolute_y &= ~1; -} - static void draw_minimap_tile(int x_view, int y_view, int grid_offset) { if (grid_offset < 0) { return; } - int terrain = map_terrain_get(grid_offset); - - if (terrain & TERRAIN_BUILDING) { - // Native huts/fields - if (map_property_is_draw_tile(grid_offset)) { - int image_id = image_group(GROUP_MINIMAP_BUILDING); - switch (map_property_multi_tile_size(grid_offset)) { - case 1: image_draw(image_id, x_view, y_view); break; - case 2: image_draw(image_id + 1, x_view, y_view - 1); break; - } - } - } else { - int rand = map_random_get(grid_offset); - const tile_color *color; - const tile_color_set *set = &MINIMAP_COLOR_SETS[scenario_property_climate()]; - if (terrain & TERRAIN_WATER) { - color = &set->water[rand & 3]; - } else if (terrain & (TERRAIN_SHRUB | TERRAIN_TREE)) { - color = &set->tree[rand & 3]; - } else if (terrain & (TERRAIN_ROCK | TERRAIN_ELEVATION)) { - color = &set->rock[rand & 3]; - } else if (terrain & TERRAIN_ROAD) { - color = &set->road; - } else if (terrain & TERRAIN_MEADOW) { - color = &set->meadow[rand & 3]; - } else { - color = &set->grass[rand & 7]; - } - graphics_draw_vertical_line(x_view, y_view, y_view, color->left); - graphics_draw_vertical_line(x_view + 1, y_view, y_view, color->right); - } -} - -void widget_scenario_minimap_draw(int x_offset, int y_offset, int width, int height) -{ - set_bounds(x_offset, y_offset, width + 2, height); - graphics_set_clip_rectangle(x_offset, y_offset, width, height); - foreach_map_tile(draw_minimap_tile); - graphics_reset_clip_rectangle(); -} - -static void draw_minimap_tile_from_save(int x_view, int y_view, int grid_offset) -{ - if (grid_offset < 0) { - return; - } - - int terrain = map_terrain_get_from_buffer(minimap_buffers->map_terrain, grid_offset); + int terrain = map_terrain_get_from_buffer(data.buffers->map_terrain, grid_offset); building b; // exception for fort ground: display as empty land - if (terrain & TERRAIN_BUILDING) { - building_get_from_buffer(minimap_buffers->buildings, - map_building_from_buffer(minimap_buffers->map_building, grid_offset), &b); + if (terrain & TERRAIN_BUILDING && data.buffers->buildings) { + building_get_from_buffer(data.buffers->buildings, + map_building_from_buffer(data.buffers->map_building, grid_offset), &b); if (b.type == BUILDING_FORT_GROUND) { terrain = 0; } } if (terrain & TERRAIN_BUILDING) { - if (map_property_is_draw_tile_from_buffer(minimap_buffers->map_edge, grid_offset)) { + // For scenarios these can be Native huts/fields + if (map_property_is_draw_tile_from_buffer(data.buffers->map_edge, grid_offset)) { int image_id; - if (b.house_size) { + if (data.buffers->buildings && b.house_size) { image_id = image_group(GROUP_MINIMAP_HOUSE); - } else if (b.type == BUILDING_RESERVOIR) { + } else if (data.buffers->buildings && b.type == BUILDING_RESERVOIR) { image_id = image_group(GROUP_MINIMAP_AQUEDUCT) - 1; } else { image_id = image_group(GROUP_MINIMAP_BUILDING); } - switch (map_property_multi_tile_size_from_buffer(minimap_buffers->map_bitfields, grid_offset)) { + switch (map_property_multi_tile_size_from_buffer(data.buffers->map_bitfields, grid_offset)) { case 1: image_draw(image_id, x_view, y_view); break; case 2: image_draw(image_id + 1, x_view, y_view - 1); break; case 3: image_draw(image_id + 2, x_view, y_view - 2); break; @@ -189,9 +122,9 @@ static void draw_minimap_tile_from_save(int x_view, int y_view, int grid_offset) } else if (terrain & TERRAIN_WALL) { image_draw(image_group(GROUP_MINIMAP_WALL), x_view, y_view); } else { - int rand = map_random_get_from_buffer(minimap_buffers->map_random, grid_offset); + int rand = map_random_get_from_buffer(data.buffers->map_random, grid_offset); const tile_color *color; - const tile_color_set *set = &MINIMAP_COLOR_SETS[minimap_buffers->climate]; + const tile_color_set *set = &MINIMAP_COLOR_SETS[data.buffers->climate]; if (terrain & TERRAIN_WATER) { color = &set->water[rand & 3]; } else if (terrain & (TERRAIN_SHRUB | TERRAIN_TREE)) { @@ -210,30 +143,21 @@ static void draw_minimap_tile_from_save(int x_view, int y_view, int grid_offset) } } -const color_t *widget_scenario_minimap_draw_from_save(const minimap_save_buffers *buffers, int *width, int *height) +const color_t *game_file_minimap_create(const file_buffers *buffers) { - *width = 0; - *height = 0; - - minimap_buffers = buffers; - - static color_t screen[MINIMAP_SAVE_WIDTH * MINIMAP_SAVE_HEIGHT]; - static color_t dst[MINIMAP_SAVE_WIDTH * MINIMAP_SAVE_HEIGHT]; + data.buffers = buffers; - graphics_save_to_buffer(0, 0, MINIMAP_SAVE_WIDTH, MINIMAP_SAVE_HEIGHT, screen); - graphics_fill_rect(0, 0, MINIMAP_SAVE_WIDTH, MINIMAP_SAVE_HEIGHT, 0); - graphics_set_clip_rectangle(0, 0, MINIMAP_SAVE_WIDTH, MINIMAP_SAVE_HEIGHT); - set_bounds(0, 0, MINIMAP_SAVE_WIDTH, MINIMAP_SAVE_HEIGHT); + graphics_save_to_buffer(0, 0, FILE_MINIMAP_IMAGE_WIDTH, FILE_MINIMAP_IMAGE_HEIGHT, data.screen); + graphics_fill_rect(0, 0, FILE_MINIMAP_IMAGE_WIDTH, FILE_MINIMAP_IMAGE_HEIGHT, 0); city_view_set_custom_lookup(buffers->grid_start, buffers->grid_width, buffers->grid_height, buffers->grid_border_size); - foreach_map_tile(draw_minimap_tile_from_save); - city_view_restore_lookup(); + city_view_foreach_minimap_tile(0, 0, MINIMAP_X_OFFSET, MINIMAP_Y_OFFSET, + MINIMAP_WIDTH_TILES, MINIMAP_HEIGHT_TILES, draw_minimap_tile); + graphics_set_clip_rectangle(0, 0, FILE_MINIMAP_IMAGE_WIDTH, FILE_MINIMAP_IMAGE_HEIGHT); graphics_reset_clip_rectangle(); - graphics_save_to_buffer(0, 0, MINIMAP_SAVE_WIDTH, MINIMAP_SAVE_HEIGHT, dst); - graphics_draw_from_buffer(0, 0, MINIMAP_SAVE_WIDTH, MINIMAP_SAVE_HEIGHT, screen); - - *width = MINIMAP_SAVE_WIDTH; - *height = MINIMAP_SAVE_HEIGHT; + city_view_restore_lookup(); + graphics_save_to_buffer(0, 0, FILE_MINIMAP_IMAGE_WIDTH, FILE_MINIMAP_IMAGE_HEIGHT, data.dst); + graphics_draw_from_buffer(0, 0, FILE_MINIMAP_IMAGE_WIDTH, FILE_MINIMAP_IMAGE_HEIGHT, data.screen); - return dst; + return data.dst; } diff --git a/src/game/file_minimap.h b/src/game/file_minimap.h new file mode 100644 index 0000000000..03ac16baf9 --- /dev/null +++ b/src/game/file_minimap.h @@ -0,0 +1,26 @@ +#ifndef GAME_FILE_MINIMAP_H +#define GAME_FILE_MINIMAP_H + +#include "core/buffer.h" +#include "graphics/color.h" + +#define FILE_MINIMAP_IMAGE_WIDTH 324 +#define FILE_MINIMAP_IMAGE_HEIGHT 324 + +typedef struct { + buffer *map_terrain; + buffer *map_bitfields; + buffer *map_edge; + buffer *map_random; + buffer *map_building; + buffer *buildings; + int climate; + int grid_width; + int grid_height; + int grid_start; + int grid_border_size; +} file_buffers; + +const color_t *game_file_minimap_create(const file_buffers *buffers); + +#endif // GAME_FILE_MINIMAP_H diff --git a/src/scenario/data.h b/src/scenario/data.h index 80c6dad9a7..95a803dd80 100644 --- a/src/scenario/data.h +++ b/src/scenario/data.h @@ -123,6 +123,25 @@ typedef struct { int is_rise; } demand_change_t; +typedef struct { + struct win_criteria_t population; + struct win_criteria_t culture; + struct win_criteria_t prosperity; + struct win_criteria_t peace; + struct win_criteria_t favor; + struct { + int enabled; + int years; + } time_limit; + struct { + int enabled; + int years; + } survival_time; + int milestone25_year; + int milestone50_year; + int milestone75_year; +} scenario_win_criteria; + extern struct scenario_t { uint8_t scenario_name[MAX_SCENARIO_NAME]; @@ -141,24 +160,7 @@ extern struct scenario_t { int is_open_play; int open_play_scenario_id; - struct { - struct win_criteria_t population; - struct win_criteria_t culture; - struct win_criteria_t prosperity; - struct win_criteria_t peace; - struct win_criteria_t favor; - struct { - int enabled; - int years; - } time_limit; - struct { - int enabled; - int years; - } survival_time; - int milestone25_year; - int milestone50_year; - int milestone75_year; - } win_criteria; + scenario_win_criteria win_criteria; struct { int id; diff --git a/src/scenario/scenario.c b/src/scenario/scenario.c index 615ba633eb..c1b9fcc0eb 100644 --- a/src/scenario/scenario.c +++ b/src/scenario/scenario.c @@ -437,12 +437,77 @@ void scenario_load_state(buffer *buf) scenario.is_saved = 1; } +void scenario_description_from_buffer(buffer *buf, uint8_t *description) +{ + buffer_set(buf, 404); + buffer_read_raw(buf, description, MAX_BRIEF_DESCRIPTION); +} + int scenario_climate_from_buffer(buffer *buf) { buffer_set(buf, 1704); return buffer_read_u8(buf); } +int scenario_invasions_from_buffer(buffer *buf) +{ + buffer_set(buf, 214); + int num_invasions = 0; + for (int i = 0; i < MAX_INVASIONS; i++) { + if (buffer_read_i16(buf)) { + num_invasions++; + } + } + return num_invasions; +} + +int scenario_image_id_from_buffer(buffer *buf) +{ + buffer_set(buf, 1010); + return buffer_read_i16(buf); +} + +int scenario_rank_from_buffer(buffer *buf) +{ + buffer_set(buf, 1014); + return buffer_read_i16(buf); + +} + +void scenario_open_play_info_from_buffer(buffer *buf, int *is_open_play, int *open_play_id) +{ + buffer_set(buf, 1012); + *is_open_play = buffer_read_i16(buf); + buffer_set(buf, 1718); + *open_play_id = buffer_read_u8(buf); +} + +int scenario_start_year_from_buffer(buffer *buf) +{ + buffer_set(buf, 0); + return buffer_read_i16(buf); +} + +void scenario_objectives_from_buffer(buffer *buf, scenario_win_criteria *win_criteria) +{ + buffer_set(buf, 1572); + win_criteria->culture.goal = buffer_read_i32(buf); + win_criteria->prosperity.goal = buffer_read_i32(buf); + win_criteria->peace.goal = buffer_read_i32(buf); + win_criteria->favor.goal = buffer_read_i32(buf); + win_criteria->culture.enabled = buffer_read_u8(buf); + win_criteria->prosperity.enabled = buffer_read_u8(buf); + win_criteria->peace.enabled = buffer_read_u8(buf); + win_criteria->favor.enabled = buffer_read_u8(buf); + win_criteria->time_limit.enabled = buffer_read_i32(buf); + win_criteria->time_limit.years = buffer_read_i32(buf); + win_criteria->survival_time.enabled = buffer_read_i32(buf); + win_criteria->survival_time.years = buffer_read_i32(buf); + buffer_skip(buf, 8); + win_criteria->population.enabled = buffer_read_i32(buf); + win_criteria->population.goal = buffer_read_i32(buf); +} + void scenario_map_data_from_buffer(buffer *buf, int *width, int *height, int *grid_start, int *grid_border_size) { buffer_set(buf, 388); diff --git a/src/scenario/scenario.h b/src/scenario/scenario.h index 19b3ac21db..6a0154f016 100644 --- a/src/scenario/scenario.h +++ b/src/scenario/scenario.h @@ -2,6 +2,7 @@ #define SCENARIO_SCENARIO_H #include "core/buffer.h" +#include "scenario/data.h" int scenario_is_saved(void); @@ -13,8 +14,14 @@ void scenario_save_state(buffer *buf); void scenario_load_state(buffer *buf); +void scenario_description_from_buffer(buffer *buf, uint8_t *description); int scenario_climate_from_buffer(buffer *buf); - +int scenario_image_id_from_buffer(buffer *buf); +int scenario_invasions_from_buffer(buffer *buf); +int scenario_rank_from_buffer(buffer *buf); +int scenario_start_year_from_buffer(buffer *buf); +void scenario_open_play_info_from_buffer(buffer *buf, int *is_open_play, int *open_play_id); +void scenario_objectives_from_buffer(buffer *buf, scenario_win_criteria *win_criteria); void scenario_map_data_from_buffer(buffer *buf, int *width, int *height, int *grid_start, int *grid_border_size); void scenario_settings_save_state( diff --git a/src/widget/minimap.c b/src/widget/minimap.c index 06186d6756..62bd12df4f 100644 --- a/src/widget/minimap.c +++ b/src/widget/minimap.c @@ -5,6 +5,7 @@ #include "core/buffer.h" #include "figure/figure.h" #include "figure/formation.h" +#include "game/file_minimap.h" #include "graphics/graphics.h" #include "graphics/image.h" #include "map/building.h" @@ -308,6 +309,19 @@ void widget_minimap_draw(int x_offset, int y_offset, int width, int height, int } } +void widget_minimap_draw_from_buffer(int x, int y, int width, int height, const color_t *buffer) +{ + int x_offset = (FILE_MINIMAP_IMAGE_WIDTH - width) / 2; + int y_offset = (FILE_MINIMAP_IMAGE_HEIGHT - height) / 2; + + const color_t *dst = buffer + y_offset * FILE_MINIMAP_IMAGE_WIDTH + x_offset; + + for (int i = 0; i < height; i++) { + graphics_blend_from_buffer(x, y + i, width, 1, dst); + dst += FILE_MINIMAP_IMAGE_WIDTH; + } +} + static void update_mouse_grid_offset(int x_view, int y_view, int grid_offset) { if (data.mouse.y == y_view && (data.mouse.x == x_view || data.mouse.x == x_view + 1)) { diff --git a/src/widget/minimap.h b/src/widget/minimap.h index 608baf0321..e8ade0a039 100644 --- a/src/widget/minimap.h +++ b/src/widget/minimap.h @@ -1,12 +1,15 @@ #ifndef WIDGET_MINIMAP_H #define WIDGET_MINIMAP_H +#include "graphics/color.h" #include "input/mouse.h" void widget_minimap_invalidate(void); void widget_minimap_draw(int x_offset, int y_offset, int width, int height, int force); +void widget_minimap_draw_from_buffer(int x, int y, int width, int height, const color_t *buffer); + int widget_minimap_handle_mouse(const mouse *m); #endif // WIDGET_MINIMAP_H diff --git a/src/widget/scenario_minimap.h b/src/widget/scenario_minimap.h deleted file mode 100644 index a304818f88..0000000000 --- a/src/widget/scenario_minimap.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef WIDGET_SCENARIO_MINIMAP_H -#define WIDGET_SCENARIO_MINIMAP_H - -#include "core/buffer.h" -#include "graphics/color.h" - -typedef struct { - buffer *map_terrain; - buffer *map_bitfields; - buffer *map_edge; - buffer *map_random; - buffer *map_building; - buffer *buildings; - int climate; - int grid_width; - int grid_height; - int grid_start; - int grid_border_size; -} minimap_save_buffers; - -void widget_scenario_minimap_draw(int x_offset, int y_offset, int width, int height); - -const color_t *widget_scenario_minimap_draw_from_save(const minimap_save_buffers *buffers, int *width, int *height); - -#endif // WIDGET_SCENARIO_MINIMAP_H diff --git a/src/window/cck_selection.c b/src/window/cck_selection.c index 1bac2148ff..3ee1845e7e 100644 --- a/src/window/cck_selection.c +++ b/src/window/cck_selection.c @@ -5,6 +5,7 @@ #include "core/file.h" #include "core/image_group.h" #include "game/file.h" +#include "game/file_io.h" #include "graphics/generic_button.h" #include "graphics/graphics.h" #include "graphics/image.h" @@ -15,12 +16,8 @@ #include "graphics/text.h" #include "graphics/window.h" #include "input/input.h" -#include "scenario/criteria.h" -#include "scenario/invasion.h" -#include "scenario/map.h" -#include "scenario/property.h" #include "sound/music.h" -#include "widget/scenario_minimap.h" +#include "widget/minimap.h" #include "window/city.h" #include @@ -65,13 +62,13 @@ static struct { int show_minimap; char selected_scenario_filename[FILE_NAME_MAX]; uint8_t selected_scenario_display[FILE_NAME_MAX]; + scenario_info info; const dir_listing *scenarios; } data; static void init(void) { - scenario_set_custom(2); data.scenarios = dir_find_files_with_extension("map"); data.focus_button_id = 0; data.focus_toggle_button = 0; @@ -106,32 +103,33 @@ static void draw_scenario_info(void) const int scenario_info_width = 280; const int scenario_criteria_x = 420; - image_draw(image_group(GROUP_SCENARIO_IMAGE) + scenario_image_id(), 78, 36); + image_draw(image_group(GROUP_SCENARIO_IMAGE) + data.info.image_id, 78, 36); text_ellipsize(data.selected_scenario_display, FONT_LARGE_BLACK, scenario_info_width + 10); text_draw_centered(data.selected_scenario_display, scenario_info_x, 25, scenario_info_width + 10, FONT_LARGE_BLACK, 0); - text_draw_centered(scenario_brief_description(), scenario_info_x, 60, scenario_info_width, FONT_NORMAL_WHITE, 0); - lang_text_draw_year(scenario_property_start_year(), scenario_criteria_x, 90, FONT_LARGE_BLACK); + text_draw_centered(data.info.description, scenario_info_x, 60, scenario_info_width, FONT_NORMAL_WHITE, 0); + lang_text_draw_year(data.info.start_year, scenario_criteria_x, 90, FONT_LARGE_BLACK); if (data.show_minimap) { - widget_scenario_minimap_draw(332, 119, 286, 300); + widget_minimap_draw_from_buffer(332, 119, 286, 300, data.info.minimap_image); // minimap button: draw mission instructions image image_draw(image_group(GROUP_SIDEBAR_BRIEFING_ROTATE_BUTTONS), toggle_minimap_button.x + 3, toggle_minimap_button.y + 3); } else { // minimap button: draw minimap - widget_scenario_minimap_draw( + widget_minimap_draw_from_buffer( toggle_minimap_button.x + 3, toggle_minimap_button.y + 3, - toggle_minimap_button.width - 6, toggle_minimap_button.height - 6 + toggle_minimap_button.width - 6, toggle_minimap_button.height - 6, + data.info.minimap_image ); - lang_text_draw_centered(44, 77 + scenario_property_climate(), + lang_text_draw_centered(44, 77 + data.info.climate, scenario_info_x, 150, scenario_info_width, FONT_NORMAL_BLACK); // map size int text_id; - switch (scenario_map_size()) { + switch (data.info.map_size) { case 40: text_id = 121; break; case 60: text_id = 122; break; case 80: text_id = 123; break; @@ -142,7 +140,7 @@ static void draw_scenario_info(void) lang_text_draw_centered(44, text_id, scenario_info_x, 170, scenario_info_width, FONT_NORMAL_BLACK); // military - int num_invasions = scenario_invasion_count(); + int num_invasions = data.info.total_invasions; if (num_invasions <= 0) { text_id = 112; } else if (num_invasions <= 2) { @@ -156,48 +154,48 @@ static void draw_scenario_info(void) } lang_text_draw_centered(44, text_id, scenario_info_x, 190, scenario_info_width, FONT_NORMAL_BLACK); - lang_text_draw_centered(32, 11 + scenario_property_player_rank(), + lang_text_draw_centered(32, 11 + data.info.player_rank, scenario_info_x, 210, scenario_info_width, FONT_NORMAL_BLACK); - if (scenario_is_open_play()) { - if (scenario_open_play_id() < 12) { - lang_text_draw_multiline(145, scenario_open_play_id(), + if (data.info.is_open_play) { + if (data.info.open_play_id < 12) { + lang_text_draw_multiline(145, data.info.open_play_id, scenario_info_x + 10, 270, scenario_info_width - 10, FONT_NORMAL_BLACK); } } else { lang_text_draw_centered(44, 127, scenario_info_x, 262, scenario_info_width, FONT_NORMAL_BLACK); int width; - if (scenario_criteria_culture_enabled()) { - width = text_draw_number(scenario_criteria_culture(), '@', " ", + if (data.info.win_criteria.culture.enabled) { + width = text_draw_number(data.info.win_criteria.culture.goal, '@', " ", scenario_criteria_x, 290, FONT_NORMAL_BLACK); lang_text_draw(44, 129, scenario_criteria_x + width, 290, FONT_NORMAL_BLACK); } - if (scenario_criteria_prosperity_enabled()) { - width = text_draw_number(scenario_criteria_prosperity(), '@', " ", + if (data.info.win_criteria.prosperity.enabled) { + width = text_draw_number(data.info.win_criteria.prosperity.goal, '@', " ", scenario_criteria_x, 306, FONT_NORMAL_BLACK); lang_text_draw(44, 130, scenario_criteria_x + width, 306, FONT_NORMAL_BLACK); } - if (scenario_criteria_peace_enabled()) { - width = text_draw_number(scenario_criteria_peace(), '@', " ", + if (data.info.win_criteria.peace.enabled) { + width = text_draw_number(data.info.win_criteria.peace.goal, '@', " ", scenario_criteria_x, 322, FONT_NORMAL_BLACK); lang_text_draw(44, 131, scenario_criteria_x + width, 322, FONT_NORMAL_BLACK); } - if (scenario_criteria_favor_enabled()) { - width = text_draw_number(scenario_criteria_favor(), '@', " ", + if (data.info.win_criteria.favor.enabled) { + width = text_draw_number(data.info.win_criteria.favor.goal, '@', " ", scenario_criteria_x, 338, FONT_NORMAL_BLACK); lang_text_draw(44, 132, scenario_criteria_x + width, 338, FONT_NORMAL_BLACK); } - if (scenario_criteria_population_enabled()) { - width = text_draw_number(scenario_criteria_population(), '@', " ", + if (data.info.win_criteria.population.enabled) { + width = text_draw_number(data.info.win_criteria.population.goal, '@', " ", scenario_criteria_x, 354, FONT_NORMAL_BLACK); lang_text_draw(44, 133, scenario_criteria_x + width, 354, FONT_NORMAL_BLACK); } - if (scenario_criteria_time_limit_enabled()) { - width = text_draw_number(scenario_criteria_time_limit_years(), '@', " ", + if (data.info.win_criteria.time_limit.enabled) { + width = text_draw_number(data.info.win_criteria.time_limit.years, '@', " ", scenario_criteria_x, 370, FONT_NORMAL_BLACK); lang_text_draw(44, 134, scenario_criteria_x + width, 370, FONT_NORMAL_BLACK); } - if (scenario_criteria_survival_enabled()) { - width = text_draw_number(scenario_criteria_survival_years(), '@', " ", + if (data.info.win_criteria.survival_time.enabled) { + width = text_draw_number(data.info.win_criteria.survival_time.years, '@', " ", scenario_criteria_x, 386, FONT_NORMAL_BLACK); lang_text_draw(44, 135, scenario_criteria_x + width, 386, FONT_NORMAL_BLACK); } @@ -260,7 +258,7 @@ static void button_select_item(int index, int param2) } data.selected_item = scrollbar.scroll_position + index; strcpy(data.selected_scenario_filename, data.scenarios->files[data.selected_item]); - game_file_load_scenario_data(data.selected_scenario_filename); + game_file_io_read_scenario_info(data.selected_scenario_filename, &data.info); encoding_from_utf8(data.selected_scenario_filename, data.selected_scenario_display, FILE_NAME_MAX); file_remove_extension(data.selected_scenario_display); window_invalidate(); diff --git a/src/window/file_dialog.c b/src/window/file_dialog.c index fa3a92b353..6a5ee053c2 100644 --- a/src/window/file_dialog.c +++ b/src/window/file_dialog.c @@ -24,6 +24,7 @@ #include "platform/file_manager.h" #include "translation/translation.h" #include "widget/input_box.h" +#include "widget/minimap.h" #include "window/city.h" #include "window/editor/map.h" @@ -245,8 +246,7 @@ static void draw_foreground(void) 500, 396, 108, FONT_NORMAL_BLACK, 0); text_draw(translation_for(TR_SAVE_DIALOG_POPULATION), 362, 416, FONT_NORMAL_BLACK, 0); text_draw_number(data.info.population, '\0', "", 500, 416, FONT_NORMAL_BLACK); - graphics_blend_from_buffer(352, 80, - data.info.minimap_image_width, data.info.minimap_image_height, data.info.minimap_image); + widget_minimap_draw_from_buffer(352, 80, 266, 272, data.info.minimap_image); } else { text_draw_centered(translation_for(TR_SAVE_DIALOG_INVALID_FILE), 362, 241, 246, FONT_LARGE_BLACK, 0); } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index cccbbca6e2..08820e7316 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -20,6 +20,8 @@ except_file(TEST_CORE_FILES "core/image.c" ${CORE_FILES}) except_file(TEST_CORE_FILES "core/lang.c" ${TEST_CORE_FILES}) except_file(TEST_CORE_FILES "core/speed.c" ${TEST_CORE_FILES}) except_file(TEST_BUILDING_FILES "building/model.c" ${BUILDING_FILES}) +except_file(TEST_GAME_FILES "game/file_minimap.c" ${GAME_FILES}) + add_executable(translationcheck translation/check.c @@ -53,11 +55,11 @@ add_executable(autopilot ${PROJECT_SOURCE_DIR}/src/platform/file_manager.c ${TEST_CORE_FILES} ${TEST_BUILDING_FILES} + ${TEST_GAME_FILES} ${CITY_FILES} ${EMPIRE_FILES} ${FIGURE_FILES} ${FIGURETYPE_FILES} - ${GAME_FILES} ${MAP_FILES} ${SCENARIO_FILES} ${SOUND_FILES} diff --git a/test/stub/ui.c b/test/stub/ui.c index 735f9675f9..0bec9f9d88 100644 --- a/test/stub/ui.c +++ b/test/stub/ui.c @@ -58,7 +58,7 @@ void window_popup_dialog_show(popup_dialog_type type, void (*okFunc)(int), int h void widget_minimap_invalidate(void) {} -const void *widget_scenario_minimap_draw_from_save(const void *buffers, int *width, int *height) +const void *game_file_minimap_create(const void *buffers) { return 0; }