Skip to content

Commit ef67aec

Browse files
committed
fix persistent variables and containers
Storage of persistent variables had been broken since #1631 -- the player-persistent variable code would inadvertently not run if there were no campaign-persistent variables. Additionally, there were several places where the persistent variable logic was hard to follow, which could have hidden other related bugs. This fixes the check and cleans up and consolidates the relevant functions.
1 parent 306f34a commit ef67aec

15 files changed

Lines changed: 154 additions & 295 deletions

File tree

code/mission/missioncampaign.cpp

Lines changed: 68 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -928,15 +928,11 @@ void mission_campaign_eval_next_mission()
928928
*/
929929
void mission_campaign_store_goals_and_events()
930930
{
931-
int cur;
932-
cmission *mission_obj;
933-
934931
if (!(Game_mode & GM_CAMPAIGN_MODE) || (Campaign.current_mission < 0))
935932
return;
936933

937-
cur = Campaign.current_mission;
938-
939-
mission_obj = &Campaign.missions[cur];
934+
int cur = Campaign.current_mission;
935+
auto mission_obj = &Campaign.missions[cur];
940936

941937
// first we must save the status of the current missions goals in the campaign mission structure.
942938
// After that, we can determine which mission is tagged as the next mission. Finally, we
@@ -992,66 +988,49 @@ void mission_campaign_store_goals_and_events()
992988

993989
void mission_campaign_store_variables(int persistence_type, bool store_red_alert)
994990
{
995-
int cur, i, j;
996-
cmission *mission_obj;
997-
998991
if (!(Game_mode & GM_CAMPAIGN_MODE) || (Campaign.current_mission < 0))
999992
return;
1000993

1001-
cur = Campaign.current_mission;
1002-
mission_obj = &Campaign.missions[cur];
1003-
1004-
// handle variables that are saved on mission victory -------------------------------------
994+
int cur = Campaign.current_mission;
995+
auto mission_obj = &Campaign.missions[cur];
1005996
mission_obj->variables.clear();
1006997

1007-
int num_mission_variables = sexp_campaign_file_variable_count();
1008-
1009-
if (num_mission_variables > 0) {
1010-
1011-
if (store_red_alert) {
1012-
for (auto& current_rav : Campaign.red_alert_variables) {
1013-
Campaign.persistent_variables.push_back(current_rav);
1014-
}
998+
if (store_red_alert) {
999+
for (auto& current_rav : Campaign.red_alert_variables) {
1000+
Campaign.persistent_variables.push_back(current_rav);
10151001
}
1002+
}
10161003

1017-
for (i = 0; i < sexp_variable_count(); i++) {
1018-
if (!(Sexp_variables[i].type & SEXP_VARIABLE_SAVE_TO_PLAYER_FILE)) {
1019-
if (Sexp_variables[i].type & persistence_type) {
1020-
bool add_it = true;
1021-
1022-
// see if we already have a variable with this name
1023-
for (j = 0; j < (int)Campaign.persistent_variables.size(); j++) {
1024-
if (!(stricmp(Sexp_variables[i].variable_name, Campaign.persistent_variables[j].variable_name))) {
1025-
add_it = false;
1026-
Campaign.persistent_variables[j].type = Sexp_variables[i].type;
1027-
strcpy_s(Campaign.persistent_variables[j].text, Sexp_variables[i].text);
1028-
break;
1029-
}
1030-
}
1004+
int num_sexp_variables = sexp_variable_count();
1005+
for (int i = 0; i < num_sexp_variables; i++) {
1006+
if (!(Sexp_variables[i].type & persistence_type)) {
1007+
continue;
1008+
}
10311009

1032-
// new variable
1033-
if (add_it) {
1034-
Campaign.persistent_variables.push_back(Sexp_variables[i]);
1035-
}
1036-
}
1010+
// player-persistent (aka "eternal")
1011+
if (Sexp_variables[i].type & SEXP_VARIABLE_SAVE_TO_PLAYER_FILE) {
1012+
// see if we already have a variable with this name
1013+
int j = find_item_with_string(Player->variables, &sexp_variable::variable_name, Sexp_variables[i].variable_name);
1014+
if (j >= 0) {
1015+
Player->variables[j].type = Sexp_variables[i].type;
1016+
strcpy_s(Player->variables[j].text, Sexp_variables[i].text);
10371017
}
1038-
// we might need to save some eternal variables
1039-
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)) {
1040-
bool add_it = true;
1041-
1042-
for (j = 0; j < (int)Player->variables.size(); j++) {
1043-
if (!(stricmp(Sexp_variables[i].variable_name, Player->variables[j].variable_name))) {
1044-
Player->variables[j] = Sexp_variables[i];
1045-
1046-
add_it = false;
1047-
break;
1048-
}
1049-
}
1050-
1051-
// if not found then add new entry
1052-
if (add_it) {
1053-
Player->variables.push_back(Sexp_variables[i]);
1054-
}
1018+
// new variable
1019+
else {
1020+
Player->variables.push_back(Sexp_variables[i]);
1021+
}
1022+
}
1023+
// campaign-persistent
1024+
else {
1025+
// see if we already have a variable with this name
1026+
int j = find_item_with_string(Campaign.persistent_variables, &sexp_variable::variable_name, Sexp_variables[i].variable_name);
1027+
if (j >= 0) {
1028+
Campaign.persistent_variables[j].type = Sexp_variables[i].type;
1029+
strcpy_s(Campaign.persistent_variables[j].text, Sexp_variables[i].text);
1030+
}
1031+
// new variable
1032+
else {
1033+
Campaign.persistent_variables.push_back(Sexp_variables[i]);
10551034
}
10561035
}
10571036
}
@@ -1063,58 +1042,57 @@ void mission_campaign_store_containers(ContainerType persistence_type, bool stor
10631042
if (!(Game_mode & GM_CAMPAIGN_MODE) || (Campaign.current_mission < 0))
10641043
return;
10651044

1066-
if (!sexp_container_has_persistent_non_eternal_containers()) {
1067-
// nothing to do
1068-
return;
1069-
}
1070-
10711045
if (store_red_alert) {
10721046
for (const auto& current_con : Campaign.red_alert_containers) {
10731047
Campaign.persistent_containers.emplace_back(current_con);
10741048
}
10751049
}
10761050

10771051
for (const auto &container : get_all_sexp_containers()) {
1078-
if (!container.is_eternal()) {
1079-
if (any(container.type & persistence_type)) {
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.emplace_back(container);
1092-
}
1093-
}
1094-
} else if (any(persistence_type & ContainerType::SAVE_ON_MISSION_PROGRESS) &&
1095-
any(container.type & persistence_type) && container.is_eternal()) {
1096-
// we might need to save some eternal player-persistent containers
1052+
if (!any(container.type & persistence_type)) {
1053+
continue;
1054+
}
1055+
1056+
// player-persistent (aka "eternal")
1057+
if (container.is_eternal()) {
1058+
// see if we already have a container with this name
10971059
auto ppc_it = std::find_if(Player->containers.begin(),
10981060
Player->containers.end(),
1099-
[container](const sexp_container &ppc) {
1061+
[container](const sexp_container& ppc) {
11001062
return ppc.name_matches(container);
11011063
});
11021064

11031065
if (ppc_it != Player->containers.end()) {
11041066
*ppc_it = container;
11051067
} else {
11061068
// new player-persistent container
1107-
Player->containers.emplace_back(container);
1069+
Player->containers.push_back(container);
1070+
}
1071+
}
1072+
// campaign-persistent
1073+
else {
1074+
// see if we already have a container with this name
1075+
auto cpc_it = std::find_if(Campaign.persistent_containers.begin(),
1076+
Campaign.persistent_containers.end(),
1077+
[container](const sexp_container& cpc) {
1078+
return cpc.name_matches(container);
1079+
});
1080+
1081+
if (cpc_it != Campaign.persistent_containers.end()) {
1082+
*cpc_it = container;
1083+
} else {
1084+
// new container
1085+
Campaign.persistent_containers.emplace_back(container);
11081086
}
11091087
}
11101088
}
11111089
}
11121090

1113-
void mission_campaign_store_goals_and_events_and_variables()
1091+
void mission_campaign_store_goals_and_events_and_variables(bool store_red_alert_data)
11141092
{
11151093
mission_campaign_store_goals_and_events();
1116-
mission_campaign_store_variables(SEXP_VARIABLE_SAVE_ON_MISSION_PROGRESS);
1117-
mission_campaign_store_containers(ContainerType::SAVE_ON_MISSION_PROGRESS);
1094+
mission_campaign_store_variables(SEXP_VARIABLE_SAVE_ON_MISSION_PROGRESS, store_red_alert_data);
1095+
mission_campaign_store_containers(ContainerType::SAVE_ON_MISSION_PROGRESS, store_red_alert_data);
11181096
}
11191097

11201098
/**
@@ -1146,9 +1124,6 @@ void mission_campaign_mission_over(bool do_next_mission)
11461124
Campaign.weapons_allowed[Granted_weapons[i]] = 1;
11471125
}
11481126

1149-
// Goober5000 - player-persistent variables are handled when the mission is
1150-
// over, not necessarily when the mission is accepted
1151-
11521127
// update campaign.mission stats (used to allow backout inRedAlert)
11531128
// .. but we don't do this if we are inside of the prev/current loop hack
11541129
if ( Campaign.prev_mission != Campaign.current_mission ) {
@@ -1682,6 +1657,9 @@ void mission_campaign_end_init()
16821657

16831658
void mission_campaign_end_do()
16841659
{
1660+
mission_campaign_store_variables(SEXP_VARIABLE_SAVE_ON_MISSION_PROGRESS, false);
1661+
mission_campaign_store_containers(ContainerType::SAVE_ON_MISSION_PROGRESS, false);
1662+
16851663
// close out the mission
16861664
event_music_level_close();
16871665
mission_goal_fail_incomplete();
@@ -1728,7 +1706,7 @@ void mission_campaign_skip_to_next()
17281706
mission_goal_mark_events_complete();
17291707

17301708
// store
1731-
mission_campaign_store_goals_and_events_and_variables();
1709+
mission_campaign_store_goals_and_events_and_variables(false);
17321710

17331711
// now set the next mission
17341712
mission_campaign_eval_next_mission();
@@ -1845,84 +1823,6 @@ bool mission_campaign_jump_to_mission(const char* filename, bool no_skip)
18451823
}
18461824
}
18471825

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