]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/multi_ingame.cpp
warning cleanup
[taylor/freespace2.git] / src / network / multi_ingame.cpp
1 /*
2  * $Logfile: /Freespace2/code/Network/multi_ingame.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * $Log$
8  * Revision 1.2  2002/06/02 04:26:34  relnev
9  * warning cleanup
10  *
11  * Revision 1.1.1.1  2002/05/03 03:28:10  root
12  * Initial import.
13  *
14  * 
15  * 20    8/03/99 11:02p Dave
16  * Maybe fixed sync problems in multiplayer.
17  * 
18  * 19    7/30/99 7:01p Dave
19  * Dogfight escort gauge. Fixed up laser rendering in Glide.
20  * 
21  * 18    7/28/99 5:33p Dave
22  * Nailed the missing stats bug to the wall. Problem was optimized build
23  * and using GET_DATA() with array elements. BLECH.
24  * 
25  * 17    7/26/99 6:07p Dave
26  * Removed some warnings.
27  * 
28  * 16    7/26/99 5:50p Dave
29  * Revised ingame join. Better? We'll see....
30  * 
31  * 15    7/24/99 5:48p Jefff
32  * converted to new UI stuff -- added 1024 support
33  * 
34  * 14    7/08/99 10:53a Dave
35  * New multiplayer interpolation scheme. Not 100% done yet, but still
36  * better than the old way.
37  * 
38  * 13    4/21/99 6:15p Dave
39  * Did some serious housecleaning in the beam code. Made it ready to go
40  * for anti-fighter "pulse" weapons. Fixed collision pair creation. Added
41  * a handy macro for recalculating collision pairs for a given object.
42  * 
43  * 12    3/10/99 6:50p Dave
44  * Changed the way we buffer packets for all clients. Optimized turret
45  * fired packets. Did some weapon firing optimizations.
46  * 
47  * 11    3/09/99 6:24p Dave
48  * More work on object update revamping. Identified several sources of
49  * unnecessary bandwidth.
50  * 
51  * 10    3/08/99 7:03p Dave
52  * First run of new object update system. Looks very promising.
53  * 
54  * 9     3/01/99 7:39p Dave
55  * Added prioritizing ship respawns. Also fixed respawns in TvT so teams
56  * don't mix respawn points.
57  * 
58  * 8     1/30/99 5:08p Dave
59  * More new hi-res stuff.Support for nice D3D textures.
60  * 
61  * 7     1/27/99 9:56a Dave
62  * Temporary checkin of beam weapons for Dan to make cool sounds.
63  * 
64  * 6     11/19/98 8:03a Dave
65  * Full support for D3-style reliable sockets. Revamped packet lag/loss
66  * system, made it receiver side and at the lowest possible level.
67  * 
68  * 5     11/17/98 11:12a Dave
69  * Removed player identification by address. Now assign explicit id #'s.
70  * 
71  * 4     11/05/98 5:55p Dave
72  * Big pass at reducing #includes
73  * 
74  * 3     10/13/98 9:29a Dave
75  * Started neatening up freespace.h. Many variables renamed and
76  * reorganized. Added AlphaColors.[h,cpp]
77  * 
78  * 2     10/07/98 10:53a Dave
79  * Initial checkin.
80  * 
81  * 1     10/07/98 10:50a Dave
82  * 
83  * 83    9/18/98 4:54p Dave
84  * Fixed ingame ship select icon problem.
85  * 
86  * 82    9/18/98 4:23p Dave
87  * Reversed the logic on a bogus assert.
88  * 
89  * 81    9/18/98 3:13p Allender
90  * actually delete ships from wings when ingame joining.  Shoudl get over
91  * problem were too many ships are presend in the mission since we don't
92  * delete unused ships until after ingame join is completed
93  * 
94  * 80    9/15/98 1:59p Dave
95  * Fixed bonehead mistake calling multi_endgame_ending()
96  * 
97  * 79    9/11/98 4:14p Dave
98  * Fixed file checksumming of < file_size. Put in more verbose kicking and
99  * PXO stats store reporting.
100  * 
101  * 78    9/11/98 2:10p Allender
102  * base temporary parse_object's ai_goals to -1 so that we don't try and
103  * free sepxressions that shouldn't be freed
104  * 
105  * 77    8/07/98 10:16a Allender
106  * use obj_set_flags for the COULD_BE_PLAYER flag
107  * 
108  * 76    7/24/98 9:27a Dave
109  * Tidied up endgame sequencing by removing several old flags and
110  * standardizing _all_ endgame stuff with a single function call.
111  * 
112  * 75    6/30/98 2:17p Dave
113  * Revised object update system. Removed updates for all weapons. Put
114  * button info back into control info packet.
115  * 
116  * 74    6/13/98 6:01p Hoffoss
117  * Externalized all new (or forgot to be added) strings to all the code.
118  * 
119  * 73    6/13/98 3:18p Hoffoss
120  * NOX()ed out a bunch of strings that shouldn't be translated.
121  * 
122  * 72    6/10/98 2:56p Dave
123  * Substantial changes to reduce bandwidth and latency problems.
124  * 
125  * 71    6/04/98 11:46a Dave
126  * Drastically reduce size/rate of client control info update packets. Put
127  * in rate limiting for object updating from server.
128  * 
129  * 70    5/26/98 11:54a Allender
130  * fix multiplayer problems and sexpression crash
131  * 
132  * 69    5/25/98 1:33a Allender
133  * fixed timestamp problem for client update packets, small fix for ingame
134  * validation code
135  * 
136  * 68    5/24/98 9:17p Allender
137  * commented out test code to help rectify bogus player objects when
138  * ingame joining
139  * 
140  * 67    5/23/98 3:16p Allender
141  * work on object update packet optimizations (a new updating system).
142  * Don't allow medals/promotions/badges when playing singple player
143  * missions through the simulator
144  * 
145  * 66    5/22/98 9:35p Dave
146  * Put in channel based support for PXO. Put in "shutdown" button for
147  * standalone. UI tweaks for TvT
148  * 
149  * 65    5/21/98 10:03p Allender
150  * add secondary ammo counts to ingame join packets
151  * 
152  * 64    5/21/98 1:52a Dave
153  * Remove obsolete command line functions. Reduce shield explosion packets
154  * drastically. Tweak PXO screen even more. Fix file xfer system so that
155  * we can guarantee file uniqueness.
156  * 
157  * 63    5/21/98 12:14a Allender
158  * fix ingame join problems
159  * 
160  * 62    5/20/98 3:25p Allender
161  * ingame join changes (which probably won't make the final version).
162  * Added RAS code into psnet
163  * 
164  * 61    5/19/98 11:36p Allender
165  * fixed very nasty mask problem with ingame joiner marking player objects
166  * incorrectly.  Named ingame joiner ship and observer ship unique names
167  * 
168  * 60    5/19/98 8:35p Dave
169  * Revamp PXO channel listing system. Send campaign goals/events to
170  * clients for evaluation. Made lock button pressable on all screens. 
171  * 
172  * 59    5/18/98 12:41a Allender
173  * fixed subsystem problems on clients (i.e. not reporting properly on
174  * damage indicator).  Fixed ingame join problem with respawns.  minor
175  * comm menu stuff
176  * 
177  * 58    5/15/98 4:12p Allender
178  * removed redbook code.  Put back in ingame join timer.  Major fixups for
179  * stats in multiplayer.  Pass correct score, medals, etc when leaving
180  * game.  Be sure clients display medals, badges, etc.
181  * 
182  * 57    5/15/98 1:44p Allender
183  * initialize hotkeys when entering the mission ingame joining
184  * 
185  * 56    5/11/98 4:33p Allender
186  * fixed ingame join problems -- started to work on new object updating
187  * code (currently ifdef'ed out)
188  * 
189  * 55    5/09/98 4:31p Chad
190  * Fixed weapon recharge rate problem and fixed weapon link status problem
191  * for ingame joiners.
192  * 
193  * 54    5/08/98 11:21a Allender
194  * fix ingame join trouble.  Small messaging fix.  Enable collisions for
195  * friendlies again
196  * 
197  * 53    5/03/98 7:04p Dave
198  * Make team vs. team work mores smoothly with standalone. Change how host
199  * interacts with standalone for picking missions. Put in a time limit for
200  * ingame join ship select. Fix ingame join ship select screen for Vasudan
201  * ship icons.
202  * 
203  * 52    5/03/98 2:52p Dave
204  * Removed multiplayer furball mode.
205  * 
206  * 51    5/02/98 1:47a Dave
207  * Make sure ingame joiners know how many respawns they have left. Tidy up
208  * some multiui stuff.
209  * 
210  * 50    5/01/98 4:11p Comet
211  * Fixed ship_ets bug. I think.
212  * 
213  * 49    4/30/98 12:49a Allender
214  * change ship type and weapons of any player wing ship, not just ones
215  * that players currently occupy
216  * 
217  * 48    4/29/98 9:36p Allender
218  * ingame join tweaks.  added network message for countermeasures
219  * 
220  * 47    4/29/98 12:28p Chad
221  * set packet size when selecting a player's ingame choice
222  * 
223  * 46    4/25/98 2:02p Dave
224  * Put in multiplayer context help screens. Reworked ingame join ship
225  * select screen. Fixed places where network timestamps get hosed.
226  * 
227  * 45    4/23/98 11:52p Allender
228  * make homing weapons send their homing object.  Fixed ingame joiners so
229  * they bash ship types and weapons correctly when joining
230  * 
231  * 44    4/23/98 1:49a Allender
232  * major rearm/repair fixes for multiplayer.  Fixed respawning of AI ships
233  * to not respawn until 5 seconds after they die.  Send escort information
234  * to ingame joiners
235  * 
236  * 43    4/22/98 5:53p Dave
237  * Large reworking of endgame sequencing. Updated multi host options
238  * screen for new artwork. Put in checks for host or team captains leaving
239  * midgame.
240  * 
241  * 42    4/22/98 4:59p Allender
242  * new multiplayer dead popup.  big changes to the comm menu system for
243  * team vs. team.  Start of debriefing stuff for team vs. team  Make form
244  * on my wing work with individual ships who have high priority orders
245  * 
246  * 41    4/21/98 11:56p Dave
247  * Put in player deaths statskeeping. Use arrow keys in the ingame join
248  * ship select screen. Don't quit the game if in the debriefing and server
249  * leaves.
250  * 
251  * 40    4/20/98 12:40a Allender
252  * fixed nasty problem where network read code was not reentrant.  minor
253  * UI tweaks.  ingame joiners now get netgame info correctly.
254  * 
255  * 39    4/07/98 5:42p Dave
256  * Put in support for ui display of voice system status (recording,
257  * playing back, etc). Make sure main hall music is stopped before
258  * entering a multiplayer game via ingame join.
259  * 
260  * 38    4/06/98 6:47p Allender
261  * be sure that ingame joiner has reasonable current primary and secondary
262  * banks
263  * 
264  * 37    4/06/98 12:33a Allender
265  * ingame joiners need to unmark all player ships as could be players
266  * before getting ship information from host.  Don't send count with
267  * countermeasure fired packet
268  * 
269  * 36    4/04/98 4:22p Dave
270  * First rev of UDP reliable sockets is done. Seems to work well if not
271  * overly burdened.
272  * 
273  * 35    4/04/98 3:55p Allender
274  * made ingame join send packet to all other clients in the game when in
275  * game joiner selects his ship
276  * 
277  * 34    4/03/98 1:03a Dave
278  * First pass at unreliable guaranteed delivery packets.
279  * 
280  * 33    4/02/98 5:36p John
281  * Made the level paging occur at the same time as the level is read in.
282  * 
283  * 32    3/31/98 4:03p Allender
284  * some ingame join fixed -- make sure ingame joiners have parse objects
285  * for all other players
286  * 
287  * 31    3/24/98 5:12p Allender
288  * ingame join packet sequencing
289  *
290  * $NoKeywords: $
291  */
292
293 #include <limits.h>
294
295 #include "ai.h"
296 #include "object.h"
297 #include "ship.h"
298 #include "multi.h"
299 #include "multiutil.h"
300 #include "multimsgs.h"
301 #include "multiui.h"
302 #include "missionparse.h"
303 #include "freespace.h"
304 #include "gamesequence.h"
305 #include "2d.h"
306 #include "ui.h"
307 #include "key.h"
308 #include "gamesnd.h"
309 #include "linklist.h"
310 #include "multi_ingame.h"
311 #include "missionscreencommon.h"
312 #include "popup.h"
313 #include "bmpman.h"
314 #include "mouse.h"
315 #include "multi_observer.h"
316 #include "multi_xfer.h"
317 #include "multi_kick.h"
318 #include "missiongoals.h"
319 #include "mainhallmenu.h"
320 #include "stats.h"
321 #include "multiteamselect.h"
322 #include "missionweaponchoice.h"
323 #include "multi_endgame.h"
324 #include "hudescort.h"
325 #include "hudshield.h"
326 #include "objcollide.h"
327 #include "missionhotkey.h"
328 #include "multi_campaign.h"
329 #include "multi_obj.h"
330 #include "alphacolors.h"
331 #include "timer.h"
332
333 // --------------------------------------------------------------------------------------------------
334 // DAVE's BIGASS INGAME JOIN WARNING/DISCLAIMER
335 //
336 // Ingame joining is another delicate system. Although not as delicate as server transfer, it will
337 // help to take as many precautions as possible when handling ingame joins. Please be sure to follow
338 // all the same rules as explained in multi_strans.h
339 //
340 // --------------------------------------------------------------------------------------------------
341
342 // --------------------------------------------------------------------------------------------------
343 // INGAME JOIN DESCRIPTION
344 //
345 // 1.) Joiner sends a JOIN packet to the server
346 // 2.) If the server accepts him, he receives an ACCEPT packet in return
347 // 3.) The client then moves into the INGAME_SYNC state to begin receiving data from the server
348 // 4.) The first thing he does on this screen is send his filesig packet to the server. At which 
349 //     point the server will either let him in or deny him. There are no file transfers ingame.
350 // 5.) The server calls multi_handle_ingame_joiners() once per frame, through multi_do_frame()
351 // 6.) After verifiying or kicking the player because of his file signature, the server tells the
352 //     player to load the mission
353 // 7.) When the mission is loaded, the server, sends a netgame update to the client
354 // 8.) Without waiting, the server then begins sending data ship packets to the player
355 // 9.) Upon confirmation of receiving these packets, the server sends wing data packets
356 // 10.) Upon completion of this, the server sends respawn point packets
357 // 11.) Upon completion of this, the server sends a post briefing data block packet containing ship class and 
358 //      weapon information
359 // 12.) After this, the server sends a player settings packet (to all players for good measure)
360 // 13.) At this point, the server sends a jump into mission packet
361 // 14.) Upon receipt of this packet, the client moves into the ingame ship select state
362 // 15.) The first thing the client does in this state is load the mission data (textures, etc)
363 // 16.) The player is presented with a list of ships he can choose from. He selects one and sends
364 //      an INGAME_SHIP_REQUEST to the server. 
365 // 17.) The server checks to see if this request is acceptable and sends an INGAME_SHIP_REQUEST back
366 //      with the appropriate data.
367 // 18.) If the client received an affirmative, he selects the ship and jumps into the mission, otherwise
368 //      he removes it from the list and tries for another ship
369 // --------------------------------------------------------------------------------------------------
370
371
372 LOCAL   int     Ingame_ships_deleted = 0;
373 LOCAL   int     Ingame_ships_to_delete[MAX_SHIPS];
374
375
376 // --------------------------------------------------------------------------------------------------
377 // INGAME JOIN FORWARD DECLARATIONS
378 //
379
380 void multi_ingame_send_ship_update(net_player *p);
381
382 void multi_ingame_join_check_buttons();
383 void multi_ingame_join_button_pressed(int n);
384
385
386
387 // --------------------------------------------------------------------------------------------------
388 // INGAME JOIN COMMON DEFINITIONS
389 //
390
391
392 // --------------------------------------------------------------------------------------------------
393 // INGAME JOIN SERVER FUNCTIONS
394 //
395
396 // called on the server to process ingame joiners and move them through the motions of ingame joining
397 void multi_handle_ingame_joiners()
398 {
399         int idx;
400
401         Assert( MULTIPLAYER_MASTER );
402
403         // if my ingame joining flag isn't set, then don't do anything.
404         if ( !(Netgame.flags & NG_FLAG_INGAME_JOINING) ){
405                 return;
406         }
407
408         // traverse through all the players
409         for(idx = 0; idx<MAX_PLAYERS; idx++){
410                 // only process ingame joiners
411                 if( !(Net_players[idx].flags & NETINFO_FLAG_RELIABLE_CONNECTED) || !(Net_players[idx].flags & NETINFO_FLAG_INGAME_JOIN)){
412                         continue;
413                 }
414                 
415                 // if we're waiting for players to receive files, then check on their status
416                 if(Net_players[idx].s_info.ingame_join_flags & INGAME_JOIN_FLAG_FILE_XFER){                                             
417                         switch(multi_xfer_get_status(Net_players[idx].s_info.xfer_handle)){
418                         // if it has successfully completed, set his ok flag
419                         case MULTI_XFER_SUCCESS :
420                                 // set his ok flag
421                                 Net_players[idx].flags |= NETINFO_FLAG_MISSION_OK;
422
423                                 // release the xfer instance handle
424                                 multi_xfer_release_handle(Net_players[idx].s_info.xfer_handle);
425                                 Net_players[idx].s_info.xfer_handle = -1;
426                                 break;
427                         // if it has failed or timed-out, kick the player
428                         case MULTI_XFER_TIMEDOUT:
429                         case MULTI_XFER_FAIL:
430                                 // release the xfer handle
431                                 multi_xfer_release_handle(Net_players[idx].s_info.xfer_handle);
432                                 Net_players[idx].s_info.xfer_handle = -1;
433                                                 
434                                 // kick the loser
435                                 multi_kick_player(idx, 0, KICK_REASON_BAD_XFER);
436                                 break;
437                         }                                               
438                 }               
439                 
440                 // if the player has verified his file signature then send him the packet to load the mission and mark this down
441                 if((Net_players[idx].flags & NETINFO_FLAG_MISSION_OK) && !(Net_players[idx].s_info.ingame_join_flags & INGAME_JOIN_FLAG_LOADING_MISSION)){
442                         // send the netgame update here as well
443                         send_netgame_update_packet(&Net_players[idx]);
444                         send_netplayer_update_packet(&Net_players[idx]);
445
446                         // send the packet and mark it down
447                         send_netplayer_load_packet(&Net_players[idx]);                  
448                         Net_players[idx].s_info.ingame_join_flags |= INGAME_JOIN_FLAG_LOADING_MISSION;                                          
449                 }
450
451                 // once he has finished loading the mission, start sending him ship data packets and mark this down
452                 if((Net_players[idx].state == NETPLAYER_STATE_MISSION_LOADED) && !(Net_players[idx].s_info.ingame_join_flags & INGAME_JOIN_FLAG_SENDING_SHIPS)){
453                         int i;
454
455                         // send the packet and mark it down
456                         for (i = 0; i < Num_teams; i++ ) {
457                                 if(Game_mode & GM_STANDALONE_SERVER){
458                                         send_wss_slots_data_packet(i, 1, &Net_players[idx], 0);
459                                 } else {
460                                         send_wss_slots_data_packet(i, 1, &Net_players[idx]);
461                                 }
462                         }
463
464                         // mark the netgame as a critical stage in ingame joining so that I don't evaluate mission event/
465                         // goals, ship arrivals, etc.
466                         Netgame.flags |= NG_FLAG_INGAME_JOINING_CRITICAL;
467
468                         // send the packet and mark it down
469                         send_ingame_ships_packet(&Net_players[idx]);
470                         Net_players[idx].s_info.ingame_join_flags |= INGAME_JOIN_FLAG_SENDING_SHIPS;
471                 }
472
473                 // once he has finished receiving the ship data, start sending him wing data and mark this down
474                 /*
475                 if((Net_players[idx].state == NETPLAYER_STATE_INGAME_SHIPS) && !(Net_players[idx].s_info.ingame_join_flags & INGAME_JOIN_FLAG_SENDING_WINGS)){
476                         // setup the list of wings to send
477                         Net_players[idx].s_info.wing_index = 0;
478                         Net_players[idx].s_info.wing_index_backup = 0;
479
480                         // send the packet and mark it down
481                         send_ingame_wings_packet(&Net_players[idx]);
482                         Net_players[idx].s_info.ingame_join_flags |= INGAME_JOIN_FLAG_SENDING_WINGS;
483                 }
484                 */
485
486                 // once he has received the respawn packet, send him the player settings for all the players in the game and mark this down
487                 if((Net_players[idx].state == NETPLAYER_STATE_INGAME_SHIPS) && !(Net_players[idx].s_info.ingame_join_flags & INGAME_JOIN_FLAG_SENDING_POST)){
488                         // reset the critical ingame joining flag so that I as server, will start evaluating mission
489                         // things again
490                         Netgame.flags &= ~NG_FLAG_INGAME_JOINING_CRITICAL;
491
492                         // send the packet and mark it down
493                         if(Game_mode & GM_STANDALONE_SERVER){
494                                 send_post_sync_data_packet(&Net_players[idx],0);
495                         } else {
496                                 send_post_sync_data_packet(&Net_players[idx]);
497                         }
498                         Net_players[idx].s_info.ingame_join_flags |= INGAME_JOIN_FLAG_SENDING_POST;
499                 }                               
500
501                 // once the settings have been received, send him the jump into mission packet and mark this down. now the joiner
502                 // moves into the ship select state (ingame)
503                 if((Net_players[idx].state == NETPLAYER_STATE_POST_DATA_ACK) && !(Net_players[idx].s_info.ingame_join_flags & INGAME_JOIN_FLAG_PICK_SHIP)){                     
504                         // if this guy is an obsever, create his observer object and be done!
505                         if(Net_players[idx].flags & NETINFO_FLAG_OBSERVER){
506                                 multi_obs_create_observer(&Net_players[idx]);
507                                 Net_players[idx].flags &= ~(NETINFO_FLAG_INGAME_JOIN);
508                                 Netgame.flags &= ~(NG_FLAG_INGAME_JOINING_CRITICAL | NG_FLAG_INGAME_JOINING);
509                         }
510                 
511                         // send the packet and mark it down
512                         send_jump_into_mission_packet(&Net_players[idx]);
513                         Net_players[idx].s_info.ingame_join_flags |= INGAME_JOIN_FLAG_PICK_SHIP;
514                 }
515
516                 // check to see if his timestamp for ship update (hull, shields, etc) has popped. If so, send some info and reset
517                 if(timestamp_elapsed(Net_players[idx].s_info.last_full_update_time)){
518                         // send the ships
519                         multi_ingame_send_ship_update(&Net_players[idx]);
520
521                         // reset the timestamp
522                         Net_players[idx].s_info.last_full_update_time = timestamp(INGAME_SHIP_UPDATE_TIME);
523                 }
524
525                 // once he has received the weapon state packet, send him the player settings for all the players in the game and mark this down
526                 if(!(Net_players[idx].s_info.ingame_join_flags & INGAME_JOIN_FLAG_SENDING_SETS)){                       
527                         // send the packet and mark it down
528                         // this will update _ALL_ players in the game which is important
529                         send_player_settings_packet();
530                         send_player_settings_packet( &Net_players[idx] );               // send directly so he gets the packet
531                 
532                         Net_players[idx].s_info.ingame_join_flags |= INGAME_JOIN_FLAG_SENDING_SETS;
533                 }               
534         }
535 }
536
537 // the final step for an ingame joining observer - create my observer object, unflag myself as joining and jump into mission
538 void multi_ingame_observer_finish()
539 {
540         // create my local observer object
541         multi_obs_create_observer_client();
542
543         // unflag myself as being an ingame joiner
544         Net_player->flags &= ~(NETINFO_FLAG_INGAME_JOIN);
545
546         // set my state to be in-mission
547         Net_player->state = NETPLAYER_STATE_IN_MISSION;
548         send_netplayer_update_packet();
549
550         // jump into the game
551         gameseq_post_event(GS_EVENT_ENTER_GAME);
552 }
553
554 // --------------------------------------------------------------------------------------------------
555 // INGAME DATA SYNC SCREEN 
556 //
557
558 // mission sync screen init function for ingame joining
559 void multi_ingame_sync_init()
560 {       
561         // if we couldn't get the file signature correctly. send some bogus values
562         multi_get_mission_checksum(Game_current_mission_filename);
563         
564         // everyone should re-initialize these 
565         init_multiplayer_stats();
566
567         // reset all sequencing info
568         multi_oo_reset_sequencing();
569
570         // send the file signature to the host for possible mission file transfer
571         strcpy(Netgame.mission_name,Game_current_mission_filename);
572         send_file_sig_packet(Multi_current_file_checksum,Multi_current_file_length);
573         
574         Ingame_ships_deleted = 0;
575 }
576
577 // mission sync screen do function for ingame joining
578 void multi_ingame_sync_do()
579 {       
580 }
581
582 // mission sync screen do function for ingame joining
583 void multi_ingame_sync_close()
584 {
585 }
586
587
588 // --------------------------------------------------------------------------------------------------
589 // INGAME SHIP SELECT SCREEN 
590 //
591 static char *Multi_ingame_join_bitmap_fname[GR_NUM_RESOLUTIONS] = {
592         "MultiIngame",                          // GR_640
593         "2_MultiIngame"                 // GR_1024
594 };
595
596 static char *Multi_ingame_join_bitmap_mask_fname[GR_NUM_RESOLUTIONS] = {
597         "MultiIngame-M",                        // GR_640
598         "2_MultiIngame-M"                       // GR_1024
599 };
600
601
602 // button defs
603 #define MULTI_INGAME_JOIN_NUM_BUTTONS       2
604 #define MIJ_CANCEL              0
605 #define MIJ_JOIN                        1
606
607 ui_button_info Multi_ingame_join_buttons[GR_NUM_RESOLUTIONS][MULTI_INGAME_JOIN_NUM_BUTTONS] = {
608         { // GR_640
609                 ui_button_info( "MIB_00",       532,    434,    510,    413,    0 ),                                            // cancel
610                 ui_button_info( "MIB_01",       572,    428,    585,    413,    1 ),                                            // join
611         },
612         { // GR_1024
613                 ui_button_info( "2_MIB_00",     851,    695,    916,    685,    0 ),                                            // cancel
614                 ui_button_info( "2_MIB_01",     916,    685,    950,    665,    1 ),                                            // join
615         }
616 };
617
618 #define MULTI_INGAME_JOIN_NUM_TEXT                      8
619
620 UI_XSTR Multi_ingame_join_text[GR_NUM_RESOLUTIONS][MULTI_INGAME_JOIN_NUM_TEXT] = {
621         { // GR_640             
622                 {"Cancel",                                                      387,    510,    413,    UI_XSTR_COLOR_PINK, -1, &Multi_ingame_join_buttons[GR_640][MIJ_CANCEL].button}, 
623                 {"Join",                                                                1303,   585,    413,    UI_XSTR_COLOR_PINK, -1, &Multi_ingame_join_buttons[GR_640][MIJ_JOIN].button},
624                 {"Select Ship",                                 317,    39,     6,              UI_XSTR_COLOR_PINK, -1, NULL},
625                 {"name",                                                                1423,   39,     28,     UI_XSTR_COLOR_GREEN, -1, NULL},
626                 {"class",                                                       1424,   145,    28,     UI_XSTR_COLOR_GREEN,    -1, NULL},
627                 {"status",                                                      1425,   214,    28,     UI_XSTR_COLOR_GREEN,    -1, NULL},
628                 {"primary",                                                     1426,   295,    28,     UI_XSTR_COLOR_GREEN, -1, NULL},
629                 {"secondary",                                           1427,   440,    28,     UI_XSTR_COLOR_GREEN, -1, NULL}
630         },
631         { // GR_1024            
632                 {"Cancel",                                                      387,    843,    665,    UI_XSTR_COLOR_PINK, -1, &Multi_ingame_join_buttons[GR_1024][MIJ_CANCEL].button},        
633                 {"Join",                                                                1303,   950,    665,    UI_XSTR_COLOR_PINK, -1, &Multi_ingame_join_buttons[GR_1024][MIJ_JOIN].button},
634                 {"Select Ship",                                 317,    63,     14,     UI_XSTR_COLOR_PINK, -1, NULL},
635                 {"name",                                                                1423,   63,     45,     UI_XSTR_COLOR_GREEN, -1, NULL},
636                 {"class",                                                       1424,   233,    45,     UI_XSTR_COLOR_GREEN,    -1, NULL},
637                 {"status",                                                      1425,   343,    45,     UI_XSTR_COLOR_GREEN,    -1, NULL},
638                 {"primary",                                                     1426,   473,    45,     UI_XSTR_COLOR_GREEN, -1, NULL},
639                 {"secondary",                                           1427,   704,    45,     UI_XSTR_COLOR_GREEN, -1, NULL}
640         }
641 };
642
643 #define MI_FIELD_X              0
644 #define MI_FIELD_Y              1
645 #define MI_FIELD_W              2
646 #define MI_FIELD_H              3
647
648 static int Mi_width[GR_NUM_RESOLUTIONS] = { 
649         569,            // GR_640
650         910             // GR_1024
651 };
652
653 static int Mi_height[GR_NUM_RESOLUTIONS] = {
654         339,            // GR_640
655         542             // GR_1024
656 };
657
658 static int Mi_spacing[GR_NUM_RESOLUTIONS] = {
659         30,
660         48
661 };
662
663 static int Mi_name_field[GR_NUM_RESOLUTIONS][4] = {
664         // GR_640
665         {
666                 33,                     // x
667                 49,                     // y
668                 100,                    // width
669                 339                     // height
670         },
671         // GR_1024
672         {
673                 53,                     // x
674                 78,                     // y
675                 160,                    // width
676                 542                     // height
677         }
678 };
679
680 static int Mi_class_field[GR_NUM_RESOLUTIONS][4] = {
681         // GR_640
682         {
683                 140,                    // x
684                 49,                     // y
685                 59,                     // width
686                 339                     // height
687         },
688         // GR_1024
689         {
690                 224,                    // x
691                 78,                     // y
692                 94,                     // width
693                 542                     // height
694         }
695 };
696
697 static int Mi_status_field[GR_NUM_RESOLUTIONS][4] = {
698         // GR_640
699         {
700                 209,                    // x
701                 49,                     // y
702                 69,                     // width
703                 339                     // height
704         },
705         // GR_1024
706         {
707                 334,                    // x
708                 78,                     // y
709                 110,                    // width
710                 542                     // height
711         }
712 };
713
714 static int Mi_primary_field[GR_NUM_RESOLUTIONS][4] = {
715         // GR_640
716         {
717                 287,                    // x
718                 49,                     // y
719                 145,                    // width
720                 339                     // height
721         },
722         // GR_1024
723         {
724                 459,                    // x
725                 78,                     // y
726                 232,                    // width
727                 542                     // height
728         }
729 };
730
731 static int Mi_secondary_field[GR_NUM_RESOLUTIONS][4] = {
732         // GR_640
733         {
734                 441,                    // x
735                 49,                     // y
736                 145,                    // width
737                 339                     // height
738         },
739         // GR_1024
740         {
741                 706,                    // x
742                 78,                     // y
743                 232,                    // width
744                 542                     // height
745         }
746 };
747
748 // for timing a player out
749 static int Multi_ingame_timer_coords[GR_NUM_RESOLUTIONS][2] = {
750         {
751                 // GR_640
752                 26,
753                 411
754         },
755         {
756                 // GR_1024
757                 42,
758                 658
759         }
760 };
761
762 //#define MULTI_INGAME_TIME_LEFT_X                      26
763 //#define MULTI_INGAME_TIME_LEFT_Y                      411
764
765 #define MULTI_INGAME_TIME_SECONDS               (1000 * 15)
766 LOCAL int Ingame_time_left;
767
768 // uses MULTI_JOIN_REFRESH_TIME as its timestamp
769 UI_WINDOW Multi_ingame_window;                                                                                  // the window object for the join screen
770 UI_BUTTON Multi_ingame_select_button;                                                                   // for selecting list items
771 int Multi_ingame_bitmap;                                                                                                        // the background bitmap
772
773 // ship class icons
774 #define MULTI_INGAME_MAX_SHIP_ICONS                     40
775 typedef struct is_icon {
776         int bmaps[NUM_ICON_FRAMES];
777         int ship_class;
778 } is_icon;
779 is_icon Multi_ingame_ship_icon[MULTI_INGAME_MAX_SHIP_ICONS];
780 int Multi_ingame_num_ship_icons;
781
782 // # of available ships (also == the # currently being displayed)
783 int Multi_ingame_num_avail;
784
785 // signatures for each of the available ships
786 ushort Multi_ingame_ship_sigs[MAX_PLAYERS];
787
788 // net signature of the ship we've requested to grab as an ingame joiner (waiting for server response if >= 0)
789 ushort Multi_ingame_join_sig;
790
791 // the index into the list of the ship currently selected
792 int Multi_ingame_ship_selected;
793
794 // temporary stuff - used only until we come up with a more permanent interface for this screen
795 #define MAX_INGAME_SHIPS 50
796 #define INGAME_FINAL_TIMEOUT 4000
797
798 ushort Ingame_ship_signatures[MAX_INGAME_SHIPS];
799
800 //XSTR:ON
801
802 // local variables to hold ship/obj/ai information for the joiner.  We need to
803 // create a bogus ship so that packets that the joiner receives during his join
804 // have valid Player_ship, Player_obj, and Player_ai to work with
805 int Ingame_shipnum;
806
807 // display the available ships (OF_COULD_BE_PLAYER flagged)
808 void multi_ingame_join_display_avail();
809
810 // try and scroll the selected ship up
811 void multi_ingame_scroll_select_up();
812
813 // try and scroll the selected ship down
814 void multi_ingame_scroll_select_down();
815
816 // handle all timeout details
817 void multi_ingame_handle_timeout();
818
819 int multi_ingame_get_ship_class_icon(int ship_class)
820 {
821         int idx;
822
823         // lookup through all available ship icons
824         for(idx=0;idx<Multi_ingame_num_ship_icons;idx++){
825                 if(Multi_ingame_ship_icon[idx].ship_class == ship_class){
826                         return idx;
827                 }
828         }
829
830         // couldn't find it 
831         return -1;
832 }
833
834 void multi_ingame_load_icons()
835 {
836         int first_frame, num_frames, idx, s_idx;
837
838         // zero out the icon handles    
839         for(idx=0;idx<MULTI_INGAME_MAX_SHIP_ICONS;idx++){
840                 Multi_ingame_ship_icon[idx].ship_class = -1;            
841                 for(s_idx=0;s_idx<NUM_ICON_FRAMES;s_idx++){
842                         Multi_ingame_ship_icon[idx].bmaps[s_idx] = -1;          
843                 }
844         }               
845         Multi_ingame_num_ship_icons = 0;
846
847         // traverse through all ship types
848         for(idx=0;idx<MAX_SHIP_TYPES;idx++){
849                 // if there is a valid icon for this ship
850                 if((strlen(Ship_info[idx].icon_filename) > 0) && (Multi_ingame_num_ship_icons < MULTI_INGAME_MAX_SHIP_ICONS)){
851                         // set the ship class
852                         Multi_ingame_ship_icon[Multi_ingame_num_ship_icons].ship_class = idx;
853
854                         // load in the animation frames for the icon    
855                         first_frame = bm_load_animation(Ship_info[idx].icon_filename, &num_frames);
856                         if ( first_frame == -1 ) {
857                                 Int3(); // Could not load in icon frames.. get Dave
858                         }       
859                         for ( s_idx = 0; s_idx < num_frames; s_idx++ ) {
860                                 Multi_ingame_ship_icon[Multi_ingame_num_ship_icons].bmaps[s_idx] = first_frame+s_idx;
861                         }
862
863                         Multi_ingame_num_ship_icons++;
864                 }
865         }
866 }
867
868 void multi_ingame_unload_icons()
869 {
870         int idx,s_idx;
871
872         // unload all the bitmaps
873         for(idx=0;idx<Multi_ingame_num_ship_icons;idx++){
874                 for(s_idx=0;s_idx<NUM_ICON_FRAMES;s_idx++){
875                         if(Multi_ingame_ship_icon[idx].bmaps[s_idx] != -1){
876                                 bm_release(Multi_ingame_ship_icon[idx].bmaps[s_idx]);
877                                 Multi_ingame_ship_icon[idx].bmaps[s_idx] = -1;
878                         }
879                 }
880         }
881 }
882
883 // ingame join ship selection screen init
884 void multi_ingame_select_init()
885 {
886         /// int objnum, wingnum_save,idx, goals_save;
887         // ushort net_signature;
888         int idx;
889
890         Multi_ingame_join_sig = 0;
891         Net_player->player->objnum = -1;
892
893         // create a ship, then find a ship to copy crucial information from.  Save and restore the wing
894         // number to be safe.
895         /*
896         wingnum_save = Player_start_pobject.wingnum;
897         net_signature = Player_start_pobject.net_signature;
898         goals_save = Player_start_pobject.ai_goals;
899         Player_start_pobject.wingnum = -1;
900         Player_start_pobject.net_signature = 0;
901         Player_start_pobject.ai_goals = -1;
902         objnum = parse_create_object( &Player_start_pobject );
903         Player_start_pobject.wingnum = wingnum_save;
904         Player_start_pobject.net_signature = net_signature;
905         Player_start_pobject.ai_goals = goals_save;
906
907         if ( objnum == -1 ) {
908                 nprintf(("Network", "Bailing ingame join because unable to create parse object player ship\n"));
909                 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_INGAME_SHIP);
910                 return;
911         }
912
913         // make it invalid
914         Player_obj = &Objects[objnum];
915         Player_obj->net_signature = 0;                                          
916         Player_ship = &Ships[Player_obj->instance];
917         strcpy(Player_ship->ship_name, NOX("JIP Ship"));
918         Player_ai = &Ai_info[Player_ship->ai_index];
919         */
920
921         // load the temp ship icons
922         multi_ingame_load_icons();
923
924         // blast all the ingame ship signatures
925         memset(Multi_ingame_ship_sigs,0,sizeof(ushort) * MAX_PLAYERS);
926
927         // the index into the list of the ship currently selected
928         Multi_ingame_ship_selected = -1;
929
930         // initialize the time he has left to select a ship
931         Ingame_time_left = timestamp(MULTI_INGAME_TIME_SECONDS);
932
933         // initialize GUI data  
934
935         // create the interface window
936         Multi_ingame_window.create(0,0,gr_screen.max_w,gr_screen.max_h,0);
937         Multi_ingame_window.set_mask_bmap(Multi_ingame_join_bitmap_mask_fname[gr_screen.res]);
938
939         // load the background bitmap
940         Multi_ingame_bitmap = bm_load(Multi_ingame_join_bitmap_fname[gr_screen.res]);
941         if(Multi_ingame_bitmap < 0)
942                 Error(LOCATION, "Couldn't load background bitmap for ingame join");     
943         
944         // create the interface buttons
945         for(idx=0; idx<MULTI_INGAME_JOIN_NUM_BUTTONS; idx++) {
946                 // create the object
947                 Multi_ingame_join_buttons[gr_screen.res][idx].button.create(&Multi_ingame_window, "", Multi_ingame_join_buttons[gr_screen.res][idx].x, Multi_ingame_join_buttons[gr_screen.res][idx].y, 1, 1, 0, 1);
948
949                 // set the sound to play when highlighted
950                 Multi_ingame_join_buttons[gr_screen.res][idx].button.set_highlight_action(common_play_highlight_sound);
951
952                 // set the ani for the button
953                 Multi_ingame_join_buttons[gr_screen.res][idx].button.set_bmaps(Multi_ingame_join_buttons[gr_screen.res][idx].filename);
954
955                 // set the hotspot
956                 Multi_ingame_join_buttons[gr_screen.res][idx].button.link_hotspot(Multi_ingame_join_buttons[gr_screen.res][idx].hotspot);
957         }       
958         
959         // create all xstrs
960         for(idx=0; idx<MULTI_INGAME_JOIN_NUM_TEXT; idx++) {
961                 Multi_ingame_window.add_XSTR(&Multi_ingame_join_text[gr_screen.res][idx]);
962         }
963
964         // create the list item select button
965         Multi_ingame_select_button.create(&Multi_ingame_window, "", Mi_name_field[gr_screen.res][MI_FIELD_X], Mi_name_field[gr_screen.res][MI_FIELD_Y], Mi_width[gr_screen.res], Mi_height[gr_screen.res], 0, 1);
966         Multi_ingame_select_button.hide();                      
967
968         // load freespace stuff
969         // JAS: Code to do paging used to be here.
970 }
971
972 // process all ship list related details
973 void multi_ingame_ship_list_process()
974 {
975         int select_index,y;
976
977         // if we currently don't have any ships selected, but we've got items on the list, select the first one
978         if((Multi_ingame_ship_selected == -1) && (Multi_ingame_num_avail > 0)){
979                 gamesnd_play_iface(SND_USER_SELECT);
980                 Multi_ingame_ship_selected = 0;
981         }
982
983         // if we currently have a ship selected, but it disappears, select the next ship (is possible0
984         if((Multi_ingame_ship_selected >= 0) && (Multi_ingame_ship_selected >= Multi_ingame_num_avail)){
985                 gamesnd_play_iface(SND_USER_SELECT);
986                 Multi_ingame_ship_selected = Multi_ingame_num_avail-1;
987         }
988         
989         // if the player clicked on the select button, see if the selection has changed
990         if(Multi_ingame_select_button.pressed()){
991                 Multi_ingame_select_button.get_mouse_pos(NULL,&y);
992                 select_index = y / Mi_spacing[gr_screen.res];
993
994                 // if we've selected a valid item
995                 if((select_index >= 0) && (select_index < Multi_ingame_num_avail)){
996                         // if we're not selected the same item, play a sound
997                         if(Multi_ingame_ship_selected != select_index){
998                                 gamesnd_play_iface(SND_USER_SELECT);
999                         }
1000
1001                         // select the item
1002                         Multi_ingame_ship_selected = select_index;
1003                 }
1004         }
1005 }
1006
1007
1008 // determines if a button was pressed, and acts accordingly
1009 void multi_ingame_join_check_buttons()
1010 {
1011         int idx;
1012         for(idx=0; idx<MULTI_INGAME_JOIN_NUM_BUTTONS; idx++) {
1013                 // we only really need to check for one button pressed at a time,
1014                 // so we can break after finding one.
1015                 if(Multi_ingame_join_buttons[gr_screen.res][idx].button.pressed()) {
1016                         multi_ingame_join_button_pressed(idx);
1017                         break;
1018                 }
1019         }
1020 }
1021
1022 // a button was pressed, so make it do its thing
1023 // this is the "acting accordingly" part
1024 void multi_ingame_join_button_pressed(int n)
1025 {
1026         switch(n) {
1027         case MIJ_CANCEL:
1028                 multi_quit_game(PROMPT_CLIENT);
1029                 break;
1030         case MIJ_JOIN:
1031                 // don't do further processing if the game is paused
1032                 if ( Netgame.game_state == NETGAME_STATE_PAUSED )
1033                         return;
1034
1035                 if(Multi_ingame_join_sig == 0) {
1036                         // if he has a valid ship selected
1037                         if(Multi_ingame_ship_selected >= 0) {
1038                                 gamesnd_play_iface(SND_USER_SELECT);
1039                         
1040                                 // select the sig of this ship and send a request for it
1041                                 Multi_ingame_join_sig = Multi_ingame_ship_sigs[Multi_ingame_ship_selected];
1042                                 
1043                                 // send a request to the
1044                                 send_ingame_ship_request_packet(INGAME_SR_REQUEST,Multi_ingame_join_sig);
1045                         } else {
1046                                 gamesnd_play_iface(SND_GENERAL_FAIL);
1047                         }
1048                 } else {
1049                         gamesnd_play_iface(SND_GENERAL_FAIL);
1050                 }
1051
1052                 break;
1053         default:
1054                 // how the hell did this happen?
1055                 Int3();
1056         }
1057 }
1058
1059
1060 // ingame join ship selection screen do
1061 void multi_ingame_select_do()
1062 {       
1063         int k = Multi_ingame_window.process();
1064
1065         // process any keypresses
1066         switch(k){
1067         case KEY_ESC :
1068                 multi_quit_game(PROMPT_CLIENT);         
1069                 break;
1070
1071         case KEY_UP:
1072                 multi_ingame_scroll_select_up();
1073                 break;
1074
1075         case KEY_DOWN:
1076                 multi_ingame_scroll_select_down();
1077                 break;
1078         }       
1079
1080         // process button presses
1081         // multi_ingame_process_buttons();
1082         multi_ingame_join_check_buttons();
1083         
1084         // process any ship list related events
1085         multi_ingame_ship_list_process();       
1086         
1087         // draw the background, etc
1088         gr_reset_clip();        
1089         GR_MAYBE_CLEAR_RES(Multi_ingame_bitmap);
1090         if(Multi_ingame_bitmap != -1){
1091                 gr_set_bitmap(Multi_ingame_bitmap);
1092                 gr_bitmap(0,0);
1093         }
1094         Multi_ingame_window.draw();
1095
1096         // handle all timeout details. blitting, etc
1097         multi_ingame_handle_timeout();
1098
1099         // display the available ships
1100         multi_ingame_join_display_avail();              
1101
1102         // flip the buffer
1103         gr_flip();      
1104 }
1105
1106 // ingame join ship select close
1107 void multi_ingame_select_close()
1108 {       
1109         // unload any bitmaps
1110         if(!bm_unload(Multi_ingame_bitmap)){
1111                 nprintf(("General","WARNING : could not unload background bitmap %s\n",Multi_ingame_join_bitmap_fname[gr_screen.res]));
1112         }       
1113
1114         // unload all the ship class icons
1115         multi_ingame_unload_icons();
1116         
1117         // destroy the UI_WINDOW
1118         Multi_ingame_window.destroy();  
1119
1120         // stop main hall music
1121         main_hall_stop_music(); 
1122 }
1123
1124 // display an individual ships information, starting at the indicated y pixel value
1125 void multi_ingame_join_display_ship(object *objp,int y_start)
1126 {
1127         int icon_num,idx;
1128         ship_info *sip;
1129         int y_spacing;
1130         ship_weapon *wp;
1131
1132         sip = &Ship_info[Ships[objp->instance].ship_info_index];
1133         
1134         // blit the ship name itself
1135         gr_set_color_fast(&Color_normal);
1136         gr_string(Mi_name_field[gr_screen.res][MI_FIELD_X],y_start+10, Ships[objp->instance].ship_name);
1137         
1138         // blit the ship class icon
1139         icon_num = multi_ingame_get_ship_class_icon(Ships[objp->instance].ship_info_index);
1140         if(icon_num != -1){
1141                 gr_set_bitmap(Multi_ingame_ship_icon[icon_num].bmaps[0]);
1142                 gr_bitmap(Mi_class_field[gr_screen.res][MI_FIELD_X] + 15, y_start);
1143         }
1144         
1145         gr_set_color_fast(&Color_bright);
1146         wp = &Ships[objp->instance].weapons;
1147         
1148         // blit the ship's primary weapons      
1149         y_spacing = (Mi_spacing[gr_screen.res] - (wp->num_primary_banks * 10)) / 2;
1150         for(idx=0;idx<wp->num_primary_banks;idx++){
1151                 gr_string(Mi_primary_field[gr_screen.res][MI_FIELD_X], y_start + y_spacing + (idx * 10), Weapon_info[wp->primary_bank_weapons[idx]].name);
1152         }
1153
1154         // blit the ship's secondary weapons    
1155         y_spacing = (Mi_spacing[gr_screen.res] - (wp->num_secondary_banks * 10)) / 2;
1156         for(idx=0;idx<wp->num_secondary_banks;idx++){
1157                 gr_string(Mi_secondary_field[gr_screen.res][MI_FIELD_X], y_start + y_spacing + (idx * 10), Weapon_info[wp->secondary_bank_weapons[idx]].name);
1158         }       
1159
1160         // blit the shield/hull integrity
1161         hud_shield_show_mini(objp, Mi_status_field[gr_screen.res][MI_FIELD_X] + 15, y_start + 3,5,7);
1162 }
1163
1164 // display the available ships (OF_COULD_BE_PLAYER flagged)
1165 void multi_ingame_join_display_avail()
1166 {               
1167         ship_obj *moveup;       
1168
1169         // recalculate this # every frame
1170         Multi_ingame_num_avail = 0;     
1171
1172         // display a background highlight rectangle for any selected lines
1173         if(Multi_ingame_ship_selected != -1){           
1174                 int y_start = (Mi_name_field[gr_screen.res][MI_FIELD_Y] + (Multi_ingame_ship_selected * Mi_spacing[gr_screen.res]));            
1175
1176                 // draw the border
1177                 gr_set_color_fast(&Color_bright_blue);
1178                 gr_line(Mi_name_field[gr_screen.res][MI_FIELD_X]-1,y_start-1, (Mi_name_field[gr_screen.res][MI_FIELD_X]-1) + (Mi_width[gr_screen.res]+2),y_start-1);
1179                 gr_line(Mi_name_field[gr_screen.res][MI_FIELD_X]-1,y_start + Mi_spacing[gr_screen.res] - 2, (Mi_name_field[gr_screen.res][MI_FIELD_X]-1) + (Mi_width[gr_screen.res]+2),y_start + Mi_spacing[gr_screen.res] - 2);
1180                 gr_line(Mi_name_field[gr_screen.res][MI_FIELD_X]-1,y_start, Mi_name_field[gr_screen.res][MI_FIELD_X]-1, y_start + Mi_spacing[gr_screen.res] - 2);
1181                 gr_line((Mi_name_field[gr_screen.res][MI_FIELD_X]-1) + (Mi_width[gr_screen.res]+2), y_start,(Mi_name_field[gr_screen.res][MI_FIELD_X]-1) + (Mi_width[gr_screen.res]+2),y_start + Mi_spacing[gr_screen.res] - 2);
1182         }
1183
1184         moveup = GET_FIRST(&Ship_obj_list);     
1185         while(moveup != END_OF_LIST(&Ship_obj_list)){
1186                 if( !(Ships[Objects[moveup->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) && (Objects[moveup->objnum].flags & OF_COULD_BE_PLAYER) ) {
1187                         // display the ship
1188                         multi_ingame_join_display_ship(&Objects[moveup->objnum],Mi_name_field[gr_screen.res][MI_FIELD_Y] + (Multi_ingame_num_avail * Mi_spacing[gr_screen.res]));
1189
1190                         // set the ship signature
1191                         Multi_ingame_ship_sigs[Multi_ingame_num_avail] = Objects[moveup->objnum].net_signature;
1192                         
1193                         // inc the # available
1194                         Multi_ingame_num_avail++;
1195                 }
1196                 moveup = GET_NEXT(moveup);
1197         }               
1198 }
1199
1200 // try and scroll the selected ship up
1201 void multi_ingame_scroll_select_up()
1202 {
1203         if(Multi_ingame_ship_selected > 0){
1204                 gamesnd_play_iface(SND_USER_SELECT);
1205                 Multi_ingame_ship_selected--;
1206         } else {
1207                 gamesnd_play_iface(SND_GENERAL_FAIL);
1208         }       
1209 }
1210
1211 // try and scroll the selected ship down
1212 void multi_ingame_scroll_select_down()
1213 {
1214         if(Multi_ingame_ship_selected < (Multi_ingame_num_avail - 1)){
1215                 gamesnd_play_iface(SND_USER_SELECT);
1216                 Multi_ingame_ship_selected++;
1217         } else {
1218                 gamesnd_play_iface(SND_GENERAL_FAIL);
1219         }
1220 }
1221
1222 // handle all timeout details
1223 void multi_ingame_handle_timeout()
1224 {
1225         /*
1226         // uncomment this block to disable the timer
1227         gr_set_color_fast(&Color_bright_red);
1228         gr_string(Multi_ingame_timer_coords[gr_screen.res][0], Multi_ingame_timer_coords[gr_screen.res][1], "Timer disabled!!");
1229         return;
1230         */
1231
1232         // if we've timed out, leave the game
1233         if( timestamp_elapsed(Ingame_time_left) ) {
1234                 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_INGAME_TIMEOUT, MULTI_END_ERROR_NONE);
1235                 return;
1236         }
1237
1238         // otherwise, blit how much time we have left
1239         int time_left = timestamp_until(Ingame_time_left) / 1000;
1240         char tl_string[100];
1241         gr_set_color_fast(&Color_bright);
1242         memset(tl_string,0,100);
1243         sprintf(tl_string,XSTR("Time remaining : %d s\n",682),time_left);       
1244         gr_string(Multi_ingame_timer_coords[gr_screen.res][0], Multi_ingame_timer_coords[gr_screen.res][1], tl_string);
1245 }
1246
1247
1248 // --------------------------------------------------------------------------------------------------
1249 // PACKET HANDLER functions
1250 // these are also defined in multimsgs.h, but the implementations are in the module for the sake of convenience
1251 //
1252
1253 #define INGAME_PACKET_SLOP              75                              // slop value used for packets to ingame joiner
1254
1255 void process_ingame_ships_packet( ubyte *data, header *hinfo )
1256 {
1257         int offset, sflags, oflags, team, j;
1258         ubyte p_type;
1259         ushort net_signature;   
1260         short wing_data;        
1261         int team_val, slot_index, idx;
1262         char ship_name[255] = "";
1263         object *objp;
1264         int net_sig_modify;
1265
1266         // go through the ship obj list and delete everything. YEAH
1267         if(!Ingame_ships_deleted){
1268                 int idx;
1269
1270                 // no player object
1271                 Player_obj = NULL;
1272                 Player_ship = NULL;
1273                 Player_ai = NULL;
1274
1275                 // delete all ships
1276                 for(idx=0; idx<MAX_SHIPS; idx++){
1277                         if((Ships[idx].objnum >= 0) && (Ships[idx].objnum < MAX_OBJECTS)){
1278                                 obj_delete(Ships[idx].objnum);
1279                         }
1280                 }
1281
1282                 Ingame_ships_deleted = 1;
1283         }
1284
1285         offset = HEADER_LENGTH;
1286
1287         // go
1288         GET_DATA( p_type );     
1289         while ( p_type == INGAME_SHIP_NEXT ) {
1290                 p_object *p_objp;
1291                 int ship_num, objnum;
1292
1293                 GET_STRING( ship_name );
1294                 GET_DATA( net_signature );
1295                 GET_DATA( sflags );
1296                 GET_DATA( oflags );
1297                 GET_DATA( team );               
1298                 GET_DATA( wing_data );
1299                 net_sig_modify = 0;
1300                 if(wing_data >= 0){
1301                         GET_DATA(Wings[wing_data].current_wave);                        
1302                         net_sig_modify = Wings[wing_data].current_wave - 1;
1303                 }
1304
1305                 // lookup ship in the original ships array
1306                 p_objp = mission_parse_get_original_ship(net_signature);
1307                 if(p_objp == NULL){
1308                         // if this ship is part of wing not on its current wave, look for its "original" by subtracting out wave #
1309                         p_objp = mission_parse_get_arrival_ship((ushort)(net_signature - (ushort)net_sig_modify));
1310                 }
1311                 if(p_objp == NULL){
1312                         Int3();
1313                         nprintf(("Network", "Couldn't find ship %s in either arrival list or in mission"));
1314                         multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_INGAME_BOGUS);
1315                         return;
1316                 }
1317
1318                 // go ahead and create the parse object.  Set the network signature of this guy before
1319                 // creation
1320                 // multi_set_network_signature( net_signature, MULTI_SIG_SHIP );
1321                 objnum = parse_create_object( p_objp );
1322                 ship_num = Objects[objnum].instance;
1323                 Objects[objnum].flags = oflags;
1324                 Objects[objnum].net_signature = net_signature;
1325
1326                 // assign any common data
1327                 strcpy(Ships[ship_num].ship_name, ship_name);
1328                 Ships[ship_num].flags = sflags;
1329                 Ships[ship_num].team = team;
1330                 Ships[ship_num].wingnum = (int)wing_data;                               
1331
1332                 GET_DATA( p_type );
1333         }
1334
1335         PACKET_SET_SIZE();
1336
1337         // if we have reached the end of the list and change our network state
1338         if ( p_type == INGAME_SHIP_LIST_EOL ) {         
1339                 // merge all created list
1340                 obj_merge_created_list();
1341
1342                 // fixup player ship stuff
1343                 for(idx=0; idx<MAX_SHIPS; idx++){
1344                         if(Ships[idx].objnum < 0){      
1345                                 continue;
1346                         }
1347
1348                         // get the team and slot.  Team will be -1 when it isn't a part of player wing.  So, if
1349                         // not -1, then be sure we have a valid slot, then change the ship type, etc.
1350                         objp = &Objects[Ships[idx].objnum];             
1351                         multi_ts_get_team_and_slot(Ships[idx].ship_name, &team_val, &slot_index);
1352                         if ( team_val != -1 ) {
1353                                 Assert( slot_index != -1 );
1354
1355                                 // change the ship type and the weapons
1356                                 change_ship_type(objp->instance, Wss_slots_teams[team_val][slot_index].ship_class);
1357                                 wl_bash_ship_weapons(&Ships[idx].weapons, &Wss_slots_teams[team_val][slot_index]);
1358         
1359                                 // Be sure to mark this ship as as a could_be_player
1360                                 obj_set_flags( objp, objp->flags | OF_COULD_BE_PLAYER );
1361                                 objp->flags &= ~OF_PLAYER_SHIP;
1362                         }
1363
1364                         // if this is a player ship, make sure we find out who's it is and set their objnum accordingly
1365                         if(team_val != -1){
1366                                 for( j = 0; j < MAX_PLAYERS; j++){
1367                                         if(MULTI_CONNECTED(Net_players[j]) && (Net_players[j].player->objnum == Objects[Ships[idx].objnum].net_signature)) {                                            
1368                                                 // nprintf(("Network", "Making %s ship for %s\n", Ships[shipnum].ship_name, Net_players[j].player->callsign));
1369                                                 multi_assign_player_ship( j, objp, Ships[idx].ship_info_index );
1370                                                 objp->flags |= OF_PLAYER_SHIP;
1371                                                 objp->flags &= ~OF_COULD_BE_PLAYER;
1372                                                 break;
1373                                         }
1374                                 }
1375                         }
1376                 }
1377
1378                 // notify the server that we're all good.
1379                 Net_player->state = NETPLAYER_STATE_INGAME_SHIPS;
1380                 send_netplayer_update_packet();
1381
1382                 // add some mission sync text
1383                 multi_common_add_text(XSTR("Ships packet ack (ingame)\n",683));
1384         }
1385 }
1386
1387 void send_ingame_ships_packet(net_player *player)
1388 {
1389         ubyte data[MAX_PACKET_SIZE];
1390         ubyte p_type;
1391         ship_obj *so;
1392         int packet_size;
1393         short wing_data;
1394
1395         BUILD_HEADER( SHIPS_INGAME_PACKET );
1396
1397         // essentially, we are going to send a list of ship names to the joiner for ships that are not
1398         // in wings.  The joiner will take the list, create any ships which should be created, and delete all
1399         // other ships after the list is sent.
1400         for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
1401                 ship *shipp;
1402
1403                 shipp = &Ships[Objects[so->objnum].instance];
1404
1405                 // skip all wings.
1406                 // if ( shipp->wingnum != -1 ){
1407                         // continue;
1408                 // }
1409
1410                 if ( Objects[so->objnum].net_signature == STANDALONE_SHIP_SIG ){
1411                         continue;
1412                 }
1413
1414                 //  add the ship name and other information such as net signature, ship and object(?) flags.
1415                 p_type = INGAME_SHIP_NEXT;
1416                 ADD_DATA( p_type );
1417                 ADD_STRING( shipp->ship_name );
1418                 ADD_DATA( Objects[so->objnum].net_signature );
1419                 ADD_DATA( shipp->flags );
1420                 ADD_DATA( Objects[so->objnum].flags );
1421                 ADD_DATA( shipp->team );
1422                 wing_data = (short)shipp->wingnum;
1423                 ADD_DATA(wing_data);
1424                 if(wing_data >= 0){
1425                         ADD_DATA(Wings[wing_data].current_wave);
1426                 }
1427
1428                 // don't send anymore data if we are getting close to the maximum size of this packet.  Send it off and
1429                 // keep going
1430                 if ( packet_size > (MAX_PACKET_SIZE - INGAME_PACKET_SLOP) ) {
1431                         p_type = INGAME_SHIP_LIST_EOP;
1432                         ADD_DATA( p_type );                     
1433                         multi_io_send_reliable(player, data, packet_size);
1434                         BUILD_HEADER( SHIPS_INGAME_PACKET );
1435                 }
1436         }
1437
1438         // end of the ship list!!!
1439         p_type = INGAME_SHIP_LIST_EOL;
1440         ADD_DATA( p_type );     
1441         multi_io_send_reliable(player, data, packet_size);
1442 }
1443
1444 void process_ingame_wings_packet( ubyte *data, header *hinfo )
1445 {
1446         Int3();
1447 }
1448 /*
1449 // code to process the wing data from a server.
1450 void process_ingame_wings_packet( ubyte *data, header *hinfo )
1451 {
1452         int offset, wingnum;
1453         ubyte p_type, what;
1454
1455         offset = HEADER_LENGTH;
1456
1457         GET_DATA( p_type );
1458
1459         // p_type tells us whether to stop or not
1460         while ( p_type == INGAME_WING_NEXT ) {
1461                 wing *wingp;
1462
1463                 // get the wingnum and a pointer to it.  The game stores data for all wings always, so this
1464                 // is perfectly valid
1465                 GET_DATA( wingnum );
1466                 wingp = &Wings[wingnum];
1467
1468                 GET_DATA( what );
1469                 if ( what == INGAME_WING_NOT_ARRIVED ) {
1470                         Assert( wingp->total_arrived_count == 0 );                      // this had better be true!!!
1471                 } else if ( what == INGAME_WING_DEPARTED ) {
1472                         // mark the wing as gone.  if it isn't, it soon will be.  Maybe we should send more information
1473                         // about these wings later (like total_arrived_count, etc), but we will see.
1474                         wingp->flags |= WF_WING_GONE;
1475                 } else {
1476                         int total_arrived_count, current_count, current_wave, i, j;
1477                         ushort signature;
1478                         int shipnum;
1479
1480                         // the wing is present in the mission on the server.  Get the crucial information about the
1481                         // wing.  Then get the ships for this wing in order on the client machine
1482                         GET_DATA( total_arrived_count );
1483                         GET_DATA( current_count );
1484                         GET_DATA( current_wave );
1485
1486                         Assert( current_wave > 0 );
1487                         Assert( total_arrived_count > 0 );
1488
1489                         // for this wing, strip it down to nothing.  Let the parse object ocde recreate the
1490                         // wing from the parse objects, then bash any weapons, etc for player wings.  We need
1491                         // to do this because we might actually wind up with > MAX_SHIPS_PER_WING if we
1492                         // don't delete them all first, and have a > 0 threshold, and are on something other
1493                         // than the first wave.  Only do this for non-player wings.
1494
1495                         nprintf(("Network", "Clearing %s -- %d ships\n", wingp->name, wingp->current_count));
1496                         for ( i = 0; i < wingp->current_count; i++ ) {
1497                                 int index, objnum;
1498
1499                                 index = wingp->ship_index[i];
1500                                 Assert( index != -1 );
1501                                 objnum = Ships[index].objnum;
1502                                 Assert( objnum != -1 );
1503
1504                                 // delete the object since we are filling the wing again anyway.
1505                                 obj_delete( objnum );
1506                                 Objects[objnum].net_signature = 0;                              // makes this object "invalid" until dead.
1507                                 if ( Objects[objnum].type == OBJ_GHOST ) {
1508                                         nprintf(("Network", "Marking ghost objnum %d as dead\n", objnum));
1509                                         Objects[objnum].flags |= OF_SHOULD_BE_DEAD;
1510                                 }
1511                                 Ingame_ships_to_delete[index] = 0;              // be sure that this guy doesn't get deleted, since we already deleted it
1512                                 wingp->ship_index[i] = -1;
1513                         }
1514                         wingp->current_count = 0;
1515                         wingp->total_arrived_count = 0;
1516
1517                         // now, recreate all the ships needed
1518                         for (i = 0; i < current_count; i++ ) {
1519                                 int which_one, team, slot_index, specific_instance;;
1520                                 ship *shipp;
1521                                 object *objp;
1522
1523                                 GET_DATA( signature );
1524
1525                                 // assign which_one to be the given signature - wing's base signature.  This let's us
1526                                 // know which ship to create (i.e. the total_arrivel_count);
1527                                 which_one = signature - wingp->net_signature;
1528                                 Assert( (which_one >= 0) && (which_one < (wingp->net_signature + (wingp->wave_count*wingp->num_waves))) );
1529                                 wingp->total_arrived_count = (ushort)which_one;
1530
1531                                 // determine which ship in the ahip arrival list this guy is.  It is a 0 based index
1532                                 specific_instance = which_one % wingp->wave_count;
1533
1534                                 // call parse_wing_create_ships making sure that we only ever create 1 ship at a time.  We don't
1535                                 // want parse_wing_create_ships() to assign network signature either.  We will directly
1536                                 // assign it here.
1537
1538                                 wingp->current_wave = 0;                                                // make it the first wave.  Ensures that ships don't get removed off the list
1539                                 parse_wing_create_ships( wingp, 1, 1, specific_instance );
1540                                 shipnum = wingp->ship_index[wingp->current_count-1];
1541                                 Ingame_ships_to_delete[shipnum] = 0;                    // "unmark" this ship so it doesn't get deleted.
1542
1543                                 // kind of stupid, but bash the name since it won't get recreated properly from
1544                                 // the parse_wing_create_ships call.
1545                                 shipp = &Ships[shipnum];
1546                                 sprintf(shipp->ship_name, NOX("%s %d"), wingp->name, which_one + 1);
1547                                 nprintf(("Network", "Created %s\n", shipp->ship_name));
1548
1549                                 objp = &Objects[shipp->objnum];
1550                                 objp->net_signature = (ushort)(wingp->net_signature + which_one);
1551
1552                                 // get the team and slot.  Team will be -1 when it isn't a part of player wing.  So, if
1553                                 // not -1, then be sure we have a valid slot, then change the ship type, etc.
1554                                 multi_ts_get_team_and_slot(shipp->ship_name, &team, &slot_index);
1555                                 if ( team != -1 ) {
1556                                         Assert( slot_index != -1 );
1557
1558                                         // change the ship type and the weapons
1559                                         change_ship_type(objp->instance, Wss_slots_teams[team][slot_index].ship_class);
1560                                         wl_bash_ship_weapons(&shipp->weapons,&Wss_slots_teams[team][slot_index]);
1561
1562                                         // Be sure to mark this ship as as a could_be_player
1563                                         obj_set_flags( objp, objp->flags | OF_COULD_BE_PLAYER );
1564                                         objp->flags &= ~OF_PLAYER_SHIP;
1565                                 }
1566
1567                                 // if this is a player ship, make sure we find out who's it is and set their objnum accordingly
1568                                 for( j = 0; j < MAX_PLAYERS; j++){
1569                                         if(MULTI_CONNECTED(Net_players[j]) && (Net_players[j].player->objnum == signature)) {
1570                                                 Assert( team != -1 );           // to help trap errors!!!
1571                                                 nprintf(("Network", "Making %s ship for %s\n", Ships[shipnum].ship_name, Net_players[j].player->callsign));
1572                                                 multi_assign_player_ship( j, objp, Ships[shipnum].ship_info_index );
1573                                                 objp->flags |= OF_PLAYER_SHIP;
1574                                                 objp->flags &= ~OF_COULD_BE_PLAYER;
1575                                                 break;
1576                                         }
1577                                 }
1578                         }
1579
1580
1581                         // we will have no ships in any wings at this point (we didn't create any when we loaded the
1582                         // mission).  Set the current wave of this wing to be 1 less than was passed in since this value
1583                         // will get incremented in parse_wing_create_ships;
1584                         wingp->current_wave = current_wave;
1585                         wingp->total_arrived_count = total_arrived_count;
1586                 }
1587
1588                 GET_DATA( p_type );
1589         }
1590
1591    PACKET_SET_SIZE();
1592
1593         // if we have reached the end of the list change our network state
1594         if ( p_type == INGAME_WING_LIST_EOL ) {
1595                 Net_player->state = NETPLAYER_STATE_INGAME_WINGS;
1596                 send_netplayer_update_packet();
1597
1598                 // add some mission sync text
1599                 multi_common_add_text(XSTR("Wings packet (ingame)\n",684));
1600         }
1601         
1602 }
1603
1604 // function to send information about wings.  We need to send enough information to let the client
1605 // construct or reconstruct any wings in the mission.  We will rely on the fact that the host wing array
1606 // will exactly match the client wing array (in terms of number, and wing names)
1607 void send_ingame_wings_packet( net_player *player )
1608 {
1609         ubyte data[MAX_PACKET_SIZE];
1610         ubyte p_type;
1611         int packet_size, i;
1612         ubyte what;
1613
1614         BUILD_HEADER( WINGS_INGAME_PACKET );
1615
1616         // iterate through the wings list
1617         for ( i = 0; i < num_wings; i++ ) {
1618                 wing *wingp;
1619
1620                 wingp = &Wings[i];
1621
1622                 p_type = INGAME_WING_NEXT;
1623                 ADD_DATA( p_type );
1624
1625                 ADD_DATA( i );
1626
1627                 // add wing data that the client needs.  There are several conditions to send to clients:
1628                 //
1629                 // 1. wing hasn't arrived -- total_arrived_count will be 0
1630                 // 2. wing is done (or currently departing)
1631                 // 3. wing is present (any wave, any number of ships).
1632                 //
1633                 // 1 and 2 are easy to handle.  (3) is the hardest.
1634                 if ( wingp->total_arrived_count == 0 ) {
1635                         what = INGAME_WING_NOT_ARRIVED;
1636                         ADD_DATA( what );
1637                 } else if ( wingp->flags & (WF_WING_GONE | WF_WING_DEPARTING) ) {
1638                         what = INGAME_WING_DEPARTED;
1639                         ADD_DATA( what );
1640                 } else {
1641                         int j;
1642
1643                         // include to code to possibly send more wing data here in this part of the if/else
1644                         // chain.  We can do this because MAX_WINGS * 8 (8 being the number of byte for a minimum
1645                         // description of a wing) is always less than MAX_PACKET_SIZE.  Checking here ensures that
1646                         // we have enough space for *this* wing in the packet, and not the largest wing.  The
1647                         // formula below looks at number of ships in the wing, the name length, length of the signature,
1648                         // and the size of the bytes added before the ship names.  32 accounts for a little slop
1649                         if ( packet_size > (MAX_PACKET_SIZE - (wingp->current_count * (NAME_LENGTH+2) + 32)) ) {
1650                                 p_type = INGAME_WING_LIST_EOP;
1651                                 ADD_DATA( p_type );                             
1652                                 multi_io_send_reliable(player, data, packet_size);
1653                                 BUILD_HEADER( WINGS_INGAME_PACKET );
1654                         }
1655                         what = INGAME_WING_PRESENT;
1656                         ADD_DATA( what );
1657                         ADD_DATA( wingp->total_arrived_count );
1658                         ADD_DATA( wingp->current_count );
1659                         ADD_DATA( wingp->current_wave );
1660
1661                         // add the ship name and net signature of all ships currently in the wing.
1662                         for ( j = 0; j < wingp->current_count; j++ ) {
1663                                 ship *shipp;
1664
1665                                 shipp = &Ships[wingp->ship_index[j]];
1666                                 //ADD_STRING( shipp->ship_name );
1667                                 ADD_DATA( Objects[shipp->objnum].net_signature );
1668                         }
1669                 }
1670
1671         }
1672
1673         p_type = INGAME_WING_LIST_EOL;
1674         ADD_DATA( p_type );
1675         
1676         multi_io_send_reliable(player, data, packet_size);
1677 }
1678 */
1679
1680 // send a request or a reply regarding ingame join ship choice
1681 void send_ingame_ship_request_packet(int code,int rdata,net_player *pl)
1682 {
1683         ubyte data[MAX_PACKET_SIZE],val;
1684         ship *shipp;
1685         int i, packet_size = 0;
1686         ushort signature;
1687         p_object *pobj;
1688
1689         // add the data
1690         BUILD_HEADER(INGAME_SHIP_REQUEST);
1691
1692         // add the code
1693         ADD_DATA(code);
1694         
1695         // add any code specific data
1696         switch(code){
1697         case INGAME_SR_REQUEST:
1698                 // add the net signature of the ship we're requesting
1699                 signature = (ushort)rdata;
1700                 ADD_DATA( signature );
1701                 break;
1702         case INGAME_SR_CONFIRM:
1703                 // get a pointer to the ship
1704                 shipp = &Ships[Objects[rdata].instance];
1705
1706                 // add the most recent position and orientation for the requested ship
1707                 ADD_DATA(Objects[rdata].pos);
1708                 ADD_ORIENT(Objects[rdata].orient);
1709                 ADD_DATA( Missiontime );
1710
1711                 // add the # of respawns this ship has left
1712                 pobj = mission_parse_get_arrival_ship( Objects[rdata].net_signature );
1713                 Assert(pobj != NULL);
1714                 ADD_DATA(pobj->respawn_count);
1715
1716                 // add the ships ets settings
1717                 val = (ubyte)shipp->weapon_recharge_index;
1718                 ADD_DATA(val);
1719                 val = (ubyte)shipp->shield_recharge_index;
1720                 ADD_DATA(val);
1721                 val = (ubyte)shipp->engine_recharge_index;
1722                 ADD_DATA(val);
1723
1724                 // add current primary and secondary banks, and add link status
1725                 val = (ubyte)shipp->weapons.current_primary_bank;
1726                 ADD_DATA(val);
1727                 val = (ubyte)shipp->weapons.current_secondary_bank;
1728                 ADD_DATA(val);          
1729
1730                 // add the current ammo count for secondary banks;
1731                 val = (ubyte)shipp->weapons.num_secondary_banks;                // for sanity checking
1732                 ADD_DATA(val);
1733                 for ( i = 0; i < shipp->weapons.num_secondary_banks; i++ ) {
1734                         Assert( shipp->weapons.secondary_bank_ammo[i] < UCHAR_MAX );
1735                         val = (ubyte)shipp->weapons.secondary_bank_ammo[i];
1736                         ADD_DATA(val);
1737                 }
1738
1739                 // add the link status of weapons
1740                 // primary link status  
1741                 val = 0;
1742                 if(shipp->flags & SF_PRIMARY_LINKED){
1743                         val |= (1<<0);
1744                 }
1745                 if(shipp->flags & SF_SECONDARY_DUAL_FIRE){
1746                         val |= (1<<1);
1747                 }
1748                 ADD_DATA(val);          
1749                 break;
1750         }
1751
1752         // send the packet
1753         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1754                 Assert(pl != NULL);             
1755                 multi_io_send_reliable(pl, data, packet_size);
1756         } else {                
1757                 multi_io_send_reliable(Net_player, data, packet_size);
1758         }
1759
1760         // if this is a confirm to a player -- send data to the other players in the game telling them
1761         if ( (code == INGAME_SR_CONFIRM) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) ) {
1762                 int i, player_num;
1763
1764                 player_num = NET_PLAYER_NUM(pl);
1765                 code = INGAME_PLAYER_CHOICE;
1766                 BUILD_HEADER(INGAME_SHIP_REQUEST);
1767                 ADD_DATA(code);
1768                 ADD_DATA(player_num);
1769                 ADD_DATA(Objects[rdata].net_signature);
1770                 for (i = 0; i < MAX_PLAYERS; i++ ) {
1771                         if(MULTI_CONNECTED(Net_players[i]) && (&Net_players[i] != Net_player) && (i != player_num) ) {                          
1772                                 multi_io_send_reliable(&Net_players[i], data, packet_size);
1773                         }
1774                 }
1775         }
1776 }
1777
1778 // function to validate all players in the game according to their team select index.  If discrepancies
1779 // are found, this function should be able to fix them up.
1780 void multi_ingame_validate_players()
1781 {
1782         int i;
1783
1784         for ( i = 0; i < MAX_PLAYERS; i++ ) {
1785                 if( MULTI_CONNECTED(Net_players[i]) && (Net_player != &Net_players[i]) && !MULTI_STANDALONE(Net_players[i]) ) {
1786                         char *ship_name;
1787                         int shipnum, objnum, player_objnum;
1788
1789                         player_objnum = Net_players[i].player->objnum;
1790                         if ( (Objects[player_objnum].type != OBJ_SHIP) || (Objects[player_objnum].type != OBJ_GHOST) ) {
1791                                 Int3();
1792                         }
1793
1794                         ship_name = multi_ts_get_shipname( Net_players[i].p_info.team, Net_players[i].p_info.ship_index );
1795                         Assert( ship_name != NULL );
1796                         shipnum = ship_name_lookup( ship_name );
1797                         if ( shipnum == -1 ) {
1798                                 // ship could be respawning
1799                                 continue;
1800                         }
1801                         objnum = Ships[shipnum].objnum;
1802                         Assert( objnum != -1 );
1803
1804                         // if this guy's objnum isn't a ship, then it should proably be a ghost!!
1805                         if ( Objects[objnum].type == OBJ_SHIP ) {
1806                                 if ( objnum != Net_players[i].player->objnum ) {
1807                                         Int3();
1808                                         Net_players[i].player->objnum = objnum;
1809                                 }
1810                         } else {
1811                                 Assert( Objects[objnum].type == OBJ_GHOST );
1812                         }
1813                 }
1814         }
1815 }
1816
1817 // process an ingame ship request packet
1818 void process_ingame_ship_request_packet(ubyte *data, header *hinfo)
1819 {
1820         int code;
1821         object *objp;
1822         int offset = HEADER_LENGTH;
1823         int team, slot_index, i;
1824         uint respawn_count;
1825         ubyte val, num_secondary_banks;
1826         p_object *pobj;
1827
1828         // get the code
1829         GET_DATA(code);
1830
1831         switch(code){
1832         // a request for a ship from an ingame joiner
1833         case INGAME_SR_REQUEST:                 
1834                 int player_num;         
1835                 ushort sig_request;
1836
1837                 // lookup the player and make sure he doesn't already have an objnum (along with possible error conditions)
1838                 GET_DATA(sig_request);
1839                 PACKET_SET_SIZE();
1840                         
1841                 player_num = find_player_id(hinfo->id); 
1842                 if(player_num == -1){
1843                         nprintf(("Network","Received ingame ship request packet from unknown player!!\n"));             
1844                         break;
1845                 }
1846                 
1847                 // make sure this player doesn't already have an object
1848                 Assert(MULTI_CONNECTED(Net_players[player_num]));
1849                 if(Net_players[player_num].player->objnum != -1){
1850                         send_ingame_ship_request_packet(INGAME_SR_DENY,0,&Net_players[player_num]);
1851                         break;
1852                 }
1853                 
1854                 // try and find the object
1855                 objp = NULL;
1856                 objp = multi_get_network_object(sig_request);
1857                 if(objp == NULL || !(objp->flags & OF_COULD_BE_PLAYER)){
1858                         send_ingame_ship_request_packet(INGAME_SR_DENY,0,&Net_players[player_num]);
1859                         break;
1860                 }               
1861
1862                 // Assign the player this objnum and ack him
1863                 Net_players[player_num].player->objnum = OBJ_INDEX(objp);
1864                 Net_players[player_num].state = NETPLAYER_STATE_IN_MISSION;                   // since he'll do this anyway...
1865                 Net_players[player_num].flags &= ~(NETINFO_FLAG_INGAME_JOIN);
1866                 multi_assign_player_ship( player_num, objp, Ships[objp->instance].ship_info_index );
1867
1868                 // update his ets and link status stuff
1869                 multi_server_update_player_weapons(&Net_players[player_num],&Ships[objp->instance]);
1870
1871                 objp->flags &= ~(OF_COULD_BE_PLAYER);
1872                 objp->flags |= OF_PLAYER_SHIP;
1873
1874                 // send a player settings packet to update all other players of this guy's final choices
1875                 send_player_settings_packet();
1876
1877                 // initialize datarate limiting for this guy
1878                 multi_oo_rate_init(&Net_players[player_num]);
1879                 
1880                 // ack him
1881                 send_ingame_ship_request_packet(INGAME_SR_CONFIRM,OBJ_INDEX(objp),&Net_players[player_num]);
1882
1883                 // clear my ingame join flag so that others may join
1884                 Netgame.flags &= ~NG_FLAG_INGAME_JOINING;
1885
1886                 // clear his net stats
1887                 scoring_level_init( &(Net_players[player_num].player->stats) );
1888                 break;
1889
1890                 // a denial for the ship we requested from the server
1891         case INGAME_SR_DENY :
1892                 PACKET_SET_SIZE();
1893
1894                 // set this to -1 so we can pick again
1895                 Multi_ingame_join_sig = 0;
1896
1897                 // display a popup
1898                 popup(PF_BODY_BIG | PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been denied the requested ship",686));
1899                 break;
1900
1901         // a confirmation that we can use the selected ship
1902         case INGAME_SR_CONFIRM:
1903                 // object *temp_objp;
1904
1905                 // delete the ship this ingame joiner was using.  Unassign Player_obj so that this object
1906                 // doesn't become a ghost.
1907                 // temp_objp = Player_obj;
1908                 // Player_obj = NULL;
1909                 // obj_delete( OBJ_INDEX(temp_objp) );
1910
1911                 // get the object itself
1912                 objp = multi_get_network_object(Multi_ingame_join_sig);
1913                 Assert(objp != NULL);
1914
1915                 // get its most recent position and orientation
1916                 GET_DATA(objp->pos);
1917                 GET_ORIENT(objp->orient);
1918                 GET_DATA( Missiontime );
1919                 GET_DATA( respawn_count );
1920                                 
1921                 // tell the server I'm in the mission
1922                 Net_player->state = NETPLAYER_STATE_IN_MISSION;
1923                 send_netplayer_update_packet();
1924
1925                 // setup our object                             
1926                 Net_player->player->objnum = OBJ_INDEX(objp);                   
1927                 Player_obj = objp;
1928                 Player_obj->flags &= ~(OF_COULD_BE_PLAYER);
1929                 Player_obj->flags |= OF_PLAYER_SHIP;
1930                 multi_assign_player_ship( MY_NET_PLAYER_NUM, objp, Ships[objp->instance].ship_info_index );
1931
1932                 // must change the ship type and weapons.  An ingame joiner know about the default class
1933                 // and weapons for a ship, but these could have changed.
1934                 multi_ts_get_team_and_slot(Player_ship->ship_name, &team, &slot_index);
1935                 Assert( team != -1 );
1936                 Assert( slot_index != -1 );
1937                 change_ship_type(objp->instance, Wss_slots_teams[team][slot_index].ship_class);
1938                 wl_bash_ship_weapons(&Player_ship->weapons,&Wss_slots_teams[team][slot_index]);
1939
1940                 // get the parse object for it and assign the respawn count
1941                 pobj = mission_parse_get_arrival_ship( objp->net_signature );
1942                 Assert(pobj != NULL);
1943                 pobj->respawn_count = respawn_count;
1944
1945                 // get the ships ets settings
1946                 GET_DATA(val);
1947                 Player_ship->weapon_recharge_index = val;
1948                 GET_DATA(val);
1949                 Player_ship->shield_recharge_index = val;
1950                 GET_DATA(val);
1951                 Player_ship->engine_recharge_index = val;               
1952
1953                 // get current primary and secondary banks, and add link status
1954                 GET_DATA(val);
1955                 Player_ship->weapons.current_primary_bank = val;
1956                 GET_DATA(val);
1957                 Player_ship->weapons.current_secondary_bank = val;                              
1958
1959                 // secondary bank ammo data
1960                 GET_DATA( num_secondary_banks );
1961                 Assert( num_secondary_banks == Player_ship->weapons.num_secondary_banks );
1962                 for ( i = 0; i < Player_ship->weapons.num_secondary_banks; i++ ) {
1963                         GET_DATA(val);
1964                         Player_ship->weapons.secondary_bank_ammo[i] = val;
1965                 }
1966
1967
1968                 // get the link status of weapons
1969                 GET_DATA(val);
1970                 if(val & (1<<0)){
1971                         Player_ship->flags |= SF_PRIMARY_LINKED;
1972                 }
1973                 if(val & (1<<1)){
1974                         Player_ship->flags |= SF_SECONDARY_DUAL_FIRE;
1975                 }               
1976                 PACKET_SET_SIZE();                                      
1977
1978                 // be sure that this ships current primary/secondary weapons are valid.  Easiest is to just
1979                 // bash the values to 0!
1980                 /*
1981                 if ( Player_ship->weapons.current_primary_bank == -1 )
1982                         Player_ship->weapons.current_primary_bank = 0;
1983                 if ( Player_ship->weapons.current_secondary_bank == -1 )
1984                         Player_ship->weapons.current_secondary_bank = 0;
1985                 */
1986                 
1987                 Net_player->flags &= ~(NETINFO_FLAG_INGAME_JOIN);
1988
1989                 // clear all object collision pairs, then add myself to the list
1990                 extern void obj_reset_all_collisions();
1991                 obj_reset_all_collisions();
1992                 // obj_reset_pairs();
1993                 // obj_add_pairs( OBJ_INDEX(Player_obj) );
1994
1995                 mission_hotkey_set_defaults();
1996
1997                 //multi_ingame_validate_players();
1998
1999                 // jump into the mission 
2000                 // NOTE : we check this flag because its possible that the player could have received an endgame packet in the same
2001                 //        frame as getting this confirmation. In that case, he should be quitting to the main menu. We must not make
2002                 //        him continue on into the mission
2003                 if(!multi_endgame_ending()){
2004                         gameseq_post_event(GS_EVENT_ENTER_GAME);                                                                
2005                 } 
2006                 break;
2007
2008         case INGAME_PLAYER_CHOICE: {
2009                 int player_num;
2010                 ushort net_signature;
2011                 object *objp;
2012
2013                 // get the player number of this guy, and the net signature of the ship he has chosen
2014                 GET_DATA(player_num);
2015                 GET_DATA(net_signature);
2016                 PACKET_SET_SIZE();
2017
2018                 objp = multi_get_network_object(net_signature);
2019                 if ( objp == NULL ) {
2020                         // bogus!!!  couldn't find the object -- we cannot connect his -- this is really bad!!!
2021                         nprintf(("Network", "Couldn't find ship for ingame joiner %s\n", Net_players[player_num].player->callsign));
2022                         break;
2023                 }
2024                 objp->flags |= OF_PLAYER_SHIP;
2025                 objp->flags &= ~OF_COULD_BE_PLAYER;
2026
2027                 multi_assign_player_ship( player_num, objp, Ships[objp->instance].ship_info_index );
2028
2029                 break;
2030                 }
2031         }
2032 }
2033
2034
2035 // --------------------------------------------------------------------------------------------------
2036 // INGAME JOIN FORWARD DEFINITIONS
2037 //
2038
2039 void multi_ingame_send_ship_update(net_player *p)
2040 {
2041         ship_obj *moveup;
2042         
2043         // get the first object on the list
2044         moveup = GET_FIRST(&Ship_obj_list);
2045         
2046         // go through the list and send all ships which are mark as OF_COULD_BE_PLAYER
2047         while(moveup!=END_OF_LIST(&Ship_obj_list)){
2048                 if(Objects[moveup->objnum].flags & OF_COULD_BE_PLAYER){
2049                         // send the update
2050                         send_ingame_ship_update_packet(p,&Ships[Objects[moveup->objnum].instance]);
2051                 }
2052
2053                 // move to the next item
2054                 moveup = GET_NEXT(moveup);
2055         }
2056 }
2057
2058 // for now, I guess we'll just send hull and shield % values
2059 void send_ingame_ship_update_packet(net_player *p,ship *sp)
2060 {
2061         ubyte data[MAX_PACKET_SIZE];
2062         object *objp;
2063         int idx;
2064         int packet_size = 0;
2065         float f_tmp;
2066
2067         BUILD_HEADER(INGAME_SHIP_UPDATE);
2068         
2069         // just send net signature, shield and hull percentages
2070         objp = &Objects[sp->objnum];
2071         ADD_DATA(objp->net_signature);
2072         ADD_DATA(objp->flags);
2073         ADD_DATA(objp->hull_strength);
2074         
2075         // shield percentages
2076         for(idx=0; idx<MAX_SHIELD_SECTIONS; idx++){
2077                 f_tmp = objp->shields[idx];
2078                 ADD_DATA(f_tmp);
2079         }
2080         
2081         multi_io_send_reliable(p, data, packet_size);
2082 }
2083
2084 void process_ingame_ship_update_packet(ubyte *data, header *hinfo)
2085 {
2086         int offset;
2087         float garbage;
2088         int flags;
2089         int idx;
2090         ushort net_sig;
2091         object *lookup;
2092         float f_tmp;
2093         
2094         offset = HEADER_LENGTH;
2095         // get the net sig for the ship and do a lookup
2096         GET_DATA(net_sig);
2097         GET_DATA(flags);
2098    
2099         // get the object
2100         lookup = multi_get_network_object(net_sig);
2101         if(lookup == NULL){
2102                 // read in garbage values if we can't find the ship
2103                 nprintf(("Network","Got ingame ship update for unknown object\n"));
2104                 GET_DATA(garbage);
2105                 for(idx=0;idx<MAX_SHIELD_SECTIONS;idx++){
2106                         GET_DATA(garbage);
2107                 }
2108
2109                 PACKET_SET_SIZE();
2110                 return;
2111         }
2112         // otherwise read in the ship values
2113         lookup->flags = flags;
2114         GET_DATA(lookup->hull_strength);
2115         for(idx=0;idx<MAX_SHIELD_SECTIONS;idx++){
2116                 GET_DATA(f_tmp);
2117                 lookup->shields[idx] = f_tmp;
2118         }
2119
2120         PACKET_SET_SIZE();
2121 }
2122