2 * $Logfile: /Freespace2/code/Network/multi_dogfight.cpp $
8 * Revision 1.2 2002/05/07 03:16:47 theoddone33
9 * The Great Newline Fix
11 * Revision 1.1.1.1 2002/05/03 03:28:10 root
15 * 11 8/18/99 11:31a Jefff
16 * mission title on kill matrix
18 * 10 8/17/99 9:55a Dave
19 * Fixed dogfight scoring problem.
21 * 9 8/06/99 12:29a Dave
24 * 8 5/03/99 8:32p Dave
25 * New version of multi host options screen.
27 * 7 4/12/99 10:07p Dave
28 * Made network startup more forgiving. Added checkmarks to dogfight
29 * screen for players who hit commit.
31 * 6 4/12/99 2:22p Dave
32 * More checks for dogfight stats.
34 * 5 2/24/99 3:40p Dave
35 * Fixed problem where ships were becoming traitor all the time.
37 * 4 2/24/99 2:25p Dave
38 * Fixed up chatbox bugs. Made squad war reporting better. Fixed a respawn
39 * bug for dogfight more.
41 * 3 2/23/99 8:11p Dave
42 * Tidied up dogfight mode. Fixed TvT ship type problems for alpha wing.
43 * Small pass over todolist items.
45 * 2 2/23/99 2:29p Dave
46 * First run of oldschool dogfight mode.
52 #include "multiutil.h"
53 #include "multi_log.h"
56 #include "systemvars.h"
57 #include "freespace.h"
59 #include "missionscreencommon.h"
60 #include "eventmusic.h"
66 #include "multi_dogfight.h"
67 #include "alphacolors.h"
69 // ----------------------------------------------------------------------------------------------------
70 // MULTI DOGFIGHT DEFINES/VARS
74 UI_WINDOW Multi_df_window;
76 #define NUM_MULTI_DF_BUTTONS 1
77 #define ACCEPT_BUTTON 0
79 ui_button_info Multi_df_buttons[GR_NUM_RESOLUTIONS][NUM_MULTI_DF_BUTTONS] = {
82 ui_button_info("CB_05a", 571, 425, 578, 413, 5),
86 ui_button_info("2_CB_05a", 914, 681, 914, 660, 5),
90 int Multi_df_background_bitmap = -1;
91 char *Multi_df_background_fname[GR_NUM_RESOLUTIONS] = {
95 char *Multi_df_mask_fname[GR_NUM_RESOLUTIONS] = {
100 // coord 3 is max width
101 static int Kill_matrix_title_coords[GR_NUM_RESOLUTIONS][3] = {
110 // display area coords
111 int Multi_df_display_coords[GR_NUM_RESOLUTIONS][4] = {
120 #define MULTI_DF_TOTAL_ADJUST 5
122 // "check" icon coords
123 int Multi_df_check_coords[GR_NUM_RESOLUTIONS] = {
131 // players when the screen started - we need to store this explicity so that even after players leave, we can display the full kill matrix
132 typedef struct multi_df_score {
133 char callsign[CALLSIGN_LEN+1]; // callsign for this guy
134 scoring_struct stats; // stats for the guy
135 int np_index; // absolute index into the netplayers array
137 multi_df_score Multi_df_score[MAX_PLAYERS];
138 int Multi_df_score_count = 0;
141 // ----------------------------------------------------------------------------------------------------
142 // MULTI DOGFIGHT FORWARD DECLARATIONS
145 // process button presses
146 void multi_df_process_buttons();
148 // button was pressed
149 void multi_df_button_pressed(int button);
151 // setup kill matrix data
152 void multi_df_setup_kill_matrix();
154 // blit the kill matrix
155 void multi_df_blit_kill_matrix();
157 // stuff a string representing the # of kills, player X had on player Y (where X and Y are indices into Multi_df_score)
158 // returns the # of kills
159 int multi_df_stuff_kills(char *kills, int player_x, int player_y);
162 // ----------------------------------------------------------------------------------------------------
163 // MULTI DOGFIGHT FUNCTIONS
166 // call once per level just before entering the mission
167 void multi_df_level_pre_enter()
171 // if we're not in dogfight mode, do nothing
172 if(!(Netgame.type_flags & NG_TYPE_DOGFIGHT)){
176 // go through all player ships and make them hostile
177 for(idx=0; idx<MAX_PLAYERS; idx++){
178 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx]) && (Net_players[idx].player != NULL) && (Net_players[idx].player->objnum >= 0) && (Objects[Net_players[idx].player->objnum].type == OBJ_SHIP)){
179 Ships[Objects[Net_players[idx].player->objnum].instance].team = TEAM_TRAITOR;
186 // evaluate a kill in dogfight by a netplayer
187 void multi_df_eval_kill(net_player *killer, object *dead_obj)
191 // if we're not in dogfight mode, do nothing
192 if(!(Netgame.type_flags & NG_TYPE_DOGFIGHT)){
197 if((killer == NULL) || (dead_obj == NULL) || (killer->player == NULL)){
201 // try and find the dead player
202 dead_index = multi_find_player_by_object(dead_obj);
206 Assert(dead_index < MAX_PLAYERS);
207 if(dead_index == NET_PLAYER_INDEX(killer)){
212 killer->player->stats.m_dogfight_kills[dead_index]++;
216 void multi_df_debrief_init()
218 // no longer is mission
219 Game_mode &= ~(GM_IN_MISSION);
222 // call scoring level close for my stats. Needed for award_init. The stats will
223 // be backed out if used chooses to replace them.
224 scoring_level_close();
226 // multiplayer debriefing stuff
227 multi_debrief_init();
229 // close down any old instances of the chatbox
232 // create the new one
235 // always play success music
236 common_music_init(SCORE_DEBRIEF_SUCCESS);
239 multi_df_setup_kill_matrix();
245 // load background bitmap
246 Multi_df_background_bitmap = bm_load(Multi_df_background_fname[gr_screen.res]);
247 Assert(Multi_df_background_bitmap);
249 // create the UI window
250 Multi_df_window.create(0, 0, gr_screen.max_w, gr_screen.max_h, 0);
251 Multi_df_window.set_mask_bmap(Multi_df_mask_fname[gr_screen.res]);
253 // initialize the control buttons
254 for (idx=0; idx<NUM_MULTI_DF_BUTTONS; idx++) {
255 b = &Multi_df_buttons[gr_screen.res][idx];
258 b->button.create(&Multi_df_window, NULL, b->x, b->y, 60, 30, 1, 1);
260 // set its highlight action
261 b->button.set_highlight_action(common_play_highlight_sound);
263 // set its animation bitmaps
264 b->button.set_bmaps(b->filename);
266 // link the mask hotspot
267 b->button.link_hotspot(b->hotspot);
271 w = &Multi_df_window;
272 w->add_XSTR("Accept", 1035, Multi_df_buttons[gr_screen.res][ACCEPT_BUTTON].xt, Multi_df_buttons[gr_screen.res][ACCEPT_BUTTON].yt, &Multi_df_buttons[gr_screen.res][ACCEPT_BUTTON].button, UI_XSTR_COLOR_PINK);
276 void multi_df_debrief_do()
281 k = chatbox_process();
282 new_k = Multi_df_window.process(k, 0);
284 // process keypresses
287 multi_debrief_esc_hit();
292 multi_df_process_buttons();
297 // process debriefing details
298 multi_debrief_do_frame();
300 // draw the background
301 GR_MAYBE_CLEAR_RES(Multi_df_background_bitmap);
302 if (Multi_df_background_bitmap >= 0) {
303 gr_set_bitmap(Multi_df_background_bitmap);
308 Multi_df_window.draw();
311 multi_df_blit_kill_matrix();
313 // render the chatbox
316 // draw the mission title
317 strcpy(buf, The_mission.name);
318 gr_force_fit_string(buf, 255, Kill_matrix_title_coords[gr_screen.res][2]);
319 gr_set_color_fast(&Color_bright_white);
320 gr_string(Kill_matrix_title_coords[gr_screen.res][0], Kill_matrix_title_coords[gr_screen.res][1], buf);
327 void multi_df_debrief_close()
331 // shutdown the chatbox
334 // if stats weren't accepted, backout my own stats
335 if (multi_debrief_stats_accept_code() != 1) {
336 // if stats weren't accepted, backout my own stats
337 if (multi_debrief_stats_accept_code() != 1) {
338 if(MULTIPLAYER_MASTER){
339 for(idx=0; idx<MAX_PLAYERS; idx++){
340 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].player != NULL)){
341 scoring_backout_accept(&Net_players[idx].player->stats);
345 scoring_backout_accept( &Player->stats );
351 common_music_close();
355 // ----------------------------------------------------------------------------------------------------
356 // MULTI DOGFIGHT FORWARD DEFINITIONS
359 // process button presses
360 void multi_df_process_buttons()
364 for(idx=0; idx<NUM_MULTI_DF_BUTTONS; idx++){
365 if(Multi_df_buttons[gr_screen.res][idx].button.pressed()){
366 multi_df_button_pressed(idx);
372 // button was pressed
373 void multi_df_button_pressed(int button)
377 multi_debrief_accept_hit();
382 // setup kill matrix data
383 void multi_df_setup_kill_matrix()
388 Multi_df_score_count = 0;
390 // add players as necessary
391 for(idx=0; idx<MAX_PLAYERS; idx++){
392 if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].player != NULL)){
393 // stuff data for this guy
394 s = &Multi_df_score[Multi_df_score_count++];
396 ml_printf("Dogfight debrief stats for %s", Net_players[idx].player->callsign);
397 for(s_idx=0; s_idx<MAX_PLAYERS; s_idx++){
398 ml_printf("%d", Net_players[idx].player->stats.m_dogfight_kills[s_idx]);
401 s->stats = Net_players[idx].player->stats;
402 strcpy(s->callsign, Net_players[idx].player->callsign);
408 // blit the kill matrix
409 void multi_df_blit_kill_matrix()
411 int idx, s_idx, str_len;
413 char squashed_string[CALLSIGN_LEN+1] = "";
415 // max width of an individual item, and the text that can be in that item
416 float max_item_width = ((float)Multi_df_display_coords[gr_screen.res][2] - 40.0f) / (float)(Multi_df_score_count + 1);
417 float max_text_width = max_item_width * 0.8f;
419 // start x for the top bar (one item to the right)
420 int top_x_start = Multi_df_display_coords[gr_screen.res][0] + (int)max_item_width;
421 int top_y_start = Multi_df_display_coords[gr_screen.res][1];
423 // start x for the side bar
424 int side_x_start = Multi_df_display_coords[gr_screen.res][0];
425 int side_y_start = Multi_df_display_coords[gr_screen.res][1] + 10;
430 for(idx=0; idx<Multi_df_score_count; idx++){
431 // force the string to fit nicely
432 strcpy(squashed_string, Multi_df_score[idx].callsign);
433 gr_force_fit_string(squashed_string, CALLSIGN_LEN, (int)max_text_width);
434 gr_get_string_size(&str_len, NULL, squashed_string);
436 // set color and blit the string
437 Assert(Multi_df_score[idx].np_index >= 0);
438 if(Multi_df_score[idx].np_index >= 0){
439 gr_set_color_fast(Color_netplayer[Multi_df_score[idx].np_index]);
441 gr_string(cx + (int)((max_item_width - (float)str_len)/2.0f), cy, squashed_string);
444 cx += (int)max_item_width;
447 // draw the rest of the scoreboard
451 for(idx=0; idx<Multi_df_score_count; idx++){
452 // draw a check if necessary
453 if(!MULTI_CONNECTED(Net_players[Multi_df_score[idx].np_index]) || (Net_players[Multi_df_score[idx].np_index].state == NETPLAYER_STATE_DEBRIEF_ACCEPT) || (Net_players[Multi_df_score[idx].np_index].state == NETPLAYER_STATE_DEBRIEF_REPLAY)){
454 if(Multi_common_icons[MICON_VALID] != -1){
455 gr_set_bitmap(Multi_common_icons[MICON_VALID]);
456 gr_bitmap(Multi_df_check_coords[gr_screen.res], cy);
461 cx = Multi_df_display_coords[gr_screen.res][0];
462 strcpy(squashed_string, Multi_df_score[idx].callsign);
463 gr_force_fit_string(squashed_string, CALLSIGN_LEN, (int)max_text_width);
464 gr_get_string_size(&str_len, NULL, squashed_string);
465 Assert(Multi_df_score[idx].np_index >= 0);
466 if(Multi_df_score[idx].np_index >= 0){
467 gr_set_color_fast(Color_netplayer[Multi_df_score[idx].np_index]);
469 gr_string(cx, cy, squashed_string);
473 for(s_idx=0; s_idx<Multi_df_score_count; s_idx++){
474 // stuff the string to be displayed and select the proper display color
476 strcpy(squashed_string, "-");
477 gr_set_color_fast(&Color_grey);
479 row_total += multi_df_stuff_kills(squashed_string, idx, s_idx);
480 Assert(Multi_df_score[idx].np_index >= 0);
481 if(Multi_df_score[idx].np_index >= 0){
482 gr_set_color_fast(Color_netplayer[Multi_df_score[idx].np_index]);
487 gr_force_fit_string(squashed_string, CALLSIGN_LEN, (int)max_text_width);
488 gr_get_string_size(&str_len, NULL, squashed_string);
489 gr_string(cx + (int)((max_item_width - (float)str_len)/2.0f), cy, squashed_string);
492 cx += (int)max_item_width;
495 // draw the row total
496 gr_set_color_fast(Color_netplayer[Multi_df_score[idx].np_index]);
497 sprintf(squashed_string, "(%d)", row_total);
498 gr_get_string_size(&str_len, NULL, squashed_string);
499 gr_string(Multi_df_display_coords[gr_screen.res][0] + Multi_df_display_coords[gr_screen.res][2] - (MULTI_DF_TOTAL_ADJUST + str_len), cy, squashed_string);
509 for(idx=0; idx<Multi_df_score_count; idx++){
510 // add up this column
512 for(s_idx=0; s_idx<Multi_df_score_count; s_idx++){
514 column_total += Multi_df_score[idx].stats.m_dogfight_kills[s_idx];
518 sprintf(squashed_string, "%d", column_total);
519 gr_set_color_fast(Color_netplayer[Multi_df_score[idx].np_index]);
520 gr_string(cx, cy, squashed_string);
523 cx += (int)max_item_width;
528 // stuff a string representing the # of kills, player X had on player Y (where X and Y are indices into Multi_df_score)
529 // returns the # of kills
530 int multi_df_stuff_kills(char *kills, int player_x, int player_y)
532 multi_df_score *s = &Multi_df_score[player_x];
535 sprintf(kills, "%d", s->stats.m_dogfight_kills[Multi_df_score[player_y].np_index]);
536 return s->stats.m_dogfight_kills[Multi_df_score[player_y].np_index];