Custom Data for Campaigns (#6906)

* campaign custom data

* Assertion instead of assert
This commit is contained in:
Mike Nelson authored and GitHub committed 2025-08-07 09:56:52 -04:00
1 parent b8c3c560d2
commit 75b61efbd1
11 files changed
+89 -7

No files matched your search

+5
View File
@@ -518,6 +518,10 @@ int mission_campaign_load(const char* filename, const char* full_path, player* p
stuff_int( &(Campaign.flags) );
}
if (optional_string("$begin_custom_data_map")) {
parse_string_map(Campaign.custom_data, "$end_custom_data_map", "+Val:");
}
// parse the optional ship/weapon information
mission_campaign_get_sw_info();
@@ -1259,6 +1263,7 @@ void mission_campaign_clear()
memset(Campaign.name, 0, NAME_LENGTH);
memset(Campaign.filename, 0, MAX_FILENAME_LEN);
Campaign.type = 0;
Campaign.custom_data.clear();
Campaign.flags = CF_DEFAULT_VALUE;
Campaign.num_missions = 0;
Campaign.num_missions_completed = 0;
+1
View File
@@ -136,6 +136,7 @@ public:
SCP_vector<sexp_variable> red_alert_variables; // state of the variables in the previous mission of a Red Alert scenario.
SCP_vector<sexp_container> persistent_containers; // These containers will be saved at the end of a mission
SCP_vector<sexp_container> red_alert_containers; // state of the containers in the previous mission of a Red Alert scenario.
SCP_map<SCP_string, SCP_string> custom_data; // Custom data for the campaign
campaign()
: desc(nullptr), num_missions(0)
+23
View File
@@ -3035,6 +3035,29 @@ ADE_FUNC(jumpToMission, l_Campaign, "string filename, [boolean hub]", "Jumps to
return ade_set_args(L, "b", success);
}
ADE_VIRTVAR(CustomData, l_Campaign, nullptr, "Gets the custom data table for this campaign", "table", "The campaign's custom data table")
{
if (ADE_SETTING_VAR) {
LuaError(L, "Setting Custom Data is not supported");
}
auto table = luacpp::LuaTable::create(L);
for (const auto& pair : Campaign.custom_data)
{
table.addValue(pair.first, pair.second);
}
return ade_set_args(L, "t", &table);
}
ADE_FUNC(hasCustomData, l_Campaign, nullptr, "Detects whether the campaign has any custom data", "boolean", "true if the campaign's custom_data is not empty, false otherwise")
{
bool result = !Campaign.custom_data.empty();
return ade_set_args(L, "b", result);
}
// TODO: add a proper indexer type that returns a handle
// something like ca.Mission[filename/index]
+11
View File
@@ -103,6 +103,7 @@ BEGIN_MESSAGE_MAP(campaign_editor, CFormView)
ON_EN_CHANGE(IDC_SUBSTITUTE_MAIN_HALL, OnChangeSubstituteMainHall)
ON_EN_CHANGE(IDC_DEBRIEFING_PERSONA, OnChangeDebriefingPersona)
ON_BN_CLICKED(IDC_CUSTOM_TECH_DB, OnCustomTechDB)
ON_BN_CLICKED(IDC_OPEN_CUSTOM_DATA, OnCustomData)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
@@ -951,6 +952,16 @@ void campaign_editor::OnCustomTechDB()
Campaign.flags &= ~CF_CUSTOM_TECH_DATABASE;
}
void campaign_editor::OnCustomData()
{
UpdateData(TRUE);
CustomDataDlg dlg(&Campaign.custom_data, this);
dlg.DoModal();
UpdateData(FALSE);
}
CString campaign_editor::GetPathWithoutFile() const
{
if (m_current_campaign_path.IsEmpty())
+1
View File
@@ -115,6 +115,7 @@ protected:
afx_msg void OnChangeSubstituteMainHall();
afx_msg void OnChangeDebriefingPersona();
afx_msg void OnCustomTechDB();
afx_msg void OnCustomData();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
+8 -5
View File
@@ -22,8 +22,8 @@ static char THIS_FILE[] = __FILE__;
/////////////////////////////////////////////////////////////////////////////
// CustomDataDlg dialog
CustomDataDlg::CustomDataDlg(CWnd* pParent /*=nullptr*/)
: CDialog(CustomDataDlg::IDD, pParent)
CustomDataDlg::CustomDataDlg(SCP_map<SCP_string, SCP_string>* data_ptr, CWnd* pParent /*=nullptr*/)
: CDialog(CustomDataDlg::IDD, pParent), m_target_data(data_ptr)
{
}
@@ -65,7 +65,8 @@ BOOL CustomDataDlg::OnInitDialog()
CDialog::OnInitDialog();
// grab the existing list of custom data pairs and duplicate it. We only update it if the user clicks OK.
m_custom_data = The_mission.custom_data;
Assertion(m_target_data != nullptr, "Custom Data target is nullptr. Get a coder!");
m_custom_data = *m_target_data;
update_data_lister();
@@ -79,7 +80,8 @@ BOOL CustomDataDlg::OnInitDialog()
void CustomDataDlg::OnButtonOk()
{
// now we set the custom data to our copy
The_mission.custom_data = m_custom_data;
Assertion(m_target_data != nullptr, "Custom Data target is nullptr. Get a coder!");
*m_target_data = m_custom_data;
CDialog::OnOK();
}
@@ -314,5 +316,6 @@ void CustomDataDlg::update_help_text(const SCP_string& description)
bool CustomDataDlg::query_modified() const
{
return The_mission.custom_data != m_custom_data;
Assertion(m_target_data != nullptr, "Custom Data target is nullptr. Get a coder!");
return *m_target_data != m_custom_data;
}
+2 -1
View File
@@ -11,7 +11,7 @@
class CustomDataDlg : public CDialog {
public:
CustomDataDlg(CWnd* pParent = nullptr);
CustomDataDlg(SCP_map<SCP_string, SCP_string>* data_ptr, CWnd* pParent = nullptr);
enum {
IDD = IDD_EDIT_CUSTOM_DATA
@@ -55,6 +55,7 @@ class CustomDataDlg : public CDialog {
private:
bool query_modified() const;
SCP_map<SCP_string, SCP_string>* m_target_data = nullptr;
SCP_map<SCP_string, SCP_string> m_custom_data;
// read-only view of data pair keys
+1
View File
@@ -1760,6 +1760,7 @@ BEGIN
LTEXT "Substitute",IDC_STATIC | UDS_ALIGNRIGHT,14,207,58,8
EDITTEXT IDC_SUBSTITUTE_MAIN_HALL,73,205,66,12,ES_AUTOHSCROLL
LTEXT "Branches",IDC_STATIC,7,229,31,8
PUSHBUTTON "Custom Data",IDC_OPEN_CUSTOM_DATA,181,203,71,15
CONTROL "Tree1",IDC_SEXP_TREE,"SysTreeView32",TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_EDITLABELS | TVS_SHOWSELALWAYS | WS_BORDER | WS_HSCROLL | WS_TABSTOP,7,239,188,111,WS_EX_CLIENTEDGE
GROUPBOX "Branch Options",IDC_STATIC,202,229,61,64
PUSHBUTTON "Move Up",IDC_MOVE_UP,206,239,53,14,BS_CENTER,WS_EX_STATICEDGE
+1 -1
View File
@@ -725,7 +725,7 @@ void CMissionNotesDlg::OnCustomData()
{
UpdateData(TRUE);
CustomDataDlg dlg;
CustomDataDlg dlg(&The_mission.custom_data, this);
dlg.DoModal();
UpdateData(FALSE);
+18
View File
@@ -1354,6 +1354,24 @@ int CFred_mission_save::save_campaign_file(const char *pathname)
fout(" %d\n", Campaign.flags);
}
if (Mission_save_format != FSO_FORMAT_RETAIL && !Campaign.custom_data.empty()) {
if (optional_string_fred("$begin_custom_data_map")) {
parse_comments(2);
} else {
fout("\n$begin_custom_data_map");
}
for (const auto& pair : Campaign.custom_data) {
fout("\n +Val: %s %s", pair.first.c_str(), pair.second.c_str());
}
if (optional_string_fred("$end_custom_data_map")) {
parse_comments();
} else {
fout("\n$end_custom_data_map");
}
}
// write out the ships and weapons which the player can start the campaign with
optional_string_fred("+Starting Ships: (");
parse_comments(2);
+18
View File
@@ -2351,6 +2351,24 @@ int CFred_mission_save::save_campaign_file(const char *pathname)
fout(" %d\n", Campaign.flags);
}
if (save_format != MissionFormat::RETAIL && !Campaign.custom_data.empty()) {
if (optional_string_fred("$begin_custom_data_map")) {
parse_comments(2);
} else {
fout("\n$begin_custom_data_map");
}
for (const auto& pair : Campaign.custom_data) {
fout("\n +Val: %s %s", pair.first.c_str(), pair.second.c_str());
}
if (optional_string_fred("$end_custom_data_map")) {
parse_comments();
} else {
fout("\n$end_custom_data_map");
}
}
// write out the ships and weapons which the player can start the campaign with
optional_string_fred("+Starting Ships: (");
parse_comments(2);