1 //
2 //
3
4 #if defined(_MSC_VER) && _MSC_VER <= 1920
5 // work around MSVC 2015 and 2017 compiler bug
6 // https://bugreports.qt.io/browse/QTBUG-72073
7 #define QT_NO_FLOAT16_OPERATORS
8 #endif
9
10 #include "MissionSpecDialogModel.h"
11 #include "ui/dialogs/MissionSpecDialog.h"
12
13 #include "cfile/cfile.h"
14 #include "mission/missionmessage.h"
15
16 #include <QtWidgets>
17
18 namespace fso {
19 namespace fred {
20 namespace dialogs {
21
MissionSpecDialogModel(QObject * parent,EditorViewport * viewport)22 MissionSpecDialogModel::MissionSpecDialogModel(QObject* parent, EditorViewport* viewport) :
23 AbstractDialogModel(parent, viewport) {
24 initializeData();
25 }
26
initializeData()27 void MissionSpecDialogModel::initializeData() {
28 _m_mission_title = The_mission.name;
29 _m_designer_name = The_mission.author;
30 _m_created = The_mission.created;
31 _m_modified = The_mission.modified;
32 _m_mission_notes = The_mission.notes;
33 _m_mission_desc = The_mission.mission_desc;
34
35 _m_full_war = Mission_all_attack;
36 _m_disallow_support = (The_mission.support_ships.max_support_ships == 0);
37
38 _m_flags = The_mission.flags;
39
40 _m_loading_640 = The_mission.loading_screen[GR_640];
41 _m_loading_1024 = The_mission.loading_screen[GR_1024];
42
43 // squad info
44 if (strlen(The_mission.squad_name) > 0) { //-V805
45 _m_squad_name = The_mission.squad_name;
46 _m_squad_filename = The_mission.squad_filename;
47 }
48 else {
49 _m_squad_name = NO_SQUAD;
50 _m_squad_filename = "";
51 }
52
53 _m_type = The_mission.game_type;
54 _m_ai_profile = AI_PROFILES_INDEX(The_mission.ai_profile);
55
56 _m_event_music = Current_soundtrack_num + 1;
57 _m_substitute_event_music = The_mission.substitute_event_music_name;
58
59 _m_command_persona = The_mission.command_persona;
60 _m_command_sender = The_mission.command_sender;
61
62 _m_num_respawns = The_mission.num_respawns;
63 _m_max_respawn_delay = The_mission.max_respawn_delay;
64 _m_max_hull_repair_val = The_mission.support_ships.max_hull_repair_val;
65 _m_max_subsys_repair_val = The_mission.support_ships.max_subsys_repair_val;
66
67 _m_contrail_threshold = The_mission.contrail_threshold;
68 _m_contrail_threshold_flag = (_m_contrail_threshold != CONTRAIL_THRESHOLD_DEFAULT);
69
70 modelChanged();
71 }
72
apply()73 bool MissionSpecDialogModel::apply() {
74 int new_m_type;
75
76 // deal with changing the mission type. Code is done this way since training missions
77 // just override anything else.
78 new_m_type = _m_type;
79
80 if (!new_m_type) {
81 auto button = _viewport->dialogProvider->showButtonDialog(DialogType::Error, "Invalid mission type", "You must select the game type: training, single, or multiplayer",
82 { DialogButton::Ok });
83 if (button == DialogButton::Ok) {
84 return false;
85 }
86 }
87
88 The_mission.game_type = new_m_type;
89 The_mission.num_respawns = _m_num_respawns;
90 The_mission.max_respawn_delay = _m_max_respawn_delay;
91 The_mission.support_ships.max_support_ships = (_m_disallow_support) ? 0 : -1;
92 The_mission.support_ships.max_hull_repair_val = _m_max_hull_repair_val;
93 The_mission.support_ships.max_subsys_repair_val = _m_max_subsys_repair_val;
94
95 // Copy mission flags
96 The_mission.flags = _m_flags;
97
98 // set ship trail threshold
99 if (_m_contrail_threshold_flag) {
100 The_mission.contrail_threshold = _m_contrail_threshold;
101 } else {
102 The_mission.contrail_threshold = CONTRAIL_THRESHOLD_DEFAULT;
103 }
104
105 //if there's a odd number of quotation marks, the mission won't parse
106 //If there are an even number, nothing after the first one appears
107 //So just get rid of them
108 Editor::strip_quotation_marks(_m_mission_title);
109 Editor::strip_quotation_marks(_m_designer_name);
110 Editor::strip_quotation_marks(_m_mission_notes);
111 Editor::strip_quotation_marks(_m_mission_desc);
112 Editor::strip_quotation_marks(_m_squad_name);
113
114 // puts "$End Notes:" on a different line to ensure it's not interpreted as part of a comment
115 Editor::pad_with_newline(_m_mission_notes, NOTES_LENGTH - 1);
116
117 strncpy(The_mission.name, _m_mission_title.c_str(), NAME_LENGTH-1);
118 strncpy(The_mission.author, _m_designer_name.c_str(), NAME_LENGTH-1);
119 strncpy(The_mission.loading_screen[GR_640], _m_loading_640.c_str(), NAME_LENGTH-1);
120 strncpy(The_mission.loading_screen[GR_1024], _m_loading_1024.c_str(), NAME_LENGTH-1);
121 strncpy(The_mission.notes, _m_mission_notes.c_str(), NOTES_LENGTH);
122 strncpy(The_mission.mission_desc, _m_mission_desc.c_str(), MISSION_DESC_LENGTH);
123
124 // copy squad stuff
125 if (_m_squad_name == NO_SQUAD) {
126 strcpy_s(The_mission.squad_name, "");
127 strcpy_s(The_mission.squad_filename, "");
128 } else {
129 strncpy(The_mission.squad_name, _m_squad_name.c_str(), NAME_LENGTH);
130 strncpy(The_mission.squad_filename, _m_squad_filename.c_str(), MAX_FILENAME_LEN);
131 }
132
133 The_mission.ai_profile = &Ai_profiles[_m_ai_profile];
134
135 Current_soundtrack_num = _m_event_music - 1;
136 strcpy_s(The_mission.substitute_event_music_name, _m_substitute_event_music.c_str());
137
138 The_mission.command_persona = _m_command_persona;
139 if (_m_command_sender.at(0) == '#')
140 strcpy_s(The_mission.command_sender, _m_command_sender.substr(1).c_str());
141 else
142 strcpy_s(The_mission.command_sender, _m_command_sender.c_str());
143
144 Mission_all_attack = (int)_m_full_war;
145
146 // update the Num_teams variable accoriding to mission types
147 Num_teams = 1;
148 if ((The_mission.game_type & MISSION_TYPE_MULTI) && (The_mission.game_type & MISSION_TYPE_MULTI_TEAMS)) {
149 Num_teams = 2;
150 }
151
152 return true;
153 }
154
reject()155 void MissionSpecDialogModel::reject() {
156
157 }
158
setMissionTitle(const SCP_string & m_mission_title)159 void MissionSpecDialogModel::setMissionTitle(const SCP_string& m_mission_title) {
160 modify(_m_mission_title, m_mission_title);
161 }
162
getMissionTitle()163 SCP_string MissionSpecDialogModel::getMissionTitle() {
164 return _m_mission_title;
165 }
166
setDesigner(const SCP_string & m_designer_name)167 void MissionSpecDialogModel::setDesigner(const SCP_string& m_designer_name) {
168 modify(_m_designer_name, m_designer_name);
169 }
170
getDesigner()171 SCP_string MissionSpecDialogModel::getDesigner() {
172 return _m_designer_name;
173 }
174
getCreatedTime()175 SCP_string MissionSpecDialogModel::getCreatedTime() {
176 return _m_created;
177 }
178
getModifiedTime()179 SCP_string MissionSpecDialogModel::getModifiedTime() {
180 return _m_modified;
181 }
182
setMissionType(int m_type)183 void MissionSpecDialogModel::setMissionType(int m_type) {
184 if (m_type & (MISSION_TYPE_SINGLE |
185 MISSION_TYPE_MULTI |
186 MISSION_TYPE_TRAINING |
187 MISSION_TYPE_MULTI_COOP |
188 MISSION_TYPE_MULTI_DOGFIGHT |
189 MISSION_TYPE_MULTI_TEAMS)) {
190 modify(_m_type, m_type);
191 modelChanged();
192 } else {
193 auto button = _viewport->dialogProvider->showButtonDialog(DialogType::Error, "Invalid mission type", "You must select the game type: training, single, or multiplayer",
194 { DialogButton::Ok });
195 if (button == DialogButton::Ok) {
196 return;
197 }
198 }
199 }
200
getMissionType()201 int MissionSpecDialogModel::getMissionType() {
202 return _m_type;
203 }
204
setNumRespawns(uint m_num_respawns)205 void MissionSpecDialogModel::setNumRespawns(uint m_num_respawns) {
206 modify(_m_num_respawns, m_num_respawns);
207 }
208
getNumRespawns()209 uint MissionSpecDialogModel::getNumRespawns() {
210 return _m_num_respawns;
211 }
212
setMaxRespawnDelay(int m_max_respawn_delay)213 void MissionSpecDialogModel::setMaxRespawnDelay(int m_max_respawn_delay) {
214 modify(_m_max_respawn_delay, m_max_respawn_delay);
215 }
216
getMaxRespawnDelay()217 int MissionSpecDialogModel::getMaxRespawnDelay() {
218 return _m_max_respawn_delay;
219 }
220
setSquadronName(const SCP_string & m_squad_name)221 void MissionSpecDialogModel::setSquadronName(const SCP_string& m_squad_name) {
222 modify(_m_squad_name, m_squad_name);
223 }
224
getSquadronName()225 SCP_string MissionSpecDialogModel::getSquadronName() {
226 return _m_squad_name;
227 }
228
setSquadronLogo(const SCP_string & m_squad_filename)229 void MissionSpecDialogModel::setSquadronLogo(const SCP_string& m_squad_filename) {
230 modify(_m_squad_filename, m_squad_filename);
231 }
232
getSquadronLogo()233 SCP_string MissionSpecDialogModel::getSquadronLogo() {
234 return _m_squad_filename;
235 }
236
setLowResLoadingScreen(const SCP_string & m_loading_640)237 void MissionSpecDialogModel::setLowResLoadingScreen(const SCP_string& m_loading_640) {
238 modify(_m_loading_640, m_loading_640);
239 }
240
getLowResLoadingScren()241 SCP_string MissionSpecDialogModel::getLowResLoadingScren() {
242 return _m_loading_640;
243 }
244
setHighResLoadingScreen(const SCP_string & m_loading_1024)245 void MissionSpecDialogModel::setHighResLoadingScreen(const SCP_string& m_loading_1024) {
246 modify(_m_loading_1024, m_loading_1024);
247 }
248
getHighResLoadingScren()249 SCP_string MissionSpecDialogModel::getHighResLoadingScren() {
250 return _m_loading_1024;
251 }
252
setDisallowSupport(bool m_disallow_support)253 void MissionSpecDialogModel::setDisallowSupport(bool m_disallow_support) {
254 modify(_m_disallow_support, m_disallow_support);
255 }
256
getDisallowSupport()257 bool MissionSpecDialogModel::getDisallowSupport() {
258 return _m_disallow_support;
259 }
260
setHullRepairMax(float m_max_hull_repair_val)261 void MissionSpecDialogModel::setHullRepairMax(float m_max_hull_repair_val) {
262 modify(_m_max_hull_repair_val, m_max_hull_repair_val);
263 }
264
getHullRepairMax()265 int MissionSpecDialogModel::getHullRepairMax() {
266 return _m_max_hull_repair_val;
267 }
268
setSubsysRepairMax(float m_max_subsys_repair_val)269 void MissionSpecDialogModel::setSubsysRepairMax(float m_max_subsys_repair_val){
270 modify(_m_max_subsys_repair_val, m_max_subsys_repair_val);
271 }
272
getSubsysRepairMax()273 int MissionSpecDialogModel::getSubsysRepairMax() {
274 return _m_max_subsys_repair_val;
275 }
276
setTrailThresholdFlag(bool m_contrail_threshold_flag)277 void MissionSpecDialogModel::setTrailThresholdFlag(bool m_contrail_threshold_flag) {
278 modify(_m_contrail_threshold_flag, m_contrail_threshold_flag);
279 }
280
getTrailThresholdFlag()281 bool MissionSpecDialogModel::getTrailThresholdFlag() {
282 return _m_contrail_threshold_flag;
283 }
284
setTrailDisplaySpeed(int m_contrail_threshold)285 void MissionSpecDialogModel::setTrailDisplaySpeed(int m_contrail_threshold) {
286 modify(_m_contrail_threshold, m_contrail_threshold);
287 }
288
getTrailDisplaySpeed()289 int MissionSpecDialogModel::getTrailDisplaySpeed() {
290 return _m_contrail_threshold;
291 }
292
setCommandSender(const SCP_string & m_command_sender)293 void MissionSpecDialogModel::setCommandSender(const SCP_string& m_command_sender) {
294 modify(_m_command_sender, m_command_sender);
295 }
296
getCommandSender()297 SCP_string MissionSpecDialogModel::getCommandSender() {
298 return _m_command_sender;
299 }
300
setCommandPersona(int m_command_persona)301 void MissionSpecDialogModel::setCommandPersona(int m_command_persona) {
302 modify(_m_command_persona, m_command_persona);
303 }
304
getCommandPersona()305 int MissionSpecDialogModel::getCommandPersona() {
306 return _m_command_persona;
307 }
308
setEventMusic(int m_event_music)309 void MissionSpecDialogModel::setEventMusic(int m_event_music) {
310 modify(_m_event_music, m_event_music);
311 }
312
getEventMusic()313 int MissionSpecDialogModel::getEventMusic() {
314 return _m_event_music;
315 }
316
setSubEventMusic(const SCP_string & m_substitute_event_music)317 void MissionSpecDialogModel::setSubEventMusic(const SCP_string& m_substitute_event_music) {
318 modify(_m_substitute_event_music, m_substitute_event_music);
319 }
320
getSubEventMusic()321 SCP_string MissionSpecDialogModel::getSubEventMusic() {
322 return _m_substitute_event_music;
323 }
324
setMissionFlag(Mission::Mission_Flags flag,bool enabled)325 void MissionSpecDialogModel::setMissionFlag(Mission::Mission_Flags flag, bool enabled) {
326 if (_m_flags[flag] != enabled) {
327 _m_flags.set(flag, enabled);
328 set_modified();
329 modelChanged();
330 }
331 }
332
getMissionFlags() const333 const flagset<Mission::Mission_Flags>& MissionSpecDialogModel::getMissionFlags() const {
334 return _m_flags;
335 }
336
setMissionFullWar(bool enabled)337 void MissionSpecDialogModel::setMissionFullWar(bool enabled) {
338 if (_m_full_war != enabled) {
339 _m_full_war = enabled;
340 _m_flags.set(Mission::Mission_Flags::All_attack, enabled);
341 set_modified();
342 modelChanged();
343 }
344 }
345
setAIProfileIndex(int m_ai_profile)346 void MissionSpecDialogModel::setAIProfileIndex(int m_ai_profile) {
347 modify(_m_ai_profile, m_ai_profile);
348 }
349
getAIProfileIndex() const350 int MissionSpecDialogModel::getAIProfileIndex() const {
351 return _m_ai_profile;
352 }
353
setMissionDescText(const SCP_string & m_mission_desc)354 void MissionSpecDialogModel::setMissionDescText(const SCP_string& m_mission_desc) {
355 modify(_m_mission_desc, m_mission_desc.substr(0, MIN(MISSION_DESC_LENGTH, m_mission_desc.length())));
356 }
357
getMissionDescText()358 SCP_string MissionSpecDialogModel::getMissionDescText() {
359 return _m_mission_desc;
360 }
361
setDesignerNoteText(const SCP_string & m_mission_notes)362 void MissionSpecDialogModel::setDesignerNoteText(const SCP_string& m_mission_notes) {
363 modify(_m_mission_notes, m_mission_notes.substr(0, MIN(NOTES_LENGTH, m_mission_notes.length())));
364 }
365
getDesignerNoteText()366 SCP_string MissionSpecDialogModel::getDesignerNoteText() {
367 return _m_mission_notes;
368 }
369
set_modified()370 void MissionSpecDialogModel::set_modified() {
371 if (!_modified) {
372 _modified = true;
373 }
374 }
375
query_modified()376 bool MissionSpecDialogModel::query_modified() {
377 return _modified;
378 }
379
380 }
381 }
382 }
383