FS2_Open
Open source remastering of the Freespace 2 engine
multi_dogfight.cpp
Go to the documentation of this file.
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 
13 #include "network/multi_dogfight.h"
14 #include "network/multi.h"
15 #include "network/multiutil.h"
16 #include "network/multi_log.h"
17 #include "object/object.h"
18 #include "ship/ship.h"
19 #include "freespace2/freespace.h"
20 #include "io/key.h"
22 #include "gamesnd/eventmusic.h"
23 #include "gamesnd/gamesnd.h"
24 #include "network/multiui.h"
25 #include "missionui/chatbox.h"
26 #include "ui/ui.h"
27 #include "graphics/font.h"
28 #include "globalincs/alphacolors.h"
29 #include "playerman/player.h"
30 #include "stats/scoring.h"
31 #include "mission/missionparse.h"
32 #include "iff_defs/iff_defs.h"
33 #include "pilotfile/pilotfile.h"
34 #include "fs2netd/fs2netd_client.h"
35 #include "cfile/cfile.h"
36 
37 
38 // ----------------------------------------------------------------------------------------------------
39 // MULTI DOGFIGHT DEFINES/VARS
40 //
41 
42 // interface stuff
44 
45 #define NUM_MULTI_DF_BUTTONS 1
46 #define ACCEPT_BUTTON 0
47 
49  { // GR_640
50  // accept
51  ui_button_info("CB_05a", 571, 425, 578, 413, 5),
52  },
53  { // GR_1024
54  // accept
55  ui_button_info("2_CB_05a", 914, 681, 914, 660, 5),
56  }
57 };
58 
61  "KillMatrix",
62  "2_KillMatrix"
63 };
65  "KillMatrix-m",
66  "2_KillMatrix-m"
67 };
68 
69 // coord 3 is max width
70 static int Kill_matrix_title_coords[GR_NUM_RESOLUTIONS][3] = {
71  { // GR_640
72  19, 118, 172
73  },
74  { // GR_1024
75  33, 194, 272
76  }
77 };
78 
79 // display area coords
81  { // GR_640
82  43, 133, 569, 269
83  },
84  { // GR_1024
85  60, 213, 919, 429
86  }
87 };
88 
89 #define MULTI_DF_TOTAL_ADJUST 5
90 
91 // "check" icon coords
93  // GR_640
94  28,
95 
96  // GR_1024
97  45
98 };
99 
100 // players when the screen started - we need to store this explicity so that even after players leave, we can display the full kill matrix
101 typedef struct multi_df_score {
102  char callsign[CALLSIGN_LEN+1]; // callsign for this guy
103  scoring_struct stats; // stats for the guy
104  int np_index; // absolute index into the netplayers array
108 
109 
110 // ----------------------------------------------------------------------------------------------------
111 // MULTI DOGFIGHT FORWARD DECLARATIONS
112 //
113 
114 // process button presses
116 
117 // button was pressed
118 void multi_df_button_pressed(int button);
119 
120 // setup kill matrix data
122 
123 // blit the kill matrix
125 
126 // stuff a string representing the # of kills, player X had on player Y (where X and Y are indices into Multi_df_score)
127 // returns the # of kills
128 int multi_df_stuff_kills(char *kills, int player_x, int player_y);
129 
130 
131 // ----------------------------------------------------------------------------------------------------
132 // MULTI DOGFIGHT FUNCTIONS
133 //
134 
135 // call once per level just before entering the mission
137 {
138  int idx;
139 
140  // if we're not in dogfight mode, do nothing
142  return;
143  }
144 
145  // go through all player ships and make them hostile
146  for(idx=0; idx<MAX_PLAYERS; idx++){
147  if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_OBSERVER(Net_players[idx]) && (Net_players[idx].m_player != NULL) && (Net_players[idx].m_player->objnum >= 0) && (Objects[Net_players[idx].m_player->objnum].type == OBJ_SHIP)){
149  }
150  }
151 
152  //
153 }
154 
155 // evaluate a kill in dogfight by a netplayer
156 void multi_df_eval_kill(net_player *killer, object *dead_obj)
157 {
158  int dead_index = -1;
159 
160  // if we're not in dogfight mode, do nothing
162  return;
163  }
164 
165  // sanity checks
166  if((killer == NULL) || (dead_obj == NULL) || (killer->m_player == NULL)){
167  return;
168  }
169 
170  // try and find the dead player
171  dead_index = multi_find_player_by_object(dead_obj);
172  if(dead_index < 0){
173  return;
174  }
175  Assert(dead_index < MAX_PLAYERS);
176  if(dead_index == NET_PLAYER_INDEX(killer)){
177  return;
178  }
179 
180  // update his kills
181  killer->m_player->stats.m_dogfight_kills[dead_index]++;
182 }
183 
184 // debrief
186 {
187  // no longer is mission
188  Game_mode &= ~(GM_IN_MISSION);
189  game_flush();
190 
191  // call scoring level close for my stats. Needed for award_init. The stats will
192  // be backed out if used chooses to replace them.
194 
195  // multiplayer debriefing stuff
197 
198  // close down any old instances of the chatbox
199  chatbox_close();
200 
201  // create the new one
202  chatbox_create();
203 
204  // always play success music
206 
207  // setup kill matrix
209 
210  UI_WINDOW *w;
211  ui_button_info *b;
212  int idx;
213 
214  // load background bitmap
217 
218  // create the UI window
219  Multi_df_window.create(0, 0, gr_screen.max_w_unscaled, gr_screen.max_h_unscaled, 0);
221 
222  // initialize the control buttons
223  for (idx=0; idx<NUM_MULTI_DF_BUTTONS; idx++) {
224  b = &Multi_df_buttons[gr_screen.res][idx];
225 
226  // create the button
227  b->button.create(&Multi_df_window, NULL, b->x, b->y, 60, 30, 1, 1);
228 
229  // set its highlight action
231 
232  // set its animation bitmaps
233  b->button.set_bmaps(b->filename);
234 
235  // link the mask hotspot
236  b->button.link_hotspot(b->hotspot);
237  }
238 
239  // add some text
240  w = &Multi_df_window;
241  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);
242 }
243 
244 // do frame
246 {
247  int k, new_k;
248  char buf[256];
249 
250  k = chatbox_process();
251  new_k = Multi_df_window.process(k, 0);
252 
253  // process keypresses
254  switch(new_k){
255  case KEY_ESC:
257  break;
258  }
259 
260  // process buttons
262 
263  // music stuff
264  common_music_do();
265 
266  // process debriefing details
268 
269  // draw the background
271  if (Multi_df_background_bitmap >= 0) {
273  gr_bitmap(0, 0, GR_RESIZE_MENU);
274  }
275 
276  // draw the window
277  Multi_df_window.draw();
278 
279  // kill matrix
281 
282  // render the chatbox
283  chatbox_render();
284 
285  // draw the mission title
286  strcpy_s(buf, The_mission.name);
287  gr_force_fit_string(buf, 255, Kill_matrix_title_coords[gr_screen.res][2]);
289  gr_string(Kill_matrix_title_coords[gr_screen.res][0], Kill_matrix_title_coords[gr_screen.res][1], buf, GR_RESIZE_MENU);
290 
291  // flip
292  gr_flip();
293 }
294 
295 // close
297 {
298  int idx;
299  scoring_struct *sc;
300 
301  // shutdown the chatbox
302  chatbox_close();
303 
304  // if stats weren't accepted, backout my own stats
305  if (multi_debrief_stats_accept_code() != 1) {
306  // if stats weren't accepted, backout my own stats
307  if (multi_debrief_stats_accept_code() != 1) {
308  if(MULTIPLAYER_MASTER){
309  for(idx=0; idx<MAX_PLAYERS; idx++){
310  if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].m_player != NULL)){
311  sc = &Net_players[idx].m_player->stats;
313 
314  if (Net_player == &Net_players[idx]) {
316  }
317  }
318  }
319  } else {
322  }
323  }
324  }
325 
326  // music stuff
328 }
329 
330 
331 // ----------------------------------------------------------------------------------------------------
332 // MULTI DOGFIGHT FORWARD DEFINITIONS
333 //
334 
335 // process button presses
337 {
338  int idx;
339 
340  for(idx=0; idx<NUM_MULTI_DF_BUTTONS; idx++){
341  if(Multi_df_buttons[gr_screen.res][idx].button.pressed()){
343  break;
344  }
345  }
346 }
347 
348 // button was pressed
349 void multi_df_button_pressed(int button)
350 {
351  switch(button){
352  case ACCEPT_BUTTON:
354  break;
355  }
356 }
357 
358 // setup kill matrix data
360 {
361  int idx, s_idx;
362  multi_df_score *s;
363 
365 
366  // add players as necessary
367  for(idx=0; idx<MAX_PLAYERS; idx++){
368  if(MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && !MULTI_PERM_OBSERVER(Net_players[idx]) && (Net_players[idx].m_player != NULL)){
369  // stuff data for this guy
370  s = &Multi_df_score[Multi_df_score_count++];
371 
372  ml_printf("Dogfight debrief stats for %s", Net_players[idx].m_player->callsign);
373  for(s_idx=0; s_idx<MAX_PLAYERS; s_idx++){
374  ml_printf("%d", Net_players[idx].m_player->stats.m_dogfight_kills[s_idx]);
375  }
376 
379  s->np_index = idx;
380  }
381  }
382 }
383 
384 // blit the kill matrix
386 {
387  int idx, s_idx, str_len;
388  int cx, cy;
389  char squashed_string[CALLSIGN_LEN+1] = "";
390  int dy = gr_get_font_height() + 1;
391 
392  // max width of an individual item, and the text that can be in that item
393  float max_item_width = ((float)Multi_df_display_coords[gr_screen.res][2] - 40.0f) / (float)(Multi_df_score_count + 1);
394  float max_text_width = max_item_width * 0.8f;
395 
396  // start x for the top bar (one item to the right)
397  int top_x_start = Multi_df_display_coords[gr_screen.res][0] + (int)max_item_width;
398  int top_y_start = Multi_df_display_coords[gr_screen.res][1];
399 
400  // start x for the side bar
401  int side_x_start = Multi_df_display_coords[gr_screen.res][0];
402  int side_y_start = Multi_df_display_coords[gr_screen.res][1] + dy;
403 
404  // draw the top bar
405  cx = top_x_start;
406  cy = top_y_start;
407  for(idx=0; idx<Multi_df_score_count; idx++){
408  // force the string to fit nicely
409  strcpy_s(squashed_string, Multi_df_score[idx].callsign);
410  gr_force_fit_string(squashed_string, CALLSIGN_LEN, (int)max_text_width);
411  gr_get_string_size(&str_len, NULL, squashed_string);
412 
413  // set color and blit the string
414  Assert(Multi_df_score[idx].np_index >= 0);
415  if(Multi_df_score[idx].np_index >= 0){
416  gr_set_color_fast(Color_netplayer[Multi_df_score[idx].np_index]);
417  }
418  gr_string(cx + (int)((max_item_width - (float)str_len)/2.0f), cy, squashed_string, GR_RESIZE_MENU);
419 
420  // next spot
421  cx += (int)max_item_width;
422  }
423 
424  // draw the rest of the scoreboard
425  cx = side_x_start;
426  cy = side_y_start;
427  int row_total;
428  for(idx=0; idx<Multi_df_score_count; idx++){
429  // draw a check if necessary
430  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)){
431  if(Multi_common_icons[MICON_VALID] != -1){
434  }
435  }
436 
437  // draw the name
439  strcpy_s(squashed_string, Multi_df_score[idx].callsign);
440  gr_force_fit_string(squashed_string, CALLSIGN_LEN, (int)max_text_width);
441  gr_get_string_size(&str_len, NULL, squashed_string);
442  Assert(Multi_df_score[idx].np_index >= 0);
443  if(Multi_df_score[idx].np_index >= 0){
444  gr_set_color_fast(Color_netplayer[Multi_df_score[idx].np_index]);
445  }
446  gr_string(cx, cy, squashed_string, GR_RESIZE_MENU);
447 
448  cx = top_x_start;
449  row_total = 0;
450  for(s_idx=0; s_idx<Multi_df_score_count; s_idx++){
451  // stuff the string to be displayed and select the proper display color
452  if(s_idx == idx){
453  strcpy_s(squashed_string, "-");
455  } else {
456  row_total += multi_df_stuff_kills(squashed_string, idx, s_idx);
457  Assert(Multi_df_score[idx].np_index >= 0);
458  if(Multi_df_score[idx].np_index >= 0){
459  gr_set_color_fast(Color_netplayer[Multi_df_score[idx].np_index]);
460  }
461  }
462 
463  // draw the string
464  gr_force_fit_string(squashed_string, CALLSIGN_LEN, (int)max_text_width);
465  gr_get_string_size(&str_len, NULL, squashed_string);
466  gr_string(cx + (int)((max_item_width - (float)str_len)/2.0f), cy, squashed_string, GR_RESIZE_MENU);
467 
468  // next spot
469  cx += (int)max_item_width;
470  }
471 
472  // draw the row total
473  gr_set_color_fast(Color_netplayer[Multi_df_score[idx].np_index]);
474  sprintf(squashed_string, "(%d)", row_total);
475  gr_get_string_size(&str_len, NULL, squashed_string);
477 
478  cy += dy;
479  }
480 }
481 
482 // stuff a string representing the # of kills, player X had on player Y (where X and Y are indices into Multi_df_score)
483 // returns the # of kills
484 int multi_df_stuff_kills(char *kills, int player_x, int player_y)
485 {
486  multi_df_score *s = &Multi_df_score[player_x];
487  strcpy(kills, "");
488 
489  sprintf(kills, "%d", s->stats.m_dogfight_kills[Multi_df_score[player_y].np_index]);
490  return s->stats.m_dogfight_kills[Multi_df_score[player_y].np_index];
491 }
void game_flush()
Definition: fredstubs.cpp:83
void set_highlight_action(void(*_user_function)(void))
Definition: button.cpp:375
pilotfile Pilot
Definition: pilotfile.cpp:7
int chatbox_create(int mode_flags)
Definition: chatbox.cpp:495
void add_XSTR(char *string, int _xstr_id, int _x, int _y, UI_GADGET *_assoc, int _color_type, int _font_id=-1)
Definition: window.cpp:476
int team
Definition: ship.h:606
int Game_mode
Definition: systemvars.cpp:24
void gr_flip()
Definition: 2d.cpp:2113
int x
Definition: ui.h:658
net_player * Net_player
Definition: multi.cpp:94
#define GR_RESIZE_MENU
Definition: 2d.h:684
char * Multi_df_mask_fname[GR_NUM_RESOLUTIONS]
int y
Definition: ui.h:658
char name[NAME_LENGTH]
Definition: missionparse.h:131
player * m_player
Definition: multi.h:459
scoring_struct stats
#define MULTI_STANDALONE(np)
Definition: multi.h:139
Assert(pm!=NULL)
char callsign[CALLSIGN_LEN+1]
int Multi_df_background_bitmap
#define GR_NUM_RESOLUTIONS
Definition: 2d.h:651
__inline void gr_string(int x, int y, const char *string, int resize_mode=GR_RESIZE_FULL)
Definition: 2d.h:769
int res
Definition: 2d.h:370
int max_h_unscaled
Definition: 2d.h:361
GLclampf f
Definition: Glext.h:7097
#define GR_MAYBE_CLEAR_RES(bmap)
Definition: 2d.h:639
void common_music_close()
void gr_set_color_fast(color *dst)
Definition: 2d.cpp:1197
void gr_set_bitmap(int bitmap_num, int alphablend_mode, int bitblt_mode, float alpha)
Definition: 2d.cpp:2105
int max_w_unscaled
Definition: 2d.h:361
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: Glext.h:7308
char callsign[CALLSIGN_LEN+1]
Definition: player.h:91
void multi_df_eval_kill(net_player *killer, object *dead_obj)
void multi_debrief_do_frame()
Definition: multiui.cpp:8664
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
void set_mask_bmap(char *fname)
Definition: window.cpp:75
int instance
Definition: object.h:150
int set_bmaps(char *ani_filename, int nframes=3, int start_frame=1)
Definition: gadget.cpp:71
#define NET_PLAYER_INDEX(np)
Definition: multi.h:125
void chatbox_render()
Definition: chatbox.cpp:683
int type_flags
Definition: multi.h:493
void multi_df_button_pressed(int button)
void scoring_backout_accept(scoring_struct *score)
Definition: scoring.cpp:378
void ml_printf(const char *format,...)
Definition: multi_log.cpp:112
int state
Definition: multi.h:464
void scoring_level_close(int accepted)
Definition: scoring.cpp:432
netgame_info Netgame
Definition: multi.cpp:97
int hotspot
Definition: ui.h:659
int pressed()
Definition: button.cpp:325
#define w(p)
Definition: modelsinc.h:68
sprintf(buf,"(%f,%f,%f)", v3->xyz.x, v3->xyz.y, v3->xyz.z)
#define MULTI_OBSERVER(np)
Definition: multi.h:140
char * Multi_df_background_fname[GR_NUM_RESOLUTIONS]
GLdouble s
Definition: Glext.h:5321
#define MAX_PLAYERS
Definition: pstypes.h:32
UI_BUTTON button
Definition: ui.h:660
#define ACCEPT_BUTTON
#define NETPLAYER_STATE_DEBRIEF_REPLAY
Definition: multi.h:704
color * Color_netplayer[NETPLAYER_COLORS]
int idx
Definition: multiui.cpp:761
int m_dogfight_kills[MAX_PLAYERS]
Definition: scoring.h:126
void multi_debrief_init()
Definition: multiui.cpp:8622
object Objects[MAX_OBJECTS]
Definition: object.cpp:62
#define MICON_VALID
Definition: multiui.h:64
color Color_grey
Definition: alphacolors.cpp:32
int yt
Definition: ui.h:658
int objnum
Definition: player.h:124
void multi_df_level_pre_enter()
#define GM_IN_MISSION
Definition: systemvars.h:23
void multi_df_debrief_do()
#define OBJ_SHIP
Definition: object.h:32
void common_music_do()
void multi_debrief_esc_hit()
Definition: multiui.cpp:8793
int bm_load(const char *real_filename)
Loads a bitmap so we can draw with it later.
Definition: bmpman.cpp:1119
GLboolean GLboolean GLboolean b
Definition: Glext.h:5781
ship Ships[MAX_SHIPS]
Definition: ship.cpp:122
#define MULTI_PERM_OBSERVER(np)
Definition: multi.h:142
typedef float(SCP_EXT_CALLCONV *SCPTRACKIR_PFFLOATVOID)()
void chatbox_close()
Definition: chatbox.cpp:634
color Color_bright_white
Definition: alphacolors.cpp:32
UI_WINDOW Multi_df_window
#define CALLSIGN_LEN
Definition: globals.h:31
void update_stats_backout(scoring_struct *stats, bool training=false)
Definition: pilotfile.cpp:185
void link_hotspot(int num)
Definition: gadget.cpp:50
int xt
Definition: ui.h:658
void multi_debrief_accept_hit()
Definition: multiui.cpp:8711
void create(UI_WINDOW *wnd, char *_text, int _x, int _y, int _w, int _h, int do_repeat=0, int ignore_focus=0)
Definition: button.cpp:26
#define KEY_ESC
Definition: key.h:124
multi_df_score Multi_df_score[MAX_PLAYERS]
#define UI_XSTR_COLOR_PINK
Definition: ui.h:161
int Multi_df_display_coords[GR_NUM_RESOLUTIONS][4]
#define MULTI_CONNECTED(np)
Definition: multi.h:136
void create(int _x, int _y, int _w, int _h, int _flags, int _f_id=-1)
Definition: window.cpp:140
player * Player
#define NETPLAYER_STATE_DEBRIEF_ACCEPT
Definition: multi.h:703
int gr_force_fit_string(char *str, int max_str, int max_width)
Definition: font.cpp:48
void multi_df_process_buttons()
Definition: ui.h:584
screen gr_screen
Definition: 2d.cpp:46
void gr_get_string_size(int *w, int *h, const char *text, int len=9999)
Definition: font.cpp:196
int gr_get_font_height()
Definition: font.cpp:187
#define MULTIPLAYER_MASTER
Definition: multi.h:130
void common_play_highlight_sound()
Definition: gamesnd.cpp:1151
int chatbox_process(int key_in)
Definition: chatbox.cpp:575
int Iff_traitor
Definition: iff_defs.cpp:22
void multi_df_debrief_init()
char * filename
Definition: ui.h:657
struct multi_df_score multi_df_score
int multi_df_stuff_kills(char *kills, int player_x, int player_y)
void gr_bitmap(int _x, int _y, int resize_mode)
Definition: 2d.cpp:1303
#define SCORE_DEBRIEF_SUCCESS
Definition: eventmusic.h:52
ui_button_info Multi_df_buttons[GR_NUM_RESOLUTIONS][NUM_MULTI_DF_BUTTONS]
#define MULTI_DF_TOTAL_ADJUST
int multi_debrief_stats_accept_code()
Definition: multiui.cpp:8942
int Multi_df_score_count
mission The_mission
void draw()
Definition: window.cpp:220
struct ui_button_info ui_button_info
void multi_df_debrief_close()
char type
Definition: object.h:146
int multi_find_player_by_object(object *objp)
Definition: multiutil.cpp:500
int process(int key_in=-1, int process_mouse=1)
Definition: window.cpp:401
int Multi_common_icons[MULTI_NUM_COMMON_ICONS]
Definition: multiui.cpp:304
#define NUM_MULTI_DF_BUTTONS
net_player Net_players[MAX_PLAYERS]
Definition: multi.cpp:93
int Multi_df_check_coords[GR_NUM_RESOLUTIONS]
void multi_df_setup_kill_matrix()
void common_music_init(int score_index)
#define NG_TYPE_DOGFIGHT
Definition: multi.h:651
scoring_struct stats
Definition: player.h:127
#define strcpy_s(...)
Definition: safe_strings.h:67
void multi_df_blit_kill_matrix()