]> icculus.org git repositories - taylor/freespace2.git/blob - src/fred2/briefingeditordlg.cpp
fix issue with looping audio streams
[taylor/freespace2.git] / src / fred2 / briefingeditordlg.cpp
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
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Fred2/BriefingEditorDlg.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Briefing editor dialog box class.
16  *
17  * $Log$
18  * Revision 1.3  2002/06/09 04:41:16  relnev
19  * added copyright header
20  *
21  * Revision 1.2  2002/05/07 03:16:43  theoddone33
22  * The Great Newline Fix
23  *
24  * Revision 1.1.1.1  2002/05/03 03:28:08  root
25  * Initial import.
26  *
27  * 
28  * 9     7/19/99 3:01p Dave
29  * Fixed icons. Added single transport icon.
30  * 
31  * 8     7/18/99 5:19p Dave
32  * Jump node icon. Fixed debris fogging. Framerate warning stuff.
33  * 
34  * 7     7/09/99 5:54p Dave
35  * Seperated cruiser types into individual types. Added tons of new
36  * briefing icons. Campaign screen.
37  * 
38  * 6     5/20/99 1:46p Andsager
39  * Add briefing view copy and paste between stages
40  * 
41  * 5     4/23/99 12:01p Johnson
42  * Added SIF_HUGE_SHIP
43  * 
44  * 4     11/30/98 5:32p Dave
45  * Fixed up Fred support for software mode.
46  * 
47  * 3     10/16/98 4:28p Andsager
48  * Fix fred dependency
49  * 
50  * 2     10/07/98 6:28p Dave
51  * Initial checkin. Renamed all relevant stuff to be Fred2 instead of
52  * Fred. Globalized mission and campaign file extensions. Removed Silent
53  * Threat specific code.
54  * 
55  * 1     10/07/98 3:02p Dave
56  * 
57  * 1     10/07/98 3:00p Dave
58  * 
59  * 63    5/21/98 4:20p Dave
60  * Fixed bug with briefing editor when no current stage selected.
61  * 
62  * 62    5/21/98 12:58a Hoffoss
63  * Fixed warnings optimized build turned up.
64  * 
65  * 61    5/14/98 4:47p Hoffoss
66  * Made it so when you switch to a new team's debriefing (via menu), it
67  * updates the camera position to what it should be for new briefing
68  * stage.
69  * 
70  * 60    4/30/98 8:23p John
71  * Fixed some bugs with Fred caused by my new cfile code.
72  * 
73  * 59    4/22/98 9:56a Sandeep
74  * 
75  * 58    4/20/98 4:40p Hoffoss
76  * Added a button to 4 editors to play the chosen wave file.
77  * 
78  * 57    4/16/98 2:49p Johnson
79  * Fixed initialization for new icons in briefing.
80  * 
81  * 56    4/07/98 6:32p Dave
82  * Fixed function I forget to change back.
83  * 
84  * 55    4/07/98 6:27p Dave
85  * Implemented a more boiler-plate solution to the multiple team briefing
86  * problem in this editor.
87  * 
88  * 54    4/07/98 4:51p Dave
89  * (Hoffoss) Fixed a boat load of bugs caused by the new change to
90  * multiple briefings.  Allender's code changed to support this in the
91  * briefing editor wasn't quite correct.
92  * 
93  * 53    4/06/98 5:37p Hoffoss
94  * Added sexp tree support to briefings in Fred.
95  * 
96  * 52    4/06/98 10:43a John
97  * Fixed bugs with inserting/deleting stages
98  * 
99  * 51    4/03/98 12:39p Hoffoss
100  * Changed starting directory for browse buttons in several editors.
101  * 
102  * 50    4/03/98 11:34a John
103  * Fixed the stuff I broke in Fred from the new breifing
104  * 
105  * 49    3/26/98 6:40p Lawrance
106  * Don't store icon text for briefings
107  * 
108  * 48    3/21/98 7:36p Lawrance
109  * Move jump nodes to own lib.
110  * 
111  * 47    3/19/98 4:24p Hoffoss
112  * Added remaining support for command brief screen (ANI and WAVE file
113  * playing).
114  * 
115  * 46    3/17/98 2:00p Hoffoss
116  * Added ability to make an icon from a jump node in briefing editor.
117  * 
118  * 45    2/18/98 6:44p Hoffoss
119  * Added support for lines between icons in briefings for Fred.
120  * 
121  * 44    2/09/98 9:25p Allender
122  * team v team support.  multiple pools and breifings
123  * 
124  * 43    2/04/98 4:31p Allender
125  * support for multiple briefings and debriefings.  Changes to mission
126  * type (now a bitfield).  Bitfield defs for multiplayer modes
127  * 
128  * 42    1/28/98 7:19p Lawrance
129  * Get fading/highlighting animations working
130  * 
131  * 41    12/28/97 5:52p Lawrance
132  * Add support for debriefing success/fail music.
133  * 
134  * 40    11/04/97 4:33p Hoffoss
135  * Made saving keep the current briefing state intact.
136  * 
137  * 39    11/04/97 11:31a Duncan
138  * Made make icon button gray if at max icons already.
139  * 
140  * 38    11/03/97 4:07p Jasen
141  * Fixed bug in briefing editor caused by changes in TEAM_* defines in the
142  * past and whoever made these changes failed to update this editor along
143  * with it.
144  * 
145  * 37    10/19/97 11:32p Hoffoss
146  * Added support for briefing cuts in Fred.
147  * 
148  * 36    10/12/97 11:23p Mike
149  * About ten fixes/changes in the docking system.
150  * Also, renamed SIF_REARM_REPAIR to SIF_SUPPORT.
151  * 
152  * 35    9/30/97 5:56p Hoffoss
153  * Added music selection combo boxes to Fred.
154  *
155  * $NoKeywords: $
156  */
157
158 #include "stdafx.h"
159 #include <mmsystem.h>
160 #include "fred.h"
161 #include "briefingeditordlg.h"
162 #include "freddoc.h"
163 #include "missionbriefcommon.h"
164 #include "missionparse.h"
165 #include "fredrender.h"
166 #include "management.h"
167 #include "linklist.h"
168 #include "mainfrm.h"
169 #include "bmpman.h"
170 #include "eventmusic.h"
171 #include "starfield.h"
172 #include "jumpnode.h"
173 #include "cfile.h"
174
175 #ifdef _DEBUG
176 #define new DEBUG_NEW
177 #undef THIS_FILE
178 static char THIS_FILE[] = __FILE__;
179 #endif
180
181 #define ID_MENU         9000
182 #define NAVBUOY_NAME "Terran NavBuoy"
183
184 static int Max_icons_for_lines;
185
186 /////////////////////////////////////////////////////////////////////////////
187 // briefing_editor_dlg dialog
188
189 briefing_editor_dlg::briefing_editor_dlg(CWnd* pParent /*=NULL*/)
190         : CDialog(briefing_editor_dlg::IDD, pParent)
191 {
192         int i, z;
193
194         // figure out max icons we can have with lines to each other less than max allowed lines.
195         // Basically, # lines = (# icons - 1) factorial
196         Max_icons_for_lines = 0;
197         do {
198                 i = ++Max_icons_for_lines + 1;
199                 z = 0;
200                 while (--i)
201                         z += i;
202
203         } while (z < MAX_BRIEF_STAGE_LINES);
204
205         //{{AFX_DATA_INIT(briefing_editor_dlg)
206         m_hilight = FALSE;
207         m_icon_image = -1;
208         m_icon_label = _T("");
209         m_stage_title = _T("");
210         m_text = _T("");
211         m_time = _T("");
212         m_voice = _T("");
213         m_icon_text = _T("");
214         m_icon_team = -1;
215         m_ship_type = -1;
216         m_change_local = FALSE;
217         m_id = 0;
218         m_briefing_music = -1;
219         m_cut_next = FALSE;
220         m_cut_prev = FALSE;
221         m_current_briefing = -1;
222         //}}AFX_DATA_INIT
223         m_cur_stage = 0;
224         m_last_stage = m_cur_icon = m_last_icon = -1;
225         m_tree.link_modified(&modified);  // provide way to indicate trees are modified in dialog
226
227         // copy view initialization
228         m_copy_view_set = 0;
229 }
230
231 void briefing_editor_dlg::DoDataExchange(CDataExchange* pDX)
232 {
233         CDialog::DoDataExchange(pDX);
234         //{{AFX_DATA_MAP(briefing_editor_dlg)
235         DDX_Control(pDX, IDC_TREE, m_tree);
236         DDX_Control(pDX, IDC_LINES, m_lines);
237         DDX_Check(pDX, IDC_HILIGHT, m_hilight);
238         DDX_CBIndex(pDX, IDC_ICON_IMAGE, m_icon_image);
239         DDX_Text(pDX, IDC_ICON_LABEL, m_icon_label);
240         DDX_Text(pDX, IDC_STAGE_TITLE, m_stage_title);
241         DDX_Text(pDX, IDC_TEXT, m_text);
242         DDX_Text(pDX, IDC_TIME, m_time);
243         DDX_Text(pDX, IDC_VOICE, m_voice);
244         DDX_Text(pDX, IDC_ICON_TEXT, m_icon_text);
245         DDX_CBIndex(pDX, IDC_TEAM, m_icon_team);
246         DDX_CBIndex(pDX, IDC_SHIP_TYPE, m_ship_type);
247         DDX_Check(pDX, IDC_LOCAL, m_change_local);
248         DDX_Text(pDX, IDC_ID, m_id);
249         DDX_CBIndex(pDX, IDC_BRIEFING_MUSIC, m_briefing_music);
250         DDX_Check(pDX, IDC_CUT_NEXT, m_cut_next);
251         DDX_Check(pDX, IDC_CUT_PREV, m_cut_prev);
252         //}}AFX_DATA_MAP
253
254         DDV_MaxChars(pDX, m_text, MAX_BRIEF_LEN - 1);
255         DDV_MaxChars(pDX, m_voice, MAX_FILENAME_LEN - 1);
256         DDV_MaxChars(pDX, m_icon_label, MAX_LABEL_LEN - 1);
257         DDV_MaxChars(pDX, m_icon_text, MAX_ICON_TEXT_LEN - 1);
258 }
259
260 BEGIN_MESSAGE_MAP(briefing_editor_dlg, CDialog)
261         //{{AFX_MSG_MAP(briefing_editor_dlg)
262         ON_WM_CLOSE()
263         ON_BN_CLICKED(IDC_NEXT, OnNext)
264         ON_BN_CLICKED(IDC_PREV, OnPrev)
265         ON_BN_CLICKED(IDC_BROWSE, OnBrowse)
266         ON_BN_CLICKED(IDC_ADD_STAGE, OnAddStage)
267         ON_BN_CLICKED(IDC_DELETE_STAGE, OnDeleteStage)
268         ON_BN_CLICKED(IDC_INSERT_STAGE, OnInsertStage)
269         ON_BN_CLICKED(IDC_MAKE_ICON, OnMakeIcon)
270         ON_BN_CLICKED(IDC_DELETE_ICON, OnDeleteIcon)
271         ON_BN_CLICKED(IDC_GOTO_VIEW, OnGotoView)
272         ON_BN_CLICKED(IDC_SAVE_VIEW, OnSaveView)
273         ON_CBN_SELCHANGE(IDC_ICON_IMAGE, OnSelchangeIconImage)
274         ON_CBN_SELCHANGE(IDC_TEAM, OnSelchangeTeam)
275         ON_BN_CLICKED(IDC_PROPAGATE_ICONS, OnPropagateIcons)
276         ON_WM_INITMENU()
277         ON_BN_CLICKED(IDC_LINES, OnLines)
278         ON_NOTIFY(NM_RCLICK, IDC_TREE, OnRclickTree)
279         ON_NOTIFY(TVN_BEGINLABELEDIT, IDC_TREE, OnBeginlabeleditTree)
280         ON_NOTIFY(TVN_ENDLABELEDIT, IDC_TREE, OnEndlabeleditTree)
281         ON_BN_CLICKED(IDC_PLAY, OnPlay)
282         ON_BN_CLICKED(IDC_COPY_VIEW, OnCopyView)
283         ON_BN_CLICKED(IDC_PASTE_VIEW, OnPasteView)
284         //}}AFX_MSG_MAP
285 END_MESSAGE_MAP()
286
287 /////////////////////////////////////////////////////////////////////////////
288 // briefing_editor_dlg message handlers
289
290 void briefing_editor_dlg::OnInitMenu(CMenu* pMenu)
291 {
292         int i;
293         CMenu *m;
294
295         // disable any items we should disable
296         m = pMenu->GetSubMenu(0);
297
298         // uncheck all menu items
299         for (i=0; i<Num_teams; i++)
300                 m->CheckMenuItem(i, MF_BYPOSITION | MF_UNCHECKED);
301
302         for (i=Num_teams; i<MAX_TEAMS; i++)
303                 m->EnableMenuItem(i, MF_BYPOSITION | MF_GRAYED);
304
305         // put a check next to the currently selected item
306         m->CheckMenuItem(m_current_briefing, MF_BYPOSITION | MF_CHECKED );
307
308         CDialog::OnInitMenu(pMenu);
309 }
310
311 void briefing_editor_dlg::create()
312 {
313         int i;
314         CComboBox *box;
315
316         CDialog::Create(IDD);
317         theApp.init_window(&Briefing_wnd_data, this);
318         box = (CComboBox *) GetDlgItem(IDC_ICON_IMAGE);
319         for (i=0; i<MAX_BRIEF_ICONS; i++)
320                 box->AddString(Icon_names[i]);
321
322         box = (CComboBox *) GetDlgItem(IDC_TEAM);
323         for (i=0; i<Num_team_names; i++)
324                 box->AddString(Team_names[i]);
325
326         box = (CComboBox *) GetDlgItem(IDC_SHIP_TYPE);
327         for (i=0; i<Num_ship_types; i++)
328                 box->AddString(Ship_info[i].name);
329
330         box = (CComboBox *) GetDlgItem(IDC_BRIEFING_MUSIC);
331         box->AddString("None");
332         for (i=0; i<Num_music_files; i++)
333                 box->AddString(Spooled_music[i].name);
334
335         m_play_bm.LoadBitmap(IDB_PLAY);
336         ((CButton *) GetDlgItem(IDC_PLAY)) -> SetBitmap(m_play_bm);
337
338         m_current_briefing = 0;
339         Briefing = &Briefings[m_current_briefing];
340         m_briefing_music = Mission_music[SCORE_BRIEFING] + 1;
341         UpdateData(FALSE);
342         update_data();
343         OnGotoView();
344         update_map_window();
345 }
346
347 void briefing_editor_dlg::focus_sexp(int select_sexp_node)
348 {
349         int i, n;
350
351         n = m_tree.select_sexp_node = select_sexp_node;
352         if (n != -1) {
353                 for (i=0; i<Briefing->num_stages; i++)
354                         if (query_node_in_sexp(n, Briefing->stages[i].formula))
355                                 break;
356
357                 if (i < Briefing->num_stages) {
358                         m_cur_stage = i;
359                         update_data();
360                         GetDlgItem(IDC_TREE) -> SetFocus();
361                         m_tree.hilite_item(m_tree.select_sexp_node);
362                 }
363         }
364 }
365
366 void briefing_editor_dlg::OnOK()
367 {
368 }
369
370 void briefing_editor_dlg::OnCancel()
371 {
372         OnClose();
373 }
374
375 void briefing_editor_dlg::OnClose() 
376 {
377         int bs, i, j, s, t, dup = 0;
378         briefing_editor_dlg *ptr;
379         brief_stage *sp;
380
381         m_cur_stage = -1;
382         update_data(1);
383
384         for ( bs = 0; bs < Num_teams; bs++ ) {
385                 for (s=0; s<Briefing[bs].num_stages; s++) {
386                         sp = &Briefing[bs].stages[s];
387                         t = sp->num_icons;
388                         for (i=0; i<t-1; i++)
389                                 for (j=i+1; j<t; j++) {
390                                         if ((sp->icons[i].id >= 0) && (sp->icons[i].id == sp->icons[j].id))
391                                                 dup = 1;
392                                 }
393                 }
394         }
395
396         if (dup)
397                 MessageBox("You have duplicate icons names.  You should resolve these.", "Warning");
398
399         theApp.record_window_data(&Briefing_wnd_data, this);
400         ptr = Briefing_dialog;
401         Briefing_dialog = NULL;
402         delete ptr;
403 }
404
405 void briefing_editor_dlg::reset_editor()
406 {
407         m_cur_stage = -1;
408         update_data(0);
409 }
410
411 // some kind of hackish code to get around the problem if saving (which implicitly loads,
412 // which implicitly clears all mission info) not affecting the editor's state at save.
413 void briefing_editor_dlg::save_editor_state()
414 {
415         stage_saved = m_cur_stage;
416         icon_saved = m_cur_icon;
417 }
418
419 void briefing_editor_dlg::restore_editor_state()
420 {
421         m_cur_stage = stage_saved;
422         m_cur_icon = icon_saved;
423 }
424
425 void briefing_editor_dlg::update_data(int update)
426 {
427         char buf[MAX_LABEL_LEN], buf2[MAX_ICON_TEXT_LEN], buf3[MAX_BRIEF_LEN];
428         int i, j, l, lines, count, enable = TRUE, valid = 0, invalid = 0;
429         object *objp;
430         brief_stage *ptr = NULL;
431
432         if (update)
433                 UpdateData(TRUE);
434
435         // save off current data before we update over it with new briefing stage/team stuff
436         Briefing = save_briefing;
437
438         Mission_music[SCORE_BRIEFING] = m_briefing_music - 1;
439         if (m_last_stage >= 0) {
440                 ptr = &Briefing->stages[m_last_stage];
441                 deconvert_multiline_string(buf3, m_text, MAX_BRIEF_LEN);
442                 if (stricmp(ptr->new_text, buf3))
443                         set_modified();
444
445                 strcpy(ptr->new_text, buf3);
446                 MODIFY(ptr->camera_time, atoi(m_time));
447                 string_copy(ptr->voice, m_voice, MAX_FILENAME_LEN, 1);
448                 i = ptr->flags;
449                 if (m_cut_prev)
450                         i |= BS_BACKWARD_CUT;
451                 else
452                         i &= ~BS_BACKWARD_CUT;
453
454                 if (m_cut_next)
455                         i |= BS_FORWARD_CUT;
456                 else
457                         i &= ~BS_FORWARD_CUT;
458
459                 MODIFY(ptr->flags, i);
460                 ptr->formula = m_tree.save_tree();
461                 switch (m_lines.GetCheck()) {
462                         case 1:
463                                 // add lines between every pair of 2 marked icons if there isn't one already.
464                                 for (i=0; i<ptr->num_icons - 1; i++)
465                                         for (j=i+1; j<ptr->num_icons; j++) {
466                                                 if ( icon_marked[i] && icon_marked[j] ) {
467                                                         for (l=0; l<ptr->num_lines; l++)
468                                                                 if ( ((ptr->lines[l].start_icon == i) && (ptr->lines[l].end_icon == j)) || ((ptr->lines[l].start_icon == j) && (ptr->lines[l].end_icon == i)) )
469                                                                         break;
470
471                                                         if ((l == ptr->num_lines) && (l < MAX_BRIEF_STAGE_LINES)) {
472                                                                 ptr->lines[l].start_icon = i;
473                                                                 ptr->lines[l].end_icon = j;
474                                                                 ptr->num_lines++;
475                                                         }
476                                                 }
477                                         }
478
479                                 break;
480
481                         case 0:
482                                 // remove all existing lines between any 2 marked icons
483                                 i = ptr->num_lines;
484                                 while (i--)
485                                         if ( icon_marked[ptr->lines[i].start_icon] && icon_marked[ptr->lines[i].end_icon] ) {
486                                                 ptr->num_lines--;
487                                                 for (l=i; l<ptr->num_lines; l++)
488                                                         ptr->lines[l] = ptr->lines[l + 1];
489                                         }
490
491                                 break;
492                 }
493
494                 if (m_last_icon >= 0) {
495                         valid = (m_id != ptr->icons[m_last_icon].id);
496                         if (m_id >= 0) {
497                                 if (valid && !m_change_local) {
498                                         for (i=m_last_stage+1; i<Briefing->num_stages; i++) {
499                                                 if (find_icon(m_id, i) >= 0) {
500                                                         char msg[1024];
501
502                                                         valid = 0;
503                                                         sprintf(msg, "Icon ID #%d is already used in a later stage.  You can only\n"
504                                                                 "change to that ID locally.  Icon ID has been reset back to %d", m_id, ptr->icons[m_last_icon].id);
505
506                                                         m_id = ptr->icons[m_last_icon].id;
507                                                         MessageBox(msg);
508                                                         break;
509                                                 }
510                                         }
511                                 }
512
513                                 for (i=0; i<ptr->num_icons; i++)
514                                         if ((i != m_last_icon) && (ptr->icons[i].id == m_id)) {
515                                                 char msg[1024];
516
517                                                 sprintf(msg, "Icon ID #%d is already used in this stage.  Icon ID has been reset back to %d",
518                                                         m_id, ptr->icons[m_last_icon].id);
519
520                                                 m_id = ptr->icons[m_last_icon].id;
521                                                 MessageBox(msg);
522                                                 break;
523                                         }
524
525                                 if (valid && !m_change_local) {
526                                         set_modified();
527                                         reset_icon_loop(m_last_stage);
528                                         while (get_next_icon(ptr->icons[m_last_icon].id))
529                                                 iconp->id = m_id;
530                                 }
531                         }
532
533                         ptr->icons[m_last_icon].id = m_id;
534                         string_copy(buf, m_icon_label, MAX_LABEL_LEN);
535                         if (stricmp(ptr->icons[m_last_icon].label, buf) && !m_change_local) {
536                                 set_modified();
537                                 reset_icon_loop(m_last_stage);
538                                 while (get_next_icon(m_id))
539                                         strcpy(iconp->label, buf);
540                         }
541
542                         strcpy(ptr->icons[m_last_icon].label, buf);
543                         if ( m_hilight )
544                                 ptr->icons[m_last_icon].flags |= BI_HIGHLIGHT;
545                         else
546                                 ptr->icons[m_last_icon].flags &= ~BI_HIGHLIGHT;
547
548                         if ((ptr->icons[m_last_icon].type != m_icon_image) && !m_change_local) {
549                                 set_modified();
550                                 reset_icon_loop(m_last_stage);
551                                 while (get_next_icon(m_id))
552                                         iconp->type = m_icon_image;
553                         }
554
555                         ptr->icons[m_last_icon].type = m_icon_image;
556                         if ((ptr->icons[m_last_icon].team != (1 << m_icon_team)) && !m_change_local) {
557                                 set_modified();
558                                 reset_icon_loop(m_last_stage);
559                                 while (get_next_icon(m_id))
560                                         iconp->team = (1 << m_icon_team);
561                         }
562
563                         ptr->icons[m_last_icon].team = (1 << m_icon_team);
564                         if ((ptr->icons[m_last_icon].ship_class != m_ship_type) && !m_change_local) {
565                                 set_modified();
566                                 reset_icon_loop(m_last_stage);
567                                 while (get_next_icon(m_id))
568                                         iconp->ship_class = m_ship_type;
569                         }
570
571                         MODIFY(ptr->icons[m_last_icon].ship_class, m_ship_type);
572                         deconvert_multiline_string(buf2, m_icon_text, MAX_ICON_TEXT_LEN);
573 /*
574                         if (stricmp(ptr->icons[m_last_icon].text, buf2) && !m_change_local) {
575                                 set_modified();
576                                 reset_icon_loop(m_last_stage);
577                                 while (get_next_icon(m_id))
578                                         strcpy(iconp->text, buf2);
579                         }
580
581                         strcpy(ptr->icons[m_last_icon].text, buf2);
582 */
583                 }
584         }
585
586         if (!::IsWindow(m_hWnd))
587                 return;
588
589         // set briefing pointer to correct team
590         Briefing = &Briefings[m_current_briefing];
591
592         if ((m_cur_stage >= 0) && (m_cur_stage < Briefing->num_stages)) {
593                 ptr = &Briefing->stages[m_cur_stage];
594                 m_stage_title.Format("Stage %d of %d", m_cur_stage + 1, Briefing->num_stages);
595                 m_text = convert_multiline_string(ptr->new_text);
596                 m_time.Format("%d", ptr->camera_time);
597                 m_voice = ptr->voice;
598                 m_cut_prev = (ptr->flags & BS_BACKWARD_CUT) ? 1 : 0;
599                 m_cut_next = (ptr->flags & BS_FORWARD_CUT) ? 1 : 0;
600                 m_tree.load_tree(ptr->formula);
601
602         } else {
603                 m_stage_title = _T("No stages");
604                 m_text = _T("");
605                 m_time = _T("");
606                 m_voice = _T("");
607                 m_cut_prev = m_cut_next = 0;
608                 m_tree.clear_tree();
609                 enable = FALSE;
610                 m_cur_stage = -1;
611         }
612
613         if (m_cur_stage == Briefing->num_stages - 1)
614                 GetDlgItem(IDC_NEXT) -> EnableWindow(FALSE);
615         else
616                 GetDlgItem(IDC_NEXT) -> EnableWindow(enable);
617
618         if (m_cur_stage)
619                 GetDlgItem(IDC_PREV) -> EnableWindow(enable);
620         else
621                 GetDlgItem(IDC_PREV) -> EnableWindow(FALSE);
622
623         if (Briefing->num_stages >= MAX_BRIEF_STAGES)
624                 GetDlgItem(IDC_ADD_STAGE) -> EnableWindow(FALSE);
625         else
626                 GetDlgItem(IDC_ADD_STAGE) -> EnableWindow(TRUE);
627
628         if (Briefing->num_stages) {
629                 GetDlgItem(IDC_DELETE_STAGE) -> EnableWindow(enable);
630                 GetDlgItem(IDC_INSERT_STAGE) -> EnableWindow(enable);
631         } else {
632                 GetDlgItem(IDC_DELETE_STAGE) -> EnableWindow(FALSE);
633                 GetDlgItem(IDC_INSERT_STAGE) -> EnableWindow(FALSE);
634         }
635
636         GetDlgItem(IDC_TIME) -> EnableWindow(enable);
637         GetDlgItem(IDC_VOICE) -> EnableWindow(enable);
638         GetDlgItem(IDC_BROWSE) -> EnableWindow(enable);
639         GetDlgItem(IDC_TEXT) -> EnableWindow(enable);
640         GetDlgItem(IDC_SAVE_VIEW) -> EnableWindow(enable);
641         GetDlgItem(IDC_GOTO_VIEW) -> EnableWindow(enable);
642         GetDlgItem(IDC_CUT_PREV) -> EnableWindow(enable);
643         GetDlgItem(IDC_CUT_NEXT) -> EnableWindow(enable);
644         GetDlgItem(IDC_TREE) -> EnableWindow(enable);
645         GetDlgItem(IDC_PLAY) -> EnableWindow(enable);
646
647         if ((m_cur_stage >= 0) && (m_cur_icon >= 0) && (m_cur_icon < ptr->num_icons)) {
648                 m_hilight = (ptr->icons[m_cur_icon].flags & BI_HIGHLIGHT)?1:0;
649                 m_icon_image = ptr->icons[m_cur_icon].type;
650                 m_icon_team = bitmask_2_bitnum(ptr->icons[m_cur_icon].team);
651                 m_icon_label = ptr->icons[m_cur_icon].label;
652                 m_ship_type = ptr->icons[m_cur_icon].ship_class;
653 //              m_icon_text = convert_multiline_string(ptr->icons[m_cur_icon].text);
654                 m_id = ptr->icons[m_cur_icon].id;
655                 enable = TRUE;
656
657         } else {
658                 m_hilight = FALSE;
659                 m_icon_image = -1;
660                 m_icon_team = -1;
661                 m_ship_type = -1;
662                 m_icon_label = _T("");
663                 m_cur_icon = -1;
664                 m_id = 0;
665                 enable = FALSE;
666         }
667
668         GetDlgItem(IDC_ICON_TEXT) -> EnableWindow(enable);
669         GetDlgItem(IDC_ICON_LABEL) -> EnableWindow(enable);
670         GetDlgItem(IDC_ICON_IMAGE) -> EnableWindow(enable);
671         GetDlgItem(IDC_SHIP_TYPE) -> EnableWindow(enable);
672         GetDlgItem(IDC_HILIGHT) -> EnableWindow(enable);
673         GetDlgItem(IDC_TEAM) -> EnableWindow(enable);
674         GetDlgItem(IDC_ID) -> EnableWindow(enable);
675         GetDlgItem(IDC_DELETE_ICON) -> EnableWindow(enable);
676
677         valid = invalid = 0;
678         objp = GET_FIRST(&obj_used_list);
679         while (objp != END_OF_LIST(&obj_used_list)) {
680                 if (objp->flags & OF_MARKED) {
681                         if ((objp->type == OBJ_SHIP) || (objp->type == OBJ_START) || (objp->type == OBJ_WAYPOINT) || (objp->type == OBJ_JUMP_NODE))
682                                 valid = 1;
683                         else
684                                 invalid = 1;
685                 }
686
687                 objp = GET_NEXT(objp);
688         }
689
690         if (m_cur_stage >= 0)
691                 ptr = &Briefing->stages[m_cur_stage];
692
693         if (valid && !invalid && (m_cur_stage >= 0) && (ptr->num_icons < MAX_STAGE_ICONS))
694                 GetDlgItem(IDC_MAKE_ICON) -> EnableWindow(TRUE);
695         else
696                 GetDlgItem(IDC_MAKE_ICON) -> EnableWindow(FALSE);
697
698         if (m_cur_stage >= 0)
699                 for (i=0; i<ptr->num_icons; i++)
700                         icon_marked[i] = 0;
701
702         valid = invalid = 0;
703         objp = GET_FIRST(&obj_used_list);
704         while (objp != END_OF_LIST(&obj_used_list)) {
705                 if (objp->flags & OF_MARKED) {
706                         if (objp->type == OBJ_POINT) {
707                                 valid++;
708                                 icon_marked[objp->instance] = 1;
709
710                         } else
711                                 invalid++;
712                 }
713
714                 objp = GET_NEXT(objp);
715         }
716
717         if (valid && !invalid && (m_cur_stage >= 0))
718                 GetDlgItem(IDC_PROPAGATE_ICONS) -> EnableWindow(TRUE);
719         else
720                 GetDlgItem(IDC_PROPAGATE_ICONS) -> EnableWindow(FALSE);
721
722         count = 0;
723         lines = 1;  // default lines checkbox to checked
724         
725         if (m_cur_stage >= 0) {
726                 for (i=0; i<ptr->num_lines; i++)
727                         line_marked[i] = 0;
728
729                 // go through and locate all lines between marked icons
730                 for (i=0; i<ptr->num_icons - 1; i++)
731                         for (j=i+1; j<ptr->num_icons; j++) {
732                                 if ( icon_marked[i] && icon_marked[j] ) {
733                                         for (l=0; l<ptr->num_lines; l++)
734                                                 if ( ((ptr->lines[l].start_icon == i) && (ptr->lines[l].end_icon == j)) || ((ptr->lines[l].start_icon == j) && (ptr->lines[l].end_icon == i)) ) {
735                                                         line_marked[l] = 1;
736                                                         count++;  // track number of marked lines (lines between 2 icons that are both marked)
737                                                         break;
738                                                 }
739
740                                         // at least 1 line missing between 2 marked icons, so use mixed state
741                                         if (l == ptr->num_lines)
742                                                 lines = 2;
743                                 }
744                         }
745         }
746
747         // not even 1 line between any 2 marked icons?  Set checkbox to unchecked.
748         if (!count)
749                 lines = 0;
750
751         i = 0;
752         if (m_cur_stage >= 0){
753                 i = calc_num_lines_for_icons(valid) + ptr->num_lines - count;
754         }
755
756         if ((valid > 1) && !invalid && (m_cur_stage >= 0) && (i <= MAX_BRIEF_STAGE_LINES))
757                 GetDlgItem(IDC_LINES) -> EnableWindow(TRUE);
758         else
759                 GetDlgItem(IDC_LINES) -> EnableWindow(FALSE);
760
761         m_lines.SetCheck(lines);
762
763         UpdateData(FALSE);
764         if ((m_last_stage != m_cur_stage) || (Briefing != save_briefing)) {
765                 if (m_last_stage >= 0) {
766                         for (i=0; i<save_briefing->stages[m_last_stage].num_icons; i++) {
767                                 // save positions of all icons, in case they have moved
768                                 save_briefing->stages[m_last_stage].icons[i].pos = Objects[icon_obj[i]].pos;
769                                 // release objects being used by last stage
770                                 obj_delete(icon_obj[i]);
771                         }
772                 }
773
774                 if (m_cur_stage >= 0) {
775                         for (i=0; i<ptr->num_icons; i++) {
776                                 // create an object for each icon for display/manipulation purposes
777                                 icon_obj[i] = obj_create(OBJ_POINT, -1, i, NULL, &ptr->icons[i].pos, 0.0f, OF_RENDERS);
778                         }
779
780                         obj_merge_created_list();
781                 }
782
783                 m_last_stage = m_cur_stage;
784         }
785
786         m_last_icon = m_cur_icon;
787         Update_window = 1;
788         save_briefing = Briefing;
789 }
790
791 // Given a number of icons, figure out how many lines would be required to connect each one
792 // with all of the others.
793 //
794 int briefing_editor_dlg::calc_num_lines_for_icons(int num)
795 {
796         int lines = 0;
797
798         if (num < 2)
799                 return 0;
800
801         // Basically, this is # lines = (# icons - 1) factorial
802         while (--num)
803                 lines += num;
804
805         return lines;
806 }
807
808 void briefing_editor_dlg::OnNext()
809 {
810         m_cur_stage++;
811         m_cur_icon = -1;
812         update_data();
813         OnGotoView();
814 }
815
816 void briefing_editor_dlg::OnPrev()
817 {
818         m_cur_stage--;
819         m_cur_icon = -1;
820         update_data();
821         OnGotoView();
822 }
823
824 void briefing_editor_dlg::OnBrowse() 
825 {
826         int z;
827         CString name;
828
829         UpdateData(TRUE);
830
831         if (The_mission.game_type & MISSION_TYPE_TRAINING)
832                 z = cfile_push_chdir(CF_TYPE_VOICE_TRAINING);
833         else
834                 z = cfile_push_chdir(CF_TYPE_VOICE_BRIEFINGS);
835
836         CFileDialog dlg(TRUE, "wav", NULL, OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR,
837                 "Wave Files (*.wav)|*.wav||");
838
839         if (dlg.DoModal() == IDOK) {
840                 m_voice = dlg.GetFileName();
841                 UpdateData(FALSE);
842         }
843
844         if (!z)
845                 cfile_pop_dir();
846 }
847
848 void briefing_editor_dlg::OnAddStage() 
849 {
850         int i;
851
852         if (Briefing->num_stages >= MAX_BRIEF_STAGES)
853                 return;
854
855         m_cur_stage = i = Briefing->num_stages++;
856         copy_stage(i - 1, i);
857         update_data(1);
858 }
859
860 void briefing_editor_dlg::OnDeleteStage() 
861 {
862         int i, z;
863
864         if (m_cur_stage < 0)
865                 return;
866         
867         SDL_assert(Briefing->num_stages);
868         z = m_cur_stage;
869         m_cur_stage = -1;
870         update_data(1);
871         for (i=z+1; i<Briefing->num_stages; i++)        {
872                 copy_stage(i, i-1);
873         }
874
875         Briefing->num_stages--;
876         m_cur_stage = z;
877         if (m_cur_stage >= Briefing->num_stages)
878                 m_cur_stage = Briefing->num_stages - 1;
879
880         update_data(0);
881 }
882
883 void briefing_editor_dlg::draw_icon(object *objp)
884 {
885         if (m_cur_stage < 0)
886                 return;
887
888         brief_render_icon(m_cur_stage, objp->instance, 1.0f/30.0f, objp->flags & OF_MARKED,
889                 (float) True_rw / BRIEF_GRID_W, (float) True_rh / BRIEF_GRID_H);
890 }
891
892 void briefing_editor_dlg::batch_render()
893 {
894         int i, num_lines;
895
896
897         if (m_cur_stage < 0)
898                 return;
899
900         num_lines = Briefing->stages[m_cur_stage].num_lines;
901         for (i=0; i<num_lines; i++)
902                 brief_render_icon_line(m_cur_stage, i);
903 }
904
905 void briefing_editor_dlg::icon_select(int num)
906 {
907         m_cur_icon = num;
908         update_data(1);
909 }
910
911 void briefing_editor_dlg::OnInsertStage() 
912 {
913         int i, z;
914
915         if (Briefing->num_stages >= MAX_BRIEF_STAGES)
916                 return;
917
918         if (!Briefing->num_stages) {
919                 OnAddStage();
920                 return;
921         }
922
923         z = m_cur_stage;
924         m_cur_stage = -1;
925         update_data(1);
926         for (i=Briefing->num_stages; i>z; i--)  {
927                 copy_stage(i-1, i);
928         }
929
930         Briefing->num_stages++;
931         copy_stage(z, z + 1);
932         m_cur_stage = z;
933         update_data(0);
934 }
935
936 void briefing_editor_dlg::copy_stage(int from, int to)
937 {
938         if ((from < 0) || (from >= Briefing->num_stages)) {
939                 strcpy(Briefing->stages[to].new_text, "<Text here>");
940                 strcpy(Briefing->stages[to].voice, "none.wav");
941                 Briefing->stages[to].camera_pos = view_pos;
942                 Briefing->stages[to].camera_orient = view_orient;
943                 Briefing->stages[to].camera_time = 500;
944                 Briefing->stages[to].num_icons = 0;
945                 Briefing->stages[to].formula = Locked_sexp_true;
946                 return;
947         }
948
949         // Copy all the data in the stage structure.
950         strcpy( Briefing->stages[to].new_text, Briefing->stages[from].new_text );
951         strcpy( Briefing->stages[to].voice, Briefing->stages[from].voice );
952         Briefing->stages[to].camera_pos = Briefing->stages[from].camera_pos;
953         Briefing->stages[to].camera_orient = Briefing->stages[from].camera_orient;
954         Briefing->stages[to].camera_time = Briefing->stages[from].camera_time;
955         Briefing->stages[to].flags = Briefing->stages[from].flags;
956         Briefing->stages[to].num_icons = Briefing->stages[from].num_icons;
957         Briefing->stages[to].num_lines = Briefing->stages[from].num_lines;
958         Briefing->stages[to].formula = Briefing->stages[from].formula;
959
960         memmove( Briefing->stages[to].icons, Briefing->stages[from].icons, sizeof(brief_icon)*MAX_STAGE_ICONS );
961         memmove( Briefing->stages[to].lines, Briefing->stages[from].lines, sizeof(brief_line)*MAX_BRIEF_STAGE_LINES );
962 }
963
964 void briefing_editor_dlg::update_positions()
965 {
966         int i, s, z;
967         vector v1, v2;
968
969         if (m_cur_stage < 0)
970                 return;
971
972         for (i=0; i<Briefing->stages[m_cur_stage].num_icons; i++) {
973                 v1 = Briefing->stages[m_cur_stage].icons[i].pos;
974                 v2 = Objects[icon_obj[i]].pos;
975                 if ((v1.x != v2.x) || (v1.y != v2.y) || (v1.z != v2.z)) {
976                         Briefing->stages[m_cur_stage].icons[i].pos = Objects[icon_obj[i]].pos;
977                         if (!m_change_local)  // propagate changes through rest of stages..
978                                 for (s=m_cur_stage+1; s<Briefing->num_stages; s++) {
979                                         z = find_icon(Briefing->stages[m_cur_stage].icons[i].id, s);
980                                         if (z >= 0)
981                                                 Briefing->stages[s].icons[z].pos = Objects[icon_obj[i]].pos;
982                                 }
983                 }
984         }
985 }
986
987 void briefing_editor_dlg::OnMakeIcon() 
988 {
989         char *name;
990         int z, len, team, ship, waypoint, jump_node, count = -1;
991         int cargo = 0, cargo_count = 0, freighter_count = 0;
992         object *ptr;
993         vector min, max, pos;
994         brief_icon *iconp;
995
996         if (Briefing->stages[m_cur_stage].num_icons >= MAX_STAGE_ICONS)
997                 return;
998
999         m_cur_icon = Briefing->stages[m_cur_stage].num_icons++;
1000         iconp = &Briefing->stages[m_cur_stage].icons[m_cur_icon];
1001         ship = waypoint = jump_node = -1;
1002         team = TEAM_FRIENDLY;
1003
1004         vm_vec_make(&min, 9e19f, 9e19f, 9e19f);
1005         vm_vec_make(&max, -9e19f, -9e19f, -9e19f);
1006         ptr = GET_FIRST(&obj_used_list);
1007         while (ptr != END_OF_LIST(&obj_used_list)) {
1008                 if (ptr->flags & OF_MARKED) {
1009                         if (ptr->pos.x < min.x)
1010                                 min.x = ptr->pos.x;
1011                         if (ptr->pos.x > max.x)
1012                                 max.x = ptr->pos.x;
1013                         if (ptr->pos.y < min.y)
1014                                 min.y = ptr->pos.y;
1015                         if (ptr->pos.y > max.y)
1016                                 max.y = ptr->pos.y;
1017                         if (ptr->pos.z < min.z)
1018                                 min.z = ptr->pos.z;
1019                         if (ptr->pos.z > max.z)
1020                                 max.z = ptr->pos.z;
1021                         
1022                         switch (ptr->type) {
1023                                 case OBJ_SHIP:
1024                                 case OBJ_START:
1025                                         ship = ptr->instance;
1026                                         break;
1027
1028                                 case OBJ_WAYPOINT:
1029                                         waypoint = ptr->instance;
1030                                         break;
1031                                 
1032                                 case OBJ_JUMP_NODE:
1033                                         jump_node = ptr->instance;
1034                                         break;
1035
1036                                 default:
1037                                         Int3();
1038                         }
1039
1040                         if (ship >= 0) {
1041                                 team = Ships[ship].team;
1042
1043                                 z = ship_query_general_type(ship);
1044                                 if (z == SHIP_TYPE_CARGO)
1045                                         cargo_count++;
1046
1047                                 if (z == SHIP_TYPE_FREIGHTER)
1048                                 {
1049                                         z = Ai_info[Ships[ship].ai_index].dock_objnum;
1050                                         if (z) {  // docked with anything?
1051                                                 if ((Objects[z].flags & OF_MARKED) && (Objects[z].type == OBJ_SHIP)) {
1052                                                         if (ship_query_general_type(Objects[z].instance) == SHIP_TYPE_CARGO)
1053                                                                 freighter_count++;
1054                                                 }
1055                                         }
1056                                 }
1057                         }
1058
1059                         count++;
1060                 }
1061
1062                 ptr = GET_NEXT(ptr);
1063         }
1064
1065         if (cargo_count && cargo_count == freighter_count)
1066                 cargo = 1;
1067
1068         vm_vec_avg(&pos, &min, &max);
1069         if (ship >= 0)
1070                 name = Ships[ship].ship_name;
1071         else if (waypoint >= 0)
1072                 name = Waypoint_lists[waypoint / 65536].name;
1073         else if (jump_node >= 0)
1074                 name = Jump_nodes[jump_node].name;
1075         else
1076                 return;
1077
1078         len = strlen(name);
1079         if (len >= MAX_LABEL_LEN - 1)
1080                 len = MAX_LABEL_LEN - 1;
1081
1082         strncpy(iconp->label, name, len);
1083         iconp->label[len] = 0;
1084 //      iconp->text[0] = 0;
1085         iconp->type = 0;
1086         iconp->team = team;
1087         iconp->pos = pos;
1088         iconp->flags = 0;
1089         iconp->id = Cur_brief_id++;
1090         if (ship >= 0) {
1091                 iconp->ship_class = Ships[ship].ship_info_index;
1092                 switch (Ship_info[Ships[ship].ship_info_index].flags & SIF_ALL_SHIP_TYPES) {
1093                         case SIF_KNOSSOS_DEVICE:
1094                                 iconp->type = ICON_KNOSSOS_DEVICE;
1095                                 break;
1096
1097                         case SIF_CORVETTE:
1098                                 iconp->type = ICON_CORVETTE;
1099                                 break;
1100
1101                         case SIF_GAS_MINER:
1102                                 iconp->type = ICON_GAS_MINER;
1103                                 break;
1104
1105                         case SIF_SUPERCAP:
1106                                 iconp->type = ICON_SUPERCAP;
1107                                 break;
1108
1109                         case SIF_SENTRYGUN:
1110                                 iconp->type = ICON_SENTRYGUN;
1111                                 break;
1112
1113                         case SIF_AWACS:
1114                                 iconp->type = ICON_AWACS;
1115                                 break;
1116
1117                         case SIF_CARGO:
1118                                 if (cargo)
1119                                         iconp->type = (count == 1) ? ICON_FREIGHTER_WITH_CARGO : ICON_FREIGHTER_WING_WITH_CARGO;
1120                                 else
1121                                         iconp->type = count ? ICON_CARGO_WING : ICON_CARGO;
1122
1123                                 break;
1124
1125                         case SIF_SUPPORT:
1126                                 iconp->type = ICON_SUPPORT_SHIP;
1127                                 break;
1128
1129                         case SIF_FIGHTER:
1130                                 iconp->type = count ? ICON_FIGHTER_WING : ICON_FIGHTER;
1131                                 break;
1132
1133                         case SIF_BOMBER:
1134                                 iconp->type = count ? ICON_BOMBER_WING : ICON_BOMBER;
1135                                 break;
1136
1137                         case SIF_FREIGHTER:
1138                                 if (cargo)
1139                                         iconp->type = (count == 1) ? ICON_FREIGHTER_WITH_CARGO : ICON_FREIGHTER_WING_WITH_CARGO;
1140                                 else
1141                                         iconp->type = count ? ICON_FREIGHTER_WING_NO_CARGO : ICON_FREIGHTER_NO_CARGO;
1142
1143                                 break;
1144
1145                         case SIF_CRUISER:
1146                                 iconp->type = count ? ICON_CRUISER_WING : ICON_CRUISER;
1147                                 break;
1148
1149                         case SIF_TRANSPORT:
1150                                 iconp->type = count ? ICON_TRANSPORT_WING : ICON_TRANSPORT;
1151                                 break;
1152
1153                         case SIF_CAPITAL:                       
1154                         case SIF_DRYDOCK:
1155                                 iconp->type = ICON_CAPITAL;
1156                                 break;                  
1157
1158                         default:
1159                                 if (Ships[ship].ship_info_index == ship_info_lookup(NAVBUOY_NAME))
1160                                         iconp->type = ICON_WAYPOINT;
1161                                 else
1162                                         iconp->type = ICON_ASTEROID_FIELD;
1163
1164                                 break;
1165                 }
1166         }
1167         // jumpnodes
1168         else if(jump_node >= 0){
1169                 iconp->ship_class = ship_info_lookup(NAVBUOY_NAME);
1170                 iconp->type = ICON_JUMP_NODE;
1171         } 
1172         // everything else
1173         else {
1174                 iconp->ship_class = ship_info_lookup(NAVBUOY_NAME);
1175                 iconp->type = ICON_WAYPOINT;
1176         }
1177
1178         if (!m_change_local){
1179                 propagate_icon(m_cur_icon);
1180         }
1181
1182         icon_obj[m_cur_icon] = obj_create(OBJ_POINT, -1, m_cur_icon, NULL, &pos, 0.0f, OF_RENDERS);
1183         SDL_assert(icon_obj[m_cur_icon] >= 0);
1184         obj_merge_created_list();
1185         unmark_all();
1186         set_cur_object_index(icon_obj[m_cur_icon]);
1187         GetDlgItem(IDC_MAKE_ICON) -> EnableWindow(FALSE);
1188         GetDlgItem(IDC_PROPAGATE_ICONS) -> EnableWindow(TRUE);
1189         update_data(1);
1190 }
1191
1192 void briefing_editor_dlg::OnDeleteIcon()
1193 {
1194         delete_icon(m_cur_icon);
1195 }
1196
1197 void briefing_editor_dlg::delete_icon(int num)
1198 {
1199         int i, z;
1200
1201         if (num < 0)
1202                 num = m_cur_icon;
1203
1204         if (num < 0)
1205                 return;
1206
1207         SDL_assert(m_cur_stage >= 0);
1208         SDL_assert(Briefing->stages[m_cur_stage].num_icons);
1209         z = m_cur_icon;
1210         if (z == num)
1211                 z = -1;
1212         if (z > num)
1213                 z--;
1214
1215         m_cur_icon = -1;
1216         update_data(1);
1217         obj_delete(icon_obj[num]);
1218         for (i=num+1; i<Briefing->stages[m_cur_stage].num_icons; i++) {
1219                 Briefing->stages[m_cur_stage].icons[i-1] = Briefing->stages[m_cur_stage].icons[i];
1220                 icon_obj[i-1] = icon_obj[i];
1221                 Objects[icon_obj[i-1]].instance = i - 1;
1222         }
1223
1224         Briefing->stages[m_cur_stage].num_icons--;
1225         if (z >= 0) {
1226                 m_cur_icon = z;
1227                 update_data(0);
1228         }
1229 }
1230
1231 void briefing_editor_dlg::OnGotoView()
1232 {
1233         if (m_cur_stage < 0)
1234                 return;
1235
1236         view_pos = Briefing->stages[m_cur_stage].camera_pos;
1237         view_orient = Briefing->stages[m_cur_stage].camera_orient;
1238         Update_window = 1;
1239 }
1240
1241 void briefing_editor_dlg::OnSaveView()
1242 {
1243         if (m_cur_stage < 0)
1244                 return;
1245
1246         Briefing->stages[m_cur_stage].camera_pos = view_pos;
1247         Briefing->stages[m_cur_stage].camera_orient = view_orient;
1248 }
1249
1250 void briefing_editor_dlg::OnSelchangeIconImage()
1251 {
1252         update_data(1);
1253 }
1254
1255 void briefing_editor_dlg::OnSelchangeTeam()
1256 {
1257         update_data(1);
1258 }
1259
1260 int briefing_editor_dlg::check_mouse_hit(int x, int y)
1261 {
1262         int i;
1263         brief_icon *ptr;
1264
1265         if (m_cur_stage < 0)
1266                 return -1;
1267
1268         for (i=0; i<Briefing->stages[m_cur_stage].num_icons; i++) {
1269                 ptr = &Briefing->stages[m_cur_stage].icons[i];
1270                 if ((x > ptr->x) && (x < ptr->x + ptr->w) && (y > ptr->y) && (y < ptr->y + ptr->h))     {
1271                         return icon_obj[i];
1272                 }
1273         }
1274
1275         return -1;
1276 }
1277
1278 void briefing_editor_dlg::OnPropagateIcons() 
1279 {
1280         object *ptr;
1281
1282         ptr = GET_FIRST(&obj_used_list);
1283         while (ptr != END_OF_LIST(&obj_used_list)) {
1284                 if ((ptr->type == OBJ_POINT) && (ptr->flags & OF_MARKED)) {
1285                         propagate_icon(ptr->instance);
1286                 }
1287
1288                 ptr = GET_NEXT(ptr);
1289         }
1290 }
1291
1292 void briefing_editor_dlg::propagate_icon(int num)
1293 {
1294         int i, s;
1295
1296         for (s=m_cur_stage+1; s<Briefing->num_stages; s++) {
1297                 i = Briefing->stages[s].num_icons;
1298                 if (i >= MAX_STAGE_ICONS)
1299                         continue;
1300
1301                 if (find_icon(Briefing->stages[m_cur_stage].icons[num].id, s) >= 0)
1302                         continue;  // don't change if icon exists here already.
1303
1304                 Briefing->stages[s].icons[i] = Briefing->stages[m_cur_stage].icons[num];
1305                 Briefing->stages[s].num_icons++;
1306         }
1307 }
1308
1309 int briefing_editor_dlg::find_icon(int id, int stage)
1310 {
1311         int i;
1312
1313         if (id >= 0)
1314                 for (i=0; i<Briefing->stages[stage].num_icons; i++)
1315                         if (Briefing->stages[stage].icons[i].id == id)
1316                                 return i;
1317
1318         return -1;
1319 }
1320
1321 void briefing_editor_dlg::reset_icon_loop(int stage)
1322 {
1323         stage_loop = stage + 1;
1324         icon_loop = -1;
1325 }
1326
1327 int briefing_editor_dlg::get_next_icon(int id)
1328 {
1329         while (1) {
1330                 icon_loop++;
1331                 if (icon_loop >= Briefing->stages[stage_loop].num_icons) {
1332                         stage_loop++;
1333                         if (stage_loop > Briefing->num_stages)
1334                                 return 0;
1335
1336                         icon_loop = -1;
1337                         continue;
1338                 }
1339
1340                 iconp = &Briefing->stages[stage_loop].icons[icon_loop];
1341                 if ((id >= 0) && (iconp->id == id))
1342                         return 1;
1343         }
1344 }
1345
1346 BOOL briefing_editor_dlg::OnCommand(WPARAM wParam, LPARAM lParam) 
1347 {
1348         int id;
1349
1350         // deal with figuring out menu stuff
1351         id = LOWORD(wParam);
1352         if ( (id >= ID_TEAM_1) && (id < ID_TEAM_3) ) {
1353                 m_current_briefing = id - ID_TEAM_1;
1354
1355                 // put user back at first stage for this team (or no current stage is there are none).
1356                 Briefing = &Briefings[m_current_briefing];
1357                 if ( Briefing->num_stages > 0 )
1358                         m_cur_stage = 0;
1359                 else
1360                         m_cur_stage = -1;
1361
1362                 update_data(1);
1363                 OnGotoView();
1364                 return 1;
1365         }
1366
1367         return CDialog::OnCommand(wParam, lParam);
1368 }
1369
1370 void briefing_editor_dlg::OnLines() 
1371 {
1372         if (m_lines.GetCheck() == 1)
1373                 m_lines.SetCheck(0);
1374         else
1375                 m_lines.SetCheck(1);
1376
1377         update_data(1);
1378 }
1379
1380 void briefing_editor_dlg::OnRclickTree(NMHDR* pNMHDR, LRESULT* pResult) 
1381 {
1382         m_tree.right_clicked(); 
1383         *pResult = 0;
1384 }
1385
1386 void briefing_editor_dlg::OnBeginlabeleditTree(NMHDR* pNMHDR, LRESULT* pResult) 
1387 {
1388         TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
1389
1390         if (m_tree.edit_label(pTVDispInfo->item.hItem) == 1)    {
1391                 *pResult = 0;
1392                 modified = 1;
1393
1394         } else
1395                 *pResult = 1;
1396 }
1397
1398 void briefing_editor_dlg::OnEndlabeleditTree(NMHDR* pNMHDR, LRESULT* pResult) 
1399 {
1400         TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
1401
1402         *pResult = m_tree.end_label_edit(pTVDispInfo->item.hItem, pTVDispInfo->item.pszText);
1403 }
1404
1405 BOOL briefing_editor_dlg::DestroyWindow() 
1406 {
1407         m_play_bm.DeleteObject();
1408         return CDialog::DestroyWindow();
1409 }
1410
1411 void briefing_editor_dlg::OnPlay() 
1412 {
1413         char path[MAX_PATH_LEN + 1];
1414         GetDlgItem(IDC_VOICE)->GetWindowText(m_voice);
1415
1416         int size, offset;
1417         cf_find_file_location((char *) (LPCSTR) m_voice, CF_TYPE_ANY, path, &size, &offset );
1418
1419         PlaySound(path, NULL, SND_ASYNC | SND_FILENAME);
1420 }
1421
1422 void briefing_editor_dlg::OnCopyView() 
1423 {
1424         // TODO: Add your control notification handler code here
1425
1426         m_copy_view_set = 1;
1427         m_copy_view_pos = view_pos;
1428         m_copy_view_orient = view_orient;
1429 }
1430
1431 void briefing_editor_dlg::OnPasteView() 
1432 {
1433         // TODO: Add your control notification handler code here
1434         if (m_cur_stage < 0)
1435                 return;
1436
1437         if (m_copy_view_set == 0) {
1438                 MessageBox("No view set", "Unable to copy view");
1439         } else {
1440                 Briefing->stages[m_cur_stage].camera_pos = m_copy_view_pos;
1441                 Briefing->stages[m_cur_stage].camera_orient = m_copy_view_orient;
1442                 
1443                 update_data(1);
1444                 OnGotoView();
1445         }
1446 }
1447