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