1 /*
2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
3 *
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on the
6 * source.
7 *
8 */
9
10
11
12 #include "stdafx.h"
13 #include "FRED.h"
14 #include "DebriefingEditorDlg.h"
15 #include "FREDDoc.h"
16 #include "mission/missionbriefcommon.h"
17 #include "mission/missionparse.h"
18 #include "globalincs/linklist.h"
19 #include "parse/sexp.h"
20 #include "gamesnd/eventmusic.h"
21 #include "cfile/cfile.h"
22 #include "sound/audiostr.h"
23 #include "localization/localize.h"
24 #include "jumpnode/jumpnode.h"
25
26
27 #ifdef _DEBUG
28 #undef THIS_FILE
29 static char THIS_FILE[] = __FILE__;
30 #endif
31
32 /////////////////////////////////////////////////////////////////////////////
33 // debriefing_editor_dlg dialog
34
debriefing_editor_dlg(CWnd * pParent)35 debriefing_editor_dlg::debriefing_editor_dlg(CWnd* pParent /*=NULL*/)
36 : CDialog(debriefing_editor_dlg::IDD, pParent)
37 {
38 //{{AFX_DATA_INIT(debriefing_editor_dlg)
39 m_text = _T("");
40 m_voice = _T("");
41 m_stage_title = _T("");
42 m_rec_text = _T("");
43 m_debriefPass_music = 0;
44 m_debriefAvg_music = 0;
45 m_debriefFail_music = 0;
46 m_current_debriefing = -1;
47 //}}AFX_DATA_INIT
48
49 modified = 0;
50 m_cur_stage = 0;
51 m_last_stage = -1;
52 m_voice_id = -1;
53 select_sexp_node = -1;
54 }
55
DoDataExchange(CDataExchange * pDX)56 void debriefing_editor_dlg::DoDataExchange(CDataExchange* pDX)
57 {
58 CDialog::DoDataExchange(pDX);
59 //{{AFX_DATA_MAP(debriefing_editor_dlg)
60 DDX_Control(pDX, IDC_TREE, m_tree);
61 DDX_Text(pDX, IDC_TEXT, m_text);
62 DDX_Text(pDX, IDC_VOICE, m_voice);
63 DDX_Text(pDX, IDC_STAGE_TITLE, m_stage_title);
64 DDX_Text(pDX, IDC_REC_TEXT, m_rec_text);
65 DDX_CBIndex(pDX, IDC_SUCCESSFUL_MISSION_TRACK, m_debriefPass_music);
66 DDX_CBIndex(pDX, IDC_DEBRIEFING_TRACK, m_debriefAvg_music);
67 DDX_CBIndex(pDX, IDC_FAILED_MISSION_TRACK, m_debriefFail_music);
68 //}}AFX_DATA_MAP
69
70 DDV_MaxChars(pDX, m_voice, MAX_FILENAME_LEN - 1);
71 }
72
BEGIN_MESSAGE_MAP(debriefing_editor_dlg,CDialog)73 BEGIN_MESSAGE_MAP(debriefing_editor_dlg, CDialog)
74 //{{AFX_MSG_MAP(debriefing_editor_dlg)
75 ON_BN_CLICKED(IDC_NEXT, OnNext)
76 ON_BN_CLICKED(IDC_PREV, OnPrev)
77 ON_BN_CLICKED(IDC_BROWSE, OnBrowse)
78 ON_BN_CLICKED(IDC_ADD_STAGE, OnAddStage)
79 ON_BN_CLICKED(IDC_DELETE_STAGE, OnDeleteStage)
80 ON_BN_CLICKED(IDC_INSERT_STAGE, OnInsertStage)
81 ON_NOTIFY(NM_RCLICK, IDC_TREE, OnRclickTree)
82 ON_NOTIFY(TVN_BEGINLABELEDIT, IDC_TREE, OnBeginlabeleditTree)
83 ON_NOTIFY(TVN_ENDLABELEDIT, IDC_TREE, OnEndlabeleditTree)
84 ON_WM_CLOSE()
85 ON_WM_INITMENU()
86 ON_BN_CLICKED(IDC_PLAY, OnPlay)
87 //}}AFX_MSG_MAP
88 END_MESSAGE_MAP()
89
90 /////////////////////////////////////////////////////////////////////////////
91 // debriefing_editor_dlg message handlers
92
93 void debriefing_editor_dlg::OnInitMenu(CMenu* pMenu)
94 {
95 int i;
96 CMenu *m;
97
98 // disable any items we should disable
99 m = pMenu->GetSubMenu(0);
100
101 // uncheck all menu items
102 for (i = 0; i < Num_teams; i++ )
103 m->CheckMenuItem( i, MF_BYPOSITION | MF_UNCHECKED );
104
105 for ( i = Num_teams; i < MAX_TVT_TEAMS; i++ )
106 m->EnableMenuItem(i, MF_BYPOSITION | MF_GRAYED);
107
108
109 // put a check next to the currently selected item
110 m->CheckMenuItem(m_current_debriefing, MF_BYPOSITION | MF_CHECKED );
111
112 // Karajorma - it might be nice to autobalance the briefings and debriefings but I'm not doing anything till I
113 // understand how the how system works better. disabling the option for now.
114 m = pMenu->GetSubMenu(1);
115 m->EnableMenuItem(ID_AUTOBALANCE, MF_GRAYED);
116
117 CDialog::OnInitMenu(pMenu);
118 }
119
OnInitDialog()120 BOOL debriefing_editor_dlg::OnInitDialog()
121 {
122 int i, n;
123
124 CDialog::OnInitDialog();
125 m_play_bm.LoadBitmap(IDB_PLAY);
126 ((CButton *) GetDlgItem(IDC_PLAY)) -> SetBitmap(m_play_bm);
127 CComboBox *box;
128 box = (CComboBox *) GetDlgItem(IDC_ICON_IMAGE);
129
130 m_current_debriefing = 0;
131 UpdateData(FALSE);
132
133 Debriefing = &Debriefings[m_current_debriefing];
134
135 box = (CComboBox *) GetDlgItem(IDC_SUCCESSFUL_MISSION_TRACK);
136 box->AddString("None");
137 for (i=0; i<Num_music_files; i++)
138 box->AddString(Spooled_music[i].name);
139
140 box = (CComboBox *) GetDlgItem(IDC_DEBRIEFING_TRACK);
141 box->AddString("None");
142 for (i=0; i<Num_music_files; i++)
143 box->AddString(Spooled_music[i].name);
144
145 box = (CComboBox *) GetDlgItem(IDC_FAILED_MISSION_TRACK);
146 box->AddString("None");
147 for (i=0; i<Num_music_files; i++)
148 box->AddString(Spooled_music[i].name);
149
150 m_debriefPass_music = Mission_music[SCORE_DEBRIEF_SUCCESS] + 1;
151 m_debriefAvg_music = Mission_music[SCORE_DEBRIEF_AVERAGE] + 1;
152 m_debriefFail_music = Mission_music[SCORE_DEBRIEF_FAIL] + 1;
153
154 m_tree.link_modified(&modified); // provide way to indicate trees are modified in dialog
155 n = m_tree.select_sexp_node = select_sexp_node;
156 select_sexp_node = -1;
157 if (n != -1) {
158 for (i=0; i<Debriefing->num_stages; i++)
159 if (query_node_in_sexp(n, Debriefing->stages[i].formula))
160 break;
161
162 if (i < Debriefing->num_stages) {
163 m_cur_stage = i;
164 update_data();
165 GetDlgItem(IDC_TREE) -> SetFocus();
166 m_tree.hilite_item(m_tree.select_sexp_node);
167 set_modified();
168 return FALSE;
169 }
170 }
171
172 CDialog::OnInitDialog();
173 update_data();
174 set_modified();
175
176 // hard coded stuff to deal with the multiple briefings per mission.
177
178 return TRUE;
179 }
180
update_data(int update)181 void debriefing_editor_dlg::update_data(int update)
182 {
183 int enable, save_debriefing;
184 debrief_stage *ptr;
185
186 save_debriefing = m_current_debriefing;
187
188 if (update)
189 UpdateData(TRUE);
190
191 // based on the game type, enable the multiple briefings combo box (or disable it)
192
193 // set up the pointer to the briefing that we are editing
194 if ( save_debriefing != m_current_debriefing )
195 Debriefing = &Debriefings[save_debriefing];
196 else
197 Debriefing = &Debriefings[m_current_debriefing];
198
199 if (m_last_stage >= 0) {
200 ptr = &Debriefing->stages[m_last_stage];
201 if (ptr->formula >= 0)
202 free_sexp2(ptr->formula);
203
204 ptr->formula = m_tree.save_tree();
205 deconvert_multiline_string(ptr->text, m_text);
206 lcl_fred_replace_stuff(ptr->text);
207 deconvert_multiline_string(ptr->recommendation_text, m_rec_text);
208 lcl_fred_replace_stuff(ptr->recommendation_text);
209 string_copy(ptr->voice, m_voice, MAX_FILENAME_LEN);
210 }
211
212 // now get new stage data
213 if ((m_cur_stage >= 0) && (m_cur_stage < Debriefing->num_stages)) {
214 ptr = &Debriefing->stages[m_cur_stage];
215 m_stage_title.Format("Stage %d of %d", m_cur_stage + 1, Debriefing->num_stages);
216 m_tree.load_tree(ptr->formula);
217 convert_multiline_string(m_text, ptr->text);
218 convert_multiline_string(m_rec_text, ptr->recommendation_text);
219 m_voice = ptr->voice;
220 enable = TRUE;
221
222 } else {
223 m_stage_title = _T("No stages");
224 m_tree.clear_tree();
225 m_text = _T("");
226 m_rec_text = _T("");
227 m_voice = _T("");
228 enable = FALSE;
229 m_cur_stage = -1;
230 }
231
232 if (m_cur_stage == Debriefing->num_stages - 1)
233 GetDlgItem(IDC_NEXT) -> EnableWindow(FALSE);
234 else
235 GetDlgItem(IDC_NEXT) -> EnableWindow(enable);
236
237 if (m_cur_stage)
238 GetDlgItem(IDC_PREV) -> EnableWindow(enable);
239 else
240 GetDlgItem(IDC_PREV) -> EnableWindow(FALSE);
241
242 if (Debriefing->num_stages >= MAX_DEBRIEF_STAGES)
243 GetDlgItem(IDC_ADD_STAGE) -> EnableWindow(FALSE);
244 else
245 GetDlgItem(IDC_ADD_STAGE) -> EnableWindow(TRUE);
246
247 if (Debriefing->num_stages) {
248 GetDlgItem(IDC_DELETE_STAGE) -> EnableWindow(enable);
249 GetDlgItem(IDC_INSERT_STAGE) -> EnableWindow(enable);
250
251 } else {
252 GetDlgItem(IDC_DELETE_STAGE) -> EnableWindow(FALSE);
253 GetDlgItem(IDC_INSERT_STAGE) -> EnableWindow(FALSE);
254 }
255
256 GetDlgItem(IDC_VOICE) -> EnableWindow(enable);
257 GetDlgItem(IDC_BROWSE) -> EnableWindow(enable);
258 GetDlgItem(IDC_TEXT) -> EnableWindow(enable);
259 GetDlgItem(IDC_REC_TEXT) -> EnableWindow(enable);
260 GetDlgItem(IDC_TREE) -> EnableWindow(enable);
261
262 m_last_stage = m_cur_stage;
263 UpdateData(FALSE);
264
265 #ifndef NDEBUG
266 count_free_sexp_nodes();
267 #endif
268 }
269
OnNext()270 void debriefing_editor_dlg::OnNext()
271 {
272 audiostream_close_file(m_voice_id, 0);
273 m_voice_id = -1;
274
275 m_cur_stage++;
276 update_data();
277 }
278
OnPrev()279 void debriefing_editor_dlg::OnPrev()
280 {
281 audiostream_close_file(m_voice_id, 0);
282 m_voice_id = -1;
283
284 m_cur_stage--;
285 update_data();
286 }
287
OnBrowse()288 void debriefing_editor_dlg::OnBrowse()
289 {
290 int z;
291 CString name;
292
293 audiostream_close_file(m_voice_id, 0);
294 m_voice_id = -1;
295
296 UpdateData(TRUE);
297
298 if (The_mission.game_type & MISSION_TYPE_TRAINING)
299 z = cfile_push_chdir(CF_TYPE_VOICE_TRAINING);
300 else
301 z = cfile_push_chdir(CF_TYPE_VOICE_DEBRIEFINGS);
302
303 CFileDialog dlg(TRUE, "wav", NULL, OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR,
304 "Voice Files (*.ogg, *.wav)|*.ogg;*.wav|Ogg Vorbis Files (*.ogg)|*.ogg|Wave Files (*.wav)|*.wav||");
305
306 if (dlg.DoModal() == IDOK) {
307 m_voice = dlg.GetFileName();
308 UpdateData(FALSE);
309 }
310
311 if (!z)
312 cfile_pop_dir();
313 }
314
OnAddStage()315 void debriefing_editor_dlg::OnAddStage()
316 {
317 int i;
318
319 if (Debriefing->num_stages >= MAX_DEBRIEF_STAGES)
320 return;
321
322 audiostream_close_file(m_voice_id, 0);
323 m_voice_id = -1;
324
325 m_cur_stage = i = Debriefing->num_stages++;
326 copy_stage(i - 1, i, 1);
327 update_data(1);
328 }
329
OnDeleteStage()330 void debriefing_editor_dlg::OnDeleteStage()
331 {
332 int i, z;
333
334 if (m_cur_stage < 0)
335 return;
336
337 audiostream_close_file(m_voice_id, 0);
338 m_voice_id = -1;
339
340 Assert(Debriefing->num_stages);
341 z = m_cur_stage;
342 m_cur_stage = -1;
343 update_data(1);
344 for (i=z+1; i<Debriefing->num_stages; i++) {
345 copy_stage(i, i - 1);
346 }
347
348 Debriefing->num_stages--;
349 m_cur_stage = z;
350 if (m_cur_stage >= Debriefing->num_stages)
351 m_cur_stage = Debriefing->num_stages - 1;
352
353 update_data(0);
354 }
355
OnInsertStage()356 void debriefing_editor_dlg::OnInsertStage()
357 {
358 int i, z;
359
360 if (Debriefing->num_stages >= MAX_DEBRIEF_STAGES)
361 return;
362
363 if (!Debriefing->num_stages) {
364 OnAddStage();
365 return;
366 }
367
368 audiostream_close_file(m_voice_id, 0);
369 m_voice_id = -1;
370
371 z = m_cur_stage;
372 m_cur_stage = -1;
373 update_data(1);
374 for (i=Debriefing->num_stages; i>z; i--) {
375 copy_stage(i - 1, i);
376 }
377
378 Debriefing->num_stages++;
379 copy_stage(z, z + 1);
380 Debriefing->stages[z].formula = -1;
381 m_cur_stage = z;
382 update_data(0);
383 }
384
copy_stage(int from,int to,int clear_formula)385 void debriefing_editor_dlg::copy_stage(int from, int to, int clear_formula)
386 {
387 if ((from < 0) || (from >= Debriefing->num_stages)) {
388 Debriefing->stages[to].text = "<Text here>";
389 strcpy_s(Debriefing->stages[to].voice, "none.wav");
390 Debriefing->stages[to].formula = -1;
391 return;
392 }
393
394 if (clear_formula)
395 Debriefing->stages[to].formula = -1;
396 else
397 Debriefing->stages[to].formula = Debriefing->stages[from].formula;
398
399 Debriefing->stages[to].text = Debriefing->stages[from].text;
400 strcpy_s( Debriefing->stages[to].voice, Debriefing->stages[from].voice );
401 Debriefing->stages[to].recommendation_text = Debriefing->stages[from].recommendation_text;
402 }
403
OnRclickTree(NMHDR * pNMHDR,LRESULT * pResult)404 void debriefing_editor_dlg::OnRclickTree(NMHDR* pNMHDR, LRESULT* pResult)
405 {
406 m_tree.right_clicked();
407 *pResult = 0;
408 }
409
OnBeginlabeleditTree(NMHDR * pNMHDR,LRESULT * pResult)410 void debriefing_editor_dlg::OnBeginlabeleditTree(NMHDR* pNMHDR, LRESULT* pResult)
411 {
412 TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
413
414 if (m_tree.edit_label(pTVDispInfo->item.hItem) == 1) {
415 *pResult = 0;
416 modified = 1;
417
418 } else
419 *pResult = 1;
420 }
421
OnEndlabeleditTree(NMHDR * pNMHDR,LRESULT * pResult)422 void debriefing_editor_dlg::OnEndlabeleditTree(NMHDR* pNMHDR, LRESULT* pResult)
423 {
424 TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
425
426 *pResult = m_tree.end_label_edit(pTVDispInfo->item);
427 }
428
OnClose()429 void debriefing_editor_dlg::OnClose()
430 {
431 audiostream_close_file(m_voice_id, 0);
432 m_voice_id = -1;
433 m_cur_stage = -1;
434 update_data(1);
435
436 Mission_music[SCORE_DEBRIEF_SUCCESS] = m_debriefPass_music - 1;
437 Mission_music[SCORE_DEBRIEF_AVERAGE] = m_debriefAvg_music - 1;
438 Mission_music[SCORE_DEBRIEF_FAIL] = m_debriefFail_music - 1;
439
440 CDialog::OnClose();
441 }
442
OnOK()443 void debriefing_editor_dlg::OnOK()
444 {
445 }
446
OnCommand(WPARAM wParam,LPARAM lParam)447 BOOL debriefing_editor_dlg::OnCommand(WPARAM wParam, LPARAM lParam)
448 {
449 int id;
450
451 // deal with figuring out menu stuff
452 id = LOWORD(wParam);
453 if ( (id >= ID_TEAM_1) && (id < ID_TEAM_3) ) {
454 update_data(1);
455
456 // set the current debriefing
457 m_current_debriefing = id - ID_TEAM_1;
458
459 // put user back at first stage for this team (or no current stage is there are none).
460 Debriefing = &Debriefings[m_current_debriefing];
461 if ( Debriefing->num_stages > 0 )
462 m_cur_stage = 0;
463 else
464 m_cur_stage = -1;
465
466 m_last_stage = -1;
467 update_data(0);
468 }
469
470 return CDialog::OnCommand(wParam, lParam);
471 }
472
DestroyWindow()473 BOOL debriefing_editor_dlg::DestroyWindow()
474 {
475 audiostream_close_file(m_voice_id, 0);
476 m_play_bm.DeleteObject();
477 return CDialog::DestroyWindow();
478 }
479
OnPlay()480 void debriefing_editor_dlg::OnPlay()
481 {
482 GetDlgItem(IDC_VOICE)->GetWindowText(m_voice);
483
484 if (m_voice_id >= 0) {
485 audiostream_close_file(m_voice_id, 0);
486 m_voice_id = -1;
487 return;
488 }
489
490 // we use ASF_EVENTMUSIC here so that it will keep the extension in place
491 m_voice_id = audiostream_open((char *)(LPCSTR) m_voice, ASF_EVENTMUSIC);
492
493 if (m_voice_id >= 0) {
494 audiostream_play(m_voice_id, 1.0f, 0);
495 }
496 }
497