Skip to content

Commit

Permalink
Add a campaign mission selection window
Browse files Browse the repository at this point in the history
- The window will only show campaign scenarios up to the current mission being played. If a campaign hasn't been played the scenario selection screen won't be available.
- This does not apply to the original campaign, which will have all missions available to choose. The rationale is, everyone has probably already finished the campaign anyway.
- The "new campaign" window will indicate whether a campaign was finished or is in progress.

Also fix some code bugs and refactor the xml exporter a bit.
  • Loading branch information
crudelios committed Sep 25, 2024
1 parent 9f71f3f commit 63ff254
Show file tree
Hide file tree
Showing 30 changed files with 1,302 additions and 406 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ set(CAMPAIGN_FILES
${PROJECT_SOURCE_DIR}/src/campaign/campaign.c
${PROJECT_SOURCE_DIR}/src/campaign/file.c
${PROJECT_SOURCE_DIR}/src/campaign/mission.c
${PROJECT_SOURCE_DIR}/src/campaign/player_data.c
${PROJECT_SOURCE_DIR}/src/campaign/xml.c
)
set(CITY_FILES
Expand Down Expand Up @@ -642,6 +643,7 @@ set(WINDOW_FILES
${PROJECT_SOURCE_DIR}/src/window/military_menu.c
${PROJECT_SOURCE_DIR}/src/window/mission_briefing.c
${PROJECT_SOURCE_DIR}/src/window/mission_end.c
${PROJECT_SOURCE_DIR}/src/window/mission_list.c
${PROJECT_SOURCE_DIR}/src/window/mission_selection.c
${PROJECT_SOURCE_DIR}/src/window/new_campaign.c
${PROJECT_SOURCE_DIR}/src/window/numeric_input.c
Expand Down
43 changes: 22 additions & 21 deletions res/asset_packer/src/asset_packer.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,27 +120,26 @@ static void add_attribute_int(const char *name, int value)
static void add_attribute_bool(const char *name, int value, const char *expression_if_true)
{
if (value != 0) {
xml_exporter_add_attribute_text(name, string_from_ascii(expression_if_true));
xml_exporter_add_attribute_text(name, expression_if_true);
}
}

static void add_attribute_enum(const char *name, int value, const char **display_value, int max_values)
{
if (value > 0 && value <= max_values) {
xml_exporter_add_attribute_text(name, string_from_ascii(display_value[value - 1]));
xml_exporter_add_attribute_text(name, display_value[value - 1]);
}
}

static void add_attribute_string(const char *name, const char *value)
{
if (value && *value != 0) {
xml_exporter_add_attribute_text(name, string_from_ascii(value));
xml_exporter_add_attribute_text(name, value);
}
}

static void create_image_xml_line(const asset_image *image)
static void create_image_xml_attributes(const asset_image *image)
{
xml_exporter_new_element("image", 1);
add_attribute_string("id", image->id);
if (image->has_defined_size) {
add_attribute_int("width", image->img.width);
Expand All @@ -154,7 +153,7 @@ static void create_layer_xml_line(const layer *l)
if (!l->original_image_group && !l->original_image_id && !l->width && !l->height) {
return;
}
xml_exporter_new_element("layer", 1);
xml_exporter_new_element("layer");

add_attribute_string("group", l->original_image_group);
add_attribute_string("image", l->original_image_id);
Expand All @@ -169,12 +168,11 @@ static void create_layer_xml_line(const layer *l)
add_attribute_enum("part", l->part, LAYER_PART, 2);
add_attribute_enum("mask", l->mask, LAYER_MASK, 2);

xml_exporter_close_element(0);
xml_exporter_close_element();
}

static void create_animation_xml_line(const asset_image *image)
static void create_animation_xml_attributes(const asset_image *image)
{
xml_exporter_new_element("animation", 1);

if (!image->has_frame_elements) {
add_attribute_int("frames", image->img.animation->num_sprites);
Expand All @@ -187,7 +185,7 @@ static void create_animation_xml_line(const asset_image *image)

static void create_frame_xml_line(const layer *l)
{
xml_exporter_new_element("frame", 1);
xml_exporter_new_element("frame");

add_attribute_string("group", l->original_image_group);
add_attribute_string("image", l->original_image_id);
Expand All @@ -200,7 +198,7 @@ static void create_frame_xml_line(const layer *l)
add_attribute_enum("invert", l->invert, LAYER_INVERT, 3);
add_attribute_enum("rotate", l->rotate, LAYER_ROTATE, 3);

xml_exporter_close_element(0);
xml_exporter_close_element();
}

void new_packed_asset(packed_asset *asset, int index)
Expand Down Expand Up @@ -566,26 +564,29 @@ static void pack_group(int group_id)
uint8_t *buf_data = malloc(buf_size);
buffer_init(&buf, buf_data, buf_size);
xml_exporter_init(&buf, "assetlist");
xml_exporter_add_text(string_from_ascii("<!-- XML auto packed by asset_packer. DO NOT use as a reference."));
xml_exporter_add_text("<!-- XML auto generated by asset_packer. DO NOT use as a reference.");
xml_exporter_newline();
xml_exporter_add_text(string_from_ascii(" Use the assets directory from the source code instead. -->"));
xml_exporter_add_text(" Use the assets directory from the source code instead. -->");
xml_exporter_newline();
xml_exporter_newline();
xml_exporter_new_element("assetlist", 0);
xml_exporter_add_attribute_text("name", string_from_ascii(group->name));
xml_exporter_new_element("assetlist");
xml_exporter_add_attribute_text("name", group->name);

for (int image_id = group->first_image_index; image_id <= group->last_image_index; image_id++) {
asset_image *image = asset_image_get_from_id(image_id);
if (!image->has_defined_size) {
calculate_image_size(image);
}
create_image_xml_line(image);
xml_exporter_new_element("image");

create_image_xml_attributes(image);
for (layer *l = &image->first_layer; l; l = l->next) {
pack_layer(&packer, l);
create_layer_xml_line(l);
}
if (image->img.animation) {
create_animation_xml_line(image);
xml_exporter_new_element("animation");
create_animation_xml_attributes(image);
if (image->has_frame_elements) {
for (int i = 0; i < image->img.animation->num_sprites; i++) {
image_id++;
Expand All @@ -595,12 +596,12 @@ static void pack_group(int group_id)
create_frame_xml_line(l);
}
}
xml_exporter_close_element(0);
xml_exporter_close_element();
}
xml_exporter_close_element(0);
xml_exporter_close_element();
}

xml_exporter_close_element(0);
xml_exporter_close_element();

packed_asset *asset;
array_foreach(packed_assets, asset) {
Expand All @@ -614,7 +615,7 @@ static void pack_group(int group_id)
return;
}

fwrite(buf.data, 1, (size_t) buf.index, xml_dest);
fwrite(buf.data, 1, buf.index, xml_dest);

fclose(xml_dest);
image_packer_free(&packer);
Expand Down
20 changes: 16 additions & 4 deletions src/campaign/campaign.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "campaign/file.h"
#include "campaign/mission.h"
#include "campaign/player_data.h"
#include "campaign/xml.h"
#include "core/file.h"
#include "core/log.h"
Expand All @@ -18,7 +19,7 @@ static struct {
campaign_mission_info mission_info;
} data;

static void get_campaign_data(void)
static void get_campaign_data(const char *filename)
{
if (!campaign_file_open_zip()) {
log_error("Error opening campaign file", 0, 0);
Expand All @@ -43,6 +44,8 @@ static void get_campaign_data(void)
campaign_clear();
}

data.campaign.current_mission = campaign_player_data_get_current_mission(filename);

data.active = result;
}

Expand All @@ -60,7 +63,7 @@ int campaign_load(const char *filename)

campaign_clear();
campaign_file_set_path(filename);
get_campaign_data();
get_campaign_data(filename);
if (data.active) {
snprintf(data.file_name, FILE_NAME_MAX, "%s", filename);
}
Expand Down Expand Up @@ -139,11 +142,20 @@ const campaign_mission_info *campaign_get_current_mission(int scenario_id)
return &data.mission_info;
}

const campaign_mission_info *campaign_get_next_mission(int last_scenario_id)
const campaign_mission_info *campaign_advance_mission(int last_scenario_id)
{
if (!data.active || !fill_mission_info(campaign_mission_next(last_scenario_id))) {
if (!data.active) {
return 0;
}
campaign_mission *mission = campaign_mission_next(last_scenario_id);
if (!fill_mission_info(mission)) {
mission = campaign_mission_current(last_scenario_id);
if (mission) {
campaign_player_data_update_current_mission(data.file_name, mission->id + 1);
}
return 0;
}
campaign_player_data_update_current_mission(data.file_name, mission->id);
return &data.mission_info;
}

Expand Down
3 changes: 2 additions & 1 deletion src/campaign/campaign.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ typedef struct {
const uint8_t *description;
int number_of_missions;
int starting_rank;
int current_mission;
} campaign_info;

typedef struct {
Expand Down Expand Up @@ -94,7 +95,7 @@ const campaign_mission_info *campaign_get_current_mission(int scenario_id);
* @return A pointer to the first mission whose first scenario is higher than last_scenario_id,
* or 0 if there's an error or if there are no new missions.
*/
const campaign_mission_info *campaign_get_next_mission(int last_scenario_id);
const campaign_mission_info *campaign_advance_mission(int last_scenario_id);

/**
* Gets a scenario from the campaign.
Expand Down
8 changes: 2 additions & 6 deletions src/campaign/mission.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ static void new_scenario(campaign_scenario *scenario, int index)

campaign_mission *campaign_mission_new(void)
{
campaign_mission *mission;
array_new_item(data.missions, data.missions.size, mission);
return mission;
return array_advance(data.missions);
}

campaign_mission *campaign_mission_current(int index)
Expand All @@ -53,9 +51,7 @@ campaign_mission *campaign_mission_next(int last_index)

campaign_scenario *campaign_mission_new_scenario(void)
{
campaign_scenario *scenario;
array_new_item(data.scenarios, data.scenarios.size, scenario);
return scenario;
return array_advance(data.scenarios);
}

campaign_scenario *campaign_mission_get_scenario(int scenario_id)
Expand Down
Loading

0 comments on commit 63ff254

Please sign in to comment.