]> icculus.org git repositories - taylor/freespace2.git/blob - src/fred2/eventeditor.cpp
The Great Newline Fix
[taylor/freespace2.git] / src / fred2 / eventeditor.cpp
1 /*
2  * $Logfile: /Freespace2/code/fred2/EventEditor.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * Event editor dialog box class and event tree class
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  * 12    9/13/99 8:03a Andsager
18  * Add command heads 3,4,5 as allowable head animations.
19  * 
20  * 11    9/09/99 5:07a Andsager
21  * Make sure TP2 is available in FRED head ani
22  * 
23  * 10    9/01/99 2:52p Andsager
24  * Add new heads to FRED and some debug code for playing heads
25  * 
26  * 9     8/28/99 7:29p Dave
27  * Fixed wingmen persona messaging. Make sure locked turrets don't count
28  * towards the # attacking a player.
29  * 
30  * 8     8/26/99 8:52p Dave
31  * Gave multiplayer TvT messaging a heavy dose of sanity. Cheat codes.
32  * 
33  * 7     5/04/99 5:21p Andsager
34  * 
35  * 6     2/17/99 2:11p Dave
36  * First full run of squad war. All freespace and tracker side stuff
37  * works.
38  * 
39  * 5     1/21/99 9:29a Andsager
40  * 
41  * 4     12/17/98 2:41p Andsager
42  * Changed input into sexp_tree::insert() to include bitmaps
43  * 
44  * 3     11/06/98 11:21a Johnson
45  * Put in handling code for wacky event editor Assert().
46  * 
47  * 2     10/07/98 6:28p Dave
48  * Initial checkin. Renamed all relevant stuff to be Fred2 instead of
49  * Fred. Globalized mission and campaign file extensions. Removed Silent
50  * Threat specific code.
51  * 
52  * 1     10/07/98 3:02p Dave
53  * 
54  * 1     10/07/98 3:00p Dave
55  * 
56  * 55    9/25/98 1:33p Andsager
57  * Add color to event editor (root and chain) indicating mission directive
58  * 
59  * 54    7/09/98 10:57a Hoffoss
60  * Fixed bug where the 'update stuff' button was reverting changes made to
61  * various message fields.
62  * 
63  * 53    5/15/98 5:51p Hoffoss
64  * Fixed escape key and cancel button bugs.
65  * 
66  * 52    5/12/98 11:44a Hoffoss
67  * Made escape key not close dialog (and lose changes made).
68  * 
69  * 51    4/30/98 9:53p Hoffoss
70  * Added "Head-VC" to ani list at Sandeep's request.
71  * 
72  * 50    4/30/98 8:23p John
73  * Fixed some bugs with Fred caused by my new cfile code.
74  * 
75  * 49    4/22/98 9:56a Sandeep
76  * 
77  * 48    4/20/98 4:40p Hoffoss
78  * Added a button to 4 editors to play the chosen wave file.
79  * 
80  * 47    4/03/98 5:20p Hoffoss
81  * Changed code so that changing a message's wave file will update the
82  * persona as well, if the wave file has the proper prefix.
83  * 
84  * 46    4/03/98 12:39p Hoffoss
85  * Changed starting directory for browse buttons in several editors.
86  * 
87  * 45    3/10/98 4:06p Hoffoss
88  * Fixed browse button blues.
89  * 
90  * 44    3/06/98 2:24p Hoffoss
91  * Fixed bug with going to reference with deleting a entity referenced by
92  * an sexp tree.
93  * 
94  * 43    2/16/98 6:25p Hoffoss
95  * Did major rework of the whole right_clicked() handler to simplify it
96  * all, break it down and make it more flexible.  Should be a lot easier
97  * to work with from now on.
98  * 
99  * 42    2/16/98 2:42p Hoffoss
100  * Added new code in preparation to simplify the sexp_tree monster.
101  * Checking in code now as a good foundation point that I can revert back
102  * to if needed.
103  * 
104  * 41    1/23/98 3:06p Hoffoss
105  * Added an explicit <none> item to the filename combo boxes at designers
106  * request.
107  * 
108  * 40    1/09/98 3:41p Hoffoss
109  * Fixed bug with event moving not updating fields properly.
110  * 
111  * 39    1/08/98 11:18a Hoffoss
112  * Fixed several bugs in new Event Editor.
113  * 
114  * 38    1/08/98 10:24a Johnson
115  * Fixed bug with null strings for filenames.
116  * 
117  * 37    1/07/98 5:58p Hoffoss
118  * Combined message editor into event editor.
119  * 
120  * 36    1/06/98 8:25p Hoffoss
121  * Added insert event functionality to event editor.
122  * 
123  * 35    1/06/98 3:31p Hoffoss
124  * Added image to indicate chained events, and added code to support it.
125  * 
126  * 34    10/20/97 5:13p Allender
127  * new subsystem sabotage/repair/set sexpressions.  Added new event/goal
128  * status checking sexpressions (not fully implemented yet).  Change
129  * campaign save files to save all events as well as goals
130  * 
131  * 33    10/10/97 6:21p Hoffoss
132  * Put in Fred support for training object list editing.
133  * 
134  * 32    10/10/97 2:53p Johnson
135  * Fixed bug with new items being selected before they are fully
136  * registered as added.
137  * 
138  * $NoKeywords: $
139  */
140
141 #include "stdafx.h"
142 #include <mmsystem.h>
143 #include "fred.h"
144 #include "freddoc.h"
145 #include "eventeditor.h"
146 #include "fredview.h"
147 #include "management.h"
148 #include "sexp_tree.h"
149 #include "missionmessage.h"
150 #include "cfile.h"
151
152 #ifdef _DEBUG
153 #define new DEBUG_NEW
154 #undef THIS_FILE
155 static char THIS_FILE[] = __FILE__;
156 #endif
157
158 event_editor *Event_editor_dlg = NULL; // global reference needed by event tree class
159
160 // determine the node number that would be allocated without actually allocating it yet.
161 int sexp_event_tree::get_new_node_position()
162 {
163         int i;
164
165         for (i=0; i<MAX_SEXP_TREE_SIZE; i++)
166                 if (nodes[i].type == SEXPT_UNUSED)
167                         return i;
168
169         return -1;
170 }
171
172 // construct tree nodes for an sexp, adding them to the list and returning first node
173 int sexp_event_tree::load_sub_tree(int index)
174 {
175         int cur;
176
177         if (index < 0) {
178                 cur = allocate_node(-1);
179                 set_node(cur, SEXPT_OPERATOR, "do-nothing");  // setup a default tree if none
180                 return cur;
181         }
182
183         // assumption: first token is an operator.  I require this because it would cause problems
184         // with child/parent relations otherwise, and it should be this way anyway, since the
185         // return type of the whole sexp is boolean, and only operators can satisfy this.
186         Assert(Sexp_nodes[index].subtype == SEXP_ATOM_OPERATOR);
187         cur = get_new_node_position();
188         load_branch(index, -1);
189         return cur;
190 }
191
192 /////////////////////////////////////////////////////////////////////////////
193 // event_editor dialog
194
195 event_editor::event_editor(CWnd* pParent /*=NULL*/)
196         : CDialog(event_editor::IDD, pParent)
197 {
198         //{{AFX_DATA_INIT(event_editor)
199         m_repeat_count = 0;
200         m_interval = 0;
201         m_event_score = 0;
202         m_chain_delay = 0;
203         m_chained = FALSE;
204         m_obj_text = _T("");
205         m_obj_key_text = _T("");
206         m_avi_filename = _T("");
207         m_message_name = _T("");
208         m_message_text = _T("");
209         m_persona = -1;
210         m_wave_filename = _T("");
211         m_cur_msg = -1;
212         m_team = -1;
213         m_message_team = -1;
214         m_last_message_node = -1;
215         //}}AFX_DATA_INIT
216         m_event_tree.m_mode = MODE_EVENTS;
217         m_num_events = 0;
218         m_event_tree.link_modified(&modified);
219         modified = 0;
220         select_sexp_node = -1;
221 }
222
223 void event_editor::DoDataExchange(CDataExchange* pDX)
224 {
225         CDialog::DoDataExchange(pDX);
226         //{{AFX_DATA_MAP(event_editor)
227         DDX_Control(pDX, IDC_EVENT_TREE, m_event_tree);
228         DDX_Text(pDX, IDC_REPEAT_COUNT, m_repeat_count);
229         DDX_Text(pDX, IDC_INTERVAL_TIME, m_interval);
230         DDX_Text(pDX, IDC_EVENT_SCORE, m_event_score);
231         DDX_Text(pDX, IDC_CHAIN_DELAY, m_chain_delay);
232         DDX_Check(pDX, IDC_CHAINED, m_chained);
233         DDX_Text(pDX, IDC_OBJ_TEXT, m_obj_text);
234         DDX_Text(pDX, IDC_OBJ_KEY_TEXT, m_obj_key_text);
235         DDX_CBString(pDX, IDC_AVI_FILENAME, m_avi_filename);
236         DDX_Text(pDX, IDC_MESSAGE_NAME, m_message_name);
237         DDX_Text(pDX, IDC_MESSAGE_TEXT, m_message_text);
238         DDX_CBIndex(pDX, IDC_PERSONA_NAME, m_persona);
239         DDX_CBString(pDX, IDC_WAVE_FILENAME, m_wave_filename);
240         DDX_LBIndex(pDX, IDC_MESSAGE_LIST, m_cur_msg);
241
242         // m_team == -1 maps to 2
243         if(m_team == -1){
244                 m_team = 2;
245         }
246         DDX_CBIndex(pDX, IDC_EVENT_TEAM, m_team);
247
248         // m_message_team == -1 maps to 2
249         if(m_message_team == -1){
250                 m_message_team = 2;
251         }
252         DDX_CBIndex(pDX, IDC_MESSAGE_TEAM, m_message_team);
253         //}}AFX_DATA_MAP
254
255         DDV_MaxChars(pDX, m_obj_text, NAME_LENGTH - 1);
256         DDV_MaxChars(pDX, m_obj_key_text, NAME_LENGTH - 1);
257         DDV_MaxChars(pDX, m_message_name, NAME_LENGTH - 1);
258         DDV_MaxChars(pDX, m_message_text, MESSAGE_LENGTH - 1);
259         DDV_MaxChars(pDX, m_avi_filename, MAX_FILENAME_LEN - 1);
260         DDV_MaxChars(pDX, m_wave_filename, MAX_FILENAME_LEN - 1);
261 }
262
263 BEGIN_MESSAGE_MAP(event_editor, CDialog)
264         //{{AFX_MSG_MAP(event_editor)
265         ON_NOTIFY(NM_RCLICK, IDC_EVENT_TREE, OnRclickEventTree)
266         ON_NOTIFY(TVN_BEGINLABELEDIT, IDC_EVENT_TREE, OnBeginlabeleditEventTree)
267         ON_NOTIFY(TVN_ENDLABELEDIT, IDC_EVENT_TREE, OnEndlabeleditEventTree)
268         ON_BN_CLICKED(IDC_BUTTON_NEW_EVENT, OnButtonNewEvent)
269         ON_BN_CLICKED(IDC_DELETE, OnDelete)
270         ON_BN_CLICKED(ID_OK, OnOk)
271         ON_WM_CLOSE()
272         ON_NOTIFY(TVN_SELCHANGED, IDC_EVENT_TREE, OnSelchangedEventTree)
273         ON_EN_UPDATE(IDC_REPEAT_COUNT, OnUpdateRepeatCount)
274         ON_BN_CLICKED(IDC_CHAINED, OnChained)
275         ON_BN_CLICKED(IDC_INSERT, OnInsert)
276         ON_LBN_SELCHANGE(IDC_MESSAGE_LIST, OnSelchangeMessageList)
277         ON_BN_CLICKED(IDC_NEW_MSG, OnNewMsg)
278         ON_BN_CLICKED(IDC_DELETE_MSG, OnDeleteMsg)
279         ON_BN_CLICKED(IDC_BROWSE_AVI, OnBrowseAvi)
280         ON_BN_CLICKED(IDC_BROWSE_WAVE, OnBrowseWave)
281         ON_CBN_SELCHANGE(IDC_WAVE_FILENAME, OnSelchangeWaveFilename)
282         ON_BN_CLICKED(IDC_PLAY, OnPlay)
283         ON_BN_CLICKED(IDC_UPDATE, OnUpdate)
284         ON_BN_CLICKED(ID_CANCEL, On_Cancel)
285         ON_CBN_SELCHANGE(IDC_EVENT_TEAM, OnSelchangeTeam)
286         ON_CBN_SELCHANGE(IDC_MESSAGE_TEAM, OnSelchangeMessageTeam)
287         ON_LBN_DBLCLK(IDC_MESSAGE_LIST, OnDblclkMessageList)
288         //}}AFX_MSG_MAP
289 END_MESSAGE_MAP()
290
291 /////////////////////////////////////////////////////////////////////////////
292 // event_editor message handlers
293
294 void maybe_add_head(CComboBox *box, char* name)
295 {
296         if (box->FindStringExact(-1, name) == CB_ERR) {
297                 box->AddString(name);
298         }
299 }
300
301 BOOL event_editor::OnInitDialog() 
302 {
303         int i, adjust = 0;
304         BOOL r = TRUE;
305         CListBox *list;
306         CComboBox *box;
307
308         CDialog::OnInitDialog();  // let the base class do the default work
309         m_play_bm.LoadBitmap(IDB_PLAY);
310         ((CButton *) GetDlgItem(IDC_PLAY)) -> SetBitmap(m_play_bm);
311
312         if (!Show_sexp_help)
313                 adjust = -SEXP_HELP_BOX_SIZE;
314
315         theApp.init_window(&Events_wnd_data, this, adjust);
316         m_event_tree.setup((CEdit *) GetDlgItem(IDC_HELP_BOX));
317         load_tree();
318         create_tree();
319         if (m_num_events >= MAX_MISSION_EVENTS){
320                 GetDlgItem(IDC_BUTTON_NEW_EVENT)->EnableWindow(FALSE);
321         }
322
323         update_cur_event();
324         i = m_event_tree.select_sexp_node;
325         if (i != -1) {
326                 GetDlgItem(IDC_EVENT_TREE) -> SetFocus();
327                 m_event_tree.hilite_item(i);
328                 r = FALSE;
329         }
330
331         m_num_messages = Num_messages - Num_builtin_messages;
332         for (i=0; i<m_num_messages; i++) {
333                 m_messages[i] = Messages[i + Num_builtin_messages];
334                 if (m_messages[i].avi_info.name){
335                         m_messages[i].avi_info.name = strdup(m_messages[i].avi_info.name);
336                 }
337                 if (m_messages[i].wave_info.name){
338                         m_messages[i].wave_info.name = strdup(m_messages[i].wave_info.name);
339                 }
340                 m_msg_sig[i] = i + Num_builtin_messages;
341         }
342
343         ((CEdit *) GetDlgItem(IDC_MESSAGE_NAME))->LimitText(NAME_LENGTH - 1);
344         ((CEdit *) GetDlgItem(IDC_MESSAGE_TEXT))->LimitText(MESSAGE_LENGTH - 1);
345         ((CComboBox *) GetDlgItem(IDC_AVI_FILENAME))->LimitText(MAX_FILENAME_LEN - 1);
346         ((CComboBox *) GetDlgItem(IDC_WAVE_FILENAME))->LimitText(MAX_FILENAME_LEN - 1);
347
348         list = (CListBox *) GetDlgItem(IDC_MESSAGE_LIST);
349         list->ResetContent();
350         for (i=0; i<m_num_messages; i++) {
351                 list->AddString(m_messages[i].name);
352         }
353
354         box = (CComboBox *) GetDlgItem(IDC_AVI_FILENAME);
355         box->ResetContent();
356         box->AddString("<None>");
357         for (i=0; i<Num_messages; i++) {
358                 if (Messages[i].avi_info.name) {
359                         maybe_add_head(box, Messages[i].avi_info.name);
360                 }
361         }
362
363         // add new heads, if not already in
364         maybe_add_head(box, "Head-TP2");
365         maybe_add_head(box, "Head-VC2");
366         maybe_add_head(box, "Head-TP4");
367         maybe_add_head(box, "Head-TP5");
368         maybe_add_head(box, "Head-TP6");
369         maybe_add_head(box, "Head-TP7");
370         maybe_add_head(box, "Head-TP8");
371         maybe_add_head(box, "Head-VP2");
372         maybe_add_head(box, "Head-VP2");
373         maybe_add_head(box, "Head-CM2");
374         maybe_add_head(box, "Head-CM3");
375         maybe_add_head(box, "Head-CM4");
376         maybe_add_head(box, "Head-CM5");
377         maybe_add_head(box, "Head-BSH");
378
379 /*
380         box->AddString("Head-VC");  // force it in, since Sandeep wants it and it's not used in built-in messages
381         box->AddString("Head-VC2");
382
383         // add terran pilot heads
384         box->AddString("Head-TP4");
385         box->AddString("Head-TP5");
386         box->AddString("Head-TP6");
387         box->AddString("Head-TP7");
388         box->AddString("Head-TP8");
389
390         // add vasudan pilot heads
391         box->AddString("Head-VP2");
392
393         // BSH and CM2
394         box->AddString("Head-CM2");
395         box->AddString("Head-BSH");
396         */
397
398         box = (CComboBox *) GetDlgItem(IDC_WAVE_FILENAME);
399         box->ResetContent();
400         box->AddString("<None>");
401         for (i=0; i<Num_messages; i++){
402                 if (Messages[i].wave_info.name){
403                         if (box->FindStringExact(i, Messages[i].wave_info.name) == CB_ERR){
404                                 box->AddString(Messages[i].wave_info.name);
405                         }
406                 }
407         }
408
409         // add the persona names into the combo box
410         box = (CComboBox *) GetDlgItem(IDC_PERSONA_NAME);
411         box->ResetContent();
412         box->AddString("<None>");
413         for (i = 0; i < Num_personas; i++ ){
414                 box->AddString( Personas[i].name );
415         }
416
417         // set the first message to be the first non-builtin message (if it exists)
418         if ( Num_messages > Num_builtin_messages ){
419                 m_cur_msg = 0;
420         } else {
421                 m_cur_msg = -1;
422         }
423
424         if (Num_messages >= MAX_MISSION_MESSAGES){
425                 GetDlgItem(IDC_NEW_MSG)->EnableWindow(FALSE);
426         }
427
428         update_cur_message();
429         return r;
430 }
431
432 void event_editor::load_tree()
433 {
434         int i;
435
436         m_event_tree.select_sexp_node = select_sexp_node;
437         select_sexp_node = -1;
438
439         m_event_tree.clear_tree();
440         m_num_events = Num_mission_events;
441         for (i=0; i<m_num_events; i++) {
442                 m_events[i] = Mission_events[i];
443                 if (Mission_events[i].objective_text){
444                         m_events[i].objective_text = strdup(Mission_events[i].objective_text);
445                 } else {
446                         m_events[i].objective_text = NULL;
447                 }
448
449                 if (Mission_events[i].objective_key_text){
450                         m_events[i].objective_key_text = strdup(Mission_events[i].objective_key_text);
451                 } else {
452                         m_events[i].objective_key_text = NULL;
453                 }
454                 
455                 m_sig[i] = i;
456                 if (!(*m_events[i].name)){
457                         strcpy(m_events[i].name, "<Unnamed>");
458                 }
459
460                 m_events[i].formula = m_event_tree.load_sub_tree(Mission_events[i].formula);
461
462                 // we must check for the case of the repeat count being 0.  This would happen if the repeat
463                 // count is not specified in a mission
464                 if ( m_events[i].repeat_count <= 0 ){
465                         m_events[i].repeat_count = 1;
466                 }
467         }
468
469         m_event_tree.post_load();
470         cur_event = -1;
471 }
472
473 void event_editor::create_tree()
474 {
475         int i;
476         HTREEITEM h;
477
478         m_event_tree.DeleteAllItems();
479         for (i=0; i<m_num_events; i++) {
480
481                 // set the proper bitmap
482                 int image;
483                 if (m_events[i].chain_delay >= 0) {
484                         image = BITMAP_CHAIN;
485                         if (m_events[i].objective_text) {
486                                 image = BITMAP_CHAIN_DIRECTIVE;
487                         }
488                 } else {
489                         image = BITMAP_ROOT;
490                         if (m_events[i].objective_text) {
491                                 image = BITMAP_ROOT_DIRECTIVE;
492                         }
493                 }
494
495                 h = m_event_tree.insert(m_events[i].name, image, image);
496
497                 m_event_tree.SetItemData(h, m_events[i].formula);
498                 m_event_tree.add_sub_tree(m_events[i].formula, h);
499         }
500
501         cur_event = -1;
502 }
503
504 void event_editor::OnRclickEventTree(NMHDR* pNMHDR, LRESULT* pResult) 
505 {
506         save();
507         m_event_tree.right_clicked(MODE_EVENTS);
508         *pResult = 0;
509 }
510
511 void event_editor::OnBeginlabeleditEventTree(NMHDR* pNMHDR, LRESULT* pResult) 
512 {
513         TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
514         CEdit *edit;
515
516         if (m_event_tree.edit_label(pTVDispInfo->item.hItem) == 1)      {
517                 *pResult = 0;
518                 modified = 1;
519                 edit = m_event_tree.GetEditControl();
520                 Assert(edit);
521                 edit->SetLimitText(NAME_LENGTH - 1);
522
523         } else
524                 *pResult = 1;
525 }
526
527 void event_editor::OnEndlabeleditEventTree(NMHDR* pNMHDR, LRESULT* pResult) 
528 {
529         TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
530
531         *pResult = m_event_tree.end_label_edit(pTVDispInfo->item.hItem, pTVDispInfo->item.pszText);
532 }
533
534 // This is needed as a HACK around default MFC standard
535 // It is not required, but overrides default MFC and links no errors without.
536 void event_editor::OnOK()
537 {
538         HWND h;
539         CWnd *w;
540
541         save();
542         w = GetFocus();
543         if (w) {
544                 h = w->m_hWnd;
545                 GetDlgItem(IDC_EVENT_TREE)->SetFocus();
546                 ::SetFocus(h);
547         }
548 }
549
550 int event_editor::query_modified()
551 {
552         int i;
553         char *ptr, buf[MESSAGE_LENGTH];
554
555         UpdateData(TRUE);
556         if (modified)
557                 return 1;
558
559         if (Num_mission_events != m_num_events)
560                 return 1;
561
562         for (i=0; i<m_num_events; i++) {
563                 if (stricmp(m_events[i].name, Mission_events[i].name))
564                         return 1;
565                 if (m_events[i].repeat_count != Mission_events[i].repeat_count)
566                         return 1;
567                 if (m_events[i].interval != Mission_events[i].interval)
568                         return 1;
569                 if (m_events[i].score != Mission_events[i].score)
570                         return 1;
571                 if (m_events[i].chain_delay != Mission_events[i].chain_delay)
572                         return 1;
573                 if (advanced_stricmp(m_events[i].objective_text, Mission_events[i].objective_text))
574                         return 1;
575                 if (advanced_stricmp(m_events[i].objective_key_text, Mission_events[i].objective_key_text))
576                         return 1;
577         }
578
579         if (m_cur_msg < 0)
580                 return 0;
581
582         if (m_num_messages != Num_messages)
583                 return 1;
584
585         ptr = (char *) (LPCTSTR) m_message_name;
586         for (i=0; i<Num_builtin_messages; i++)
587                 if (!stricmp(ptr, Messages[i].name))
588                         return 1;
589
590         for (i=0; i<m_num_messages; i++) {
591                 if (m_msg_sig[i] < 0)
592                         return 1;
593
594                 if ((i != m_cur_msg) && (!stricmp(ptr, m_messages[m_cur_msg].name)))
595                         return 1;
596         }
597
598         if (stricmp(ptr, m_messages[m_cur_msg].name))
599                 return 1;  // name is different and allowed to update
600
601         string_copy(buf, m_message_text, MESSAGE_LENGTH - 1);
602         if (stricmp(buf, m_messages[m_cur_msg].message))
603                 return 1;
604
605         ptr = (char *) (LPCTSTR) m_avi_filename;
606         if (advanced_stricmp(ptr, m_messages[m_cur_msg].avi_info.name))
607                 return 1;
608
609         ptr = (char *) (LPCTSTR) m_wave_filename;
610         if (advanced_stricmp(ptr, m_messages[m_cur_msg].wave_info.name))
611                 return 1;
612
613         // check to see if persona changed.  use -1 since we stuck a "None" for persona
614         // at the beginning of the list.
615         if ( (m_persona - 1 ) != m_messages[m_cur_msg].persona_index )
616                 return 1;
617
618         return 0;
619 }
620
621 void event_editor::OnOk()
622 {
623         char buf[256], names[2][MAX_MISSION_EVENTS][NAME_LENGTH];
624         int i, count;
625
626         save();
627         if (query_modified())
628                 set_modified();
629
630         for (i=0; i<Num_mission_events; i++) {
631                 free_sexp2(Mission_events[i].formula);
632                 if (Mission_events[i].objective_text)
633                         free(Mission_events[i].objective_text);
634                 if (Mission_events[i].objective_key_text)
635                         free(Mission_events[i].objective_key_text);
636         }
637
638         count = 0;
639         for (i=0; i<Num_mission_events; i++)
640                 Mission_events[i].result = 0;  // use this as a processed flag
641         
642         // rename all sexp references to old events
643         for (i=0; i<m_num_events; i++)
644                 if (m_sig[i] >= 0) {
645                         strcpy(names[0][count], Mission_events[m_sig[i]].name);
646                         strcpy(names[1][count], m_events[i].name);
647                         count++;
648                         Mission_events[m_sig[i]].result = 1;
649                 }
650
651         // invalidate all sexp references to deleted events.
652         for (i=0; i<Num_mission_events; i++)
653                 if (!Mission_events[i].result) {
654                         sprintf(buf, "<%s>", Mission_events[i].name);
655                         strcpy(buf + NAME_LENGTH - 2, ">");  // force it to be not too long
656                         strcpy(names[0][count], Mission_events[i].name);
657                         strcpy(names[1][count], buf);
658                         count++;
659                 }
660
661         Num_mission_events = m_num_events;
662         for (i=0; i<m_num_events; i++) {
663                 Mission_events[i] = m_events[i];
664                 Mission_events[i].formula = m_event_tree.save_tree(m_events[i].formula);
665                 Mission_events[i].objective_text = m_events[i].objective_text;
666                 Mission_events[i].objective_key_text = m_events[i].objective_key_text;
667         }
668
669         // now update all sexp references
670         while (count--)
671                 update_sexp_references(names[0][count], names[1][count], OPF_EVENT_NAME);
672
673         for (i=Num_builtin_messages; i<Num_messages; i++) {
674                 if (Messages[i].avi_info.name)
675                         free(Messages[i].avi_info.name);
676
677                 if (Messages[i].wave_info.name)
678                         free(Messages[i].wave_info.name);
679         }
680
681         Num_messages = m_num_messages + Num_builtin_messages;
682         for (i=0; i<m_num_messages; i++)
683                 Messages[i + Num_builtin_messages] = m_messages[i];
684
685         theApp.record_window_data(&Events_wnd_data, this);
686         delete Event_editor_dlg;
687         Event_editor_dlg = NULL;
688 }
689
690 // load controls with structure data
691 void event_editor::update_cur_message()
692 {
693         int enable = TRUE;
694
695         if (m_cur_msg < 0) {
696                 enable = FALSE;
697                 m_message_name = _T("");
698                 m_message_text = _T("");
699                 m_avi_filename = _T("");
700                 m_wave_filename = _T("");
701                 m_persona = 0;
702                 m_message_team = -1;
703         } else {
704                 m_message_name = m_messages[m_cur_msg].name;
705                 m_message_text = m_messages[m_cur_msg].message;
706                 if (m_messages[m_cur_msg].avi_info.name){
707                         m_avi_filename = _T(m_messages[m_cur_msg].avi_info.name);
708                 } else {
709                         m_avi_filename = _T("<None>");
710                 }
711
712                 if (m_messages[m_cur_msg].wave_info.name){
713                         m_wave_filename = _T(m_messages[m_cur_msg].wave_info.name);
714                 } else {
715                         m_wave_filename = _T("<None>");
716                 }
717
718                 // add persona id
719                 if ( m_messages[m_cur_msg].persona_index != -1 ){
720                         m_persona = m_messages[m_cur_msg].persona_index + 1;  // add one for the "none" at the beginning of the list
721                 } else {
722                         m_persona = 0;
723                 }
724
725                 if(m_messages[m_cur_msg].multi_team >= 2){
726                         m_message_team = -1;
727                         m_messages[m_cur_msg].multi_team = -1;
728                 } else {
729                         m_message_team = m_messages[m_cur_msg].multi_team;
730                 }
731 /*
732                 m_event_num = find_event();
733                 if (m_event_num < 0) {
734                         node = -1;
735                         m_sender = m_priority = 0;
736
737                 } else
738                         node = CADR(Mission_events[m_event_num].formula);
739 */      }
740
741         GetDlgItem(IDC_MESSAGE_NAME)->EnableWindow(enable);
742         GetDlgItem(IDC_MESSAGE_TEXT)->EnableWindow(enable);
743         GetDlgItem(IDC_AVI_FILENAME)->EnableWindow(enable);
744         GetDlgItem(IDC_BROWSE_AVI)->EnableWindow(enable);
745         GetDlgItem(IDC_BROWSE_WAVE)->EnableWindow(enable);
746         GetDlgItem(IDC_WAVE_FILENAME)->EnableWindow(enable);
747         GetDlgItem(IDC_DELETE_MSG)->EnableWindow(enable);
748         GetDlgItem(IDC_PERSONA_NAME)->EnableWindow(enable);
749         GetDlgItem(IDC_MESSAGE_TEAM)->EnableWindow(enable);
750         UpdateData(FALSE);
751 }
752
753 int event_editor::handler(int code, int node, char *str)
754 {
755         int i;
756
757         switch (code) {
758                 case ROOT_DELETED:
759                         for (i=0; i<m_num_events; i++)
760                                 if (m_events[i].formula == node)
761                                         break;
762
763                         Assert(i < m_num_events);
764                         while (i < m_num_events - 1) {
765                                 m_events[i] = m_events[i + 1];
766                                 m_sig[i] = m_sig[i + 1];
767                                 i++;
768                         }
769
770                         m_num_events--;
771                         GetDlgItem(IDC_BUTTON_NEW_EVENT)->EnableWindow(TRUE);
772                         return node;
773
774                 case ROOT_RENAMED:
775                         for (i=0; i<m_num_events; i++)
776                                 if (m_events[i].formula == node)
777                                         break;
778
779                         Assert(i < m_num_events);
780                         Assert(strlen(str) < NAME_LENGTH);
781                         strcpy(m_events[i].name, str);
782                         return node;
783
784                 default:
785                         Int3();
786         }
787
788         return -1;
789 }
790
791 void event_editor::OnButtonNewEvent() 
792 {
793         if (m_num_events == MAX_MISSION_EVENTS) {
794                 MessageBox("You have reached the limit on mission events.\n"
795                         "Can't add any more.");
796                 return;
797         }
798
799         reset_event(m_num_events++, TVI_LAST);
800 }
801
802 void event_editor::OnInsert() 
803 {
804         int i;
805
806         if (m_num_events == MAX_MISSION_EVENTS) {
807                 MessageBox("You have reached the limit on mission events.\n"
808                         "Can't add any more.");
809                 return;
810         }
811
812         for (i=m_num_events; i>cur_event; i--) {
813                 m_events[i] = m_events[i - 1];
814                 m_sig[i] = m_sig[i - 1];
815         }
816
817         if (cur_event){
818                 reset_event(cur_event, get_event_handle(cur_event - 1));
819         } else {
820                 reset_event(cur_event, TVI_FIRST);
821         }
822
823         m_num_events++;
824 }
825
826 HTREEITEM event_editor::get_event_handle(int num)
827 {
828         HTREEITEM h;
829
830         h = m_event_tree.GetRootItem();
831         while (h) {
832                 if ((int) m_event_tree.GetItemData(h) == m_events[num].formula){
833                         return h;
834                 }
835
836                 h = m_event_tree.GetNextSiblingItem(h);
837         }
838
839         return 0;
840 }
841
842 void event_editor::reset_event(int num, HTREEITEM after)
843 {
844         int index;
845         HTREEITEM h;
846
847         strcpy(m_events[num].name, "Event name");
848         h = m_event_tree.insert(m_events[num].name, BITMAP_ROOT, BITMAP_ROOT, TVI_ROOT, after);
849
850         m_events[num].repeat_count = 1;
851         m_events[num].interval = 1;
852         m_events[num].score = 0;
853         m_events[num].chain_delay = -1;
854         m_events[num].objective_text = NULL;
855         m_events[num].objective_key_text = NULL;
856         m_sig[num] = -1;
857
858         m_event_tree.item_index = -1;
859         m_event_tree.add_operator("when", h);
860         index = m_events[num].formula = m_event_tree.item_index;
861         m_event_tree.SetItemData(h, index);
862         m_event_tree.add_operator("true");
863         m_event_tree.item_index = index;
864         m_event_tree.add_operator("do-nothing");
865
866         m_event_tree.SelectItem(h);
867 //      GetDlgItem(IDC_CHAIN_DELAY) -> EnableWindow(FALSE);
868         if (num >= MAX_MISSION_EVENTS){
869                 GetDlgItem(IDC_BUTTON_NEW_EVENT)->EnableWindow(FALSE);
870         }
871 }
872
873 void event_editor::OnDelete() 
874 {
875         HTREEITEM h;
876
877         // call update_cur_event to clean up local class variables so that we can correctly
878         // set up the newly selected item.
879         cur_event = -1;
880         update_cur_event();
881
882         h = m_event_tree.GetSelectedItem();
883         if (h) {
884                 while (m_event_tree.GetParentItem(h))
885                         h = m_event_tree.GetParentItem(h);
886
887                 m_event_tree.setup_selected(h);
888                 m_event_tree.OnCommand(ID_DELETE, 0);
889         }
890 }
891
892 // this is called when you hit the escape key..
893 void event_editor::OnCancel()
894 {
895 }
896
897 // this is called the clicking the ID_CANCEL button
898 void event_editor::On_Cancel()
899 {
900         theApp.record_window_data(&Events_wnd_data, this);
901         delete Event_editor_dlg;
902         Event_editor_dlg = NULL;
903 }
904
905 void event_editor::OnClose() 
906 {
907         int z;
908
909         if (query_modified()) {
910                 z = MessageBox("Do you want to keep your changes?", "Close", MB_ICONQUESTION | MB_YESNOCANCEL);
911                 if (z == IDCANCEL){
912                         return;
913                 }
914
915                 if (z == IDYES) {
916                         OnOk();
917                         return;
918                 }
919         }
920         
921         theApp.record_window_data(&Events_wnd_data, this);
922         delete Event_editor_dlg;
923         Event_editor_dlg = NULL;
924 }
925
926 void event_editor::insert_handler(int old, int node)
927 {
928         int i;
929
930         for (i=0; i<m_num_events; i++){
931                 if (m_events[i].formula == old){
932                         break;
933                 }
934         }
935
936         Assert(i < m_num_events);
937         m_events[i].formula = node;
938         return;
939 }
940
941 void event_editor::save()
942 {
943         int m = m_cur_msg;
944
945         save_event(cur_event);
946         save_message(m);
947 }
948
949 void event_editor::save_event(int e)
950 {
951         if (e < 0) {
952                 return;
953         }
954
955         UpdateData(TRUE);
956         m_events[e].repeat_count = m_repeat_count;
957         m_events[e].interval = m_interval;
958         m_events[e].score = m_event_score;
959
960         // handle chain
961         if (m_chained) {
962                 m_events[e].chain_delay = m_chain_delay;
963         } else {
964                 m_events[e].chain_delay = -1;
965         }
966
967         // handle objective text
968         if (m_events[e].objective_text) {
969                 free(m_events[e].objective_text);
970         }
971
972         if (m_obj_text.IsEmpty()) {
973                 m_events[e].objective_text = NULL;
974         } else {
975                 m_events[e].objective_text = strdup(m_obj_text);
976         }
977
978         // handle objective key text
979         if (m_events[e].objective_key_text) {
980                 free(m_events[e].objective_key_text);
981         }
982
983         if (m_obj_key_text.IsEmpty()) {
984                 m_events[e].objective_key_text = NULL;
985         } else {
986                 m_events[e].objective_key_text = strdup(m_obj_key_text);
987         }
988
989         // update bitmap
990         int bitmap;
991         if (m_chained) {
992                 if (m_obj_text.IsEmpty()) {
993                         bitmap = BITMAP_CHAIN;
994                 } else {
995                         bitmap = BITMAP_CHAIN_DIRECTIVE;
996                 }
997         } else {
998                 // not chained
999                 if (m_obj_text.IsEmpty()) {
1000                         bitmap = BITMAP_ROOT;
1001                 } else {
1002                         bitmap = BITMAP_ROOT_DIRECTIVE;
1003                 }
1004         }
1005
1006         // Search for item to update
1007         HTREEITEM h = m_event_tree.GetRootItem();
1008         while (h) {
1009                 if ((int) m_event_tree.GetItemData(h) == m_events[e].formula) {
1010                         m_event_tree.SetItemImage(h, bitmap, bitmap);
1011                         return;
1012                 }
1013
1014                 h = m_event_tree.GetNextSiblingItem(h);
1015         }
1016
1017 }
1018
1019 // this function deals with the left click on an event in the tree view.  We get into this
1020 // function so that we may update the other data on the screen (i.e repeat count and interval
1021 // count)
1022 void event_editor::OnSelchangedEventTree(NMHDR* pNMHDR, LRESULT* pResult) 
1023 {
1024         int i, z;
1025         NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
1026         HTREEITEM h, h2;
1027
1028         // before we do anything, we must check and save off any data from the current event (i.e.
1029         // the repeat count and interval count)
1030         save();
1031         h = pNMTreeView->itemNew.hItem;
1032         if (!h){
1033                 return;
1034         }
1035
1036         m_event_tree.update_help(h);
1037         while ((h2 = m_event_tree.GetParentItem(h))>0){
1038                 h = h2;
1039         }
1040
1041         z = m_event_tree.GetItemData(h);
1042         for (i=0; i<m_num_events; i++){
1043                 if (m_events[i].formula == z){
1044                         break;
1045                 }
1046         }
1047
1048         Assert(i < m_num_events);
1049         cur_event = i;
1050         update_cur_event();
1051         
1052         *pResult = 0;
1053 }
1054
1055 void event_editor::update_cur_event()
1056 {
1057         if (cur_event < 0) {
1058                 m_repeat_count = 1;
1059                 m_interval = 1;
1060                 m_chain_delay = 0;
1061                 m_team = -1;
1062                 m_obj_text.Empty();
1063                 m_obj_key_text.Empty();
1064                 GetDlgItem(IDC_INTERVAL_TIME) -> EnableWindow(FALSE);
1065                 GetDlgItem(IDC_REPEAT_COUNT) -> EnableWindow(FALSE);
1066                 GetDlgItem(IDC_EVENT_SCORE) -> EnableWindow(FALSE);
1067                 GetDlgItem(IDC_CHAINED) -> EnableWindow(FALSE);
1068                 GetDlgItem(IDC_CHAIN_DELAY) -> EnableWindow(FALSE);
1069                 GetDlgItem(IDC_OBJ_TEXT) -> EnableWindow(FALSE);
1070                 GetDlgItem(IDC_OBJ_KEY_TEXT) -> EnableWindow(FALSE);
1071                 GetDlgItem(IDC_EVENT_TEAM)->EnableWindow(FALSE);
1072                 return;
1073         }
1074
1075         m_team = m_events[cur_event].team;
1076
1077         m_repeat_count = m_events[cur_event].repeat_count;
1078         m_interval = m_events[cur_event].interval;
1079         m_event_score = m_events[cur_event].score;
1080         if (m_events[cur_event].chain_delay >= 0) {
1081                 m_chained = TRUE;
1082                 m_chain_delay = m_events[cur_event].chain_delay;
1083                 GetDlgItem(IDC_CHAIN_DELAY) -> EnableWindow(TRUE);
1084
1085         } else {
1086                 m_chained = FALSE;
1087                 m_chain_delay = 0;
1088                 GetDlgItem(IDC_CHAIN_DELAY) -> EnableWindow(FALSE);
1089         }
1090
1091         if (m_events[cur_event].objective_text){
1092                 m_obj_text = m_events[cur_event].objective_text;
1093         } else {
1094                 m_obj_text.Empty();
1095         }
1096
1097         if (m_events[cur_event].objective_key_text){
1098                 m_obj_key_text = m_events[cur_event].objective_key_text;
1099         } else {
1100                 m_obj_key_text.Empty();
1101         }
1102
1103         GetDlgItem(IDC_REPEAT_COUNT)->EnableWindow(TRUE);
1104         if ( m_repeat_count <= 1 ) {
1105                 m_interval = 1;
1106                 GetDlgItem(IDC_INTERVAL_TIME) -> EnableWindow(FALSE);
1107         } else {
1108                 GetDlgItem(IDC_INTERVAL_TIME) -> EnableWindow(TRUE);
1109         }
1110
1111         GetDlgItem(IDC_EVENT_SCORE) -> EnableWindow(TRUE);
1112         GetDlgItem(IDC_CHAINED) -> EnableWindow(TRUE);
1113         GetDlgItem(IDC_OBJ_TEXT) -> EnableWindow(TRUE);
1114         GetDlgItem(IDC_OBJ_KEY_TEXT) -> EnableWindow(TRUE);
1115         GetDlgItem(IDC_EVENT_TEAM)->EnableWindow(FALSE);
1116         if ( The_mission.game_type & MISSION_TYPE_MULTI_TEAMS ){
1117                 GetDlgItem(IDC_EVENT_TEAM)->EnableWindow(TRUE);
1118         }
1119         UpdateData(FALSE);
1120 }
1121
1122 void event_editor::OnUpdateRepeatCount()
1123 {
1124         char buf[128];
1125         int count;
1126
1127         count = 128;
1128         GetDlgItem(IDC_REPEAT_COUNT)->GetWindowText(buf, count);
1129         m_repeat_count = atoi(buf);
1130
1131         if ( m_repeat_count <= 1 ){
1132                 GetDlgItem(IDC_INTERVAL_TIME)->EnableWindow(FALSE);
1133         } else {
1134                 GetDlgItem(IDC_INTERVAL_TIME)->EnableWindow(TRUE);
1135         }
1136 }
1137
1138 void event_editor::swap_handler(int node1, int node2)
1139 {
1140         int index1, index2;
1141         mission_event m;
1142
1143         save();
1144         for (index1=0; index1<m_num_events; index1++){
1145                 if (m_events[index1].formula == node1){
1146                         break;
1147                 }
1148         }
1149
1150         Assert(index1 < m_num_events);
1151         for (index2=0; index2<m_num_events; index2++){
1152                 if (m_events[index2].formula == node2){
1153                         break;
1154                 }
1155         }
1156
1157         Assert(index2 < m_num_events);
1158         m = m_events[index1];
1159 //      m_events[index1] = m_events[index2];
1160         while (index1 < index2) {
1161                 m_events[index1] = m_events[index1 + 1];
1162                 m_sig[index1] = m_sig[index1 + 1];
1163                 index1++;
1164         }
1165
1166         while (index1 > index2 + 1) {
1167                 m_events[index1] = m_events[index1 - 1];
1168                 m_sig[index1] = m_sig[index1 - 1];
1169                 index1--;
1170         }
1171
1172         m_events[index1] = m;
1173         cur_event = index1;
1174         update_cur_event();
1175 }
1176
1177 void event_editor::OnChained() 
1178 {
1179         int image;
1180         HTREEITEM h;
1181
1182         UpdateData(TRUE);
1183         if (m_chained) {
1184                 GetDlgItem(IDC_CHAIN_DELAY) -> EnableWindow(TRUE);
1185                 if (m_obj_text.IsEmpty()) {
1186                         image = BITMAP_CHAIN;
1187                 } else {
1188                         image = BITMAP_CHAIN_DIRECTIVE;
1189                 }
1190         } else {
1191                 GetDlgItem(IDC_CHAIN_DELAY) -> EnableWindow(FALSE);
1192                 if (m_obj_text.IsEmpty()) {
1193                         image = BITMAP_ROOT;
1194                 } else {
1195                         image = BITMAP_ROOT_DIRECTIVE;
1196                 }
1197         }
1198
1199         h = m_event_tree.GetRootItem();
1200         while (h) {
1201                 if ((int) m_event_tree.GetItemData(h) == m_events[cur_event].formula) {
1202                         m_event_tree.SetItemImage(h, image, image);
1203                         return;
1204                 }
1205
1206                 h = m_event_tree.GetNextSiblingItem(h);
1207         }
1208 }
1209
1210 void event_editor::OnSelchangeMessageList() 
1211 {       
1212         static flag = 0;
1213
1214         if (flag)
1215                 return;
1216 /*
1217         if (save_message(m_cur_msg)) {
1218                 flag = 1;
1219                 ((CListBox *) GetDlgItem(IDC_MESSAGE_LIST)) -> SetCurSel(old);
1220                 m_cur_msg = old;
1221                 flag = 0;
1222                 return;
1223         }*/
1224
1225         save();
1226         update_cur_message();
1227 }
1228
1229 int event_editor::save_message(int num)
1230 {
1231         char *ptr;
1232         int i, conflict = 0;
1233         CListBox *list;
1234
1235         UpdateData(TRUE);
1236         if (num >= 0) {
1237                 ptr = (char *) (LPCTSTR) m_message_name;
1238                 for (i=0; i<Num_builtin_messages; i++){
1239                         if (!stricmp(m_message_name, Messages[i].name)) {
1240                                 conflict = 1;
1241                                 break;
1242                         }
1243                 }
1244
1245                 for (i=0; i<m_num_messages; i++){
1246                         if ((i != num) && (!stricmp(m_message_name, m_messages[i].name))) {
1247                                 conflict = 1;
1248                                 break;
1249                         }
1250                 }
1251
1252                 if (!conflict) {  // update name if no conflicts, otherwise keep old name
1253                         string_copy(m_messages[num].name, m_message_name, NAME_LENGTH - 1);
1254
1255                         list = (CListBox *) GetDlgItem(IDC_MESSAGE_LIST);
1256                         list->DeleteString(num);
1257                         list->InsertString(num, m_message_name);
1258                 }
1259
1260                 string_copy(m_messages[num].message, m_message_text, MESSAGE_LENGTH - 1);
1261                 if (m_messages[num].avi_info.name){
1262                         free(m_messages[num].avi_info.name);
1263                 }
1264
1265                 ptr = (char *) (LPCTSTR) m_avi_filename;
1266                 if (!ptr || !strlen(ptr) || !stricmp(ptr, "none") || !stricmp(ptr, "<none>")){
1267                         m_messages[num].avi_info.name = NULL;
1268                 } else {
1269                         m_messages[num].avi_info.name = strdup(ptr);
1270                 }
1271
1272                 if (m_messages[num].wave_info.name){
1273                         free(m_messages[num].wave_info.name);
1274                 }
1275
1276                 ptr = (char *) (LPCTSTR) m_wave_filename;
1277                 if (!ptr || !strlen(ptr) || !stricmp(ptr, "none") || !stricmp(ptr, "<none>")){
1278                         m_messages[num].wave_info.name = NULL;
1279                 } else {
1280                         m_messages[num].wave_info.name = strdup(ptr);
1281                 }
1282
1283                 // update the persona to the message.  We subtract 1 for the "None" at the beginning of the combo
1284                 // box list.
1285                 m_messages[num].persona_index = m_persona - 1;
1286
1287                 if(m_message_team >= 2){
1288                         m_messages[num].multi_team = -1;
1289                         m_message_team = -1;
1290                 } else {
1291                         m_messages[num].multi_team = m_message_team;
1292                 }
1293
1294                 // possible TODO: auto-update event tree references to this message if we renamed it.
1295         }
1296
1297         return 0;
1298 }
1299
1300 void event_editor::OnNewMsg() 
1301 {
1302 //      if (save_message(m_cur_msg))
1303 //              return;
1304
1305         save();
1306         Assert(m_num_messages + Num_builtin_messages < MAX_MISSION_MESSAGES);
1307         strcpy(m_messages[m_num_messages].name, "<new message>");
1308         ((CListBox *) GetDlgItem(IDC_MESSAGE_LIST))->AddString("<new message>");
1309
1310         strcpy(m_messages[m_num_messages].message, "<put description here>");
1311         m_messages[m_num_messages].avi_info.name = NULL;
1312         m_messages[m_num_messages].wave_info.name = NULL;
1313         m_messages[m_num_messages].persona_index = -1;
1314         m_messages[m_num_messages].multi_team = -1;
1315         m_cur_msg = m_num_messages++;
1316         if (m_num_messages + Num_builtin_messages >= MAX_MISSION_MESSAGES){
1317                 GetDlgItem(IDC_NEW_MSG)->EnableWindow(FALSE);
1318         }
1319
1320         modified = 1;
1321         update_cur_message();
1322 }
1323
1324 void event_editor::OnDeleteMsg() 
1325 {
1326         char buf[256];
1327         int i;
1328
1329         // handle this case somewhat gracefully
1330         Assert((m_cur_msg >= 0) && (m_cur_msg < m_num_messages));
1331         if((m_cur_msg < 0) || (m_cur_msg >= m_num_messages)){
1332                 return;
1333         }
1334         
1335         if (m_messages[m_cur_msg].avi_info.name){
1336                 free(m_messages[m_cur_msg].avi_info.name);
1337         }
1338         if (m_messages[m_cur_msg].wave_info.name){
1339                 free(m_messages[m_cur_msg].wave_info.name);
1340         }
1341
1342         ((CListBox *) GetDlgItem(IDC_MESSAGE_LIST))->DeleteString(m_cur_msg);
1343         sprintf(buf, "<%s>", m_messages[m_cur_msg].name);
1344         update_sexp_references(m_messages[m_cur_msg].name, buf, OPF_MESSAGE);
1345
1346         for (i=m_cur_msg; i<m_num_messages-1; i++){
1347                 m_messages[i] = m_messages[i + 1];
1348         }
1349
1350         m_num_messages--;
1351         if (m_cur_msg >= m_num_messages){
1352                 m_cur_msg = m_num_messages - 1;
1353         }
1354
1355         GetDlgItem(IDC_NEW_MSG)->EnableWindow(TRUE);
1356         modified = 1;
1357         update_cur_message();
1358 }
1359
1360 void event_editor::OnBrowseAvi() 
1361 {
1362         int z;
1363         CString name;   
1364
1365         UpdateData(TRUE);
1366         if (!stricmp(m_avi_filename, "<None>"))
1367                 m_avi_filename = _T("");
1368
1369         z = cfile_push_chdir(CF_TYPE_INTERFACE);
1370         CFileDialog dlg(TRUE, "ani", m_avi_filename, OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR,
1371                 "Ani Files (*.ani)|*.ani|Avi Files (*.avi)|*.avi|Both (*.ani, *.avi)|*.ani;*.avi||");
1372
1373         if (dlg.DoModal() == IDOK) {
1374                 m_avi_filename = dlg.GetFileName();
1375                 UpdateData(FALSE);
1376                 modified = 1;
1377         }
1378
1379         if (!z)
1380                 cfile_pop_dir();
1381 }
1382
1383 void event_editor::OnBrowseWave() 
1384 {
1385         int z;
1386         CString name;
1387
1388         UpdateData(TRUE);
1389         if (!stricmp(m_wave_filename, "<None>"))
1390                 m_wave_filename = _T("");
1391
1392         if (The_mission.game_type & MISSION_TYPE_TRAINING)
1393                 z = cfile_push_chdir(CF_TYPE_VOICE_TRAINING);
1394         else
1395                 z = cfile_push_chdir(CF_TYPE_VOICE_SPECIAL);
1396
1397         CFileDialog dlg(TRUE, "wav", m_wave_filename, OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR,
1398                 "Wave Files (*.wav)|*.wav||");
1399
1400         if (dlg.DoModal() == IDOK) {
1401                 m_wave_filename = dlg.GetFileName();
1402                 update_persona();
1403         }
1404
1405         if (!z){
1406                 cfile_pop_dir();
1407         }
1408 }
1409
1410 char *event_editor::current_message_name(int i)
1411 {
1412         if ( (i < 0) || (i >= m_num_messages) ){
1413                 return NULL;
1414         }
1415
1416         return m_messages[i].name;
1417 }
1418
1419 char *event_editor::get_message_list_item(int i)
1420 {
1421         return m_messages[i].name;
1422 }
1423
1424 void event_editor::update_persona()
1425 {
1426         int i, mask;
1427
1428         if ((m_wave_filename[0] >= '1') && (m_wave_filename[0] <= '9') && (m_wave_filename[1] == '_') ) {
1429                 i = m_wave_filename[0] - '1';
1430                 if ( (i < Num_personas) && (Personas[i].flags & PERSONA_FLAG_WINGMAN) ) {
1431                         m_persona = i + 1;
1432                         if ((m_persona==1) || (m_persona==2)) 
1433                                 m_avi_filename = "HEAD-TP1";
1434                         else if ((m_persona==3) || (m_persona==4))
1435                                 m_avi_filename = "HEAD-TP2";
1436                         else if ((m_persona==5))
1437                                 m_avi_filename = "HEAD-TP3";
1438                         else if ((m_persona==6))
1439                                 m_avi_filename = "HEAD-VP1";
1440                 }
1441         } else {
1442                 mask = 0;
1443                 if (!strnicmp(m_wave_filename, "S_", 2)) {
1444                         mask = PERSONA_FLAG_SUPPORT;
1445                         m_avi_filename = "HEAD-CM1";
1446                 }
1447                 else if (!strnicmp(m_wave_filename, "L_", 2)) {
1448                         mask = PERSONA_FLAG_LARGE;
1449                         m_avi_filename = "HEAD-CM1";
1450                 }
1451                 else if (!strnicmp(m_wave_filename, "TC_", 3)) {
1452                         mask = PERSONA_FLAG_COMMAND;
1453                         m_avi_filename = "HEAD-CM1";
1454                 }
1455
1456                 for (i=0; i<Num_personas; i++)
1457                         if (Personas[i].flags & mask)
1458                                 m_persona = i + 1;
1459         }
1460         //GetDlgItem(IDC_ANI_FILENAME)->SetWindowText(m_avi_filename);
1461         UpdateData(FALSE);
1462         modified = 1;
1463 }
1464
1465 void event_editor::OnSelchangeWaveFilename() 
1466 {
1467         int z;
1468         CComboBox *box;
1469
1470         box = (CComboBox *) GetDlgItem(IDC_WAVE_FILENAME);
1471         z = box -> GetCurSel();
1472         UpdateData(TRUE);
1473         UpdateData(TRUE);
1474
1475         box -> GetLBText(z, m_wave_filename);
1476         UpdateData(FALSE);
1477         update_persona();
1478 }
1479
1480 BOOL event_editor::DestroyWindow() 
1481 {
1482         m_play_bm.DeleteObject();
1483         return CDialog::DestroyWindow();
1484 }
1485
1486 void event_editor::OnPlay() 
1487 {
1488         char path[MAX_PATH_LEN + 1];
1489         GetDlgItem(IDC_WAVE_FILENAME)->GetWindowText(m_wave_filename);
1490
1491         int size, offset;
1492         cf_find_file_location((char *)(LPCSTR)m_wave_filename, CF_TYPE_ANY, path, &size, &offset );
1493
1494         PlaySound(path, NULL, SND_ASYNC | SND_FILENAME);
1495 }
1496
1497 void event_editor::OnUpdate() 
1498 {
1499 //      GetDlgItem(IDC_WAVE_FILENAME)->GetWindowText(m_wave_filename);
1500         UpdateData(TRUE);
1501         update_persona();
1502 }
1503
1504 // code when the "team" selection in the combo box changes
1505 void event_editor::OnSelchangeTeam() 
1506 {
1507         if ( cur_event < 0 ){
1508                 return;
1509         }
1510
1511         UpdateData(TRUE);
1512
1513         // team == 2, means no team
1514         if(m_team == 2){
1515                 m_team = -1;
1516         }
1517
1518         m_events[cur_event].team = m_team;
1519 }
1520
1521 // code when the "team" selection in the combo box changes
1522 void event_editor::OnSelchangeMessageTeam() 
1523 {
1524         if ( m_cur_msg < 0 ){
1525                 return;
1526         }
1527
1528         UpdateData(TRUE);
1529
1530         // team == 2, means no team
1531         if(m_message_team == 2){
1532                 m_message_team = -1;
1533         }
1534
1535         m_messages[m_cur_msg].multi_team = m_message_team;
1536 }
1537
1538 // Cycles among sexp nodes with message text
1539 void event_editor::OnDblclkMessageList() 
1540 {
1541         CListBox *list = (CListBox*) GetDlgItem(IDC_MESSAGE_LIST);
1542         int num_messages;
1543         int message_nodes[MAX_SEARCH_MESSAGE_DEPTH];
1544
1545         // get current message index and message name
1546         int cur_index = list->GetCurSel();
1547
1548         // check if message name is in event tree
1549         char buffer[256];
1550         list->GetText(cur_index, buffer);
1551
1552
1553         num_messages = m_event_tree.find_text(buffer, message_nodes);
1554
1555         if (num_messages == 0) {
1556                 char message[256];
1557                 sprintf(message, "No events using message '%s'", buffer);
1558                 MessageBox(message);
1559         } else {
1560                 // find last message_node
1561                 if (m_last_message_node == -1) {
1562                         m_last_message_node = message_nodes[0];
1563                 } else {
1564
1565                         if (num_messages == 1) {
1566                                 // only 1 message
1567                                 m_last_message_node = message_nodes[0];
1568                         } else {
1569                                 // find which message and go to next message
1570                                 int found_pos = -1;
1571                                 for (int i=0; i<num_messages; i++) {
1572                                         if (message_nodes[i] == m_last_message_node) {
1573                                                 found_pos = i;
1574                                                 break;
1575                                         }
1576                                 }
1577
1578                                 if (found_pos == -1) {
1579                                         // no previous message
1580                                         m_last_message_node = message_nodes[0];
1581                                 } else if (found_pos == num_messages-1) {
1582                                         // cycle back to start
1583                                         m_last_message_node = message_nodes[0];
1584                                 } else {
1585                                         // go to next
1586                                         m_last_message_node = message_nodes[found_pos+1];
1587                                 }
1588                         }
1589                 }
1590
1591                 // highlight next
1592                 m_event_tree.hilite_item(m_last_message_node);
1593         }
1594 }
1595