]> icculus.org git repositories - taylor/freespace2.git/blob - src/fred2/missiongoalsdlg.cpp
fix issue with looping audio streams
[taylor/freespace2.git] / src / fred2 / missiongoalsdlg.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/MissionGoalsDlg.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Mission goals editor dialog box handling code
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:44  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  * 4     2/17/99 2:11p Dave
29  * First full run of squad war. All freespace and tracker side stuff
30  * works.
31  * 
32  * 3     1/19/99 3:57p Andsager
33  * Round 2 of variables
34  * 
35  * 2     10/07/98 6:28p Dave
36  * Initial checkin. Renamed all relevant stuff to be Fred2 instead of
37  * Fred. Globalized mission and campaign file extensions. Removed Silent
38  * Threat specific code.
39  * 
40  * 1     10/07/98 3:01p Dave
41  * 
42  * 1     10/07/98 3:00p Dave
43  * 
44  * 47    5/23/98 12:20p Sandeep
45  * 
46  * 46    5/22/98 1:06a Hoffoss
47  * Made Fred not use OLE.
48  * 
49  * 45    5/20/98 1:04p Hoffoss
50  * Made credits screen use new artwork and removed rating field usage from
51  * Fred (a goal struct member).
52  * 
53  * 44    3/31/98 12:23a Allender
54  * changed macro names of campaign types to be more descriptive.  Added
55  * "team" to objectives dialog for team v. team missions.  Added two
56  * distinct multiplayer campaign types
57  * 
58  * 43    12/08/97 2:03p Hoffoss
59  * Added Fred support for MGF_NO_MUSIC flag in objectives.
60  * 
61  * 42    11/11/97 4:13p Duncan
62  * changed assert to abort operation instead.
63  * 
64  * 41    10/10/97 6:21p Hoffoss
65  * Put in Fred support for training object list editing.
66  * 
67  * 40    10/10/97 2:53p Johnson
68  * Fixed bug with new items being selected before they are fully
69  * registered as added.
70  * 
71  * 39    10/09/97 1:03p Hoffoss
72  * Renaming events or goals now updates sexp references as well.
73  * 
74  * 38    9/30/97 12:30p Hoffoss
75  * Drag and drop reordering of sexp tree roots now does an insert after
76  * rather than a swap operation.
77  * 
78  * 37    9/09/97 3:39p Sandeep
79  * warning level 4 bugs
80  * 
81  * 36    8/12/97 3:33p Hoffoss
82  * Fixed the "press cancel to go to reference" code to work properly.
83  * 
84  * 35    8/12/97 2:39p Johnson
85  * fixed bug with sexp tree goal name problem.
86  * 
87  * 34    8/01/97 3:10p Hoffoss
88  * Made Sexp help hidable.
89  * 
90  * 33    7/30/97 5:23p Hoffoss
91  * Removed Sexp tree verification code, since it duplicates normal sexp
92  * verification, and is just another set of code to keep maintained.
93  * 
94  * 32    7/25/97 3:05p Allender
95  * added score field to goals and events editor
96  * 
97  * 31    7/25/97 2:40p Hoffoss
98  * Fixed bug in sexp tree selection updating handling.
99  * 
100  * 30    7/24/97 12:45p Hoffoss
101  * Added sexp help system to sexp trees and some dialog boxes.
102  * 
103  * 29    7/17/97 4:10p Hoffoss
104  * Added drag and drop to sexp trees for reordering root items.
105  * 
106  * 28    7/16/97 6:30p Hoffoss
107  * Added icons to sexp trees, mainly because I think they will be required
108  * for drag n drop.
109  * 
110  * 27    7/07/97 12:04p Allender
111  * mission goal validation.
112  * 
113  * 26    6/02/97 8:47p Hoffoss
114  * Fixed bug with inserting an operator at root position, but under a
115  * label.
116  * 
117  * 25    5/20/97 2:28p Hoffoss
118  * Added message box queries for close window operation on all modal
119  * dialog boxes.
120  * 
121  * 24    5/01/97 4:12p Hoffoss
122  * Added return handling to dialogs.
123  * 
124  * 23    4/25/97 12:50p Allender
125  * change globals to new naming conventions
126  * 
127  * 22    4/23/97 11:55a Hoffoss
128  * Fixed many bugs uncovered while trying to create Mission 6.
129  * 
130  * 21    4/17/97 2:01p Hoffoss
131  * All dialog box window states are saved between sessions now.
132  * 
133  * 20    4/11/97 4:22p Hoffoss
134  * Fixed bug in Sexp trees, moved Show starfield option to view menu and
135  * removed preferences dialog box.
136  * 
137  * 19    4/11/97 10:11a Hoffoss
138  * Name fields supported by Fred for Events and Mission Goals.
139  * 
140  * 18    4/10/97 3:20p Mike
141  * Change hull damage to be like shields.
142  * 
143  * 17    4/01/97 5:15p Hoffoss
144  * Fixed errors in max length checks, renaming a wing now renames the
145  * ships in the wing as well, as it should.
146  * 
147  * 16    2/21/97 5:34p Hoffoss
148  * Added extensive modification detection and fixed a bug in initial
149  * orders editor.
150  * 
151  * 15    2/17/97 5:28p Hoffoss
152  * Checked RCS headers, added them were missing, changing description to
153  * something better, etc where needed.
154  *
155  * $NoKeywords: $
156  */
157
158 #include "stdafx.h"
159 #include "fred.h"
160 #include "freddoc.h"
161 #include "fredview.h"
162 #include "linklist.h"
163 #include "sexp.h"
164 #include "missiongoalsdlg.h"
165 #include "management.h"
166 #include "operatorargtypeselect.h"
167
168 #define ID_ADD_SHIPS                    9000
169 #define ID_REPLACE_SHIPS        11000
170 #define ID_ADD_WINGS                    13000
171 #define ID_REPLACE_WINGS        15000
172
173 #ifdef _DEBUG
174 #define new DEBUG_NEW
175 #undef THIS_FILE
176 static char THIS_FILE[] = __FILE__;
177 #endif
178
179 CMissionGoalsDlg *Goal_editor_dlg; // global reference needed by sexp_tree class
180
181 /////////////////////////////////////////////////////////////////////////////
182 // sexp_goal_tree class member functions
183
184 // determine the node number that would be allocated without actually allocating it yet.
185 int sexp_goal_tree::get_new_node_position()
186 {
187         int i;
188
189         for (i=0; i<MAX_SEXP_TREE_SIZE; i++)
190                 if (nodes[i].type == SEXPT_UNUSED)
191                         return i;
192
193         return -1;
194 }
195
196 // construct tree nodes for an sexp, adding them to the list and returning first node
197 int sexp_goal_tree::load_sub_tree(int index)
198 {
199         int cur;
200
201         if (index < 0) {
202                 cur = allocate_node(-1);
203                 set_node(cur, (SEXPT_OPERATOR | SEXPT_VALID), "true");  // setup a default tree if none
204                 return cur;
205         }
206
207         // assumption: first token is an operator.  I require this because it would cause problems
208         // with child/parent relations otherwise, and it should be this way anyway, since the
209         // return type of the whole sexp is boolean, and only operators can satisfy this.
210         SDL_assert(Sexp_nodes[index].subtype == SEXP_ATOM_OPERATOR);
211         cur = get_new_node_position();
212         load_branch(index, -1);
213         return cur;
214 }
215
216 /////////////////////////////////////////////////////////////////////////////
217 // CMissionGoalsDlg dialog class member functions
218
219 CMissionGoalsDlg::CMissionGoalsDlg(CWnd* pParent /*=NULL*/)
220         : CDialog(CMissionGoalsDlg::IDD, pParent)
221 {
222         //{{AFX_DATA_INIT(CMissionGoalsDlg)
223         m_goal_desc = _T("");
224         m_goal_type = -1;
225         m_display_goal_types = 0;
226         m_name = _T("");
227         m_goal_invalid = FALSE;
228         m_goal_score = 0;
229         m_no_music = FALSE;
230         m_team = -1;
231         //}}AFX_DATA_INIT
232         m_goals_tree.m_mode = MODE_GOALS;
233         m_num_goals = 0;
234         m_goals_tree.link_modified(&modified);
235         modified = 0;
236         select_sexp_node = -1;
237 }
238
239 BOOL CMissionGoalsDlg::OnInitDialog()
240 {
241         int i, adjust = 0;
242
243         CDialog::OnInitDialog();  // let the base class do the default work
244         if (!Show_sexp_help)
245                 adjust = -SEXP_HELP_BOX_SIZE;
246
247         theApp.init_window(&Mission_goals_wnd_data, this, adjust);
248         m_goals_tree.setup((CEdit *) GetDlgItem(IDC_HELP_BOX));
249         load_tree();
250         create_tree();
251         if (m_num_goals >= MAX_GOALS)
252                 GetDlgItem(IDC_BUTTON_NEW_GOAL)->EnableWindow(FALSE);
253
254         Goal_editor_dlg = this;
255         i = m_goals_tree.select_sexp_node;
256         if (i != -1) {
257                 GetDlgItem(IDC_GOALS_TREE) -> SetFocus();
258                 m_goals_tree.hilite_item(i);
259                 return FALSE;
260         }
261
262         return TRUE;
263 }
264
265 void CMissionGoalsDlg::DoDataExchange(CDataExchange* pDX)
266 {
267         CDialog::DoDataExchange(pDX);
268         //{{AFX_DATA_MAP(CMissionGoalsDlg)
269         DDX_Control(pDX, IDC_GOALS_TREE, m_goals_tree);
270         DDX_Text(pDX, IDC_GOAL_DESC, m_goal_desc);
271         DDX_CBIndex(pDX, IDC_GOAL_TYPE_DROP, m_goal_type);
272         DDX_CBIndex(pDX, IDC_DISPLAY_GOAL_TYPES_DROP, m_display_goal_types);
273         DDX_Text(pDX, IDC_GOAL_NAME, m_name);
274         DDX_Check(pDX, IDC_GOAL_INVALID, m_goal_invalid);
275         DDX_Text(pDX, IDC_GOAL_SCORE, m_goal_score);
276         DDX_Check(pDX, IDC_NO_MUSIC, m_no_music);
277         DDX_CBIndex(pDX, IDC_OBJ_TEAM, m_team);
278         //}}AFX_DATA_MAP
279         DDV_MaxChars(pDX, m_goal_desc, MAX_GOAL_TEXT - 1);
280         DDV_MaxChars(pDX, m_name, NAME_LENGTH - 1);
281 }
282
283 BEGIN_MESSAGE_MAP(CMissionGoalsDlg, CDialog)
284         //{{AFX_MSG_MAP(CMissionGoalsDlg)
285         ON_CBN_SELCHANGE(IDC_DISPLAY_GOAL_TYPES_DROP, OnSelchangeDisplayGoalTypesDrop)
286         ON_NOTIFY(TVN_SELCHANGED, IDC_GOALS_TREE, OnSelchangedGoalsTree)
287         ON_NOTIFY(NM_RCLICK, IDC_GOALS_TREE, OnRclickGoalsTree)
288         ON_NOTIFY(TVN_ENDLABELEDIT, IDC_GOALS_TREE, OnEndlabeleditGoalsTree)
289         ON_NOTIFY(TVN_BEGINLABELEDIT, IDC_GOALS_TREE, OnBeginlabeleditGoalsTree)
290         ON_BN_CLICKED(IDC_BUTTON_NEW_GOAL, OnButtonNewGoal)
291         ON_EN_CHANGE(IDC_GOAL_DESC, OnChangeGoalDesc)
292         ON_EN_CHANGE(IDC_GOAL_RATING, OnChangeGoalRating)
293         ON_CBN_SELCHANGE(IDC_GOAL_TYPE_DROP, OnSelchangeGoalTypeDrop)
294         ON_EN_CHANGE(IDC_GOAL_NAME, OnChangeGoalName)
295         ON_BN_CLICKED(ID_OK, OnOk)
296         ON_WM_CLOSE()
297         ON_BN_CLICKED(IDC_GOAL_INVALID, OnGoalInvalid)
298         ON_EN_CHANGE(IDC_GOAL_SCORE, OnChangeGoalScore)
299         ON_BN_CLICKED(IDC_NO_MUSIC, OnNoMusic)
300         ON_CBN_SELCHANGE(IDC_OBJ_TEAM, OnSelchangeTeam)
301         //}}AFX_MSG_MAP
302 END_MESSAGE_MAP()
303
304 /////////////////////////////////////////////////////////////////////////////
305 // CMissionGoalsDlg message handlers
306
307 // Initialization: sets up internal working copy of mission goals and goal trees.
308 void CMissionGoalsDlg::load_tree()
309 {
310         int i;
311
312         m_goals_tree.select_sexp_node = select_sexp_node;
313         select_sexp_node = -1;
314
315         m_goals_tree.clear_tree();
316         m_num_goals = Num_goals;
317         for (i=0; i<Num_goals; i++) {
318                 m_goals[i] = Mission_goals[i];
319                 m_sig[i] = i;
320                 if (!(*m_goals[i].name))
321                         strcpy(m_goals[i].name, "<unnamed>");
322
323                 m_goals[i].formula = m_goals_tree.load_sub_tree(Mission_goals[i].formula);
324         }
325
326         m_goals_tree.post_load();
327         cur_goal = -1;
328         update_cur_goal();
329 }
330
331 // create the CTreeCtrl tree from the goal tree, filtering based on m_display_goal_types
332 void CMissionGoalsDlg::create_tree()
333 {
334         int i;
335         HTREEITEM h;
336
337         m_goals_tree.DeleteAllItems();
338         m_goals_tree.reset_handles();
339         for (i=0; i<m_num_goals; i++) {
340                 if ( (m_goals[i].type & GOAL_TYPE_MASK) != m_display_goal_types)
341                         continue;
342
343                 h = m_goals_tree.insert(m_goals[i].name);
344                 m_goals_tree.SetItemData(h, m_goals[i].formula);
345                 m_goals_tree.add_sub_tree(m_goals[i].formula, h);
346         }
347
348         cur_goal = -1;
349         update_cur_goal();
350 }
351
352 // Display goal types selection changed, so update the display
353 void CMissionGoalsDlg::OnSelchangeDisplayGoalTypesDrop() 
354 {
355         UpdateData(TRUE);
356         create_tree();
357 }
358
359 // New tree item selected.  Because goal info is displayed for the selected tree item,
360 // we need to update the display when this occurs.
361 void CMissionGoalsDlg::OnSelchangedGoalsTree(NMHDR* pNMHDR, LRESULT* pResult) 
362 {
363         int i, z;
364         NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
365         HTREEITEM h, h2;
366
367         h = pNMTreeView->itemNew.hItem;
368         if (!h)
369                 return;
370
371         m_goals_tree.update_help(h);
372         while ((h2 = m_goals_tree.GetParentItem(h)) != 0)
373                 h = h2;
374
375         z = m_goals_tree.GetItemData(h);
376         for (i=0; i<m_num_goals; i++)
377                 if (m_goals[i].formula == z)
378                         break;
379
380         SDL_assert(i < m_num_goals);
381         cur_goal = i;
382         update_cur_goal();
383         *pResult = 0;
384 }
385
386 // update display info to reflect the currently selected goal.
387 void CMissionGoalsDlg::update_cur_goal()
388 {
389         if (cur_goal < 0) {
390                 m_name = _T("");
391                 m_goal_desc = _T("");
392                 m_goal_type = -1;
393                 m_team = 0;
394                 UpdateData(FALSE);
395                 GetDlgItem(IDC_GOAL_TYPE_DROP) -> EnableWindow(FALSE);
396                 GetDlgItem(IDC_GOAL_NAME) -> EnableWindow(FALSE);
397                 GetDlgItem(IDC_GOAL_DESC) -> EnableWindow(FALSE);
398                 GetDlgItem(IDC_GOAL_INVALID)->EnableWindow(FALSE);
399                 GetDlgItem(IDC_GOAL_SCORE)->EnableWindow(FALSE);
400                 GetDlgItem(IDC_NO_MUSIC)->EnableWindow(FALSE);
401                 GetDlgItem(IDC_OBJ_TEAM)->EnableWindow(FALSE);
402                 return;
403         }
404
405         m_name = _T(m_goals[cur_goal].name);
406         m_goal_desc = _T(m_goals[cur_goal].message);
407         m_goal_type = m_goals[cur_goal].type & GOAL_TYPE_MASK;
408         if ( m_goals[cur_goal].type & INVALID_GOAL ){
409                 m_goal_invalid = 1;
410         } else {
411                 m_goal_invalid = 0;
412         }
413
414         if ( m_goals[cur_goal].flags & MGF_NO_MUSIC ){
415                 m_no_music = 1;
416         } else {
417                 m_no_music = 0;
418         }
419
420         m_goal_score = m_goals[cur_goal].score;
421
422         m_team = m_goals[cur_goal].team;
423
424         UpdateData(FALSE);
425         GetDlgItem(IDC_GOAL_TYPE_DROP) -> EnableWindow(TRUE);
426         GetDlgItem(IDC_GOAL_NAME) -> EnableWindow(TRUE);
427         GetDlgItem(IDC_GOAL_DESC) -> EnableWindow(TRUE);
428 //      GetDlgItem(IDC_GOAL_RATING) -> EnableWindow(TRUE);
429         GetDlgItem(IDC_GOAL_INVALID)->EnableWindow(TRUE);
430         GetDlgItem(IDC_GOAL_SCORE)->EnableWindow(TRUE);
431         GetDlgItem(IDC_NO_MUSIC)->EnableWindow(TRUE);
432         GetDlgItem(IDC_OBJ_TEAM)->EnableWindow(FALSE);
433         if ( The_mission.game_type & MISSION_TYPE_MULTI_TEAMS ){
434                 GetDlgItem(IDC_OBJ_TEAM)->EnableWindow(TRUE);
435         }
436 }
437
438 // handler for context menu (i.e. a right mouse button click).
439 void CMissionGoalsDlg::OnRclickGoalsTree(NMHDR* pNMHDR, LRESULT* pResult) 
440 {
441         m_goals_tree.right_clicked(MODE_GOALS);
442         *pResult = 0;
443 }
444
445 // goal tree item label editing is requested.  Determine if it should be allowed.
446 void CMissionGoalsDlg::OnBeginlabeleditGoalsTree(NMHDR* pNMHDR, LRESULT* pResult)
447 {
448         TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
449
450         if (m_goals_tree.edit_label(pTVDispInfo->item.hItem) == 1)      {
451                 *pResult = 0;
452                 modified = 1;
453         } else {
454                 *pResult = 1;
455         }
456 }
457
458 // Once we finish editing, we need to clean up, which we do here.
459 void CMissionGoalsDlg::OnEndlabeleditGoalsTree(NMHDR* pNMHDR, LRESULT* pResult) 
460 {
461         TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
462
463         *pResult = m_goals_tree.end_label_edit(pTVDispInfo->item.hItem, pTVDispInfo->item.pszText);
464 }
465
466 void CMissionGoalsDlg::OnOK()
467 {
468         HWND h;
469         CWnd *w;
470
471         w = GetFocus();
472         if (w) {
473                 h = w->m_hWnd;
474                 GetDlgItem(IDC_GOALS_TREE)->SetFocus();
475                 ::SetFocus(h);
476         }
477 }
478
479 int CMissionGoalsDlg::query_modified()
480 {
481         int i;
482
483         if (modified)
484                 return 1;
485
486         if (Num_goals != m_num_goals)
487                 return 1;
488
489         for (i=0; i<Num_goals; i++) {
490                 if (stricmp(Mission_goals[i].name, m_goals[i].name))
491                         return 1;
492                 if (stricmp(Mission_goals[i].message, m_goals[i].message))
493                         return 1;
494                 if (Mission_goals[i].type != m_goals[i].type)
495                         return 1;
496                 if ( Mission_goals[i].score != m_goals[i].score )
497                         return 1;
498                 if ( Mission_goals[i].team != m_goals[i].team )
499                         return 1;
500         }
501
502         return 0;
503 }
504
505 void CMissionGoalsDlg::OnOk()
506 {
507         char buf[256], names[2][MAX_GOALS][NAME_LENGTH];
508         int i, count;
509
510         for (i=0; i<Num_goals; i++)
511                 free_sexp2(Mission_goals[i].formula);
512
513         UpdateData(TRUE);
514         if (query_modified())
515                 set_modified();
516
517         count = 0;
518         for (i=0; i<Num_goals; i++)
519                 Mission_goals[i].satisfied = 0;  // use this as a processed flag
520         
521         // rename all sexp references to old events
522         for (i=0; i<m_num_goals; i++)
523                 if (m_sig[i] >= 0) {
524                         strcpy(names[0][count], Mission_goals[m_sig[i]].name);
525                         strcpy(names[1][count], m_goals[i].name);
526                         count++;
527                         Mission_goals[m_sig[i]].satisfied = 1;
528                 }
529
530         // invalidate all sexp references to deleted events.
531         for (i=0; i<Num_goals; i++)
532                 if (!Mission_goals[i].satisfied) {
533                         sprintf(buf, "<%s>", Mission_goals[i].name);
534                         strcpy(buf + NAME_LENGTH - 2, ">");  // force it to be not too long
535                         strcpy(names[0][count], Mission_goals[i].name);
536                         strcpy(names[1][count], buf);
537                         count++;
538                 }
539
540         Num_goals = m_num_goals;
541         for (i=0; i<Num_goals; i++) {
542                 Mission_goals[i] = m_goals[i];
543                 Mission_goals[i].formula = m_goals_tree.save_tree(Mission_goals[i].formula);
544                 if ( The_mission.game_type & MISSION_TYPE_MULTI_TEAMS ) {
545                         SDL_assert( Mission_goals[i].team != -1 );
546                 }
547         }
548
549         // now update all sexp references
550         while (count--)
551                 update_sexp_references(names[0][count], names[1][count], OPF_GOAL_NAME);
552
553         theApp.record_window_data(&Mission_goals_wnd_data, this);
554         CDialog::OnOK();
555 }
556
557 void CMissionGoalsDlg::OnButtonNewGoal() 
558 {
559         int index;
560         HTREEITEM h;
561
562         SDL_assert(m_num_goals < MAX_GOALS);
563         m_goals[m_num_goals].type = m_display_goal_types;                       // this also marks the goal as valid since bit not set
564         m_sig[m_num_goals] = -1;
565         strcpy(m_goals[m_num_goals].name, "Goal name");
566         strcpy(m_goals[m_num_goals].message, "Mission goal text");
567         h = m_goals_tree.insert(m_goals[m_num_goals].name);
568
569         m_goals_tree.item_index = -1;
570         m_goals_tree.add_operator("true", h);
571         m_goals[m_num_goals].score = 0;
572         index = m_goals[m_num_goals].formula = m_goals_tree.item_index;
573         m_goals_tree.SetItemData(h, index);
574
575         // team defaults to the first team.
576         m_goals[m_num_goals].team = 0;
577
578         m_num_goals++;
579
580         if (m_num_goals >= MAX_GOALS){
581                 GetDlgItem(IDC_BUTTON_NEW_GOAL)->EnableWindow(FALSE);
582         }
583
584         m_goals_tree.SelectItem(h);
585 }
586
587 int CMissionGoalsDlg::handler(int code, int node)
588 {
589         int goal;
590
591         switch (code) {
592         case ROOT_DELETED:
593                 for (goal=0; goal<m_num_goals; goal++){
594                         if (m_goals[goal].formula == node){
595                                 break;
596                         }
597                 }
598
599                 SDL_assert(goal < m_num_goals);
600                 while (goal < m_num_goals - 1) {
601                         m_goals[goal] = m_goals[goal + 1];
602                         m_sig[goal] = m_sig[goal + 1];
603                         goal++;
604                 }
605                 m_num_goals--;
606                 GetDlgItem(IDC_BUTTON_NEW_GOAL)->EnableWindow(TRUE);
607                 return node;
608
609         default:
610                 Int3();
611         }
612
613         return -1;
614 }
615
616 void CMissionGoalsDlg::OnChangeGoalDesc() 
617 {
618         if (cur_goal < 0){
619                 return;
620         }
621
622         UpdateData(TRUE);
623         string_copy(m_goals[cur_goal].message, m_goal_desc, MAX_GOAL_TEXT);
624 }
625
626 void CMissionGoalsDlg::OnChangeGoalRating() 
627 {
628         if (cur_goal < 0){
629                 return;
630         }
631
632         UpdateData(TRUE);
633 }
634
635 void CMissionGoalsDlg::OnSelchangeGoalTypeDrop() 
636 {
637         HTREEITEM h, h2;
638         int otype;
639
640         if (cur_goal < 0){
641                 return;
642         }
643
644         UpdateData(TRUE);
645         UpdateData(TRUE);  // doesn't seem to update unless we do it twice..
646
647         // change the type being sure to keep the invalid bit if set
648         otype = m_goals[cur_goal].type;
649         m_goals[cur_goal].type = m_goal_type;
650         if ( otype & INVALID_GOAL ){
651                 m_goals[cur_goal].type |= INVALID_GOAL;
652         }
653
654         h = m_goals_tree.GetSelectedItem();
655         SDL_assert(h);
656         while ((h2 = m_goals_tree.GetParentItem(h)) != 0){
657                 h = h2;
658         }
659
660         m_goals_tree.DeleteItem(h);
661         cur_goal = -1;
662         update_cur_goal();
663 }
664
665 void CMissionGoalsDlg::OnChangeGoalName() 
666 {
667         HTREEITEM h, h2;
668
669         if (cur_goal < 0){
670                 return;
671         }
672
673         UpdateData(TRUE);
674         h = m_goals_tree.GetSelectedItem();
675         if (!h){
676                 return;
677         }
678
679         while ((h2 = m_goals_tree.GetParentItem(h)) != 0){
680                 h = h2;
681         }
682
683         m_goals_tree.SetItemText(h, m_name);
684         string_copy(m_goals[cur_goal].name, m_name, NAME_LENGTH);
685 }
686
687 void CMissionGoalsDlg::OnCancel()
688 {
689         theApp.record_window_data(&Messages_wnd_data, this);
690         CDialog::OnCancel();
691 }
692
693 void CMissionGoalsDlg::OnClose() 
694 {
695         int z;
696
697         if (query_modified()) {
698                 z = MessageBox("Do you want to keep your changes?", "Close", MB_ICONQUESTION | MB_YESNOCANCEL);
699                 if (z == IDCANCEL)
700                         return;
701
702                 if (z == IDYES) {
703                         OnOk();
704                         return;
705                 }
706         }
707         
708         CDialog::OnClose();
709 }
710
711 void CMissionGoalsDlg::insert_handler(int old, int node)
712 {
713         int i;
714
715         for (i=0; i<m_num_goals; i++){
716                 if (m_goals[i].formula == old){
717                         break;
718                 }
719         }
720
721         SDL_assert(i < m_num_goals);
722         m_goals[i].formula = node;
723         return;
724 }
725
726 void CMissionGoalsDlg::OnGoalInvalid() 
727 {
728         if ( cur_goal < 0 ){
729                 return;
730         }
731
732         m_goal_invalid = !m_goal_invalid;
733         m_goals[cur_goal].type ^= INVALID_GOAL;
734         UpdateData(TRUE);
735 }
736
737 void CMissionGoalsDlg::OnNoMusic() 
738 {
739         if (cur_goal < 0){
740                 return;
741         }
742
743         m_no_music = !m_no_music;
744         m_goals[cur_goal].flags ^= MGF_NO_MUSIC;
745         UpdateData(TRUE);
746 }
747
748 void CMissionGoalsDlg::swap_handler(int node1, int node2)
749 {
750         int index1, index2;
751         mission_goal m;
752
753         for (index1=0; index1<m_num_goals; index1++){
754                 if (m_goals[index1].formula == node1){
755                         break;
756                 }
757         }
758
759         SDL_assert(index1 < m_num_goals);
760         for (index2=0; index2<m_num_goals; index2++){
761                 if (m_goals[index2].formula == node2){
762                         break;
763                 }
764         }
765
766         SDL_assert(index2 < m_num_goals);
767         m = m_goals[index1];
768 //      m_goals[index1] = m_goals[index2];
769         while (index1 < index2) {
770                 m_goals[index1] = m_goals[index1 + 1];
771                 m_sig[index1] = m_sig[index1 + 1];
772                 index1++;
773         }
774
775         while (index1 > index2 + 1) {
776                 m_goals[index1] = m_goals[index1 - 1];
777                 m_sig[index1] = m_sig[index1 - 1];
778                 index1--;
779         }
780
781         m_goals[index1] = m;
782 }
783
784 void CMissionGoalsDlg::OnChangeGoalScore() 
785 {
786         if (cur_goal < 0){
787                 return;
788         }
789
790         UpdateData(TRUE);
791         m_goals[cur_goal].score = m_goal_score;
792 }
793
794
795 // code when the "team" selection in the combo box changes
796 void CMissionGoalsDlg::OnSelchangeTeam() 
797 {
798         if ( cur_goal < 0 ){
799                 return;
800         }
801
802         UpdateData(TRUE);
803         m_goals[cur_goal].team = m_team;
804 }
805