Got rid of all compiler warnings, for non-OpenGL on linux, anyway...
[btb/d2x.git] / main / multi.c
1 /*
2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14 #include <conf.h>
15
16 #ifdef NETWORK
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <time.h>
22 #include <ctype.h>
23
24 #include "u_mem.h"
25 #include "strutil.h"
26 #include "game.h"
27 #include "modem.h"
28 #include "network.h"
29 #include "multi.h"
30 #include "object.h"
31 #include "laser.h"
32 #include "fuelcen.h"
33 #include "scores.h"
34 #include "gauges.h"
35 #include "collide.h"
36 #include "error.h"
37 #include "fireball.h"
38 #include "newmenu.h"
39 #include "mono.h"
40 #include "wall.h"
41 #include "cntrlcen.h"
42 #include "powerup.h"
43 #include "polyobj.h"
44 #include "bm.h"
45 #include "endlevel.h"
46 #include "key.h"
47 #include "playsave.h"
48 #include "timer.h"
49 #include "digi.h"
50 #include "sounds.h"
51 #include "kconfig.h"
52 #include "newdemo.h"
53 #include "text.h"
54 #include "kmatrix.h"
55 #include "multibot.h"
56 #include "gameseq.h"
57 #include "physics.h"
58 #include "config.h"
59 #include "state.h"
60 #include "ai.h"
61 #include "switch.h"
62 #include "textures.h"
63 #include "byteswap.h"
64 #include "sounds.h"
65 #include "args.h"
66 #include "d_delay.h"
67 #include "cfile.h"
68 #include "effects.h"
69
70 void multi_reset_player_object(object *objp);
71 void multi_reset_object_texture (object *objp);
72 void multi_add_lifetime_killed ();
73 void multi_add_lifetime_kills ();
74 void multi_send_play_by_play (int num,int spnum,int dpnum);
75 void multi_send_heartbeat ();
76 void multi_send_modem_ping ();
77 void multi_cap_objects ();
78 void multi_adjust_remote_cap (int pnum);
79 void multi_save_game(ubyte slot, uint id, char *desc);
80 void multi_restore_game(ubyte slot, uint id);
81 void multi_set_robot_ai(void);
82 void multi_send_powerup_update ();
83 void bash_to_shield (int i,char *s);
84 void init_hoard_data();
85 void multi_apply_goal_textures();
86 int find_goal_texture (ubyte t);
87 void multi_bad_restore ();
88 void multi_do_capture_bonus(char *buf);
89 void multi_do_orb_bonus(char *buf);
90 void multi_send_drop_flag (int objnum,int seed);
91 void multi_send_ranking ();
92 void multi_do_play_by_play (char *buf);
93
94 //
95 // Local macros and prototypes
96 //
97
98 // LOCALIZE ME!!
99
100 #define vm_angvec_zero(v) (v)->p=(v)->b=(v)->h=0
101
102 void drop_player_eggs(object *player); // from collide.c
103 void GameLoop(int, int); // From game.c
104
105 //
106 // Global variables
107 //
108
109 extern vms_vector MarkerPoint[];
110 extern char MarkerMessage[16][40];
111 extern char MarkerOwner[16][40];
112 extern int MarkerObject[];
113
114 int control_invul_time = 0;
115 int who_killed_controlcen = -1;  // -1 = noone
116
117 //do we draw the kill list on the HUD?
118 int Show_kill_list = 1;
119 int Show_reticle_name = 1;
120 fix Show_kill_list_timer = 0;
121
122 char Multi_is_guided=0;
123 char PKilledFlags[MAX_NUM_NET_PLAYERS];
124
125 int multi_sending_message = 0;
126 int multi_defining_message = 0;
127 int multi_message_index = 0;
128
129 char multibuf[MAX_MULTI_MESSAGE_LEN+4];                // This is where multiplayer message are built
130
131 short remote_to_local[MAX_NUM_NET_PLAYERS][MAX_OBJECTS];  // Remote object number for each local object
132 short local_to_remote[MAX_OBJECTS]; 
133 byte  object_owner[MAX_OBJECTS];   // Who created each object in my universe, -1 = loaded at start
134
135 int     Net_create_objnums[MAX_NET_CREATE_OBJECTS]; // For tracking object creation that will be sent to remote
136 int     Net_create_loc = 0;  // pointer into previous array
137 int     Network_laser_fired = 0; // How many times we shot
138 int     Network_laser_gun; // Which gun number we shot
139 int   Network_laser_flags; // Special flags for the shot
140 int   Network_laser_level; // What level
141 short   Network_laser_track; // Who is it tracking?
142 char    Network_message[MAX_MESSAGE_LEN];
143 char  Network_message_macro[4][MAX_MESSAGE_LEN];
144 int     Network_message_reciever=-1;
145 int     sorted_kills[MAX_NUM_NET_PLAYERS];
146 short kill_matrix[MAX_NUM_NET_PLAYERS][MAX_NUM_NET_PLAYERS];
147 int     multi_goto_secret = 0;
148 short   team_kills[2];
149 int     multi_in_menu = 0;
150 int     multi_leave_menu = 0;
151 int     multi_quit_game = 0;
152
153 netgame_info Netgame;
154 AllNetPlayers_info NetPlayers;
155
156 bitmap_index multi_player_textures[MAX_NUM_NET_PLAYERS][N_PLAYER_SHIP_TEXTURES];
157
158 typedef struct netplayer_stats {
159         ubyte           message_type;
160         ubyte           Player_num;                                             // Who am i?
161         uint            flags;                                                  // Powerup flags, see below...
162         fix             energy;                                                 // Amount of energy remaining.
163         fix             shields;                                                        // shields remaining (protection) 
164         ubyte           lives;                                                  // Lives remaining, 0 = game over.
165         ubyte           laser_level;                                    //      Current level of the laser.
166         ubyte           primary_weapon_flags;                                   //      bit set indicates the player has this weapon.
167         ubyte           secondary_weapon_flags;                                 //      bit set indicates the player has this weapon.
168         ushort  primary_ammo[MAX_PRIMARY_WEAPONS];      // How much ammo of each type.
169         ushort  secondary_ammo[MAX_SECONDARY_WEAPONS]; // How much ammo of each type.
170         int             last_score;                                     // Score at beginning of current level.
171         int             score;                                                  // Current score.
172         fix             cloak_time;                                             // Time cloaked
173         fix             invulnerable_time;                      // Time invulnerable
174         fix             homing_object_dist;                     //      Distance of nearest homing object.
175         short           KillGoalCount;
176         short           net_killed_total;                               // Number of times killed total
177         short           net_kills_total;                                // Number of net kills total
178         short           num_kills_level;                                // Number of kills this level
179         short           num_kills_total;                                // Number of kills total
180         short           num_robots_level;                       // Number of initial robots this level
181         short           num_robots_total;                       // Number of robots total
182         ushort  hostages_rescued_total;         // Total number of hostages rescued.
183         ushort  hostages_total;                         // Total number of hostages.
184         ubyte           hostages_on_board;                      //      Number of hostages on ship.
185         ubyte           unused[16];
186 } netplayer_stats;                                                      
187
188 int message_length[MULTI_MAX_TYPE+1] = {
189         24, // POSITION
190         3,  // REAPPEAR
191         8,  // FIRE
192         5,  // KILL
193         4,  // REMOVE_OBJECT
194         97+9, // PLAYER_EXPLODE
195         37, // MESSAGE (MAX_MESSAGE_LENGTH = 40)
196         2,  // QUIT
197         4,  // PLAY_SOUND
198         41, // BEGIN_SYNC
199         4,  // CONTROLCEN
200         5,  // CLAIM ROBOT
201         4,  // END_SYNC
202    2,  // CLOAK
203         3,  // ENDLEVEL_START
204    5,  // DOOR_OPEN
205         2,  // CREATE_EXPLOSION
206         16, // CONTROLCEN_FIRE
207         97+9, // PLAYER_DROP
208         19, // CREATE_POWERUP
209         9,  // MISSILE_TRACK
210         2,  // DE-CLOAK
211         2,       // MENU_CHOICE
212         28, // ROBOT_POSITION  (shortpos_length (23) + 5 = 28)
213         9,  // ROBOT_EXPLODE
214         5,       // ROBOT_RELEASE
215         18, // ROBOT_FIRE
216         6,  // SCORE
217         6,  // CREATE_ROBOT
218         3,  // TRIGGER
219         10, // BOSS_ACTIONS     
220         27, // ROBOT_POWERUPS
221         7,  // HOSTAGE_DOOR
222         2+24,   //SAVE_GAME             (ubyte slot, uint id, char name[20])
223         2+4,   //RESTORE_GAME   (ubyte slot, uint id)
224         1+1,    // MULTI_REQ_PLAYER
225         sizeof(netplayer_stats),                        // MULTI_SEND_PLAYER
226         55, // MULTI_MARKER
227         12, // MULTI_DROP_WEAPON
228 #ifndef MACINTOSH
229         3+sizeof(shortpos), // MULTI_GUIDED, IF SHORTPOS CHANGES, CHANGE MAC VALUE BELOW
230 #else
231         26,     //MULTI_GUIDED IF SIZE OF SHORTPOS CHANGES, CHANGE THIS VALUE AS WELL!!!!!!
232 #endif
233         11, // MULTI_STOLEN_ITEMS
234         6, // MULTI_WALL_STATUS
235         5, // MULTI_HEARTBEAT
236         9, // MULTI_KILLGOALS
237    9, // MULTI_SEISMIC
238         18, // MULTI_LIGHT
239    2, // MULTI_START_TRIGGER     
240         6, // MULTI_FLAGS
241         2, // MULTI_DROP_BLOB
242         MAX_POWERUP_TYPES+1, // MULTI_POWERUP_UPDATE
243         sizeof(active_door)+3, // MULTI_ACTIVE_DOOR
244         4, // MULTI_SOUND_FUNCTION
245         2, // MULTI_CAPTURE_BONUS
246    2, // MULTI_GOT_FLAG
247         12, // MULTI_DROP_FLAG
248    142, // MULTI_ROBOT_CONTROLS
249    2, // MULTI_FINISH_GAME
250    3, // MULTI_RANK
251    1, // MULTI_MODEM_PING
252    1, // MULTI_MODEM_PING_RETURN
253         3, // MULTI_ORB_BONUS
254    2, // MULTI_GOT_ORB
255         12, // MULTI_DROP_ORB
256         4,  // MULTI_PLAY_BY_PLAY
257 };
258
259 void extract_netplayer_stats( netplayer_stats *ps, player * pd );
260 void use_netplayer_stats( player * ps, netplayer_stats *pd );
261 char PowerupsInMine[MAX_POWERUP_TYPES],MaxPowerupsAllowed[MAX_POWERUP_TYPES];
262 extern fix ThisLevelTime;
263
264 //
265 //  Functions that replace what used to be macros
266 //              
267
268 int objnum_remote_to_local(int remote_objnum, int owner)
269 {
270         // Map a remote object number from owner to a local object number
271
272         int result;     
273
274         if ((owner >= N_players) || (owner < -1)) {
275                 Int3(); // Illegal!
276                 return(remote_objnum);
277         }
278
279         if (owner == -1)
280                 return(remote_objnum);
281         
282         if ((remote_objnum < 0) || (remote_objnum >= MAX_OBJECTS))
283                 return(-1);
284
285         result = remote_to_local[owner][remote_objnum];
286
287         if (result < 0)
288         {
289                 mprintf((1, "Remote object owner %d number %d mapped to -1!\n", owner, remote_objnum));
290                 return(-1);
291         }
292
293 #ifndef NDEBUG
294         if (object_owner[result] != owner)
295         {
296                 mprintf((1, "Remote object owner %d number %d doesn't match owner %d.\n", owner, remote_objnum, object_owner[result]));
297         }
298 #endif  
299 //      Assert(object_owner[result] == owner);
300
301         return(result);
302 }
303
304 int objnum_local_to_remote(int local_objnum, byte *owner)
305 {
306         // Map a local object number to a remote + owner
307
308         int result;
309
310         if ((local_objnum < 0) || (local_objnum > Highest_object_index)) {
311                 *owner = -1;
312                 return(-1);
313         }
314
315         *owner = object_owner[local_objnum];
316
317         if (*owner == -1)
318                 return(local_objnum);
319
320         if ((*owner >= N_players) || (*owner < -1)) {
321                 Int3(); // Illegal!
322                 *owner = -1;
323                 return local_objnum;
324         }
325         
326         result = local_to_remote[local_objnum];
327         
328 //      mprintf((0, "Local object %d mapped to owner %d objnum %d.\n", local_objnum,
329 //              *owner, result));
330
331         if (result < 0)
332         {
333                 Int3(); // See Rob, object has no remote number!
334         }
335
336         return(result);
337 }
338
339 void
340 map_objnum_local_to_remote(int local_objnum, int remote_objnum, int owner)
341 {
342         // Add a mapping from a network remote object number to a local one
343
344         Assert(local_objnum > -1);
345         Assert(remote_objnum > -1);
346         Assert(owner > -1);
347         Assert(owner != Player_num);
348         Assert(local_objnum < MAX_OBJECTS);
349         Assert(remote_objnum < MAX_OBJECTS);
350
351         object_owner[local_objnum] = owner;
352
353         remote_to_local[owner][remote_objnum] = local_objnum;
354         local_to_remote[local_objnum] = remote_objnum;
355
356         return;
357 }
358
359 void
360 map_objnum_local_to_local(int local_objnum)
361 {
362         // Add a mapping for our locally created objects
363
364         Assert(local_objnum > -1);
365         Assert(local_objnum < MAX_OBJECTS);
366
367         object_owner[local_objnum] = Player_num;
368         remote_to_local[Player_num][local_objnum] = local_objnum;
369         local_to_remote[local_objnum] = local_objnum;
370
371         return;
372 }
373
374 //
375 // Part 1 : functions whose main purpose in life is to divert the flow
376 //          of execution to either network or serial specific code based
377 //          on the curretn Game_mode value.
378 //
379
380 void
381 multi_endlevel_score(void)
382 {
383         int old_connect=0;
384         int i;
385
386         // Show a score list to end of net players
387
388         // Save connect state and change to new connect state
389 #ifdef NETWORK
390         if (Game_mode & GM_NETWORK)
391         {
392                 old_connect = Players[Player_num].connected;
393                 if (Players[Player_num].connected!=3)
394                  Players[Player_num].connected = CONNECT_END_MENU;
395                 Network_status = NETSTAT_ENDLEVEL;
396                 
397         }
398 #endif
399
400         // Do the actual screen we wish to show
401
402         Function_mode = FMODE_MENU;
403
404         kmatrix_view(Game_mode & GM_NETWORK);
405
406         Function_mode = FMODE_GAME;
407
408         // Restore connect state
409
410         if (Game_mode & GM_NETWORK)
411         {
412           Players[Player_num].connected = old_connect;
413         }
414
415 #ifndef SHAREWARE
416         if (Game_mode & GM_MULTI_COOP)
417         {
418            int i;
419                 for (i = 0; i < MaxNumNetPlayers; i++)
420                 // Reset keys
421                         Players[i].flags &= ~(PLAYER_FLAGS_BLUE_KEY | PLAYER_FLAGS_RED_KEY | PLAYER_FLAGS_GOLD_KEY);
422         }
423         for (i = 0; i < MaxNumNetPlayers; i++)
424            Players[i].flags &= ~(PLAYER_FLAGS_FLAG);  // Clear capture flag
425         
426 #endif
427
428   for (i=0;i<MAX_PLAYERS;i++)
429     Players[i].KillGoalCount=0;
430
431   for (i=0;i<MAX_POWERUP_TYPES;i++)
432         {
433                 MaxPowerupsAllowed[i]=0;
434                 PowerupsInMine[i]=0;
435         }  
436
437 }
438
439 int
440 get_team(int pnum)
441 {
442         if ((Game_mode & GM_CAPTURE) && ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM)))
443                 return pnum;
444
445         if (Netgame.team_vector & (1 << pnum))
446                 return 1;
447         else
448                 return 0;
449 }
450
451 int
452 multi_choose_mission(int *anarchy_only)
453 {
454         int i, n_missions;
455         int default_mission;
456    char *m[MAX_MISSIONS];
457         int new_mission_num = 0;
458
459         *anarchy_only = 0;
460
461         n_missions = build_mission_list(1);
462
463         if (n_missions > 1) {
464
465                 default_mission = 0;
466                 for (i=0;i<n_missions;i++) {
467                         m[i] = Mission_list[i].mission_name;
468                         if ( !stricmp( m[i], config_last_mission ) )    
469                                 default_mission = i;
470                 }
471
472       ExtGameStatus=GAMESTAT_START_MULTIPLAYER_MISSION;
473                 new_mission_num = newmenu_listbox1(TXT_MULTI_MISSION, n_missions, m, 1, default_mission, NULL );
474
475                 if (new_mission_num == -1)
476                         return -1;      //abort!
477
478                 strcpy(config_last_mission, m[new_mission_num]  );
479                 
480                 if (!load_mission(new_mission_num)) {
481                         nm_messagebox( NULL, 1, TXT_OK, TXT_MISSION_ERROR); 
482                         return -1;
483                 }
484
485            *anarchy_only = Mission_list[new_mission_num].anarchy_only_flag;
486         }
487         return(new_mission_num);
488 }
489
490 extern void game_disable_cheats();
491         
492 void
493 multi_new_game(void)
494 {
495         int i;
496         
497         // Reset variables for a new net game
498
499         memset(kill_matrix, 0, MAX_NUM_NET_PLAYERS*MAX_NUM_NET_PLAYERS*2); // Clear kill matrix
500
501         for (i = 0; i < MAX_NUM_NET_PLAYERS; i++)
502         {
503                 sorted_kills[i] = i;
504                 Players[i].net_killed_total = 0;
505                 Players[i].net_kills_total = 0;
506                 Players[i].flags = 0;
507                 Players[i].KillGoalCount=0;
508         }
509
510 #ifndef SHAREWARE
511         for (i = 0; i < MAX_ROBOTS_CONTROLLED; i++)
512         {
513                 robot_controlled[i] = -1;       
514                 robot_agitation[i] = 0;
515                 robot_fired[i] = 0;
516         }
517 #endif
518
519         team_kills[0] = team_kills[1] = 0;
520         Endlevel_sequence = 0;
521         Player_is_dead = 0;
522         multi_leave_menu = 0;
523         multi_quit_game = 0;
524         Show_kill_list = 1;
525         game_disable_cheats();
526         Player_exploded = 0;
527         Dead_player_camera = 0;
528 }
529         
530 void
531 multi_make_player_ghost(int playernum)
532 {
533         object *obj;
534
535 //      Assert(playernum != Player_num);
536 //      Assert(playernum < MAX_NUM_NET_PLAYERS);
537
538         if ((playernum == Player_num) || (playernum >= MAX_NUM_NET_PLAYERS) || (playernum < 0))
539         {
540                 Int3(); // Non-terminal, see Rob
541                 return;
542         }
543
544 //      if (Objects[Players[playernum].objnum].type != OBJ_PLAYER)
545 //              mprintf((1, "Warning: Player %d is not currently a player.\n", playernum));
546
547         obj = &Objects[Players[playernum].objnum];
548
549         obj->type = OBJ_GHOST;
550         obj->render_type = RT_NONE;
551         obj->movement_type = MT_NONE;
552         multi_reset_player_object(obj);
553
554         if (Game_mode & GM_MULTI_ROBOTS)
555                 multi_strip_robots(playernum);
556 }
557
558 void
559 multi_make_ghost_player(int playernum)
560 {
561         object *obj;
562
563 // Assert(playernum != Player_num);
564 // Assert(playernum < MAX_NUM_NET_PLAYERS);
565
566         if ((playernum == Player_num) || (playernum >= MAX_NUM_NET_PLAYERS))
567         {
568                 Int3(); // Non-terminal, see rob
569                 return;
570         }
571
572 //      if(Objects[Players[playernum].objnum].type != OBJ_GHOST)
573 //              mprintf((1, "Warning: Player %d is not currently a ghost.\n", playernum));
574
575         obj = &Objects[Players[playernum].objnum];
576
577         obj->type = OBJ_PLAYER;
578         obj->movement_type = MT_PHYSICS;
579         multi_reset_player_object(obj);
580 }
581
582 int multi_get_kill_list(int *plist)
583 {
584         // Returns the number of active net players and their
585         // sorted order of kills
586         int i;
587         int n = 0;
588
589         for (i = 0; i < N_players; i++)
590 //              if (Players[sorted_kills[i]].connected)
591                         plist[n++] = sorted_kills[i];
592
593         if (n == 0)
594                 Int3(); // SEE ROB OR MATT
595
596 //      memcpy(plist, sorted_kills, N_players*sizeof(int));     
597
598         return(n);
599 }
600         
601 void
602 multi_sort_kill_list(void)
603 {
604         // Sort the kills list each time a new kill is added
605
606         int kills[MAX_NUM_NET_PLAYERS];
607         int i;
608         int changed = 1;
609         
610         for (i = 0; i < MAX_NUM_NET_PLAYERS; i++)
611         {
612 #ifndef SHAREWARE
613                 if (Game_mode & GM_MULTI_COOP)
614                         kills[i] = Players[i].score;
615                 else
616 #endif
617                 if (Show_kill_list==2)
618                  {
619                   if (Players[i].net_killed_total+Players[i].net_kills_total==0)
620                         kills[i]=-1;  // always draw the ones without any ratio last
621                   else
622                    kills[i]=(int)((float)((float)Players[i].net_kills_total/((float)Players[i].net_killed_total+(float)Players[i].net_kills_total))*100.0);             
623                  }      
624                 else                    
625                         kills[i] = Players[i].net_kills_total;
626         }
627
628         while (changed)
629         {
630                 changed = 0;
631                 for (i = 0; i < N_players-1; i++)
632                 {
633                         if (kills[sorted_kills[i]] < kills[sorted_kills[i+1]])
634                         {
635                                 changed = sorted_kills[i];
636                                 sorted_kills[i] = sorted_kills[i+1];
637                                 sorted_kills[i+1] = changed;
638                                 changed = 1;
639                         }
640                 }
641         }
642       mprintf((0, "Sorted kills %d %d.\n", sorted_kills[0], sorted_kills[1]));
643 }
644
645 extern object *obj_find_first_of_type (int);
646 char Multi_killed_yourself=0;
647
648 void multi_compute_kill(int killer, int killed)
649 {
650         // Figure out the results of a network kills and add it to the
651         // appropriate player's tally.
652
653         int killed_pnum, killed_type;
654         int killer_pnum, killer_type,killer_id;
655         int TheGoal;
656         char killed_name[(CALLSIGN_LEN*2)+4];
657         char killer_name[(CALLSIGN_LEN*2)+4];
658
659         kmatrix_kills_changed = 1;
660    Multi_killed_yourself=0;
661   
662         // Both object numbers are localized already!
663
664         mprintf((0, "compute_kill passed: object %d killed object %d.\n", killer, killed));
665
666         if ((killed < 0) || (killed > Highest_object_index) || (killer < 0) || (killer > Highest_object_index))
667         {
668                 Int3(); // See Rob, illegal value passed to compute_kill;
669                 return;
670         }
671
672         killed_type = Objects[killed].type;
673         killer_type = Objects[killer].type;
674    killer_id = Objects[killer].id;
675
676         if ((killed_type != OBJ_PLAYER) && (killed_type != OBJ_GHOST)) 
677         {
678                 Int3(); // compute_kill passed non-player object!
679                 return;
680         }
681
682         killed_pnum = Objects[killed].id;
683
684    PKilledFlags[killed_pnum]=1;
685
686         Assert ((killed_pnum >= 0) && (killed_pnum < N_players));
687
688         if (Game_mode & GM_TEAM)
689                 sprintf(killed_name, "%s (%s)", Players[killed_pnum].callsign, Netgame.team_name[get_team(killed_pnum)]);
690         else
691                 sprintf(killed_name, "%s", Players[killed_pnum].callsign);
692
693         if (Newdemo_state == ND_STATE_RECORDING)
694                 newdemo_record_multi_death(killed_pnum);
695
696         digi_play_sample( SOUND_HUD_KILL, F3_0 );
697
698    if (Control_center_destroyed)
699          Players[killed_pnum].connected=3;
700
701         if (killer_type == OBJ_CNTRLCEN)
702         {
703                 Players[killed_pnum].net_killed_total++;
704                 Players[killed_pnum].net_kills_total--;
705
706                 if (Newdemo_state == ND_STATE_RECORDING)
707                         newdemo_record_multi_kill(killed_pnum, -1);
708
709                 if (killed_pnum == Player_num)
710                  {
711                         HUD_init_message("%s %s.", TXT_YOU_WERE, TXT_KILLED_BY_NONPLAY);
712                         multi_add_lifetime_killed ();
713                  }
714                 else
715                         HUD_init_message("%s %s %s.", killed_name, TXT_WAS, TXT_KILLED_BY_NONPLAY );
716                 return;         
717         }
718
719 #ifndef SHAREWARE
720         else if ((killer_type != OBJ_PLAYER) && (killer_type != OBJ_GHOST))
721         {
722                 if (killer_id==PMINE_ID && killer_type!=OBJ_ROBOT)
723             {
724                   if (killed_pnum == Player_num) 
725                                 HUD_init_message("You were killed by a mine!");
726                         else
727                                 HUD_init_message("%s was killed by a mine!",killed_name);
728                  }
729                 else
730             {
731                   if (killed_pnum == Player_num) 
732                          {
733                                 HUD_init_message("%s %s.", TXT_YOU_WERE, TXT_KILLED_BY_ROBOT);  
734                                 multi_add_lifetime_killed();
735                          }
736              else
737                                 HUD_init_message("%s %s %s.", killed_name, TXT_WAS, TXT_KILLED_BY_ROBOT );
738        }
739                 Players[killed_pnum].net_killed_total++;
740                 return;         
741         }
742 #else
743         else if ((killer_type != OBJ_PLAYER) && (killer_type != OBJ_GHOST) && (killer_id!=PMINE_ID))
744         {
745                 Int3(); // Illegal killer type?
746                 return;
747         }
748   if (killer_id==PMINE_ID)
749    {
750     if (killed_pnum==Player_num)
751            HUD_init_message("You were killed by a mine!");
752     else
753                 HUD_init_message("%s was killed by a mine!",killed_name);
754          
755     Players[killed_pnum].net_killed_total++;
756         
757     return;
758    }
759 #endif
760
761         killer_pnum = Objects[killer].id;
762
763         if (Game_mode & GM_TEAM)
764                 sprintf(killer_name, "%s (%s)", Players[killer_pnum].callsign, Netgame.team_name[get_team(killer_pnum)]);
765         else
766                 sprintf(killer_name, "%s", Players[killer_pnum].callsign);
767
768         // Beyond this point, it was definitely a player-player kill situation
769
770         if ((killer_pnum < 0) || (killer_pnum >= N_players))
771                 Int3(); // See rob, tracking down bug with kill HUD messages
772         if ((killed_pnum < 0) || (killed_pnum >= N_players))
773                 Int3(); // See rob, tracking down bug with kill HUD messages
774
775         if (killer_pnum == killed_pnum)
776         {
777       if (!(Game_mode & GM_HOARD))
778                 {
779                         if (Game_mode & GM_TEAM)
780                                 team_kills[get_team(killed_pnum)] -= 1;
781
782                         Players[killed_pnum].net_killed_total += 1;
783                         Players[killed_pnum].net_kills_total -= 1;
784
785                         if (Newdemo_state == ND_STATE_RECORDING)
786                                 newdemo_record_multi_kill(killed_pnum, -1);
787                 }
788                 kill_matrix[killed_pnum][killed_pnum] += 1; // # of suicides
789
790                 if (killer_pnum == Player_num)
791                  {
792                         HUD_init_message("%s %s %s!", TXT_YOU, TXT_KILLED, TXT_YOURSELF );      
793                    Multi_killed_yourself=1;
794                         multi_add_lifetime_killed();
795                  }
796                 else
797                         HUD_init_message("%s %s", killed_name, TXT_SUICIDE);
798         }
799
800         else
801         {
802                 if (!(Game_mode & GM_HOARD))
803                 {
804                         if (Game_mode & GM_TEAM)
805                         {
806                                 if (get_team(killed_pnum) == get_team(killer_pnum))
807                                         team_kills[get_team(killed_pnum)] -= 1;
808                                 else
809                                         team_kills[get_team(killer_pnum)] += 1;
810                         }
811
812                         Players[killer_pnum].net_kills_total += 1;
813                         Players[killer_pnum].KillGoalCount+=1;
814
815                         if (Newdemo_state == ND_STATE_RECORDING)
816                                 newdemo_record_multi_kill(killer_pnum, 1);
817                 }
818                 else
819                 {
820                         if (Game_mode & GM_TEAM)
821                         {
822                                 if (killed_pnum==Player_num && get_team(killed_pnum) == get_team(killer_pnum))
823                                         Multi_killed_yourself=1;
824                         }
825                 }
826         
827                 kill_matrix[killer_pnum][killed_pnum] += 1;
828                 Players[killed_pnum].net_killed_total += 1;
829                 if (killer_pnum == Player_num) {
830                         HUD_init_message("%s %s %s!", TXT_YOU, TXT_KILLED, killed_name);
831                         multi_add_lifetime_kills();
832                         if ((Game_mode & GM_MULTI_COOP) && (Players[Player_num].score >= 1000))
833                                 add_points_to_score(-1000);
834                 }
835                 else if (killed_pnum == Player_num)
836                   {
837                         HUD_init_message("%s %s %s!", killer_name, TXT_KILLED, TXT_YOU);
838                         multi_add_lifetime_killed();
839                         if (Game_mode & GM_HOARD) 
840                          {
841                                 if (Players[Player_num].secondary_ammo[PROXIMITY_INDEX]>3)
842                                         multi_send_play_by_play (1,killer_pnum,Player_num);
843                                 else if (Players[Player_num].secondary_ammo[PROXIMITY_INDEX]>0)
844                                         multi_send_play_by_play (0,killer_pnum,Player_num);
845                          }
846                   }
847                 else
848                         HUD_init_message("%s %s %s!", killer_name, TXT_KILLED, killed_name);
849         }
850
851   TheGoal=Netgame.KillGoal*5;
852
853   if (Netgame.KillGoal>0)
854         {
855          if (Players[killer_pnum].KillGoalCount>=TheGoal)
856           {
857            if (killer_pnum==Player_num)
858             {
859              HUD_init_message("You reached the kill goal!");
860              Players[Player_num].shields=i2f(200);
861             }  
862            else
863             HUD_init_message ("%s has reached the kill goal!",Players[killer_pnum].callsign);
864
865            HUD_init_message ("The control center has been destroyed!");
866       net_destroy_controlcen (obj_find_first_of_type (OBJ_CNTRLCEN));
867           }
868         }
869
870         multi_sort_kill_list();
871         multi_show_player_list();
872    Players[killed_pnum].flags&=(~(PLAYER_FLAGS_HEADLIGHT_ON));  // clear the killed guys flags/headlights
873 }
874
875 void
876 multi_do_frame(void)
877 {
878      static int lasttime=0;
879      int i;
880
881         if (!(Game_mode & GM_MULTI))
882         {
883                 Int3();
884                 return;
885         }
886
887   if ((Game_mode & GM_NETWORK) && Netgame.PlayTimeAllowed && lasttime!=f2i (ThisLevelTime))
888         {
889          for (i=0;i<N_players;i++)
890           if (Players[i].connected)
891            {
892             if (i==Player_num)
893              {
894               multi_send_heartbeat();
895               lasttime=f2i(ThisLevelTime);
896              }
897             break;
898            }
899         }
900
901         multi_send_message(); // Send any waiting messages
902
903         if (!multi_in_menu)
904                 multi_leave_menu = 0;
905
906 #ifndef SHAREWARE
907         if (Game_mode & GM_MULTI_ROBOTS)
908         {
909                 multi_check_robot_timeout();
910         }
911 #endif  
912
913         if ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM))
914         {
915                 com_do_frame();
916         }
917         else
918         {
919                 network_do_frame(0, 1);
920         }
921
922         if (multi_quit_game && !multi_in_menu)
923         {
924                 multi_quit_game = 0;
925                 longjmp(LeaveGame, 0);
926         }
927 }
928                 
929 void
930 multi_send_data(char *buf, int len, int repeat)
931 {
932         Assert(len == message_length[(int)buf[0]]);
933         Assert(buf[0] <= MULTI_MAX_TYPE);
934 //      Assert(buf[0] >= 0);
935
936         if (Game_mode & GM_NETWORK)
937                 Assert(buf[0] > 0);
938
939         if ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM))
940                 com_send_data(buf, len, repeat);
941         else if (Game_mode & GM_NETWORK)
942                 network_send_data(buf, len, repeat);
943 }
944
945 void
946 multi_leave_game(void)
947 {
948
949 //      if (Function_mode != FMODE_GAME)
950 //              return;
951
952         if (!(Game_mode & GM_MULTI))
953                 return;
954
955         if (Game_mode & GM_NETWORK)
956         {
957                 mprintf((0, "Sending explosion message.\n"));
958
959                 Net_create_loc = 0;
960                 AdjustMineSpawn();
961                 multi_cap_objects();
962                 drop_player_eggs(ConsoleObject);
963                 multi_send_position(Players[Player_num].objnum);
964                 multi_send_player_explode(MULTI_PLAYER_DROP);
965         }
966
967         mprintf((1, "Sending leave game.\n"));
968         multi_send_quit(MULTI_QUIT);
969
970         if ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM))
971                 serial_leave_game();
972         if (Game_mode & GM_NETWORK)
973                 network_leave_game();
974
975         Game_mode |= GM_GAME_OVER;
976
977    if (Function_mode!=FMODE_EXIT)
978                 Function_mode = FMODE_MENU;
979
980 //      N_players = 0;
981
982 //      change_playernum_to(0);
983 //      Viewer = ConsoleObject = &Objects[0];
984
985 }
986                 
987 void 
988 multi_show_player_list()
989 {
990         if (!(Game_mode & GM_MULTI) || (Game_mode & GM_MULTI_COOP))
991                 return;
992
993         if (Show_kill_list)
994                 return;
995
996         Show_kill_list_timer = F1_0*5; // 5 second timer
997         Show_kill_list = 1;
998 }
999
1000 int 
1001 multi_endlevel(int *secret)
1002 {
1003         int result = 0;
1004
1005         if ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM))
1006                 com_endlevel(secret);          // an opportunity to re-sync or whatever
1007         else if (Game_mode & GM_NETWORK)
1008                 result = network_endlevel(secret);
1009         
1010         return(result);         
1011 }
1012
1013 //
1014 // Part 2 : functions that act on network/serial messages and change the
1015 //          the state of the game in some way.
1016 //
1017
1018 #ifndef MACINTOSH
1019 //extern PORT *com_port;
1020 #endif
1021
1022 int 
1023 multi_menu_poll(void)
1024 {
1025         fix old_shields;
1026         int was_fuelcen_alive;
1027         int player_was_dead;
1028
1029         was_fuelcen_alive = Control_center_destroyed;
1030
1031         // Special polling function for in-game menus for multiplayer and serial
1032
1033         if (! ((Game_mode & GM_MULTI) && (Function_mode == FMODE_GAME)) )
1034                 return(0);
1035
1036         if (multi_leave_menu)
1037                 return(-1);
1038
1039         old_shields = Players[Player_num].shields;
1040         player_was_dead = Player_is_dead;
1041
1042         multi_in_menu++; // Track level of menu nesting
1043
1044         GameLoop( 0, 0 );                       
1045
1046         multi_in_menu--;
1047
1048 //      timer_delay(f1_0/10);   changed by allender for portability
1049         d_delay(100);                           // delay 100 milliseconds
1050                 
1051         if (Endlevel_sequence || (Control_center_destroyed && !was_fuelcen_alive) || (Player_is_dead != player_was_dead) || (Players[Player_num].shields < old_shields))
1052         {
1053                 multi_leave_menu = 1;
1054                 return(-1);
1055         }
1056         if ((Control_center_destroyed) && (Countdown_seconds_left < 10))
1057         {
1058                 multi_leave_menu = 1;
1059                 return(-1);
1060         }
1061
1062 #if !defined(WINDOWS) && !defined(MACINTOSH) && (!defined(__ENV_LINUX__) && (!defined (__ENV_DJGPP__)))
1063         if ((Game_mode & GM_MODEM) && (!GetCd(com_port)))
1064         {
1065                 multi_leave_menu = 1;
1066                 return(-1);
1067         }
1068 #endif
1069
1070         return(0);
1071 }
1072
1073 void
1074 multi_define_macro(int key)
1075 {
1076         if (!(Game_mode & GM_MULTI))
1077                 return;
1078
1079         key &= (~KEY_SHIFTED);
1080
1081         switch(key) 
1082         {
1083                 case KEY_F9:
1084                         multi_defining_message = 1; break;
1085                 case KEY_F10:
1086                         multi_defining_message = 2; break;
1087                 case KEY_F11:
1088                         multi_defining_message = 3; break;
1089                 case KEY_F12:
1090                         multi_defining_message = 4; break;
1091                 default:
1092                         Int3();
1093         }
1094
1095         if (multi_defining_message)     {
1096                 multi_message_index = 0;
1097                 Network_message[multi_message_index] = 0;
1098         }
1099
1100 }
1101
1102 char feedback_result[200];
1103
1104 void
1105 multi_message_feedback(void)
1106 {
1107         char *colon;
1108         int found = 0;
1109         int i;
1110
1111         if (!( ((colon = strrchr(Network_message, ':')) == NULL) || (colon-Network_message < 1) || (colon-Network_message > CALLSIGN_LEN) ))
1112         {
1113                 sprintf(feedback_result, "%s ", TXT_MESSAGE_SENT_TO);
1114                 if ((Game_mode & GM_TEAM) && (atoi(Network_message) > 0) && (atoi(Network_message) < 3))
1115                 {
1116                         sprintf(feedback_result+strlen(feedback_result), "%s '%s'", TXT_TEAM, Netgame.team_name[atoi(Network_message)-1]);
1117                         found = 1;
1118                 }
1119                 if (Game_mode & GM_TEAM)
1120                 {
1121                         for (i = 0; i < N_players; i++)
1122                         {
1123                                 if (!strnicmp(Netgame.team_name[i], Network_message, colon-Network_message))
1124                                 {
1125                                         if (found)
1126                                                 strcat(feedback_result, ", ");
1127                                         found++;
1128                                         if (!(found % 4))
1129                                                 strcat(feedback_result, "\n");
1130                                         sprintf(feedback_result+strlen(feedback_result), "%s '%s'", TXT_TEAM, Netgame.team_name[i]);
1131                                 }
1132                         }
1133                 }
1134                 for (i = 0; i < N_players; i++)
1135                 {
1136                         if ((!strnicmp(Players[i].callsign, Network_message, colon-Network_message)) && (i != Player_num) && (Players[i].connected))
1137                         {
1138                                 if (found)
1139                                         strcat(feedback_result, ", ");
1140                                 found++;
1141                                 if (!(found % 4))
1142                                         strcat(feedback_result, "\n");
1143                                 sprintf(feedback_result+strlen(feedback_result), "%s", Players[i].callsign);
1144                         }
1145                 }
1146                 if (!found)
1147                         strcat(feedback_result, TXT_NOBODY);
1148                 else
1149                         strcat(feedback_result, ".");
1150
1151                 digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
1152
1153                 Assert(strlen(feedback_result) < 200);
1154
1155                 HUD_init_message(feedback_result);
1156 //      sprintf (temp,"%s",colon);
1157 //         sprintf (Network_message,"%s",temp);
1158  
1159         }
1160 }
1161
1162 void
1163 multi_send_macro(int key)
1164 {
1165         if (! (Game_mode & GM_MULTI) )
1166                 return;
1167
1168         switch(key) 
1169         {
1170                 case KEY_F9:
1171                         key = 0; break;
1172                 case KEY_F10:
1173                         key = 1; break;
1174                 case KEY_F11:
1175                         key = 2; break;
1176                 case KEY_F12:
1177                         key = 3; break;
1178                 default:
1179                         Int3();
1180         }
1181
1182         if (!Network_message_macro[key][0])
1183         {
1184                 HUD_init_message(TXT_NO_MACRO);
1185                 return;
1186         }
1187
1188         strcpy(Network_message, Network_message_macro[key]);
1189         Network_message_reciever = 100;
1190
1191         HUD_init_message("%s '%s'", TXT_SENDING, Network_message);
1192         multi_message_feedback();
1193 }
1194
1195
1196 void 
1197 multi_send_message_start()
1198 {
1199         if (Game_mode&GM_MULTI) {
1200                 multi_sending_message = 1;
1201                 multi_message_index = 0;
1202                 Network_message[multi_message_index] = 0;
1203         }
1204 }
1205
1206 extern fix StartingShields;
1207 fix PingLaunchTime,PingReturnTime;
1208
1209 extern void network_send_ping (ubyte);
1210 extern void network_dump_player(ubyte * server, ubyte *node, int why);
1211 extern int network_who_is_master();
1212 extern void network_send_netgame_update();
1213 extern char NameReturning;
1214 extern int force_cockpit_redraw;
1215
1216 void network_dump_appletalk_player(ubyte node, ushort net, ubyte socket, int why);
1217
1218 void multi_send_message_end()
1219 {
1220         char *mytempbuf;
1221    int i,t;
1222         
1223         Network_message_reciever = 100;
1224
1225         if (!strnicmp (Network_message,"!Names",6))
1226                 {
1227                  NameReturning=1-NameReturning;
1228                  HUD_init_message ("Name returning is now %s.",NameReturning?"active":"disabled");
1229                 }
1230         else if (!strnicmp (Network_message,"Handicap:",9))
1231                 {
1232                  mytempbuf=&Network_message[9];          
1233                  mprintf ((0,"Networkhandi=%s\n",mytempbuf));
1234                  StartingShields=atol (mytempbuf);
1235                  if (StartingShields<10)
1236                         StartingShields=10;
1237                  if (StartingShields>100)
1238                         {
1239                                 sprintf (Network_message,"%s has tried to cheat!",Players[Player_num].callsign);
1240                                 StartingShields=100;
1241                         }
1242                  else
1243                         sprintf (Network_message,"%s handicap is now %d",Players[Player_num].callsign,StartingShields);
1244
1245                  HUD_init_message ("Telling others of your handicap of %d!",StartingShields);
1246                  StartingShields=i2f(StartingShields);
1247                 }
1248         else if (!strnicmp (Network_message,"NoBombs",7))
1249          Netgame.DoSmartMine=0;
1250         else if (!strnicmp (Network_message,"Ping:",5))
1251          {
1252           if (Game_mode & GM_NETWORK)
1253                 {
1254                         int name_index=5;
1255                         if (strlen(Network_message) > 5)
1256                                 while (Network_message[name_index] == ' ')
1257                                         name_index++;
1258
1259                         if (strlen(Network_message)<=name_index)
1260                          {
1261                                 HUD_init_message ("You must specify a name to ping");
1262                                 return;
1263                          }
1264
1265                         for (i = 0; i < N_players; i++)
1266                 if ((!strnicmp(Players[i].callsign, &Network_message[name_index], strlen(Network_message)-name_index)) && (i != Player_num) && (Players[i].connected))
1267             {
1268                                  PingLaunchTime=timer_get_fixed_seconds();
1269                                  network_send_ping (i);
1270                                  HUD_init_message("Pinging %s...",Players[i].callsign);
1271                             multi_message_index = 0;
1272                                  multi_sending_message = 0;
1273                                  return;
1274                            }
1275                 }
1276           else // Modem/Serial ping
1277            {
1278                          PingLaunchTime=timer_get_fixed_seconds();
1279                          multi_send_modem_ping ();
1280                          HUD_init_message("Pinging opponent...");
1281                     multi_message_index = 0;
1282                          multi_sending_message = 0;
1283                          return;
1284            }
1285          }                                                                                               
1286         else if (!strnicmp (Network_message,"move:",5))
1287          { 
1288                 mprintf ((0,"moving?\n"));
1289                 
1290           if ((Game_mode & GM_NETWORK) && (Game_mode & GM_TEAM))
1291                 {
1292                         int name_index=5;
1293                         if (strlen(Network_message) > 5)
1294                                 while (Network_message[name_index] == ' ')
1295                                         name_index++;
1296
1297                   if (!network_i_am_master())
1298                         {       
1299                          HUD_init_message ("Only %s can move players!",Players[network_who_is_master()].callsign);
1300                          return;
1301                         }
1302         
1303                         if (strlen(Network_message)<=name_index)
1304                          {
1305                                 HUD_init_message ("You must specify a name to move");
1306                                 return;
1307                          }
1308
1309                         for (i = 0; i < N_players; i++)
1310                 if ((!strnicmp(Players[i].callsign, &Network_message[name_index], strlen(Network_message)-name_index)) && (Players[i].connected))
1311             {
1312                                  if ((Game_mode & GM_CAPTURE) && (Players[i].flags & PLAYER_FLAGS_FLAG))
1313                                   {
1314                                         HUD_init_message ("Can't move player because s/he has a flag!");
1315                                         return;
1316                                   }
1317                 
1318                                  if (Netgame.team_vector & (1<<i))
1319                                    Netgame.team_vector&=(~(1<<i));
1320                                  else
1321                                    Netgame.team_vector|=(1<<i);
1322         
1323                                  for (t=0;t<N_players;t++)
1324                                  if (Players[t].connected)
1325                                 multi_reset_object_texture (&Objects[Players[t].objnum]);
1326
1327                                  network_send_netgame_update ();        
1328                                  sprintf (Network_message,"%s has changed teams!",Players[i].callsign);
1329                                  if (i==Player_num)
1330                                         {
1331                                     HUD_init_message ("You have changed teams!");
1332                                          reset_cockpit();       
1333                                         }
1334                                  else
1335                                          HUD_init_message ("Moving %s to other team.",Players[i].callsign);
1336                                  break;
1337                            }
1338                   }    
1339          }                                                                                               
1340
1341         else if (!strnicmp (Network_message,"kick:",5) && (Game_mode & GM_NETWORK))
1342          {
1343                 int name_index=5;
1344                 if (strlen(Network_message) > 5)
1345                         while (Network_message[name_index] == ' ')
1346                                 name_index++;
1347
1348           if (!network_i_am_master())
1349                 {       
1350                  HUD_init_message ("Only %s can kick others out!",Players[network_who_is_master()].callsign);
1351             multi_message_index = 0;
1352             multi_sending_message = 0;
1353                  return;
1354                 }
1355                 if (strlen(Network_message)<=name_index)
1356                  {
1357                         HUD_init_message ("You must specify a name to kick");
1358                         multi_message_index = 0;
1359                         multi_sending_message = 0;
1360                         return;
1361                  }
1362
1363                 if (Network_message[name_index] == '#' && isdigit(Network_message[name_index+1])) {
1364                         int players[MAX_NUM_NET_PLAYERS];
1365                         int listpos = Network_message[name_index+1] - '0';
1366
1367                         mprintf ((0,"Trying to kick %d , show_kill_list=%d\n",listpos,Show_kill_list));
1368
1369                         if (Show_kill_list==1 || Show_kill_list==2) {
1370                                 if (listpos == 0 || listpos >= N_players) {
1371                                         HUD_init_message ("Invalid player number for kick.");
1372                                    multi_message_index = 0;
1373                                    multi_sending_message = 0;
1374                                         return;
1375                                 }
1376                                 multi_get_kill_list(players);
1377                                 i = players[listpos];
1378                                 if ((i != Player_num) && (Players[i].connected))
1379                                         goto kick_player;
1380                         }
1381                         else HUD_init_message ("You cannot use # kicking with in team display.");
1382                                 
1383
1384                     multi_message_index = 0;
1385                     multi_sending_message = 0;
1386                          return;
1387                 }
1388
1389
1390                 for (i = 0; i < N_players; i++)
1391                 if ((!strnicmp(Players[i].callsign, &Network_message[name_index], strlen(Network_message)-name_index)) && (i != Player_num) && (Players[i].connected)) {
1392 kick_player:;
1393                         if (Network_game_type == IPX_GAME)
1394                                         network_dump_player(NetPlayers.players[i].network.ipx.server,NetPlayers.players[i].network.ipx.node, 7);
1395                                 else
1396                                         network_dump_appletalk_player(NetPlayers.players[i].network.appletalk.node,NetPlayers.players[i].network.appletalk.net, NetPlayers.players[i].network.appletalk.socket, 7);
1397                                 
1398                                 HUD_init_message("Dumping %s...",Players[i].callsign);
1399                                 multi_message_index = 0;
1400                                 multi_sending_message = 0;
1401                                 return;
1402                         }
1403          }                                                                                               
1404
1405    else
1406                 HUD_init_message("%s '%s'", TXT_SENDING, Network_message);
1407
1408         multi_send_message();
1409         multi_message_feedback();               
1410
1411         multi_message_index = 0;
1412         multi_sending_message = 0;
1413 }
1414
1415 void multi_define_macro_end()
1416 {
1417         Assert( multi_defining_message > 0 );
1418
1419         strcpy( Network_message_macro[multi_defining_message-1], Network_message );
1420         write_player_file();
1421
1422         multi_message_index = 0;
1423         multi_defining_message = 0;
1424 }
1425
1426 void multi_message_input_sub( int key )
1427 {
1428         switch( key )   {
1429         case KEY_F8:
1430         case KEY_ESC:
1431                 multi_sending_message = 0;
1432                 multi_defining_message = 0;
1433                 game_flush_inputs();
1434                 break;
1435         case KEY_LEFT:
1436         case KEY_BACKSP:
1437         case KEY_PAD4:
1438                 if (multi_message_index > 0)
1439                         multi_message_index--;
1440                 Network_message[multi_message_index] = 0;
1441                 break;
1442         case KEY_ENTER:
1443                 if ( multi_sending_message )    
1444                         multi_send_message_end();
1445                 else if ( multi_defining_message )
1446                         multi_define_macro_end();
1447                 game_flush_inputs();
1448                 break;
1449         default:
1450                 if ( key > 0 )  {
1451                         int ascii = key_to_ascii(key);
1452                         if ((ascii < 255 ))     {
1453                                 if (multi_message_index < MAX_MESSAGE_LEN-2 )   {
1454                                         Network_message[multi_message_index++] = ascii;
1455                                         Network_message[multi_message_index] = 0;
1456                                 } else if ( multi_sending_message )     {               
1457                                         int i;
1458                                         char * ptext, * pcolon;
1459                                         ptext = NULL;
1460                                         Network_message[multi_message_index++] = ascii;
1461                                         Network_message[multi_message_index] = 0;
1462                                         for (i=multi_message_index-1; i>=0; i-- )       {
1463                                                 if ( Network_message[i]==32 )   {
1464                                                         ptext = &Network_message[i+1];
1465                                                         Network_message[i] = 0;
1466                                                         break;
1467                                                 }
1468                                         }
1469                                         multi_send_message_end();
1470                                         if ( ptext )    {
1471                                                 multi_sending_message = 1;
1472                                                 pcolon = strchr( Network_message, ':' );
1473                                                 if ( pcolon )
1474                                                         strcpy( pcolon+1, ptext );
1475                                                 else
1476                                                         strcpy( Network_message, ptext );
1477                                                 multi_message_index = strlen( Network_message );
1478                                         } 
1479                                 }
1480                         }
1481                 }
1482         }
1483 }
1484
1485 void 
1486 multi_send_message_dialog(void)
1487 {
1488         newmenu_item m[1];
1489         int choice;
1490
1491         if (!(Game_mode&GM_MULTI))
1492                 return;
1493
1494         Network_message[0] = 0;             // Get rid of old contents
1495
1496         m[0].type=NM_TYPE_INPUT; m[0].text = Network_message; m[0].text_len = MAX_MESSAGE_LEN-1;
1497         choice = newmenu_do( NULL, TXT_SEND_MESSAGE, 1, m, NULL );
1498
1499         if ((choice > -1) && (strlen(Network_message) > 0)) {
1500                 Network_message_reciever = 100;
1501                 HUD_init_message("%s '%s'", TXT_SENDING, Network_message);
1502                 multi_message_feedback();               
1503         }
1504 }
1505
1506
1507
1508 void
1509 multi_do_death(int objnum)
1510 {
1511         // Do any miscellaneous stuff for a new network player after death
1512
1513         objnum = objnum;
1514
1515         if (!(Game_mode & GM_MULTI_COOP)) 
1516         {
1517                 mprintf((0, "Setting all keys for player %d.\n", Player_num));
1518                 Players[Player_num].flags |= (PLAYER_FLAGS_RED_KEY | PLAYER_FLAGS_BLUE_KEY | PLAYER_FLAGS_GOLD_KEY);
1519         }
1520 }
1521
1522 void
1523 multi_do_fire(char *buf)
1524 {
1525         ubyte weapon;
1526         char pnum;
1527         byte flags;
1528    //static dum=0;
1529         
1530         // Act out the actual shooting
1531         pnum = buf[1];
1532
1533 #ifndef MACINTOSH
1534         weapon = (int)buf[2];   
1535 #else
1536         weapon = buf[2];
1537 #endif
1538         flags = buf[4];
1539         Network_laser_track = INTEL_SHORT(*(short *)(buf+6));
1540         
1541         Assert (pnum < N_players);
1542
1543         if (Objects[Players[(int)pnum].objnum].type == OBJ_GHOST)
1544                 multi_make_ghost_player(pnum);
1545
1546    //  mprintf((0,"multi_do_fire, weapon = %d\n",weapon));
1547
1548         if (weapon == FLARE_ADJUST)
1549                 Laser_player_fire( Objects+Players[(int)pnum].objnum, FLARE_ID, 6, 1, 0);
1550         else if (weapon >= MISSILE_ADJUST) {
1551                 int weapon_id,weapon_gun;
1552
1553                 weapon_id = Secondary_weapon_to_weapon_info[weapon-MISSILE_ADJUST];
1554                 weapon_gun = Secondary_weapon_to_gun_num[weapon-MISSILE_ADJUST] + (flags & 1);
1555                 mprintf((0,"missile id = %d, gun = %d\n",weapon_id,weapon_gun));
1556
1557                 if (weapon-MISSILE_ADJUST==GUIDED_INDEX)
1558                  {
1559                   mprintf ((0,"Missile is guided!!!\n"));
1560                   Multi_is_guided=1;
1561                  }
1562
1563                 Laser_player_fire( Objects+Players[(int)pnum].objnum, weapon_id, weapon_gun, 1, 0 );
1564         }
1565         else {
1566                 fix save_charge = Fusion_charge;
1567
1568                 if (weapon == FUSION_INDEX) {
1569                         Fusion_charge = flags << 12;
1570                         mprintf((0, "Fusion charge X%f.\n", f2fl(Fusion_charge)));
1571                 }
1572                 if (weapon == LASER_ID) {
1573                         if (flags & LASER_QUAD)
1574                                 Players[(int)pnum].flags |= PLAYER_FLAGS_QUAD_LASERS;
1575                         else
1576                                 Players[(int)pnum].flags &= ~PLAYER_FLAGS_QUAD_LASERS;
1577                 }
1578         
1579                 do_laser_firing(Players[(int)pnum].objnum, weapon, (int)buf[3], flags, (int)buf[5]);
1580         
1581                 if (weapon == FUSION_INDEX)
1582                         Fusion_charge = save_charge;
1583         }
1584 }
1585
1586 void 
1587 multi_do_message(char *buf)
1588 {
1589         char *colon;
1590    char *tilde,mesbuf[100];
1591    int tloc,t;
1592
1593         int loc = 2;
1594         
1595    if ((tilde=strchr (buf+loc,'$')))  // do that stupid name stuff
1596          {                                                                                      // why'd I put this in?  Probably for the
1597           tloc=tilde-(buf+loc);                         // same reason you can name your guidebot
1598           mprintf ((0,"Tloc=%d\n",tloc));
1599    
1600           if (tloc>0)
1601           strncpy (mesbuf,buf+loc,tloc);
1602           strcpy (mesbuf+tloc,Players[Player_num].callsign);
1603      strcpy (mesbuf+strlen(Players[Player_num].callsign)+tloc,buf+loc+tloc+1);
1604      strcpy (buf+loc,mesbuf);
1605          }      
1606  
1607         if (((colon = strrchr(buf+loc, ':')) == NULL) || (colon-(buf+loc) < 1) || (colon-(buf+loc) > CALLSIGN_LEN))
1608         {
1609            mesbuf[0] = 1;
1610                 mesbuf[1] = BM_XRGB(28, 0, 0);
1611                 strcpy(&mesbuf[2], Players[(int)buf[1]].callsign);
1612                 t = strlen(mesbuf);
1613                 mesbuf[t] = ':';
1614                 mesbuf[t+1] = 1;
1615                 mesbuf[t+2] = BM_XRGB(0, 31, 0);
1616                 mesbuf[t+3] = 0;
1617
1618                 digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
1619                 HUD_init_message("%s %s", mesbuf, buf+2);
1620         }
1621         else
1622         {
1623                 if ( (!strnicmp(Players[Player_num].callsign, buf+loc, colon-(buf+loc))) ||
1624                           ((Game_mode & GM_TEAM) && ( (get_team(Player_num) == atoi(buf+loc)-1) || !strnicmp(Netgame.team_name[get_team(Player_num)], buf+loc, colon-(buf+loc)))) )
1625                 {
1626                    mesbuf[0] = 1;
1627                         mesbuf[1] = BM_XRGB(0, 32, 32);
1628                         strcpy(&mesbuf[2], Players[(int)buf[1]].callsign);
1629                         t = strlen(mesbuf);
1630                         mesbuf[t] = ':';
1631                         mesbuf[t+1] = 1;
1632                         mesbuf[t+2] = BM_XRGB(0, 31, 0);
1633                         mesbuf[t+3] = 0;
1634
1635                         digi_play_sample(SOUND_HUD_MESSAGE, F1_0);      
1636                 HUD_init_message("%s %s", mesbuf, colon+1);
1637                 }
1638         }
1639 }
1640
1641 void
1642 multi_do_position(char *buf)
1643 {               
1644 #ifdef MACINTOSH
1645         shortpos sp;
1646 #endif
1647
1648         // This routine does only player positions, mode game only
1649         //      mprintf((0, "Got position packet.\n"));
1650
1651         int pnum = (Player_num+1)%2;
1652
1653         Assert(&Objects[Players[pnum].objnum] != ConsoleObject);
1654
1655         if (Game_mode & GM_NETWORK)
1656          {
1657           Int3(); // Get Jason, what the hell are we doing here?
1658           return;
1659     }
1660          
1661
1662 #ifndef MACINTOSH
1663         extract_shortpos(&Objects[Players[pnum].objnum], (shortpos *)(buf+1),0);
1664 #else
1665         memcpy((ubyte *)(sp.bytemat), (ubyte *)(buf + 1), 9);
1666         memcpy((ubyte *)&(sp.xo), (ubyte *)(buf + 10), 14);
1667         extract_shortpos(&Objects[Players[pnum].objnum], &sp, 1);
1668 #endif
1669
1670         if (Objects[Players[pnum].objnum].movement_type == MT_PHYSICS)
1671                 set_thrust_from_velocity(&Objects[Players[pnum].objnum]);
1672 }
1673
1674 void
1675 multi_do_reappear(char *buf)
1676 {
1677         short objnum;
1678
1679         objnum = INTEL_SHORT(*(short *)(buf+1));
1680
1681         Assert(objnum >= 0);
1682 //      Assert(Players[Objects[objnum].id]].objnum == objnum);
1683         
1684 // mprintf((0, "Switching rendering back on for object %d.\n", objnum));
1685
1686         multi_make_ghost_player(Objects[objnum].id);
1687         create_player_appearance_effect(&Objects[objnum]);
1688         PKilledFlags[Objects[objnum].id]=0;
1689 }
1690         
1691 void
1692 multi_do_player_explode(char *buf)
1693 {
1694         // Only call this for players, not robots.  pnum is player number, not
1695         // Object number.
1696
1697         object *objp;
1698         int count;
1699         int pnum;
1700         int i;
1701         char remote_created;
1702
1703         pnum = buf[1];
1704
1705 #ifdef NDEBUG
1706         if ((pnum < 0) || (pnum >= N_players))
1707                 return;
1708 #else
1709         Assert(pnum >= 0);
1710         Assert(pnum < N_players);
1711 #endif
1712
1713 #ifdef NETWORK
1714         // If we are in the process of sending objects to a new player, reset that process
1715         if (Network_send_objects)
1716         {
1717                 mprintf((0, "Resetting object sync due to player explosion.\n"));
1718                 Network_send_objnum = -1;
1719         }
1720 #endif
1721
1722         // Stuff the Players structure to prepare for the explosion
1723         
1724         count = 2;
1725         Players[pnum].primary_weapon_flags = INTEL_SHORT(*(ushort *)(buf+count)); count += 2;
1726         Players[pnum].secondary_weapon_flags = INTEL_SHORT(*(ushort *)(buf+count)); count += 2;
1727         Players[pnum].laser_level = buf[count];                                                 count++;
1728         Players[pnum].secondary_ammo[HOMING_INDEX] = buf[count];                count++;
1729         Players[pnum].secondary_ammo[CONCUSSION_INDEX] = buf[count];count++;
1730         Players[pnum].secondary_ammo[SMART_INDEX] = buf[count];         count++;
1731         Players[pnum].secondary_ammo[MEGA_INDEX] = buf[count];          count++;
1732         Players[pnum].secondary_ammo[PROXIMITY_INDEX] = buf[count]; count++;
1733
1734         Players[pnum].secondary_ammo[SMISSILE1_INDEX] = buf[count]; count++;
1735         Players[pnum].secondary_ammo[GUIDED_INDEX]    = buf[count]; count++;
1736         Players[pnum].secondary_ammo[SMART_MINE_INDEX]= buf[count]; count++;
1737         Players[pnum].secondary_ammo[SMISSILE4_INDEX] = buf[count]; count++;
1738         Players[pnum].secondary_ammo[SMISSILE5_INDEX] = buf[count]; count++;
1739
1740         Players[pnum].primary_ammo[VULCAN_INDEX] = INTEL_SHORT(*(ushort *)(buf+count)); count += 2;
1741         Players[pnum].primary_ammo[GAUSS_INDEX] = INTEL_SHORT(*(ushort *)(buf+count)); count += 2;
1742         Players[pnum].flags = INTEL_INT(*(uint *)(buf+count));                     count += 4;
1743     
1744         multi_adjust_remote_cap (pnum);
1745
1746         objp = Objects+Players[pnum].objnum;
1747
1748 //      objp->phys_info.velocity = *(vms_vector *)(buf+16); // 12 bytes
1749 //      objp->pos = *(vms_vector *)(buf+28);                // 12 bytes
1750
1751         remote_created = buf[count++]; // How many did the other guy create?
1752
1753         Net_create_loc = 0;
1754
1755         drop_player_eggs(objp);
1756  
1757         // Create mapping from remote to local numbering system
1758
1759         mprintf((0, "I Created %d powerups, remote created %d.\n", Net_create_loc, remote_created));
1760
1761         // We now handle this situation gracefully, Int3 not required
1762         //      if (Net_create_loc != remote_created)
1763         //              Int3(); // Probably out of object array space, see Rob
1764
1765         for (i = 0; i < remote_created; i++)
1766         {
1767                 short s;
1768                 
1769                 s = INTEL_SHORT(*(short *)(buf+count));
1770                 
1771                 if ((i < Net_create_loc) && (s > 0))
1772                         map_objnum_local_to_remote((short)Net_create_objnums[i], s, pnum);          
1773                 else if (*(short *)(buf+count) <= 0)
1774                 {
1775                         mprintf((0, "WARNING: Remote created object has non-valid number %d (player %d)", s, pnum));
1776                 }
1777                 else 
1778                 {
1779                         mprintf((0, "WARNING: Could not create all powerups created by player %d.\n", pnum));
1780                 }
1781 //              Assert(s > 0);
1782                 count += 2;
1783         }
1784         for (i = remote_created; i < Net_create_loc; i++) {
1785                 mprintf((0, "WARNING: I Created more powerups than player %d, deleting.\n", pnum));
1786                 Objects[Net_create_objnums[i]].flags |= OF_SHOULD_BE_DEAD;
1787         }
1788
1789         if (buf[0] == MULTI_PLAYER_EXPLODE)
1790         {
1791                 explode_badass_player(objp);
1792                 
1793                 objp->flags &= ~OF_SHOULD_BE_DEAD;              //don't really kill player
1794                 multi_make_player_ghost(pnum);
1795         }
1796         else
1797         {
1798                 create_player_appearance_effect(objp);
1799         }
1800
1801         Players[pnum].flags &= ~(PLAYER_FLAGS_CLOAKED | PLAYER_FLAGS_INVULNERABLE | PLAYER_FLAGS_FLAG);
1802         Players[pnum].cloak_time = 0;
1803 }
1804
1805 void
1806 multi_do_kill(char *buf)
1807 {
1808         int killer, killed;
1809         int count = 1;
1810         int pnum;
1811         
1812         pnum = (int)(buf[count]);
1813         if ((pnum < 0) || (pnum >= N_players))
1814         {
1815                 Int3(); // Invalid player number killed
1816                 return;
1817         }
1818         killed = Players[pnum].objnum;                  
1819         count += 1;
1820
1821         killer = INTEL_SHORT(*(short *)(buf+count)); 
1822         if (killer > 0)
1823                 killer = objnum_remote_to_local(killer, (byte)buf[count+2]);
1824
1825 #ifdef SHAREWARE
1826         if ((Objects[killed].type != OBJ_PLAYER) && (Objects[killed].type != OBJ_GHOST))
1827         {
1828                 Int3();
1829                 mprintf( (1, "SOFT INT3: MULTI.C Non-player object %d of type %d killed! (JOHN)\n", killed, Objects[killed].type ));
1830                 return;
1831         }
1832 #endif          
1833
1834         multi_compute_kill(killer, killed);
1835
1836 }
1837
1838
1839 //      Changed by MK on 10/20/94 to send NULL as object to net_destroy_controlcen if it got -1
1840 // which means not a controlcen object, but contained in another object
1841 void multi_do_controlcen_destroy(char *buf)
1842 {
1843         byte who;
1844         short objnum;
1845
1846         objnum = INTEL_SHORT(*(short *)(buf+1));
1847         who = buf[3];
1848
1849         if (Control_center_destroyed != 1) 
1850         {
1851                 if ((who < N_players) && (who != Player_num)) {
1852                         HUD_init_message("%s %s", Players[who].callsign, TXT_HAS_DEST_CONTROL);
1853                 }
1854                 else if (who == Player_num)
1855                         HUD_init_message(TXT_YOU_DEST_CONTROL);
1856                 else 
1857                         HUD_init_message(TXT_CONTROL_DESTROYED);
1858
1859                 if (objnum != -1)
1860                         net_destroy_controlcen(Objects+objnum);
1861                 else
1862                         net_destroy_controlcen(NULL);
1863         }
1864 }
1865
1866 void 
1867 multi_do_escape(char *buf)
1868 {
1869         int objnum;
1870
1871         objnum = Players[(int)buf[1]].objnum;
1872
1873         digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
1874         digi_kill_sound_linked_to_object (objnum);
1875         
1876         if (buf[2] == 0)
1877         {
1878                 HUD_init_message("%s %s", Players[(int)buf[1]].callsign, TXT_HAS_ESCAPED);
1879                 if (Game_mode & GM_NETWORK)
1880                         Players[(int)buf[1]].connected = CONNECT_ESCAPE_TUNNEL;
1881                 if (!multi_goto_secret)
1882                         multi_goto_secret = 2;
1883         }
1884         else if (buf[2] == 1) 
1885         {
1886                 HUD_init_message("%s %s", Players[(int)buf[1]].callsign, TXT_HAS_FOUND_SECRET);
1887                 if (Game_mode & GM_NETWORK)
1888                         Players[(int)buf[1]].connected = CONNECT_FOUND_SECRET;
1889                 if (!multi_goto_secret)
1890                         multi_goto_secret = 1;
1891         }
1892         create_player_appearance_effect(&Objects[objnum]);
1893         multi_make_player_ghost(buf[1]);
1894 }
1895
1896 void
1897 multi_do_remobj(char *buf)
1898 {
1899         short objnum; // which object to remove
1900         short local_objnum;
1901         byte obj_owner; // which remote list is it entered in
1902
1903         objnum = INTEL_SHORT(*(short *)(buf+1));
1904         obj_owner = buf[3];
1905
1906         Assert(objnum >= 0);
1907
1908         if (objnum < 1)
1909                 return;
1910
1911         local_objnum = objnum_remote_to_local(objnum, obj_owner); // translate to local objnum
1912
1913 //      mprintf((0, "multi_do_remobj: %d owner %d = %d.\n", objnum, obj_owner, local_objnum));
1914
1915         if (local_objnum < 0)
1916         {
1917                 mprintf((1, "multi_do_remobj: Could not remove referenced object.\n"));
1918                 return;
1919         }
1920
1921         if ((Objects[local_objnum].type != OBJ_POWERUP) && (Objects[local_objnum].type != OBJ_HOSTAGE))
1922         {
1923                 mprintf((1, "multi_get_remobj: tried to remove invalid type %d.\n", Objects[local_objnum].type));
1924                 return;
1925         }
1926         
1927         if (Network_send_objects && network_objnum_is_past(local_objnum))
1928         {
1929                 mprintf((0, "Resetting object sync due to object removal.\n"));
1930                 Network_send_objnum = -1;
1931         }
1932         if (Objects[local_objnum].type==OBJ_POWERUP)
1933          if (Game_mode & GM_NETWORK)    
1934                 {
1935                  if (PowerupsInMine[Objects[local_objnum].id]>0)
1936                         PowerupsInMine[Objects[local_objnum].id]--;
1937
1938                   if (multi_powerup_is_4pack (Objects[local_objnum].id))
1939                          {
1940                                 mprintf ((0,"Hey babe! Doing that wacky 4 pack stuff."));
1941                 
1942                                 if (PowerupsInMine[Objects[local_objnum].id-1]-4<0)
1943                                         PowerupsInMine[Objects[local_objnum].id-1]=0;
1944                                 else
1945                                         PowerupsInMine[Objects[local_objnum].id-1]-=4;
1946                          }
1947                 
1948                  mprintf ((0,"Decrementing powerups! %d\n",PowerupsInMine[Objects[local_objnum].id]));
1949                 }
1950
1951         Objects[local_objnum].flags |= OF_SHOULD_BE_DEAD; // quick and painless
1952         
1953 }
1954
1955 void
1956 multi_do_quit(char *buf)
1957 {
1958         
1959         if (Game_mode & GM_NETWORK)
1960         {
1961                 int i, n = 0;
1962
1963                 digi_play_sample( SOUND_HUD_MESSAGE, F1_0 );
1964
1965                 HUD_init_message( "%s %s", Players[(int)buf[1]].callsign, TXT_HAS_LEFT_THE_GAME);
1966                 
1967                 network_disconnect_player(buf[1]);
1968
1969                 if (multi_in_menu)
1970                         return;
1971
1972                 for (i = 0; i < N_players; i++)
1973                         if (Players[i].connected) n++;
1974                 if (n == 1)
1975                 {
1976                         nm_messagebox(NULL, 1, TXT_OK, TXT_YOU_ARE_ONLY);
1977                 }
1978         }
1979
1980         if ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM))
1981         {
1982                 Function_mode = FMODE_MENU;
1983                 multi_quit_game = 1;
1984                 multi_leave_menu = 1;
1985                 nm_messagebox(NULL, 1, TXT_OK, TXT_OPPONENT_LEFT);
1986                 Function_mode = FMODE_GAME;
1987                 multi_reset_stuff();
1988         }
1989         return;
1990 }
1991
1992 void
1993 multi_do_cloak(char *buf)
1994 {
1995         int pnum;
1996
1997         pnum = (int)(buf[1]);
1998
1999         Assert(pnum < N_players);
2000         
2001         mprintf((0, "Cloaking player %d\n", pnum));
2002
2003         Players[pnum].flags |= PLAYER_FLAGS_CLOAKED;
2004         Players[pnum].cloak_time = GameTime;
2005         ai_do_cloak_stuff();
2006
2007 #ifndef SHAREWARE
2008         if (Game_mode & GM_MULTI_ROBOTS)
2009                 multi_strip_robots(pnum);
2010 #endif
2011
2012         if (Newdemo_state == ND_STATE_RECORDING)
2013                 newdemo_record_multi_cloak(pnum);
2014 }
2015         
2016 void
2017 multi_do_decloak(char *buf)
2018 {
2019         int pnum;
2020
2021         pnum = (int)(buf[1]);
2022
2023         if (Newdemo_state == ND_STATE_RECORDING)
2024                 newdemo_record_multi_decloak(pnum);
2025
2026 }
2027         
2028 void
2029 multi_do_door_open(char *buf)
2030 {
2031         int segnum;
2032         byte side;
2033         segment *seg;
2034         wall *w;
2035         ubyte flag;
2036
2037         segnum = INTEL_SHORT(*(short *)(buf+1));
2038         side = buf[3];
2039         flag= buf[4];
2040
2041 //      mprintf((0, "Opening door on side %d of segment # %d.\n", side, segnum));
2042
2043         if ((segnum < 0) || (segnum > Highest_segment_index) || (side < 0) || (side > 5))
2044         {
2045                 Int3();
2046                 return;
2047         }
2048
2049         seg = &Segments[segnum];
2050
2051         if (seg->sides[side].wall_num == -1) {  //Opening door on illegal wall
2052                 Int3();
2053                 return;
2054         }
2055
2056         w = &Walls[seg->sides[side].wall_num];
2057
2058         if (w->type == WALL_BLASTABLE)
2059         {
2060                 if (!(w->flags & WALL_BLASTED))
2061                 {
2062                         mprintf((0, "Blasting wall by remote command.\n"));
2063                         wall_destroy(seg, side);
2064                 }
2065                 return;
2066         }
2067         else if (w->state != WALL_DOOR_OPENING)
2068         {
2069                 wall_open_door(seg, side);
2070       w->flags=flag;
2071         }
2072         else
2073     w->flags=flag;
2074
2075 //      else
2076 //              mprintf((0, "Door already opening!\n"));
2077 }
2078
2079 void
2080 multi_do_create_explosion(char *buf)
2081 {
2082         int pnum;
2083         int count = 1;
2084
2085         pnum = buf[count++];
2086
2087 //      mprintf((0, "Creating small fireball.\n"));
2088         create_small_fireball_on_object(&Objects[Players[pnum].objnum], F1_0, 1);
2089 }
2090         
2091 void
2092 multi_do_controlcen_fire(char *buf)
2093 {
2094         vms_vector to_target;
2095         char gun_num;
2096         short objnum;
2097         int count = 1;
2098
2099         memcpy(&to_target, buf+count, 12);      count += 12;
2100         #ifdef MACINTOSH        // swap the vector to_target
2101         to_target.x = (fix)INTEL_INT((int)to_target.x);
2102         to_target.y = (fix)INTEL_INT((int)to_target.y);
2103         to_target.z = (fix)INTEL_INT((int)to_target.z);
2104         #endif
2105         gun_num = buf[count];                                   count += 1;
2106         objnum = INTEL_SHORT(*(short *)(buf+count));         count += 2;
2107
2108         Laser_create_new_easy(&to_target, &Gun_pos[(int)gun_num], objnum, CONTROLCEN_WEAPON_NUM, 1);
2109 }
2110
2111 void
2112 multi_do_create_powerup(char *buf)
2113 {
2114         short segnum;
2115         short objnum;
2116         int my_objnum;
2117         char pnum;
2118         int count = 1;
2119         vms_vector new_pos;
2120         char powerup_type;
2121
2122         if (Endlevel_sequence || Control_center_destroyed)
2123                 return;
2124
2125         pnum = buf[count++];
2126         powerup_type = buf[count++];
2127         segnum = INTEL_SHORT(*(short *)(buf+count)); count+=2;
2128         objnum = INTEL_SHORT(*(short *)(buf+count)); count+=2;
2129
2130         if ((segnum < 0) || (segnum > Highest_segment_index)) {
2131                 Int3();
2132                 return;
2133         }
2134         
2135         new_pos = *(vms_vector *)(buf+count); count+=sizeof(vms_vector);
2136 #ifdef MACINTOSH
2137         new_pos.x = (fix)SWAPINT((int)new_pos.x);
2138         new_pos.y = (fix)SWAPINT((int)new_pos.y);
2139         new_pos.z = (fix)SWAPINT((int)new_pos.z);
2140 #endif
2141
2142         Net_create_loc = 0;
2143         my_objnum = call_object_create_egg(&Objects[Players[(int)pnum].objnum], 1, OBJ_POWERUP, powerup_type);
2144
2145         if (my_objnum < 0) {
2146                 mprintf((0, "Could not create new powerup!\n"));
2147                 return;
2148         }
2149
2150         if (Network_send_objects && network_objnum_is_past(my_objnum))
2151         {
2152                 mprintf((0, "Resetting object sync due to powerup creation.\n"));
2153                 Network_send_objnum = -1;
2154         }
2155
2156         Objects[my_objnum].pos = new_pos;
2157
2158         vm_vec_zero(&Objects[my_objnum].mtype.phys_info.velocity);
2159         
2160         obj_relink(my_objnum, segnum);
2161
2162         map_objnum_local_to_remote(my_objnum, objnum, pnum);
2163
2164         object_create_explosion(segnum, &new_pos, i2f(5), VCLIP_POWERUP_DISAPPEARANCE);
2165         mprintf((0, "Creating powerup type %d in segment %i.\n", powerup_type, segnum));
2166
2167    if (Game_mode & GM_NETWORK)
2168                 PowerupsInMine[(int)powerup_type]++;
2169 }               
2170
2171 void
2172 multi_do_play_sound(char *buf)
2173 {
2174         int pnum = (int)(buf[1]);
2175         int sound_num = (int)(buf[2]);
2176         fix volume = (int)(buf[3]) << 12;
2177
2178         if (!Players[pnum].connected)
2179                 return;
2180
2181         Assert(Players[pnum].objnum >= 0);
2182         Assert(Players[pnum].objnum <= Highest_object_index);
2183
2184         digi_link_sound_to_object( sound_num, Players[pnum].objnum, 0, volume); 
2185 }
2186
2187 void
2188 multi_do_score(char *buf)
2189 {
2190         int pnum = (int)(buf[1]);
2191         
2192         if ((pnum < 0) || (pnum >= N_players))
2193         {
2194                 Int3(); // Non-terminal, see rob
2195                 return;
2196         }
2197
2198         if (Newdemo_state == ND_STATE_RECORDING)
2199                 newdemo_record_multi_score(pnum, INTEL_INT(*(int *)(buf+2)) );
2200
2201         Players[pnum].score = INTEL_INT(*(int *)(buf+2));
2202
2203         multi_sort_kill_list();
2204 }
2205
2206 void
2207 multi_do_trigger(char *buf)
2208 {
2209         int pnum = (int)(buf[1]);
2210         int trigger = (int)(buf[2]);
2211    
2212    mprintf ((0,"MULTI doing trigger!\n"));
2213
2214         if ((pnum < 0) || (pnum >= N_players) || (pnum == Player_num))
2215         {
2216                 Int3(); // Got trigger from illegal playernum
2217                 return;
2218         }
2219         if ((trigger < 0) || (trigger >= Num_triggers))
2220         {
2221                 Int3(); // Illegal trigger number in multiplayer
2222                 return;
2223         }
2224         check_trigger_sub(trigger, pnum,0);
2225 }
2226
2227 void multi_do_drop_marker (char *buf)
2228  {
2229   int i;
2230   int pnum=(int)(buf[1]);
2231   int mesnum=(int)(buf[2]);
2232   vms_vector position;
2233
2234   if (pnum==Player_num)  // my marker? don't set it down cuz it might screw up the orientation
2235    return;
2236
2237   position.x=(fix)INTEL_INT(*(int *)(buf+3));
2238   position.y=(fix)INTEL_INT(*(int *)(buf+7));
2239   position.z=(fix)INTEL_INT(*(int *)(buf+11));
2240
2241   for (i=0;i<40;i++)
2242    MarkerMessage[(pnum*2)+mesnum][i]=buf[15+i];
2243
2244   MarkerPoint[(pnum*2)+mesnum]=position;
2245
2246   if (MarkerObject[(pnum*2)+mesnum] !=-1 && Objects[MarkerObject[(pnum*2)+mesnum]].type!=OBJ_NONE && MarkerObject[(pnum*2)+mesnum] !=0)
2247                 obj_delete(MarkerObject[(pnum*2)+mesnum]);
2248
2249   MarkerObject[(pnum*2)+mesnum] = drop_marker_object(&position,Objects[Players[Player_num].objnum].segnum,&Objects[Players[Player_num].objnum].orient,(pnum*2)+mesnum);
2250   strcpy (MarkerOwner[(pnum*2)+mesnum],Players[pnum].callsign);
2251   mprintf ((0,"Dropped player %d message: %s\n",pnum,MarkerMessage[(pnum*2)+mesnum]));
2252  }
2253
2254
2255 void multi_do_hostage_door_status(char *buf)
2256 {
2257         // Update hit point status of a door
2258
2259         int count = 1;
2260         int wallnum; 
2261         fix hps;
2262
2263         wallnum = INTEL_SHORT(*(short *)(buf+count));                count += 2;
2264         hps = (fix)INTEL_INT(*(int *)(buf+count));              count += 4;
2265
2266         if ((wallnum < 0) || (wallnum > Num_walls) || (hps < 0) || (Walls[wallnum].type != WALL_BLASTABLE))
2267         {
2268                 Int3(); // Non-terminal, see Rob
2269                 return;
2270         }
2271
2272 //      mprintf((0, "Damaging wall number %d to %f points.\n", wallnum, f2fl(hps)));
2273
2274         if (hps < Walls[wallnum].hps)
2275                 wall_damage(&Segments[Walls[wallnum].segnum], Walls[wallnum].sidenum, Walls[wallnum].hps - hps);
2276 }
2277
2278 void multi_do_save_game(char *buf)
2279 {
2280         int count = 1;
2281         ubyte slot;
2282         uint id;
2283         char desc[25];
2284
2285         slot = *(ubyte *)(buf+count);           count += 1;
2286         id = INTEL_INT(*(uint *)(buf+count));              count += 4;
2287         memcpy( desc, &buf[count], 20 );        count += 20;
2288
2289         multi_save_game( slot, id, desc );
2290 }
2291
2292 void multi_do_restore_game(char *buf)
2293 {
2294         int count = 1;
2295         ubyte slot;
2296         uint id;
2297
2298         slot = *(ubyte *)(buf+count);           count += 1;
2299         id = INTEL_INT(*(uint *)(buf+count));              count += 4;
2300
2301         multi_restore_game( slot, id );
2302 }
2303
2304  
2305 void multi_do_req_player(char *buf)
2306 {
2307         netplayer_stats ps;
2308         ubyte player_n;
2309         // Send my netplayer_stats to everyone!
2310         player_n = *(ubyte *)(buf+1);
2311         if ( (player_n == Player_num) || (player_n == 255)  )   {
2312                 extract_netplayer_stats( &ps, &Players[Player_num] );
2313                 ps.Player_num = Player_num;
2314                 ps.message_type = MULTI_SEND_PLAYER;            // SET
2315                 multi_send_data((ubyte*)&ps, sizeof(netplayer_stats), 0);
2316         }
2317 }
2318
2319 void multi_do_send_player(char *buf)
2320 {
2321         // Got a player packet from someone!!!
2322         netplayer_stats * p;
2323         p = (netplayer_stats *)buf;     
2324
2325         Assert( p->Player_num <= N_players );
2326
2327         mprintf(( 0, "Got netplayer_stats for player %d (I'm %d)\n", p->Player_num, Player_num ));
2328         mprintf(( 0, "Their shields are: %d\n", f2i(p->shields) ));
2329
2330         use_netplayer_stats( &Players[p->Player_num], p );
2331 }
2332
2333 void
2334 multi_reset_stuff(void)
2335 {
2336         // A generic, emergency function to solve problems that crop up
2337         // when a player exits quick-out from the game because of a 
2338         // serial connection loss.  Fixes several weird bugs!
2339
2340         dead_player_end();
2341
2342         Players[Player_num].homing_object_dist = -F1_0; // Turn off homing sound.
2343
2344         Dead_player_camera = 0;
2345         Endlevel_sequence = 0;
2346         reset_rear_view();
2347 }
2348
2349 void
2350 multi_reset_player_object(object *objp)
2351 {
2352         int i;
2353
2354         //Init physics for a non-console player
2355
2356         Assert(objp >= Objects);
2357         Assert(objp <= Objects+Highest_object_index);
2358         Assert((objp->type == OBJ_PLAYER) || (objp->type == OBJ_GHOST));
2359
2360         vm_vec_zero(&objp->mtype.phys_info.velocity);
2361         vm_vec_zero(&objp->mtype.phys_info.thrust);
2362         vm_vec_zero(&objp->mtype.phys_info.rotvel);
2363         vm_vec_zero(&objp->mtype.phys_info.rotthrust);
2364         objp->mtype.phys_info.brakes = objp->mtype.phys_info.turnroll = 0;
2365         objp->mtype.phys_info.mass = Player_ship->mass;
2366         objp->mtype.phys_info.drag = Player_ship->drag;
2367 //      objp->mtype.phys_info.flags &= ~(PF_TURNROLL | PF_LEVELLING | PF_WIGGLE | PF_USES_THRUST);
2368         objp->mtype.phys_info.flags &= ~(PF_TURNROLL | PF_LEVELLING | PF_WIGGLE);
2369
2370         //Init render info
2371
2372         objp->render_type = RT_POLYOBJ;
2373         objp->rtype.pobj_info.model_num = Player_ship->model_num;               //what model is this?
2374         objp->rtype.pobj_info.subobj_flags = 0;         //zero the flags
2375         for (i=0;i<MAX_SUBMODELS;i++)
2376                 vm_angvec_zero(&objp->rtype.pobj_info.anim_angles[i]);
2377
2378         //reset textures for this, if not player 0
2379
2380         multi_reset_object_texture (objp);      
2381         
2382         // Clear misc
2383
2384         objp->flags = 0;
2385         
2386         if (objp->type == OBJ_GHOST)
2387                 objp->render_type = RT_NONE;
2388
2389 }
2390
2391 void multi_reset_object_texture (object *objp)
2392  {
2393         int id,i;
2394
2395         if (Game_mode & GM_TEAM)
2396                 id = get_team(objp->id);
2397         else
2398                 id = objp->id;
2399
2400         if (id == 0)
2401                 objp->rtype.pobj_info.alt_textures=0;
2402         else {
2403                 Assert(N_PLAYER_SHIP_TEXTURES == Polygon_models[objp->rtype.pobj_info.model_num].n_textures);
2404
2405                 for (i=0;i<N_PLAYER_SHIP_TEXTURES;i++)
2406                         multi_player_textures[id-1][i] = ObjBitmaps[ObjBitmapPtrs[Polygon_models[objp->rtype.pobj_info.model_num].first_texture+i]];
2407
2408                 multi_player_textures[id-1][4] = ObjBitmaps[ObjBitmapPtrs[First_multi_bitmap_num+(id-1)*2]];
2409                 multi_player_textures[id-1][5] = ObjBitmaps[ObjBitmapPtrs[First_multi_bitmap_num+(id-1)*2+1]];
2410
2411                 objp->rtype.pobj_info.alt_textures = id;
2412    }
2413  }
2414
2415
2416
2417
2418 extern int TTRecv[];
2419 extern FILE *RecieveLogFile;
2420
2421 void
2422 multi_process_bigdata(char *buf, int len)
2423 {
2424         // Takes a bunch of messages, check them for validity,
2425         // and pass them to multi_process_data. 
2426
2427         int type, sub_len, bytes_processed = 0;
2428
2429         while( bytes_processed < len )  {
2430                 type = buf[bytes_processed];
2431
2432                 if ( (type<0) || (type>MULTI_MAX_TYPE)) {
2433                         mprintf( (1, "multi_process_bigdata: Invalid packet type %d!\n", type ));
2434                         return;
2435                 }
2436                 sub_len = message_length[type];
2437
2438                 Assert(sub_len > 0);
2439
2440                 if ( (bytes_processed+sub_len) > len )  {
2441                         mprintf( (1, "multi_process_bigdata: packet type %d too short (%d>%d)!\n", type, (bytes_processed+sub_len), len ));
2442                         Int3();
2443                         return;
2444                 }
2445
2446                 multi_process_data(&buf[bytes_processed], sub_len);
2447                 bytes_processed += sub_len;
2448         }
2449 }
2450
2451 //
2452 // Part 2 : Functions that send communication messages to inform the other
2453 //          players of something we did.
2454 //
2455
2456 void
2457 multi_send_fire(void)
2458 {
2459         if (!Network_laser_fired)
2460                 return;
2461
2462         multibuf[0] = (char)MULTI_FIRE;
2463         multibuf[1] = (char)Player_num;
2464         multibuf[2] = (char)Network_laser_gun;
2465         multibuf[3] = (char)Network_laser_level;
2466         multibuf[4] = (char)Network_laser_flags;
2467         multibuf[5] = (char)Network_laser_fired;
2468        
2469         *(short *)(multibuf+6) = INTEL_SHORT(Network_laser_track);
2470
2471         multi_send_data(multibuf, 8, 0);
2472         
2473         Network_laser_fired = 0;
2474 }
2475
2476 void
2477 multi_send_destroy_controlcen(int objnum, int player)
2478 {
2479         if (player == Player_num)
2480                 HUD_init_message(TXT_YOU_DEST_CONTROL);
2481         else if ((player > 0) && (player < N_players))
2482                 HUD_init_message("%s %s", Players[player].callsign, TXT_HAS_DEST_CONTROL);
2483         else
2484                 HUD_init_message(TXT_CONTROL_DESTROYED);
2485
2486         multibuf[0] = (char)MULTI_CONTROLCEN;
2487         *(ushort *)(multibuf+1) = INTEL_SHORT(objnum);
2488         multibuf[3] = player;
2489    multi_send_data(multibuf, 4, 2);
2490 }
2491
2492 void multi_send_drop_marker (int player,vms_vector position,char messagenum,char text[])
2493  {
2494   int i;
2495
2496    if (player<N_players)
2497      {
2498        mprintf ((0,"Sending MARKER drop!\n"));
2499        multibuf[0]=(char)MULTI_MARKER;
2500        multibuf[1]=(char)player;
2501        multibuf[2]=messagenum;
2502        *(fix *)(multibuf+3)=INTEL_INT(position.x);
2503        *(fix *)(multibuf+7)=INTEL_INT(position.y);
2504        *(fix *)(multibuf+11)=INTEL_INT(position.z);
2505        for (i=0;i<40;i++)
2506              multibuf[15+i]=text[i];
2507      }
2508    multi_send_data(multibuf, 55, 1);
2509  }
2510                            
2511 void 
2512 multi_send_endlevel_start(int secret)
2513 {
2514         multibuf[0] = (char)MULTI_ENDLEVEL_START;
2515         multibuf[1] = Player_num;
2516         multibuf[2] = (char)secret;
2517         
2518         if ((secret) && !multi_goto_secret)
2519                 multi_goto_secret = 1;
2520         else if (!multi_goto_secret)
2521                 multi_goto_secret = 2;
2522
2523         multi_send_data(multibuf, 3, 1);
2524         if (Game_mode & GM_NETWORK)
2525         {
2526                 Players[Player_num].connected = 5;
2527                 network_send_endlevel_packet();
2528         }
2529 }
2530
2531 void
2532 multi_send_player_explode(char type)
2533 {
2534         int count = 0;
2535         int i;
2536
2537         Assert( (type == MULTI_PLAYER_DROP) || (type == MULTI_PLAYER_EXPLODE) );
2538
2539         multi_send_position(Players[Player_num].objnum);
2540
2541         if (Network_send_objects)
2542         {
2543                 mprintf((0, "Resetting object sync due to player explosion.\n"));
2544                 Network_send_objnum = -1;
2545         }
2546         
2547         multibuf[count++] = type;
2548         multibuf[count++] = Player_num;
2549   
2550         *(ushort *)(multibuf+count) = INTEL_SHORT((ushort)Players[Player_num].primary_weapon_flags);
2551         count += 2;
2552         *(ushort *)(multibuf+count) = INTEL_SHORT((ushort)Players[Player_num].secondary_weapon_flags);
2553         count += 2;
2554         multibuf[count++] = (char)Players[Player_num].laser_level;
2555         
2556         multibuf[count++] = (char)Players[Player_num].secondary_ammo[HOMING_INDEX];
2557         multibuf[count++] = (char)Players[Player_num].secondary_ammo[CONCUSSION_INDEX];
2558         multibuf[count++] = (char)Players[Player_num].secondary_ammo[SMART_INDEX];
2559         multibuf[count++] = (char)Players[Player_num].secondary_ammo[MEGA_INDEX];
2560         multibuf[count++] = (char)Players[Player_num].secondary_ammo[PROXIMITY_INDEX];
2561
2562         multibuf[count++] = (char)Players[Player_num].secondary_ammo[SMISSILE1_INDEX];
2563         multibuf[count++] = (char)Players[Player_num].secondary_ammo[GUIDED_INDEX];
2564         multibuf[count++] = (char)Players[Player_num].secondary_ammo[SMART_MINE_INDEX];
2565         multibuf[count++] = (char)Players[Player_num].secondary_ammo[SMISSILE4_INDEX];
2566         multibuf[count++] = (char)Players[Player_num].secondary_ammo[SMISSILE5_INDEX];
2567
2568         *(ushort *)(multibuf+count) = INTEL_SHORT( (ushort)Players[Player_num].primary_ammo[VULCAN_INDEX] );
2569         count += 2;
2570         *(ushort *)(multibuf+count) = INTEL_SHORT( (ushort)Players[Player_num].primary_ammo[GAUSS_INDEX] );
2571         count += 2;
2572         *(uint *)(multibuf+count) = INTEL_INT( (uint)Players[Player_num].flags );
2573         count += 4;
2574         
2575         multibuf[count++] = Net_create_loc;
2576
2577         Assert(Net_create_loc <= MAX_NET_CREATE_OBJECTS);
2578
2579         memset(multibuf+count, -1, MAX_NET_CREATE_OBJECTS*sizeof(short));
2580         
2581         mprintf((0, "Created %d explosion objects.\n", Net_create_loc));
2582
2583         for (i = 0; i < Net_create_loc; i++)
2584         {
2585                 if (Net_create_objnums[i] <= 0) {
2586                         Int3(); // Illegal value in created egg object numbers
2587                         count +=2;
2588                         continue;
2589                 }
2590
2591                 *(short *)(multibuf+count) = INTEL_SHORT( (short)Net_create_objnums[i] ); count += 2;
2592
2593                 // We created these objs so our local number = the network number
2594                 map_objnum_local_to_local((short)Net_create_objnums[i]);
2595         }
2596
2597         Net_create_loc = 0;
2598
2599 //      mprintf((1, "explode message size = %d, max = %d.\n", count, message_length[MULTI_PLAYER_EXPLODE]));
2600
2601         if (count > message_length[MULTI_PLAYER_EXPLODE])
2602         {
2603                 Int3(); // See Rob
2604         }
2605
2606         multi_send_data(multibuf, message_length[MULTI_PLAYER_EXPLODE], 2);
2607         if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)
2608                 multi_send_decloak();
2609         if (Game_mode & GM_MULTI_ROBOTS)
2610                 multi_strip_robots(Player_num);
2611 }
2612
2613 extern ubyte Secondary_weapon_to_powerup[];
2614 extern ubyte Primary_weapon_to_powerup[];
2615
2616 // put a lid on how many objects will be spewed by an exploding player
2617 // to prevent rampant powerups in netgames
2618
2619 void multi_cap_objects ()
2620  {
2621   char type,flagtype;
2622   int index;
2623
2624   if (!(Game_mode & GM_NETWORK))
2625         return;
2626
2627   for (index=0;index<MAX_PRIMARY_WEAPONS;index++)       
2628         {
2629                 type=Primary_weapon_to_powerup[index];
2630         if (PowerupsInMine[(int)type]>=MaxPowerupsAllowed[(int)type])
2631                  if(Players[Player_num].primary_weapon_flags & (1 << index))
2632                         {
2633                          mprintf ((0,"PIM=%d MPA=%d\n",PowerupsInMine[(int)type],MaxPowerupsAllowed[(int)type]));
2634                          mprintf ((0,"Killing a primary cuz there's too many! (%d)\n",(int)type));
2635                     Players[Player_num].primary_weapon_flags&=(~(1 << index));
2636                         }
2637         }
2638   
2639
2640   // Don't do the adjustment stuff for Hoard mode
2641   if (!(Game_mode & GM_HOARD))            
2642           Players[Player_num].secondary_ammo[2]/=4;
2643
2644   Players[Player_num].secondary_ammo[7]/=4;
2645         
2646   for (index=0;index<MAX_SECONDARY_WEAPONS;index++)     
2647         {
2648                 if ((Game_mode & GM_HOARD) && index==PROXIMITY_INDEX)
2649                         continue;
2650
2651                 type=Secondary_weapon_to_powerup[index];
2652                 
2653         if ((Players[Player_num].secondary_ammo[index]+PowerupsInMine[(int)type])>MaxPowerupsAllowed[(int)type])
2654                  {
2655         if (MaxPowerupsAllowed[(int)type]-PowerupsInMine[(int)type]<0)
2656                          Players[Player_num].secondary_ammo[index]=0;
2657                  else   
2658                  Players[Player_num].secondary_ammo[index]=(MaxPowerupsAllowed[(int)type]-PowerupsInMine[(int)type]);
2659                   
2660                         mprintf ((0,"Hey! I killed secondary type %d because PIM=%d MPA=%d\n",(int)type,PowerupsInMine[(int)type],MaxPowerupsAllowed[(int)type]));
2661                  }      
2662         }
2663
2664   if (!(Game_mode & GM_HOARD))            
2665           Players[Player_num].secondary_ammo[2]*=4;
2666   Players[Player_num].secondary_ammo[7]*=4;
2667     
2668                 if (Players[Player_num].laser_level > MAX_LASER_LEVEL)
2669                  if (PowerupsInMine[POW_SUPER_LASER]+1 > MaxPowerupsAllowed[POW_SUPER_LASER])
2670                         Players[Player_num].laser_level=0;
2671
2672                 if (Players[Player_num].flags & PLAYER_FLAGS_QUAD_LASERS)
2673                  if (PowerupsInMine[POW_QUAD_FIRE]+1 > MaxPowerupsAllowed[POW_QUAD_FIRE])
2674                         Players[Player_num].flags&=(~PLAYER_FLAGS_QUAD_LASERS);
2675
2676                 if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)
2677                  if (PowerupsInMine[POW_CLOAK]+1 > MaxPowerupsAllowed[POW_CLOAK])
2678                         Players[Player_num].flags&=(~PLAYER_FLAGS_CLOAKED);
2679
2680                 if (Players[Player_num].flags & PLAYER_FLAGS_MAP_ALL)
2681                  if (PowerupsInMine[POW_FULL_MAP]+1 > MaxPowerupsAllowed[POW_FULL_MAP])
2682                         Players[Player_num].flags&=(~PLAYER_FLAGS_MAP_ALL);
2683
2684                 if (Players[Player_num].flags & PLAYER_FLAGS_AFTERBURNER)
2685                  if (PowerupsInMine[POW_AFTERBURNER]+1 > MaxPowerupsAllowed[POW_AFTERBURNER])
2686                         Players[Player_num].flags&=(~PLAYER_FLAGS_AFTERBURNER);
2687
2688                 if (Players[Player_num].flags & PLAYER_FLAGS_AMMO_RACK)
2689                  if (PowerupsInMine[POW_AMMO_RACK]+1 > MaxPowerupsAllowed[POW_AMMO_RACK])
2690                         Players[Player_num].flags&=(~PLAYER_FLAGS_AMMO_RACK);
2691
2692                 if (Players[Player_num].flags & PLAYER_FLAGS_CONVERTER)
2693                  if (PowerupsInMine[POW_CONVERTER]+1 > MaxPowerupsAllowed[POW_CONVERTER])
2694                         Players[Player_num].flags&=(~PLAYER_FLAGS_CONVERTER);
2695
2696                 if (Players[Player_num].flags & PLAYER_FLAGS_HEADLIGHT)
2697                  if (PowerupsInMine[POW_HEADLIGHT]+1 > MaxPowerupsAllowed[POW_HEADLIGHT])
2698                         Players[Player_num].flags&=(~PLAYER_FLAGS_HEADLIGHT);
2699                 
2700                 if (Game_mode & GM_CAPTURE)
2701                 {
2702                         if (Players[Player_num].flags & PLAYER_FLAGS_FLAG)
2703                          {
2704                           if (get_team(Player_num)==TEAM_RED)
2705                                 flagtype=POW_FLAG_BLUE;
2706                           else
2707                                 flagtype=POW_FLAG_RED;
2708                         
2709                           if (PowerupsInMine[(int)flagtype]+1 > MaxPowerupsAllowed[(int)flagtype])
2710                              Players[Player_num].flags&=(~PLAYER_FLAGS_FLAG);
2711                          }
2712                 }
2713
2714  }
2715
2716 // adds players inventory to multi cap
2717
2718 void multi_adjust_cap_for_player (int pnum)
2719  {
2720   char type;
2721   
2722   int index;
2723
2724   if (!(Game_mode & GM_NETWORK))
2725         return;
2726
2727   for (index=0;index<MAX_PRIMARY_WEAPONS;index++)       
2728         {
2729                 type=Primary_weapon_to_powerup[index];
2730              if (Players[pnum].primary_weapon_flags & (1 << index))
2731                     MaxPowerupsAllowed[(int)type]++;
2732         }
2733                         
2734   for (index=0;index<MAX_SECONDARY_WEAPONS;index++)     
2735         {
2736                 type=Secondary_weapon_to_powerup[index];
2737                 MaxPowerupsAllowed[(int)type]+=Players[pnum].secondary_ammo[index];
2738         }
2739
2740   if (Players[pnum].laser_level > MAX_LASER_LEVEL)
2741          MaxPowerupsAllowed[POW_SUPER_LASER]++;
2742
2743   if (Players[pnum].flags & PLAYER_FLAGS_QUAD_LASERS)
2744     MaxPowerupsAllowed[POW_QUAD_FIRE]++;
2745
2746   if (Players[pnum].flags & PLAYER_FLAGS_CLOAKED)
2747          MaxPowerupsAllowed[POW_CLOAK]++;
2748
2749   if (Players[pnum].flags & PLAYER_FLAGS_MAP_ALL)
2750          MaxPowerupsAllowed[POW_FULL_MAP]++;
2751
2752   if (Players[pnum].flags & PLAYER_FLAGS_AFTERBURNER)
2753         MaxPowerupsAllowed[POW_AFTERBURNER]++;
2754
2755   if (Players[pnum].flags & PLAYER_FLAGS_AMMO_RACK)
2756           MaxPowerupsAllowed[POW_AMMO_RACK]++;
2757
2758   if (Players[pnum].flags & PLAYER_FLAGS_CONVERTER)
2759          MaxPowerupsAllowed[POW_CONVERTER]++;
2760
2761   if (Players[pnum].flags & PLAYER_FLAGS_HEADLIGHT)
2762          MaxPowerupsAllowed[POW_HEADLIGHT]++;
2763  }
2764
2765 void multi_adjust_remote_cap (int pnum)
2766  {
2767   char type;
2768   
2769   int index;
2770
2771   if (!(Game_mode & GM_NETWORK))
2772         return;
2773
2774   for (index=0;index<MAX_PRIMARY_WEAPONS;index++)       
2775         {
2776                 type=Primary_weapon_to_powerup[index];
2777              if (Players[pnum].primary_weapon_flags & (1 << index))
2778                     PowerupsInMine[(int)type]++;
2779         }
2780                         
2781   for (index=0;index<MAX_SECONDARY_WEAPONS;index++)     
2782         {
2783                 type=Secondary_weapon_to_powerup[index];
2784
2785                 if ((Game_mode & GM_HOARD) && index==2)
2786                         continue;
2787    
2788       if (index==2 || index==7) // PROX or SMARTMINES? Those bastards...
2789                         PowerupsInMine[(int)type]+=(Players[pnum].secondary_ammo[index]/4);
2790                 else
2791                    PowerupsInMine[(int)type]+=Players[pnum].secondary_ammo[index];
2792  
2793         }
2794
2795   if (Players[pnum].laser_level > MAX_LASER_LEVEL)
2796          PowerupsInMine[POW_SUPER_LASER]++;
2797
2798   if (Players[pnum].flags & PLAYER_FLAGS_QUAD_LASERS)
2799     PowerupsInMine[POW_QUAD_FIRE]++;
2800
2801   if (Players[pnum].flags & PLAYER_FLAGS_CLOAKED)
2802          PowerupsInMine[POW_CLOAK]++;
2803
2804   if (Players[pnum].flags & PLAYER_FLAGS_MAP_ALL)
2805          PowerupsInMine[POW_FULL_MAP]++;
2806
2807   if (Players[pnum].flags & PLAYER_FLAGS_AFTERBURNER)
2808         PowerupsInMine[POW_AFTERBURNER]++;
2809
2810   if (Players[pnum].flags & PLAYER_FLAGS_AMMO_RACK)
2811           PowerupsInMine[POW_AMMO_RACK]++;
2812
2813   if (Players[pnum].flags & PLAYER_FLAGS_CONVERTER)
2814          PowerupsInMine[POW_CONVERTER]++;
2815
2816   if (Players[pnum].flags & PLAYER_FLAGS_HEADLIGHT)
2817          PowerupsInMine[POW_HEADLIGHT]++;
2818
2819  }
2820
2821 void
2822 multi_send_message(void)
2823 {
2824         int loc = 0;
2825         if (Network_message_reciever != -1)
2826         {
2827                 multibuf[loc] = (char)MULTI_MESSAGE;            loc += 1;
2828                 multibuf[loc] = (char)Player_num;                       loc += 1;
2829                 strncpy(multibuf+loc, Network_message, MAX_MESSAGE_LEN); loc += MAX_MESSAGE_LEN;
2830                 multibuf[loc-1] = '\0';
2831                 multi_send_data(multibuf, loc, 0);
2832                 Network_message_reciever = -1;
2833         }
2834 }
2835
2836 void
2837 multi_send_reappear()
2838 {
2839         multibuf[0] = (char)MULTI_REAPPEAR;
2840         *(short *)(multibuf+1) = INTEL_SHORT(Players[Player_num].objnum);
2841            
2842         multi_send_data(multibuf, 3, 2);
2843         PKilledFlags[Player_num]=0;
2844 }
2845
2846 void
2847 multi_send_position(int objnum)
2848 {
2849 #ifdef MACINTOSH
2850         shortpos sp;
2851 #endif
2852         int count=0;
2853
2854         if (Game_mode & GM_NETWORK) {
2855                 return;
2856         }
2857                      
2858         multibuf[count++] = (char)MULTI_POSITION;
2859 #ifndef MACINTOSH
2860         create_shortpos((shortpos *)(multibuf+count), Objects+objnum,0);
2861         count += sizeof(shortpos);
2862 #else
2863         create_shortpos(&sp, Objects+objnum, 1);
2864         memcpy(&(multibuf[count]), (ubyte *)(sp.bytemat), 9);
2865         count += 9;
2866         memcpy(&(multibuf[count]), (ubyte *)&(sp.xo), 14);
2867         count += 14;
2868 #endif
2869
2870         multi_send_data(multibuf, count, 0);
2871 }
2872
2873 void
2874 multi_send_kill(int objnum)
2875 {
2876         // I died, tell the world.
2877
2878         int killer_objnum;
2879         int count = 0;
2880
2881         Assert(Objects[objnum].id == Player_num);
2882         killer_objnum = Players[Player_num].killer_objnum;
2883
2884         multi_compute_kill(killer_objnum, objnum);
2885          
2886         multibuf[0] = (char)MULTI_KILL;     count += 1;
2887         multibuf[1] = Player_num;           count += 1;
2888    if (killer_objnum > -1) {
2889                 short s;                // do it with variable since INTEL_SHORT won't work on return val from function.
2890                 
2891                 s = (short)objnum_local_to_remote(killer_objnum, (byte *)&multibuf[count+2]);
2892                 *(short *)(multibuf+count) = INTEL_SHORT(s);
2893         } 
2894         else
2895         {
2896                 *(short *)(multibuf+count) = INTEL_SHORT((short)-1);
2897                 multibuf[count+2] = (char)-1;
2898         }
2899         count += 3;
2900         multi_send_data(multibuf, count, 1);
2901
2902 #ifndef SHAREWARE
2903         if (Game_mode & GM_MULTI_ROBOTS)
2904                 multi_strip_robots(Player_num);
2905 #endif
2906 }
2907
2908 void
2909 multi_send_remobj(int objnum)
2910 {
2911         // Tell the other guy to remove an object from his list
2912
2913         byte obj_owner;
2914         short remote_objnum;
2915
2916    if (Objects[objnum].type==OBJ_POWERUP && (Game_mode & GM_NETWORK))
2917     {
2918                 if (PowerupsInMine[Objects[objnum].id] > 0)
2919                  {
2920               PowerupsInMine[Objects[objnum].id]--;
2921                   if (multi_powerup_is_4pack (Objects[objnum].id))
2922                          {
2923                                 mprintf ((0,"Hey babe! Doing that wacky 4 pack stuff."));
2924                 
2925                                 if (PowerupsInMine[Objects[objnum].id-1]-4<0)
2926                                         PowerupsInMine[Objects[objnum].id-1]=0;
2927                                 else
2928                                         PowerupsInMine[Objects[objnum].id-1]-=4;
2929                          }
2930                  }
2931                         
2932          }
2933                         
2934         multibuf[0] = (char)MULTI_REMOVE_OBJECT;
2935
2936         remote_objnum = objnum_local_to_remote((short)objnum, &obj_owner);
2937
2938         *(short *)(multibuf+1) = INTEL_SHORT(remote_objnum); // Map to network objnums
2939
2940         multibuf[3] = obj_owner;        
2941
2942 //      mprintf((0, "multi_send_remobj: %d = %d owner %d.\n", objnum, remote_objnum, obj_owner));
2943
2944         multi_send_data(multibuf, 4, 0);
2945
2946         if (Network_send_objects && network_objnum_is_past(objnum))
2947         {
2948                 mprintf((0, "Resetting object sync due to object removal.\n"));
2949                 Network_send_objnum = -1;
2950         }
2951 }
2952         
2953 void
2954 multi_send_quit(int why)
2955 {
2956         // I am quitting the game, tell the other guy the bad news.
2957
2958         Assert (why == MULTI_QUIT);
2959
2960         multibuf[0] = (char)why;
2961         multibuf[1] = Player_num;
2962         multi_send_data(multibuf, 2, 1);
2963
2964 }
2965
2966 void
2967 multi_send_cloak(void)
2968 {
2969         // Broadcast a change in our pflags (made to support cloaking)
2970
2971         multibuf[0] = MULTI_CLOAK;
2972         multibuf[1] = (char)Player_num;
2973
2974         multi_send_data(multibuf, 2, 1);
2975
2976 #ifndef SHAREWARE
2977         if (Game_mode & GM_MULTI_ROBOTS)
2978                 multi_strip_robots(Player_num);
2979 #endif
2980 }
2981
2982 void
2983 multi_send_decloak(void)
2984 {
2985         // Broadcast a change in our pflags (made to support cloaking)
2986
2987         multibuf[0] = MULTI_DECLOAK;
2988         multibuf[1] = (char)Player_num;
2989
2990         multi_send_data(multibuf, 2, 1);
2991 }
2992
2993 void
2994 multi_send_door_open(int segnum, int side,ubyte flag)
2995 {
2996         // When we open a door make sure everyone else opens that door
2997
2998         multibuf[0] = MULTI_DOOR_OPEN;
2999         *(short *)(multibuf+1) = INTEL_SHORT( (short)segnum );
3000         multibuf[3] = (byte)side;
3001    multibuf[4] = flag;
3002    
3003         multi_send_data(multibuf, 5, 2);
3004 }
3005
3006 extern void network_send_naked_packet (char *,short,int);
3007
3008 void
3009 multi_send_door_open_specific(int pnum,int segnum, int side,ubyte flag)
3010 {
3011         // For sending doors only to a specific person (usually when they're joining)
3012
3013         Assert (Game_mode & GM_NETWORK);
3014 //   Assert (pnum>-1 && pnum<N_players);
3015  
3016         multibuf[0] = MULTI_DOOR_OPEN;
3017         *(short *)(multibuf+1) = INTEL_SHORT( (short)segnum );
3018         multibuf[3] = (byte)side;
3019    multibuf[4] = flag;
3020    
3021         network_send_naked_packet(multibuf, 5, pnum);
3022 }
3023
3024 //
3025 // Part 3 : Functions that change or prepare the game for multiplayer use.
3026 //          Not including functions needed to syncronize or start the 
3027 //          particular type of multiplayer game.  Includes preparing the
3028 //                      mines, player structures, etc.
3029
3030 void
3031 multi_send_create_explosion(int pnum)
3032 {
3033         // Send all data needed to create a remote explosion
3034
3035         int count = 0;
3036
3037         multibuf[count] = MULTI_CREATE_EXPLOSION;       count += 1;
3038         multibuf[count] = (byte)pnum;                                   count += 1;
3039         //                                                                                                      -----------
3040         //                                                                                                      Total size = 2
3041
3042         multi_send_data(multibuf, count, 0);
3043 }
3044         
3045 void
3046 multi_send_controlcen_fire(vms_vector *to_goal, int best_gun_num, int objnum)
3047 {
3048 #ifdef MACINTOSH
3049         vms_vector swapped_vec;
3050 #endif
3051         int count = 0;
3052
3053         multibuf[count] = MULTI_CONTROLCEN_FIRE;                count +=  1;
3054         #ifndef MACINTOSH
3055         memcpy(multibuf+count, to_goal, 12);                    count += 12;
3056         #else
3057         swapped_vec.x = (fix)INTEL_INT( (int)to_goal->x );
3058         swapped_vec.y = (fix)INTEL_INT( (int)to_goal->y );
3059         swapped_vec.z = (fix)INTEL_INT( (int)to_goal->z );
3060         memcpy(multibuf+count, &swapped_vec, 12);                               count += 12;
3061         #endif
3062         multibuf[count] = (char)best_gun_num;                   count +=  1;
3063         *(short *)(multibuf+count) = INTEL_SHORT( (short)objnum );     count +=  2;
3064         //                                                                                                                      ------------
3065         //                                                                                                                      Total  = 16
3066         multi_send_data(multibuf, count, 0);
3067 }
3068
3069 void
3070 multi_send_create_powerup(int powerup_type, int segnum, int objnum, vms_vector *pos)
3071 {
3072         // Create a powerup on a remote machine, used for remote
3073         // placement of used powerups like missiles and cloaking
3074         // powerups.
3075
3076 #ifdef MACINTOSH
3077         vms_vector swapped_vec;
3078 #endif
3079         int count = 0;
3080
3081    if (Game_mode & GM_NETWORK)
3082            PowerupsInMine[powerup_type]++;
3083
3084         multibuf[count] = MULTI_CREATE_POWERUP;         count += 1;
3085         multibuf[count] = Player_num;                                      count += 1;
3086         multibuf[count] = powerup_type;                                 count += 1;
3087         *(short *)(multibuf+count) = INTEL_SHORT( (short)segnum );     count += 2;
3088         *(short *)(multibuf+count) = INTEL_SHORT( (short)objnum );     count += 2;
3089 #ifndef MACINTOSH
3090         *(vms_vector *)(multibuf+count) = *pos;         count += sizeof(vms_vector);
3091 #else
3092         swapped_vec.x = (fix)INTEL_INT( (int)pos->x );
3093         swapped_vec.y = (fix)INTEL_INT( (int)pos->y );
3094         swapped_vec.z = (fix)INTEL_INT( (int)pos->z );
3095         memcpy(multibuf+count, &swapped_vec, 12);                               count += 12;
3096 #endif
3097         //                                                                                                            -----------
3098         //                                                                                                            Total =  19
3099         multi_send_data(multibuf, count, 2);
3100
3101         if (Network_send_objects && network_objnum_is_past(objnum))
3102         {
3103                 mprintf((0, "Resetting object sync due to powerup creation.\n"));
3104                 Network_send_objnum = -1;
3105         }
3106
3107         mprintf((0, "Creating powerup type %d in segment %i.\n", powerup_type, segnum));
3108         map_objnum_local_to_local(objnum);
3109 }       
3110
3111 void
3112 multi_send_play_sound(int sound_num, fix volume)
3113 {
3114         int count = 0;
3115         multibuf[count] = MULTI_PLAY_SOUND;                     count += 1;
3116         multibuf[count] = Player_num;                                   count += 1;
3117         multibuf[count] = (char)sound_num;                      count += 1;
3118         multibuf[count] = (char)(volume >> 12); count += 1;
3119         //                                                                                                         -----------
3120         //                                                                                                         Total = 4
3121         multi_send_data(multibuf, count, 0);
3122 }
3123
3124 void
3125 multi_send_audio_taunt(int taunt_num)
3126 {
3127         return; // Taken out, awaiting sounds..
3128
3129 #if 0
3130         int audio_taunts[4] = {
3131                 SOUND_CONTROL_CENTER_WARNING_SIREN,
3132                 SOUND_HOSTAGE_RESCUED,
3133                 SOUND_REFUEL_STATION_GIVING_FUEL,
3134                 SOUND_BAD_SELECTION
3135         };
3136
3137
3138         Assert(taunt_num >= 0);
3139         Assert(taunt_num < 4);
3140
3141         digi_play_sample( audio_taunts[taunt_num], F1_0 );
3142         multi_send_play_sound(audio_taunts[taunt_num], F1_0);
3143 #endif
3144 }
3145
3146 void
3147 multi_send_score(void)
3148 {
3149         // Send my current score to all other players so it will remain
3150         // synced.
3151         int count = 0;
3152
3153         if (Game_mode & GM_MULTI_COOP) {
3154                 multi_sort_kill_list();
3155                 multibuf[count] = MULTI_SCORE;                  count += 1;
3156                 multibuf[count] = Player_num;                           count += 1;
3157                 *(int *)(multibuf+count) = INTEL_INT( Players[Player_num].score );  count += 4;
3158                 multi_send_data(multibuf, count, 0);
3159         }
3160 }       
3161
3162
3163 void
3164 multi_send_save_game(ubyte slot, uint id, char * desc)
3165 {
3166         int count = 0;
3167         
3168         multibuf[count] = MULTI_SAVE_GAME;              count += 1;
3169         multibuf[count] = slot;                         count += 1;    // Save slot=0
3170         *(uint *)(multibuf+count) = INTEL_INT( id );         count += 4;             // Save id
3171         memcpy( &multibuf[count], desc, 20 ); count += 20;
3172
3173         multi_send_data(multibuf, count, 2);
3174 }
3175
3176 void
3177 multi_send_restore_game(ubyte slot, uint id)
3178 {
3179         int count = 0;
3180         
3181         multibuf[count] = MULTI_RESTORE_GAME;   count += 1;
3182         multibuf[count] = slot;                                                 count += 1;             // Save slot=0
3183         *(uint *)(multibuf+count) = INTEL_INT( id );         count += 4;             // Save id
3184
3185         multi_send_data(multibuf, count, 2);
3186 }
3187
3188 void
3189 multi_send_netplayer_stats_request(ubyte player_num)
3190 {
3191         int count = 0;
3192         
3193         multibuf[count] = MULTI_REQ_PLAYER;     count += 1;
3194         multibuf[count] = player_num;                   count += 1;
3195
3196         multi_send_data(multibuf, count, 0 );
3197 }
3198
3199 void
3200 multi_send_trigger(int triggernum)
3201 {
3202         // Send an even to trigger something in the mine
3203         
3204         int count = 0;
3205         
3206         multibuf[count] = MULTI_TRIGGER;                                count += 1;
3207         multibuf[count] = Player_num;                                   count += 1;
3208         multibuf[count] = (ubyte)triggernum;            count += 1;
3209    
3210    mprintf ((0,"Sending trigger %d\n",triggernum));
3211
3212         multi_send_data(multibuf, count, 1); 
3213 //      multi_send_data(multibuf, count, 1); // twice? 
3214 }
3215
3216 void
3217 multi_send_hostage_door_status(int wallnum)
3218 {
3219         // Tell the other player what the hit point status of a hostage door
3220         // should be
3221
3222         int count = 0;
3223         
3224         Assert(Walls[wallnum].type == WALL_BLASTABLE);
3225
3226         multibuf[count] = MULTI_HOSTAGE_DOOR;           count += 1;
3227         *(short *)(multibuf+count) = INTEL_SHORT( (short)wallnum );           count += 2;
3228         *(fix *)(multibuf+count) = (fix)INTEL_INT( (int)Walls[wallnum].hps );  count += 4;
3229
3230 //      mprintf((0, "Door %d damaged by %f points.\n", wallnum, f2fl(Walls[wallnum].hps)));
3231
3232         multi_send_data(multibuf, count, 0);
3233 }
3234
3235 extern int ConsistencyCount;
3236 extern int Drop_afterburner_blob_flag;
3237 int PhallicLimit=0;
3238 int PhallicMan=-1;
3239
3240 void multi_prep_level(void)
3241 {
3242         // Do any special stuff to the level required for serial games
3243         // before we begin playing in it.
3244
3245         // Player_num MUST be set before calling this procedure.  
3246
3247         // This function must be called before checksuming the Object array,
3248         // since the resulting checksum with depend on the value of Player_num
3249         // at the time this is called.
3250
3251         int i,ng=0;
3252         int     cloak_count, inv_count;
3253
3254         Assert(Game_mode & GM_MULTI);
3255
3256         Assert(NumNetPlayerPositions > 0);
3257         
3258    PhallicLimit=0;
3259    PhallicMan=-1;
3260    Drop_afterburner_blob_flag=0;
3261    ConsistencyCount=0;
3262   
3263    for (i=0;i<MAX_NUM_NET_PLAYERS;i++)
3264          PKilledFlags[i]=0;
3265   
3266         for (i = 0; i < NumNetPlayerPositions; i++)
3267         {
3268                 if (i != Player_num)
3269                         Objects[Players[i].objnum].control_type = CT_REMOTE;
3270                 Objects[Players[i].objnum].movement_type = MT_PHYSICS;
3271                 multi_reset_player_object(&Objects[Players[i].objnum]);
3272                 LastPacketTime[i] = 0;
3273         }
3274
3275 #ifndef SHAREWARE
3276         for (i = 0; i < MAX_ROBOTS_CONTROLLED; i++)
3277         {
3278                 robot_controlled[i] = -1;       
3279                 robot_agitation[i] = 0;
3280                 robot_fired[i] = 0;
3281         }
3282 #endif
3283
3284         Viewer = ConsoleObject = &Objects[Players[Player_num].objnum];
3285
3286         if (!(Game_mode & GM_MULTI_COOP))       
3287         {
3288                 multi_delete_extra_objects(); // Removes monsters from level
3289         }
3290
3291         if (Game_mode & GM_MULTI_ROBOTS)
3292         {
3293                 multi_set_robot_ai(); // Set all Robot AI to types we can cope with
3294         }
3295  
3296    if (Game_mode & GM_NETWORK)
3297          {
3298           multi_adjust_cap_for_player(Player_num);      
3299           multi_send_powerup_update();
3300           ng=1;  // ng means network game
3301          }
3302    ng=1;        
3303
3304         inv_count = 0;
3305         cloak_count = 0;
3306         for (i=0; i<=Highest_object_index; i++)
3307         {
3308                 int objnum;
3309
3310                 if ((Objects[i].type == OBJ_HOSTAGE) && !(Game_mode & GM_MULTI_COOP))
3311                 {
3312                         objnum = obj_create(OBJ_POWERUP, POW_SHIELD_BOOST, Objects[i].segnum, &Objects[i].pos, &vmd_identity_matrix, Powerup_info[POW_SHIELD_BOOST].size, CT_POWERUP, MT_PHYSICS, RT_POWERUP);
3313                         obj_delete(i);                  
3314                         if (objnum != -1)
3315                         {
3316                                 Objects[objnum].rtype.vclip_info.vclip_num = Powerup_info[POW_SHIELD_BOOST].vclip_num;
3317                                 Objects[objnum].rtype.vclip_info.frametime = Vclip[Objects[objnum].rtype.vclip_info.vclip_num].frame_time;
3318                                 Objects[objnum].rtype.vclip_info.framenum = 0;
3319                                 Objects[objnum].mtype.phys_info.drag = 512;     //1024;
3320                                 Objects[objnum].mtype.phys_info.mass = F1_0;
3321                                 vm_vec_zero(&Objects[objnum].mtype.phys_info.velocity);
3322                         }
3323                         continue;
3324                 }
3325
3326                 if (Objects[i].type == OBJ_POWERUP)
3327                 {
3328                         if (Objects[i].id == POW_EXTRA_LIFE) 
3329                         {
3330                    if (ng && !Netgame.DoInvulnerability)
3331                       {
3332                                  Objects[i].id = POW_SHIELD_BOOST;
3333                                  Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num;
3334                                  Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time;
3335                       }
3336                    else
3337                       {
3338                                  Objects[i].id = POW_INVULNERABILITY;
3339                                  Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num;
3340                                  Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time;
3341                       } 
3342
3343               }
3344
3345                         if (!(Game_mode & GM_MULTI_COOP))
3346                                 if ((Objects[i].id >= POW_KEY_BLUE) && (Objects[i].id <= POW_KEY_GOLD))
3347                                         {
3348                                                 Objects[i].id = POW_SHIELD_BOOST;
3349                                                 Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num;
3350                                                 Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time;
3351                                         }
3352
3353                         if (Objects[i].id == POW_INVULNERABILITY) {
3354                            if (inv_count >= 3 || (ng && !Netgame.DoInvulnerability)) {
3355                                         mprintf((0, "Bashing Invulnerability object #%i to shield.\n", i));
3356                                         Objects[i].id = POW_SHIELD_BOOST;
3357                                         Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num;
3358                                         Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time;
3359                                 } else
3360                                         inv_count++;
3361                         }
3362
3363                         if (Objects[i].id == POW_CLOAK) {
3364            if (cloak_count >= 3 || (ng && !Netgame.DoCloak)) {
3365                                         mprintf((0, "Bashing Cloak object #%i to shield.\n", i));
3366                                         Objects[i].id = POW_SHIELD_BOOST;
3367                                         Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num;
3368                                         Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time;
3369                                 } else
3370                                         cloak_count++;
3371                         }
3372
3373         if (Objects[i].id == POW_AFTERBURNER && ng && !Netgame.DoAfterburner)
3374            bash_to_shield (i,"afterburner");
3375         if (Objects[i].id == POW_FUSION_WEAPON && ng &&  !Netgame.DoFusions)
3376            bash_to_shield (i,"fusion");
3377         if (Objects[i].id == POW_PHOENIX_WEAPON && ng && !Netgame.DoPhoenix)
3378            bash_to_shield (i,"phoenix");
3379
3380         if (Objects[i].id == POW_HELIX_WEAPON && ng && !Netgame.DoHelix)
3381            bash_to_shield (i,"helix");
3382
3383         if (Objects[i].id == POW_MEGA_WEAPON && ng && !Netgame.DoMegas)
3384            bash_to_shield (i,"mega");
3385
3386         if (Objects[i].id == POW_SMARTBOMB_WEAPON && ng && !Netgame.DoSmarts)
3387            bash_to_shield (i,"smartmissile");
3388
3389         if (Objects[i].id == POW_GAUSS_WEAPON && ng && !Netgame.DoGauss)
3390            bash_to_shield (i,"gauss");
3391
3392         if (Objects[i].id == POW_VULCAN_WEAPON && ng && !Netgame.DoVulcan)
3393            bash_to_shield (i,"vulcan");
3394                         
3395         if (Objects[i].id == POW_PLASMA_WEAPON && ng && !Netgame.DoPlasma)
3396            bash_to_shield (i,"plasma");
3397                  
3398         if (Objects[i].id == POW_OMEGA_WEAPON && ng && !Netgame.DoOmega)
3399            bash_to_shield (i,"omega");
3400
3401         if (Objects[i].id == POW_SUPER_LASER && ng && !Netgame.DoSuperLaser)
3402            bash_to_shield (i,"superlaser");
3403
3404         if (Objects[i].id == POW_PROXIMITY_WEAPON && ng && !Netgame.DoProximity)
3405            bash_to_shield (i,"proximity");
3406
3407 //    Special: Make all proximity bombs into shields if in hoard mode because
3408 //              we use the proximity slot in the player struct to signify how many orbs
3409 //              the player has.
3410
3411         if (Objects[i].id == POW_PROXIMITY_WEAPON && ng && (Game_mode & GM_HOARD))
3412            bash_to_shield (i,"proximity");
3413
3414         if (Objects[i].id==POW_VULCAN_AMMO && ng && (!Netgame.DoVulcan && !Netgame.DoGauss))
3415                 bash_to_shield(i,"vulcan ammo");
3416
3417         if (Objects[i].id == POW_SPREADFIRE_WEAPON && ng && !Netgame.DoSpread)
3418            bash_to_shield (i,"spread");
3419         if (Objects[i].id == POW_SMART_MINE && ng && !Netgame.DoSmartMine)
3420            bash_to_shield (i,"smartmine");
3421         if (Objects[i].id == POW_SMISSILE1_1 && ng &&  !Netgame.DoFlash)
3422            bash_to_shield (i,"flash");
3423         if (Objects[i].id == POW_SMISSILE1_4 && ng &&  !Netgame.DoFlash)
3424            bash_to_shield (i,"flash");
3425         if (Objects[i].id == POW_GUIDED_MISSILE_1 && ng &&  !Netgame.DoGuided)
3426            bash_to_shield (i,"guided");
3427         if (Objects[i].id == POW_GUIDED_MISSILE_4 && ng &&  !Netgame.DoGuided)
3428            bash_to_shield (i,"guided");
3429         if (Objects[i].id == POW_EARTHSHAKER_MISSILE && ng &&  !Netgame.DoEarthShaker)
3430            bash_to_shield (i,"earth");
3431         if (Objects[i].id == POW_MERCURY_MISSILE_1 && ng &&  !Netgame.DoMercury)
3432            bash_to_shield (i,"Mercury");
3433         if (Objects[i].id == POW_MERCURY_MISSILE_4 && ng &&  !Netgame.DoMercury)
3434            bash_to_shield (i,"Mercury");
3435         if (Objects[i].id == POW_CONVERTER && ng &&  !Netgame.DoConverter)
3436            bash_to_shield (i,"Converter");
3437         if (Objects[i].id == POW_AMMO_RACK && ng &&  !Netgame.DoAmmoRack)
3438            bash_to_shield (i,"Ammo rack");
3439         if (Objects[i].id == POW_HEADLIGHT && ng &&  !Netgame.DoHeadlight)
3440            bash_to_shield (i,"Headlight");
3441         if (Objects[i].id == POW_LASER && ng &&  !Netgame.DoLaserUpgrade)
3442            bash_to_shield (i,"Laser powerup");
3443         if (Objects[i].id == POW_HOMING_AMMO_1 && ng &&  !Netgame.DoHoming)
3444            bash_to_shield (i,"Homing");
3445         if (Objects[i].id == POW_HOMING_AMMO_4 && ng &&  !Netgame.DoHoming)
3446            bash_to_shield (i,"Homing");
3447         if (Objects[i].id == POW_QUAD_FIRE && ng &&  !Netgame.DoQuadLasers)
3448            bash_to_shield (i,"Quad Lasers");
3449    if (Objects[i].id == POW_FLAG_BLUE && !(Game_mode & GM_CAPTURE))
3450            bash_to_shield (i,"Blue flag");
3451    if (Objects[i].id == POW_FLAG_RED && !(Game_mode & GM_CAPTURE))
3452            bash_to_shield (i,"Red flag");
3453      }
3454    }
3455         
3456         if (Game_mode & GM_HOARD)
3457                 init_hoard_data();
3458
3459    if ((Game_mode & GM_CAPTURE) || (Game_mode & GM_HOARD))
3460          multi_apply_goal_textures();
3461   
3462         multi_sort_kill_list();
3463
3464         multi_show_player_list();
3465
3466         ConsoleObject->control_type = CT_FLYING;
3467
3468         reset_player_object();
3469
3470 }
3471
3472 int Goal_blue_segnum,Goal_red_segnum;
3473
3474 void multi_apply_goal_textures()
3475 {
3476         int             i,j,tex;
3477         segment *seg;
3478         segment2        *seg2;
3479  
3480         for (i=0; i <= Highest_segment_index; i++)
3481          {
3482                 seg = &Segments[i];
3483                 seg2 = &Segment2s[i];
3484  
3485       if (seg2->special==SEGMENT_IS_GOAL_BLUE)
3486                  {
3487                         
3488                         Goal_blue_segnum = i;
3489
3490                         if (Game_mode & GM_HOARD)
3491                                 tex=find_goal_texture (TMI_GOAL_HOARD);
3492                         else
3493                                 tex=find_goal_texture (TMI_GOAL_BLUE);
3494                         
3495                         if (tex>-1)
3496                                 for (j = 0; j < 6; j++) {
3497                                         int v;
3498                                         seg->sides[j].tmap_num=tex;
3499                                         for (v=0;v<4;v++)
3500                                                 seg->sides[j].uvls[v].l = i2f(100);             //max out
3501                                 }
3502
3503                         seg2->static_light = i2f(100);  //make static light bright
3504
3505                  }      
3506                         
3507       if (seg2->special==SEGMENT_IS_GOAL_RED)
3508                  {
3509                         Goal_red_segnum = i;
3510
3511                         // Make both textures the same if Hoard mode
3512
3513                         if (Game_mode & GM_HOARD)
3514                                 tex=find_goal_texture (TMI_GOAL_HOARD);
3515                         else
3516                                 tex=find_goal_texture (TMI_GOAL_RED);
3517                 
3518                         if (tex>-1)
3519                                 for (j = 0; j < 6; j++) {
3520                                         int v;
3521                                         seg->sides[j].tmap_num=tex;
3522                                         for (v=0;v<4;v++)
3523                                                 seg->sides[j].uvls[v].l = i2f(1000);            //max out
3524                                 }
3525
3526                         seg2->static_light = i2f(100);  //make static light bright
3527                  }
3528          }
3529  }
3530 int find_goal_texture (ubyte t)
3531  {
3532   int i;
3533  
3534   for (i=0;i<NumTextures;i++)
3535         if (TmapInfo[i].flags & t)
3536                 return i;
3537
3538   Int3(); // Hey, there is no goal texture for this PIG!!!!
3539                          // Edit bitmaps.tbl and designate two textures to be RED and BLUE
3540                          // goal textures
3541   return (-1);
3542  }
3543
3544
3545 /* DPH: Moved to gameseq.c 
3546 void bash_to_shield (int i,char *s)
3547  {
3548    int type=Objects[i].id;
3549   
3550     mprintf((0, "Bashing %s object #%i to shield.\n",s, i));
3551
3552          PowerupsInMine[type]=MaxPowerupsAllowed[type]=0;
3553                                   
3554     Objects[i].id = POW_SHIELD_BOOST;
3555     Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num;
3556     Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time;
3557  }
3558 */
3559
3560 void multi_set_robot_ai(void)
3561 {
3562         // Go through the objects array looking for robots and setting
3563         // them to certain supported types of NET AI behavior.
3564
3565 //      int i;
3566 //
3567 //      for (i = 0; i <= Highest_object_index; i++)
3568 //      {
3569 //              if (Objects[i].type == OBJ_ROBOT) {
3570 //                      Objects[i].ai_info.REMOTE_OWNER = -1;
3571 //                      if (Objects[i].ai_info.behavior == AIB_STATION)
3572 //                              Objects[i].ai_info.behavior = AIB_NORMAL;
3573 //              }
3574 //      }
3575 }
3576
3577 int multi_delete_extra_objects()
3578 {
3579         int i;
3580         int nnp=0;
3581         object *objp;
3582         
3583         // Go through the object list and remove any objects not used in
3584         // 'Anarchy!' games.
3585
3586         // This function also prints the total number of available multiplayer
3587         // positions in this level, even though this should always be 8 or more!
3588
3589         objp = Objects;
3590         for (i=0;i<=Highest_object_index;i++) {
3591                 if ((objp->type==OBJ_PLAYER) || (objp->type==OBJ_GHOST)) 
3592                         nnp++;
3593                 else if ((objp->type==OBJ_ROBOT) && (Game_mode & GM_MULTI_ROBOTS))
3594                         ;
3595                 else if ( (objp->type!=OBJ_NONE) && (objp->type!=OBJ_PLAYER) && (objp->type!=OBJ_POWERUP) && (objp->type!=OBJ_CNTRLCEN) && (objp->type!=OBJ_HOSTAGE) && !(objp->type==OBJ_WEAPON && objp->id==PMINE_ID) ) {
3596                         //      Before deleting object, if it's a robot, drop it's special powerup, if any
3597                         if (objp->type == OBJ_ROBOT)
3598                                 if (objp->contains_count && (objp->contains_type == OBJ_POWERUP))
3599                                         object_create_egg(objp);
3600                         obj_delete(i);
3601                 }
3602                 objp++;
3603         }
3604
3605         return nnp;
3606 }
3607
3608 void change_playernum_to( int new_Player_num )  
3609 {
3610         if (Player_num > -1)
3611                 memcpy( Players[new_Player_num].callsign, Players[Player_num].callsign, CALLSIGN_LEN+1 );
3612         Player_num = new_Player_num;
3613 }
3614
3615 int multi_all_players_alive()
3616  {
3617   int i;
3618   for (i=0;i<N_players;i++)
3619         {
3620          if (PKilledFlags[i] && Players[i].connected)
3621                 return (0);
3622         }
3623   return (1);
3624  }
3625
3626 void multi_initiate_save_game()
3627 {
3628         uint game_id;
3629         int i, slot;
3630         char filename[128];
3631         char desc[24];
3632
3633         if ((Endlevel_sequence) || (Control_center_destroyed))
3634                 return;
3635     
3636    if (!multi_all_players_alive())
3637          {
3638           HUD_init_message ("Can't save...all players must be alive!");
3639           return;
3640          }
3641
3642 //      multi_send_netplayer_stats_request(255);
3643 //      return;
3644
3645 //      stop_time();
3646         
3647         slot = state_get_save_file(filename, desc, 1 );
3648         if (!slot)      {
3649                 //start_time();
3650                 return;
3651         }
3652         slot--;
3653
3654 //      start_time();
3655
3656         // Make a unique game id
3657         game_id = timer_get_fixed_seconds();
3658         game_id ^= N_players<<4;
3659         for (i=0; i<N_players; i++ )
3660                 game_id ^= *(uint *)Players[i].callsign;
3661         if ( game_id == 0 ) game_id = 1;                // 0 is invalid
3662
3663         mprintf(( 1, "Game_id = %8x\n", game_id));
3664         multi_send_save_game(slot, game_id, desc );
3665         multi_do_frame();
3666         multi_save_game(slot,game_id, desc );
3667 }
3668
3669 extern int state_get_game_id(char *);
3670
3671 void multi_initiate_restore_game()
3672 {
3673         int slot;
3674         char filename[128];
3675
3676         if ((Endlevel_sequence) || (Control_center_destroyed))
3677                 return;
3678
3679    if (!multi_all_players_alive())
3680          {
3681           HUD_init_message ("Can't restore...all players must be alive!");
3682           return;
3683          }
3684
3685 //      stop_time();
3686         slot = state_get_restore_file(filename,1);
3687         if (!slot)      {
3688                 //start_time();
3689                 return;
3690         }
3691    state_game_id=state_get_game_id (filename);
3692    if (!state_game_id)
3693                 return;
3694   
3695         slot--;
3696 //      start_time();
3697         multi_send_restore_game(slot,state_game_id);
3698         multi_do_frame();
3699         multi_restore_game(slot,state_game_id);
3700 }
3701
3702 void multi_save_game(ubyte slot, uint id, char *desc)
3703 {
3704         char filename[128];
3705
3706         if ((Endlevel_sequence) || (Control_center_destroyed))
3707                 return;
3708
3709         #ifndef MACINTOSH
3710         sprintf( filename, "%s.mg%d", Players[Player_num].callsign, slot );
3711         #else
3712         sprintf( filename, ":Players:%s.mg%d", Players[Player_num].callsign, slot );
3713         #endif
3714         mprintf(( 0, "Save game %x on slot %d\n", id, slot ));
3715         HUD_init_message( "Saving game #%d, '%s'", slot, desc );
3716         stop_time();
3717         state_game_id = id;
3718         state_save_all_sub(filename, desc, 0 );
3719 }
3720
3721 void multi_restore_game(ubyte slot, uint id)
3722 {
3723         char filename[128];
3724         player saved_player;
3725         int pnum,i;
3726         int thisid;
3727
3728         if ((Endlevel_sequence) || (Control_center_destroyed))
3729                 return;
3730
3731         mprintf(( 0, "Restore game %x from slot %d\n", id, slot ));
3732         saved_player = Players[Player_num];
3733         #ifndef MACINTOSH
3734         sprintf( filename, "%s.mg%d", Players[Player_num].callsign, slot );
3735         #else
3736         sprintf( filename, ":Players:%s.mg%d", Players[Player_num].callsign, slot );
3737         #endif
3738    
3739    for (i=0;i<N_players;i++)
3740                 multi_strip_robots(i);
3741    
3742         thisid=state_get_game_id (filename);
3743    if (thisid!=id)
3744          {
3745                 multi_bad_restore ();
3746                 return;
3747          }
3748   
3749         pnum=state_restore_all_sub( filename, 1, 0 );
3750
3751         mprintf ((0,"StateId=%d ThisID=%d\n",state_game_id,id));
3752         
3753 /*        if (state_game_id != id )       {
3754                 // Game doesn't match!!!
3755                 nm_messagebox( "Error", 1, "Ok", "Cannot restore saved game" );
3756                 Game_mode |= GM_GAME_OVER;
3757                 Function_mode = FMODE_MENU;
3758                 longjmp(LeaveGame, 0);
3759         }
3760
3761         change_playernum_to(pnum-1);
3762         memcpy( Players[Player_num].callsign, saved_player.callsign, CALLSIGN_LEN+1 );
3763         memcpy( Players[Player_num].net_address, saved_player.net_address, 6 );
3764         Players[Player_num].connected = saved_player.connected;
3765         Players[Player_num].n_packets_got  = saved_player.n_packets_got;                                        
3766         Players[Player_num].n_packets_sent = saved_player.n_packets_sent;                               
3767         Viewer = ConsoleObject = &Objects[pnum-1]; */
3768 }
3769
3770
3771 void extract_netplayer_stats( netplayer_stats *ps, player * pd )
3772 {
3773         int i;
3774         
3775         ps->flags = INTEL_INT(pd->flags);                                                  // Powerup flags, see below...
3776         ps->energy = (fix)INTEL_INT(pd->energy);                                                        // Amount of energy remaining.
3777         ps->shields = (fix)INTEL_INT(pd->shields);                                                      // shields remaining (protection) 
3778         ps->lives = pd->lives;                                                  // Lives remaining, 0 = game over.
3779         ps->laser_level = pd->laser_level;                                      //      Current level of the laser.
3780         ps->primary_weapon_flags=pd->primary_weapon_flags;                                      //      bit set indicates the player has this weapon.
3781         ps->secondary_weapon_flags=pd->secondary_weapon_flags;                                  //      bit set indicates the player has this weapon.
3782         for (i = 0; i < MAX_PRIMARY_WEAPONS; i++)
3783                 ps->primary_ammo[i] = INTEL_SHORT(pd->primary_ammo[i]);
3784         for (i = 0; i < MAX_SECONDARY_WEAPONS; i++)
3785                 ps->secondary_ammo[i] = INTEL_SHORT(pd->secondary_ammo[i]);
3786
3787 //      memcpy( ps->primary_ammo, pd->primary_ammo, MAX_PRIMARY_WEAPONS*sizeof(short) );        // How much ammo of each type.
3788 //      memcpy( ps->secondary_ammo, pd->secondary_ammo, MAX_SECONDARY_WEAPONS*sizeof(short) ); // How much ammo of each type.
3789
3790         ps->last_score=INTEL_INT(pd->last_score);                                                               // Score at beginning of current level.
3791         ps->score=INTEL_INT(pd->score);                                                                                 // Current score.
3792         ps->cloak_time=(fix)INTEL_INT(pd->cloak_time);                                                  // Time cloaked
3793         ps->homing_object_dist=(fix)INTEL_INT(pd->homing_object_dist);          //      Distance of nearest homing object.
3794         ps->invulnerable_time=(fix)INTEL_INT(pd->invulnerable_time);                    // Time invulnerable
3795         ps->KillGoalCount=INTEL_SHORT(pd->KillGoalCount);
3796         ps->net_killed_total=INTEL_SHORT(pd->net_killed_total);                                 // Number of times killed total
3797         ps->net_kills_total=INTEL_SHORT(pd->net_kills_total);                                   // Number of net kills total
3798         ps->num_kills_level=INTEL_SHORT(pd->num_kills_level);                                   // Number of kills this level
3799         ps->num_kills_total=INTEL_SHORT(pd->num_kills_total);                                   // Number of kills total
3800         ps->num_robots_level=INTEL_SHORT(pd->num_robots_level);                                 // Number of initial robots this level
3801         ps->num_robots_total=INTEL_SHORT(pd->num_robots_total);                                 // Number of robots total
3802         ps->hostages_rescued_total=INTEL_SHORT(pd->hostages_rescued_total);             // Total number of hostages rescued.
3803         ps->hostages_total=INTEL_SHORT(pd->hostages_total);                                             // Total number of hostages.
3804         ps->hostages_on_board=pd->hostages_on_board;                                                    //      Number of hostages on ship.
3805 }
3806
3807 void use_netplayer_stats( player * ps, netplayer_stats *pd )
3808 {
3809         int i;
3810         
3811         ps->flags = INTEL_INT(pd->flags);                                                       // Powerup flags, see below...
3812         ps->energy = (fix)INTEL_INT((int)pd->energy);                           // Amount of energy remaining.
3813         ps->shields = (fix)INTEL_INT((int)pd->shields);                 // shields remaining (protection) 
3814         ps->lives = pd->lives;                                                                  // Lives remaining, 0 = game over.
3815         ps->laser_level = pd->laser_level;                                              //      Current level of the laser.
3816         ps->primary_weapon_flags=pd->primary_weapon_flags;              //      bit set indicates the player has this weapon.
3817         ps->secondary_weapon_flags=pd->secondary_weapon_flags;  //      bit set indicates the player has this weapon.
3818         for (i = 0; i < MAX_PRIMARY_WEAPONS; i++)
3819                 ps->primary_ammo[i] = INTEL_SHORT(pd->primary_ammo[i]);
3820         for (i = 0; i < MAX_SECONDARY_WEAPONS; i++)
3821                 ps->secondary_ammo[i] = INTEL_SHORT(pd->secondary_ammo[i]);
3822 //      memcpy( ps->primary_ammo, pd->primary_ammo, MAX_PRIMARY_WEAPONS*sizeof(short) );        // How much ammo of each type.
3823 //      memcpy( ps->secondary_ammo, pd->secondary_ammo, MAX_SECONDARY_WEAPONS*sizeof(short) ); // How much ammo of each type.
3824         ps->last_score = INTEL_INT(pd->last_score);                             // Score at beginning of current level.
3825         ps->score = INTEL_INT(pd->score);                                                       // Current score.
3826         ps->cloak_time = (fix)INTEL_INT((int)pd->cloak_time);           // Time cloaked
3827         ps->homing_object_dist = (fix)INTEL_INT((int)pd->homing_object_dist); //        Distance of nearest homing object.
3828         ps->invulnerable_time = (fix)INTEL_INT((int)pd->invulnerable_time);     // Time invulnerable
3829         ps->KillGoalCount=INTEL_SHORT(pd->KillGoalCount);
3830         ps->net_killed_total = INTEL_SHORT(pd->net_killed_total);       // Number of times killed total
3831         ps->net_kills_total = INTEL_SHORT(pd->net_kills_total); // Number of net kills total
3832         ps->num_kills_level = INTEL_SHORT(pd->num_kills_level); // Number of kills this level
3833         ps->num_kills_total = INTEL_SHORT(pd->num_kills_total); // Number of kills total
3834         ps->num_robots_level = INTEL_SHORT(pd->num_robots_level);       // Number of initial robots this level
3835         ps->num_robots_total = INTEL_SHORT(pd->num_robots_total);       // Number of robots total
3836         ps->hostages_rescued_total = INTEL_SHORT(pd->hostages_rescued_total);   // Total number of hostages rescued.
3837         ps->hostages_total = INTEL_SHORT(pd->hostages_total);           // Total number of hostages.
3838         ps->hostages_on_board=pd->hostages_on_board;                    //      Number of hostages on ship.
3839 }
3840
3841 void multi_send_drop_weapon (int objnum,int seed)
3842  {
3843         object *objp;
3844   int count=0;
3845         int ammo_count;
3846
3847         objp = &Objects[objnum];
3848
3849         ammo_count = objp->ctype.powerup_info.count;
3850
3851         if (objp->id == POW_OMEGA_WEAPON && ammo_count == F1_0)
3852                 ammo_count = F1_0 - 1;  //make fit in short
3853
3854         Assert(ammo_count < F1_0);      //make sure fits in short
3855
3856   multibuf[count++]=(char)MULTI_DROP_WEAPON;
3857   multibuf[count++]=(char)objp->id;
3858
3859   *(short *) (multibuf+count)=INTEL_SHORT(Player_num); count += 2;
3860   *(short *) (multibuf+count)=INTEL_SHORT(objnum); count += 2;
3861   *(short *) (multibuf+count)=INTEL_SHORT(ammo_count); count += 2;
3862   *(int *) (multibuf+count)=INTEL_INT(seed);
3863    
3864   map_objnum_local_to_local(objnum);
3865   
3866   if (Game_mode & GM_NETWORK)
3867            PowerupsInMine[objp->id]++;
3868
3869   multi_send_data(multibuf, 12, 2);
3870  }
3871
3872 void multi_do_drop_weapon (char *buf)
3873  {
3874   int pnum,ammo,objnum,remote_objnum,seed;
3875         object *objp;
3876   int powerup_id;
3877
3878         powerup_id=(int)(buf[1]);
3879         pnum = INTEL_SHORT(*(short *)(buf+2));
3880         remote_objnum = INTEL_SHORT(*(short *)(buf+4));
3881         ammo = INTEL_SHORT(*(ushort *)(buf+6));
3882         seed = INTEL_INT(*(int *)(buf+8));
3883
3884         objp = &Objects[Players[pnum].objnum];
3885
3886         objnum = spit_powerup(objp, powerup_id, seed);
3887
3888         map_objnum_local_to_remote(objnum, remote_objnum, pnum);                
3889
3890         if (objnum!=-1)
3891                 Objects[objnum].ctype.powerup_info.count = ammo;
3892    
3893    if (Game_mode & GM_NETWORK)
3894                 PowerupsInMine[powerup_id]++;
3895
3896   mprintf ((0,"Dropped weapon %d!\n"));
3897   
3898  }
3899
3900 void multi_send_guided_info (object *miss,char done)
3901 {
3902 #ifdef MACINTOSH
3903         shortpos sp;
3904 #endif
3905   int count=0;
3906
3907   mprintf ((0,"Sending guided info!\n"));
3908
3909   multibuf[count++]=(char)MULTI_GUIDED;
3910   multibuf[count++]=(char)Player_num;
3911   multibuf[count++]=done;
3912
3913 #ifndef MACINTOSH
3914   create_shortpos((shortpos *)(multibuf+count), miss,0);
3915   count+=sizeof(shortpos);
3916 #else
3917         create_shortpos(&sp, miss, 1);
3918         memcpy(&(multibuf[count]), (ubyte *)(sp.bytemat), 9);
3919         count += 9;
3920         memcpy(&(multibuf[count]), (ubyte *)&(sp.xo), 14);
3921         count += 14;
3922 #endif
3923
3924   multi_send_data(multibuf, count, 0);
3925  }
3926
3927 void multi_do_guided (char *buf)
3928  {
3929   char pnum=buf[1];
3930   int count=3;
3931   static int fun=200;
3932 #ifdef MACINTOSH
3933         shortpos sp;
3934 #endif
3935
3936   if (Guided_missile[(int)pnum]==NULL)
3937    {
3938     if (++fun>=50)
3939      {
3940       mprintf ((0,"Guided missile for %s is NULL!\n",Players[(int)pnum].callsign));
3941       fun=0;
3942      }
3943     return;
3944    }
3945   else if (++fun>=50)
3946    {
3947     mprintf ((0,"Got guided info for %d (%s)\n",pnum,Players[(int)pnum].callsign));
3948     fun=0;
3949    }
3950
3951   if (buf[2])
3952    {
3953          release_guided_missile(pnum);
3954          return;
3955         }
3956
3957
3958   if (Guided_missile[(int)pnum]-Objects<0 || Guided_missile[(int)pnum]-Objects > Highest_object_index)
3959         {       
3960          Int3();  // Get Jason immediately!
3961          return;
3962         }
3963
3964 #ifndef MACINTOSH       
3965   extract_shortpos(Guided_missile[(int)pnum], (shortpos *)(buf+count),0); 
3966 #else
3967         memcpy((ubyte *)(sp.bytemat), (ubyte *)(buf + count), 9);
3968         memcpy((ubyte *)&(sp.xo), (ubyte *)(buf + count + 9), 14);
3969         extract_shortpos(Guided_missile[(int)pnum], &sp, 1);
3970 #endif
3971
3972   count+=sizeof (shortpos);
3973
3974   update_object_seg(Guided_missile[(int)pnum]);
3975  }
3976
3977 void multi_send_stolen_items ()
3978  {
3979   int i,count=1;
3980   multibuf[0]=MULTI_STOLEN_ITEMS;
3981   
3982   for (i=0;i<MAX_STOLEN_ITEMS;i++)
3983    {
3984     multibuf[i+1]=Stolen_items[i];
3985          mprintf ((0,"[%d]=%d ",i,Stolen_items[i]));
3986     count++;      // So I like to break my stuff into smaller chunks, so what?
3987    }
3988   mprintf ((0,"\n"));
3989   multi_send_data(multibuf, count, 1);
3990  }
3991
3992 void multi_do_stolen_items (char *buf)
3993  {
3994   int i;
3995
3996   mprintf ((0,"Recieved a stolen item packet...\n"));
3997
3998   for (i=0;i<MAX_STOLEN_ITEMS;i++)
3999   {
4000    Stolen_items[i]=buf[i+1];
4001         mprintf ((0,"[%d]=%d ",i,Stolen_items[i]));
4002   }
4003   mprintf ((0,"\n"));
4004  }
4005
4006 extern void network_send_important_packet (char *,int);
4007
4008 void multi_send_wall_status (int wallnum,ubyte type,ubyte flags,ubyte state)
4009 {
4010   int count=0;
4011   multibuf[count]=MULTI_WALL_STATUS;        count++;
4012   *(short *)(multibuf+count)=INTEL_SHORT(wallnum);   count+=2;
4013   multibuf[count]=type;                 count++;
4014   multibuf[count]=flags;                count++;
4015   multibuf[count]=state;                count++;
4016
4017  /* if (Game_mode & GM_NETWORK)
4018         {
4019           network_send_important_packet (multibuf,count);
4020           network_send_important_packet (multibuf,count);
4021         } 
4022   else*/
4023         {
4024           multi_send_data(multibuf, count, 1); // twice, just to be sure
4025      multi_send_data(multibuf, count, 1);
4026         }
4027 }
4028 void multi_send_wall_status_specific (int pnum,int wallnum,ubyte type,ubyte flags,ubyte state)
4029 {
4030   // Send wall states a specific rejoining player
4031  
4032   int count=0;
4033
4034   Assert (Game_mode & GM_NETWORK);
4035 //  Assert (pnum>-1 && pnum<N_players);
4036   
4037   multibuf[count]=MULTI_WALL_STATUS;        count++;
4038   *(short *)(multibuf+count)=INTEL_SHORT(wallnum);   count+=2;
4039   multibuf[count]=type;                 count++;
4040   multibuf[count]=flags;                count++;
4041   multibuf[count]=state;                count++;
4042
4043   network_send_naked_packet(multibuf, count,pnum); // twice, just to be sure
4044   network_send_naked_packet(multibuf, count,pnum);
4045 }
4046
4047 void multi_do_wall_status (char *buf)
4048  {
4049   short wallnum;
4050   ubyte flag,type,state;
4051
4052   wallnum=INTEL_SHORT( *(short *)(buf+1) );
4053   type=buf[3];
4054   flag=buf[4];
4055   state=buf[5];
4056
4057   Assert (wallnum>=0);
4058   Walls[wallnum].type=type;
4059   Walls[wallnum].flags=flag;
4060 //  Assert(state <= 4);
4061   Walls[wallnum].state=state; 
4062   
4063   if (Walls[wallnum].type==WALL_OPEN)
4064         {  
4065           digi_kill_sound_linked_to_segment(Walls[wallnum].segnum,Walls[wallnum].sidenum,SOUND_FORCEFIELD_HUM);
4066  //  digi_kill_sound_linked_to_segment(csegp-Segments,cside,SOUND_FORCEFIELD_HUM);
4067    }
4068
4069         
4070 //  mprintf ((0,"Got a walls packet.\n"));
4071  }
4072
4073 void multi_send_jason_cheat (int num)
4074  {
4075   num=num;
4076   return;
4077  }
4078
4079 void multi_send_kill_goal_counts()
4080  {
4081   int i,count=1;
4082   multibuf[0]=MULTI_KILLGOALS;
4083   
4084   for (i=0;i<MAX_PLAYERS;i++)
4085    {
4086     *(char *)(multibuf+count)=(char)Players[i].KillGoalCount;
4087     count++;
4088    }
4089
4090   mprintf ((0,"MULTI: Sending KillGoalCounts...\n"));
4091   multi_send_data(multibuf, count, 1);
4092  }
4093
4094 void multi_do_kill_goal_counts(char *buf)
4095  {
4096   int i,count=1;
4097   
4098   for (i=0;i<MAX_PLAYERS;i++)
4099    {
4100     Players[i].KillGoalCount=*(char *)(buf+count);
4101     mprintf ((0,"KGC: %s has %d kills!\n",Players[i].callsign,Players[i].KillGoalCount));
4102     count++;
4103    }
4104
4105  }
4106
4107 void multi_send_heartbeat ()
4108  {
4109   if (!Netgame.PlayTimeAllowed)
4110         return;
4111  
4112   multibuf[0]=MULTI_HEARTBEAT;
4113   *(fix *)(multibuf+1)=(fix)INTEL_INT(ThisLevelTime);
4114   multi_send_data(multibuf, 5, 0);
4115  }
4116
4117 void multi_do_heartbeat (char *buf)
4118  {
4119   fix num;
4120
4121   num=(fix)INTEL_INT(*(int *)(buf+1));
4122
4123   ThisLevelTime=num;
4124  }
4125
4126 void multi_check_for_killgoal_winner ()
4127  {
4128   int i,best=0,bestnum=0;
4129   object *objp;
4130  
4131   
4132   if (Control_center_destroyed) 
4133         return;
4134  
4135   for (i=0;i<N_players;i++)
4136    {
4137     if (Players[i].KillGoalCount>best)
4138      {
4139       best=Players[i].KillGoalCount;
4140       bestnum=i;
4141      }
4142    }
4143
4144   if (bestnum==Player_num)
4145    {
4146     HUD_init_message("You have the best score at %d kills!",best);
4147 //    Players[Player_num].shields=i2f(200);
4148    }
4149   else
4150
4151    HUD_init_message ("%s has the best score with %d kills!",Players[bestnum].callsign,best);
4152
4153   HUD_init_message ("The control center has been destroyed!");
4154  
4155   objp=obj_find_first_of_type (OBJ_CNTRLCEN);
4156   net_destroy_controlcen (objp);
4157  }
4158   
4159 void multi_send_seismic (fix start,fix end)
4160  {
4161   int count=1; 
4162   
4163   multibuf[0]=MULTI_SEISMIC;
4164   *(fix *)(multibuf+count)=(fix)INTEL_INT(start); count+=(sizeof(fix));
4165   *(fix *)(multibuf+count)=(fix)INTEL_INT(end); count+=(sizeof(fix));
4166   
4167   multi_send_data(multibuf, count, 1);
4168  }
4169
4170 extern fix Seismic_disturbance_start_time;
4171 extern fix Seismic_disturbance_end_time;
4172      
4173 void multi_do_seismic (char *buf)
4174  {
4175   Seismic_disturbance_start_time=(fix)INTEL_INT( *(int *)(buf+1) );
4176   Seismic_disturbance_end_time=(fix)INTEL_INT( *(int *)(buf+5) );
4177   digi_play_sample (SOUND_SEISMIC_DISTURBANCE_START, F1_0);
4178  }
4179
4180 void multi_send_light (int segnum,ubyte val)
4181  {
4182   int count=1,i;
4183   multibuf[0]=MULTI_LIGHT;
4184   *(int *)(multibuf+count)=INTEL_INT(segnum); count+=(sizeof(int));
4185   *(char *)(multibuf+count)=val; count++;
4186   for (i=0;i<6;i++)
4187         {
4188     //mprintf ((0,"Sending %d!\n",Segments[segnum].sides[i].tmap_num2));
4189          *(short *)(multibuf+count)=INTEL_SHORT(Segments[segnum].sides[i].tmap_num2); count+=2;
4190         }
4191    multi_send_data(multibuf, count, 1);
4192  }
4193 void multi_send_light_specific (int pnum,int segnum,ubyte val)
4194  {
4195   int count=1,i;
4196
4197   Assert (Game_mode & GM_NETWORK);
4198 //  Assert (pnum>-1 && pnum<N_players);
4199  
4200   multibuf[0]=MULTI_LIGHT;
4201   *(int *)(multibuf+count)=INTEL_INT(segnum); count+=(sizeof(int));
4202   *(char *)(multibuf+count)=val; count++;
4203
4204   for (i=0;i<6;i++)