]> icculus.org git repositories - btb/d2x.git/blob - main/multi.c
fix compiler warnings w/opengl
[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++)
4205         {
4206     //mprintf ((0,"Sending %d!\n",Segments[segnum].sides[i].tmap_num2));
4207          *(short *)(multibuf+count)=INTEL_SHORT(Segments[segnum].sides[i].tmap_num2); count+=2;
4208         }
4209    network_send_naked_packet(multibuf, count, pnum);
4210  }
4211
4212 void multi_do_light (char *buf)
4213  {
4214   int i;
4215   int seg=INTEL_INT(*(int *)(buf+1));
4216   ubyte sides=*(char *)(buf+5);
4217
4218   for (i=0;i<6;i++)
4219         {
4220          if ((sides & (1<<i)))
4221      {
4222       subtract_light (seg,i);
4223       Segments[seg].sides[i].tmap_num2=INTEL_SHORT( *(short *)(buf+(6+(2*i))) );
4224   //            mprintf ((0,"Got %d!\n",Segments[seg].sides[i].tmap_num2));
4225           }     
4226    }
4227  }
4228
4229 //@@void multi_send_start_trigger(int triggernum)
4230 //@@{
4231 //@@    // Send an even to trigger something in the mine
4232 //@@    
4233 //@@    int count = 0;
4234 //@@    
4235 //@@    multibuf[count] = MULTI_START_TRIGGER;                          count += 1;
4236 //@@    multibuf[count] = Player_num;                                   count += 1;
4237 //@@    multibuf[count] = (ubyte)triggernum;            count += 1;
4238 //@@   
4239 //@@//   mprintf ((0,"Sending start trigger %d\n",triggernum));
4240 //@@    multi_send_data(multibuf, count, 2);
4241 //@@}
4242 //@@void multi_do_start_trigger(char *buf)
4243 //@@{
4244 //@@    int pnum = buf[1];
4245 //@@    int trigger = buf[2];
4246 //@@   
4247 //@@//   mprintf ((0,"MULTI doing start trigger!\n"));
4248 //@@
4249 //@@    if ((pnum < 0) || (pnum >= N_players) || (pnum == Player_num))
4250 //@@    {
4251 //@@            Int3(); // Got trigger from illegal playernum
4252 //@@            return;
4253 //@@    }
4254 //@@    if ((trigger < 0) || (trigger >= Num_triggers))
4255 //@@    {
4256 //@@            Int3(); // Illegal trigger number in multiplayer
4257 //@@            return;
4258 //@@    }
4259 //@@
4260 //@@  if (!(Triggers[trigger].flags & TF_SPRUNG))
4261 //@@    check_trigger_sub(trigger, pnum,0);
4262 //@@}
4263
4264
4265 void multi_do_flags (char *buf)
4266 {
4267         char pnum=buf[1];
4268         uint flags=INTEL_INT( *(uint *)(buf+2) );
4269
4270         if (pnum!=Player_num)
4271                 Players[(int)pnum].flags=flags;
4272 }
4273
4274 void multi_send_flags (char pnum)
4275  {
4276   multibuf[0]=MULTI_FLAGS;
4277   multibuf[1]=pnum;
4278   *(uint *)(multibuf+2)=INTEL_INT(Players[(int)pnum].flags);
4279   
4280   multi_send_data(multibuf, 6, 1);
4281  } 
4282   
4283 void multi_send_drop_blobs (char pnum)
4284  {
4285   multibuf[0]=MULTI_DROP_BLOB;
4286   multibuf[1]=pnum;
4287
4288   multi_send_data(multibuf, 2, 0);
4289  }
4290
4291 void multi_do_drop_blob (char *buf)
4292  {
4293    char pnum=buf[1];
4294    drop_afterburner_blobs (&Objects[Players[(int)pnum].objnum], 2, i2f(5)/2, -1);
4295  }
4296
4297 void multi_send_powerup_update ()
4298  {
4299   int i;        
4300
4301         
4302   multibuf[0]=MULTI_POWERUP_UPDATE;
4303   for (i=0;i<MAX_POWERUP_TYPES;i++)     
4304    multibuf[i+1]=MaxPowerupsAllowed[i];
4305
4306   multi_send_data(multibuf, MAX_POWERUP_TYPES+1, 1);
4307  }
4308 void multi_do_powerup_update (char *buf)
4309  {
4310   int i;
4311
4312   for (i=0;i<MAX_POWERUP_TYPES;i++)
4313         if (buf[i+1]>MaxPowerupsAllowed[i])
4314                 MaxPowerupsAllowed[i]=buf[i+1];
4315  }
4316
4317 extern active_door ActiveDoors[];
4318 extern int Num_open_doors;                                              // Number of open doors
4319   
4320 void multi_send_active_door (char i)
4321 {
4322         int count;
4323         
4324         multibuf[0]=MULTI_ACTIVE_DOOR;
4325         multibuf[1]=i;
4326         multibuf[2]=Num_open_doors;     
4327         count = 3;
4328 #ifndef MACINTOSH
4329         memcpy ((char *)(&multibuf[3]),&ActiveDoors[(int)i],sizeof(struct active_door));
4330         count += sizeof(active_door);
4331 #else
4332         *(int *)(multibuf + count) = INTEL_INT(ActiveDoors[i].n_parts);                                 count += 4;
4333         *(short *)(multibuf + count) = INTEL_SHORT(ActiveDoors[i].front_wallnum[0]);    count += 2;
4334         *(short *)(multibuf + count) = INTEL_SHORT(ActiveDoors[i].front_wallnum[1]);    count += 2;
4335         *(short *)(multibuf + count) = INTEL_SHORT(ActiveDoors[i].back_wallnum[0]);             count += 2;
4336         *(short *)(multibuf + count) = INTEL_SHORT(ActiveDoors[i].back_wallnum[1]);             count += 2;
4337         *(int *)(multibuf + count) = INTEL_INT(ActiveDoors[i].time);                                    count += 4;
4338 #endif
4339 //      multi_send_data (multibuf,sizeof(struct active_door)+3,1);
4340         multi_send_data (multibuf,count,1);
4341 }
4342
4343 void multi_do_active_door (char *buf)
4344 {
4345         int count;
4346         char i=multibuf[1];
4347         Num_open_doors=buf[2];
4348         
4349         count = 3;
4350 #ifndef MACINTOSH
4351         memcpy (&ActiveDoors[(int)i],buf+count,sizeof(struct active_door));
4352 #else
4353         ActiveDoors[i].n_parts = INTEL_INT( *(int *)(buf+count) );                              count += 4;
4354         ActiveDoors[i].front_wallnum[0] = INTEL_SHORT( *(short *)(buf+count) ); count +=2;
4355         ActiveDoors[i].front_wallnum[1] = INTEL_SHORT( *(short *)(buf+count) ); count +=2;
4356         ActiveDoors[i].back_wallnum[0] = INTEL_SHORT( *(short *)(buf+count) );  count +=2;
4357         ActiveDoors[i].back_wallnum[1] = INTEL_SHORT( *(short *)(buf+count) );  count +=2;
4358         ActiveDoors[i].time = INTEL_INT( *(int *)(buf+count) );                                 count += 4;
4359 #endif
4360 }       
4361
4362 void multi_send_sound_function (char whichfunc,char sound)
4363 {
4364         int count=0;
4365   
4366         multibuf[0]=MULTI_SOUND_FUNCTION;  count++;
4367         multibuf[1]=Player_num; count++;
4368         multibuf[2]=whichfunc;  count++;
4369         #ifndef MACINTOSH
4370         *(uint *)(multibuf+count)=sound;        count++;
4371         #else
4372         multibuf[3] = sound; count++;           // this would probably work on the PC as well.  Jason?
4373         #endif
4374         multi_send_data (multibuf,4,0);
4375 }
4376
4377 #define AFTERBURNER_LOOP_START  20098
4378 #define AFTERBURNER_LOOP_END            25776
4379
4380 void multi_do_sound_function (char *buf)
4381 {
4382    // for afterburner
4383   
4384         char pnum,whichfunc;
4385         int sound; 
4386
4387    if (Players[Player_num].connected!=1)
4388                 return; 
4389
4390    pnum=buf[1];
4391         whichfunc=buf[2];
4392         sound=buf[3];
4393         
4394         if (whichfunc==0)
4395                 digi_kill_sound_linked_to_object (Players[(int)pnum].objnum);
4396         else if (whichfunc==3)
4397            digi_link_sound_to_object3( sound, Players[(int)pnum].objnum, 1,F1_0, i2f(256), AFTERBURNER_LOOP_START, AFTERBURNER_LOOP_END);
4398 }  
4399
4400 void multi_send_capture_bonus (char pnum)
4401 {
4402   Assert (Game_mode & GM_CAPTURE);
4403   
4404   multibuf[0]=MULTI_CAPTURE_BONUS;
4405   multibuf[1]=pnum;
4406
4407   multi_send_data (multibuf,2,1); 
4408   multi_do_capture_bonus (multibuf);
4409 }
4410 void multi_send_orb_bonus (char pnum)
4411 {
4412   Assert (Game_mode & GM_HOARD);
4413   
4414   multibuf[0]=MULTI_ORB_BONUS;
4415   multibuf[1]=pnum;
4416   multibuf[2]=Players[Player_num].secondary_ammo[PROXIMITY_INDEX];
4417
4418   multi_send_data (multibuf,3,1); 
4419   multi_do_orb_bonus (multibuf);
4420 }
4421 void multi_do_capture_bonus(char *buf)
4422 {
4423         // Figure out the results of a network kills and add it to the
4424         // appropriate player's tally.
4425
4426    char pnum=buf[1];
4427    int TheGoal;
4428
4429         kmatrix_kills_changed = 1;
4430    
4431    if (pnum==Player_num)
4432                 HUD_init_message("You have Scored!");
4433         else
4434                 HUD_init_message("%s has Scored!",Players[(int)pnum].callsign);
4435
4436         if (pnum==Player_num)
4437                 digi_play_sample (SOUND_HUD_YOU_GOT_GOAL,F1_0*2);
4438         else if (get_team(pnum)==TEAM_RED)
4439                 digi_play_sample (SOUND_HUD_RED_GOT_GOAL,F1_0*2);
4440         else
4441                 digi_play_sample (SOUND_HUD_BLUE_GOT_GOAL,F1_0*2);
4442
4443         Players[(int)pnum].flags &= ~(PLAYER_FLAGS_FLAG);  // Clear capture flag
4444
4445         team_kills[get_team(pnum)] += 5;
4446         Players[(int)pnum].net_kills_total += 5;
4447         Players[(int)pnum].KillGoalCount+=5;
4448
4449   if (Netgame.KillGoal>0)
4450         {
4451     TheGoal=Netgame.KillGoal*5;
4452
4453          if (Players[(int)pnum].KillGoalCount>=TheGoal)
4454           {
4455            if (pnum==Player_num)
4456             {
4457              HUD_init_message("You reached the kill goal!");
4458              Players[Player_num].shields=i2f(200);
4459             }  
4460            else
4461             HUD_init_message ("%s has reached the kill goal!",Players[(int)pnum].callsign);
4462
4463            HUD_init_message ("The control center has been destroyed!");
4464       net_destroy_controlcen (obj_find_first_of_type (OBJ_CNTRLCEN));
4465           }
4466         }
4467
4468         multi_sort_kill_list();
4469         multi_show_player_list();
4470 }
4471
4472 int GetOrbBonus (char num)
4473  {
4474   int bonus;
4475
4476   bonus=num*(num+1)/2;
4477   return (bonus);
4478  }
4479
4480 void multi_do_orb_bonus(char *buf)
4481 {
4482         // Figure out the results of a network kills and add it to the
4483         // appropriate player's tally.
4484
4485    char pnum=buf[1];
4486    int TheGoal;
4487         int bonus=GetOrbBonus (buf[2]);
4488
4489         kmatrix_kills_changed = 1;
4490    
4491    if (pnum==Player_num)
4492                 HUD_init_message("You have scored %d points!",bonus);
4493         else
4494                 HUD_init_message("%s has scored with %d orbs!",Players[(int)pnum].callsign,buf[2]);
4495
4496         if (pnum==Player_num)
4497                 digi_start_sound_queued (SOUND_HUD_YOU_GOT_GOAL,F1_0*2);
4498         else if (Game_mode & GM_TEAM)
4499          {
4500           if (get_team(pnum)==TEAM_RED)
4501                 digi_play_sample (SOUND_HUD_RED_GOT_GOAL,F1_0*2);
4502           else
4503                 digi_play_sample (SOUND_HUD_BLUE_GOT_GOAL,F1_0*2);
4504          }
4505         else
4506                 digi_play_sample (SOUND_OPPONENT_HAS_SCORED,F1_0*2);
4507
4508    if (bonus>PhallicLimit)
4509         {
4510           if (pnum==Player_num)
4511                 HUD_init_message ("You have the record with %d points!",bonus);
4512           else
4513                 HUD_init_message ("%s has the record with %d points!",Players[(int)pnum].callsign,bonus);
4514      digi_play_sample (SOUND_BUDDY_MET_GOAL,F1_0*2);
4515           PhallicMan=pnum;
4516           PhallicLimit=bonus;
4517    }
4518
4519         Players[(int)pnum].flags &= ~(PLAYER_FLAGS_FLAG);  // Clear orb flag
4520         
4521         team_kills[get_team(pnum)] += bonus;
4522         Players[(int)pnum].net_kills_total += bonus;
4523         Players[(int)pnum].KillGoalCount+=bonus;
4524
4525         team_kills[get_team(pnum)]%=1000;
4526         Players[(int)pnum].net_kills_total%=1000;
4527         Players[(int)pnum].KillGoalCount%=1000;
4528
4529   if (Netgame.KillGoal>0)
4530         {
4531     TheGoal=Netgame.KillGoal*5;
4532
4533          if (Players[(int)pnum].KillGoalCount>=TheGoal)
4534           {
4535            if (pnum==Player_num)
4536             {
4537              HUD_init_message("You reached the kill goal!");
4538              Players[Player_num].shields=i2f(200);
4539             }  
4540            else
4541             HUD_init_message ("%s has reached the kill goal!",Players[(int)pnum].callsign);
4542
4543            HUD_init_message ("The control center has been destroyed!");
4544       net_destroy_controlcen (obj_find_first_of_type (OBJ_CNTRLCEN));
4545           }
4546         }
4547         multi_sort_kill_list();
4548         multi_show_player_list();
4549 }
4550
4551 void multi_send_got_flag (char pnum)
4552 {
4553   multibuf[0]=MULTI_GOT_FLAG;
4554   multibuf[1]=pnum;
4555   
4556   digi_start_sound_queued (SOUND_HUD_YOU_GOT_FLAG,F1_0*2);
4557
4558   multi_send_data (multibuf,2,1);
4559   multi_send_flags (Player_num);
4560 }
4561
4562 int SoundHacked=0;
4563 digi_sound ReversedSound;
4564
4565 void multi_send_got_orb (char pnum)
4566 {
4567   multibuf[0]=MULTI_GOT_ORB;
4568   multibuf[1]=pnum;
4569   
4570   digi_play_sample (SOUND_YOU_GOT_ORB,F1_0*2);
4571
4572   multi_send_data (multibuf,2,1);
4573   multi_send_flags (Player_num);
4574 }
4575
4576 void multi_do_got_flag (char *buf)
4577 {
4578         char pnum=buf[1];
4579
4580    if (pnum==Player_num)
4581                 digi_start_sound_queued (SOUND_HUD_YOU_GOT_FLAG,F1_0*2);
4582         else if (get_team(pnum)==TEAM_RED)
4583                 digi_start_sound_queued (SOUND_HUD_RED_GOT_FLAG,F1_0*2);
4584         else 
4585                 digi_start_sound_queued (SOUND_HUD_BLUE_GOT_FLAG,F1_0*2);
4586    Players[(int)pnum].flags|=PLAYER_FLAGS_FLAG;
4587         HUD_init_message ("%s picked up a flag!",Players[(int)pnum].callsign);
4588 }
4589 void multi_do_got_orb (char *buf)
4590 {
4591         char pnum=buf[1];
4592
4593    Assert (Game_mode & GM_HOARD);
4594
4595    if (Game_mode & GM_TEAM)
4596          {  
4597           if (get_team(pnum)==get_team(Player_num))
4598                 digi_play_sample (SOUND_FRIEND_GOT_ORB,F1_0*2);
4599           else 
4600                 digi_play_sample (SOUND_OPPONENT_GOT_ORB,F1_0*2);
4601     }
4602    else 
4603          digi_play_sample (SOUND_OPPONENT_GOT_ORB,F1_0*2);
4604
4605    Players[(int)pnum].flags|=PLAYER_FLAGS_FLAG;
4606         HUD_init_message ("%s picked up an orb!",Players[(int)pnum].callsign);
4607 }
4608
4609
4610 void DropOrb ()
4611 {
4612         int objnum,seed;
4613
4614         if (!(Game_mode & GM_HOARD))
4615          Int3(); // How did we get here? Get Leighton!
4616
4617         if (!Players[Player_num].secondary_ammo[PROXIMITY_INDEX])
4618         {
4619         HUD_init_message("No orbs to drop!");
4620                 return;
4621         }
4622
4623         seed = d_rand();
4624
4625    objnum = spit_powerup(ConsoleObject,POW_HOARD_ORB,seed);
4626          
4627    if (objnum<0)
4628                 return;
4629
4630         HUD_init_message("Orb dropped!");
4631         digi_play_sample (SOUND_DROP_WEAPON,F1_0);
4632
4633         if ((Game_mode & GM_HOARD) && objnum>-1)
4634                 multi_send_drop_flag(objnum,seed); 
4635         
4636         Players[Player_num].secondary_ammo[PROXIMITY_INDEX]--;
4637
4638    // If empty, tell everyone to stop drawing the box around me
4639         if (Players[Player_num].secondary_ammo[PROXIMITY_INDEX]==0)
4640          multi_send_flags (Player_num);
4641 }
4642
4643 void DropFlag ()
4644 {
4645         int objnum,seed;
4646
4647         if (!(Game_mode & GM_CAPTURE) && !(Game_mode & GM_HOARD))
4648                 return;
4649         if (Game_mode & GM_HOARD)
4650         {
4651                 DropOrb();
4652                 return;
4653    }    
4654
4655         if (!(Players[Player_num].flags & PLAYER_FLAGS_FLAG))
4656         {
4657         HUD_init_message("No flag to drop!");
4658                 return;
4659         }
4660
4661
4662         HUD_init_message("Flag dropped!");
4663         digi_play_sample (SOUND_DROP_WEAPON,F1_0);
4664
4665         seed = d_rand();
4666
4667    if (get_team (Player_num)==TEAM_RED)
4668          objnum = spit_powerup(ConsoleObject,POW_FLAG_BLUE,seed);
4669         else
4670          objnum = spit_powerup(ConsoleObject,POW_FLAG_RED,seed);
4671          
4672    if (objnum<0)
4673                 return;
4674
4675         if ((Game_mode & GM_CAPTURE) && objnum>-1)
4676                 multi_send_drop_flag(objnum,seed);
4677
4678         Players[Player_num].flags &=~(PLAYER_FLAGS_FLAG);
4679 }
4680
4681
4682 void multi_send_drop_flag (int objnum,int seed)
4683 {
4684         object *objp;
4685         int count=0;
4686
4687         objp = &Objects[objnum];
4688
4689         multibuf[count++]=(char)MULTI_DROP_FLAG;
4690         multibuf[count++]=(char)objp->id;
4691         
4692         *(short *) (multibuf+count)=INTEL_SHORT(Player_num); count += 2;
4693         *(short *) (multibuf+count)=INTEL_SHORT(objnum); count += 2;
4694         *(short *) (multibuf+count)=INTEL_SHORT(objp->ctype.powerup_info.count); count += 2;
4695         *(int *) (multibuf+count)=INTEL_INT(seed);
4696    
4697         map_objnum_local_to_local(objnum);
4698   
4699    if (!(Game_mode & GM_HOARD))
4700                 if (Game_mode & GM_NETWORK)
4701                         PowerupsInMine[objp->id]++;
4702
4703   multi_send_data(multibuf, 12, 2);
4704 }
4705
4706 void multi_do_drop_flag (char *buf)
4707 {
4708         int pnum,ammo,objnum,remote_objnum,seed;
4709         object *objp;
4710         int powerup_id;
4711
4712         powerup_id=buf[1];
4713         pnum=INTEL_SHORT( *(short *)(buf+2) );
4714         remote_objnum=INTEL_SHORT( *(short *)(buf+4) );
4715         ammo=INTEL_SHORT( *(short *)(buf+6) );
4716         seed=INTEL_INT( *(int *)(buf+8) );
4717
4718         objp = &Objects[Players[pnum].objnum];
4719
4720         objnum = spit_powerup(objp, powerup_id, seed);
4721
4722         map_objnum_local_to_remote(objnum, remote_objnum, pnum);                
4723
4724         if (objnum!=-1)
4725                 Objects[objnum].ctype.powerup_info.count = ammo;
4726    
4727         if (!(Game_mode & GM_HOARD))
4728         {
4729                 if (Game_mode & GM_NETWORK)
4730                         PowerupsInMine[powerup_id]++;
4731            Players[pnum].flags &= ~(PLAYER_FLAGS_FLAG);
4732         }
4733         mprintf ((0,"Dropped flag %d!\n"));
4734   
4735 }
4736
4737 void multi_bad_restore ()
4738 {
4739         Function_mode = FMODE_MENU;
4740         nm_messagebox(NULL, 1, TXT_OK, 
4741 "A multi-save game was restored\nthat you are missing or does not\nmatch that of the others.\nYou must rejoin if you wish to\ncontinue.");
4742         Function_mode = FMODE_GAME;
4743         multi_quit_game = 1;
4744         multi_leave_menu = 1;
4745         multi_reset_stuff();
4746 }
4747
4748 extern int robot_controlled[MAX_ROBOTS_CONTROLLED];
4749 extern int robot_agitation[MAX_ROBOTS_CONTROLLED];
4750 extern fix robot_controlled_time[MAX_ROBOTS_CONTROLLED];
4751 extern fix robot_last_send_time[MAX_ROBOTS_CONTROLLED];
4752 extern fix robot_last_message_time[MAX_ROBOTS_CONTROLLED];
4753 extern int robot_send_pending[MAX_ROBOTS_CONTROLLED];
4754 extern int robot_fired[MAX_ROBOTS_CONTROLLED];
4755 extern byte robot_fire_buf[MAX_ROBOTS_CONTROLLED][18+3];
4756
4757
4758 void multi_send_robot_controls (char pnum)
4759  {
4760   int count=2;
4761   
4762   mprintf ((0,"Sending ROBOT_CONTROLS!!!\n"));
4763  
4764   multibuf[0]=MULTI_ROBOT_CONTROLS;
4765   multibuf[1]=pnum;
4766   memcpy (&(multibuf[count]),&robot_controlled,MAX_ROBOTS_CONTROLLED*4);
4767   count+=(MAX_ROBOTS_CONTROLLED*4);
4768   memcpy (&(multibuf[count]),&robot_agitation,MAX_ROBOTS_CONTROLLED*4);
4769   count+=(MAX_ROBOTS_CONTROLLED*4);
4770   memcpy (&(multibuf[count]),&robot_controlled_time,MAX_ROBOTS_CONTROLLED*4);
4771   count+=(MAX_ROBOTS_CONTROLLED*4);
4772   memcpy (&(multibuf[count]),&robot_last_send_time,MAX_ROBOTS_CONTROLLED*4);
4773   count+=(MAX_ROBOTS_CONTROLLED*4);
4774   memcpy (&(multibuf[count]),&robot_last_message_time,MAX_ROBOTS_CONTROLLED*4);
4775   count+=(MAX_ROBOTS_CONTROLLED*4);
4776   memcpy (&(multibuf[count]),&robot_send_pending,MAX_ROBOTS_CONTROLLED*4);
4777   count+=(MAX_ROBOTS_CONTROLLED*4);
4778   memcpy (&(multibuf[count]),&robot_fired,MAX_ROBOTS_CONTROLLED*4);
4779   count+=(MAX_ROBOTS_CONTROLLED*4);
4780
4781   network_send_naked_packet (multibuf,142,pnum);
4782  }
4783 void multi_do_robot_controls(char *buf)
4784  {
4785   int count=2;
4786
4787   mprintf ((0,"Recieved ROBOT_CONTROLS!!!\n"));
4788  
4789   if (buf[1]!=Player_num)
4790         {
4791     Int3(); // Get Jason!  Recieved a coop_sync that wasn't ours!
4792     return;
4793    }
4794
4795   memcpy (&robot_controlled,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
4796   count+=(MAX_ROBOTS_CONTROLLED*4);
4797   memcpy (&robot_agitation,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
4798   count+=(MAX_ROBOTS_CONTROLLED*4);
4799   memcpy (&robot_controlled_time,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
4800   count+=(MAX_ROBOTS_CONTROLLED*4);
4801   memcpy (&robot_last_send_time,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
4802   count+=(MAX_ROBOTS_CONTROLLED*4);
4803   memcpy (&robot_last_message_time,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
4804   count+=(MAX_ROBOTS_CONTROLLED*4);
4805   memcpy (&robot_send_pending,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
4806   count+=(MAX_ROBOTS_CONTROLLED*4);
4807   memcpy (&robot_fired,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
4808   count+=(MAX_ROBOTS_CONTROLLED*4);
4809  }
4810
4811 #define POWERUPADJUSTS 5
4812 int PowerupAdjustMapping[]={11,19,39,41,44};
4813
4814 int multi_powerup_is_4pack (int id)
4815  {
4816   int i;
4817  
4818   for (i=0;i<POWERUPADJUSTS;i++)
4819    if (id==PowerupAdjustMapping[i])
4820     return (1);
4821   return (0);
4822  } 
4823
4824 int multi_powerup_is_allowed(int id)
4825  {
4826         if (id == POW_INVULNERABILITY && !Netgame.DoInvulnerability)
4827          return (0);
4828         if (id == POW_CLOAK && !Netgame.DoCloak) 
4829          return (0);
4830         if (id == POW_AFTERBURNER && !Netgame.DoAfterburner)
4831          return (0);
4832         if (id == POW_FUSION_WEAPON &&  !Netgame.DoFusions)
4833          return (0);
4834         if (id == POW_PHOENIX_WEAPON && !Netgame.DoPhoenix)
4835          return (0);
4836         if (id == POW_HELIX_WEAPON && !Netgame.DoHelix)
4837          return (0);
4838         if (id == POW_MEGA_WEAPON && !Netgame.DoMegas)
4839          return (0);
4840         if (id == POW_SMARTBOMB_WEAPON && !Netgame.DoSmarts)
4841          return (0);
4842         if (id == POW_GAUSS_WEAPON && !Netgame.DoGauss)
4843          return (0);
4844         if (id == POW_VULCAN_WEAPON && !Netgame.DoVulcan)
4845          return (0);
4846         if (id == POW_PLASMA_WEAPON && !Netgame.DoPlasma)
4847          return (0);
4848         if (id == POW_OMEGA_WEAPON && !Netgame.DoOmega)
4849          return (0);
4850         if (id == POW_SUPER_LASER && !Netgame.DoSuperLaser)
4851          return (0);
4852         if (id == POW_PROXIMITY_WEAPON && !Netgame.DoProximity)
4853          return (0);
4854         if (id==POW_VULCAN_AMMO && (!Netgame.DoVulcan && !Netgame.DoGauss))
4855          return (0);
4856         if (id == POW_SPREADFIRE_WEAPON && !Netgame.DoSpread)
4857          return (0);
4858         if (id == POW_SMART_MINE && !Netgame.DoSmartMine)
4859          return (0);
4860         if (id == POW_SMISSILE1_1 &&  !Netgame.DoFlash)
4861          return (0);
4862         if (id == POW_SMISSILE1_4 &&  !Netgame.DoFlash)
4863          return (0);
4864         if (id == POW_GUIDED_MISSILE_1 &&  !Netgame.DoGuided)
4865          return (0);
4866         if (id == POW_GUIDED_MISSILE_4 &&  !Netgame.DoGuided)
4867          return (0);
4868         if (id == POW_EARTHSHAKER_MISSILE &&  !Netgame.DoEarthShaker)
4869          return (0);
4870         if (id == POW_MERCURY_MISSILE_1 &&  !Netgame.DoMercury)
4871          return (0);
4872         if (id == POW_MERCURY_MISSILE_4 &&  !Netgame.DoMercury)
4873          return (0);
4874         if (id == POW_CONVERTER &&  !Netgame.DoConverter)
4875          return (0);
4876         if (id == POW_AMMO_RACK &&  !Netgame.DoAmmoRack)
4877          return (0);
4878         if (id == POW_HEADLIGHT &&  !Netgame.DoHeadlight)
4879          return (0);
4880         if (id == POW_LASER &&  !Netgame.DoLaserUpgrade)
4881          return (0);
4882         if (id == POW_HOMING_AMMO_1 &&  !Netgame.DoHoming)
4883          return (0);
4884         if (id == POW_HOMING_AMMO_4 &&  !Netgame.DoHoming)
4885          return (0);
4886         if (id == POW_QUAD_FIRE &&  !Netgame.DoQuadLasers)
4887          return (0);
4888    if (id == POW_FLAG_BLUE && !(Game_mode & GM_CAPTURE))
4889          return (0);
4890    if (id == POW_FLAG_RED && !(Game_mode & GM_CAPTURE))
4891          return (0);
4892
4893   return (1);
4894  }
4895
4896 void multi_send_finish_game ()
4897  {
4898   multibuf[0]=MULTI_FINISH_GAME;
4899   multibuf[1]=Player_num;
4900
4901   multi_send_data (multibuf,2,1);
4902  }
4903
4904
4905 extern void do_final_boss_hacks();
4906 void multi_do_finish_game (char *buf)
4907  {
4908   if (buf[0]!=MULTI_FINISH_GAME)
4909         return;
4910  
4911   if (Current_level_num!=Last_level)
4912         return;
4913
4914   do_final_boss_hacks();
4915  }
4916
4917 void multi_send_trigger_specific (char pnum,char trig)
4918  {
4919         multibuf[0] = MULTI_START_TRIGGER;
4920    multibuf[1] = trig;
4921    
4922         network_send_naked_packet(multibuf, 2, pnum);
4923  }
4924 void multi_do_start_trigger (char *buf)
4925  {  
4926   Triggers[(int)buf[1]].flags |=TF_DISABLED;
4927  }
4928
4929 extern int GetMyNetRanking();
4930 extern char *RankStrings[];
4931
4932 void multi_add_lifetime_kills ()
4933  {  
4934   // This function adds a kill to lifetime stats of this player, and possibly
4935   // gives a promotion.  If so, it will tell everyone else
4936         
4937   int oldrank;
4938
4939   if (!Game_mode & GM_NETWORK)
4940         return;
4941  
4942   oldrank=GetMyNetRanking();
4943   
4944   Netlife_kills++;
4945
4946   if (oldrank!=GetMyNetRanking())
4947    {
4948          multi_send_ranking();
4949     if (!args_find("-norankings"))
4950           {
4951                  HUD_init_message ("You have been promoted to %s!",RankStrings[GetMyNetRanking()]);
4952          digi_play_sample (SOUND_BUDDY_MET_GOAL,F1_0*2);
4953             NetPlayers.players[Player_num].rank=GetMyNetRanking();
4954           }
4955         }
4956   write_player_file();  
4957  } 
4958
4959 void multi_add_lifetime_killed ()
4960  {  
4961   // This function adds a "killed" to lifetime stats of this player, and possibly
4962   // gives a demotion.  If so, it will tell everyone else
4963
4964   int oldrank;
4965
4966   if (!Game_mode & GM_NETWORK)
4967         return;
4968  
4969   oldrank=GetMyNetRanking();
4970   
4971   Netlife_killed++;
4972
4973   if (oldrank!=GetMyNetRanking())
4974    {
4975           multi_send_ranking();
4976           NetPlayers.players[Player_num].rank=GetMyNetRanking();
4977           
4978      if (!args_find("-norankings"))     
4979                   HUD_init_message ("You have been demoted to %s!",RankStrings[GetMyNetRanking()]);
4980   
4981         }       
4982   write_player_file();  
4983
4984  } 
4985    
4986 void multi_send_ranking ()
4987  {
4988   multibuf[0]=(char)MULTI_RANK;
4989   multibuf[1]=(char)Player_num;
4990   multibuf[2]=(char)GetMyNetRanking();
4991   
4992   multi_send_data (multibuf,3,1);
4993  }
4994
4995 void multi_do_ranking (char *buf)
4996  {
4997   char rankstr[20];
4998   char pnum=buf[1];
4999   char rank=buf[2];
5000
5001   if (NetPlayers.players[(int)pnum].rank<rank)
5002          strcpy (rankstr,"promoted");
5003   else if (NetPlayers.players[(int)pnum].rank>rank)
5004          strcpy (rankstr,"demoted");
5005   else
5006          return;
5007
5008   NetPlayers.players[(int)pnum].rank=rank;
5009
5010   if (!args_find("-norankings"))
5011           HUD_init_message ("%s has been %s to %s!",Players[(int)pnum].callsign,rankstr,RankStrings[(int)rank]);
5012  }
5013 void multi_send_modem_ping ()
5014 {
5015   multibuf[0]=MULTI_MODEM_PING;
5016   multi_send_data (multibuf,1,1);
5017 }
5018 void multi_send_modem_ping_return ()
5019  {
5020   multibuf[0]=MULTI_MODEM_PING_RETURN;
5021   multi_send_data (multibuf,1,1);
5022  }
5023
5024 void  multi_do_modem_ping_return ()
5025  {
5026   if (PingLaunchTime==0)
5027         {
5028          mprintf ((0,"Got invalid PING RETURN from opponent!\n"));
5029     return;
5030    }
5031   
5032   PingReturnTime=timer_get_fixed_seconds();
5033
5034   HUD_init_message ("Ping time for opponent is %d ms!",f2i(fixmul(PingReturnTime-PingLaunchTime,i2f(1000))));
5035   PingLaunchTime=0;
5036  }
5037
5038
5039 void multi_quick_sound_hack (int num) 
5040  {
5041    int length,i;
5042         num = digi_xlat_sound(num);
5043    length=GameSounds[num].length;
5044    ReversedSound.data=(ubyte *)d_malloc (length);
5045    ReversedSound.length=length;
5046       
5047    for (i=0;i<length;i++)
5048          ReversedSound.data[i]=GameSounds[num].data[length-i-1];
5049
5050    SoundHacked=1;
5051  }
5052
5053 void multi_send_play_by_play (int num,int spnum,int dpnum)
5054  {
5055   if (!(Game_mode & GM_HOARD))
5056         return;
5057  
5058   return;
5059   multibuf[0]=MULTI_PLAY_BY_PLAY;
5060   multibuf[1]=(char)num; 
5061   multibuf[2]=(char)spnum;
5062   multibuf[3]=(char)dpnum;
5063   multi_send_data (multibuf,4,1);
5064   multi_do_play_by_play (multibuf);
5065  }
5066 void multi_do_play_by_play (char *buf)
5067 {
5068         int whichplay=buf[1];
5069         int spnum=buf[2];
5070         int dpnum=buf[3];
5071
5072         if (!(Game_mode & GM_HOARD))
5073         {
5074            Int3(); // Get Leighton, something bad has happened.
5075                 return;
5076    }
5077
5078         switch (whichplay)
5079         {
5080                 case 0: // Smacked!
5081        HUD_init_message ("Ouch! %s has been smacked by %s!",Players[dpnum].callsign,Players[spnum].callsign);
5082                  break;
5083                 case 1: // Spanked!
5084        HUD_init_message ("Haha! %s has been spanked by %s!",Players[dpnum].callsign,Players[spnum].callsign);
5085                  break;
5086                 default:
5087                         Int3(); 
5088         }
5089 }
5090   
5091 ///
5092 /// CODE TO LOAD HOARD DATA
5093 ///
5094
5095
5096 void init_bitmap(grs_bitmap *bm,int w,int h,int flags,ubyte *data)
5097 {
5098         bm->bm_x = bm->bm_y = 0;
5099         bm->bm_w = bm->bm_rowsize = w;
5100         bm->bm_h = h;
5101         bm->bm_type = BM_LINEAR;
5102         bm->bm_flags = flags;
5103         bm->bm_data = data;
5104         bm->bm_handle = 0;
5105         bm->avg_color = 0;
5106 }
5107
5108 grs_bitmap Orb_icons[2];
5109
5110 int Hoard_goal_eclip;
5111
5112 void init_hoard_data()
5113 {
5114         static int first_time=1;
5115         static int orb_vclip;
5116         int n_orb_frames,n_goal_frames;
5117         int orb_w,orb_h;
5118         int icon_w,icon_h;
5119         ubyte palette[256*3];
5120         CFILE *ifile;
5121         int i,save_pos;
5122         extern int Num_bitmap_files,Num_effects,Num_sound_files;
5123
5124         ifile = cfopen("hoard.ham","rb");
5125         if (ifile == NULL)
5126                 Error("can't open <hoard.dat>");
5127
5128         n_orb_frames = cfile_read_short(ifile);
5129         orb_w = cfile_read_short(ifile);
5130         orb_h = cfile_read_short(ifile);
5131         save_pos = cftell(ifile);
5132         cfseek(ifile,sizeof(palette)+n_orb_frames*orb_w*orb_h,SEEK_CUR);
5133         n_goal_frames = cfile_read_short(ifile);
5134         cfseek(ifile,save_pos,SEEK_SET);
5135
5136         if (first_time) {
5137                 ubyte *bitmap_data;
5138                 int bitmap_num=Num_bitmap_files;
5139
5140                 //Allocate memory for bitmaps
5141                 MALLOC( bitmap_data, ubyte, n_orb_frames*orb_w*orb_h + n_goal_frames*64*64 );
5142
5143                 //Create orb vclip
5144                 orb_vclip = Num_vclips++;
5145                 Assert(Num_vclips <= VCLIP_MAXNUM);
5146                 Vclip[orb_vclip].play_time = F1_0/2;
5147                 Vclip[orb_vclip].num_frames = n_orb_frames;
5148                 Vclip[orb_vclip].frame_time = Vclip[orb_vclip].play_time / Vclip[orb_vclip].num_frames;
5149                 Vclip[orb_vclip].flags = 0;
5150                 Vclip[orb_vclip].sound_num = -1;
5151                 Vclip[orb_vclip].light_value = F1_0;
5152                 for (i=0;i<n_orb_frames;i++) {
5153                         Vclip[orb_vclip].frames[i].index = bitmap_num;
5154                         init_bitmap(&GameBitmaps[bitmap_num],orb_w,orb_h,BM_FLAG_TRANSPARENT,bitmap_data);
5155                         bitmap_data += orb_w*orb_h;
5156                         bitmap_num++;
5157                         Assert(bitmap_num < MAX_BITMAP_FILES);
5158                 }
5159
5160                 //Create obj powerup
5161                 Powerup_info[POW_HOARD_ORB].vclip_num = orb_vclip;
5162                 Powerup_info[POW_HOARD_ORB].hit_sound = -1;     //Powerup_info[POW_SHIELD_BOOST].hit_sound;
5163                 Powerup_info[POW_HOARD_ORB].size = Powerup_info[POW_SHIELD_BOOST].size;
5164                 Powerup_info[POW_HOARD_ORB].light = Powerup_info[POW_SHIELD_BOOST].light;
5165
5166                 //Create orb goal wall effect
5167                 Hoard_goal_eclip = Num_effects++;
5168                 Assert(Num_effects < MAX_EFFECTS);
5169                 Effects[Hoard_goal_eclip] = Effects[94];                //copy from blue goal
5170                 Effects[Hoard_goal_eclip].changing_wall_texture = NumTextures;
5171                 Effects[Hoard_goal_eclip].vc.num_frames=n_goal_frames;
5172         
5173                 TmapInfo[NumTextures] = TmapInfo[find_goal_texture(TMI_GOAL_BLUE)];
5174                 TmapInfo[NumTextures].eclip_num = Hoard_goal_eclip;
5175                 TmapInfo[NumTextures].flags = TMI_GOAL_HOARD;
5176                 NumTextures++;
5177                 Assert(NumTextures < MAX_TEXTURES);
5178                 for (i=0;i<n_goal_frames;i++) {
5179                         Effects[Hoard_goal_eclip].vc.frames[i].index = bitmap_num;
5180                         init_bitmap(&GameBitmaps[bitmap_num],64,64,0,bitmap_data);
5181                         bitmap_data += 64*64;
5182                         bitmap_num++;
5183                         Assert(bitmap_num < MAX_BITMAP_FILES);
5184                 }
5185
5186         }
5187
5188         //Load and remap bitmap data for orb
5189         cfread(palette,3,256,ifile);
5190         for (i=0;i<n_orb_frames;i++) {
5191                 grs_bitmap *bm = &GameBitmaps[Vclip[orb_vclip].frames[i].index];
5192                 cfread(bm->bm_data,1,orb_w*orb_h,ifile);
5193                 gr_remap_bitmap_good( bm, palette, 255, -1 );
5194         }
5195
5196         //Load and remap bitmap data for goal texture
5197         cfile_read_short(ifile);                //skip frame count
5198         cfread(palette,3,256,ifile);
5199         for (i=0;i<n_goal_frames;i++) {
5200                 grs_bitmap *bm = &GameBitmaps[Effects[Hoard_goal_eclip].vc.frames[i].index];
5201                 cfread(bm->bm_data,1,64*64,ifile);
5202                 gr_remap_bitmap_good( bm, palette, 255, -1 );
5203         }
5204
5205         //Load and remap bitmap data for HUD icons
5206         for (i=0;i<2;i++) {
5207                 icon_w = cfile_read_short(ifile);
5208                 icon_h = cfile_read_short(ifile);
5209                 if (first_time) {
5210                         ubyte *bitmap_data;
5211                         MALLOC( bitmap_data, ubyte, icon_w*icon_h );
5212                         init_bitmap(&Orb_icons[i],icon_w,icon_h,BM_FLAG_TRANSPARENT,bitmap_data);
5213                 }
5214                 cfread(palette,3,256,ifile);
5215                 cfread(Orb_icons[i].bm_data,1,icon_w*icon_h,ifile);
5216                 gr_remap_bitmap_good( &Orb_icons[i], palette, 255, -1 );
5217         }
5218
5219         if (first_time) {
5220
5221                 //Load sounds for orb game
5222
5223                 for (i=0;i<4;i++) {
5224                         int len;
5225
5226                         len = cfile_read_int(ifile);    //get 11k len
5227
5228                         if (digi_sample_rate == SAMPLE_RATE_22K) {
5229                                 cfseek(ifile,len,SEEK_CUR);             //skip over 11k sample
5230                                 len = cfile_read_int(ifile);            //get 22k len
5231                         }
5232
5233                         GameSounds[Num_sound_files+i].length = len;
5234                         GameSounds[Num_sound_files+i].data = d_malloc(len);
5235                         cfread(GameSounds[Num_sound_files+i].data,1,len,ifile);
5236
5237                         if (digi_sample_rate == SAMPLE_RATE_11K) {
5238                                 len = cfile_read_int(ifile);            //get 22k len
5239                                 cfseek(ifile,len,SEEK_CUR);             //skip over 22k sample
5240                         }
5241
5242                         Sounds[SOUND_YOU_GOT_ORB+i] = Num_sound_files+i;
5243                         AltSounds[SOUND_YOU_GOT_ORB+i] = Sounds[SOUND_YOU_GOT_ORB+i];
5244                 }
5245         }
5246
5247         cfclose(ifile);
5248
5249         first_time = 0;
5250 }
5251
5252 void
5253 multi_process_data(char *buf, int len)
5254 {
5255         // Take an entire message (that has already been checked for validity,
5256         // if necessary) and act on it.  
5257
5258         int type;
5259         len = len;
5260
5261         type = buf[0];
5262         
5263         if (type > MULTI_MAX_TYPE)
5264         {
5265                 mprintf((1, "multi_process_data: invalid type %d.\n", type));
5266                 Int3();
5267                 return;
5268         }
5269
5270
5271    #ifdef NETPROFILING
5272            TTRecv[type]++;  
5273            fprintf (RecieveLogFile,"Packet type: %d Len:%d TT=%d\n",type,len,TTRecv[type]);
5274            fflush (RecieveLogFile);
5275         #endif
5276   
5277         switch(type) 
5278         {
5279                 case MULTI_POSITION:
5280                         if (!Endlevel_sequence) multi_do_position(buf); break;
5281                 case MULTI_REAPPEAR:
5282                         if (!Endlevel_sequence) multi_do_reappear(buf); break;
5283                 case MULTI_FIRE:
5284                         if (!Endlevel_sequence) multi_do_fire(buf); break;
5285                 case MULTI_KILL:
5286                         multi_do_kill(buf); break;
5287                 case MULTI_REMOVE_OBJECT:
5288                         if (!Endlevel_sequence) multi_do_remobj(buf); break;
5289                 case MULTI_PLAYER_DROP:
5290                 case MULTI_PLAYER_EXPLODE:
5291                         if (!Endlevel_sequence) multi_do_player_explode(buf); break;
5292                 case MULTI_MESSAGE:
5293                         if (!Endlevel_sequence) multi_do_message(buf); break;
5294                 case MULTI_QUIT:
5295                         if (!Endlevel_sequence) multi_do_quit(buf); break;
5296                 case MULTI_BEGIN_SYNC:
5297                    break;
5298                 case MULTI_CONTROLCEN:
5299                         if (!Endlevel_sequence) multi_do_controlcen_destroy(buf); break;
5300                 case MULTI_POWERUP_UPDATE:
5301                         if (!Endlevel_sequence) multi_do_powerup_update(buf); break;
5302                 case MULTI_SOUND_FUNCTION:
5303                         multi_do_sound_function(buf); break;
5304       case MULTI_MARKER:
5305          if (!Endlevel_sequence) multi_do_drop_marker (buf); break;
5306       case MULTI_DROP_WEAPON:
5307          if (!Endlevel_sequence) multi_do_drop_weapon(buf); break;
5308       case MULTI_DROP_FLAG:
5309          if (!Endlevel_sequence) multi_do_drop_flag(buf); break;
5310       case MULTI_GUIDED:
5311          if (!Endlevel_sequence) multi_do_guided (buf); break;
5312       case MULTI_STOLEN_ITEMS:
5313          if (!Endlevel_sequence) multi_do_stolen_items(buf); break;
5314       case MULTI_WALL_STATUS:
5315          if (!Endlevel_sequence) multi_do_wall_status(buf); break;
5316       case MULTI_HEARTBEAT:
5317          if (!Endlevel_sequence) multi_do_heartbeat (buf); break;
5318       case MULTI_SEISMIC:
5319                 if (!Endlevel_sequence) multi_do_seismic (buf); break;
5320            case MULTI_LIGHT:
5321                 if (!Endlevel_sequence) multi_do_light (buf); break;
5322       case MULTI_KILLGOALS:
5323                 
5324                  if (!Endlevel_sequence) multi_do_kill_goal_counts (buf); break;
5325                 case MULTI_ENDLEVEL_START:
5326                         if (!Endlevel_sequence) multi_do_escape(buf); break;
5327                 case MULTI_END_SYNC:
5328                         break;
5329                 case MULTI_CLOAK:
5330                         if (!Endlevel_sequence) multi_do_cloak(buf); break;
5331                 case MULTI_DECLOAK:
5332                         if (!Endlevel_sequence) multi_do_decloak(buf); break;
5333                 case MULTI_DOOR_OPEN:
5334                         if (!Endlevel_sequence) multi_do_door_open(buf); break;
5335                 case MULTI_CREATE_EXPLOSION:
5336                         if (!Endlevel_sequence) multi_do_create_explosion(buf); break;
5337                 case MULTI_CONTROLCEN_FIRE:
5338                         if (!Endlevel_sequence) multi_do_controlcen_fire(buf); break;
5339                 case MULTI_CREATE_POWERUP:
5340                         if (!Endlevel_sequence) multi_do_create_powerup(buf); break;
5341                 case MULTI_PLAY_SOUND:
5342                         if (!Endlevel_sequence) multi_do_play_sound(buf); break;
5343                 case MULTI_CAPTURE_BONUS:
5344                         if (!Endlevel_sequence) multi_do_capture_bonus(buf); break;
5345                 case MULTI_ORB_BONUS:
5346                         if (!Endlevel_sequence) multi_do_orb_bonus(buf); break;
5347                 case MULTI_GOT_FLAG:
5348                         if (!Endlevel_sequence) multi_do_got_flag(buf); break;
5349                 case MULTI_GOT_ORB:
5350                         if (!Endlevel_sequence) multi_do_got_orb(buf); break;
5351                 case MULTI_PLAY_BY_PLAY:
5352                         if (!Endlevel_sequence) multi_do_play_by_play(buf); break;
5353                 case MULTI_RANK:
5354                         if (!Endlevel_sequence) multi_do_ranking (buf); break;
5355                 case MULTI_MODEM_PING:
5356                         if (!Endlevel_sequence) multi_send_modem_ping_return(); break;
5357                 case MULTI_MODEM_PING_RETURN:
5358                         if (!Endlevel_sequence) multi_do_modem_ping_return(); break;
5359 #ifndef SHAREWARE
5360                 case MULTI_FINISH_GAME:
5361                         multi_do_finish_game(buf);      break;  // do this one regardless of endsequence        
5362                 case MULTI_ROBOT_CONTROLS:
5363                         if (!Endlevel_sequence) multi_do_robot_controls(buf); break;
5364                 case MULTI_ROBOT_CLAIM:
5365                         if (!Endlevel_sequence) multi_do_claim_robot(buf); break;
5366                 case MULTI_ROBOT_POSITION:
5367                         if (!Endlevel_sequence) multi_do_robot_position(buf); break;
5368                 case MULTI_ROBOT_EXPLODE:
5369                         if (!Endlevel_sequence) multi_do_robot_explode(buf); break;
5370                 case MULTI_ROBOT_RELEASE:
5371                         if (!Endlevel_sequence) multi_do_release_robot(buf); break;
5372                 case MULTI_ROBOT_FIRE:
5373                         if (!Endlevel_sequence) multi_do_robot_fire(buf); break;
5374 #endif
5375                 case MULTI_SCORE:
5376                         if (!Endlevel_sequence) multi_do_score(buf); break;
5377                 case MULTI_CREATE_ROBOT:
5378                         if (!Endlevel_sequence) multi_do_create_robot(buf); break;
5379                 case MULTI_TRIGGER:
5380                         if (!Endlevel_sequence) multi_do_trigger(buf); break;
5381                 case MULTI_START_TRIGGER:
5382                         if (!Endlevel_sequence) multi_do_start_trigger(buf); break;
5383                 case MULTI_FLAGS:
5384                         if (!Endlevel_sequence) multi_do_flags(buf); break;
5385                 case MULTI_DROP_BLOB:
5386                         if (!Endlevel_sequence) multi_do_drop_blob(buf); break;
5387            case MULTI_ACTIVE_DOOR:
5388                         if (!Endlevel_sequence) multi_do_active_door(buf); break;
5389                 case MULTI_BOSS_ACTIONS:
5390                         if (!Endlevel_sequence) multi_do_boss_actions(buf); break;
5391                 case MULTI_CREATE_ROBOT_POWERUPS:
5392                         if (!Endlevel_sequence) multi_do_create_robot_powerups(buf); break;
5393                 case MULTI_HOSTAGE_DOOR:
5394                         if (!Endlevel_sequence) multi_do_hostage_door_status(buf); break;
5395                 case MULTI_SAVE_GAME:
5396                         if (!Endlevel_sequence) multi_do_save_game(buf); break;
5397                 case MULTI_RESTORE_GAME:
5398                         if (!Endlevel_sequence) multi_do_restore_game(buf); break;
5399                 case MULTI_REQ_PLAYER:
5400                         if (!Endlevel_sequence) multi_do_req_player(buf); break;
5401                 case MULTI_SEND_PLAYER:
5402                         if (!Endlevel_sequence) multi_do_send_player(buf); break;
5403
5404                 default:
5405                         mprintf((1, "Invalid type in multi_process_input().\n"));
5406                         Int3();
5407         }
5408 }
5409
5410
5411 #endif
5412