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