Skip to content

Commit ce31a33

Browse files
authored
fix persistent variables and containers (scp-fs2open#7192)
1 parent b4c98de commit ce31a33

15 files changed

Lines changed: 189 additions & 302 deletions

File tree

code/mission/missioncampaign.cpp

Lines changed: 87 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -935,15 +935,11 @@ void mission_campaign_eval_next_mission()
935935
*/
936936
void mission_campaign_store_goals_and_events()
937937
{
938-
int cur;
939-
cmission *mission_obj;
940-
941938
if (!(Game_mode & GM_CAMPAIGN_MODE) || (Campaign.current_mission < 0))
942939
return;
943940

944-
cur = Campaign.current_mission;
945-
946-
mission_obj = &Campaign.missions[cur];
941+
int cur = Campaign.current_mission;
942+
auto mission_obj = &Campaign.missions[cur];
947943

948944
// first we must save the status of the current missions goals in the campaign mission structure.
949945
// After that, we can determine which mission is tagged as the next mission. Finally, we
@@ -999,66 +995,54 @@ void mission_campaign_store_goals_and_events()
999995

1000996
void mission_campaign_store_variables(int persistence_type, bool store_red_alert)
1001997
{
1002-
int cur, i, j;
1003-
cmission *mission_obj;
1004-
1005998
if (!(Game_mode & GM_CAMPAIGN_MODE) || (Campaign.current_mission < 0))
1006999
return;
10071000

1008-
cur = Campaign.current_mission;
1009-
mission_obj = &Campaign.missions[cur];
1001+
int cur = Campaign.current_mission;
1002+
auto mission_obj = &Campaign.missions[cur];
10101003

1011-
// handle variables that are saved on mission victory -------------------------------------
10121004
mission_obj->variables.clear();
10131005

1014-
int num_mission_variables = sexp_campaign_file_variable_count();
1006+
int num_sexp_variables = sexp_variable_count();
1007+
for (int i = 0; i < num_sexp_variables; i++) {
1008+
if (!(Sexp_variables[i].type & persistence_type)) {
1009+
continue;
1010+
}
10151011

1016-
if (num_mission_variables > 0) {
1017-
1018-
if (store_red_alert) {
1019-
for (auto& current_rav : Campaign.red_alert_variables) {
1020-
Campaign.persistent_variables.push_back(current_rav);
1012+
// player-persistent (aka "eternal")
1013+
if (Sexp_variables[i].type & SEXP_VARIABLE_SAVE_TO_PLAYER_FILE) {
1014+
// see if we already have a variable with this name
1015+
int j = find_item_with_string(Player->variables, &sexp_variable::variable_name, Sexp_variables[i].variable_name);
1016+
if (j >= 0) {
1017+
Player->variables[j].type = Sexp_variables[i].type;
1018+
strcpy_s(Player->variables[j].text, Sexp_variables[i].text);
1019+
}
1020+
// new variable
1021+
else {
1022+
Player->variables.push_back(Sexp_variables[i]);
10211023
}
10221024
}
1023-
1024-
for (i = 0; i < sexp_variable_count(); i++) {
1025-
if (!(Sexp_variables[i].type & SEXP_VARIABLE_SAVE_TO_PLAYER_FILE)) {
1026-
if (Sexp_variables[i].type & persistence_type) {
1027-
bool add_it = true;
1028-
1029-
// see if we already have a variable with this name
1030-
for (j = 0; j < (int)Campaign.persistent_variables.size(); j++) {
1031-
if (!(stricmp(Sexp_variables[i].variable_name, Campaign.persistent_variables[j].variable_name))) {
1032-
add_it = false;
1033-
Campaign.persistent_variables[j].type = Sexp_variables[i].type;
1034-
strcpy_s(Campaign.persistent_variables[j].text, Sexp_variables[i].text);
1035-
break;
1036-
}
1037-
}
1038-
1039-
// new variable
1040-
if (add_it) {
1041-
Campaign.persistent_variables.push_back(Sexp_variables[i]);
1042-
}
1043-
}
1025+
// campaign-persistent
1026+
else {
1027+
// see if we already have a variable with this name
1028+
int j = find_item_with_string(Campaign.persistent_variables, &sexp_variable::variable_name, Sexp_variables[i].variable_name);
1029+
if (j >= 0) {
1030+
Campaign.persistent_variables[j].type = Sexp_variables[i].type;
1031+
strcpy_s(Campaign.persistent_variables[j].text, Sexp_variables[i].text);
10441032
}
1045-
// we might need to save some eternal variables
1046-
else if ((persistence_type & SEXP_VARIABLE_SAVE_ON_MISSION_PROGRESS) && (Sexp_variables[i].type & persistence_type) && (Sexp_variables[i].type & SEXP_VARIABLE_SAVE_TO_PLAYER_FILE)) {
1047-
bool add_it = true;
1048-
1049-
for (j = 0; j < (int)Player->variables.size(); j++) {
1050-
if (!(stricmp(Sexp_variables[i].variable_name, Player->variables[j].variable_name))) {
1051-
Player->variables[j] = Sexp_variables[i];
1052-
1053-
add_it = false;
1054-
break;
1055-
}
1056-
}
1033+
// new variable
1034+
else {
1035+
Campaign.persistent_variables.push_back(Sexp_variables[i]);
1036+
}
1037+
}
1038+
}
10571039

1058-
// if not found then add new entry
1059-
if (add_it) {
1060-
Player->variables.push_back(Sexp_variables[i]);
1061-
}
1040+
if (store_red_alert) {
1041+
for (const auto& current_rav : Campaign.red_alert_variables) {
1042+
if (find_item_with_string(Campaign.persistent_variables, &sexp_variable::variable_name, current_rav.variable_name) < 0) {
1043+
Campaign.persistent_variables.push_back(current_rav);
1044+
} else {
1045+
Warning(LOCATION, "A red alert variable has the same name as a persistent variable!");
10621046
}
10631047
}
10641048
}
@@ -1070,58 +1054,68 @@ void mission_campaign_store_containers(ContainerType persistence_type, bool stor
10701054
if (!(Game_mode & GM_CAMPAIGN_MODE) || (Campaign.current_mission < 0))
10711055
return;
10721056

1073-
if (!sexp_container_has_persistent_non_eternal_containers()) {
1074-
// nothing to do
1075-
return;
1076-
}
1077-
1078-
if (store_red_alert) {
1079-
for (const auto& current_con : Campaign.red_alert_containers) {
1080-
Campaign.persistent_containers.emplace_back(current_con);
1057+
for (const auto &container : get_all_sexp_containers()) {
1058+
if (none(container.type & persistence_type)) {
1059+
continue;
10811060
}
1082-
}
10831061

1084-
for (const auto &container : get_all_sexp_containers()) {
1085-
if (!container.is_eternal()) {
1086-
if (any(container.type & persistence_type)) {
1087-
// see if we already have a container with this name
1088-
auto cpc_it = std::find_if(Campaign.persistent_containers.begin(),
1089-
Campaign.persistent_containers.end(),
1090-
[container](const sexp_container &cpc) {
1091-
return cpc.name_matches(container);
1092-
});
1093-
1094-
if (cpc_it != Campaign.persistent_containers.end()) {
1095-
*cpc_it = container;
1096-
} else {
1097-
// new container
1098-
Campaign.persistent_containers.emplace_back(container);
1099-
}
1100-
}
1101-
} else if (any(persistence_type & ContainerType::SAVE_ON_MISSION_PROGRESS) &&
1102-
any(container.type & persistence_type) && container.is_eternal()) {
1103-
// we might need to save some eternal player-persistent containers
1062+
// player-persistent (aka "eternal")
1063+
if (container.is_eternal()) {
1064+
// see if we already have a container with this name
11041065
auto ppc_it = std::find_if(Player->containers.begin(),
11051066
Player->containers.end(),
1106-
[container](const sexp_container &ppc) {
1067+
[&container](const sexp_container& ppc) {
11071068
return ppc.name_matches(container);
11081069
});
11091070

11101071
if (ppc_it != Player->containers.end()) {
11111072
*ppc_it = container;
11121073
} else {
11131074
// new player-persistent container
1114-
Player->containers.emplace_back(container);
1075+
Player->containers.push_back(container);
1076+
}
1077+
}
1078+
// campaign-persistent
1079+
else {
1080+
// see if we already have a container with this name
1081+
auto cpc_it = std::find_if(Campaign.persistent_containers.begin(),
1082+
Campaign.persistent_containers.end(),
1083+
[&container](const sexp_container& cpc) {
1084+
return cpc.name_matches(container);
1085+
});
1086+
1087+
if (cpc_it != Campaign.persistent_containers.end()) {
1088+
*cpc_it = container;
1089+
} else {
1090+
// new container
1091+
Campaign.persistent_containers.push_back(container);
1092+
}
1093+
}
1094+
}
1095+
1096+
if (store_red_alert) {
1097+
for (const auto& container : Campaign.red_alert_containers) {
1098+
// see if we already have a container with this name
1099+
auto cpc_it = std::find_if(Campaign.persistent_containers.begin(),
1100+
Campaign.persistent_containers.end(),
1101+
[&container](const sexp_container& cpc) {
1102+
return cpc.name_matches(container);
1103+
});
1104+
1105+
if (cpc_it == Campaign.persistent_containers.end()) {
1106+
Campaign.persistent_containers.push_back(container);
1107+
} else {
1108+
Warning(LOCATION, "A red alert container has the same name as a persistent container!");
11151109
}
11161110
}
11171111
}
11181112
}
11191113

1120-
void mission_campaign_store_goals_and_events_and_variables()
1114+
void mission_campaign_store_goals_and_events_and_variables(bool store_red_alert_data)
11211115
{
11221116
mission_campaign_store_goals_and_events();
1123-
mission_campaign_store_variables(SEXP_VARIABLE_SAVE_ON_MISSION_PROGRESS);
1124-
mission_campaign_store_containers(ContainerType::SAVE_ON_MISSION_PROGRESS);
1117+
mission_campaign_store_variables(SEXP_VARIABLE_SAVE_ON_MISSION_PROGRESS, store_red_alert_data);
1118+
mission_campaign_store_containers(ContainerType::SAVE_ON_MISSION_PROGRESS, store_red_alert_data);
11251119
}
11261120

11271121
/**
@@ -1153,9 +1147,6 @@ void mission_campaign_mission_over(bool do_next_mission)
11531147
Campaign.weapons_allowed[Granted_weapons[i]] = 1;
11541148
}
11551149

1156-
// Goober5000 - player-persistent variables are handled when the mission is
1157-
// over, not necessarily when the mission is accepted
1158-
11591150
// update campaign.mission stats (used to allow backout inRedAlert)
11601151
// .. but we don't do this if we are inside of the prev/current loop hack
11611152
if ( Campaign.prev_mission != Campaign.current_mission ) {
@@ -1686,6 +1677,9 @@ void mission_campaign_end_init()
16861677

16871678
void mission_campaign_end_do()
16881679
{
1680+
mission_campaign_store_variables(SEXP_VARIABLE_SAVE_ON_MISSION_PROGRESS, false);
1681+
mission_campaign_store_containers(ContainerType::SAVE_ON_MISSION_PROGRESS, false);
1682+
16891683
// close out the mission
16901684
event_music_level_close();
16911685
mission_goal_fail_incomplete();
@@ -1732,7 +1726,7 @@ void mission_campaign_skip_to_next()
17321726
mission_goal_mark_events_complete();
17331727

17341728
// store
1735-
mission_campaign_store_goals_and_events_and_variables();
1729+
mission_campaign_store_goals_and_events_and_variables(false);
17361730

17371731
// now set the next mission
17381732
mission_campaign_eval_next_mission();
@@ -1849,84 +1843,6 @@ bool mission_campaign_jump_to_mission(const char* filename, bool no_skip)
18491843
}
18501844
}
18511845

1852-
// Goober5000
1853-
void mission_campaign_save_on_close_variables()
1854-
{
1855-
int i;
1856-
1857-
// make sure we are actually playing a single-player campaign
1858-
if (!(Game_mode & GM_CAMPAIGN_MODE) || (Campaign.type != CAMPAIGN_TYPE_SINGLE) || (Campaign.current_mission < 0))
1859-
return;
1860-
1861-
// now save variables
1862-
for (i = 0; i < sexp_variable_count(); i++) {
1863-
// we only want the on mission close type. On campaign progress type are dealt with elsewhere
1864-
if ( !(Sexp_variables[i].type & SEXP_VARIABLE_SAVE_ON_MISSION_CLOSE) ) {
1865-
continue;
1866-
}
1867-
1868-
bool found = false;
1869-
1870-
// deal with eternals
1871-
if ((Sexp_variables[i].type & SEXP_VARIABLE_SAVE_TO_PLAYER_FILE)) {
1872-
// check if variable already exists and updated it
1873-
for (auto& current_variable : Player->variables) {
1874-
if (!(stricmp(Sexp_variables[i].variable_name, current_variable.variable_name))) {
1875-
current_variable = Sexp_variables[i];
1876-
1877-
found = true;
1878-
break;
1879-
}
1880-
}
1881-
1882-
// if not found then add new entry
1883-
if (!found) {
1884-
Player->variables.push_back(Sexp_variables[i]);
1885-
}
1886-
}
1887-
1888-
}
1889-
1890-
// store any non-eternal on mission close variables
1891-
mission_campaign_store_variables(SEXP_VARIABLE_SAVE_ON_MISSION_CLOSE, false);
1892-
}
1893-
1894-
// jg18 - adapted from mission_campaign_save_on_close_variables()
1895-
void mission_campaign_save_on_close_containers()
1896-
{
1897-
// make sure we are actually playing a single-player campaign
1898-
if (!(Game_mode & GM_CAMPAIGN_MODE) || (Campaign.type != CAMPAIGN_TYPE_SINGLE) || (Campaign.current_mission < 0))
1899-
return;
1900-
1901-
// now save containers
1902-
for (const auto &container : get_all_sexp_containers()) {
1903-
// we only want the on mission close type. On campaign progress type are dealt with elsewhere
1904-
if (none(container.type & ContainerType::SAVE_ON_MISSION_CLOSE)) {
1905-
continue;
1906-
}
1907-
1908-
// deal with eternals
1909-
if (container.is_eternal()) {
1910-
// check if container already exists and update it
1911-
auto ppc_it = std::find_if(Player->containers.begin(),
1912-
Player->containers.end(),
1913-
[container](const sexp_container &ppc) {
1914-
return ppc.name_matches(container);
1915-
});
1916-
1917-
if (ppc_it != Player->containers.end()) {
1918-
*ppc_it = container;
1919-
} else {
1920-
// if not found then add new entry
1921-
Player->containers.emplace_back(container);
1922-
}
1923-
}
1924-
}
1925-
1926-
// store any non-eternal on mission close containers
1927-
mission_campaign_store_containers(ContainerType::SAVE_ON_MISSION_CLOSE, false);
1928-
}
1929-
19301846
void mission_campaign_load_failure_popup()
19311847
{
19321848
if (Campaign_load_failure == 0) {

code/mission/missioncampaign.h

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -226,13 +226,13 @@ int mission_load_up_campaign(bool fall_back_from_current = false);
226226
void mission_campaign_store_goals_and_events();
227227

228228
// stores variables which will be saved only on mission progression
229-
void mission_campaign_store_variables(int persistence_type, bool store_red_alert = true);
229+
void mission_campaign_store_variables(int persistence_type, bool store_red_alert);
230230

231231
// stores containers which will be saved only on mission progression
232-
void mission_campaign_store_containers(ContainerType persistence_type, bool store_red_alert = true);
232+
void mission_campaign_store_containers(ContainerType persistence_type, bool store_red_alert);
233233

234234
// does all three of the above
235-
void mission_campaign_store_goals_and_events_and_variables();
235+
void mission_campaign_store_goals_and_events_and_variables(bool store_red_alert_data);
236236

237237
// evaluates next mission and possible loop mission
238238
void mission_campaign_eval_next_mission();
@@ -254,12 +254,6 @@ void mission_campaign_end_init();
254254
void mission_campaign_end_close();
255255
void mission_campaign_end_do();
256256

257-
// save eternal variables
258-
extern void mission_campaign_save_on_close_variables();
259-
260-
// save eternal containers
261-
extern void mission_campaign_save_on_close_containers();
262-
263257
extern void mission_campaign_load_failure_popup();
264258

265259
SCP_string mission_campaign_get_name(const char* filename);

0 commit comments

Comments
 (0)