2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
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
10 * $Logfile: /Freespace2/code/Network/multi_ingame.cpp $
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 :)
19 * Revision 1.6 2004/09/20 01:31:44 theoddone33
22 * Revision 1.5 2004/06/11 01:17:50 tigital
23 * byte-swapping changes for bigendian systems
25 * Revision 1.4 2003/08/03 16:10:29 taylor
26 * cleanup; compile warning fixes
28 * Revision 1.3 2002/06/09 04:41:23 relnev
29 * added copyright header
31 * Revision 1.2 2002/06/02 04:26:34 relnev
34 * Revision 1.1.1.1 2002/05/03 03:28:10 root
38 * 20 8/03/99 11:02p Dave
39 * Maybe fixed sync problems in multiplayer.
41 * 19 7/30/99 7:01p Dave
42 * Dogfight escort gauge. Fixed up laser rendering in Glide.
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.
48 * 17 7/26/99 6:07p Dave
49 * Removed some warnings.
51 * 16 7/26/99 5:50p Dave
52 * Revised ingame join. Better? We'll see....
54 * 15 7/24/99 5:48p Jefff
55 * converted to new UI stuff -- added 1024 support
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.
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.
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.
70 * 11 3/09/99 6:24p Dave
71 * More work on object update revamping. Identified several sources of
72 * unnecessary bandwidth.
74 * 10 3/08/99 7:03p Dave
75 * First run of new object update system. Looks very promising.
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.
81 * 8 1/30/99 5:08p Dave
82 * More new hi-res stuff.Support for nice D3D textures.
84 * 7 1/27/99 9:56a Dave
85 * Temporary checkin of beam weapons for Dan to make cool sounds.
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.
91 * 5 11/17/98 11:12a Dave
92 * Removed player identification by address. Now assign explicit id #'s.
94 * 4 11/05/98 5:55p Dave
95 * Big pass at reducing #includes
97 * 3 10/13/98 9:29a Dave
98 * Started neatening up freespace.h. Many variables renamed and
99 * reorganized. Added AlphaColors.[h,cpp]
101 * 2 10/07/98 10:53a Dave
104 * 1 10/07/98 10:50a Dave
106 * 83 9/18/98 4:54p Dave
107 * Fixed ingame ship select icon problem.
109 * 82 9/18/98 4:23p Dave
110 * Reversed the logic on a bogus assert.
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
117 * 80 9/15/98 1:59p Dave
118 * Fixed bonehead mistake calling multi_endgame_ending()
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.
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
128 * 77 8/07/98 10:16a Allender
129 * use obj_set_flags for the COULD_BE_PLAYER flag
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.
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.
139 * 74 6/13/98 6:01p Hoffoss
140 * Externalized all new (or forgot to be added) strings to all the code.
142 * 73 6/13/98 3:18p Hoffoss
143 * NOX()ed out a bunch of strings that shouldn't be translated.
145 * 72 6/10/98 2:56p Dave
146 * Substantial changes to reduce bandwidth and latency problems.
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.
152 * 70 5/26/98 11:54a Allender
153 * fix multiplayer problems and sexpression crash
155 * 69 5/25/98 1:33a Allender
156 * fixed timestamp problem for client update packets, small fix for ingame
159 * 68 5/24/98 9:17p Allender
160 * commented out test code to help rectify bogus player objects when
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
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
172 * 65 5/21/98 10:03p Allender
173 * add secondary ammo counts to ingame join packets
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.
180 * 63 5/21/98 12:14a Allender
181 * fix ingame join problems
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
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
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.
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
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.
205 * 57 5/15/98 1:44p Allender
206 * initialize hotkeys when entering the mission ingame joining
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)
212 * 55 5/09/98 4:31p Chad
213 * Fixed weapon recharge rate problem and fixed weapon link status problem
214 * for ingame joiners.
216 * 54 5/08/98 11:21a Allender
217 * fix ingame join trouble. Small messaging fix. Enable collisions for
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
226 * 52 5/03/98 2:52p Dave
227 * Removed multiplayer furball mode.
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.
233 * 50 5/01/98 4:11p Comet
234 * Fixed ship_ets bug. I think.
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
240 * 48 4/29/98 9:36p Allender
241 * ingame join tweaks. added network message for countermeasures
243 * 47 4/29/98 12:28p Chad
244 * set packet size when selecting a player's ingame choice
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.
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
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
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
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
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
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.
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.
283 * 38 4/06/98 6:47p Allender
284 * be sure that ingame joiner has reasonable current primary and secondary
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
292 * 36 4/04/98 4:22p Dave
293 * First rev of UDP reliable sockets is done. Seems to work well if not
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
300 * 34 4/03/98 1:03a Dave
301 * First pass at unreliable guaranteed delivery packets.
303 * 33 4/02/98 5:36p John
304 * Made the level paging occur at the same time as the level is read in.
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
310 * 31 3/24/98 5:12p Allender
311 * ingame join packet sequencing
322 #include "multiutil.h"
323 #include "multimsgs.h"
325 #include "missionparse.h"
326 #include "freespace.h"
327 #include "gamesequence.h"
332 #include "linklist.h"
333 #include "multi_ingame.h"
334 #include "missionscreencommon.h"
338 #include "multi_observer.h"
339 #include "multi_xfer.h"
340 #include "multi_kick.h"
341 #include "missiongoals.h"
342 #include "mainhallmenu.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"
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
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
365 // --------------------------------------------------------------------------------------------------
367 // --------------------------------------------------------------------------------------------------
368 // INGAME JOIN DESCRIPTION
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 // --------------------------------------------------------------------------------------------------
397 static int Ingame_ships_deleted = 0;
398 //static int Ingame_ships_to_delete[MAX_SHIPS]; // no longer used
401 // --------------------------------------------------------------------------------------------------
402 // INGAME JOIN FORWARD DECLARATIONS
405 void multi_ingame_send_ship_update(net_player *p);
407 void multi_ingame_join_check_buttons();
408 void multi_ingame_join_button_pressed(int n);
412 // --------------------------------------------------------------------------------------------------
413 // INGAME JOIN COMMON DEFINITIONS
417 // --------------------------------------------------------------------------------------------------
418 // INGAME JOIN SERVER FUNCTIONS
421 // called on the server to process ingame joiners and move them through the motions of ingame joining
422 void multi_handle_ingame_joiners()
426 SDL_assert( MULTIPLAYER_MASTER );
428 // if my ingame joining flag isn't set, then don't do anything.
429 if ( !(Netgame.flags & NG_FLAG_INGAME_JOINING) ){
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)){
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 :
446 Net_players[idx].flags |= NETINFO_FLAG_MISSION_OK;
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;
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;
460 multi_kick_player(idx, 0, KICK_REASON_BAD_XFER);
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]);
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;
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)){
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);
485 send_wss_slots_data_packet(i, 1, &Net_players[idx]);
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;
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;
498 // once he has finished receiving the ship data, start sending him wing data and mark this down
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;
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;
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
515 Netgame.flags &= ~NG_FLAG_INGAME_JOINING_CRITICAL;
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);
521 send_post_sync_data_packet(&Net_players[idx]);
523 Net_players[idx].s_info.ingame_join_flags |= INGAME_JOIN_FLAG_SENDING_POST;
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);
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;
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)){
544 multi_ingame_send_ship_update(&Net_players[idx]);
546 // reset the timestamp
547 Net_players[idx].s_info.last_full_update_time = timestamp(INGAME_SHIP_UPDATE_TIME);
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
557 Net_players[idx].s_info.ingame_join_flags |= INGAME_JOIN_FLAG_SENDING_SETS;
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()
565 // create my local observer object
566 multi_obs_create_observer_client();
568 // unflag myself as being an ingame joiner
569 Net_player->flags &= ~(NETINFO_FLAG_INGAME_JOIN);
571 // set my state to be in-mission
572 Net_player->state = NETPLAYER_STATE_IN_MISSION;
573 send_netplayer_update_packet();
575 // jump into the game
576 gameseq_post_event(GS_EVENT_ENTER_GAME);
579 // --------------------------------------------------------------------------------------------------
580 // INGAME DATA SYNC SCREEN
583 // mission sync screen init function for ingame joining
584 void multi_ingame_sync_init()
586 // if we couldn't get the file signature correctly. send some bogus values
587 multi_get_mission_checksum(Game_current_mission_filename);
589 // everyone should re-initialize these
590 init_multiplayer_stats();
592 // reset all sequencing info
593 multi_oo_reset_sequencing();
595 // send the file signature to the host for possible mission file transfer
596 SDL_strlcpy(Netgame.mission_name, Game_current_mission_filename, SDL_arraysize(Netgame.mission_name));
597 send_file_sig_packet(Multi_current_file_checksum,Multi_current_file_length);
599 Ingame_ships_deleted = 0;
602 // mission sync screen do function for ingame joining
603 void multi_ingame_sync_do()
607 // mission sync screen do function for ingame joining
608 void multi_ingame_sync_close()
613 // --------------------------------------------------------------------------------------------------
614 // INGAME SHIP SELECT SCREEN
616 static const char *Multi_ingame_join_bitmap_fname[GR_NUM_RESOLUTIONS] = {
617 "MultiIngame", // GR_640
618 "2_MultiIngame" // GR_1024
621 static const char *Multi_ingame_join_bitmap_mask_fname[GR_NUM_RESOLUTIONS] = {
622 "MultiIngame-M", // GR_640
623 "2_MultiIngame-M" // GR_1024
628 #define MULTI_INGAME_JOIN_NUM_BUTTONS 2
632 ui_button_info Multi_ingame_join_buttons[GR_NUM_RESOLUTIONS][MULTI_INGAME_JOIN_NUM_BUTTONS] = {
634 ui_button_info( "MIB_00", 532, 434, 510, 413, 0 ), // cancel
635 ui_button_info( "MIB_01", 572, 428, 585, 413, 1 ), // join
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
643 #define MULTI_INGAME_JOIN_NUM_TEXT 8
645 UI_XSTR Multi_ingame_join_text[GR_NUM_RESOLUTIONS][MULTI_INGAME_JOIN_NUM_TEXT] = {
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}
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}
673 static int Mi_width[GR_NUM_RESOLUTIONS] = {
678 static int Mi_height[GR_NUM_RESOLUTIONS] = {
683 static int Mi_spacing[GR_NUM_RESOLUTIONS] = {
688 static int Mi_name_field[GR_NUM_RESOLUTIONS][4] = {
705 static int Mi_class_field[GR_NUM_RESOLUTIONS][4] = {
722 static int Mi_status_field[GR_NUM_RESOLUTIONS][4] = {
739 static int Mi_primary_field[GR_NUM_RESOLUTIONS][4] = {
756 static int Mi_secondary_field[GR_NUM_RESOLUTIONS][4] = {
773 // for timing a player out
774 static int Multi_ingame_timer_coords[GR_NUM_RESOLUTIONS][2] = {
787 //#define MULTI_INGAME_TIME_LEFT_X 26
788 //#define MULTI_INGAME_TIME_LEFT_Y 411
790 #define MULTI_INGAME_TIME_SECONDS (1000 * 15)
791 static int Ingame_time_left;
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
799 #define MULTI_INGAME_MAX_SHIP_ICONS 40
800 typedef struct is_icon {
801 int bmaps[NUM_ICON_FRAMES];
804 is_icon Multi_ingame_ship_icon[MULTI_INGAME_MAX_SHIP_ICONS];
805 int Multi_ingame_num_ship_icons;
807 // # of available ships (also == the # currently being displayed)
808 int Multi_ingame_num_avail;
810 // signatures for each of the available ships
811 ushort Multi_ingame_ship_sigs[MAX_PLAYERS];
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;
816 // the index into the list of the ship currently selected
817 int Multi_ingame_ship_selected;
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
823 ushort Ingame_ship_signatures[MAX_INGAME_SHIPS];
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
832 // display the available ships (OF_COULD_BE_PLAYER flagged)
833 void multi_ingame_join_display_avail();
835 // try and scroll the selected ship up
836 void multi_ingame_scroll_select_up();
838 // try and scroll the selected ship down
839 void multi_ingame_scroll_select_down();
841 // handle all timeout details
842 void multi_ingame_handle_timeout();
844 int multi_ingame_get_ship_class_icon(int ship_class)
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){
859 void multi_ingame_load_icons()
861 int first_frame, num_frames, idx, s_idx;
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;
870 Multi_ingame_num_ship_icons = 0;
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;
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
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;
888 Multi_ingame_num_ship_icons++;
893 void multi_ingame_unload_icons()
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;
908 // ingame join ship selection screen init
909 void multi_ingame_select_init()
911 /// int objnum, wingnum_save,idx, goals_save;
912 // ushort net_signature;
915 Multi_ingame_join_sig = 0;
916 Net_player->player->objnum = -1;
918 // create a ship, then find a ship to copy crucial information from. Save and restore the wing
919 // number to be safe.
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;
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);
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];
946 // load the temp ship icons
947 multi_ingame_load_icons();
949 // blast all the ingame ship signatures
950 memset(Multi_ingame_ship_sigs,0,sizeof(ushort) * MAX_PLAYERS);
952 // the index into the list of the ship currently selected
953 Multi_ingame_ship_selected = -1;
955 // initialize the time he has left to select a ship
956 Ingame_time_left = timestamp(MULTI_INGAME_TIME_SECONDS);
958 // initialize GUI data
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]);
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");
969 // create the interface buttons
970 for(idx=0; idx<MULTI_INGAME_JOIN_NUM_BUTTONS; idx++) {
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);
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);
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);
981 Multi_ingame_join_buttons[gr_screen.res][idx].button.link_hotspot(Multi_ingame_join_buttons[gr_screen.res][idx].hotspot);
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]);
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();
993 // load freespace stuff
994 // JAS: Code to do paging used to be here.
997 // process all ship list related details
998 void multi_ingame_ship_list_process()
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;
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;
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];
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);
1027 Multi_ingame_ship_selected = select_index;
1033 // determines if a button was pressed, and acts accordingly
1034 void multi_ingame_join_check_buttons()
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);
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)
1053 multi_quit_game(PROMPT_CLIENT);
1056 // don't do further processing if the game is paused
1057 if ( Netgame.game_state == NETGAME_STATE_PAUSED )
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);
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];
1068 // send a request to the
1069 send_ingame_ship_request_packet(INGAME_SR_REQUEST,Multi_ingame_join_sig);
1071 gamesnd_play_iface(SND_GENERAL_FAIL);
1074 gamesnd_play_iface(SND_GENERAL_FAIL);
1079 // how the hell did this happen?
1085 // ingame join ship selection screen do
1086 void multi_ingame_select_do()
1088 int k = Multi_ingame_window.process();
1090 // process any keypresses
1093 multi_quit_game(PROMPT_CLIENT);
1097 multi_ingame_scroll_select_up();
1101 multi_ingame_scroll_select_down();
1105 // process button presses
1106 // multi_ingame_process_buttons();
1107 multi_ingame_join_check_buttons();
1109 // process any ship list related events
1110 multi_ingame_ship_list_process();
1112 // draw the background, etc
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);
1119 Multi_ingame_window.draw();
1121 // handle all timeout details. blitting, etc
1122 multi_ingame_handle_timeout();
1124 // display the available ships
1125 multi_ingame_join_display_avail();
1131 // ingame join ship select close
1132 void multi_ingame_select_close()
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]));
1139 // unload all the ship class icons
1140 multi_ingame_unload_icons();
1142 // destroy the UI_WINDOW
1143 Multi_ingame_window.destroy();
1145 // stop main hall music
1146 main_hall_stop_music();
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)
1156 // blit the ship name itself
1157 gr_set_color_fast(&Color_normal);
1158 gr_string(Mi_name_field[gr_screen.res][MI_FIELD_X],y_start+10, Ships[objp->instance].ship_name);
1160 // blit the ship class icon
1161 icon_num = multi_ingame_get_ship_class_icon(Ships[objp->instance].ship_info_index);
1163 gr_set_bitmap(Multi_ingame_ship_icon[icon_num].bmaps[0], GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
1164 gr_bitmap(Mi_class_field[gr_screen.res][MI_FIELD_X] + 15, y_start);
1167 gr_set_color_fast(&Color_bright);
1168 wp = &Ships[objp->instance].weapons;
1170 // blit the ship's primary weapons
1171 y_spacing = (Mi_spacing[gr_screen.res] - (wp->num_primary_banks * 10)) / 2;
1172 for(idx=0;idx<wp->num_primary_banks;idx++){
1173 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);
1176 // blit the ship's secondary weapons
1177 y_spacing = (Mi_spacing[gr_screen.res] - (wp->num_secondary_banks * 10)) / 2;
1178 for(idx=0;idx<wp->num_secondary_banks;idx++){
1179 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);
1182 // blit the shield/hull integrity
1183 hud_shield_show_mini(objp, Mi_status_field[gr_screen.res][MI_FIELD_X] + 15, y_start + 3,5,7);
1186 // display the available ships (OF_COULD_BE_PLAYER flagged)
1187 void multi_ingame_join_display_avail()
1191 // recalculate this # every frame
1192 Multi_ingame_num_avail = 0;
1194 // display a background highlight rectangle for any selected lines
1195 if(Multi_ingame_ship_selected != -1){
1196 int y_start = (Mi_name_field[gr_screen.res][MI_FIELD_Y] + (Multi_ingame_ship_selected * Mi_spacing[gr_screen.res]));
1199 gr_set_color_fast(&Color_bright_blue);
1200 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);
1201 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);
1202 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);
1203 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);
1206 moveup = GET_FIRST(&Ship_obj_list);
1207 while(moveup != END_OF_LIST(&Ship_obj_list)){
1208 if( !(Ships[Objects[moveup->objnum].instance].flags & (SF_DYING|SF_DEPARTING)) && (Objects[moveup->objnum].flags & OF_COULD_BE_PLAYER) ) {
1210 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]));
1212 // set the ship signature
1213 Multi_ingame_ship_sigs[Multi_ingame_num_avail] = Objects[moveup->objnum].net_signature;
1215 // inc the # available
1216 Multi_ingame_num_avail++;
1218 moveup = GET_NEXT(moveup);
1222 // try and scroll the selected ship up
1223 void multi_ingame_scroll_select_up()
1225 if(Multi_ingame_ship_selected > 0){
1226 gamesnd_play_iface(SND_USER_SELECT);
1227 Multi_ingame_ship_selected--;
1229 gamesnd_play_iface(SND_GENERAL_FAIL);
1233 // try and scroll the selected ship down
1234 void multi_ingame_scroll_select_down()
1236 if(Multi_ingame_ship_selected < (Multi_ingame_num_avail - 1)){
1237 gamesnd_play_iface(SND_USER_SELECT);
1238 Multi_ingame_ship_selected++;
1240 gamesnd_play_iface(SND_GENERAL_FAIL);
1244 // handle all timeout details
1245 void multi_ingame_handle_timeout()
1248 // uncomment this block to disable the timer
1249 gr_set_color_fast(&Color_bright_red);
1250 gr_string(Multi_ingame_timer_coords[gr_screen.res][0], Multi_ingame_timer_coords[gr_screen.res][1], "Timer disabled!!");
1254 // if we've timed out, leave the game
1255 if( timestamp_elapsed(Ingame_time_left) ) {
1256 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_INGAME_TIMEOUT, MULTI_END_ERROR_NONE);
1260 // otherwise, blit how much time we have left
1261 int time_left = timestamp_until(Ingame_time_left) / 1000;
1262 char tl_string[100];
1263 gr_set_color_fast(&Color_bright);
1264 SDL_snprintf(tl_string,SDL_arraysize(tl_string),XSTR("Time remaining : %d s\n",682),time_left);
1265 gr_string(Multi_ingame_timer_coords[gr_screen.res][0], Multi_ingame_timer_coords[gr_screen.res][1], tl_string);
1269 // --------------------------------------------------------------------------------------------------
1270 // PACKET HANDLER functions
1271 // these are also defined in multimsgs.h, but the implementations are in the module for the sake of convenience
1274 #define INGAME_PACKET_SLOP 75 // slop value used for packets to ingame joiner
1276 void process_ingame_ships_packet( ubyte *data, header *hinfo )
1278 int offset, sflags, oflags, team, j;
1280 ushort net_signature;
1282 int team_val, slot_index, idx;
1283 char ship_name[255] = "";
1287 // go through the ship obj list and delete everything. YEAH
1288 if(!Ingame_ships_deleted){
1295 for(idx=0; idx<MAX_SHIPS; idx++){
1296 if((Ships[idx].objnum >= 0) && (Ships[idx].objnum < MAX_OBJECTS)){
1297 obj_delete(Ships[idx].objnum);
1301 Ingame_ships_deleted = 1;
1304 offset = HEADER_LENGTH;
1308 while ( p_type == INGAME_SHIP_NEXT ) {
1310 int ship_num, objnum;
1312 GET_STRING( ship_name );
1313 GET_USHORT( net_signature );
1317 GET_SHORT( wing_data );
1320 GET_UINT(Wings[wing_data].current_wave);
1321 net_sig_modify = Wings[wing_data].current_wave - 1;
1324 // lookup ship in the original ships array
1325 p_objp = mission_parse_get_original_ship(net_signature);
1327 // if this ship is part of wing not on its current wave, look for its "original" by subtracting out wave #
1328 p_objp = mission_parse_get_arrival_ship((ushort)(net_signature - (ushort)net_sig_modify));
1332 nprintf(("Network", "Couldn't find ship %s in either arrival list or in mission"));
1333 multi_quit_game(PROMPT_NONE, MULTI_END_NOTIFY_NONE, MULTI_END_ERROR_INGAME_BOGUS);
1337 // go ahead and create the parse object. Set the network signature of this guy before
1339 // multi_set_network_signature( net_signature, MULTI_SIG_SHIP );
1340 objnum = parse_create_object( p_objp );
1341 ship_num = Objects[objnum].instance;
1342 Objects[objnum].flags = oflags;
1343 Objects[objnum].net_signature = net_signature;
1345 // assign any common data
1346 SDL_strlcpy(Ships[ship_num].ship_name, ship_name, NAME_LENGTH);
1347 Ships[ship_num].flags = sflags;
1348 Ships[ship_num].team = team;
1349 Ships[ship_num].wingnum = (int)wing_data;
1356 // if we have reached the end of the list and change our network state
1357 if ( p_type == INGAME_SHIP_LIST_EOL ) {
1358 // merge all created list
1359 obj_merge_created_list();
1361 // fixup player ship stuff
1362 for(idx=0; idx<MAX_SHIPS; idx++){
1363 if(Ships[idx].objnum < 0){
1367 // get the team and slot. Team will be -1 when it isn't a part of player wing. So, if
1368 // not -1, then be sure we have a valid slot, then change the ship type, etc.
1369 objp = &Objects[Ships[idx].objnum];
1370 multi_ts_get_team_and_slot(Ships[idx].ship_name, &team_val, &slot_index);
1371 if ( team_val != -1 ) {
1372 SDL_assert( slot_index != -1 );
1374 // change the ship type and the weapons
1375 change_ship_type(objp->instance, Wss_slots_teams[team_val][slot_index].ship_class);
1376 wl_bash_ship_weapons(&Ships[idx].weapons, &Wss_slots_teams[team_val][slot_index]);
1378 // Be sure to mark this ship as as a could_be_player
1379 obj_set_flags( objp, objp->flags | OF_COULD_BE_PLAYER );
1380 objp->flags &= ~OF_PLAYER_SHIP;
1383 // if this is a player ship, make sure we find out who's it is and set their objnum accordingly
1385 for( j = 0; j < MAX_PLAYERS; j++){
1386 if(MULTI_CONNECTED(Net_players[j]) && (Net_players[j].player->objnum == Objects[Ships[idx].objnum].net_signature)) {
1387 // nprintf(("Network", "Making %s ship for %s\n", Ships[shipnum].ship_name, Net_players[j].player->callsign));
1388 multi_assign_player_ship( j, objp, Ships[idx].ship_info_index );
1389 objp->flags |= OF_PLAYER_SHIP;
1390 objp->flags &= ~OF_COULD_BE_PLAYER;
1397 // notify the server that we're all good.
1398 Net_player->state = NETPLAYER_STATE_INGAME_SHIPS;
1399 send_netplayer_update_packet();
1401 // add some mission sync text
1402 multi_common_add_text(XSTR("Ships packet ack (ingame)\n",683));
1406 void send_ingame_ships_packet(net_player *player)
1408 ubyte data[MAX_PACKET_SIZE];
1414 BUILD_HEADER( SHIPS_INGAME_PACKET );
1416 // essentially, we are going to send a list of ship names to the joiner for ships that are not
1417 // in wings. The joiner will take the list, create any ships which should be created, and delete all
1418 // other ships after the list is sent.
1419 for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {
1422 shipp = &Ships[Objects[so->objnum].instance];
1425 // if ( shipp->wingnum != -1 ){
1429 if ( Objects[so->objnum].net_signature == STANDALONE_SHIP_SIG ){
1433 // add the ship name and other information such as net signature, ship and object(?) flags.
1434 p_type = INGAME_SHIP_NEXT;
1436 ADD_STRING( shipp->ship_name );
1437 ADD_USHORT( Objects[so->objnum].net_signature );
1438 ADD_UINT( shipp->flags );
1439 ADD_UINT( Objects[so->objnum].flags );
1440 ADD_INT( shipp->team );
1441 wing_data = (short)shipp->wingnum;
1442 ADD_SHORT(wing_data);
1444 ADD_UINT(Wings[wing_data].current_wave);
1447 // don't send anymore data if we are getting close to the maximum size of this packet. Send it off and
1449 if ( packet_size > (MAX_PACKET_SIZE - INGAME_PACKET_SLOP) ) {
1450 p_type = INGAME_SHIP_LIST_EOP;
1452 multi_io_send_reliable(player, data, packet_size);
1453 BUILD_HEADER( SHIPS_INGAME_PACKET );
1457 // end of the ship list!!!
1458 p_type = INGAME_SHIP_LIST_EOL;
1460 multi_io_send_reliable(player, data, packet_size);
1463 void process_ingame_wings_packet( ubyte *data, header *hinfo )
1468 // code to process the wing data from a server.
1469 void process_ingame_wings_packet( ubyte *data, header *hinfo )
1471 int offset, wingnum;
1474 offset = HEADER_LENGTH;
1478 // p_type tells us whether to stop or not
1479 while ( p_type == INGAME_WING_NEXT ) {
1482 // get the wingnum and a pointer to it. The game stores data for all wings always, so this
1483 // is perfectly valid
1484 GET_DATA( wingnum );
1485 wingp = &Wings[wingnum];
1488 if ( what == INGAME_WING_NOT_ARRIVED ) {
1489 SDL_assert( wingp->total_arrived_count == 0 ); // this had better be true!!!
1490 } else if ( what == INGAME_WING_DEPARTED ) {
1491 // mark the wing as gone. if it isn't, it soon will be. Maybe we should send more information
1492 // about these wings later (like total_arrived_count, etc), but we will see.
1493 wingp->flags |= WF_WING_GONE;
1495 int total_arrived_count, current_count, current_wave, i, j;
1499 // the wing is present in the mission on the server. Get the crucial information about the
1500 // wing. Then get the ships for this wing in order on the client machine
1501 GET_DATA( total_arrived_count );
1502 GET_DATA( current_count );
1503 GET_DATA( current_wave );
1505 SDL_assert( current_wave > 0 );
1506 SDL_assert( total_arrived_count > 0 );
1508 // for this wing, strip it down to nothing. Let the parse object ocde recreate the
1509 // wing from the parse objects, then bash any weapons, etc for player wings. We need
1510 // to do this because we might actually wind up with > MAX_SHIPS_PER_WING if we
1511 // don't delete them all first, and have a > 0 threshold, and are on something other
1512 // than the first wave. Only do this for non-player wings.
1514 nprintf(("Network", "Clearing %s -- %d ships\n", wingp->name, wingp->current_count));
1515 for ( i = 0; i < wingp->current_count; i++ ) {
1518 index = wingp->ship_index[i];
1519 SDL_assert( index != -1 );
1520 objnum = Ships[index].objnum;
1521 SDL_assert( objnum != -1 );
1523 // delete the object since we are filling the wing again anyway.
1524 obj_delete( objnum );
1525 Objects[objnum].net_signature = 0; // makes this object "invalid" until dead.
1526 if ( Objects[objnum].type == OBJ_GHOST ) {
1527 nprintf(("Network", "Marking ghost objnum %d as dead\n", objnum));
1528 Objects[objnum].flags |= OF_SHOULD_BE_DEAD;
1530 Ingame_ships_to_delete[index] = 0; // be sure that this guy doesn't get deleted, since we already deleted it
1531 wingp->ship_index[i] = -1;
1533 wingp->current_count = 0;
1534 wingp->total_arrived_count = 0;
1536 // now, recreate all the ships needed
1537 for (i = 0; i < current_count; i++ ) {
1538 int which_one, team, slot_index, specific_instance;;
1542 GET_DATA( signature );
1544 // assign which_one to be the given signature - wing's base signature. This let's us
1545 // know which ship to create (i.e. the total_arrivel_count);
1546 which_one = signature - wingp->net_signature;
1547 SDL_assert( (which_one >= 0) && (which_one < (wingp->net_signature + (wingp->wave_count*wingp->num_waves))) );
1548 wingp->total_arrived_count = (ushort)which_one;
1550 // determine which ship in the ahip arrival list this guy is. It is a 0 based index
1551 specific_instance = which_one % wingp->wave_count;
1553 // call parse_wing_create_ships making sure that we only ever create 1 ship at a time. We don't
1554 // want parse_wing_create_ships() to assign network signature either. We will directly
1557 wingp->current_wave = 0; // make it the first wave. Ensures that ships don't get removed off the list
1558 parse_wing_create_ships( wingp, 1, 1, specific_instance );
1559 shipnum = wingp->ship_index[wingp->current_count-1];
1560 Ingame_ships_to_delete[shipnum] = 0; // "unmark" this ship so it doesn't get deleted.
1562 // kind of stupid, but bash the name since it won't get recreated properly from
1563 // the parse_wing_create_ships call.
1564 shipp = &Ships[shipnum];
1565 sprintf(shipp->ship_name, NOX("%s %d"), wingp->name, which_one + 1);
1566 nprintf(("Network", "Created %s\n", shipp->ship_name));
1568 objp = &Objects[shipp->objnum];
1569 objp->net_signature = (ushort)(wingp->net_signature + which_one);
1571 // get the team and slot. Team will be -1 when it isn't a part of player wing. So, if
1572 // not -1, then be sure we have a valid slot, then change the ship type, etc.
1573 multi_ts_get_team_and_slot(shipp->ship_name, &team, &slot_index);
1575 SDL_assert( slot_index != -1 );
1577 // change the ship type and the weapons
1578 change_ship_type(objp->instance, Wss_slots_teams[team][slot_index].ship_class);
1579 wl_bash_ship_weapons(&shipp->weapons,&Wss_slots_teams[team][slot_index]);
1581 // Be sure to mark this ship as as a could_be_player
1582 obj_set_flags( objp, objp->flags | OF_COULD_BE_PLAYER );
1583 objp->flags &= ~OF_PLAYER_SHIP;
1586 // if this is a player ship, make sure we find out who's it is and set their objnum accordingly
1587 for( j = 0; j < MAX_PLAYERS; j++){
1588 if(MULTI_CONNECTED(Net_players[j]) && (Net_players[j].player->objnum == signature)) {
1589 SDL_assert( team != -1 ); // to help trap errors!!!
1590 nprintf(("Network", "Making %s ship for %s\n", Ships[shipnum].ship_name, Net_players[j].player->callsign));
1591 multi_assign_player_ship( j, objp, Ships[shipnum].ship_info_index );
1592 objp->flags |= OF_PLAYER_SHIP;
1593 objp->flags &= ~OF_COULD_BE_PLAYER;
1600 // we will have no ships in any wings at this point (we didn't create any when we loaded the
1601 // mission). Set the current wave of this wing to be 1 less than was passed in since this value
1602 // will get incremented in parse_wing_create_ships;
1603 wingp->current_wave = current_wave;
1604 wingp->total_arrived_count = total_arrived_count;
1612 // if we have reached the end of the list change our network state
1613 if ( p_type == INGAME_WING_LIST_EOL ) {
1614 Net_player->state = NETPLAYER_STATE_INGAME_WINGS;
1615 send_netplayer_update_packet();
1617 // add some mission sync text
1618 multi_common_add_text(XSTR("Wings packet (ingame)\n",684));
1623 // function to send information about wings. We need to send enough information to let the client
1624 // construct or reconstruct any wings in the mission. We will rely on the fact that the host wing array
1625 // will exactly match the client wing array (in terms of number, and wing names)
1626 void send_ingame_wings_packet( net_player *player )
1628 ubyte data[MAX_PACKET_SIZE];
1633 BUILD_HEADER( WINGS_INGAME_PACKET );
1635 // iterate through the wings list
1636 for ( i = 0; i < num_wings; i++ ) {
1641 p_type = INGAME_WING_NEXT;
1646 // add wing data that the client needs. There are several conditions to send to clients:
1648 // 1. wing hasn't arrived -- total_arrived_count will be 0
1649 // 2. wing is done (or currently departing)
1650 // 3. wing is present (any wave, any number of ships).
1652 // 1 and 2 are easy to handle. (3) is the hardest.
1653 if ( wingp->total_arrived_count == 0 ) {
1654 what = INGAME_WING_NOT_ARRIVED;
1656 } else if ( wingp->flags & (WF_WING_GONE | WF_WING_DEPARTING) ) {
1657 what = INGAME_WING_DEPARTED;
1662 // include to code to possibly send more wing data here in this part of the if/else
1663 // chain. We can do this because MAX_WINGS * 8 (8 being the number of byte for a minimum
1664 // description of a wing) is always less than MAX_PACKET_SIZE. Checking here ensures that
1665 // we have enough space for *this* wing in the packet, and not the largest wing. The
1666 // formula below looks at number of ships in the wing, the name length, length of the signature,
1667 // and the size of the bytes added before the ship names. 32 accounts for a little slop
1668 if ( packet_size > (MAX_PACKET_SIZE - (wingp->current_count * (NAME_LENGTH+2) + 32)) ) {
1669 p_type = INGAME_WING_LIST_EOP;
1671 multi_io_send_reliable(player, data, packet_size);
1672 BUILD_HEADER( WINGS_INGAME_PACKET );
1674 what = INGAME_WING_PRESENT;
1676 ADD_DATA( wingp->total_arrived_count );
1677 ADD_DATA( wingp->current_count );
1678 ADD_DATA( wingp->current_wave );
1680 // add the ship name and net signature of all ships currently in the wing.
1681 for ( j = 0; j < wingp->current_count; j++ ) {
1684 shipp = &Ships[wingp->ship_index[j]];
1685 //ADD_STRING( shipp->ship_name );
1686 ADD_DATA( Objects[shipp->objnum].net_signature );
1692 p_type = INGAME_WING_LIST_EOL;
1695 multi_io_send_reliable(player, data, packet_size);
1699 // send a request or a reply regarding ingame join ship choice
1700 void send_ingame_ship_request_packet(int code,int rdata,net_player *pl)
1702 ubyte data[MAX_PACKET_SIZE],val;
1704 int i, packet_size = 0;
1709 BUILD_HEADER(INGAME_SHIP_REQUEST);
1714 // add any code specific data
1716 case INGAME_SR_REQUEST:
1717 // add the net signature of the ship we're requesting
1718 signature = (ushort)rdata;
1719 ADD_USHORT( signature );
1721 case INGAME_SR_CONFIRM:
1722 // get a pointer to the ship
1723 shipp = &Ships[Objects[rdata].instance];
1725 // add the most recent position and orientation for the requested ship
1726 //ADD_DATA(Objects[rdata].pos);
1727 add_vector_data( data, &packet_size, Objects[rdata].pos );
1728 ADD_ORIENT(Objects[rdata].orient);
1729 ADD_INT( Missiontime );
1731 // add the # of respawns this ship has left
1732 pobj = mission_parse_get_arrival_ship( Objects[rdata].net_signature );
1733 SDL_assert(pobj != NULL);
1734 ADD_UINT(pobj->respawn_count);
1736 // add the ships ets settings
1737 val = (ubyte)shipp->weapon_recharge_index;
1739 val = (ubyte)shipp->shield_recharge_index;
1741 val = (ubyte)shipp->engine_recharge_index;
1744 // add current primary and secondary banks, and add link status
1745 val = (ubyte)shipp->weapons.current_primary_bank;
1747 val = (ubyte)shipp->weapons.current_secondary_bank;
1750 // add the current ammo count for secondary banks;
1751 val = (ubyte)shipp->weapons.num_secondary_banks; // for sanity checking
1753 for ( i = 0; i < shipp->weapons.num_secondary_banks; i++ ) {
1754 SDL_assert( shipp->weapons.secondary_bank_ammo[i] < UCHAR_MAX );
1755 val = (ubyte)shipp->weapons.secondary_bank_ammo[i];
1759 // add the link status of weapons
1760 // primary link status
1762 if(shipp->flags & SF_PRIMARY_LINKED){
1765 if(shipp->flags & SF_SECONDARY_DUAL_FIRE){
1773 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1774 SDL_assert(pl != NULL);
1775 multi_io_send_reliable(pl, data, packet_size);
1777 multi_io_send_reliable(Net_player, data, packet_size);
1780 // if this is a confirm to a player -- send data to the other players in the game telling them
1781 if ( (code == INGAME_SR_CONFIRM) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) ) {
1784 player_num = NET_PLAYER_NUM(pl);
1785 code = INGAME_PLAYER_CHOICE;
1786 BUILD_HEADER(INGAME_SHIP_REQUEST);
1788 ADD_INT(player_num);
1789 ADD_USHORT(Objects[rdata].net_signature);
1790 for (i = 0; i < MAX_PLAYERS; i++ ) {
1791 if(MULTI_CONNECTED(Net_players[i]) && (&Net_players[i] != Net_player) && (i != player_num) ) {
1792 multi_io_send_reliable(&Net_players[i], data, packet_size);
1798 // function to validate all players in the game according to their team select index. If discrepancies
1799 // are found, this function should be able to fix them up.
1800 void multi_ingame_validate_players()
1804 for ( i = 0; i < MAX_PLAYERS; i++ ) {
1805 if( MULTI_CONNECTED(Net_players[i]) && (Net_player != &Net_players[i]) && !MULTI_STANDALONE(Net_players[i]) ) {
1806 const char *ship_name;
1807 int shipnum, objnum, player_objnum;
1809 player_objnum = Net_players[i].player->objnum;
1810 if ( (Objects[player_objnum].type != OBJ_SHIP) || (Objects[player_objnum].type != OBJ_GHOST) ) {
1814 ship_name = multi_ts_get_shipname( Net_players[i].p_info.team, Net_players[i].p_info.ship_index );
1815 SDL_assert( ship_name != NULL );
1816 shipnum = ship_name_lookup( ship_name );
1817 if ( shipnum == -1 ) {
1818 // ship could be respawning
1821 objnum = Ships[shipnum].objnum;
1822 SDL_assert( objnum != -1 );
1824 // if this guy's objnum isn't a ship, then it should proably be a ghost!!
1825 if ( Objects[objnum].type == OBJ_SHIP ) {
1826 if ( objnum != Net_players[i].player->objnum ) {
1828 Net_players[i].player->objnum = objnum;
1831 SDL_assert( Objects[objnum].type == OBJ_GHOST );
1837 // process an ingame ship request packet
1838 void process_ingame_ship_request_packet(ubyte *data, header *hinfo)
1842 int offset = HEADER_LENGTH;
1843 int team, slot_index, i;
1845 ubyte val, num_secondary_banks;
1853 // a request for a ship from an ingame joiner
1854 case INGAME_SR_REQUEST:
1857 // lookup the player and make sure he doesn't already have an objnum (along with possible error conditions)
1858 GET_USHORT(sig_request);
1861 player_num = find_player_id(hinfo->id);
1862 if(player_num == -1){
1863 nprintf(("Network","Received ingame ship request packet from unknown player!!\n"));
1867 // make sure this player doesn't already have an object
1868 SDL_assert(MULTI_CONNECTED(Net_players[player_num]));
1869 if(Net_players[player_num].player->objnum != -1){
1870 send_ingame_ship_request_packet(INGAME_SR_DENY,0,&Net_players[player_num]);
1874 // try and find the object
1876 objp = multi_get_network_object(sig_request);
1877 if(objp == NULL || !(objp->flags & OF_COULD_BE_PLAYER)){
1878 send_ingame_ship_request_packet(INGAME_SR_DENY,0,&Net_players[player_num]);
1882 // Assign the player this objnum and ack him
1883 Net_players[player_num].player->objnum = OBJ_INDEX(objp);
1884 Net_players[player_num].state = NETPLAYER_STATE_IN_MISSION; // since he'll do this anyway...
1885 Net_players[player_num].flags &= ~(NETINFO_FLAG_INGAME_JOIN);
1886 multi_assign_player_ship( player_num, objp, Ships[objp->instance].ship_info_index );
1888 // update his ets and link status stuff
1889 multi_server_update_player_weapons(&Net_players[player_num],&Ships[objp->instance]);
1891 objp->flags &= ~(OF_COULD_BE_PLAYER);
1892 objp->flags |= OF_PLAYER_SHIP;
1894 // send a player settings packet to update all other players of this guy's final choices
1895 send_player_settings_packet();
1897 // initialize datarate limiting for this guy
1898 multi_oo_rate_init(&Net_players[player_num]);
1901 send_ingame_ship_request_packet(INGAME_SR_CONFIRM,OBJ_INDEX(objp),&Net_players[player_num]);
1903 // clear my ingame join flag so that others may join
1904 Netgame.flags &= ~NG_FLAG_INGAME_JOINING;
1906 // clear his net stats
1907 scoring_level_init( &(Net_players[player_num].player->stats) );
1910 // a denial for the ship we requested from the server
1911 case INGAME_SR_DENY :
1914 // set this to -1 so we can pick again
1915 Multi_ingame_join_sig = 0;
1918 popup(PF_BODY_BIG | PF_USE_AFFIRMATIVE_ICON,1,POPUP_OK,XSTR("You have been denied the requested ship",686));
1921 // a confirmation that we can use the selected ship
1922 case INGAME_SR_CONFIRM:
1923 // object *temp_objp;
1925 // delete the ship this ingame joiner was using. Unassign Player_obj so that this object
1926 // doesn't become a ghost.
1927 // temp_objp = Player_obj;
1928 // Player_obj = NULL;
1929 // obj_delete( OBJ_INDEX(temp_objp) );
1931 // get the object itself
1932 objp = multi_get_network_object(Multi_ingame_join_sig);
1933 SDL_assert(objp != NULL);
1935 // get its most recent position and orientation
1936 //GET_DATA(objp->pos);
1937 get_vector_data( data, &offset, objp->pos );
1938 GET_ORIENT(objp->orient);
1939 GET_INT( Missiontime );
1940 GET_UINT( respawn_count );
1942 // tell the server I'm in the mission
1943 Net_player->state = NETPLAYER_STATE_IN_MISSION;
1944 send_netplayer_update_packet();
1947 Net_player->player->objnum = OBJ_INDEX(objp);
1949 Player_obj->flags &= ~(OF_COULD_BE_PLAYER);
1950 Player_obj->flags |= OF_PLAYER_SHIP;
1951 multi_assign_player_ship( MY_NET_PLAYER_NUM, objp, Ships[objp->instance].ship_info_index );
1953 // must change the ship type and weapons. An ingame joiner know about the default class
1954 // and weapons for a ship, but these could have changed.
1955 multi_ts_get_team_and_slot(Player_ship->ship_name, &team, &slot_index);
1956 SDL_assert( team != -1 );
1957 SDL_assert( slot_index != -1 );
1958 change_ship_type(objp->instance, Wss_slots_teams[team][slot_index].ship_class);
1959 wl_bash_ship_weapons(&Player_ship->weapons,&Wss_slots_teams[team][slot_index]);
1961 // get the parse object for it and assign the respawn count
1962 pobj = mission_parse_get_arrival_ship( objp->net_signature );
1963 SDL_assert(pobj != NULL);
1964 pobj->respawn_count = respawn_count;
1966 // get the ships ets settings
1968 Player_ship->weapon_recharge_index = val;
1970 Player_ship->shield_recharge_index = val;
1972 Player_ship->engine_recharge_index = val;
1974 // get current primary and secondary banks, and add link status
1976 Player_ship->weapons.current_primary_bank = val;
1978 Player_ship->weapons.current_secondary_bank = val;
1980 // secondary bank ammo data
1981 GET_DATA( num_secondary_banks );
1982 SDL_assert( num_secondary_banks == Player_ship->weapons.num_secondary_banks );
1983 for ( i = 0; i < Player_ship->weapons.num_secondary_banks; i++ ) {
1985 Player_ship->weapons.secondary_bank_ammo[i] = val;
1989 // get the link status of weapons
1992 Player_ship->flags |= SF_PRIMARY_LINKED;
1995 Player_ship->flags |= SF_SECONDARY_DUAL_FIRE;
1999 // be sure that this ships current primary/secondary weapons are valid. Easiest is to just
2000 // bash the values to 0!
2002 if ( Player_ship->weapons.current_primary_bank == -1 )
2003 Player_ship->weapons.current_primary_bank = 0;
2004 if ( Player_ship->weapons.current_secondary_bank == -1 )
2005 Player_ship->weapons.current_secondary_bank = 0;
2008 Net_player->flags &= ~(NETINFO_FLAG_INGAME_JOIN);
2010 // clear all object collision pairs, then add myself to the list
2011 extern void obj_reset_all_collisions();
2012 obj_reset_all_collisions();
2013 // obj_reset_pairs();
2014 // obj_add_pairs( OBJ_INDEX(Player_obj) );
2016 mission_hotkey_set_defaults();
2018 //multi_ingame_validate_players();
2020 // jump into the mission
2021 // NOTE : we check this flag because its possible that the player could have received an endgame packet in the same
2022 // frame as getting this confirmation. In that case, he should be quitting to the main menu. We must not make
2023 // him continue on into the mission
2024 if(!multi_endgame_ending()){
2025 gameseq_post_event(GS_EVENT_ENTER_GAME);
2029 case INGAME_PLAYER_CHOICE: {
2030 ushort net_signature;
2032 // get the player number of this guy, and the net signature of the ship he has chosen
2033 GET_INT(player_num);
2034 GET_USHORT(net_signature);
2037 objp = multi_get_network_object(net_signature);
2038 if ( objp == NULL ) {
2039 // bogus!!! couldn't find the object -- we cannot connect his -- this is really bad!!!
2040 nprintf(("Network", "Couldn't find ship for ingame joiner %s\n", Net_players[player_num].player->callsign));
2043 objp->flags |= OF_PLAYER_SHIP;
2044 objp->flags &= ~OF_COULD_BE_PLAYER;
2046 multi_assign_player_ship( player_num, objp, Ships[objp->instance].ship_info_index );
2054 // --------------------------------------------------------------------------------------------------
2055 // INGAME JOIN FORWARD DEFINITIONS
2058 void multi_ingame_send_ship_update(net_player *p)
2062 // get the first object on the list
2063 moveup = GET_FIRST(&Ship_obj_list);
2065 // go through the list and send all ships which are mark as OF_COULD_BE_PLAYER
2066 while(moveup!=END_OF_LIST(&Ship_obj_list)){
2067 if(Objects[moveup->objnum].flags & OF_COULD_BE_PLAYER){
2069 send_ingame_ship_update_packet(p,&Ships[Objects[moveup->objnum].instance]);
2072 // move to the next item
2073 moveup = GET_NEXT(moveup);
2077 // for now, I guess we'll just send hull and shield % values
2078 void send_ingame_ship_update_packet(net_player *p,ship *sp)
2080 ubyte data[MAX_PACKET_SIZE];
2083 int packet_size = 0;
2086 BUILD_HEADER(INGAME_SHIP_UPDATE);
2088 // just send net signature, shield and hull percentages
2089 objp = &Objects[sp->objnum];
2090 ADD_USHORT(objp->net_signature);
2091 ADD_UINT(objp->flags);
2092 ADD_FLOAT(objp->hull_strength);
2094 // shield percentages
2095 for(idx=0; idx<MAX_SHIELD_SECTIONS; idx++){
2096 f_tmp = objp->shields[idx];
2100 multi_io_send_reliable(p, data, packet_size);
2103 void process_ingame_ship_update_packet(ubyte *data, header *hinfo)
2113 offset = HEADER_LENGTH;
2114 // get the net sig for the ship and do a lookup
2115 GET_USHORT(net_sig);
2119 lookup = multi_get_network_object(net_sig);
2121 // read in garbage values if we can't find the ship
2122 nprintf(("Network","Got ingame ship update for unknown object\n"));
2124 for(idx=0;idx<MAX_SHIELD_SECTIONS;idx++){
2131 // otherwise read in the ship values
2132 lookup->flags = flags;
2133 GET_FLOAT(lookup->hull_strength);
2134 for(idx=0;idx<MAX_SHIELD_SECTIONS;idx++){
2136 lookup->shields[idx] = f_tmp;