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