Skip to content

Commit e368514

Browse files
committed
update qtfred to use the new campaign save
1 parent 10ad643 commit e368514

File tree

2 files changed

+79
-14
lines changed

2 files changed

+79
-14
lines changed

qtfred/src/mission/dialogs/CampaignEditorDialogModel.cpp

Lines changed: 77 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
#include "cfile/cfile.h"
44
#include "mission/missionparse.h"
5-
#include "../src/mission/missionsave.h"
5+
#include "missioneditor/campaignsave.h"
66
#include "parse/sexp.h"
77
#include "ship/ship.h"
88
#include "weapon/weapon.h"
@@ -51,7 +51,7 @@ void CampaignEditorDialogModel::initializeData(const char* filename)
5151
// Copy simple properties from the global Campaign struct
5252
m_campaign_filename = Campaign.filename;
5353
m_campaign_name = Campaign.name;
54-
m_campaign_descr = Campaign.desc ? Campaign.desc : "";
54+
m_campaign_descr = Campaign.description;
5555
m_campaign_type = Campaign.type;
5656
m_num_players = Campaign.num_players;
5757
m_flags = Campaign.flags;
@@ -256,7 +256,7 @@ void CampaignEditorDialogModel::commitWorkingCopyToGlobal()
256256

257257
// Copy simple properties
258258
strcpy_s(Campaign.name, m_campaign_name.c_str());
259-
Campaign.desc = m_campaign_descr.empty() ? nullptr : strdup(m_campaign_descr.c_str());
259+
Campaign.description = m_campaign_descr;
260260
Campaign.type = m_campaign_type;
261261
Campaign.num_players = m_num_players;
262262
Campaign.flags = m_flags;
@@ -461,19 +461,83 @@ void CampaignEditorDialogModel::saveCampaign(const SCP_string& filename)
461461
// Copy our working data to the global Campaign struct.
462462
commitWorkingCopyToGlobal();
463463

464-
// Call the global save function.
465-
CFred_mission_save mission_saver;
466-
if (mission_saver.save_campaign_file(target_filename.c_str())) {
467-
// Save failed, clean up the global.
468-
clearCampaignGlobal();
469-
return;
464+
Fred_campaign_save save;
465+
466+
// This if/else is not strictly necessary as the underlying enum values match
467+
// the Mission_save_format values but it is clearer to read and more robust against
468+
// future changes.
469+
if (m_save_format == CampaignFormat::Retail) {
470+
save.set_save_format(MissionFormat::RETAIL);
471+
} else if (m_save_format == CampaignFormat::CompatibilityMode) {
472+
save.set_save_format(MissionFormat::COMPATIBILITY_MODE);
473+
} else {
474+
save.set_save_format(MissionFormat::STANDARD);
470475
}
471476

472-
// On success, update our internal state.
473-
modify(m_campaign_filename, target_filename);
477+
// Create a lookup map for mission indices by filename for efficient lookup.
478+
std::map<SCP_string, int> mission_indices;
479+
for (int i = 0; i < static_cast<int>(m_missions.size()); ++i) {
480+
mission_indices[m_missions[i].filename] = i;
481+
}
474482

475-
// Clean up the global struct now that the save is complete.
476-
clearCampaignGlobal();
483+
SCP_vector<campaign_link> links;
484+
// Iterate through each mission to find its outgoing branches.
485+
for (int i = 0; i < static_cast<int>(m_missions.size()); ++i) {
486+
const auto& mission = m_missions[i];
487+
488+
// Iterate through each branch of the current mission.
489+
for (const auto& branch : mission.branches) {
490+
491+
// Find the 'to' mission index using our lookup map.
492+
int to_index = -1;
493+
if (!branch.next_mission_name.empty()) {
494+
auto it = mission_indices.find(branch.next_mission_name);
495+
if (it != mission_indices.end()) {
496+
to_index = it->second;
497+
}
498+
}
499+
500+
campaign_link link;
501+
link.from = i;
502+
link.to = to_index;
503+
link.sexp = m_tree_ops.saveSexp(branch.sexp_formula);
504+
link.node = branch.sexp_formula;
505+
link.is_mission_loop = branch.is_loop;
506+
link.is_mission_fork = branch.is_fork;
507+
508+
// The descriptive text fields only apply to special (loop/fork) branches.
509+
if (branch.is_loop || branch.is_fork) {
510+
link.mission_branch_txt =
511+
branch.loop_description.empty() ? nullptr : const_cast<char*>(branch.loop_description.c_str());
512+
link.mission_branch_brief_anim =
513+
branch.loop_briefing_anim.empty() ? nullptr : const_cast<char*>(branch.loop_briefing_anim.c_str());
514+
link.mission_branch_brief_sound = branch.loop_briefing_sound.empty()
515+
? nullptr
516+
: const_cast<char*>(branch.loop_briefing_sound.c_str());
517+
} else {
518+
link.mission_branch_txt = nullptr;
519+
link.mission_branch_brief_anim = nullptr;
520+
link.mission_branch_brief_sound = nullptr;
521+
}
522+
523+
links.emplace_back(link);
524+
}
525+
}
526+
527+
bool failure = save.save_campaign_file(target_filename.c_str(), links);
528+
529+
if (failure) {
530+
_viewport->dialogProvider->showButtonDialog(DialogType::Error,
531+
"Save Error",
532+
"An error occurred while saving the campaign.",
533+
{DialogButton::Ok});
534+
}else{
535+
// On success, update our internal state.
536+
modify(m_campaign_filename, target_filename);
537+
538+
// Clean up the global struct now that the save is complete.
539+
clearCampaignGlobal();
540+
}
477541
}
478542

479543
bool CampaignEditorDialogModel::checkValidity()

qtfred/src/mission/dialogs/CampaignEditorDialogModel.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ namespace fso::fred::dialogs {
1010

1111
enum class CampaignFormat {
1212
Retail,
13-
FSO
13+
FSO,
14+
CompatibilityMode = FSO // alias as it's currently unused
1415
};
1516

1617
enum class CampaignSpecialMode {

0 commit comments

Comments
 (0)