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