// displays (renders) the training objectives list
void training_obj_display()
{
		
	char buf[256], *second_line;
	int i, t, x, y, z, height, end, offset, bx, by, y_count;
	color *c;

	if (!Training_obj_num_lines){
		return;
	}

	if ( !hud_gauge_active(HUD_DIRECTIVES_VIEW) ) {
		// Always draw the directives display if this is a training mission
		if ( !(The_mission.game_type & MISSION_TYPE_TRAINING) ) {
			return;
		}
	}

	// don't ever display directives display in multiplayer missions
	// if ( Game_mode & GM_MULTIPLAYER ){
	// 	return;
	// }

	height = gr_get_font_height();

	offset = 0;
	end = Training_obj_num_lines;
	if (end > TRAINING_OBJ_DISPLAY_LINES) {
		end = TRAINING_OBJ_DISPLAY_LINES;
		offset = Training_obj_num_lines - end;
	}

	// draw top of objective display
	// hud_set_default_color();
	hud_set_gauge_color(HUD_DIRECTIVES_VIEW);

	GR_AABITMAP(Directive_gauge[0].first_frame, Directive_coords[gr_screen.res][DIRECTIVE_COORDS_TOP][0]+fl2i(HUD_offset_x), Directive_coords[gr_screen.res][DIRECTIVE_COORDS_TOP][1]+fl2i(HUD_offset_y));
	// gr_set_bitmap(Directive_gauge[0].first_frame);
	// gr_aabitmap(Directive_coords[DIRECTIVE_COORDS_TOP][0]+fl2i(HUD_offset_x), Directive_coords[DIRECTIVE_COORDS_TOP][1]+fl2i(HUD_offset_y));

	// print out title
	emp_hud_printf(Directive_coords[gr_screen.res][DIRECTIVE_COORDS_TITLE][0]+fl2i(HUD_offset_x), Directive_coords[gr_screen.res][DIRECTIVE_COORDS_TITLE][1]+fl2i(HUD_offset_y), EG_OBJ_TITLE, XSTR( "Directives", 422));
	// gr_printf(Directive_coords[DIRECTIVE_COORDS_TITLE][0]+fl2i(HUD_offset_x), Directive_coords[DIRECTIVE_COORDS_TITLE][1]+fl2i(HUD_offset_y), XSTR( "directives", 422));
	
	bx = DIRECTIVE_X+fl2i(HUD_offset_x);
	by = Directive_coords[gr_screen.res][DIRECTIVE_COORDS_MIDDLE][1]+fl2i(HUD_offset_y);

	y_count = 0;
	for (i=0; i<end; i++) {
		x = DIRECTIVE_X + 5 + fl2i(HUD_offset_x);
		y = Training_obj_window_coords[gr_screen.res][1] + fl2i(HUD_offset_y) + y_count * height + height / 2 + 1;
		z = TRAINING_OBJ_LINES_MASK(i + offset);

		c = &Color_normal;
		if (Training_obj_lines[i + offset] & TRAINING_OBJ_LINES_KEY) {
			message_translate_tokens(buf, Mission_events[z].objective_key_text);  // remap keys
//			gr_set_color_fast(&Color_normal);
			c = &Color_bright_green;
		} else {
			strcpy(buf, Mission_events[z].objective_text);
			if (Mission_events[z].count){
				sprintf(buf + strlen(buf), NOX(" [%d]"), Mission_events[z].count);
			}

#ifndef NO_NETWORK
			// if this is a multiplayer tvt game, and this is event is not for my team, don't display it
			if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_TEAM) && (Net_player != NULL)){
				if((Mission_events[z].team != -1) && (Net_player->p_info.team != Mission_events[z].team)){
					continue;
				}
			}
#endif

			switch (mission_get_event_status(z)) {
			case EVENT_CURRENT:
//				gr_set_color_fast(&Color_bright_white);
				c = &Color_bright_white;
				break;

			case EVENT_FAILED:
//				gr_set_color_fast(&Color_bright_red);
				c = &Color_bright_red;
				break;

			case EVENT_SATISFIED:
//				gr_set_color_fast(&Color_bright_blue);
				t = Mission_events[z].satisfied_time;
				if (t + i2f(2) > Missiontime) {
					if (Missiontime % fl2f(.4f) < fl2f(.2f)){
						c = &Color_bright_blue;
					} else {
						c = &Color_bright_white;
					}
				} else {
					c = &Color_bright_blue;
				}
				break;
			}
		}

		// maybe split the directives line
		second_line = split_str_once(buf, 167);

		// blit the background frames
		// hud_set_default_color();
		hud_set_gauge_color(HUD_DIRECTIVES_VIEW);

		GR_AABITMAP(Directive_gauge[1].first_frame, bx, by);
		// gr_set_bitmap(Directive_gauge[1].first_frame);
		// gr_aabitmap(bx, by);
		
		by += DIRECTIVE_H;

		if ( second_line ) {
			GR_AABITMAP(Directive_gauge[1].first_frame, bx, by);
			// gr_set_bitmap(Directive_gauge[1].first_frame);
			// gr_aabitmap(bx, by);
			
			by += DIRECTIVE_H;
		}

		// blit the text
		gr_set_color_fast(c);
		
		emp_hud_string(x, y, EG_OBJ1 + i, buf);
		// gr_printf(x, y, buf);
		
		y_count++;

		if ( second_line ) {
			y = Training_obj_window_coords[gr_screen.res][1] + fl2i(HUD_offset_y) + y_count * height + height / 2 + 1;
			
			emp_hud_string(x+12, y, EG_OBJ1 + i + 1, second_line);
			// gr_printf(x+12, y, second_line);
			
			y_count++;
		}
	}

	// draw the bottom of objective display
	// hud_set_default_color();
	hud_set_gauge_color(HUD_DIRECTIVES_VIEW);

	GR_AABITMAP(Directive_gauge[2].first_frame, bx, by);
	// gr_set_bitmap(Directive_gauge[2].first_frame);
	// gr_aabitmap(bx, by);
}
void sort_training_objectives()
{
	int i, event_status, offset;

	// start by sorting on born on date
	qsort(Training_obj_lines, Training_obj_num_lines, sizeof(int), comp_training_lines_by_born_on_date);

	// get the index of the first directive that will be displayed
	// if less than 0, display all lines
	offset = Training_obj_num_lines - TRAINING_OBJ_DISPLAY_LINES;

	if (offset <= 0) {
		return;
	}

	// go through lines 0 to offset-1 and check if there are any CURRENT or	RECENTLY_KNOWN events that should be shown
	int num_offset_events = 0;
	for (i=0; i<offset; i++) {
		event_status = mission_get_event_status(TRAINING_OBJ_LINES_MASK(i));

		if (event_status == EVENT_CURRENT)  {
			Training_obj_lines[i] |= TRAINING_OBJ_STATUS_UNKNOWN;
			num_offset_events++;
		} else if (event_status ==	EVENT_SATISFIED) {
			if (f2i(Missiontime - Mission_events[TRAINING_OBJ_LINES_MASK(i)].satisfied_time) < MIN_SATISFIED_TIME) {
				Training_obj_lines[i] |= TRAINING_OBJ_STATUS_UNKNOWN;
				num_offset_events++;
			} else {
				Training_obj_lines[i] |= TRAINING_OBJ_STATUS_KNOWN;
			}
		} else if (event_status ==	EVENT_FAILED) {
			if (f2i(Missiontime - Mission_events[TRAINING_OBJ_LINES_MASK(i)].satisfied_time) < MIN_FAILED_TIME) {
				Training_obj_lines[i] |= TRAINING_OBJ_STATUS_UNKNOWN;
				num_offset_events++;
			} else {
				Training_obj_lines[i] |= TRAINING_OBJ_STATUS_KNOWN;
			}
		}
	}

	// if there are no directives which should be moved, we're done
	if (num_offset_events == 0) {
		return;
	}

	// go through lines offset to Training_obj_num_lines to check which should be shown, since some will need to be bumped
	for (i=offset; i<Training_obj_num_lines; i++) {
		event_status = mission_get_event_status(TRAINING_OBJ_LINES_MASK(i));

		if (event_status == EVENT_CURRENT)  {
			Training_obj_lines[i] |= TRAINING_OBJ_STATUS_UNKNOWN;
		} else if (event_status ==	EVENT_SATISFIED) {
			if (f2i(Missiontime - Mission_events[TRAINING_OBJ_LINES_MASK(i)].satisfied_time) < MIN_SATISFIED_TIME) {
				Training_obj_lines[i] |= TRAINING_OBJ_STATUS_UNKNOWN;
			} else {
				Training_obj_lines[i] |= TRAINING_OBJ_STATUS_KNOWN;
			}
		} else if (event_status ==	EVENT_FAILED) {
			if (f2i(Missiontime - Mission_events[TRAINING_OBJ_LINES_MASK(i)].satisfied_time) < MIN_FAILED_TIME) {
				Training_obj_lines[i] |= TRAINING_OBJ_STATUS_UNKNOWN;
			} else {
				Training_obj_lines[i] |= TRAINING_OBJ_STATUS_UNKNOWN;
			}
		}
	}


	int slot_idx, unkn_vis;
	// go through list and bump as needed
	for (i=0; i<num_offset_events; i++) {

		// find most recent directive that would not be shown
		for (unkn_vis=offset-1; unkn_vis>=0; unkn_vis--) {
			if (Training_obj_lines[unkn_vis] & TRAINING_OBJ_STATUS_UNKNOWN) {
				break;
			}
		}

		// find first slot that can be bumped
		// look at the last (N-4 to N) positions
		for (slot_idx=0; slot_idx<TRAINING_OBJ_DISPLAY_LINES; slot_idx++) {
			if ( Training_obj_lines[i+offset] & TRAINING_OBJ_STATUS_KNOWN ) {
				break;
			}
		}

		// shift and replace (mark old one as STATUS_KNOWN)
		for (int j=slot_idx; j>0; j--) {
			Training_obj_lines[j+offset-1] = Training_obj_lines[j+offset-2];
		}
		Training_obj_lines[offset] = Training_obj_lines[unkn_vis];
		Training_obj_lines[unkn_vis] &= ~TRAINING_OBJ_LINES_EVENT_STATUS_MASK;
		Training_obj_lines[unkn_vis] |= TRAINING_OBJ_STATUS_KNOWN;
	}

	// remove event status
	for (i=0; i<Training_obj_num_lines; i++) {
		Training_obj_lines[i] &= ~TRAINING_OBJ_LINES_EVENT_STATUS_MASK;
	}
}
void HudGaugeDirectives::render(float frametime)
{
	char buf[256], *second_line;
	int i, t, x, y, z, end, offset, bx, by, y_count;
	color *c;

	if (!Training_obj_num_lines){
		return;
	}

	offset = 0;
	end = Training_obj_num_lines;
	if (end > Max_directives) {
		end = Max_directives;
		offset = Training_obj_num_lines - end;
	}

	// draw top of objective display
	setGaugeColor();

	renderBitmap(directives_top.first_frame, position[0], position[1]);

	// print out title
	renderPrintf(position[0] + header_offsets[0], position[1] + header_offsets[1], EG_OBJ_TITLE, XSTR( "directives", 422));

	bx = position[0];
	by = position[1] + middle_frame_offset_y;

	y_count = 0;
	for (i=0; i<end; i++) {
		x = position[0] + text_start_offsets[0];
		y = position[1] + text_start_offsets[1] + y_count * text_h;
		z = TRAINING_OBJ_LINES_MASK(i + offset);

		c = &Color_normal;
		if (Training_obj_lines[i + offset] & TRAINING_OBJ_LINES_KEY) {
			message_translate_tokens(buf, Mission_events[z].objective_key_text);  // remap keys
			c = &Color_bright_green;
		} else {
			strcpy_s(buf, Mission_events[z].objective_text);
			if (Mission_events[z].count){
				sprintf(buf + strlen(buf), NOX(" [%d]"), Mission_events[z].count);
			}

			// if this is a multiplayer tvt game, and this is event is not for my team, don't display it
			if((MULTI_TEAM) && (Net_player != NULL)){
				if((Mission_events[z].team != -1) && (Net_player->p_info.team != Mission_events[z].team)){
					continue;
				}
			}

			switch (mission_get_event_status(z)) {
			case EVENT_CURRENT:
				c = &Color_bright_white;
				break;

			case EVENT_FAILED:
				c = &Color_bright_red;
				break;

			case EVENT_SATISFIED:
				t = Mission_events[z].satisfied_time;
				if (t + i2f(2) > Missiontime) {
					if (Missiontime % fl2f(.4f) < fl2f(.2f)){
						c = &Color_bright_blue;
					} else {
						c = &Color_bright_white;
					}
				} else {
					c = &Color_bright_blue;
				}
				break;
			}
		}

		// maybe split the directives line
		second_line = split_str_once(buf, max_line_width);
		Assert( second_line != buf );

		// blit the background frames
		setGaugeColor();

		renderBitmap(directives_middle.first_frame, bx, by);
		
		by += text_h;

		if ( second_line ) {
			renderBitmap(directives_middle.first_frame, bx, by);
			
			by += text_h;
		}

		// blit the text
		gr_set_color_fast(c);
		
		renderString(x, y, EG_OBJ1 + i, buf);
		
		y_count++;

		if ( second_line ) {
			y = position[1] + text_start_offsets[1] + y_count * text_h;
			
			renderString(x+12, y, EG_OBJ1 + i + 1, second_line);
			
			y_count++;
		}
	}

	// draw the bottom of objective display
	setGaugeColor();

	renderBitmap(directives_bottom.first_frame, bx, by + bottom_bg_offset);
}