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