// delete a whole wing, also deleting its ships if necessary.
int delete_wing(int wing_num, int bypass)
{
	int i, r, total;

	if (already_deleting_wing)
		return 0;

	r = check_wing_dependencies(wing_num);
	if (r)
		return r;

	already_deleting_wing = 1;
	for (i=0; i<Num_reinforcements; i++)
		if (!stricmp(Wings[wing_num].name, Reinforcements[i].name)) {
			delete_reinforcement(i);
			break;
		}

	invalidate_references(Wings[wing_num].name, REF_TYPE_WING);
	if (!bypass) {
		total = Wings[wing_num].wave_count;
		for (i=0; i<total; i++)
			delete_object(wing_objects[wing_num][i]);
	}

	Wings[wing_num].wave_count = 0;
	Wings[wing_num].wing_squad_filename[0] = '\0';
	Wings[wing_num].wing_insignia_texture = -1;

	if (cur_wing == wing_num)
		set_cur_wing(cur_wing = -1);  // yes, one '=' is correct.

	free_sexp2(Wings[wing_num].arrival_cue);
	free_sexp2(Wings[wing_num].departure_cue);

	Num_wings--;
	set_modified();

	update_custom_wing_indexes();

	already_deleting_wing = 0;
	return 0;
}
void campaign_tree_view::free_links()
{
	int i;

	for (i=0; i<Total_links; i++) {
		sexp_unmark_persistent(Links[i].sexp);
		free_sexp2(Links[i].sexp);
	}

	Total_links = 0;
}
// delete a whole wing, leaving ships intact but wingless.
void remove_wing(int wing_num)
{
	int i, total;
	object *ptr;

	if (check_wing_dependencies(wing_num))
		return;

	Ship_editor_dialog.bypass_errors = Wing_editor_dialog.bypass_errors = 1;
	Ship_editor_dialog.update_data(0);
	total = Wings[wing_num].wave_count;
	for (i=0; i<total; i++) {
		ptr = &Objects[wing_objects[wing_num][i]];
		if (ptr->type == OBJ_SHIP)
			remove_ship_from_wing(ptr->instance, 0);
		else if (ptr->type == OBJ_START)
			remove_player_from_wing(ptr->instance, 0);
	}

	Assert(!Wings[wing_num].wave_count);

	Wings[wing_num].wave_count = 0;
	Wings[wing_num].wing_squad_filename[0] = '\0';
	Wings[wing_num].wing_insignia_texture = -1;

	Ship_editor_dialog.initialize_data(1);
	Ship_editor_dialog.bypass_errors = Wing_editor_dialog.bypass_errors = 0;

	if (cur_wing == wing_num) {
		set_cur_wing(cur_wing = -1);  // yes, one '=' is correct.
	}

	free_sexp2(Wings[wing_num].arrival_cue);
	free_sexp2(Wings[wing_num].departure_cue);

	Num_wings--;

	update_custom_wing_indexes();

	set_modified();
}
void CMissionGoalsDlg::OnOk()
{
	char buf[256], names[2][MAX_GOALS][NAME_LENGTH];
	int i, count;

	for (i=0; i<Num_goals; i++)
		free_sexp2(Mission_goals[i].formula);

	UpdateData(TRUE);
	if (query_modified())
		set_modified();

	count = 0;
	for (i=0; i<Num_goals; i++)
		Mission_goals[i].satisfied = 0;  // use this as a processed flag
	
	// rename all sexp references to old events
	for (i=0; i<m_num_goals; i++)
		if (m_sig[i] >= 0) {
			strcpy(names[0][count], Mission_goals[m_sig[i]].name);
			strcpy(names[1][count], m_goals[i].name);
			count++;
			Mission_goals[m_sig[i]].satisfied = 1;
		}

	// invalidate all sexp references to deleted events.
	for (i=0; i<Num_goals; i++)
		if (!Mission_goals[i].satisfied) {
			sprintf(buf, "<%s>", Mission_goals[i].name);
			strcpy(buf + NAME_LENGTH - 2, ">");  // force it to be not too long
			strcpy(names[0][count], Mission_goals[i].name);
			strcpy(names[1][count], buf);
			count++;
		}

	Num_goals = m_num_goals;
	for (i=0; i<Num_goals; i++) {
		Mission_goals[i] = m_goals[i];
		Mission_goals[i].formula = m_goals_tree.save_tree(Mission_goals[i].formula);
		if ( The_mission.game_type & MISSION_TYPE_MULTI_TEAMS ) {
			Assert( Mission_goals[i].team != -1 );
		}
	}

	// now update all sexp references
	while (count--)
		update_sexp_references(names[0][count], names[1][count], OPF_GOAL_NAME);

	theApp.record_window_data(&Mission_goals_wnd_data, this);
	CDialog::OnOK();
}
bool set_cue_to_false(int *cue)
{
	// if the cue is not false, make it false.  Be sure to set all ship editor dialog functions
	// to update data before and after we modify the cue.
	if (*cue != Locked_sexp_false)
	{
		Ship_editor_dialog.update_data(1);
		Wing_editor_dialog.update_data(1);

		free_sexp2(*cue);
		*cue = Locked_sexp_false;

		Ship_editor_dialog.initialize_data(1);
		Wing_editor_dialog.initialize_data(1);

		return true;
	}
	else
		return false;
}
void campaign_tree_view::delete_link(int num)
{
	Assert((num >= 0) && (num < Total_links));
	if (Links[num].from != Links[num].to) {
		Elements[Links[num].from].from_links--;
		Elements[Links[num].to].to_links--;
	}

	sexp_unmark_persistent(Links[num].sexp);
	free_sexp2(Links[num].sexp);
	while (num < Total_links - 1) {
		Links[num] = Links[num + 1];
		num++;
	}

	Total_links--;
	sort_links();
	Invalidate();
	Campaign_modified = 1;
	return;
}
void campaign_editor::save_tree(int clear)
{
	int i;

	if (m_last_mission < 0){
		return;  // nothing to save
	}

	for (i=0; i<Total_links; i++){
		if (Links[i].from == m_last_mission) {
			sexp_unmark_persistent(Links[i].sexp);
			free_sexp2(Links[i].sexp);
			Links[i].sexp = m_tree.save_tree(Links[i].node);
			sexp_mark_persistent(Links[i].sexp);
		}
	}

	if (clear){
		m_last_mission = -1;
	}
}
void event_editor::OnOk()
{
	char buf[256], names[2][MAX_MISSION_EVENTS][NAME_LENGTH];
	int i, count;

	audiostream_close_file(m_wave_id, 0);
	m_wave_id = -1;

	save();
	if (query_modified())
		set_modified();

	for (i=0; i<Num_mission_events; i++) {
		free_sexp2(Mission_events[i].formula);
		if (Mission_events[i].objective_text)
			free(Mission_events[i].objective_text);
		if (Mission_events[i].objective_key_text)
			free(Mission_events[i].objective_key_text);
	}

	count = 0;
	for (i=0; i<Num_mission_events; i++)
		Mission_events[i].result = 0;  // use this as a processed flag
	
	// rename all sexp references to old events
	for (i=0; i<m_num_events; i++)
		if (m_sig[i] >= 0) {
			strcpy_s(names[0][count], Mission_events[m_sig[i]].name);
			strcpy_s(names[1][count], m_events[i].name);
			count++;
			Mission_events[m_sig[i]].result = 1;
		}

	// invalidate all sexp references to deleted events.
	for (i=0; i<Num_mission_events; i++)
		if (!Mission_events[i].result) {
			sprintf(buf, "<%s>", Mission_events[i].name);
			strcpy(buf + NAME_LENGTH - 2, ">");  // force it to be not too long
			strcpy_s(names[0][count], Mission_events[i].name);
			strcpy_s(names[1][count], buf);
			count++;
		}

	Num_mission_events = m_num_events;
	for (i=0; i<m_num_events; i++) {
		Mission_events[i] = m_events[i];
		Mission_events[i].formula = m_event_tree.save_tree(m_events[i].formula);
		Mission_events[i].objective_text = m_events[i].objective_text;
		Mission_events[i].objective_key_text = m_events[i].objective_key_text;
		Mission_events[i].mission_log_flags = m_events[i].mission_log_flags;
	}

	// now update all sexp references
	while (count--)
		update_sexp_references(names[0][count], names[1][count], OPF_EVENT_NAME);

	for (i=Num_builtin_messages; i<Num_messages; i++) {
		if (Messages[i].avi_info.name)
			free(Messages[i].avi_info.name);

		if (Messages[i].wave_info.name)
			free(Messages[i].wave_info.name);
	}

	Num_messages = m_num_messages + Num_builtin_messages;
	for (i=0; i<m_num_messages; i++)
		Messages[i + Num_builtin_messages] = m_messages[i];

	theApp.record_window_data(&Events_wnd_data, this);
	delete Event_editor_dlg;
	Event_editor_dlg = NULL;
}
// update parts of wing that can't fail.  This is useful if for when you need to change
// something in a wing that this updates elsewhere in Fred.  Normally when auto-update
// kicks in, the changes you make will be wiped out by the auto=update, so instead you
// would call this function to update the wing, make your changes, and then call the
// initialize_data_safe() function to show your changes in the dialog
void wing_editor::update_data_safe()
{
	char buf[512];
	int i, d, hotkey = -1;

	nprintf(("Fred routing", "Wing dialog save safe\n"));
	if (!GetSafeHwnd())
		return;

	UpdateData(TRUE);
	UpdateData(TRUE);

	if (cur_wing < 0)
		return;

	if (m_threshold >= Wings[cur_wing].wave_count) {
		m_threshold = Wings[cur_wing].wave_count - 1;
		if (!bypass_errors)
			sprintf(buf, "Wave threshold is set too high.  Value has been lowered to %d", (int) m_threshold);

		MessageBox(buf);
	}

	if (m_threshold + Wings[cur_wing].wave_count > MAX_SHIPS_PER_WING) {
		m_threshold = MAX_SHIPS_PER_WING - Wings[cur_wing].wave_count;
		if (!bypass_errors)
			sprintf(buf, "Wave threshold is set too high.  Value has been lowered to %d", (int) m_threshold);

		MessageBox(buf);
	}

	if (m_waves < 1) {
		m_waves = 1;
		if (!bypass_errors)
			sprintf(buf, "Number of waves illegal.  Has been set to 1.", (int) m_waves);

		MessageBox(buf);
	}

	MODIFY(Wings[cur_wing].special_ship, m_special_ship);
	MODIFY(Wings[cur_wing].num_waves, m_waves);
	MODIFY(Wings[cur_wing].threshold, m_threshold);
	MODIFY(Wings[cur_wing].arrival_location, m_arrival_location);
	MODIFY(Wings[cur_wing].departure_location, m_departure_location);
	MODIFY(Wings[cur_wing].arrival_delay, m_arrival_delay);
	if (m_arrival_delay_min > m_arrival_delay_max) {
		if (!bypass_errors)
			sprintf(buf, "Arrival delay minimum greater than maximum.  Value lowered to %d", m_arrival_delay_max);

		MessageBox(buf);
		m_arrival_delay_min = m_arrival_delay_max;
	}

	MODIFY(Wings[cur_wing].wave_delay_min, m_arrival_delay_min);
	MODIFY(Wings[cur_wing].wave_delay_max, m_arrival_delay_max);
	MODIFY(Wings[cur_wing].arrival_distance, m_arrival_dist);
	if (m_arrival_target >= 0) {
		i = ((CComboBox *) GetDlgItem(IDC_ARRIVAL_TARGET)) -> GetItemData(m_arrival_target);
		MODIFY(Wings[cur_wing].arrival_anchor, i);

		// when arriving near or in front of a ship, be sure that we are far enough away from it!!!
		if (((m_arrival_location != ARRIVE_AT_LOCATION) && (m_arrival_location != ARRIVE_FROM_DOCK_BAY)) && (i >= 0) && (i < SPECIAL_ARRIVAL_ANCHORS_OFFSET)) {
			d = int(min(500, 2.0f * Objects[Ships[i].objnum].radius));
			if ((Wings[cur_wing].arrival_distance < d) && (Wings[cur_wing].arrival_distance > -d)) {
				if (!bypass_errors)
					sprintf(buf, "Ship must arrive at least %d meters away from target.\n"
						"Value has been reset to this.  Use with caution!\r\n"
						"Reccomended distance is %d meters.\r\n", d, (int)(2.0f * Objects[Ships[i].objnum].radius) );

				MessageBox(buf);
				if (Wings[cur_wing].arrival_distance < 0)
					Wings[cur_wing].arrival_distance = -d;
				else
					Wings[cur_wing].arrival_distance = d;

				m_arrival_dist = Wings[cur_wing].arrival_distance;
			}
		}
	}

	i = ((CComboBox*)GetDlgItem(IDC_DEPARTURE_TARGET))->GetItemData(m_departure_target);
	
	if (m_departure_location == DEPART_AT_DOCK_BAY) 
		MODIFY(Wings[cur_wing].departure_anchor,  i);
	else
		MODIFY(Wings[cur_wing].jump_anchor, m_departure_target);

	MODIFY(Wings[cur_wing].departure_delay, m_departure_delay);
	hotkey = m_hotkey - 1;
	MODIFY(Wings[cur_wing].hotkey, hotkey);
	if ( m_ignore_count ) {
		if ( !(Wings[cur_wing].flags & WF_IGNORE_COUNT) )
			set_modified();
		Wings[cur_wing].flags |= WF_IGNORE_COUNT;

	} else {
		if ( Wings[cur_wing].flags & WF_IGNORE_COUNT )
			set_modified();
		Wings[cur_wing].flags &= ~WF_IGNORE_COUNT;
	}

	if ( m_no_arrival_music ) {
		if ( !(Wings[cur_wing].flags & WF_NO_ARRIVAL_MUSIC) )
			set_modified();
		Wings[cur_wing].flags |= WF_NO_ARRIVAL_MUSIC;

	} else {
		if ( Wings[cur_wing].flags & WF_NO_ARRIVAL_MUSIC )
			set_modified();
		Wings[cur_wing].flags &= ~WF_NO_ARRIVAL_MUSIC;
	}

	// check the no message flag
	if ( m_no_arrival_message ) {
		if ( !(Wings[cur_wing].flags & WF_NO_ARRIVAL_MESSAGE) )
			set_modified();
		Wings[cur_wing].flags |= WF_NO_ARRIVAL_MESSAGE;

	} else {
		if ( Wings[cur_wing].flags & WF_NO_ARRIVAL_MESSAGE )
			set_modified();
		Wings[cur_wing].flags &= ~WF_NO_ARRIVAL_MESSAGE;
	}

	// set the no warp effect for wings flag
	if ( m_no_arrival_warp ) {
		if ( !(Wings[cur_wing].flags & WF_NO_ARRIVAL_WARP) )
			set_modified();
		Wings[cur_wing].flags |= WF_NO_ARRIVAL_WARP;
	} else {
		if ( Wings[cur_wing].flags & WF_NO_ARRIVAL_WARP )
			set_modified();
		Wings[cur_wing].flags &= ~WF_NO_ARRIVAL_WARP;
	}
	// set the no warp effect for wings flag
	if ( m_no_departure_warp ) {
		if ( !(Wings[cur_wing].flags & WF_NO_DEPARTURE_WARP) )
			set_modified();
		Wings[cur_wing].flags |= WF_NO_DEPARTURE_WARP;
	} else {
		if ( Wings[cur_wing].flags & WF_NO_DEPARTURE_WARP )
			set_modified();
		Wings[cur_wing].flags &= ~WF_NO_DEPARTURE_WARP;
	}

	if ( m_no_dynamic ) {
		if ( !(Wings[cur_wing].flags & WF_NO_DYNAMIC) )
			set_modified();
		Wings[cur_wing].flags |= WF_NO_DYNAMIC;
	} else {
		if ( Wings[cur_wing].flags & WF_NO_DYNAMIC )
			set_modified();
		Wings[cur_wing].flags &= ~WF_NO_DYNAMIC;
	}

	if (Wings[cur_wing].arrival_cue >= 0)
		free_sexp2(Wings[cur_wing].arrival_cue);
	Wings[cur_wing].arrival_cue = m_arrival_tree.save_tree();

	if (Wings[cur_wing].departure_cue >= 0)
		free_sexp2(Wings[cur_wing].departure_cue);
	Wings[cur_wing].departure_cue = m_departure_tree.save_tree();

	// copy squad stuff
	if(stricmp(m_wing_squad_filename, Wings[cur_wing].wing_squad_filename))
	{
		string_copy(Wings[cur_wing].wing_squad_filename, m_wing_squad_filename, MAX_FILENAME_LEN);
		set_modified();
	}

	if (modified)
		set_modified();
}
// update wing structure(s) with dialog data.  The data is first checked for errors.  If
// no errors occur, returns 0.  If an error occurs, returns -1.  If the update is bypassed,
// returns 1.  Bypass is necessary to avoid an infinite loop, and it doesn't actually
// update the data.  Bypass only occurs if bypass mode is active and we still get an error.
// Once the error no longer occurs, bypass mode is cleared and data is updated.
int wing_editor::update_data(int redraw)
{
	char *str, old_name[255], buf[512];
	int i, z;
	object *ptr;

	nprintf(("Fred routing", "Wing dialog save\n"));
	if (!GetSafeHwnd())
		return 0;

	UpdateData(TRUE);
	UpdateData(TRUE);

	if (cur_wing >= 0) {
		if (!strnicmp(m_wing_name, "player ", 7)) {
			if (bypass_errors)
				return 1;

			bypass_errors = 1;
			z = MessageBox("Wing names can't start with the word 'player'\n"
				"Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);

			if (z == IDCANCEL)
				return -1;

			m_wing_name = _T(Wings[cur_wing].name);
			UpdateData(FALSE);
		}

		for (i=0; i<MAX_WINGS; i++)
			if (Wings[i].wave_count && !stricmp(Wings[i].name, m_wing_name) && (i != cur_wing)) {
				if (bypass_errors)
					return 1;

				bypass_errors = 1;
				z = MessageBox("This wing name is already being used by another wing\n"
					"Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);

				if (z == IDCANCEL)
					return -1;

				m_wing_name = _T(Wings[cur_wing].name);
				UpdateData(FALSE);
			}

		ptr = GET_FIRST(&obj_used_list);
		while (ptr != END_OF_LIST(&obj_used_list)) {
			if (ptr->type == OBJ_SHIP) {
				if (!stricmp(m_wing_name, Ships[ptr->instance].ship_name)) {
					if (bypass_errors)
						return 1;

					bypass_errors = 1;
					z = MessageBox("This wing name is already being used by a ship\n"
						"Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);

					if (z == IDCANCEL)
						return -1;

					m_wing_name = _T(Wings[cur_wing].name);
					UpdateData(FALSE);
				}
			}

			ptr = GET_NEXT(ptr);
		}

		for (i=0; i<MAX_WAYPOINT_LISTS; i++)
			if (Waypoint_lists[i].count && !stricmp(Waypoint_lists[i].name, m_wing_name)) {
				if (bypass_errors)
					return 1;

				bypass_errors = 1;
				z = MessageBox("This wing name is already being used by a waypoint path\n"
					"Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);

				if (z == IDCANCEL)
					return -1;

				m_wing_name = _T(Wings[cur_wing].name);
				UpdateData(FALSE);
			}

		for (i=0; i<Num_jump_nodes; i++)
			if (!stricmp(Jump_nodes[i].name, m_wing_name)) {
				if (bypass_errors)
					return 1;
 
				bypass_errors = 1;
				z = MessageBox("This wing name is already being used by a hyper buoy\n"
					"Press OK to restore old name", "Error", MB_ICONEXCLAMATION | MB_OKCANCEL);

				if (z == IDCANCEL)
					return -1;

				m_wing_name = _T(Wings[cur_wing].name);
				UpdateData(FALSE);
			}

		strcpy(old_name, Wings[cur_wing].name);
		string_copy(Wings[cur_wing].name, m_wing_name, NAME_LENGTH, 1);
		update_data_safe();

		bypass_errors = 0;
		modified = 0;
		str = Wings[cur_wing].name;
		if (stricmp(old_name, str)) {
			update_sexp_references(old_name, str);
			ai_update_goal_references(REF_TYPE_WING, old_name, str);
			for (i=0; i<Num_reinforcements; i++)
				if (!stricmp(old_name, Reinforcements[i].name)) {
					Assert(strlen(str) < NAME_LENGTH);
					strcpy(Reinforcements[i].name, str);
				}

			for (i=0; i<Wings[cur_wing].wave_count; i++) {
				if ((Objects[wing_objects[cur_wing][i]].type == OBJ_SHIP) || (Objects[wing_objects[cur_wing][i]].type == OBJ_START)) {
					sprintf(buf, "%s %d", str, i + 1);
					rename_ship(Wings[cur_wing].ship_index[i], buf);
				}
			}

			Update_window = 1;
		}

		if (set_reinforcement(str, m_reinforcement) == 1) {
			free_sexp2(Wings[cur_wing].arrival_cue);
			Wings[cur_wing].arrival_cue = Locked_sexp_false;
		}
	}

	if (redraw)
		update_map_window();

	return 0;
}
// Forms a wing from marked objects
int create_wing()
{
	char msg[1024];
	int i, ship, wing = -1, waypoints = 0, count = 0, illegal_ships = 0;
	int leader, leader_team;
	object *ptr;
	create_wing_dlg dlg;

	if (!query_valid_object())
		return -1;

	leader = cur_object_index;
	ptr = GET_FIRST(&obj_used_list);
	while (ptr != END_OF_LIST(&obj_used_list)) {
		if (( (ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START) ) && (ptr->flags & OF_MARKED)) {
			count++;
			i = -1;
			switch (ptr->type) {
				case OBJ_SHIP:
				case OBJ_START:
					i = Ships[ptr->instance].wingnum;
					break;
			}

			if (i >= 0) {
				if (wing < 0)
					wing = i;
				else if (wing != i)
					wing = MULTI_WING;
			}
		}

		ptr = GET_NEXT(ptr);
	}

	if (count > MAX_SHIPS_PER_WING) {
		sprintf(msg, "You have too many ships marked!\n"
			"A wing is limited to %d ships total", MAX_SHIPS_PER_WING);

		Fred_main_wnd->MessageBox(msg, "Error", MB_ICONEXCLAMATION);
		return -1;
	}

	if ((wing >= 0) && (wing != MULTI_WING)) {
		sprintf(msg, "Do you want to reform wing \"%s\"?", Wings[wing].name);
		i = Fred_main_wnd->MessageBox(msg, "Query", MB_YESNOCANCEL);
		if (i == IDCANCEL)
			return -1;

		else if (i == IDNO)
			wing = -1;

		else {  // must be IDYES
			for (i=Wings[wing].wave_count-1; i>=0; i--) {
				ptr = &Objects[wing_objects[wing][i]];
				switch (ptr->type) {
					case OBJ_SHIP:
						remove_ship_from_wing(ptr->instance, 0);
						break;

					case OBJ_START:
						remove_player_from_wing(ptr->instance, 0);
						break;

					default:
						Int3();  // shouldn't be in a wing!
				}
			}

			Assert(!Wings[wing].wave_count);
			Num_wings--;
		}

	} else
		wing = -1;

	if (wing < 0) {
		wing = find_free_wing();

		if (wing < 0) {
			Fred_main_wnd->MessageBox("Too many wings, can't create more!",
				"Error", MB_ICONEXCLAMATION);

			return -1;
		}

		Wings[wing].num_waves = 1;
		Wings[wing].threshold = 0;
		Wings[wing].arrival_location = Wings[wing].departure_location = 0;
		Wings[wing].arrival_distance = 0;
		Wings[wing].arrival_anchor = -1;
		Wings[wing].arrival_delay = 0;
		Wings[wing].arrival_cue = Locked_sexp_true;
		Wings[wing].departure_delay = 0;
		Wings[wing].departure_cue = Locked_sexp_false;
		Wings[wing].hotkey = -1;
		Wings[wing].flags = 0;
		Wings[wing].wave_delay_min = 0;
		Wings[wing].wave_delay_max = 0;

		for (i=0; i<MAX_AI_GOALS; i++) {
			Wings[wing].ai_goals[i].ai_mode = AI_GOAL_NONE;
			Wings[wing].ai_goals[i].priority = -1;				// this sets up the priority field to be like ships
		}

		if (dlg.DoModal() == IDCANCEL)
			return -1;

		dlg.m_name.TrimLeft();
		dlg.m_name.TrimRight();
		string_copy(Wings[wing].name, dlg.m_name, NAME_LENGTH - 1);
	}

	set_cur_indices(-1);
	ptr = GET_FIRST(&obj_used_list);
	while (ptr != END_OF_LIST(&obj_used_list)) {
		if (ptr->flags & OF_MARKED) {
//			if ((ptr->type == OBJ_START) && (ptr->instance)) {
//				starts++;
//				unmark_object(OBJ_INDEX(ptr));

//			} else if (ptr->type == OBJ_WAYPOINT) {
			if (ptr->type == OBJ_WAYPOINT) {
				waypoints++;
				unmark_object(OBJ_INDEX(ptr));

			} else if (ptr->type == OBJ_SHIP) {
				int ship_type = ship_query_general_type(ptr->instance);
				if(ship_type < 0 || !(Ship_types[ship_type].ai_bools & STI_AI_CAN_FORM_WING))
				{
					illegal_ships++;
					unmark_object(OBJ_INDEX(ptr));
				}
			}
		}

		ptr = GET_NEXT(ptr);
	}

	// if this wing is a player starting wing, automatically set the hotkey for this wing
	for (i = 0; i < MAX_STARTING_WINGS; i++ ) {
		if ( !stricmp(Wings[wing].name, Starting_wing_names[i]) ) {
			Wings[wing].hotkey = i;
			break;
		}
	}

	count = 0;
	if (Objects[Ships[Player_start_shipnum].objnum].flags & OF_MARKED)
		count = 1;

	ptr = GET_FIRST(&obj_used_list);
	while (ptr != END_OF_LIST(&obj_used_list)) {
		if (ptr->flags & OF_MARKED) {
			if ((ptr->type == OBJ_START) && (ptr->instance == Player_start_shipnum))
				i = 0;  // player 1 start always goes to front of the wing
			else
				i = count++;

			Assert((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START));
			ship = ptr->instance;
			if (Ships[ship].wingnum != -1) {
				if (ptr->type == OBJ_SHIP)
					remove_ship_from_wing(ship);
				else
					remove_player_from_wing(ptr->instance);
			}

			wing_bash_ship_name(msg, Wings[wing].name, i + 1);
			rename_ship(ship, msg);

			Wings[wing].ship_index[i] = ship;
			Ships[ship].wingnum = wing;
			if (Ships[ship].arrival_cue >= 0)
				free_sexp2(Ships[ship].arrival_cue);

			Ships[ship].arrival_cue = Locked_sexp_false;
			if (Ships[ship].departure_cue >= 0)
				free_sexp2(Ships[ship].departure_cue);

			Ships[ship].departure_cue = Locked_sexp_false;

			wing_objects[wing][i] = OBJ_INDEX(ptr);
			if (OBJ_INDEX(ptr) == leader)
				Wings[wing].special_ship = i;
		}

		ptr = GET_NEXT(ptr);
	}

	if (!count)  // this should never happen, so if it does, needs to be fixed now.
		Error(LOCATION, "No valid ships were selected to form wing from");

	Wings[wing].wave_count = count;
	Num_wings++;

//	if (starts)
//		Fred_main_wnd->MessageBox("Multi-player starting points can't be part of a wing!\n"
//			"All marked multi-player starting points were ignored",
//			"Error", MB_ICONEXCLAMATION);

	if (waypoints)
		Fred_main_wnd->MessageBox("Waypoints can't be part of a wing!\n"
			"All marked waypoints were ignored",
			"Error", MB_ICONEXCLAMATION);

	if (illegal_ships)
		Fred_main_wnd->MessageBox("Some ship types aren't allowed to be in a wing.\n"
			"All marked ships of these types were ignored",
			"Error", MB_ICONEXCLAMATION);


	leader_team = Ships[Wings[wing].ship_index[Wings[wing].special_ship]].team;
	for (i = 0; i < Wings[wing].wave_count; i++)
	{
		if (Ships[Wings[wing].ship_index[i]].team != leader_team)
		{
			Fred_main_wnd->MessageBox("Wing contains ships on different teams", "Warning");
			break;
		}
	}

	mark_wing(wing);

	update_custom_wing_indexes();

	return 0;
}
void debriefing_editor_dlg::update_data(int update)
{
	int enable, save_debriefing;
	debrief_stage *ptr;

	save_debriefing = m_current_debriefing;

	if (update)
		UpdateData(TRUE);

	// based on the game type, enable the multiple briefings combo box (or disable it)

	// set up the pointer to the briefing that we are editing
	if ( save_debriefing != m_current_debriefing )
		Debriefing = &Debriefings[save_debriefing];
	else
		Debriefing = &Debriefings[m_current_debriefing];

	if (m_last_stage >= 0) {
		ptr = &Debriefing->stages[m_last_stage];
		if (ptr->formula >= 0)
			free_sexp2(ptr->formula);

		ptr->formula = m_tree.save_tree();
		deconvert_multiline_string(ptr->new_text, m_text, MAX_DEBRIEF_LEN);
		deconvert_multiline_string(ptr->new_recommendation_text, m_rec_text, MAX_RECOMMENDATION_LEN);
		string_copy(ptr->voice, m_voice, MAX_FILENAME_LEN);
	}

	// now get new stage data
	if ((m_cur_stage >= 0) && (m_cur_stage < Debriefing->num_stages)) {
		ptr = &Debriefing->stages[m_cur_stage];
		m_stage_title.Format("Stage %d of %d", m_cur_stage + 1, Debriefing->num_stages);
		m_tree.load_tree(ptr->formula);
		m_text = convert_multiline_string(ptr->new_text);
		m_rec_text = convert_multiline_string(ptr->new_recommendation_text);
		m_voice = ptr->voice;
		enable = TRUE;

	} else {
		m_stage_title = _T("No stages");
		m_tree.clear_tree();
		m_text = _T("");
		m_rec_text = _T("");
		m_voice = _T("");
		enable = FALSE;
		m_cur_stage = -1;
	}

	if (m_cur_stage == Debriefing->num_stages - 1)
		GetDlgItem(IDC_NEXT) -> EnableWindow(FALSE);
	else
		GetDlgItem(IDC_NEXT) -> EnableWindow(enable);

	if (m_cur_stage)
		GetDlgItem(IDC_PREV) -> EnableWindow(enable);
	else
		GetDlgItem(IDC_PREV) -> EnableWindow(FALSE);

	if (Debriefing->num_stages >= MAX_DEBRIEF_STAGES)
		GetDlgItem(IDC_ADD_STAGE) -> EnableWindow(FALSE);
	else
		GetDlgItem(IDC_ADD_STAGE) -> EnableWindow(TRUE);

	if (Debriefing->num_stages) {
		GetDlgItem(IDC_DELETE_STAGE) -> EnableWindow(enable);
		GetDlgItem(IDC_INSERT_STAGE) -> EnableWindow(enable);

	} else {
		GetDlgItem(IDC_DELETE_STAGE) -> EnableWindow(FALSE);
		GetDlgItem(IDC_INSERT_STAGE) -> EnableWindow(FALSE);
	}

	GetDlgItem(IDC_VOICE) -> EnableWindow(enable);
	GetDlgItem(IDC_BROWSE) -> EnableWindow(enable);
	GetDlgItem(IDC_TEXT) -> EnableWindow(enable);
	GetDlgItem(IDC_REC_TEXT) -> EnableWindow(enable);
	GetDlgItem(IDC_TREE) -> EnableWindow(enable);

	m_last_stage = m_cur_stage;
	UpdateData(FALSE);

	#ifndef NDEBUG
	count_free_sexp_nodes();
	#endif
}
int CMessageEditorDlg::update(int num)
{
	char *ptr, buf[4096];
	int i, node, fnode;
	CListBox *list;

	UpdateData(TRUE);
	if (num >= 0)
	{
		ptr = (char *) (LPCTSTR) m_message_name;
		for (i=0; i<Num_messages; i++)
			if ((i != num) && (!stricmp(m_message_name, Messages[i].name)))
				break;

		if (i == Num_messages) {  // update name if no conflicts, otherwise keep old name
			update_sexp_references(Messages[num].name, ptr, OPF_MESSAGE);
			string_copy(Messages[num].name, m_message_name, NAME_LENGTH - 1);

			list = (CListBox *) GetDlgItem(IDC_MESSAGE_LIST);
			list->DeleteString(num);
			list->InsertString(num, m_message_name);
		}

		string_copy(Messages[num].message, m_message_text, MESSAGE_LENGTH - 1);
		if (Messages[num].avi_info.name)
			free(Messages[num].avi_info.name);

		ptr = (char *) (LPCTSTR) m_avi_filename;
		if (!ptr || !strlen(ptr))
			Messages[num].avi_info.name = NULL;
		else
			Messages[num].avi_info.name = strdup(ptr);

		if (Messages[num].wave_info.name)
			free(Messages[num].wave_info.name);

		ptr = (char *) (LPCTSTR) m_wave_filename;
		if (!ptr || !strlen(ptr))
			Messages[num].wave_info.name = NULL;
		else
			Messages[num].wave_info.name = strdup(ptr);

		// update the persona to the message.  We subtract 1 for the "None" at the beginning of the combo
		// box list.
		Messages[num].persona_index = m_persona - 1;

		if (m_tree.query_false()) {
			if (m_event_num >= 0) {  // need to delete event
				i = m_event_num;
				free_sexp2(Mission_events[i].formula);
				Assert(i < Num_mission_events);
				while (i < Num_mission_events - 1) {
					Mission_events[i] = Mission_events[i + 1];
					i++;
				}

				Num_mission_events--;
				m_event_num = -1;
			}

		} else {
			if (m_event_num >= 0)
				free_sexp2(Mission_events[m_event_num].formula);
			
			else {
				if (Num_mission_events == MAX_MISSION_EVENTS) {
					MessageBox("You have reached the limit on mission events.\n"
						"Can't add an event to send this message.");

					goto exit;
				}

				Assert(Num_mission_events < MAX_MISSION_EVENTS);
				m_event_num = Num_mission_events++;
				string_copy(Mission_events[m_event_num].name, m_message_name, NAME_LENGTH - 1);
				Mission_events[m_event_num].repeat_count = 1;
				Mission_events[m_event_num].interval = 1;
				Mission_events[m_event_num].score = 0;
				Mission_events[m_event_num].chain_delay = -1;
				Mission_events[m_event_num].objective_text = NULL;
				Mission_events[m_event_num].objective_key_text = NULL;
			}

			fnode = m_tree.save_tree();
			ptr = (char *) (LPCTSTR) m_message_name;
			node = alloc_sexp(ptr, SEXP_ATOM, SEXP_ATOM_STRING, -1, -1);
			((CComboBox *) GetDlgItem(IDC_PRIORITY))->GetLBText(m_priority, buf);
			node = alloc_sexp(buf, SEXP_ATOM, SEXP_ATOM_STRING, -1, node);
			((CComboBox *) GetDlgItem(IDC_SENDER))->GetLBText(m_sender, buf);
			node = alloc_sexp(buf, SEXP_ATOM, SEXP_ATOM_STRING, -1, node);
			node = alloc_sexp("send-message", SEXP_ATOM, SEXP_ATOM_OPERATOR, -1, node);
			node = alloc_sexp("", SEXP_LIST, SEXP_ATOM_LIST, node, -1);
			node = alloc_sexp("", SEXP_LIST, SEXP_ATOM_LIST, fnode, node);
			node = alloc_sexp("when", SEXP_ATOM, SEXP_ATOM_OPERATOR, -1, node);
			Mission_events[m_event_num].formula = node;
		}
	}

exit:
	if (query_modified())
		set_modified();

	modified = 0;
	return 0;
}
Exemple #14
0
// Forms a wing from marked objects
int create_wing()
{
	char msg[1024];
	int i, ship, wing = -1, waypoints = 0, count = 0, illegal_ships = 0;
	int friendly, hostile, leader;
	object *ptr;
	create_wing_dlg dlg;

	if (!query_valid_object())
		return -1;

	leader = cur_object_index;
	ptr = GET_FIRST(&obj_used_list);
	while (ptr != END_OF_LIST(&obj_used_list)) {
		if ((ptr->type == OBJ_SHIP) && (ptr->flags & OF_MARKED)) {
			count++;
			i = -1;
			switch (ptr->type) {
				case OBJ_SHIP:
				case OBJ_START:
					i = Ships[ptr->instance].wingnum;
					break;
			}

			if (i >= 0) {
				if (wing < 0)
					wing = i;
				else if (wing != i)
					wing = MULTI_WING;
			}
		}

		ptr = GET_NEXT(ptr);
	}

	if (count > MAX_SHIPS_PER_WING) {
		sprintf(msg, "You have too many ships marked!\n"
			"A flight group is limited to %d ships total", MAX_SHIPS_PER_WING);

		Fred_main_wnd->MessageBox(msg, "Error", MB_ICONEXCLAMATION);
		return -1;
	}

	if ((wing >= 0) && (wing != MULTI_WING)) {
		sprintf(msg, "Do you want to reform flight group \"%s\"?", Wings[wing].name);
		i = Fred_main_wnd->MessageBox(msg, "Query", MB_YESNOCANCEL);
		if (i == IDCANCEL)
			return -1;

		else if (i == IDNO)
			wing = -1;

		else {  // must be IDYES
			for (i=Wings[wing].wave_count-1; i>=0; i--) {
				ptr = &Objects[wing_objects[wing][i]];
				switch (ptr->type) {
					case OBJ_SHIP:
						remove_ship_from_wing(ptr->instance, 0);
						break;

					case OBJ_START:
						remove_player_from_wing(ptr->instance, 0);
						break;

					default:
						Int3();  // shouldn't be in a wing!
				}
			}

			Assert(!Wings[wing].wave_count);
			num_wings--;
		}

	} else
		wing = -1;

	if (wing < 0) {
		wing = find_free_wing();
		Wings[wing].num_waves = 1;
		Wings[wing].threshold = 0;
		Wings[wing].arrival_location = Wings[wing].departure_location = 0;
		Wings[wing].arrival_distance = 0;
		Wings[wing].arrival_anchor = -1;
		Wings[wing].arrival_cue = Locked_sexp_true;
		Wings[wing].departure_cue = Locked_sexp_false;
		Wings[wing].hotkey = -1;
		Wings[wing].flags = 0;

		for (i=0; i<MAX_AI_GOALS; i++) {
			Wings[wing].ai_goals[i].ai_mode = AI_GOAL_NONE;
			Wings[wing].ai_goals[i].priority = -1;				// this sets up the priority field to be like ships
		}

		if (wing < 0) {
			Fred_main_wnd->MessageBox("Too many flight groups, can't create more!",
				"Error", MB_ICONEXCLAMATION);

			return -1;
		}

		if (dlg.DoModal() == IDCANCEL)
			return -1;

		string_copy(Wings[wing].name, dlg.m_name, NAME_LENGTH - 1);
	}

	set_cur_indices(-1);
	ptr = GET_FIRST(&obj_used_list);
	while (ptr != END_OF_LIST(&obj_used_list)) {
		if (ptr->flags & OF_MARKED) {
//			if ((ptr->type == OBJ_START) && (ptr->instance)) {
//				starts++;
//				unmark_object(OBJ_INDEX(ptr));

//			} else if (ptr->type == OBJ_WAYPOINT) {
			if (ptr->type == OBJ_WAYPOINT) {
				waypoints++;
				unmark_object(OBJ_INDEX(ptr));

			} else if (ptr->type == OBJ_SHIP) {
				switch (ship_query_general_type(ptr->instance))
				{
					case SHIP_TYPE_CARGO:						
					case SHIP_TYPE_FIGHTER_BOMBER:			
					case SHIP_TYPE_CRUISER:					
					case SHIP_TYPE_FREIGHTER:			
					case SHIP_TYPE_CAPITAL:					
					case SHIP_TYPE_TRANSPORT:				
					case SHIP_TYPE_REPAIR_REARM:		
					case SHIP_TYPE_NAVBUOY:					
					case SHIP_TYPE_SENTRYGUN:
					case SHIP_TYPE_SPACE_OBJECT:
					case SHIP_TYPE_ESCAPEPOD:				
					case SHIP_TYPE_SUPERCAP:					
					case SHIP_TYPE_STEALTH:					
					case SHIP_TYPE_DRYDOCK:					
					//case SHIP_TYPE_AWACS:						
					//case SHIP_TYPE_GAS_MINER:
						
					// all ships added so that any craft type can be formed into a flight group
					/*case SHIP_TYPE_FIGHTER_BOMBER:
					case SHIP_TYPE_CRUISER:
					case SHIP_TYPE_AWACS:
					case SHIP_TYPE_GAS_MINER:
					case SHIP_TYPE_CORVETTE:
					case SHIP_TYPE_FREIGHTER:
					case SHIP_TYPE_CAPITAL:
					case SHIP_TYPE_TRANSPORT:
					case SHIP_TYPE_SUPERCAP:*/
						break;

					default:
						illegal_ships++;
						unmark_object(OBJ_INDEX(ptr));
				}
			}
		}

		ptr = GET_NEXT(ptr);
	}

	// if this wing is a player starting wing, automatically set the hotkey for this wing
	for (i = 0; i < MAX_STARTING_WINGS; i++ ) {
		if ( !stricmp(Wings[wing].name, Starting_wing_names[i]) ) {
			Wings[wing].hotkey = i;
			break;
		}
	}

	count = friendly = hostile = 0;
	if (Objects[Ships[Player_start_shipnum].objnum].flags & OF_MARKED)
		count = 1;

	ptr = GET_FIRST(&obj_used_list);
	while (ptr != END_OF_LIST(&obj_used_list)) {
		if (ptr->flags & OF_MARKED) {
			if ((ptr->type == OBJ_START) && (ptr->instance == Player_start_shipnum))
				i = 0;  // player 1 start always goes to front of the wing
			else
				i = count++;

			Assert((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START));
			ship = ptr->instance;
			if (Ships[ship].wingnum != -1) {
				if (ptr->type == OBJ_SHIP)
					remove_ship_from_wing(ship);
				else
					remove_player_from_wing(ptr->instance);
			}

			sprintf(msg, "%s %d", Wings[wing].name, i + 1);
			rename_ship(ship, msg);
			if (Ships[ship].team == TEAM_FRIENDLY)
				friendly = 1;
			else if ((Ships[ship].team == TEAM_HOSTILE) || (Ships[ship].team == TEAM_NEUTRAL))
				hostile = 1;

			Wings[wing].ship_index[i] = ship;
			Ships[ship].wingnum = wing;
			if (Ships[ship].arrival_cue >= 0)
				free_sexp2(Ships[ship].arrival_cue);

			Ships[ship].arrival_cue = Locked_sexp_false;
			if (Ships[ship].departure_cue >= 0)
				free_sexp2(Ships[ship].departure_cue);

			Ships[ship].departure_cue = Locked_sexp_false;

			wing_objects[wing][i] = OBJ_INDEX(ptr);
			if (OBJ_INDEX(ptr) == leader)
				Wings[wing].special_ship = i;
		}

		ptr = GET_NEXT(ptr);
	}

	if (!count)  // this should never happen, so if it does, needs to be fixed now.
		Error(LOCATION, "No valid ships were selected to form wing from");

	Wings[wing].wave_count = count;
	num_wings++;

//	if (starts)
//		Fred_main_wnd->MessageBox("Multi-player starting points can't be part of a wing!\n"
//			"All marked multi-player starting points were ignored",
//			"Error", MB_ICONEXCLAMATION);

	if (waypoints)
		Fred_main_wnd->MessageBox("Waypoints can't be part of a wing!\n"
			"All marked waypoints were ignored",
			"Error", MB_ICONEXCLAMATION);

	if (illegal_ships)
		Fred_main_wnd->MessageBox("Some ship types aren't allowed to be in a wing.\n"
			"All marked ships of these types were ignored",
			"Error", MB_ICONEXCLAMATION);

	if (friendly && hostile)
		Fred_main_wnd->MessageBox("Both hostile and friendly ships in same wing", "Warning");

	mark_wing(wing);
	return 0;
}