1 /* $Id: multi.c,v 1.9 2003/03/14 21:24:03 btb Exp $ */
2 /*
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
13 */
14 
15 /*
16  *
17  * Multiplayer code shared by serial and network play.
18  *
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include <conf.h>
23 #endif
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <time.h>
29 #include <ctype.h>
30 
31 #include "u_mem.h"
32 #include "strutil.h"
33 #include "game.h"
34 #include "modem.h"
35 #include "network.h"
36 #include "multi.h"
37 #include "object.h"
38 #include "laser.h"
39 #include "fuelcen.h"
40 #include "scores.h"
41 #include "gauges.h"
42 #include "collide.h"
43 #include "error.h"
44 #include "fireball.h"
45 #include "newmenu.h"
46 #include "mono.h"
47 #include "wall.h"
48 #include "cntrlcen.h"
49 #include "powerup.h"
50 #include "polyobj.h"
51 #include "bm.h"
52 #include "endlevel.h"
53 #include "key.h"
54 #include "playsave.h"
55 #include "timer.h"
56 #include "digi.h"
57 #include "sounds.h"
58 #include "kconfig.h"
59 #include "newdemo.h"
60 #include "text.h"
61 #include "kmatrix.h"
62 #include "multibot.h"
63 #include "gameseq.h"
64 #include "physics.h"
65 #include "config.h"
66 #include "state.h"
67 #include "ai.h"
68 #include "switch.h"
69 #include "textures.h"
70 #include "byteswap.h"
71 #include "sounds.h"
72 #include "args.h"
73 #include "cfile.h"
74 #include "effects.h"
75 
76 void multi_reset_player_object(object *objp);
77 void multi_reset_object_texture(object *objp);
78 void multi_add_lifetime_killed();
79 void multi_add_lifetime_kills();
80 void multi_send_play_by_play(int num,int spnum,int dpnum);
81 void multi_send_heartbeat();
82 void multi_send_modem_ping();
83 void multi_cap_objects();
84 void multi_adjust_remote_cap(int pnum);
85 void multi_save_game(ubyte slot, uint id, char *desc);
86 void multi_restore_game(ubyte slot, uint id);
87 void multi_set_robot_ai(void);
88 void multi_send_powerup_update();
89 void bash_to_shield(int i,char *s);
90 void init_hoard_data();
91 void multi_apply_goal_textures();
92 int  find_goal_texture(ubyte t);
93 void multi_bad_restore();
94 void multi_do_capture_bonus(char *buf);
95 void multi_do_orb_bonus(char *buf);
96 void multi_send_drop_flag(int objnum,int seed);
97 void multi_send_ranking();
98 void multi_do_play_by_play(char *buf);
99 
100 //
101 // Local macros and prototypes
102 //
103 
104 // LOCALIZE ME!!
105 
106 #define vm_angvec_zero(v) (v)->p=(v)->b=(v)->h=0
107 
108 void drop_player_eggs(object *player); // from collide.c
109 void GameLoop(int, int); // From game.c
110 
111 //
112 // Global variables
113 //
114 
115 extern vms_vector MarkerPoint[];
116 extern char MarkerMessage[16][40];
117 extern char MarkerOwner[16][40];
118 extern int MarkerObject[];
119 
120 int control_invul_time = 0;
121 int who_killed_controlcen = -1;  // -1 = noone
122 
123 //do we draw the kill list on the HUD?
124 int Show_kill_list = 1;
125 int Show_reticle_name = 1;
126 fix Show_kill_list_timer = 0;
127 
128 char Multi_is_guided=0;
129 char PKilledFlags[MAX_NUM_NET_PLAYERS];
130 
131 int multi_sending_message = 0;
132 int multi_defining_message = 0;
133 int multi_message_index = 0;
134 
135 char multibuf[MAX_MULTI_MESSAGE_LEN+4];            // This is where multiplayer message are built
136 
137 short remote_to_local[MAX_NUM_NET_PLAYERS][MAX_OBJECTS];  // Remote object number for each local object
138 short local_to_remote[MAX_OBJECTS];
139 byte  object_owner[MAX_OBJECTS];   // Who created each object in my universe, -1 = loaded at start
140 
141 int   Net_create_objnums[MAX_NET_CREATE_OBJECTS]; // For tracking object creation that will be sent to remote
142 int   Net_create_loc = 0;       // pointer into previous array
143 int   Network_laser_fired = 0;  // How many times we shot
144 int   Network_laser_gun;        // Which gun number we shot
145 int   Network_laser_flags;      // Special flags for the shot
146 int   Network_laser_level;      // What level
147 short Network_laser_track;      // Who is it tracking?
148 char  Network_message[MAX_MESSAGE_LEN];
149 char  Network_message_macro[4][MAX_MESSAGE_LEN];
150 int   Network_message_reciever=-1;
151 int   sorted_kills[MAX_NUM_NET_PLAYERS];
152 short kill_matrix[MAX_NUM_NET_PLAYERS][MAX_NUM_NET_PLAYERS];
153 int   multi_goto_secret = 0;
154 short team_kills[2];
155 int   multi_in_menu = 0;
156 int   multi_leave_menu = 0;
157 int   multi_quit_game = 0;
158 
159 netgame_info Netgame;
160 AllNetPlayers_info NetPlayers;
161 
162 bitmap_index multi_player_textures[MAX_NUM_NET_PLAYERS][N_PLAYER_SHIP_TEXTURES];
163 
164 typedef struct netplayer_stats {
165 	ubyte  message_type;
166 	ubyte  Player_num;              // Who am i?
167 	uint   flags;                   // Powerup flags, see below...
168 	fix    energy;                  // Amount of energy remaining.
169 	fix    shields;                 // shields remaining (protection)
170 	ubyte  lives;                   // Lives remaining, 0 = game over.
171 	ubyte  laser_level;             // Current level of the laser.
172 	ubyte  primary_weapon_flags;    // bit set indicates the player has this weapon.
173 	ubyte  secondary_weapon_flags;  // bit set indicates the player has this weapon.
174 	ushort primary_ammo[MAX_PRIMARY_WEAPONS];     // How much ammo of each type.
175 	ushort secondary_ammo[MAX_SECONDARY_WEAPONS]; // How much ammo of each type.
176 	int    last_score;              // Score at beginning of current level.
177 	int    score;                   // Current score.
178 	fix    cloak_time;              // Time cloaked
179 	fix    invulnerable_time;       // Time invulnerable
180 	fix    homing_object_dist;      // Distance of nearest homing object.
181 	short  KillGoalCount;
182 	short  net_killed_total;        // Number of times killed total
183 	short  net_kills_total;         // Number of net kills total
184 	short  num_kills_level;         // Number of kills this level
185 	short  num_kills_total;         // Number of kills total
186 	short  num_robots_level;        // Number of initial robots this level
187 	short  num_robots_total;        // Number of robots total
188 	ushort hostages_rescued_total;  // Total number of hostages rescued.
189 	ushort hostages_total;          // Total number of hostages.
190 	ubyte  hostages_on_board;       // Number of hostages on ship.
191 	ubyte  unused[16];
192 } netplayer_stats;
193 
194 int message_length[MULTI_MAX_TYPE+1] = {
195 	24, // POSITION
196 	3,  // REAPPEAR
197 	8,  // FIRE
198 	5,  // KILL
199 	4,  // REMOVE_OBJECT
200 	97+9, // PLAYER_EXPLODE
201 	37, // MESSAGE (MAX_MESSAGE_LENGTH = 40)
202 	2,  // QUIT
203 	4,  // PLAY_SOUND
204 	41, // BEGIN_SYNC
205 	4,  // CONTROLCEN
206 	5,  // CLAIM ROBOT
207 	4,  // END_SYNC
208 	2,  // CLOAK
209 	3,  // ENDLEVEL_START
210 	5,  // DOOR_OPEN
211 	2,  // CREATE_EXPLOSION
212 	16, // CONTROLCEN_FIRE
213 	97+9, // PLAYER_DROP
214 	19, // CREATE_POWERUP
215 	9,  // MISSILE_TRACK
216 	2,  // DE-CLOAK
217 	2,  // MENU_CHOICE
218 	28, // ROBOT_POSITION  (shortpos_length (23) + 5 = 28)
219 	9,  // ROBOT_EXPLODE
220 	5,  // ROBOT_RELEASE
221 	18, // ROBOT_FIRE
222 	6,  // SCORE
223 	6,  // CREATE_ROBOT
224 	3,  // TRIGGER
225 	10, // BOSS_ACTIONS
226 	27, // ROBOT_POWERUPS
227 	7,  // HOSTAGE_DOOR
228 	2+24, // SAVE_GAME      (ubyte slot, uint id, char name[20])
229 	2+4,  // RESTORE_GAME   (ubyte slot, uint id)
230 	1+1,  // MULTI_REQ_PLAYER
231 	sizeof(netplayer_stats), // MULTI_SEND_PLAYER
232 	55, // MULTI_MARKER
233 	12, // MULTI_DROP_WEAPON
234 #ifndef MACINTOSH
235 	3+sizeof(shortpos), // MULTI_GUIDED, IF SHORTPOS CHANGES, CHANGE MAC VALUE BELOW
236 #else
237 	26, // MULTI_GUIDED IF SIZE OF SHORTPOS CHANGES, CHANGE THIS VALUE AS WELL!!!!!!
238 #endif
239 	11, // MULTI_STOLEN_ITEMS
240 	6,  // MULTI_WALL_STATUS
241 	5,  // MULTI_HEARTBEAT
242 	9,  // MULTI_KILLGOALS
243 	9,  // MULTI_SEISMIC
244 	18, // MULTI_LIGHT
245 	2,  // MULTI_START_TRIGGER
246 	6,  // MULTI_FLAGS
247 	2,  // MULTI_DROP_BLOB
248 	MAX_POWERUP_TYPES+1, // MULTI_POWERUP_UPDATE
249 	sizeof(active_door)+3, // MULTI_ACTIVE_DOOR
250 	4,  // MULTI_SOUND_FUNCTION
251 	2,  // MULTI_CAPTURE_BONUS
252 	2,  // MULTI_GOT_FLAG
253 	12, // MULTI_DROP_FLAG
254 	142, // MULTI_ROBOT_CONTROLS
255 	2,  // MULTI_FINISH_GAME
256 	3,  // MULTI_RANK
257 	1,  // MULTI_MODEM_PING
258 	1,  // MULTI_MODEM_PING_RETURN
259 	3,  // MULTI_ORB_BONUS
260 	2,  // MULTI_GOT_ORB
261 	12, // MULTI_DROP_ORB
262 	4,  // MULTI_PLAY_BY_PLAY
263 };
264 
265 void extract_netplayer_stats( netplayer_stats *ps, player * pd );
266 void use_netplayer_stats( player * ps, netplayer_stats *pd );
267 char PowerupsInMine[MAX_POWERUP_TYPES],MaxPowerupsAllowed[MAX_POWERUP_TYPES];
268 extern fix ThisLevelTime;
269 
270 //
271 //  Functions that replace what used to be macros
272 //
273 
objnum_remote_to_local(int remote_objnum,int owner)274 int objnum_remote_to_local(int remote_objnum, int owner)
275 {
276 	// Map a remote object number from owner to a local object number
277 
278 	int result;
279 
280 	if ((owner >= N_players) || (owner < -1)) {
281 		Int3(); // Illegal!
282 		return(remote_objnum);
283 	}
284 
285 	if (owner == -1)
286 		return(remote_objnum);
287 
288 	if ((remote_objnum < 0) || (remote_objnum >= MAX_OBJECTS))
289 		return(-1);
290 
291 	result = remote_to_local[owner][remote_objnum];
292 
293 	if (result < 0)
294 	{
295 		mprintf((1, "Remote object owner %d number %d mapped to -1!\n", owner, remote_objnum));
296 		return(-1);
297 	}
298 
299 #ifndef NDEBUG
300 	if (object_owner[result] != owner)
301 	{
302 		mprintf((1, "Remote object owner %d number %d doesn't match owner %d.\n", owner, remote_objnum, object_owner[result]));
303 	}
304 #endif
305 	//Assert(object_owner[result] == owner);
306 
307 	return(result);
308 }
309 
objnum_local_to_remote(int local_objnum,byte * owner)310 int objnum_local_to_remote(int local_objnum, byte *owner)
311 {
312 	// Map a local object number to a remote + owner
313 
314 	int result;
315 
316 	if ((local_objnum < 0) || (local_objnum > Highest_object_index)) {
317 		*owner = -1;
318 		return(-1);
319 	}
320 
321 	*owner = object_owner[local_objnum];
322 
323 	if (*owner == -1)
324 		return(local_objnum);
325 
326 	if ((*owner >= N_players) || (*owner < -1)) {
327 		Int3(); // Illegal!
328 		*owner = -1;
329 		return local_objnum;
330 	}
331 
332 	result = local_to_remote[local_objnum];
333 
334 	//mprintf((0, "Local object %d mapped to owner %d objnum %d.\n", local_objnum,
335 	//	*owner, result));
336 
337 	if (result < 0)
338 	{
339 		Int3(); // See Rob, object has no remote number!
340 	}
341 
342 	return(result);
343 }
344 
345 void
map_objnum_local_to_remote(int local_objnum,int remote_objnum,int owner)346 map_objnum_local_to_remote(int local_objnum, int remote_objnum, int owner)
347 {
348 	// Add a mapping from a network remote object number to a local one
349 
350 	Assert(local_objnum > -1);
351 	Assert(remote_objnum > -1);
352 	Assert(owner > -1);
353 	Assert(owner != Player_num);
354 	Assert(local_objnum < MAX_OBJECTS);
355 	Assert(remote_objnum < MAX_OBJECTS);
356 
357 	object_owner[local_objnum] = owner;
358 
359 	remote_to_local[owner][remote_objnum] = local_objnum;
360 	local_to_remote[local_objnum] = remote_objnum;
361 
362 	return;
363 }
364 
365 void
map_objnum_local_to_local(int local_objnum)366 map_objnum_local_to_local(int local_objnum)
367 {
368 	// Add a mapping for our locally created objects
369 
370 	Assert(local_objnum > -1);
371 	Assert(local_objnum < MAX_OBJECTS);
372 
373 	object_owner[local_objnum] = Player_num;
374 	remote_to_local[Player_num][local_objnum] = local_objnum;
375 	local_to_remote[local_objnum] = local_objnum;
376 
377 	return;
378 }
379 
380 //
381 // Part 1 : functions whose main purpose in life is to divert the flow
382 //          of execution to either network or serial specific code based
383 //          on the curretn Game_mode value.
384 //
385 
386 void
multi_endlevel_score(void)387 multi_endlevel_score(void)
388 {
389 	int old_connect=0;
390 	int i;
391 
392 	// Show a score list to end of net players
393 
394 	// Save connect state and change to new connect state
395 #ifdef NETWORK
396 	if (Game_mode & GM_NETWORK)
397 	{
398 		old_connect = Players[Player_num].connected;
399 		if (Players[Player_num].connected!=3)
400 			Players[Player_num].connected = CONNECT_END_MENU;
401 		Network_status = NETSTAT_ENDLEVEL;
402 
403 	}
404 #endif
405 
406 	// Do the actual screen we wish to show
407 
408 	Function_mode = FMODE_MENU;
409 
410 	kmatrix_view(Game_mode & GM_NETWORK);
411 
412 	Function_mode = FMODE_GAME;
413 
414 	// Restore connect state
415 
416 	if (Game_mode & GM_NETWORK)
417 	{
418 		Players[Player_num].connected = old_connect;
419 	}
420 
421 #ifndef SHAREWARE
422 	if (Game_mode & GM_MULTI_COOP)
423 	{
424 		int i;
425 		for (i = 0; i < MaxNumNetPlayers; i++)
426 			// Reset keys
427 			Players[i].flags &= ~(PLAYER_FLAGS_BLUE_KEY | PLAYER_FLAGS_RED_KEY | PLAYER_FLAGS_GOLD_KEY);
428 	}
429 	for (i = 0; i < MaxNumNetPlayers; i++)
430 		Players[i].flags &= ~(PLAYER_FLAGS_FLAG);  // Clear capture flag
431 
432 #endif
433 
434 	for (i=0;i<MAX_PLAYERS;i++)
435 		Players[i].KillGoalCount=0;
436 
437 	for (i=0;i<MAX_POWERUP_TYPES;i++)
438 	{
439 		MaxPowerupsAllowed[i]=0;
440 		PowerupsInMine[i]=0;
441 	}
442 
443 }
444 
445 int
get_team(int pnum)446 get_team(int pnum)
447 {
448 	if ((Game_mode & GM_CAPTURE) && ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM)))
449 		return pnum;
450 
451 	if (Netgame.team_vector & (1 << pnum))
452 		return 1;
453 	else
454 		return 0;
455 }
456 
457 int
multi_choose_mission(int * anarchy_only)458 multi_choose_mission(int *anarchy_only)
459 {
460 	int i, n_missions;
461 	int default_mission;
462 	char *m[MAX_MISSIONS];
463 	int new_mission_num = 0;
464 
465 	*anarchy_only = 0;
466 
467 	n_missions = build_mission_list(1);
468 
469 	if (n_missions > 1) {
470 
471 		default_mission = 0;
472 		for (i=0;i<n_missions;i++) {
473 			m[i] = Mission_list[i].mission_name;
474 			if ( !stricmp( m[i], config_last_mission ) )
475 				default_mission = i;
476 		}
477 
478       ExtGameStatus=GAMESTAT_START_MULTIPLAYER_MISSION;
479 		new_mission_num = newmenu_listbox1(TXT_MULTI_MISSION, n_missions, m, 1, default_mission, NULL );
480 
481 		if (new_mission_num == -1)
482 			return -1;      //abort!
483 
484 		strcpy(config_last_mission, m[new_mission_num]  );
485 
486 		if (!load_mission(new_mission_num)) {
487 			nm_messagebox( NULL, 1, TXT_OK, TXT_MISSION_ERROR);
488 			return -1;
489 		}
490 
491 		*anarchy_only = Mission_list[new_mission_num].anarchy_only_flag;
492 	}
493 	return(new_mission_num);
494 }
495 
496 extern void game_disable_cheats();
497 
498 void
multi_new_game(void)499 multi_new_game(void)
500 {
501 	int i;
502 
503 	// Reset variables for a new net game
504 
505 	memset(kill_matrix, 0, MAX_NUM_NET_PLAYERS*MAX_NUM_NET_PLAYERS*2); // Clear kill matrix
506 
507 	for (i = 0; i < MAX_NUM_NET_PLAYERS; i++)
508 	{
509 		sorted_kills[i] = i;
510 		Players[i].net_killed_total = 0;
511 		Players[i].net_kills_total = 0;
512 		Players[i].flags = 0;
513 		Players[i].KillGoalCount=0;
514 	}
515 
516 #ifndef SHAREWARE
517 	for (i = 0; i < MAX_ROBOTS_CONTROLLED; i++)
518 	{
519 		robot_controlled[i] = -1;
520 		robot_agitation[i] = 0;
521 		robot_fired[i] = 0;
522 	}
523 #endif
524 
525 	team_kills[0] = team_kills[1] = 0;
526 	Endlevel_sequence = 0;
527 	Player_is_dead = 0;
528 	multi_leave_menu = 0;
529 	multi_quit_game = 0;
530 	Show_kill_list = 1;
531 	game_disable_cheats();
532 	Player_exploded = 0;
533 	Dead_player_camera = 0;
534 }
535 
536 void
multi_make_player_ghost(int playernum)537 multi_make_player_ghost(int playernum)
538 {
539 	object *obj;
540 
541 	//Assert(playernum != Player_num);
542 	//Assert(playernum < MAX_NUM_NET_PLAYERS);
543 
544 	if ((playernum == Player_num) || (playernum >= MAX_NUM_NET_PLAYERS) || (playernum < 0))
545 	{
546 		Int3(); // Non-terminal, see Rob
547 		return;
548 	}
549 
550 //      if (Objects[Players[playernum].objnum].type != OBJ_PLAYER)
551 //              mprintf((1, "Warning: Player %d is not currently a player.\n", playernum));
552 
553 	obj = &Objects[Players[playernum].objnum];
554 
555 	obj->type = OBJ_GHOST;
556 	obj->render_type = RT_NONE;
557 	obj->movement_type = MT_NONE;
558 	multi_reset_player_object(obj);
559 
560 	if (Game_mode & GM_MULTI_ROBOTS)
561 		multi_strip_robots(playernum);
562 }
563 
564 void
multi_make_ghost_player(int playernum)565 multi_make_ghost_player(int playernum)
566 {
567 	object *obj;
568 
569 // Assert(playernum != Player_num);
570 // Assert(playernum < MAX_NUM_NET_PLAYERS);
571 
572 	if ((playernum == Player_num) || (playernum >= MAX_NUM_NET_PLAYERS))
573 	{
574 		Int3(); // Non-terminal, see rob
575 		return;
576 	}
577 
578 //      if(Objects[Players[playernum].objnum].type != OBJ_GHOST)
579 //              mprintf((1, "Warning: Player %d is not currently a ghost.\n", playernum));
580 
581 	obj = &Objects[Players[playernum].objnum];
582 
583 	obj->type = OBJ_PLAYER;
584 	obj->movement_type = MT_PHYSICS;
585 	multi_reset_player_object(obj);
586 }
587 
multi_get_kill_list(int * plist)588 int multi_get_kill_list(int *plist)
589 {
590 	// Returns the number of active net players and their
591 	// sorted order of kills
592 	int i;
593 	int n = 0;
594 
595 	for (i = 0; i < N_players; i++)
596 		//if (Players[sorted_kills[i]].connected)
597 		plist[n++] = sorted_kills[i];
598 
599 	if (n == 0)
600 		Int3(); // SEE ROB OR MATT
601 
602 	//memcpy(plist, sorted_kills, N_players*sizeof(int));
603 
604 	return(n);
605 }
606 
607 void
multi_sort_kill_list(void)608 multi_sort_kill_list(void)
609 {
610 	// Sort the kills list each time a new kill is added
611 
612 	int kills[MAX_NUM_NET_PLAYERS];
613 	int i;
614 	int changed = 1;
615 
616 	for (i = 0; i < MAX_NUM_NET_PLAYERS; i++)
617 	{
618 #ifndef SHAREWARE
619 		if (Game_mode & GM_MULTI_COOP)
620 			kills[i] = Players[i].score;
621 		else
622 #endif
623 		if (Show_kill_list==2)
624 		{
625 			if (Players[i].net_killed_total+Players[i].net_kills_total==0)
626 				kills[i]=-1;  // always draw the ones without any ratio last
627 			else
628 				kills[i]=(int)((float)((float)Players[i].net_kills_total/((float)Players[i].net_killed_total+(float)Players[i].net_kills_total))*100.0);
629 		}
630 		else
631 			kills[i] = Players[i].net_kills_total;
632 	}
633 
634 	while (changed)
635 	{
636 		changed = 0;
637 		for (i = 0; i < N_players-1; i++)
638 		{
639 			if (kills[sorted_kills[i]] < kills[sorted_kills[i+1]])
640 			{
641 				changed = sorted_kills[i];
642 				sorted_kills[i] = sorted_kills[i+1];
643 				sorted_kills[i+1] = changed;
644 				changed = 1;
645 			}
646 		}
647 	}
648 	mprintf((0, "Sorted kills %d %d.\n", sorted_kills[0], sorted_kills[1]));
649 }
650 
651 extern object *obj_find_first_of_type (int);
652 char Multi_killed_yourself=0;
653 
multi_compute_kill(int killer,int killed)654 void multi_compute_kill(int killer, int killed)
655 {
656 	// Figure out the results of a network kills and add it to the
657 	// appropriate player's tally.
658 
659 	int killed_pnum, killed_type;
660 	int killer_pnum, killer_type,killer_id;
661 	int TheGoal;
662 	char killed_name[(CALLSIGN_LEN*2)+4];
663 	char killer_name[(CALLSIGN_LEN*2)+4];
664 
665 	kmatrix_kills_changed = 1;
666 	Multi_killed_yourself=0;
667 
668 	// Both object numbers are localized already!
669 
670 	mprintf((0, "compute_kill passed: object %d killed object %d.\n", killer, killed));
671 
672 	if ((killed < 0) || (killed > Highest_object_index) || (killer < 0) || (killer > Highest_object_index))
673 	{
674 		Int3(); // See Rob, illegal value passed to compute_kill;
675 		return;
676 	}
677 
678 	killed_type = Objects[killed].type;
679 	killer_type = Objects[killer].type;
680 	killer_id = Objects[killer].id;
681 
682 	if ((killed_type != OBJ_PLAYER) && (killed_type != OBJ_GHOST))
683 	{
684 		Int3(); // compute_kill passed non-player object!
685 		return;
686 	}
687 
688 	killed_pnum = Objects[killed].id;
689 
690 	PKilledFlags[killed_pnum]=1;
691 
692 	Assert ((killed_pnum >= 0) && (killed_pnum < N_players));
693 
694 	if (Game_mode & GM_TEAM)
695 		sprintf(killed_name, "%s (%s)", Players[killed_pnum].callsign, Netgame.team_name[get_team(killed_pnum)]);
696 	else
697 		sprintf(killed_name, "%s", Players[killed_pnum].callsign);
698 
699 	if (Newdemo_state == ND_STATE_RECORDING)
700 		newdemo_record_multi_death(killed_pnum);
701 
702 	digi_play_sample( SOUND_HUD_KILL, F3_0 );
703 
704 	if (Control_center_destroyed)
705 		Players[killed_pnum].connected=3;
706 
707 	if (killer_type == OBJ_CNTRLCEN)
708 	{
709 		Players[killed_pnum].net_killed_total++;
710 		Players[killed_pnum].net_kills_total--;
711 
712 		if (Newdemo_state == ND_STATE_RECORDING)
713 			newdemo_record_multi_kill(killed_pnum, -1);
714 
715 		if (killed_pnum == Player_num)
716 		{
717 			HUD_init_message("%s %s.", TXT_YOU_WERE, TXT_KILLED_BY_NONPLAY);
718 			multi_add_lifetime_killed ();
719 		}
720 		else
721 			HUD_init_message("%s %s %s.", killed_name, TXT_WAS, TXT_KILLED_BY_NONPLAY );
722 		return;
723 	}
724 
725 #ifndef SHAREWARE
726 	else if ((killer_type != OBJ_PLAYER) && (killer_type != OBJ_GHOST))
727 	{
728 		if (killer_id==PMINE_ID && killer_type!=OBJ_ROBOT)
729 		{
730 			if (killed_pnum == Player_num)
731 				HUD_init_message("You were killed by a mine!");
732 			else
733 				HUD_init_message("%s was killed by a mine!",killed_name);
734 		}
735 		else
736 		{
737 			if (killed_pnum == Player_num)
738 			{
739 				HUD_init_message("%s %s.", TXT_YOU_WERE, TXT_KILLED_BY_ROBOT);
740 				multi_add_lifetime_killed();
741 			}
742 			else
743 				HUD_init_message("%s %s %s.", killed_name, TXT_WAS, TXT_KILLED_BY_ROBOT );
744 		}
745 		Players[killed_pnum].net_killed_total++;
746 		return;
747 	}
748 #else
749 	else if ((killer_type != OBJ_PLAYER) && (killer_type != OBJ_GHOST) && (killer_id!=PMINE_ID))
750 	{
751 		Int3(); // Illegal killer type?
752 		return;
753 	}
754 	if (killer_id==PMINE_ID)
755 	{
756 		if (killed_pnum==Player_num)
757 			HUD_init_message("You were killed by a mine!");
758 		else
759 			HUD_init_message("%s was killed by a mine!",killed_name);
760 
761 		Players[killed_pnum].net_killed_total++;
762 
763 		return;
764 	}
765 #endif
766 
767 	killer_pnum = Objects[killer].id;
768 
769 	if (Game_mode & GM_TEAM)
770 		sprintf(killer_name, "%s (%s)", Players[killer_pnum].callsign, Netgame.team_name[get_team(killer_pnum)]);
771 	else
772 		sprintf(killer_name, "%s", Players[killer_pnum].callsign);
773 
774 	// Beyond this point, it was definitely a player-player kill situation
775 
776 	if ((killer_pnum < 0) || (killer_pnum >= N_players))
777 		Int3(); // See rob, tracking down bug with kill HUD messages
778 	if ((killed_pnum < 0) || (killed_pnum >= N_players))
779 		Int3(); // See rob, tracking down bug with kill HUD messages
780 
781 	if (killer_pnum == killed_pnum)
782 	{
783 		if (!(Game_mode & GM_HOARD))
784 		{
785 			if (Game_mode & GM_TEAM)
786 				team_kills[get_team(killed_pnum)] -= 1;
787 
788 			Players[killed_pnum].net_killed_total += 1;
789 			Players[killed_pnum].net_kills_total -= 1;
790 
791 			if (Newdemo_state == ND_STATE_RECORDING)
792 				newdemo_record_multi_kill(killed_pnum, -1);
793 		}
794 		kill_matrix[killed_pnum][killed_pnum] += 1; // # of suicides
795 
796 		if (killer_pnum == Player_num)
797 		{
798 			HUD_init_message("%s %s %s!", TXT_YOU, TXT_KILLED, TXT_YOURSELF );
799 			Multi_killed_yourself=1;
800 			multi_add_lifetime_killed();
801 		}
802 		else
803 			HUD_init_message("%s %s", killed_name, TXT_SUICIDE);
804 	}
805 
806 	else
807 	{
808 		if (!(Game_mode & GM_HOARD))
809 		{
810 			if (Game_mode & GM_TEAM)
811 			{
812 				if (get_team(killed_pnum) == get_team(killer_pnum))
813 					team_kills[get_team(killed_pnum)] -= 1;
814 				else
815 					team_kills[get_team(killer_pnum)] += 1;
816 			}
817 
818 			Players[killer_pnum].net_kills_total += 1;
819 			Players[killer_pnum].KillGoalCount+=1;
820 
821 			if (Newdemo_state == ND_STATE_RECORDING)
822 				newdemo_record_multi_kill(killer_pnum, 1);
823 		}
824 		else
825 		{
826 			if (Game_mode & GM_TEAM)
827 			{
828 				if (killed_pnum==Player_num && get_team(killed_pnum) == get_team(killer_pnum))
829 					Multi_killed_yourself=1;
830 			}
831 		}
832 
833 		kill_matrix[killer_pnum][killed_pnum] += 1;
834 		Players[killed_pnum].net_killed_total += 1;
835 		if (killer_pnum == Player_num) {
836 			HUD_init_message("%s %s %s!", TXT_YOU, TXT_KILLED, killed_name);
837 			multi_add_lifetime_kills();
838 			if ((Game_mode & GM_MULTI_COOP) && (Players[Player_num].score >= 1000))
839 				add_points_to_score(-1000);
840 		}
841 		else if (killed_pnum == Player_num)
842 		{
843 			HUD_init_message("%s %s %s!", killer_name, TXT_KILLED, TXT_YOU);
844 			multi_add_lifetime_killed();
845 			if (Game_mode & GM_HOARD)
846 			{
847 				if (Players[Player_num].secondary_ammo[PROXIMITY_INDEX]>3)
848 					multi_send_play_by_play (1,killer_pnum,Player_num);
849 				else if (Players[Player_num].secondary_ammo[PROXIMITY_INDEX]>0)
850 					multi_send_play_by_play (0,killer_pnum,Player_num);
851 			}
852 		}
853 		else
854 			HUD_init_message("%s %s %s!", killer_name, TXT_KILLED, killed_name);
855 	}
856 
857 	TheGoal=Netgame.KillGoal*5;
858 
859 	if (Netgame.KillGoal>0)
860 	{
861 		if (Players[killer_pnum].KillGoalCount>=TheGoal)
862 		{
863 			if (killer_pnum==Player_num)
864 			{
865 				HUD_init_message("You reached the kill goal!");
866 				Players[Player_num].shields=i2f(200);
867 			}
868 			else
869 				HUD_init_message ("%s has reached the kill goal!",Players[killer_pnum].callsign);
870 
871 			HUD_init_message ("The control center has been destroyed!");
872 			net_destroy_controlcen (obj_find_first_of_type (OBJ_CNTRLCEN));
873 		}
874 	}
875 
876 	multi_sort_kill_list();
877 	multi_show_player_list();
878 	Players[killed_pnum].flags&=(~(PLAYER_FLAGS_HEADLIGHT_ON));  // clear the killed guys flags/headlights
879 }
880 
881 void
multi_do_frame(void)882 multi_do_frame(void)
883 {
884 	static int lasttime=0;
885 	int i;
886 
887 	if (!(Game_mode & GM_MULTI))
888 	{
889 		Int3();
890 		return;
891 	}
892 
893 	if ((Game_mode & GM_NETWORK) && Netgame.PlayTimeAllowed && lasttime!=f2i (ThisLevelTime))
894 	{
895 		for (i=0;i<N_players;i++)
896 			if (Players[i].connected)
897 			{
898 				if (i==Player_num)
899 				{
900 					multi_send_heartbeat();
901 					lasttime=f2i(ThisLevelTime);
902 				}
903 				break;
904 			}
905 	}
906 
907 	multi_send_message(); // Send any waiting messages
908 
909 	if (!multi_in_menu)
910 		multi_leave_menu = 0;
911 
912 #ifndef SHAREWARE
913 	if (Game_mode & GM_MULTI_ROBOTS)
914 	{
915 		multi_check_robot_timeout();
916 	}
917 #endif
918 
919 	if ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM))
920 	{
921 		com_do_frame();
922 	}
923 	else
924 	{
925 		network_do_frame(0, 1);
926 	}
927 
928 	if (multi_quit_game && !multi_in_menu)
929 	{
930 		multi_quit_game = 0;
931 		longjmp(LeaveGame, 0);
932 	}
933 }
934 
935 void
multi_send_data(char * buf,int len,int repeat)936 multi_send_data(char *buf, int len, int repeat)
937 {
938 	Assert(len == message_length[(int)buf[0]]);
939 	Assert(buf[0] <= MULTI_MAX_TYPE);
940 	//      Assert(buf[0] >= 0);
941 
942 	if (Game_mode & GM_NETWORK)
943 		Assert(buf[0] > 0);
944 
945 	if ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM))
946 		com_send_data(buf, len, repeat);
947 	else if (Game_mode & GM_NETWORK)
948 		network_send_data(buf, len, repeat);
949 }
950 
951 void
multi_leave_game(void)952 multi_leave_game(void)
953 {
954 
955 	//      if (Function_mode != FMODE_GAME)
956 	//              return;
957 
958 	if (!(Game_mode & GM_MULTI))
959 		return;
960 
961 	if (Game_mode & GM_NETWORK)
962 	{
963 		mprintf((0, "Sending explosion message.\n"));
964 
965 		Net_create_loc = 0;
966 		AdjustMineSpawn();
967 		multi_cap_objects();
968 		drop_player_eggs(ConsoleObject);
969 		multi_send_position(Players[Player_num].objnum);
970 		multi_send_player_explode(MULTI_PLAYER_DROP);
971 	}
972 
973 	mprintf((1, "Sending leave game.\n"));
974 	multi_send_quit(MULTI_QUIT);
975 
976 	if ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM))
977 		serial_leave_game();
978 	if (Game_mode & GM_NETWORK)
979 		network_leave_game();
980 
981 	Game_mode |= GM_GAME_OVER;
982 
983 	if (Function_mode!=FMODE_EXIT)
984 		Function_mode = FMODE_MENU;
985 
986 	//      N_players = 0;
987 
988 	//      change_playernum_to(0);
989 	//      Viewer = ConsoleObject = &Objects[0];
990 
991 }
992 
993 void
multi_show_player_list()994 multi_show_player_list()
995 {
996 	if (!(Game_mode & GM_MULTI) || (Game_mode & GM_MULTI_COOP))
997 		return;
998 
999 	if (Show_kill_list)
1000 		return;
1001 
1002 	Show_kill_list_timer = F1_0*5; // 5 second timer
1003 	Show_kill_list = 1;
1004 }
1005 
1006 int
multi_endlevel(int * secret)1007 multi_endlevel(int *secret)
1008 {
1009 	int result = 0;
1010 
1011 	if ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM))
1012 		com_endlevel(secret);          // an opportunity to re-sync or whatever
1013 	else if (Game_mode & GM_NETWORK)
1014 		result = network_endlevel(secret);
1015 
1016 	return(result);
1017 }
1018 
1019 //
1020 // Part 2 : functions that act on network/serial messages and change the
1021 //          the state of the game in some way.
1022 //
1023 
1024 #ifndef MACINTOSH
1025 //extern PORT *com_port;
1026 #endif
1027 
1028 int
multi_menu_poll(void)1029 multi_menu_poll(void)
1030 {
1031 	fix old_shields;
1032 	int was_fuelcen_alive;
1033 	int player_was_dead;
1034 
1035 	was_fuelcen_alive = Control_center_destroyed;
1036 
1037 	// Special polling function for in-game menus for multiplayer and serial
1038 
1039 	if (! ((Game_mode & GM_MULTI) && (Function_mode == FMODE_GAME)) )
1040 		return(0);
1041 
1042 	if (multi_leave_menu)
1043 		return(-1);
1044 
1045 	old_shields = Players[Player_num].shields;
1046 	player_was_dead = Player_is_dead;
1047 
1048 	multi_in_menu++; // Track level of menu nesting
1049 
1050 	GameLoop( 0, 0 );
1051 
1052 	multi_in_menu--;
1053 
1054 	timer_delay(f0_1);   // delay 100 milliseconds
1055 
1056 	if (Endlevel_sequence || (Control_center_destroyed && !was_fuelcen_alive) || (Player_is_dead != player_was_dead) || (Players[Player_num].shields < old_shields))
1057 	{
1058 		multi_leave_menu = 1;
1059 		return(-1);
1060 	}
1061 	if ((Control_center_destroyed) && (Countdown_seconds_left < 10))
1062 	{
1063 		multi_leave_menu = 1;
1064 		return(-1);
1065 	}
1066 
1067 #if 0
1068 	if ((Game_mode & GM_MODEM) && (!GetCd(com_port)))
1069 	{
1070 		multi_leave_menu = 1;
1071 		return(-1);
1072 	}
1073 #endif
1074 
1075 	return(0);
1076 }
1077 
1078 void
multi_define_macro(int key)1079 multi_define_macro(int key)
1080 {
1081 	if (!(Game_mode & GM_MULTI))
1082 		return;
1083 
1084 	key &= (~KEY_SHIFTED);
1085 
1086 	switch(key)
1087 	{
1088 	case KEY_F9:
1089 		multi_defining_message = 1; break;
1090 	case KEY_F10:
1091 		multi_defining_message = 2; break;
1092 	case KEY_F11:
1093 		multi_defining_message = 3; break;
1094 	case KEY_F12:
1095 		multi_defining_message = 4; break;
1096 	default:
1097 		Int3();
1098 	}
1099 
1100 	if (multi_defining_message)     {
1101 		multi_message_index = 0;
1102 		Network_message[multi_message_index] = 0;
1103 	}
1104 
1105 }
1106 
1107 char feedback_result[200];
1108 
1109 void
multi_message_feedback(void)1110 multi_message_feedback(void)
1111 {
1112 	char *colon;
1113 	int found = 0;
1114 	int i;
1115 
1116 	if (!( ((colon = strrchr(Network_message, ':')) == NULL) || (colon-Network_message < 1) || (colon-Network_message > CALLSIGN_LEN) ))
1117 	{
1118 		sprintf(feedback_result, "%s ", TXT_MESSAGE_SENT_TO);
1119 		if ((Game_mode & GM_TEAM) && (atoi(Network_message) > 0) && (atoi(Network_message) < 3))
1120 		{
1121 			sprintf(feedback_result+strlen(feedback_result), "%s '%s'", TXT_TEAM, Netgame.team_name[atoi(Network_message)-1]);
1122 			found = 1;
1123 		}
1124 		if (Game_mode & GM_TEAM)
1125 		{
1126 			for (i = 0; i < N_players; i++)
1127 			{
1128 				if (!strnicmp(Netgame.team_name[i], Network_message, colon-Network_message))
1129 				{
1130 					if (found)
1131 						strcat(feedback_result, ", ");
1132 					found++;
1133 					if (!(found % 4))
1134 						strcat(feedback_result, "\n");
1135 					sprintf(feedback_result+strlen(feedback_result), "%s '%s'", TXT_TEAM, Netgame.team_name[i]);
1136 				}
1137 			}
1138 		}
1139 		for (i = 0; i < N_players; i++)
1140 		{
1141 			if ((!strnicmp(Players[i].callsign, Network_message, colon-Network_message)) && (i != Player_num) && (Players[i].connected))
1142 			{
1143 				if (found)
1144 					strcat(feedback_result, ", ");
1145 				found++;
1146 				if (!(found % 4))
1147 					strcat(feedback_result, "\n");
1148 				sprintf(feedback_result+strlen(feedback_result), "%s", Players[i].callsign);
1149 			}
1150 		}
1151 		if (!found)
1152 			strcat(feedback_result, TXT_NOBODY);
1153 		else
1154 			strcat(feedback_result, ".");
1155 
1156 		digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
1157 
1158 		Assert(strlen(feedback_result) < 200);
1159 
1160 		HUD_init_message(feedback_result);
1161 		//sprintf (temp,"%s",colon);
1162 		//sprintf (Network_message,"%s",temp);
1163 
1164 	}
1165 }
1166 
1167 void
multi_send_macro(int key)1168 multi_send_macro(int key)
1169 {
1170 	if (! (Game_mode & GM_MULTI) )
1171 		return;
1172 
1173 	switch(key)
1174 	{
1175 	case KEY_F9:
1176 		key = 0; break;
1177 	case KEY_F10:
1178 		key = 1; break;
1179 	case KEY_F11:
1180 		key = 2; break;
1181 	case KEY_F12:
1182 		key = 3; break;
1183 	default:
1184 		Int3();
1185 	}
1186 
1187 	if (!Network_message_macro[key][0])
1188 	{
1189 		HUD_init_message(TXT_NO_MACRO);
1190 		return;
1191 	}
1192 
1193 	strcpy(Network_message, Network_message_macro[key]);
1194 	Network_message_reciever = 100;
1195 
1196 	HUD_init_message("%s '%s'", TXT_SENDING, Network_message);
1197 	multi_message_feedback();
1198 }
1199 
1200 
1201 void
multi_send_message_start()1202 multi_send_message_start()
1203 {
1204 	if (Game_mode&GM_MULTI) {
1205 		multi_sending_message = 1;
1206 		multi_message_index = 0;
1207 		Network_message[multi_message_index] = 0;
1208 	}
1209 }
1210 
1211 extern fix StartingShields;
1212 fix PingLaunchTime,PingReturnTime;
1213 
1214 extern void network_send_ping (ubyte);
1215 extern int network_who_is_master();
1216 extern char NameReturning;
1217 extern int force_cockpit_redraw;
1218 
1219 void network_dump_appletalk_player(ubyte node, ushort net, ubyte socket, int why);
1220 
multi_send_message_end()1221 void multi_send_message_end()
1222 {
1223 	char *mytempbuf;
1224 	int i,t;
1225 
1226 	Network_message_reciever = 100;
1227 
1228 	if (!strnicmp (Network_message,"!Names",6))
1229 	{
1230 		NameReturning=1-NameReturning;
1231 		HUD_init_message ("Name returning is now %s.",NameReturning?"active":"disabled");
1232 	}
1233 	else if (!strnicmp (Network_message,"Handicap:",9))
1234 	{
1235 		mytempbuf=&Network_message[9];
1236 		mprintf ((0,"Networkhandi=%s\n",mytempbuf));
1237 		StartingShields=atol (mytempbuf);
1238 		if (StartingShields<10)
1239 			StartingShields=10;
1240 		if (StartingShields>100)
1241 		{
1242 			sprintf (Network_message,"%s has tried to cheat!",Players[Player_num].callsign);
1243 			StartingShields=100;
1244 		}
1245 		else
1246 			sprintf (Network_message,"%s handicap is now %d",Players[Player_num].callsign,StartingShields);
1247 
1248 		HUD_init_message ("Telling others of your handicap of %d!",StartingShields);
1249 		StartingShields=i2f(StartingShields);
1250 	}
1251 	else if (!strnicmp (Network_message,"NoBombs",7))
1252 		Netgame.DoSmartMine=0;
1253 	else if (!strnicmp (Network_message,"Ping:",5))
1254 	{
1255 		if (Game_mode & GM_NETWORK)
1256 		{
1257 			int name_index=5;
1258 			if (strlen(Network_message) > 5)
1259 				while (Network_message[name_index] == ' ')
1260 					name_index++;
1261 
1262 			if (strlen(Network_message)<=name_index)
1263 			{
1264 				HUD_init_message ("You must specify a name to ping");
1265 				return;
1266 			}
1267 
1268 			for (i = 0; i < N_players; i++)
1269 				if ((!strnicmp(Players[i].callsign, &Network_message[name_index], strlen(Network_message)-name_index)) && (i != Player_num) && (Players[i].connected))
1270 				{
1271 					PingLaunchTime=timer_get_fixed_seconds();
1272 					network_send_ping (i);
1273 					HUD_init_message("Pinging %s...",Players[i].callsign);
1274 					multi_message_index = 0;
1275 					multi_sending_message = 0;
1276 					return;
1277 				}
1278 		}
1279 		else // Modem/Serial ping
1280 		{
1281 			PingLaunchTime=timer_get_fixed_seconds();
1282 			multi_send_modem_ping ();
1283 			HUD_init_message("Pinging opponent...");
1284 		    multi_message_index = 0;
1285 			multi_sending_message = 0;
1286 			return;
1287 		}
1288 	}
1289 	else if (!strnicmp (Network_message,"move:",5))
1290 	{
1291 		mprintf ((0,"moving?\n"));
1292 
1293 		if ((Game_mode & GM_NETWORK) && (Game_mode & GM_TEAM))
1294 		{
1295 			int name_index=5;
1296 			if (strlen(Network_message) > 5)
1297 				while (Network_message[name_index] == ' ')
1298 					name_index++;
1299 
1300 			if (!network_i_am_master())
1301 			{
1302 				HUD_init_message ("Only %s can move players!",Players[network_who_is_master()].callsign);
1303 				return;
1304 			}
1305 
1306 			if (strlen(Network_message)<=name_index)
1307 			{
1308 				HUD_init_message ("You must specify a name to move");
1309 				return;
1310 			}
1311 
1312 			for (i = 0; i < N_players; i++)
1313 				if ((!strnicmp(Players[i].callsign, &Network_message[name_index], strlen(Network_message)-name_index)) && (Players[i].connected))
1314 				{
1315 					if ((Game_mode & GM_CAPTURE) && (Players[i].flags & PLAYER_FLAGS_FLAG))
1316 					{
1317 						HUD_init_message ("Can't move player because s/he has a flag!");
1318 						return;
1319 					}
1320 
1321 					if (Netgame.team_vector & (1<<i))
1322 						Netgame.team_vector&=(~(1<<i));
1323 					else
1324 						Netgame.team_vector|=(1<<i);
1325 
1326 					for (t=0;t<N_players;t++)
1327 						if (Players[t].connected)
1328 							multi_reset_object_texture (&Objects[Players[t].objnum]);
1329 
1330 					network_send_netgame_update ();
1331 					sprintf (Network_message,"%s has changed teams!",Players[i].callsign);
1332 					if (i==Player_num)
1333 					{
1334 						HUD_init_message ("You have changed teams!");
1335 						reset_cockpit();
1336 					}
1337 					else
1338 						HUD_init_message ("Moving %s to other team.",Players[i].callsign);
1339 					break;
1340 				}
1341 		}
1342 	}
1343 
1344 	else if (!strnicmp (Network_message,"kick:",5) && (Game_mode & GM_NETWORK))
1345 	{
1346 		int name_index=5;
1347 		if (strlen(Network_message) > 5)
1348 			while (Network_message[name_index] == ' ')
1349 				name_index++;
1350 
1351 		if (!network_i_am_master())
1352 		{
1353 			HUD_init_message ("Only %s can kick others out!",Players[network_who_is_master()].callsign);
1354 			multi_message_index = 0;
1355 			multi_sending_message = 0;
1356 			return;
1357 		}
1358 		if (strlen(Network_message)<=name_index)
1359 		{
1360 			HUD_init_message ("You must specify a name to kick");
1361 			multi_message_index = 0;
1362 			multi_sending_message = 0;
1363 			return;
1364 		}
1365 
1366 		if (Network_message[name_index] == '#' && isdigit(Network_message[name_index+1])) {
1367 			int players[MAX_NUM_NET_PLAYERS];
1368 			int listpos = Network_message[name_index+1] - '0';
1369 
1370 			mprintf ((0,"Trying to kick %d , show_kill_list=%d\n",listpos,Show_kill_list));
1371 
1372 			if (Show_kill_list==1 || Show_kill_list==2) {
1373 				if (listpos == 0 || listpos >= N_players) {
1374 					HUD_init_message ("Invalid player number for kick.");
1375 					multi_message_index = 0;
1376 					multi_sending_message = 0;
1377 					return;
1378 				}
1379 				multi_get_kill_list(players);
1380 				i = players[listpos];
1381 				if ((i != Player_num) && (Players[i].connected))
1382 					goto kick_player;
1383 			}
1384 			else HUD_init_message ("You cannot use # kicking with in team display.");
1385 
1386 
1387 		    multi_message_index = 0;
1388 		    multi_sending_message = 0;
1389 			return;
1390 		}
1391 
1392 
1393 		for (i = 0; i < N_players; i++)
1394 		if ((!strnicmp(Players[i].callsign, &Network_message[name_index], strlen(Network_message)-name_index)) && (i != Player_num) && (Players[i].connected)) {
1395 			kick_player:;
1396 				if (Network_game_type == IPX_GAME)
1397 					network_dump_player(NetPlayers.players[i].network.ipx.server,NetPlayers.players[i].network.ipx.node, 7);
1398 				else
1399 					network_dump_appletalk_player(NetPlayers.players[i].network.appletalk.node,NetPlayers.players[i].network.appletalk.net, NetPlayers.players[i].network.appletalk.socket, 7);
1400 
1401 				HUD_init_message("Dumping %s...",Players[i].callsign);
1402 				multi_message_index = 0;
1403 				multi_sending_message = 0;
1404 				return;
1405 			}
1406 	}
1407 
1408 	else
1409 		HUD_init_message("%s '%s'", TXT_SENDING, Network_message);
1410 
1411 	multi_send_message();
1412 	multi_message_feedback();
1413 
1414 	multi_message_index = 0;
1415 	multi_sending_message = 0;
1416 }
1417 
multi_define_macro_end()1418 void multi_define_macro_end()
1419 {
1420 	Assert( multi_defining_message > 0 );
1421 
1422 	strcpy( Network_message_macro[multi_defining_message-1], Network_message );
1423 	write_player_file();
1424 
1425 	multi_message_index = 0;
1426 	multi_defining_message = 0;
1427 }
1428 
multi_message_input_sub(int key)1429 void multi_message_input_sub( int key )
1430 {
1431 	switch( key )   {
1432 	case KEY_F8:
1433 	case KEY_ESC:
1434 		multi_sending_message = 0;
1435 		multi_defining_message = 0;
1436 		game_flush_inputs();
1437 		break;
1438 	case KEY_LEFT:
1439 	case KEY_BACKSP:
1440 	case KEY_PAD4:
1441 		if (multi_message_index > 0)
1442 			multi_message_index--;
1443 		Network_message[multi_message_index] = 0;
1444 		break;
1445 	case KEY_ENTER:
1446 		if ( multi_sending_message )
1447 			multi_send_message_end();
1448 		else if ( multi_defining_message )
1449 			multi_define_macro_end();
1450 		game_flush_inputs();
1451 		break;
1452 	default:
1453 		if ( key > 0 )  {
1454 			int ascii = key_to_ascii(key);
1455 			if ((ascii < 255 ))     {
1456 				if (multi_message_index < MAX_MESSAGE_LEN-2 )   {
1457 					Network_message[multi_message_index++] = ascii;
1458 					Network_message[multi_message_index] = 0;
1459 				} else if ( multi_sending_message )     {
1460 					int i;
1461 					char * ptext, * pcolon;
1462 					ptext = NULL;
1463 					Network_message[multi_message_index++] = ascii;
1464 					Network_message[multi_message_index] = 0;
1465 					for (i=multi_message_index-1; i>=0; i-- )       {
1466 						if ( Network_message[i]==32 )   {
1467 							ptext = &Network_message[i+1];
1468 							Network_message[i] = 0;
1469 							break;
1470 						}
1471 					}
1472 					multi_send_message_end();
1473 					if ( ptext )    {
1474 						multi_sending_message = 1;
1475 						pcolon = strchr( Network_message, ':' );
1476 						if ( pcolon )
1477 							strcpy( pcolon+1, ptext );
1478 						else
1479 							strcpy( Network_message, ptext );
1480 						multi_message_index = strlen( Network_message );
1481 					}
1482 				}
1483 			}
1484 		}
1485 	}
1486 }
1487 
1488 void
multi_send_message_dialog(void)1489 multi_send_message_dialog(void)
1490 {
1491 	newmenu_item m[1];
1492 	int choice;
1493 
1494 	if (!(Game_mode&GM_MULTI))
1495 		return;
1496 
1497 	Network_message[0] = 0;             // Get rid of old contents
1498 
1499 	m[0].type=NM_TYPE_INPUT; m[0].text = Network_message; m[0].text_len = MAX_MESSAGE_LEN-1;
1500 	choice = newmenu_do( NULL, TXT_SEND_MESSAGE, 1, m, NULL );
1501 
1502 	if ((choice > -1) && (strlen(Network_message) > 0)) {
1503 		Network_message_reciever = 100;
1504 		HUD_init_message("%s '%s'", TXT_SENDING, Network_message);
1505 		multi_message_feedback();
1506 	}
1507 }
1508 
1509 
1510 
1511 void
multi_do_death(int objnum)1512 multi_do_death(int objnum)
1513 {
1514 	// Do any miscellaneous stuff for a new network player after death
1515 
1516 	objnum = objnum;
1517 
1518 	if (!(Game_mode & GM_MULTI_COOP))
1519 	{
1520 		mprintf((0, "Setting all keys for player %d.\n", Player_num));
1521 		Players[Player_num].flags |= (PLAYER_FLAGS_RED_KEY | PLAYER_FLAGS_BLUE_KEY | PLAYER_FLAGS_GOLD_KEY);
1522 	}
1523 }
1524 
1525 void
multi_do_fire(char * buf)1526 multi_do_fire(char *buf)
1527 {
1528 	ubyte weapon;
1529 	char pnum;
1530 	byte flags;
1531 	//static dum=0;
1532 
1533 	// Act out the actual shooting
1534 	pnum = buf[1];
1535 
1536 #ifndef MACINTOSH
1537 	weapon = (int)buf[2];
1538 #else
1539 	weapon = buf[2];
1540 #endif
1541 	flags = buf[4];
1542 	Network_laser_track = INTEL_SHORT(*(short *)(buf+6));
1543 
1544 	Assert (pnum < N_players);
1545 
1546 	if (Objects[Players[(int)pnum].objnum].type == OBJ_GHOST)
1547 		multi_make_ghost_player(pnum);
1548 
1549 	//  mprintf((0,"multi_do_fire, weapon = %d\n",weapon));
1550 
1551 	if (weapon == FLARE_ADJUST)
1552 		Laser_player_fire( Objects+Players[(int)pnum].objnum, FLARE_ID, 6, 1, 0);
1553 	else if (weapon >= MISSILE_ADJUST) {
1554 		int weapon_id,weapon_gun;
1555 
1556 		weapon_id = Secondary_weapon_to_weapon_info[weapon-MISSILE_ADJUST];
1557 		weapon_gun = Secondary_weapon_to_gun_num[weapon-MISSILE_ADJUST] + (flags & 1);
1558 		mprintf((0,"missile id = %d, gun = %d\n",weapon_id,weapon_gun));
1559 
1560 		if (weapon-MISSILE_ADJUST==GUIDED_INDEX)
1561 		{
1562 			mprintf ((0,"Missile is guided!!!\n"));
1563 			Multi_is_guided=1;
1564 		}
1565 
1566 		Laser_player_fire( Objects+Players[(int)pnum].objnum, weapon_id, weapon_gun, 1, 0 );
1567 	}
1568 	else {
1569 		fix save_charge = Fusion_charge;
1570 
1571 		if (weapon == FUSION_INDEX) {
1572 			Fusion_charge = flags << 12;
1573 			mprintf((0, "Fusion charge X%f.\n", f2fl(Fusion_charge)));
1574 		}
1575 		if (weapon == LASER_ID) {
1576 			if (flags & LASER_QUAD)
1577 				Players[(int)pnum].flags |= PLAYER_FLAGS_QUAD_LASERS;
1578 			else
1579 				Players[(int)pnum].flags &= ~PLAYER_FLAGS_QUAD_LASERS;
1580 		}
1581 
1582 		do_laser_firing(Players[(int)pnum].objnum, weapon, (int)buf[3], flags, (int)buf[5]);
1583 
1584 		if (weapon == FUSION_INDEX)
1585 			Fusion_charge = save_charge;
1586 	}
1587 }
1588 
1589 void
multi_do_message(char * buf)1590 multi_do_message(char *buf)
1591 {
1592 	char *colon;
1593 	char *tilde,mesbuf[100];
1594 	int tloc,t;
1595 
1596 	int loc = 2;
1597 
1598 	if ((tilde=strchr (buf+loc,'$')))  // do that stupid name stuff
1599 	{											// why'd I put this in?  Probably for the
1600 		tloc=tilde-(buf+loc);				// same reason you can name your guidebot
1601 		mprintf ((0,"Tloc=%d\n",tloc));
1602 
1603 		if (tloc>0)
1604 			strncpy (mesbuf,buf+loc,tloc);
1605 		strcpy (mesbuf+tloc,Players[Player_num].callsign);
1606 		strcpy (mesbuf+strlen(Players[Player_num].callsign)+tloc,buf+loc+tloc+1);
1607 		strcpy (buf+loc,mesbuf);
1608 	}
1609 
1610 	if (((colon = strrchr(buf+loc, ':')) == NULL) || (colon-(buf+loc) < 1) || (colon-(buf+loc) > CALLSIGN_LEN))
1611 	{
1612 		mesbuf[0] = 1;
1613 		mesbuf[1] = BM_XRGB(28, 0, 0);
1614 		strcpy(&mesbuf[2], Players[(int)buf[1]].callsign);
1615 		t = strlen(mesbuf);
1616 		mesbuf[t] = ':';
1617 		mesbuf[t+1] = 1;
1618 		mesbuf[t+2] = BM_XRGB(0, 31, 0);
1619 		mesbuf[t+3] = 0;
1620 
1621 		digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
1622 		HUD_init_message("%s %s", mesbuf, buf+2);
1623 	}
1624 	else
1625 	{
1626 		if ( (!strnicmp(Players[Player_num].callsign, buf+loc, colon-(buf+loc))) ||
1627 			 ((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)))) )
1628 		{
1629 			mesbuf[0] = 1;
1630 			mesbuf[1] = BM_XRGB(0, 32, 32);
1631 			strcpy(&mesbuf[2], Players[(int)buf[1]].callsign);
1632 			t = strlen(mesbuf);
1633 			mesbuf[t] = ':';
1634 			mesbuf[t+1] = 1;
1635 			mesbuf[t+2] = BM_XRGB(0, 31, 0);
1636 			mesbuf[t+3] = 0;
1637 
1638 			digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
1639 			HUD_init_message("%s %s", mesbuf, colon+1);
1640 		}
1641 	}
1642 }
1643 
1644 void
multi_do_position(char * buf)1645 multi_do_position(char *buf)
1646 {
1647 #ifdef MACINTOSH
1648 	shortpos sp;
1649 #endif
1650 
1651 	// This routine does only player positions, mode game only
1652 	//      mprintf((0, "Got position packet.\n"));
1653 
1654 	int pnum = (Player_num+1)%2;
1655 
1656 	Assert(&Objects[Players[pnum].objnum] != ConsoleObject);
1657 
1658 	if (Game_mode & GM_NETWORK)
1659 	{
1660 		Int3(); // Get Jason, what the hell are we doing here?
1661 		return;
1662     }
1663 
1664 
1665 #ifndef MACINTOSH
1666 	extract_shortpos(&Objects[Players[pnum].objnum], (shortpos *)(buf+1),0);
1667 #else
1668 	memcpy((ubyte *)(sp.bytemat), (ubyte *)(buf + 1), 9);
1669 	memcpy((ubyte *)&(sp.xo), (ubyte *)(buf + 10), 14);
1670 	extract_shortpos(&Objects[Players[pnum].objnum], &sp, 1);
1671 #endif
1672 
1673 	if (Objects[Players[pnum].objnum].movement_type == MT_PHYSICS)
1674 		set_thrust_from_velocity(&Objects[Players[pnum].objnum]);
1675 }
1676 
1677 void
multi_do_reappear(char * buf)1678 multi_do_reappear(char *buf)
1679 {
1680 	short objnum;
1681 
1682 	objnum = INTEL_SHORT(*(short *)(buf+1));
1683 
1684 	Assert(objnum >= 0);
1685 	//      Assert(Players[Objects[objnum].id]].objnum == objnum);
1686 
1687 	// mprintf((0, "Switching rendering back on for object %d.\n", objnum));
1688 
1689 	multi_make_ghost_player(Objects[objnum].id);
1690 	create_player_appearance_effect(&Objects[objnum]);
1691 	PKilledFlags[Objects[objnum].id]=0;
1692 }
1693 
1694 void
multi_do_player_explode(char * buf)1695 multi_do_player_explode(char *buf)
1696 {
1697 	// Only call this for players, not robots.  pnum is player number, not
1698 	// Object number.
1699 
1700 	object *objp;
1701 	int count;
1702 	int pnum;
1703 	int i;
1704 	char remote_created;
1705 
1706 	pnum = buf[1];
1707 
1708 #ifdef NDEBUG
1709 	if ((pnum < 0) || (pnum >= N_players))
1710 		return;
1711 #else
1712 	Assert(pnum >= 0);
1713 	Assert(pnum < N_players);
1714 #endif
1715 
1716 #ifdef NETWORK
1717 	// If we are in the process of sending objects to a new player, reset that process
1718 	if (Network_send_objects)
1719 	{
1720 		mprintf((0, "Resetting object sync due to player explosion.\n"));
1721 		Network_send_objnum = -1;
1722 	}
1723 #endif
1724 
1725 	// Stuff the Players structure to prepare for the explosion
1726 
1727 	count = 2;
1728 	Players[pnum].primary_weapon_flags = INTEL_SHORT(*(ushort *)(buf+count)); count += 2;
1729 	Players[pnum].secondary_weapon_flags = INTEL_SHORT(*(ushort *)(buf+count)); count += 2;
1730 	Players[pnum].laser_level = buf[count];                                                 count++;
1731 	Players[pnum].secondary_ammo[HOMING_INDEX] = buf[count];                count++;
1732 	Players[pnum].secondary_ammo[CONCUSSION_INDEX] = buf[count];count++;
1733 	Players[pnum].secondary_ammo[SMART_INDEX] = buf[count];         count++;
1734 	Players[pnum].secondary_ammo[MEGA_INDEX] = buf[count];          count++;
1735 	Players[pnum].secondary_ammo[PROXIMITY_INDEX] = buf[count]; count++;
1736 
1737 	Players[pnum].secondary_ammo[SMISSILE1_INDEX] = buf[count]; count++;
1738 	Players[pnum].secondary_ammo[GUIDED_INDEX]    = buf[count]; count++;
1739 	Players[pnum].secondary_ammo[SMART_MINE_INDEX]= buf[count]; count++;
1740 	Players[pnum].secondary_ammo[SMISSILE4_INDEX] = buf[count]; count++;
1741 	Players[pnum].secondary_ammo[SMISSILE5_INDEX] = buf[count]; count++;
1742 
1743 	Players[pnum].primary_ammo[VULCAN_INDEX] = INTEL_SHORT(*(ushort *)(buf+count)); count += 2;
1744 	Players[pnum].primary_ammo[GAUSS_INDEX] = INTEL_SHORT(*(ushort *)(buf+count)); count += 2;
1745 	Players[pnum].flags = INTEL_INT(*(uint *)(buf+count));                     count += 4;
1746 
1747 	multi_adjust_remote_cap (pnum);
1748 
1749 	objp = Objects+Players[pnum].objnum;
1750 
1751 	//      objp->phys_info.velocity = *(vms_vector *)(buf+16); // 12 bytes
1752 	//      objp->pos = *(vms_vector *)(buf+28);                // 12 bytes
1753 
1754 	remote_created = buf[count++]; // How many did the other guy create?
1755 
1756 	Net_create_loc = 0;
1757 
1758 	drop_player_eggs(objp);
1759 
1760 	// Create mapping from remote to local numbering system
1761 
1762 	mprintf((0, "I Created %d powerups, remote created %d.\n", Net_create_loc, remote_created));
1763 
1764 	// We now handle this situation gracefully, Int3 not required
1765 	//      if (Net_create_loc != remote_created)
1766 	//              Int3(); // Probably out of object array space, see Rob
1767 
1768 	for (i = 0; i < remote_created; i++)
1769 	{
1770 		short s;
1771 
1772 		s = INTEL_SHORT(*(short *)(buf+count));
1773 
1774 		if ((i < Net_create_loc) && (s > 0))
1775 			map_objnum_local_to_remote((short)Net_create_objnums[i], s, pnum);
1776 		else if (*(short *)(buf+count) <= 0)
1777 		{
1778 			mprintf((0, "WARNING: Remote created object has non-valid number %d (player %d)", s, pnum));
1779 		}
1780 		else
1781 		{
1782 			mprintf((0, "WARNING: Could not create all powerups created by player %d.\n", pnum));
1783 		}
1784 		//              Assert(s > 0);
1785 		count += 2;
1786 	}
1787 	for (i = remote_created; i < Net_create_loc; i++) {
1788 		mprintf((0, "WARNING: I Created more powerups than player %d, deleting.\n", pnum));
1789 		Objects[Net_create_objnums[i]].flags |= OF_SHOULD_BE_DEAD;
1790 	}
1791 
1792 	if (buf[0] == MULTI_PLAYER_EXPLODE)
1793 	{
1794 		explode_badass_player(objp);
1795 
1796 		objp->flags &= ~OF_SHOULD_BE_DEAD;              //don't really kill player
1797 		multi_make_player_ghost(pnum);
1798 	}
1799 	else
1800 	{
1801 		create_player_appearance_effect(objp);
1802 	}
1803 
1804 	Players[pnum].flags &= ~(PLAYER_FLAGS_CLOAKED | PLAYER_FLAGS_INVULNERABLE | PLAYER_FLAGS_FLAG);
1805 	Players[pnum].cloak_time = 0;
1806 }
1807 
1808 void
multi_do_kill(char * buf)1809 multi_do_kill(char *buf)
1810 {
1811 	int killer, killed;
1812 	int count = 1;
1813 	int pnum;
1814 
1815 	pnum = (int)(buf[count]);
1816 	if ((pnum < 0) || (pnum >= N_players))
1817 	{
1818 		Int3(); // Invalid player number killed
1819 		return;
1820 	}
1821 	killed = Players[pnum].objnum;
1822 	count += 1;
1823 
1824 	killer = INTEL_SHORT(*(short *)(buf+count));
1825 	if (killer > 0)
1826 		killer = objnum_remote_to_local(killer, (byte)buf[count+2]);
1827 
1828 #ifdef SHAREWARE
1829 	if ((Objects[killed].type != OBJ_PLAYER) && (Objects[killed].type != OBJ_GHOST))
1830 	{
1831 		Int3();
1832 		mprintf( (1, "SOFT INT3: MULTI.C Non-player object %d of type %d killed! (JOHN)\n", killed, Objects[killed].type ));
1833 		return;
1834 	}
1835 #endif
1836 
1837 	multi_compute_kill(killer, killed);
1838 
1839 }
1840 
1841 
1842 //      Changed by MK on 10/20/94 to send NULL as object to net_destroy_controlcen if it got -1
1843 // which means not a controlcen object, but contained in another object
multi_do_controlcen_destroy(char * buf)1844 void multi_do_controlcen_destroy(char *buf)
1845 {
1846 	byte who;
1847 	short objnum;
1848 
1849 	objnum = INTEL_SHORT(*(short *)(buf+1));
1850 	who = buf[3];
1851 
1852 	if (Control_center_destroyed != 1)
1853 	{
1854 		if ((who < N_players) && (who != Player_num)) {
1855 			HUD_init_message("%s %s", Players[who].callsign, TXT_HAS_DEST_CONTROL);
1856 		}
1857 		else if (who == Player_num)
1858 			HUD_init_message(TXT_YOU_DEST_CONTROL);
1859 		else
1860 			HUD_init_message(TXT_CONTROL_DESTROYED);
1861 
1862 		if (objnum != -1)
1863 			net_destroy_controlcen(Objects+objnum);
1864 		else
1865 			net_destroy_controlcen(NULL);
1866 	}
1867 }
1868 
1869 void
multi_do_escape(char * buf)1870 multi_do_escape(char *buf)
1871 {
1872 	int objnum;
1873 
1874 	objnum = Players[(int)buf[1]].objnum;
1875 
1876 	digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
1877 	digi_kill_sound_linked_to_object (objnum);
1878 
1879 	if (buf[2] == 0)
1880 	{
1881 		HUD_init_message("%s %s", Players[(int)buf[1]].callsign, TXT_HAS_ESCAPED);
1882 		if (Game_mode & GM_NETWORK)
1883 			Players[(int)buf[1]].connected = CONNECT_ESCAPE_TUNNEL;
1884 		if (!multi_goto_secret)
1885 			multi_goto_secret = 2;
1886 	}
1887 	else if (buf[2] == 1)
1888 	{
1889 		HUD_init_message("%s %s", Players[(int)buf[1]].callsign, TXT_HAS_FOUND_SECRET);
1890 		if (Game_mode & GM_NETWORK)
1891 			Players[(int)buf[1]].connected = CONNECT_FOUND_SECRET;
1892 		if (!multi_goto_secret)
1893 			multi_goto_secret = 1;
1894 	}
1895 	create_player_appearance_effect(&Objects[objnum]);
1896 	multi_make_player_ghost(buf[1]);
1897 }
1898 
1899 void
multi_do_remobj(char * buf)1900 multi_do_remobj(char *buf)
1901 {
1902 	short objnum; // which object to remove
1903 	short local_objnum;
1904 	byte obj_owner; // which remote list is it entered in
1905 
1906 	objnum = INTEL_SHORT(*(short *)(buf+1));
1907 	obj_owner = buf[3];
1908 
1909 	Assert(objnum >= 0);
1910 
1911 	if (objnum < 1)
1912 		return;
1913 
1914 	local_objnum = objnum_remote_to_local(objnum, obj_owner); // translate to local objnum
1915 
1916 	//      mprintf((0, "multi_do_remobj: %d owner %d = %d.\n", objnum, obj_owner, local_objnum));
1917 
1918 	if (local_objnum < 0)
1919 	{
1920 		mprintf((1, "multi_do_remobj: Could not remove referenced object.\n"));
1921 		return;
1922 	}
1923 
1924 	if ((Objects[local_objnum].type != OBJ_POWERUP) && (Objects[local_objnum].type != OBJ_HOSTAGE))
1925 	{
1926 		mprintf((1, "multi_get_remobj: tried to remove invalid type %d.\n", Objects[local_objnum].type));
1927 		return;
1928 	}
1929 
1930 	if (Network_send_objects && network_objnum_is_past(local_objnum))
1931 	{
1932 		mprintf((0, "Resetting object sync due to object removal.\n"));
1933 		Network_send_objnum = -1;
1934 	}
1935 	if (Objects[local_objnum].type==OBJ_POWERUP)
1936 		if (Game_mode & GM_NETWORK)
1937 		{
1938 			if (PowerupsInMine[Objects[local_objnum].id]>0)
1939 				PowerupsInMine[Objects[local_objnum].id]--;
1940 
1941 			if (multi_powerup_is_4pack (Objects[local_objnum].id))
1942 			{
1943 				mprintf ((0,"Hey babe! Doing that wacky 4 pack stuff."));
1944 
1945 				if (PowerupsInMine[Objects[local_objnum].id-1]-4<0)
1946 					PowerupsInMine[Objects[local_objnum].id-1]=0;
1947 				else
1948 					PowerupsInMine[Objects[local_objnum].id-1]-=4;
1949 			}
1950 
1951 			mprintf ((0,"Decrementing powerups! %d\n",PowerupsInMine[Objects[local_objnum].id]));
1952 		}
1953 
1954 	Objects[local_objnum].flags |= OF_SHOULD_BE_DEAD; // quick and painless
1955 
1956 }
1957 
1958 void
multi_do_quit(char * buf)1959 multi_do_quit(char *buf)
1960 {
1961 
1962 	if (Game_mode & GM_NETWORK)
1963 	{
1964 		int i, n = 0;
1965 
1966 		digi_play_sample( SOUND_HUD_MESSAGE, F1_0 );
1967 
1968 		HUD_init_message( "%s %s", Players[(int)buf[1]].callsign, TXT_HAS_LEFT_THE_GAME);
1969 
1970 		network_disconnect_player(buf[1]);
1971 
1972 		if (multi_in_menu)
1973 			return;
1974 
1975 		for (i = 0; i < N_players; i++)
1976 			if (Players[i].connected) n++;
1977 		if (n == 1)
1978 		{
1979 			nm_messagebox(NULL, 1, TXT_OK, TXT_YOU_ARE_ONLY);
1980 		}
1981 	}
1982 
1983 	if ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM))
1984 	{
1985 		Function_mode = FMODE_MENU;
1986 		multi_quit_game = 1;
1987 		multi_leave_menu = 1;
1988 		nm_messagebox(NULL, 1, TXT_OK, TXT_OPPONENT_LEFT);
1989 		Function_mode = FMODE_GAME;
1990 		multi_reset_stuff();
1991 	}
1992 	return;
1993 }
1994 
1995 void
multi_do_cloak(char * buf)1996 multi_do_cloak(char *buf)
1997 {
1998 	int pnum;
1999 
2000 	pnum = (int)(buf[1]);
2001 
2002 	Assert(pnum < N_players);
2003 
2004 	mprintf((0, "Cloaking player %d\n", pnum));
2005 
2006 	Players[pnum].flags |= PLAYER_FLAGS_CLOAKED;
2007 	Players[pnum].cloak_time = GameTime;
2008 	ai_do_cloak_stuff();
2009 
2010 #ifndef SHAREWARE
2011 	if (Game_mode & GM_MULTI_ROBOTS)
2012 		multi_strip_robots(pnum);
2013 #endif
2014 
2015 	if (Newdemo_state == ND_STATE_RECORDING)
2016 		newdemo_record_multi_cloak(pnum);
2017 }
2018 
2019 void
multi_do_decloak(char * buf)2020 multi_do_decloak(char *buf)
2021 {
2022 	int pnum;
2023 
2024 	pnum = (int)(buf[1]);
2025 
2026 	if (Newdemo_state == ND_STATE_RECORDING)
2027 		newdemo_record_multi_decloak(pnum);
2028 
2029 }
2030 
2031 void
multi_do_door_open(char * buf)2032 multi_do_door_open(char *buf)
2033 {
2034 	int segnum;
2035 	byte side;
2036 	segment *seg;
2037 	wall *w;
2038 	ubyte flag;
2039 
2040 	segnum = INTEL_SHORT(*(short *)(buf+1));
2041 	side = buf[3];
2042 	flag= buf[4];
2043 
2044 	//      mprintf((0, "Opening door on side %d of segment # %d.\n", side, segnum));
2045 
2046 	if ((segnum < 0) || (segnum > Highest_segment_index) || (side < 0) || (side > 5))
2047 	{
2048 		Int3();
2049 		return;
2050 	}
2051 
2052 	seg = &Segments[segnum];
2053 
2054 	if (seg->sides[side].wall_num == -1) {  //Opening door on illegal wall
2055 		Int3();
2056 		return;
2057 	}
2058 
2059 	w = &Walls[seg->sides[side].wall_num];
2060 
2061 	if (w->type == WALL_BLASTABLE)
2062 	{
2063 		if (!(w->flags & WALL_BLASTED))
2064 		{
2065 			mprintf((0, "Blasting wall by remote command.\n"));
2066 			wall_destroy(seg, side);
2067 		}
2068 		return;
2069 	}
2070 	else if (w->state != WALL_DOOR_OPENING)
2071 	{
2072 		wall_open_door(seg, side);
2073 		w->flags=flag;
2074 	}
2075 	else
2076 		w->flags=flag;
2077 
2078 	//      else
2079 	//              mprintf((0, "Door already opening!\n"));
2080 }
2081 
2082 void
multi_do_create_explosion(char * buf)2083 multi_do_create_explosion(char *buf)
2084 {
2085 	int pnum;
2086 	int count = 1;
2087 
2088 	pnum = buf[count++];
2089 
2090 	//      mprintf((0, "Creating small fireball.\n"));
2091 	create_small_fireball_on_object(&Objects[Players[pnum].objnum], F1_0, 1);
2092 }
2093 
2094 void
multi_do_controlcen_fire(char * buf)2095 multi_do_controlcen_fire(char *buf)
2096 {
2097 	vms_vector to_target;
2098 	char gun_num;
2099 	short objnum;
2100 	int count = 1;
2101 
2102 	memcpy(&to_target, buf+count, 12);      count += 12;
2103 #ifdef MACINTOSH	// swap the vector to_target
2104 	to_target.x = (fix)INTEL_INT((int)to_target.x);
2105 	to_target.y = (fix)INTEL_INT((int)to_target.y);
2106 	to_target.z = (fix)INTEL_INT((int)to_target.z);
2107 #endif
2108 	gun_num = buf[count];                                   count += 1;
2109 	objnum = INTEL_SHORT(*(short *)(buf+count));         count += 2;
2110 
2111 	Laser_create_new_easy(&to_target, &Gun_pos[(int)gun_num], objnum, CONTROLCEN_WEAPON_NUM, 1);
2112 }
2113 
2114 void
multi_do_create_powerup(char * buf)2115 multi_do_create_powerup(char *buf)
2116 {
2117 	short segnum;
2118 	short objnum;
2119 	int my_objnum;
2120 	char pnum;
2121 	int count = 1;
2122 	vms_vector new_pos;
2123 	char powerup_type;
2124 
2125 	if (Endlevel_sequence || Control_center_destroyed)
2126 		return;
2127 
2128 	pnum = buf[count++];
2129 	powerup_type = buf[count++];
2130 	segnum = INTEL_SHORT(*(short *)(buf+count)); count+=2;
2131 	objnum = INTEL_SHORT(*(short *)(buf+count)); count+=2;
2132 
2133 	if ((segnum < 0) || (segnum > Highest_segment_index)) {
2134 		Int3();
2135 		return;
2136 	}
2137 
2138 	new_pos = *(vms_vector *)(buf+count); count+=sizeof(vms_vector);
2139 #ifdef MACINTOSH
2140 	new_pos.x = (fix)SWAPINT((int)new_pos.x);
2141 	new_pos.y = (fix)SWAPINT((int)new_pos.y);
2142 	new_pos.z = (fix)SWAPINT((int)new_pos.z);
2143 #endif
2144 
2145 	Net_create_loc = 0;
2146 	my_objnum = call_object_create_egg(&Objects[Players[(int)pnum].objnum], 1, OBJ_POWERUP, powerup_type);
2147 
2148 	if (my_objnum < 0) {
2149 		mprintf((0, "Could not create new powerup!\n"));
2150 		return;
2151 	}
2152 
2153 	if (Network_send_objects && network_objnum_is_past(my_objnum))
2154 	{
2155 		mprintf((0, "Resetting object sync due to powerup creation.\n"));
2156 		Network_send_objnum = -1;
2157 	}
2158 
2159 	Objects[my_objnum].pos = new_pos;
2160 
2161 	vm_vec_zero(&Objects[my_objnum].mtype.phys_info.velocity);
2162 
2163 	obj_relink(my_objnum, segnum);
2164 
2165 	map_objnum_local_to_remote(my_objnum, objnum, pnum);
2166 
2167 	object_create_explosion(segnum, &new_pos, i2f(5), VCLIP_POWERUP_DISAPPEARANCE);
2168 	mprintf((0, "Creating powerup type %d in segment %i.\n", powerup_type, segnum));
2169 
2170 	if (Game_mode & GM_NETWORK)
2171 		PowerupsInMine[(int)powerup_type]++;
2172 }
2173 
2174 void
multi_do_play_sound(char * buf)2175 multi_do_play_sound(char *buf)
2176 {
2177 	int pnum = (int)(buf[1]);
2178 	int sound_num = (int)(buf[2]);
2179 	fix volume = (int)(buf[3]) << 12;
2180 
2181 	if (!Players[pnum].connected)
2182 		return;
2183 
2184 	Assert(Players[pnum].objnum >= 0);
2185 	Assert(Players[pnum].objnum <= Highest_object_index);
2186 
2187 	digi_link_sound_to_object( sound_num, Players[pnum].objnum, 0, volume);
2188 }
2189 
2190 void
multi_do_score(char * buf)2191 multi_do_score(char *buf)
2192 {
2193 	int pnum = (int)(buf[1]);
2194 
2195 	if ((pnum < 0) || (pnum >= N_players))
2196 	{
2197 		Int3(); // Non-terminal, see rob
2198 		return;
2199 	}
2200 
2201 	if (Newdemo_state == ND_STATE_RECORDING)
2202 		newdemo_record_multi_score(pnum, INTEL_INT(*(int *)(buf+2)) );
2203 
2204 	Players[pnum].score = INTEL_INT(*(int *)(buf+2));
2205 
2206 	multi_sort_kill_list();
2207 }
2208 
2209 void
multi_do_trigger(char * buf)2210 multi_do_trigger(char *buf)
2211 {
2212 	int pnum = (int)(buf[1]);
2213 	int trigger = (int)(buf[2]);
2214 
2215 	mprintf ((0,"MULTI doing trigger!\n"));
2216 
2217 	if ((pnum < 0) || (pnum >= N_players) || (pnum == Player_num))
2218 	{
2219 		Int3(); // Got trigger from illegal playernum
2220 		return;
2221 	}
2222 	if ((trigger < 0) || (trigger >= Num_triggers))
2223 	{
2224 		Int3(); // Illegal trigger number in multiplayer
2225 		return;
2226 	}
2227 	check_trigger_sub(trigger, pnum,0);
2228 }
2229 
multi_do_drop_marker(char * buf)2230 void multi_do_drop_marker (char *buf)
2231 {
2232 	int i;
2233 	int pnum=(int)(buf[1]);
2234 	int mesnum=(int)(buf[2]);
2235 	vms_vector position;
2236 
2237 	if (pnum==Player_num)  // my marker? don't set it down cuz it might screw up the orientation
2238 		return;
2239 
2240 	position.x=(fix)INTEL_INT(*(int *)(buf+3));
2241 	position.y=(fix)INTEL_INT(*(int *)(buf+7));
2242 	position.z=(fix)INTEL_INT(*(int *)(buf+11));
2243 
2244 	for (i=0;i<40;i++)
2245 		MarkerMessage[(pnum*2)+mesnum][i]=buf[15+i];
2246 
2247 	MarkerPoint[(pnum*2)+mesnum]=position;
2248 
2249 	if (MarkerObject[(pnum*2)+mesnum] !=-1 && Objects[MarkerObject[(pnum*2)+mesnum]].type!=OBJ_NONE && MarkerObject[(pnum*2)+mesnum] !=0)
2250 		obj_delete(MarkerObject[(pnum*2)+mesnum]);
2251 
2252 	MarkerObject[(pnum*2)+mesnum] = drop_marker_object(&position,Objects[Players[Player_num].objnum].segnum,&Objects[Players[Player_num].objnum].orient,(pnum*2)+mesnum);
2253 	strcpy (MarkerOwner[(pnum*2)+mesnum],Players[pnum].callsign);
2254 	mprintf ((0,"Dropped player %d message: %s\n",pnum,MarkerMessage[(pnum*2)+mesnum]));
2255 }
2256 
2257 
multi_do_hostage_door_status(char * buf)2258 void multi_do_hostage_door_status(char *buf)
2259 {
2260 	// Update hit point status of a door
2261 
2262 	int count = 1;
2263 	int wallnum;
2264 	fix hps;
2265 
2266 	wallnum = INTEL_SHORT(*(short *)(buf+count));                count += 2;
2267 	hps = (fix)INTEL_INT(*(int *)(buf+count));              count += 4;
2268 
2269 	if ((wallnum < 0) || (wallnum > Num_walls) || (hps < 0) || (Walls[wallnum].type != WALL_BLASTABLE))
2270 	{
2271 		Int3(); // Non-terminal, see Rob
2272 		return;
2273 	}
2274 
2275 	//      mprintf((0, "Damaging wall number %d to %f points.\n", wallnum, f2fl(hps)));
2276 
2277 	if (hps < Walls[wallnum].hps)
2278 		wall_damage(&Segments[Walls[wallnum].segnum], Walls[wallnum].sidenum, Walls[wallnum].hps - hps);
2279 }
2280 
multi_do_save_game(char * buf)2281 void multi_do_save_game(char *buf)
2282 {
2283 	int count = 1;
2284 	ubyte slot;
2285 	uint id;
2286 	char desc[25];
2287 
2288 	slot = *(ubyte *)(buf+count);           count += 1;
2289 	id = INTEL_INT(*(uint *)(buf+count));              count += 4;
2290 	memcpy( desc, &buf[count], 20 );        count += 20;
2291 
2292 	multi_save_game( slot, id, desc );
2293 }
2294 
multi_do_restore_game(char * buf)2295 void multi_do_restore_game(char *buf)
2296 {
2297 	int count = 1;
2298 	ubyte slot;
2299 	uint id;
2300 
2301 	slot = *(ubyte *)(buf+count);           count += 1;
2302 	id = INTEL_INT(*(uint *)(buf+count));              count += 4;
2303 
2304 	multi_restore_game( slot, id );
2305 }
2306 
2307 
multi_do_req_player(char * buf)2308 void multi_do_req_player(char *buf)
2309 {
2310 	netplayer_stats ps;
2311 	ubyte player_n;
2312 	// Send my netplayer_stats to everyone!
2313 	player_n = *(ubyte *)(buf+1);
2314 	if ( (player_n == Player_num) || (player_n == 255)  )   {
2315 		extract_netplayer_stats( &ps, &Players[Player_num] );
2316 		ps.Player_num = Player_num;
2317 		ps.message_type = MULTI_SEND_PLAYER;            // SET
2318 		multi_send_data((ubyte*)&ps, sizeof(netplayer_stats), 0);
2319 	}
2320 }
2321 
multi_do_send_player(char * buf)2322 void multi_do_send_player(char *buf)
2323 {
2324 	// Got a player packet from someone!!!
2325 	netplayer_stats * p;
2326 	p = (netplayer_stats *)buf;
2327 
2328 	Assert( p->Player_num <= N_players );
2329 
2330 	mprintf(( 0, "Got netplayer_stats for player %d (I'm %d)\n", p->Player_num, Player_num ));
2331 	mprintf(( 0, "Their shields are: %d\n", f2i(p->shields) ));
2332 
2333 	use_netplayer_stats( &Players[p->Player_num], p );
2334 }
2335 
2336 void
multi_reset_stuff(void)2337 multi_reset_stuff(void)
2338 {
2339 	// A generic, emergency function to solve problems that crop up
2340 	// when a player exits quick-out from the game because of a
2341 	// serial connection loss.  Fixes several weird bugs!
2342 
2343 	dead_player_end();
2344 
2345 	Players[Player_num].homing_object_dist = -F1_0; // Turn off homing sound.
2346 
2347 	Dead_player_camera = 0;
2348 	Endlevel_sequence = 0;
2349 	reset_rear_view();
2350 }
2351 
2352 void
multi_reset_player_object(object * objp)2353 multi_reset_player_object(object *objp)
2354 {
2355 	int i;
2356 
2357 	//Init physics for a non-console player
2358 
2359 	Assert(objp >= Objects);
2360 	Assert(objp <= Objects+Highest_object_index);
2361 	Assert((objp->type == OBJ_PLAYER) || (objp->type == OBJ_GHOST));
2362 
2363 	vm_vec_zero(&objp->mtype.phys_info.velocity);
2364 	vm_vec_zero(&objp->mtype.phys_info.thrust);
2365 	vm_vec_zero(&objp->mtype.phys_info.rotvel);
2366 	vm_vec_zero(&objp->mtype.phys_info.rotthrust);
2367 	objp->mtype.phys_info.brakes = objp->mtype.phys_info.turnroll = 0;
2368 	objp->mtype.phys_info.mass = Player_ship->mass;
2369 	objp->mtype.phys_info.drag = Player_ship->drag;
2370 	//      objp->mtype.phys_info.flags &= ~(PF_TURNROLL | PF_LEVELLING | PF_WIGGLE | PF_USES_THRUST);
2371 	objp->mtype.phys_info.flags &= ~(PF_TURNROLL | PF_LEVELLING | PF_WIGGLE);
2372 
2373 	//Init render info
2374 
2375 	objp->render_type = RT_POLYOBJ;
2376 	objp->rtype.pobj_info.model_num = Player_ship->model_num;               //what model is this?
2377 	objp->rtype.pobj_info.subobj_flags = 0;         //zero the flags
2378 	for (i=0;i<MAX_SUBMODELS;i++)
2379 		vm_angvec_zero(&objp->rtype.pobj_info.anim_angles[i]);
2380 
2381 	//reset textures for this, if not player 0
2382 
2383 	multi_reset_object_texture (objp);
2384 
2385 	// Clear misc
2386 
2387 	objp->flags = 0;
2388 
2389 	if (objp->type == OBJ_GHOST)
2390 		objp->render_type = RT_NONE;
2391 
2392 }
2393 
multi_reset_object_texture(object * objp)2394 void multi_reset_object_texture (object *objp)
2395 {
2396 	int id,i;
2397 
2398 	if (Game_mode & GM_TEAM)
2399 		id = get_team(objp->id);
2400 	else
2401 		id = objp->id;
2402 
2403 	if (id == 0)
2404 		objp->rtype.pobj_info.alt_textures=0;
2405 	else {
2406 		Assert(N_PLAYER_SHIP_TEXTURES == Polygon_models[objp->rtype.pobj_info.model_num].n_textures);
2407 
2408 		for (i=0;i<N_PLAYER_SHIP_TEXTURES;i++)
2409 			multi_player_textures[id-1][i] = ObjBitmaps[ObjBitmapPtrs[Polygon_models[objp->rtype.pobj_info.model_num].first_texture+i]];
2410 
2411 		multi_player_textures[id-1][4] = ObjBitmaps[ObjBitmapPtrs[First_multi_bitmap_num+(id-1)*2]];
2412 		multi_player_textures[id-1][5] = ObjBitmaps[ObjBitmapPtrs[First_multi_bitmap_num+(id-1)*2+1]];
2413 
2414 		objp->rtype.pobj_info.alt_textures = id;
2415 	}
2416 }
2417 
2418 
2419 
2420 
2421 extern int TTRecv[];
2422 extern FILE *RecieveLogFile;
2423 
2424 void
multi_process_bigdata(char * buf,int len)2425 multi_process_bigdata(char *buf, int len)
2426 {
2427 	// Takes a bunch of messages, check them for validity,
2428 	// and pass them to multi_process_data.
2429 
2430 	int type, sub_len, bytes_processed = 0;
2431 
2432 	while( bytes_processed < len )  {
2433 		type = buf[bytes_processed];
2434 
2435 		if ( (type<0) || (type>MULTI_MAX_TYPE)) {
2436 			mprintf( (1, "multi_process_bigdata: Invalid packet type %d!\n", type ));
2437 			return;
2438 		}
2439 		sub_len = message_length[type];
2440 
2441 		Assert(sub_len > 0);
2442 
2443 		if ( (bytes_processed+sub_len) > len )  {
2444 			mprintf( (1, "multi_process_bigdata: packet type %d too short (%d>%d)!\n", type, (bytes_processed+sub_len), len ));
2445 			Int3();
2446 			return;
2447 		}
2448 
2449 		multi_process_data(&buf[bytes_processed], sub_len);
2450 		bytes_processed += sub_len;
2451 	}
2452 }
2453 
2454 //
2455 // Part 2 : Functions that send communication messages to inform the other
2456 //          players of something we did.
2457 //
2458 
2459 void
multi_send_fire(void)2460 multi_send_fire(void)
2461 {
2462 	if (!Network_laser_fired)
2463 		return;
2464 
2465 	multibuf[0] = (char)MULTI_FIRE;
2466 	multibuf[1] = (char)Player_num;
2467 	multibuf[2] = (char)Network_laser_gun;
2468 	multibuf[3] = (char)Network_laser_level;
2469 	multibuf[4] = (char)Network_laser_flags;
2470 	multibuf[5] = (char)Network_laser_fired;
2471 
2472 	*(short *)(multibuf+6) = INTEL_SHORT(Network_laser_track);
2473 
2474 	multi_send_data(multibuf, 8, 0);
2475 
2476 	Network_laser_fired = 0;
2477 }
2478 
2479 void
multi_send_destroy_controlcen(int objnum,int player)2480 multi_send_destroy_controlcen(int objnum, int player)
2481 {
2482 	if (player == Player_num)
2483 		HUD_init_message(TXT_YOU_DEST_CONTROL);
2484 	else if ((player > 0) && (player < N_players))
2485 		HUD_init_message("%s %s", Players[player].callsign, TXT_HAS_DEST_CONTROL);
2486 	else
2487 		HUD_init_message(TXT_CONTROL_DESTROYED);
2488 
2489 	multibuf[0] = (char)MULTI_CONTROLCEN;
2490 	*(ushort *)(multibuf+1) = INTEL_SHORT(objnum);
2491 	multibuf[3] = player;
2492 	multi_send_data(multibuf, 4, 2);
2493 }
2494 
multi_send_drop_marker(int player,vms_vector position,char messagenum,char text[])2495 void multi_send_drop_marker (int player,vms_vector position,char messagenum,char text[])
2496 {
2497 	int i;
2498 
2499 	if (player<N_players)
2500 	{
2501 		mprintf ((0,"Sending MARKER drop!\n"));
2502 		multibuf[0]=(char)MULTI_MARKER;
2503 		multibuf[1]=(char)player;
2504 		multibuf[2]=messagenum;
2505 		*(fix *)(multibuf+3)=INTEL_INT(position.x);
2506 		*(fix *)(multibuf+7)=INTEL_INT(position.y);
2507 		*(fix *)(multibuf+11)=INTEL_INT(position.z);
2508 		for (i=0;i<40;i++)
2509 			multibuf[15+i]=text[i];
2510 	}
2511 	multi_send_data(multibuf, 55, 1);
2512 }
2513 
2514 void
multi_send_endlevel_start(int secret)2515 multi_send_endlevel_start(int secret)
2516 {
2517 	multibuf[0] = (char)MULTI_ENDLEVEL_START;
2518 	multibuf[1] = Player_num;
2519 	multibuf[2] = (char)secret;
2520 
2521 	if ((secret) && !multi_goto_secret)
2522 		multi_goto_secret = 1;
2523 	else if (!multi_goto_secret)
2524 		multi_goto_secret = 2;
2525 
2526 	multi_send_data(multibuf, 3, 1);
2527 	if (Game_mode & GM_NETWORK)
2528 	{
2529 		Players[Player_num].connected = 5;
2530 		network_send_endlevel_packet();
2531 	}
2532 }
2533 
2534 void
multi_send_player_explode(char type)2535 multi_send_player_explode(char type)
2536 {
2537 	int count = 0;
2538 	int i;
2539 
2540 	Assert( (type == MULTI_PLAYER_DROP) || (type == MULTI_PLAYER_EXPLODE) );
2541 
2542 	multi_send_position(Players[Player_num].objnum);
2543 
2544 	if (Network_send_objects)
2545 	{
2546 		mprintf((0, "Resetting object sync due to player explosion.\n"));
2547 		Network_send_objnum = -1;
2548 	}
2549 
2550 	multibuf[count++] = type;
2551 	multibuf[count++] = Player_num;
2552 
2553 	*(ushort *)(multibuf+count) = INTEL_SHORT((ushort)Players[Player_num].primary_weapon_flags);
2554 	count += 2;
2555 	*(ushort *)(multibuf+count) = INTEL_SHORT((ushort)Players[Player_num].secondary_weapon_flags);
2556 	count += 2;
2557 	multibuf[count++] = (char)Players[Player_num].laser_level;
2558 
2559 	multibuf[count++] = (char)Players[Player_num].secondary_ammo[HOMING_INDEX];
2560 	multibuf[count++] = (char)Players[Player_num].secondary_ammo[CONCUSSION_INDEX];
2561 	multibuf[count++] = (char)Players[Player_num].secondary_ammo[SMART_INDEX];
2562 	multibuf[count++] = (char)Players[Player_num].secondary_ammo[MEGA_INDEX];
2563 	multibuf[count++] = (char)Players[Player_num].secondary_ammo[PROXIMITY_INDEX];
2564 
2565 	multibuf[count++] = (char)Players[Player_num].secondary_ammo[SMISSILE1_INDEX];
2566 	multibuf[count++] = (char)Players[Player_num].secondary_ammo[GUIDED_INDEX];
2567 	multibuf[count++] = (char)Players[Player_num].secondary_ammo[SMART_MINE_INDEX];
2568 	multibuf[count++] = (char)Players[Player_num].secondary_ammo[SMISSILE4_INDEX];
2569 	multibuf[count++] = (char)Players[Player_num].secondary_ammo[SMISSILE5_INDEX];
2570 
2571 	*(ushort *)(multibuf+count) = INTEL_SHORT( (ushort)Players[Player_num].primary_ammo[VULCAN_INDEX] );
2572 	count += 2;
2573 	*(ushort *)(multibuf+count) = INTEL_SHORT( (ushort)Players[Player_num].primary_ammo[GAUSS_INDEX] );
2574 	count += 2;
2575 	*(uint *)(multibuf+count) = INTEL_INT( (uint)Players[Player_num].flags );
2576 	count += 4;
2577 
2578 	multibuf[count++] = Net_create_loc;
2579 
2580 	Assert(Net_create_loc <= MAX_NET_CREATE_OBJECTS);
2581 
2582 	memset(multibuf+count, -1, MAX_NET_CREATE_OBJECTS*sizeof(short));
2583 
2584 	mprintf((0, "Created %d explosion objects.\n", Net_create_loc));
2585 
2586 	for (i = 0; i < Net_create_loc; i++)
2587 	{
2588 		if (Net_create_objnums[i] <= 0) {
2589 			Int3(); // Illegal value in created egg object numbers
2590 			count +=2;
2591 			continue;
2592 		}
2593 
2594 		*(short *)(multibuf+count) = INTEL_SHORT( (short)Net_create_objnums[i] ); count += 2;
2595 
2596 		// We created these objs so our local number = the network number
2597 		map_objnum_local_to_local((short)Net_create_objnums[i]);
2598 	}
2599 
2600 	Net_create_loc = 0;
2601 
2602 	//      mprintf((1, "explode message size = %d, max = %d.\n", count, message_length[MULTI_PLAYER_EXPLODE]));
2603 
2604 	if (count > message_length[MULTI_PLAYER_EXPLODE])
2605 	{
2606 		Int3(); // See Rob
2607 	}
2608 
2609 	multi_send_data(multibuf, message_length[MULTI_PLAYER_EXPLODE], 2);
2610 	if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)
2611 		multi_send_decloak();
2612 	if (Game_mode & GM_MULTI_ROBOTS)
2613 		multi_strip_robots(Player_num);
2614 }
2615 
2616 extern ubyte Secondary_weapon_to_powerup[];
2617 extern ubyte Primary_weapon_to_powerup[];
2618 
2619 // put a lid on how many objects will be spewed by an exploding player
2620 // to prevent rampant powerups in netgames
2621 
multi_cap_objects()2622 void multi_cap_objects ()
2623 {
2624 	char type,flagtype;
2625 	int index;
2626 
2627 	if (!(Game_mode & GM_NETWORK))
2628 		return;
2629 
2630 	for (index=0;index<MAX_PRIMARY_WEAPONS;index++)
2631 	{
2632 		type=Primary_weapon_to_powerup[index];
2633 		if (PowerupsInMine[(int)type]>=MaxPowerupsAllowed[(int)type])
2634 			if(Players[Player_num].primary_weapon_flags & (1 << index))
2635 			{
2636 				mprintf ((0,"PIM=%d MPA=%d\n",PowerupsInMine[(int)type],MaxPowerupsAllowed[(int)type]));
2637 				mprintf ((0,"Killing a primary cuz there's too many! (%d)\n",(int)type));
2638 				Players[Player_num].primary_weapon_flags&=(~(1 << index));
2639 			}
2640 	}
2641 
2642 
2643 	// Don't do the adjustment stuff for Hoard mode
2644 	if (!(Game_mode & GM_HOARD))
2645 		Players[Player_num].secondary_ammo[2]/=4;
2646 
2647 	Players[Player_num].secondary_ammo[7]/=4;
2648 
2649 	for (index=0;index<MAX_SECONDARY_WEAPONS;index++)
2650 	{
2651 		if ((Game_mode & GM_HOARD) && index==PROXIMITY_INDEX)
2652 			continue;
2653 
2654 		type=Secondary_weapon_to_powerup[index];
2655 
2656 		if ((Players[Player_num].secondary_ammo[index]+PowerupsInMine[(int)type])>MaxPowerupsAllowed[(int)type])
2657 		{
2658 			if (MaxPowerupsAllowed[(int)type]-PowerupsInMine[(int)type]<0)
2659 				Players[Player_num].secondary_ammo[index]=0;
2660 			else
2661 				Players[Player_num].secondary_ammo[index]=(MaxPowerupsAllowed[(int)type]-PowerupsInMine[(int)type]);
2662 
2663 			mprintf ((0,"Hey! I killed secondary type %d because PIM=%d MPA=%d\n",(int)type,PowerupsInMine[(int)type],MaxPowerupsAllowed[(int)type]));
2664 		}
2665 	}
2666 
2667 	if (!(Game_mode & GM_HOARD))
2668 		Players[Player_num].secondary_ammo[2]*=4;
2669 	Players[Player_num].secondary_ammo[7]*=4;
2670 
2671 	if (Players[Player_num].laser_level > MAX_LASER_LEVEL)
2672 		if (PowerupsInMine[POW_SUPER_LASER]+1 > MaxPowerupsAllowed[POW_SUPER_LASER])
2673 			Players[Player_num].laser_level=0;
2674 
2675 	if (Players[Player_num].flags & PLAYER_FLAGS_QUAD_LASERS)
2676 		if (PowerupsInMine[POW_QUAD_FIRE]+1 > MaxPowerupsAllowed[POW_QUAD_FIRE])
2677 			Players[Player_num].flags&=(~PLAYER_FLAGS_QUAD_LASERS);
2678 
2679 	if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)
2680 		if (PowerupsInMine[POW_CLOAK]+1 > MaxPowerupsAllowed[POW_CLOAK])
2681 			Players[Player_num].flags&=(~PLAYER_FLAGS_CLOAKED);
2682 
2683 	if (Players[Player_num].flags & PLAYER_FLAGS_MAP_ALL)
2684 		if (PowerupsInMine[POW_FULL_MAP]+1 > MaxPowerupsAllowed[POW_FULL_MAP])
2685 			Players[Player_num].flags&=(~PLAYER_FLAGS_MAP_ALL);
2686 
2687 	if (Players[Player_num].flags & PLAYER_FLAGS_AFTERBURNER)
2688 		if (PowerupsInMine[POW_AFTERBURNER]+1 > MaxPowerupsAllowed[POW_AFTERBURNER])
2689 			Players[Player_num].flags&=(~PLAYER_FLAGS_AFTERBURNER);
2690 
2691 	if (Players[Player_num].flags & PLAYER_FLAGS_AMMO_RACK)
2692 		if (PowerupsInMine[POW_AMMO_RACK]+1 > MaxPowerupsAllowed[POW_AMMO_RACK])
2693 			Players[Player_num].flags&=(~PLAYER_FLAGS_AMMO_RACK);
2694 
2695 	if (Players[Player_num].flags & PLAYER_FLAGS_CONVERTER)
2696 		if (PowerupsInMine[POW_CONVERTER]+1 > MaxPowerupsAllowed[POW_CONVERTER])
2697 			Players[Player_num].flags&=(~PLAYER_FLAGS_CONVERTER);
2698 
2699 	if (Players[Player_num].flags & PLAYER_FLAGS_HEADLIGHT)
2700 		if (PowerupsInMine[POW_HEADLIGHT]+1 > MaxPowerupsAllowed[POW_HEADLIGHT])
2701 			Players[Player_num].flags&=(~PLAYER_FLAGS_HEADLIGHT);
2702 
2703 	if (Game_mode & GM_CAPTURE)
2704 	{
2705 		if (Players[Player_num].flags & PLAYER_FLAGS_FLAG)
2706 		{
2707 			if (get_team(Player_num)==TEAM_RED)
2708 				flagtype=POW_FLAG_BLUE;
2709 			else
2710 				flagtype=POW_FLAG_RED;
2711 
2712 			if (PowerupsInMine[(int)flagtype]+1 > MaxPowerupsAllowed[(int)flagtype])
2713 				Players[Player_num].flags&=(~PLAYER_FLAGS_FLAG);
2714 		}
2715 	}
2716 
2717 }
2718 
2719 // adds players inventory to multi cap
2720 
multi_adjust_cap_for_player(int pnum)2721 void multi_adjust_cap_for_player (int pnum)
2722 {
2723 	char type;
2724 
2725 	int index;
2726 
2727 	if (!(Game_mode & GM_NETWORK))
2728 		return;
2729 
2730 	for (index=0;index<MAX_PRIMARY_WEAPONS;index++)
2731 	{
2732 		type=Primary_weapon_to_powerup[index];
2733 		if (Players[pnum].primary_weapon_flags & (1 << index))
2734 		    MaxPowerupsAllowed[(int)type]++;
2735 	}
2736 
2737 	for (index=0;index<MAX_SECONDARY_WEAPONS;index++)
2738 	{
2739 		type=Secondary_weapon_to_powerup[index];
2740 		MaxPowerupsAllowed[(int)type]+=Players[pnum].secondary_ammo[index];
2741 	}
2742 
2743 	if (Players[pnum].laser_level > MAX_LASER_LEVEL)
2744 		MaxPowerupsAllowed[POW_SUPER_LASER]++;
2745 
2746 	if (Players[pnum].flags & PLAYER_FLAGS_QUAD_LASERS)
2747 		MaxPowerupsAllowed[POW_QUAD_FIRE]++;
2748 
2749 	if (Players[pnum].flags & PLAYER_FLAGS_CLOAKED)
2750 		MaxPowerupsAllowed[POW_CLOAK]++;
2751 
2752 	if (Players[pnum].flags & PLAYER_FLAGS_MAP_ALL)
2753 		MaxPowerupsAllowed[POW_FULL_MAP]++;
2754 
2755 	if (Players[pnum].flags & PLAYER_FLAGS_AFTERBURNER)
2756 		MaxPowerupsAllowed[POW_AFTERBURNER]++;
2757 
2758 	if (Players[pnum].flags & PLAYER_FLAGS_AMMO_RACK)
2759 		MaxPowerupsAllowed[POW_AMMO_RACK]++;
2760 
2761 	if (Players[pnum].flags & PLAYER_FLAGS_CONVERTER)
2762 		MaxPowerupsAllowed[POW_CONVERTER]++;
2763 
2764 	if (Players[pnum].flags & PLAYER_FLAGS_HEADLIGHT)
2765 		MaxPowerupsAllowed[POW_HEADLIGHT]++;
2766 }
2767 
multi_adjust_remote_cap(int pnum)2768 void multi_adjust_remote_cap (int pnum)
2769 {
2770 	char type;
2771 
2772 	int index;
2773 
2774 	if (!(Game_mode & GM_NETWORK))
2775 		return;
2776 
2777 	for (index=0;index<MAX_PRIMARY_WEAPONS;index++)
2778 	{
2779 		type=Primary_weapon_to_powerup[index];
2780 		if (Players[pnum].primary_weapon_flags & (1 << index))
2781 		    PowerupsInMine[(int)type]++;
2782 	}
2783 
2784 	for (index=0;index<MAX_SECONDARY_WEAPONS;index++)
2785 	{
2786 		type=Secondary_weapon_to_powerup[index];
2787 
2788 		if ((Game_mode & GM_HOARD) && index==2)
2789 			continue;
2790 
2791 		if (index==2 || index==7) // PROX or SMARTMINES? Those bastards...
2792 			PowerupsInMine[(int)type]+=(Players[pnum].secondary_ammo[index]/4);
2793 		else
2794 			PowerupsInMine[(int)type]+=Players[pnum].secondary_ammo[index];
2795 
2796 	}
2797 
2798 	if (Players[pnum].laser_level > MAX_LASER_LEVEL)
2799 		PowerupsInMine[POW_SUPER_LASER]++;
2800 
2801 	if (Players[pnum].flags & PLAYER_FLAGS_QUAD_LASERS)
2802 		PowerupsInMine[POW_QUAD_FIRE]++;
2803 
2804 	if (Players[pnum].flags & PLAYER_FLAGS_CLOAKED)
2805 		PowerupsInMine[POW_CLOAK]++;
2806 
2807 	if (Players[pnum].flags & PLAYER_FLAGS_MAP_ALL)
2808 		PowerupsInMine[POW_FULL_MAP]++;
2809 
2810 	if (Players[pnum].flags & PLAYER_FLAGS_AFTERBURNER)
2811 		PowerupsInMine[POW_AFTERBURNER]++;
2812 
2813 	if (Players[pnum].flags & PLAYER_FLAGS_AMMO_RACK)
2814 		PowerupsInMine[POW_AMMO_RACK]++;
2815 
2816 	if (Players[pnum].flags & PLAYER_FLAGS_CONVERTER)
2817 		PowerupsInMine[POW_CONVERTER]++;
2818 
2819 	if (Players[pnum].flags & PLAYER_FLAGS_HEADLIGHT)
2820 		PowerupsInMine[POW_HEADLIGHT]++;
2821 
2822 }
2823 
2824 void
multi_send_message(void)2825 multi_send_message(void)
2826 {
2827 	int loc = 0;
2828 	if (Network_message_reciever != -1)
2829 	{
2830 		multibuf[loc] = (char)MULTI_MESSAGE;            loc += 1;
2831 		multibuf[loc] = (char)Player_num;                       loc += 1;
2832 		strncpy(multibuf+loc, Network_message, MAX_MESSAGE_LEN); loc += MAX_MESSAGE_LEN;
2833 		multibuf[loc-1] = '\0';
2834 		multi_send_data(multibuf, loc, 0);
2835 		Network_message_reciever = -1;
2836 	}
2837 }
2838 
2839 void
multi_send_reappear()2840 multi_send_reappear()
2841 {
2842 	multibuf[0] = (char)MULTI_REAPPEAR;
2843 	*(short *)(multibuf+1) = INTEL_SHORT(Players[Player_num].objnum);
2844 
2845 	multi_send_data(multibuf, 3, 2);
2846 	PKilledFlags[Player_num]=0;
2847 }
2848 
2849 void
multi_send_position(int objnum)2850 multi_send_position(int objnum)
2851 {
2852 #ifdef MACINTOSH
2853 	shortpos sp;
2854 #endif
2855 	int count=0;
2856 
2857 	if (Game_mode & GM_NETWORK) {
2858 		return;
2859 	}
2860 
2861 	multibuf[count++] = (char)MULTI_POSITION;
2862 #ifndef MACINTOSH
2863 	create_shortpos((shortpos *)(multibuf+count), Objects+objnum,0);
2864 	count += sizeof(shortpos);
2865 #else
2866 	create_shortpos(&sp, Objects+objnum, 1);
2867 	memcpy(&(multibuf[count]), (ubyte *)(sp.bytemat), 9);
2868 	count += 9;
2869 	memcpy(&(multibuf[count]), (ubyte *)&(sp.xo), 14);
2870 	count += 14;
2871 #endif
2872 
2873 	multi_send_data(multibuf, count, 0);
2874 }
2875 
2876 void
multi_send_kill(int objnum)2877 multi_send_kill(int objnum)
2878 {
2879 	// I died, tell the world.
2880 
2881 	int killer_objnum;
2882 	int count = 0;
2883 
2884 	Assert(Objects[objnum].id == Player_num);
2885 	killer_objnum = Players[Player_num].killer_objnum;
2886 
2887 	multi_compute_kill(killer_objnum, objnum);
2888 
2889 	multibuf[0] = (char)MULTI_KILL;     count += 1;
2890 	multibuf[1] = Player_num;           count += 1;
2891 	if (killer_objnum > -1) {
2892 		short s;		// do it with variable since INTEL_SHORT won't work on return val from function.
2893 
2894 		s = (short)objnum_local_to_remote(killer_objnum, (byte *)&multibuf[count+2]);
2895 		*(short *)(multibuf+count) = INTEL_SHORT(s);
2896 	}
2897 	else
2898 	{
2899 		*(short *)(multibuf+count) = INTEL_SHORT((short)-1);
2900 		multibuf[count+2] = (char)-1;
2901 	}
2902 	count += 3;
2903 	multi_send_data(multibuf, count, 1);
2904 
2905 #ifndef SHAREWARE
2906 	if (Game_mode & GM_MULTI_ROBOTS)
2907 		multi_strip_robots(Player_num);
2908 #endif
2909 }
2910 
2911 void
multi_send_remobj(int objnum)2912 multi_send_remobj(int objnum)
2913 {
2914 	// Tell the other guy to remove an object from his list
2915 
2916 	byte obj_owner;
2917 	short remote_objnum;
2918 
2919 	if (Objects[objnum].type==OBJ_POWERUP && (Game_mode & GM_NETWORK))
2920     {
2921 		if (PowerupsInMine[Objects[objnum].id] > 0)
2922 		{
2923 			PowerupsInMine[Objects[objnum].id]--;
2924 			if (multi_powerup_is_4pack (Objects[objnum].id))
2925 			{
2926 				mprintf ((0,"Hey babe! Doing that wacky 4 pack stuff."));
2927 
2928 				if (PowerupsInMine[Objects[objnum].id-1]-4<0)
2929 					PowerupsInMine[Objects[objnum].id-1]=0;
2930 				else
2931 					PowerupsInMine[Objects[objnum].id-1]-=4;
2932 			}
2933 		}
2934 
2935 	}
2936 
2937 	multibuf[0] = (char)MULTI_REMOVE_OBJECT;
2938 
2939 	remote_objnum = objnum_local_to_remote((short)objnum, &obj_owner);
2940 
2941 	*(short *)(multibuf+1) = INTEL_SHORT(remote_objnum); // Map to network objnums
2942 
2943 	multibuf[3] = obj_owner;
2944 
2945 	//      mprintf((0, "multi_send_remobj: %d = %d owner %d.\n", objnum, remote_objnum, obj_owner));
2946 
2947 	multi_send_data(multibuf, 4, 0);
2948 
2949 	if (Network_send_objects && network_objnum_is_past(objnum))
2950 	{
2951 		mprintf((0, "Resetting object sync due to object removal.\n"));
2952 		Network_send_objnum = -1;
2953 	}
2954 }
2955 
2956 void
multi_send_quit(int why)2957 multi_send_quit(int why)
2958 {
2959 	// I am quitting the game, tell the other guy the bad news.
2960 
2961 	Assert (why == MULTI_QUIT);
2962 
2963 	multibuf[0] = (char)why;
2964 	multibuf[1] = Player_num;
2965 	multi_send_data(multibuf, 2, 1);
2966 
2967 }
2968 
2969 void
multi_send_cloak(void)2970 multi_send_cloak(void)
2971 {
2972 	// Broadcast a change in our pflags (made to support cloaking)
2973 
2974 	multibuf[0] = MULTI_CLOAK;
2975 	multibuf[1] = (char)Player_num;
2976 
2977 	multi_send_data(multibuf, 2, 1);
2978 
2979 #ifndef SHAREWARE
2980 	if (Game_mode & GM_MULTI_ROBOTS)
2981 		multi_strip_robots(Player_num);
2982 #endif
2983 }
2984 
2985 void
multi_send_decloak(void)2986 multi_send_decloak(void)
2987 {
2988 	// Broadcast a change in our pflags (made to support cloaking)
2989 
2990 	multibuf[0] = MULTI_DECLOAK;
2991 	multibuf[1] = (char)Player_num;
2992 
2993 	multi_send_data(multibuf, 2, 1);
2994 }
2995 
2996 void
multi_send_door_open(int segnum,int side,ubyte flag)2997 multi_send_door_open(int segnum, int side,ubyte flag)
2998 {
2999 	// When we open a door make sure everyone else opens that door
3000 
3001 	multibuf[0] = MULTI_DOOR_OPEN;
3002 	*(short *)(multibuf+1) = INTEL_SHORT( (short)segnum );
3003 	multibuf[3] = (byte)side;
3004 	multibuf[4] = flag;
3005 
3006 	multi_send_data(multibuf, 5, 2);
3007 }
3008 
3009 extern void network_send_naked_packet (char *,short,int);
3010 
3011 void
multi_send_door_open_specific(int pnum,int segnum,int side,ubyte flag)3012 multi_send_door_open_specific(int pnum,int segnum, int side,ubyte flag)
3013 {
3014 	// For sending doors only to a specific person (usually when they're joining)
3015 
3016 	Assert (Game_mode & GM_NETWORK);
3017 	//   Assert (pnum>-1 && pnum<N_players);
3018 
3019 	multibuf[0] = MULTI_DOOR_OPEN;
3020 	*(short *)(multibuf+1) = INTEL_SHORT( (short)segnum );
3021 	multibuf[3] = (byte)side;
3022 	multibuf[4] = flag;
3023 
3024 	network_send_naked_packet(multibuf, 5, pnum);
3025 }
3026 
3027 //
3028 // Part 3 : Functions that change or prepare the game for multiplayer use.
3029 //          Not including functions needed to syncronize or start the
3030 //          particular type of multiplayer game.  Includes preparing the
3031 //                      mines, player structures, etc.
3032 
3033 void
multi_send_create_explosion(int pnum)3034 multi_send_create_explosion(int pnum)
3035 {
3036 	// Send all data needed to create a remote explosion
3037 
3038 	int count = 0;
3039 
3040 	multibuf[count] = MULTI_CREATE_EXPLOSION;       count += 1;
3041 	multibuf[count] = (byte)pnum;                                   count += 1;
3042 	//                                                                                                      -----------
3043 	//                                                                                                      Total size = 2
3044 
3045 	multi_send_data(multibuf, count, 0);
3046 }
3047 
3048 void
multi_send_controlcen_fire(vms_vector * to_goal,int best_gun_num,int objnum)3049 multi_send_controlcen_fire(vms_vector *to_goal, int best_gun_num, int objnum)
3050 {
3051 #ifdef MACINTOSH
3052 	vms_vector swapped_vec;
3053 #endif
3054 	int count = 0;
3055 
3056 	multibuf[count] = MULTI_CONTROLCEN_FIRE;                count +=  1;
3057 #ifndef MACINTOSH
3058 	memcpy(multibuf+count, to_goal, 12);                    count += 12;
3059 #else
3060 	swapped_vec.x = (fix)INTEL_INT( (int)to_goal->x );
3061 	swapped_vec.y = (fix)INTEL_INT( (int)to_goal->y );
3062 	swapped_vec.z = (fix)INTEL_INT( (int)to_goal->z );
3063 	memcpy(multibuf+count, &swapped_vec, 12);				count += 12;
3064 #endif
3065 	multibuf[count] = (char)best_gun_num;                   count +=  1;
3066 	*(short *)(multibuf+count) = INTEL_SHORT( (short)objnum );     count +=  2;
3067 	//                                                                                                                      ------------
3068 	//                                                                                                                      Total  = 16
3069 	multi_send_data(multibuf, count, 0);
3070 }
3071 
3072 void
multi_send_create_powerup(int powerup_type,int segnum,int objnum,vms_vector * pos)3073 multi_send_create_powerup(int powerup_type, int segnum, int objnum, vms_vector *pos)
3074 {
3075 	// Create a powerup on a remote machine, used for remote
3076 	// placement of used powerups like missiles and cloaking
3077 	// powerups.
3078 
3079 #ifdef MACINTOSH
3080 	vms_vector swapped_vec;
3081 #endif
3082 	int count = 0;
3083 
3084 	if (Game_mode & GM_NETWORK)
3085 		PowerupsInMine[powerup_type]++;
3086 
3087 	multibuf[count] = MULTI_CREATE_POWERUP;         count += 1;
3088 	multibuf[count] = Player_num;                                      count += 1;
3089 	multibuf[count] = powerup_type;                                 count += 1;
3090 	*(short *)(multibuf+count) = INTEL_SHORT( (short)segnum );     count += 2;
3091 	*(short *)(multibuf+count) = INTEL_SHORT( (short)objnum );     count += 2;
3092 #ifndef MACINTOSH
3093 	*(vms_vector *)(multibuf+count) = *pos;         count += sizeof(vms_vector);
3094 #else
3095 	swapped_vec.x = (fix)INTEL_INT( (int)pos->x );
3096 	swapped_vec.y = (fix)INTEL_INT( (int)pos->y );
3097 	swapped_vec.z = (fix)INTEL_INT( (int)pos->z );
3098 	memcpy(multibuf+count, &swapped_vec, 12);				count += 12;
3099 #endif
3100 	//                                                                                                            -----------
3101 	//                                                                                                            Total =  19
3102 	multi_send_data(multibuf, count, 2);
3103 
3104 	if (Network_send_objects && network_objnum_is_past(objnum))
3105 	{
3106 		mprintf((0, "Resetting object sync due to powerup creation.\n"));
3107 		Network_send_objnum = -1;
3108 	}
3109 
3110 	mprintf((0, "Creating powerup type %d in segment %i.\n", powerup_type, segnum));
3111 	map_objnum_local_to_local(objnum);
3112 }
3113 
3114 void
multi_send_play_sound(int sound_num,fix volume)3115 multi_send_play_sound(int sound_num, fix volume)
3116 {
3117 	int count = 0;
3118 	multibuf[count] = MULTI_PLAY_SOUND;                     count += 1;
3119 	multibuf[count] = Player_num;                                   count += 1;
3120 	multibuf[count] = (char)sound_num;                      count += 1;
3121 	multibuf[count] = (char)(volume >> 12); count += 1;
3122 	//                                                                                                         -----------
3123 	//                                                                                                         Total = 4
3124 	multi_send_data(multibuf, count, 0);
3125 }
3126 
3127 void
multi_send_audio_taunt(int taunt_num)3128 multi_send_audio_taunt(int taunt_num)
3129 {
3130 	return; // Taken out, awaiting sounds..
3131 
3132 #if 0
3133 	int audio_taunts[4] = {
3134 		SOUND_CONTROL_CENTER_WARNING_SIREN,
3135 		SOUND_HOSTAGE_RESCUED,
3136 		SOUND_REFUEL_STATION_GIVING_FUEL,
3137 		SOUND_BAD_SELECTION
3138 	};
3139 
3140 
3141 	Assert(taunt_num >= 0);
3142 	Assert(taunt_num < 4);
3143 
3144 	digi_play_sample( audio_taunts[taunt_num], F1_0 );
3145 	multi_send_play_sound(audio_taunts[taunt_num], F1_0);
3146 #endif
3147 }
3148 
3149 void
multi_send_score(void)3150 multi_send_score(void)
3151 {
3152 	// Send my current score to all other players so it will remain
3153 	// synced.
3154 	int count = 0;
3155 
3156 	if (Game_mode & GM_MULTI_COOP) {
3157 		multi_sort_kill_list();
3158 		multibuf[count] = MULTI_SCORE;                  count += 1;
3159 		multibuf[count] = Player_num;                           count += 1;
3160 		*(int *)(multibuf+count) = INTEL_INT( Players[Player_num].score );  count += 4;
3161 		multi_send_data(multibuf, count, 0);
3162 	}
3163 }
3164 
3165 
3166 void
multi_send_save_game(ubyte slot,uint id,char * desc)3167 multi_send_save_game(ubyte slot, uint id, char * desc)
3168 {
3169 	int count = 0;
3170 
3171 	multibuf[count] = MULTI_SAVE_GAME;              count += 1;
3172 	multibuf[count] = slot;                         count += 1;    // Save slot=0
3173 	*(uint *)(multibuf+count) = INTEL_INT( id );         count += 4;             // Save id
3174 	memcpy( &multibuf[count], desc, 20 ); count += 20;
3175 
3176 	multi_send_data(multibuf, count, 2);
3177 }
3178 
3179 void
multi_send_restore_game(ubyte slot,uint id)3180 multi_send_restore_game(ubyte slot, uint id)
3181 {
3182 	int count = 0;
3183 
3184 	multibuf[count] = MULTI_RESTORE_GAME;   count += 1;
3185 	multibuf[count] = slot;                                                 count += 1;             // Save slot=0
3186 	*(uint *)(multibuf+count) = INTEL_INT( id );         count += 4;             // Save id
3187 
3188 	multi_send_data(multibuf, count, 2);
3189 }
3190 
3191 void
multi_send_netplayer_stats_request(ubyte player_num)3192 multi_send_netplayer_stats_request(ubyte player_num)
3193 {
3194 	int count = 0;
3195 
3196 	multibuf[count] = MULTI_REQ_PLAYER;     count += 1;
3197 	multibuf[count] = player_num;                   count += 1;
3198 
3199 	multi_send_data(multibuf, count, 0 );
3200 }
3201 
3202 void
multi_send_trigger(int triggernum)3203 multi_send_trigger(int triggernum)
3204 {
3205 	// Send an even to trigger something in the mine
3206 
3207 	int count = 0;
3208 
3209 	multibuf[count] = MULTI_TRIGGER;                                count += 1;
3210 	multibuf[count] = Player_num;                                   count += 1;
3211 	multibuf[count] = (ubyte)triggernum;            count += 1;
3212 
3213 	mprintf ((0,"Sending trigger %d\n",triggernum));
3214 
3215 	multi_send_data(multibuf, count, 1);
3216 	//multi_send_data(multibuf, count, 1); // twice?
3217 }
3218 
3219 void
multi_send_hostage_door_status(int wallnum)3220 multi_send_hostage_door_status(int wallnum)
3221 {
3222 	// Tell the other player what the hit point status of a hostage door
3223 	// should be
3224 
3225 	int count = 0;
3226 
3227 	Assert(Walls[wallnum].type == WALL_BLASTABLE);
3228 
3229 	multibuf[count] = MULTI_HOSTAGE_DOOR;           count += 1;
3230 	*(short *)(multibuf+count) = INTEL_SHORT( (short)wallnum );           count += 2;
3231 	*(fix *)(multibuf+count) = (fix)INTEL_INT( (int)Walls[wallnum].hps );  count += 4;
3232 
3233 	//      mprintf((0, "Door %d damaged by %f points.\n", wallnum, f2fl(Walls[wallnum].hps)));
3234 
3235 	multi_send_data(multibuf, count, 0);
3236 }
3237 
3238 extern int ConsistencyCount;
3239 extern int Drop_afterburner_blob_flag;
3240 int PhallicLimit=0;
3241 int PhallicMan=-1;
3242 
multi_prep_level(void)3243 void multi_prep_level(void)
3244 {
3245 	// Do any special stuff to the level required for serial games
3246 	// before we begin playing in it.
3247 
3248 	// Player_num MUST be set before calling this procedure.
3249 
3250 	// This function must be called before checksuming the Object array,
3251 	// since the resulting checksum with depend on the value of Player_num
3252 	// at the time this is called.
3253 
3254 	int i,ng=0;
3255 	int     cloak_count, inv_count;
3256 
3257 	Assert(Game_mode & GM_MULTI);
3258 
3259 	Assert(NumNetPlayerPositions > 0);
3260 
3261 	PhallicLimit=0;
3262 	PhallicMan=-1;
3263 	Drop_afterburner_blob_flag=0;
3264 	ConsistencyCount=0;
3265 
3266 	for (i=0;i<MAX_NUM_NET_PLAYERS;i++)
3267 		PKilledFlags[i]=0;
3268 
3269 	for (i = 0; i < NumNetPlayerPositions; i++)
3270 	{
3271 		if (i != Player_num)
3272 			Objects[Players[i].objnum].control_type = CT_REMOTE;
3273 		Objects[Players[i].objnum].movement_type = MT_PHYSICS;
3274 		multi_reset_player_object(&Objects[Players[i].objnum]);
3275 		LastPacketTime[i] = 0;
3276 	}
3277 
3278 #ifndef SHAREWARE
3279 	for (i = 0; i < MAX_ROBOTS_CONTROLLED; i++)
3280 	{
3281 		robot_controlled[i] = -1;
3282 		robot_agitation[i] = 0;
3283 		robot_fired[i] = 0;
3284 	}
3285 #endif
3286 
3287 	Viewer = ConsoleObject = &Objects[Players[Player_num].objnum];
3288 
3289 	if (!(Game_mode & GM_MULTI_COOP))
3290 	{
3291 		multi_delete_extra_objects(); // Removes monsters from level
3292 	}
3293 
3294 	if (Game_mode & GM_MULTI_ROBOTS)
3295 	{
3296 		multi_set_robot_ai(); // Set all Robot AI to types we can cope with
3297 	}
3298 
3299 	if (Game_mode & GM_NETWORK)
3300 	{
3301 		multi_adjust_cap_for_player(Player_num);
3302 		multi_send_powerup_update();
3303 		ng=1;  // ng means network game
3304 	}
3305 	ng=1;
3306 
3307 	inv_count = 0;
3308 	cloak_count = 0;
3309 	for (i=0; i<=Highest_object_index; i++)
3310 	{
3311 		int objnum;
3312 
3313 		if ((Objects[i].type == OBJ_HOSTAGE) && !(Game_mode & GM_MULTI_COOP))
3314 		{
3315 			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);
3316 			obj_delete(i);
3317 			if (objnum != -1)
3318 			{
3319 				Objects[objnum].rtype.vclip_info.vclip_num = Powerup_info[POW_SHIELD_BOOST].vclip_num;
3320 				Objects[objnum].rtype.vclip_info.frametime = Vclip[Objects[objnum].rtype.vclip_info.vclip_num].frame_time;
3321 				Objects[objnum].rtype.vclip_info.framenum = 0;
3322 				Objects[objnum].mtype.phys_info.drag = 512;     //1024;
3323 				Objects[objnum].mtype.phys_info.mass = F1_0;
3324 				vm_vec_zero(&Objects[objnum].mtype.phys_info.velocity);
3325 			}
3326 			continue;
3327 		}
3328 
3329 		if (Objects[i].type == OBJ_POWERUP)
3330 		{
3331 			if (Objects[i].id == POW_EXTRA_LIFE)
3332 			{
3333 				if (ng && !Netgame.DoInvulnerability)
3334 				{
3335 					Objects[i].id = POW_SHIELD_BOOST;
3336 					Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num;
3337 					Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time;
3338 				}
3339 				else
3340 				{
3341 					Objects[i].id = POW_INVULNERABILITY;
3342 					Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num;
3343 					Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time;
3344 				}
3345 
3346 			}
3347 
3348 			if (!(Game_mode & GM_MULTI_COOP))
3349 				if ((Objects[i].id >= POW_KEY_BLUE) && (Objects[i].id <= POW_KEY_GOLD))
3350 				{
3351 					Objects[i].id = POW_SHIELD_BOOST;
3352 					Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num;
3353 					Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time;
3354 				}
3355 
3356 			if (Objects[i].id == POW_INVULNERABILITY) {
3357 				if (inv_count >= 3 || (ng && !Netgame.DoInvulnerability)) {
3358 					mprintf((0, "Bashing Invulnerability object #%i to shield.\n", i));
3359 					Objects[i].id = POW_SHIELD_BOOST;
3360 					Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num;
3361 					Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time;
3362 				} else
3363 					inv_count++;
3364 			}
3365 
3366 			if (Objects[i].id == POW_CLOAK) {
3367 				if (cloak_count >= 3 || (ng && !Netgame.DoCloak)) {
3368 					mprintf((0, "Bashing Cloak object #%i to shield.\n", i));
3369 					Objects[i].id = POW_SHIELD_BOOST;
3370 					Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num;
3371 					Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time;
3372 				} else
3373 					cloak_count++;
3374 			}
3375 
3376 			if (Objects[i].id == POW_AFTERBURNER && ng && !Netgame.DoAfterburner)
3377 				bash_to_shield (i,"afterburner");
3378 			if (Objects[i].id == POW_FUSION_WEAPON && ng &&  !Netgame.DoFusions)
3379 				bash_to_shield (i,"fusion");
3380 			if (Objects[i].id == POW_PHOENIX_WEAPON && ng && !Netgame.DoPhoenix)
3381 				bash_to_shield (i,"phoenix");
3382 
3383 			if (Objects[i].id == POW_HELIX_WEAPON && ng && !Netgame.DoHelix)
3384 				bash_to_shield (i,"helix");
3385 
3386 			if (Objects[i].id == POW_MEGA_WEAPON && ng && !Netgame.DoMegas)
3387 				bash_to_shield (i,"mega");
3388 
3389 			if (Objects[i].id == POW_SMARTBOMB_WEAPON && ng && !Netgame.DoSmarts)
3390 				bash_to_shield (i,"smartmissile");
3391 
3392 			if (Objects[i].id == POW_GAUSS_WEAPON && ng && !Netgame.DoGauss)
3393 				bash_to_shield (i,"gauss");
3394 
3395 			if (Objects[i].id == POW_VULCAN_WEAPON && ng && !Netgame.DoVulcan)
3396 				bash_to_shield (i,"vulcan");
3397 
3398 			if (Objects[i].id == POW_PLASMA_WEAPON && ng && !Netgame.DoPlasma)
3399 				bash_to_shield (i,"plasma");
3400 
3401 			if (Objects[i].id == POW_OMEGA_WEAPON && ng && !Netgame.DoOmega)
3402 				bash_to_shield (i,"omega");
3403 
3404 			if (Objects[i].id == POW_SUPER_LASER && ng && !Netgame.DoSuperLaser)
3405 				bash_to_shield (i,"superlaser");
3406 
3407 			if (Objects[i].id == POW_PROXIMITY_WEAPON && ng && !Netgame.DoProximity)
3408 				bash_to_shield (i,"proximity");
3409 
3410 			// Special: Make all proximity bombs into shields if in
3411 			// hoard mode because we use the proximity slot in the
3412 			// player struct to signify how many orbs the player has.
3413 
3414 			if (Objects[i].id == POW_PROXIMITY_WEAPON && ng && (Game_mode & GM_HOARD))
3415 				bash_to_shield (i,"proximity");
3416 
3417 			if (Objects[i].id==POW_VULCAN_AMMO && ng && (!Netgame.DoVulcan && !Netgame.DoGauss))
3418 				bash_to_shield(i,"vulcan ammo");
3419 
3420 			if (Objects[i].id == POW_SPREADFIRE_WEAPON && ng && !Netgame.DoSpread)
3421 				bash_to_shield (i,"spread");
3422 			if (Objects[i].id == POW_SMART_MINE && ng && !Netgame.DoSmartMine)
3423 				bash_to_shield (i,"smartmine");
3424 			if (Objects[i].id == POW_SMISSILE1_1 && ng &&  !Netgame.DoFlash)
3425 				bash_to_shield (i,"flash");
3426 			if (Objects[i].id == POW_SMISSILE1_4 && ng &&  !Netgame.DoFlash)
3427 				bash_to_shield (i,"flash");
3428 			if (Objects[i].id == POW_GUIDED_MISSILE_1 && ng &&  !Netgame.DoGuided)
3429 				bash_to_shield (i,"guided");
3430 			if (Objects[i].id == POW_GUIDED_MISSILE_4 && ng &&  !Netgame.DoGuided)
3431 				bash_to_shield (i,"guided");
3432 			if (Objects[i].id == POW_EARTHSHAKER_MISSILE && ng &&  !Netgame.DoEarthShaker)
3433 				bash_to_shield (i,"earth");
3434 			if (Objects[i].id == POW_MERCURY_MISSILE_1 && ng &&  !Netgame.DoMercury)
3435 				bash_to_shield (i,"Mercury");
3436 			if (Objects[i].id == POW_MERCURY_MISSILE_4 && ng &&  !Netgame.DoMercury)
3437 				bash_to_shield (i,"Mercury");
3438 			if (Objects[i].id == POW_CONVERTER && ng &&  !Netgame.DoConverter)
3439 				bash_to_shield (i,"Converter");
3440 			if (Objects[i].id == POW_AMMO_RACK && ng &&  !Netgame.DoAmmoRack)
3441 				bash_to_shield (i,"Ammo rack");
3442 			if (Objects[i].id == POW_HEADLIGHT && ng &&  !Netgame.DoHeadlight)
3443 				bash_to_shield (i,"Headlight");
3444 			if (Objects[i].id == POW_LASER && ng &&  !Netgame.DoLaserUpgrade)
3445 				bash_to_shield (i,"Laser powerup");
3446 			if (Objects[i].id == POW_HOMING_AMMO_1 && ng &&  !Netgame.DoHoming)
3447 				bash_to_shield (i,"Homing");
3448 			if (Objects[i].id == POW_HOMING_AMMO_4 && ng &&  !Netgame.DoHoming)
3449 				bash_to_shield (i,"Homing");
3450 			if (Objects[i].id == POW_QUAD_FIRE && ng &&  !Netgame.DoQuadLasers)
3451 				bash_to_shield (i,"Quad Lasers");
3452 			if (Objects[i].id == POW_FLAG_BLUE && !(Game_mode & GM_CAPTURE))
3453 				bash_to_shield (i,"Blue flag");
3454 			if (Objects[i].id == POW_FLAG_RED && !(Game_mode & GM_CAPTURE))
3455 				bash_to_shield (i,"Red flag");
3456 		}
3457 	}
3458 
3459 	if (Game_mode & GM_HOARD)
3460 		init_hoard_data();
3461 
3462 	if ((Game_mode & GM_CAPTURE) || (Game_mode & GM_HOARD))
3463 		multi_apply_goal_textures();
3464 
3465 	multi_sort_kill_list();
3466 
3467 	multi_show_player_list();
3468 
3469 	ConsoleObject->control_type = CT_FLYING;
3470 
3471 	reset_player_object();
3472 
3473 }
3474 
3475 int Goal_blue_segnum,Goal_red_segnum;
3476 
multi_apply_goal_textures()3477 void multi_apply_goal_textures()
3478 {
3479 	int		i,j,tex;
3480 	segment	*seg;
3481 	segment2	*seg2;
3482 
3483 	for (i=0; i <= Highest_segment_index; i++)
3484 	{
3485 		seg = &Segments[i];
3486 		seg2 = &Segment2s[i];
3487 
3488 		if (seg2->special==SEGMENT_IS_GOAL_BLUE)
3489 		{
3490 
3491 			Goal_blue_segnum = i;
3492 
3493 			if (Game_mode & GM_HOARD)
3494 				tex=find_goal_texture (TMI_GOAL_HOARD);
3495 			else
3496 				tex=find_goal_texture (TMI_GOAL_BLUE);
3497 
3498 			if (tex>-1)
3499 				for (j = 0; j < 6; j++) {
3500 					int v;
3501 					seg->sides[j].tmap_num=tex;
3502 					for (v=0;v<4;v++)
3503 						seg->sides[j].uvls[v].l = i2f(100);		//max out
3504 				}
3505 
3506 			seg2->static_light = i2f(100);	//make static light bright
3507 
3508 		}
3509 
3510 		if (seg2->special==SEGMENT_IS_GOAL_RED)
3511 		{
3512 			Goal_red_segnum = i;
3513 
3514 			// Make both textures the same if Hoard mode
3515 
3516 			if (Game_mode & GM_HOARD)
3517 				tex=find_goal_texture (TMI_GOAL_HOARD);
3518 			else
3519 				tex=find_goal_texture (TMI_GOAL_RED);
3520 
3521 			if (tex>-1)
3522 				for (j = 0; j < 6; j++) {
3523 					int v;
3524 					seg->sides[j].tmap_num=tex;
3525 					for (v=0;v<4;v++)
3526 						seg->sides[j].uvls[v].l = i2f(1000);		//max out
3527 				}
3528 
3529 			seg2->static_light = i2f(100);	//make static light bright
3530 		}
3531 	}
3532 }
find_goal_texture(ubyte t)3533 int find_goal_texture (ubyte t)
3534 {
3535 	int i;
3536 
3537 	for (i=0;i<NumTextures;i++)
3538 		if (TmapInfo[i].flags & t)
3539 			return i;
3540 
3541 	Int3(); // Hey, there is no goal texture for this PIG!!!!
3542 	// Edit bitmaps.tbl and designate two textures to be RED and BLUE
3543 	// goal textures
3544 	return (-1);
3545 }
3546 
3547 
3548 /* DPH: Moved to gameseq.c
3549    void bash_to_shield (int i,char *s)
3550    {
3551    int type=Objects[i].id;
3552 
3553    mprintf((0, "Bashing %s object #%i to shield.\n",s, i));
3554 
3555    PowerupsInMine[type]=MaxPowerupsAllowed[type]=0;
3556 
3557    Objects[i].id = POW_SHIELD_BOOST;
3558    Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num;
3559    Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time;
3560    }
3561 */
3562 
multi_set_robot_ai(void)3563 void multi_set_robot_ai(void)
3564 {
3565 	// Go through the objects array looking for robots and setting
3566 	// them to certain supported types of NET AI behavior.
3567 
3568 	//      int i;
3569 	//
3570 	//      for (i = 0; i <= Highest_object_index; i++)
3571 	//      {
3572 	//              if (Objects[i].type == OBJ_ROBOT) {
3573 	//                      Objects[i].ai_info.REMOTE_OWNER = -1;
3574 	//                      if (Objects[i].ai_info.behavior == AIB_STATION)
3575 	//                              Objects[i].ai_info.behavior = AIB_NORMAL;
3576 	//              }
3577 	//      }
3578 }
3579 
multi_delete_extra_objects()3580 int multi_delete_extra_objects()
3581 {
3582 	int i;
3583 	int nnp=0;
3584 	object *objp;
3585 
3586 	// Go through the object list and remove any objects not used in
3587 	// 'Anarchy!' games.
3588 
3589 	// This function also prints the total number of available multiplayer
3590 	// positions in this level, even though this should always be 8 or more!
3591 
3592 	objp = Objects;
3593 	for (i=0;i<=Highest_object_index;i++) {
3594 		if ((objp->type==OBJ_PLAYER) || (objp->type==OBJ_GHOST))
3595 			nnp++;
3596 		else if ((objp->type==OBJ_ROBOT) && (Game_mode & GM_MULTI_ROBOTS))
3597 			;
3598 		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) ) {
3599 			// Before deleting object, if it's a robot, drop it's special powerup, if any
3600 			if (objp->type == OBJ_ROBOT)
3601 				if (objp->contains_count && (objp->contains_type == OBJ_POWERUP))
3602 					object_create_egg(objp);
3603 			obj_delete(i);
3604 		}
3605 		objp++;
3606 	}
3607 
3608 	return nnp;
3609 }
3610 
change_playernum_to(int new_Player_num)3611 void change_playernum_to( int new_Player_num )
3612 {
3613 	if (Player_num > -1)
3614 		memcpy( Players[new_Player_num].callsign, Players[Player_num].callsign, CALLSIGN_LEN+1 );
3615 	Player_num = new_Player_num;
3616 }
3617 
multi_all_players_alive()3618 int multi_all_players_alive()
3619 {
3620 	int i;
3621 	for (i=0;i<N_players;i++)
3622 	{
3623 		if (PKilledFlags[i] && Players[i].connected)
3624 			return (0);
3625 	}
3626 	return (1);
3627 }
3628 
multi_initiate_save_game()3629 void multi_initiate_save_game()
3630 {
3631 	uint game_id;
3632 	int i, slot;
3633 	char filename[128];
3634 	char desc[24];
3635 
3636 	if ((Endlevel_sequence) || (Control_center_destroyed))
3637 		return;
3638 
3639 	if (!multi_all_players_alive())
3640 	{
3641 		HUD_init_message ("Can't save...all players must be alive!");
3642 		return;
3643 	}
3644 
3645 	//multi_send_netplayer_stats_request(255);
3646 	//return;
3647 
3648 	//stop_time();
3649 
3650 	slot = state_get_save_file(filename, desc, 1 );
3651 	if (!slot)      {
3652 		//start_time();
3653 		return;
3654 	}
3655 	slot--;
3656 
3657 	//start_time();
3658 
3659 	// Make a unique game id
3660 	game_id = timer_get_fixed_seconds();
3661 	game_id ^= N_players<<4;
3662 	for (i=0; i<N_players; i++ )
3663 		game_id ^= *(uint *)Players[i].callsign;
3664 	if ( game_id == 0 ) game_id = 1;                // 0 is invalid
3665 
3666 	mprintf(( 1, "Game_id = %8x\n", game_id));
3667 	multi_send_save_game(slot, game_id, desc );
3668 	multi_do_frame();
3669 	multi_save_game(slot,game_id, desc );
3670 }
3671 
3672 extern int state_get_game_id(char *);
3673 
multi_initiate_restore_game()3674 void multi_initiate_restore_game()
3675 {
3676 	int slot;
3677 	char filename[128];
3678 
3679 	if ((Endlevel_sequence) || (Control_center_destroyed))
3680 		return;
3681 
3682 	if (!multi_all_players_alive())
3683 	{
3684 		HUD_init_message ("Can't restore...all players must be alive!");
3685 		return;
3686 	}
3687 
3688 	//stop_time();
3689 	slot = state_get_restore_file(filename,1);
3690 	if (!slot)      {
3691 		//start_time();
3692 		return;
3693 	}
3694 	state_game_id=state_get_game_id (filename);
3695 	if (!state_game_id)
3696 		return;
3697 
3698 	slot--;
3699 	//start_time();
3700 	multi_send_restore_game(slot,state_game_id);
3701 	multi_do_frame();
3702 	multi_restore_game(slot,state_game_id);
3703 }
3704 
multi_save_game(ubyte slot,uint id,char * desc)3705 void multi_save_game(ubyte slot, uint id, char *desc)
3706 {
3707 	char filename[128];
3708 
3709 	if ((Endlevel_sequence) || (Control_center_destroyed))
3710 		return;
3711 
3712 #ifndef MACINTOSH
3713 	sprintf( filename, "%s.mg%d", Players[Player_num].callsign, slot );
3714 #else
3715 	sprintf( filename, ":Players:%s.mg%d", Players[Player_num].callsign, slot );
3716 #endif
3717 	mprintf(( 0, "Save game %x on slot %d\n", id, slot ));
3718 	HUD_init_message( "Saving game #%d, '%s'", slot, desc );
3719 	stop_time();
3720 	state_game_id = id;
3721 	state_save_all_sub(filename, desc, 0 );
3722 }
3723 
multi_restore_game(ubyte slot,uint id)3724 void multi_restore_game(ubyte slot, uint id)
3725 {
3726 	char filename[128];
3727 	player saved_player;
3728 	int pnum,i;
3729 	int thisid;
3730 
3731 	if ((Endlevel_sequence) || (Control_center_destroyed))
3732 		return;
3733 
3734 	mprintf(( 0, "Restore game %x from slot %d\n", id, slot ));
3735 	saved_player = Players[Player_num];
3736 #ifndef MACINTOSH
3737 	sprintf( filename, "%s.mg%d", Players[Player_num].callsign, slot );
3738 #else
3739 	sprintf( filename, ":Players:%s.mg%d", Players[Player_num].callsign, slot );
3740 #endif
3741 
3742 	for (i=0;i<N_players;i++)
3743 		multi_strip_robots(i);
3744 
3745 	thisid=state_get_game_id (filename);
3746 	if (thisid!=id)
3747 	{
3748 		multi_bad_restore ();
3749 		return;
3750 	}
3751 
3752 	pnum=state_restore_all_sub( filename, 1, 0 );
3753 
3754 	mprintf ((0,"StateId=%d ThisID=%d\n",state_game_id,id));
3755 
3756 #if 0
3757 	if (state_game_id != id )       {
3758 		// Game doesn't match!!!
3759 		nm_messagebox( "Error", 1, "Ok", "Cannot restore saved game" );
3760 		Game_mode |= GM_GAME_OVER;
3761 		Function_mode = FMODE_MENU;
3762 		longjmp(LeaveGame, 0);
3763 	}
3764 
3765 	change_playernum_to(pnum-1);
3766 	memcpy( Players[Player_num].callsign, saved_player.callsign, CALLSIGN_LEN+1 );
3767 	memcpy( Players[Player_num].net_address, saved_player.net_address, 6 );
3768 	Players[Player_num].connected = saved_player.connected;
3769 	Players[Player_num].n_packets_got  = saved_player.n_packets_got;
3770 	Players[Player_num].n_packets_sent = saved_player.n_packets_sent;
3771 	Viewer = ConsoleObject = &Objects[pnum-1];
3772 #endif
3773 
3774 }
3775 
3776 
extract_netplayer_stats(netplayer_stats * ps,player * pd)3777 void extract_netplayer_stats( netplayer_stats *ps, player * pd )
3778 {
3779 	int i;
3780 
3781 	ps->flags = INTEL_INT(pd->flags);                                   // Powerup flags, see below...
3782 	ps->energy = (fix)INTEL_INT(pd->energy);                            // Amount of energy remaining.
3783 	ps->shields = (fix)INTEL_INT(pd->shields);                          // shields remaining (protection)
3784 	ps->lives = pd->lives;                                              // Lives remaining, 0 = game over.
3785 	ps->laser_level = pd->laser_level;                                  // Current level of the laser.
3786 	ps->primary_weapon_flags=pd->primary_weapon_flags;                  // bit set indicates the player has this weapon.
3787 	ps->secondary_weapon_flags=pd->secondary_weapon_flags;              // bit set indicates the player has this weapon.
3788 	for (i = 0; i < MAX_PRIMARY_WEAPONS; i++)
3789 		ps->primary_ammo[i] = INTEL_SHORT(pd->primary_ammo[i]);
3790 	for (i = 0; i < MAX_SECONDARY_WEAPONS; i++)
3791 		ps->secondary_ammo[i] = INTEL_SHORT(pd->secondary_ammo[i]);
3792 
3793 	//memcpy( ps->primary_ammo, pd->primary_ammo, MAX_PRIMARY_WEAPONS*sizeof(short) );        // How much ammo of each type.
3794 	//memcpy( ps->secondary_ammo, pd->secondary_ammo, MAX_SECONDARY_WEAPONS*sizeof(short) ); // How much ammo of each type.
3795 
3796 	ps->last_score=INTEL_INT(pd->last_score);                           // Score at beginning of current level.
3797 	ps->score=INTEL_INT(pd->score);                                     // Current score.
3798 	ps->cloak_time=(fix)INTEL_INT(pd->cloak_time);                      // Time cloaked
3799 	ps->homing_object_dist=(fix)INTEL_INT(pd->homing_object_dist);      // Distance of nearest homing object.
3800 	ps->invulnerable_time=(fix)INTEL_INT(pd->invulnerable_time);        // Time invulnerable
3801 	ps->KillGoalCount=INTEL_SHORT(pd->KillGoalCount);
3802 	ps->net_killed_total=INTEL_SHORT(pd->net_killed_total);             // Number of times killed total
3803 	ps->net_kills_total=INTEL_SHORT(pd->net_kills_total);               // Number of net kills total
3804 	ps->num_kills_level=INTEL_SHORT(pd->num_kills_level);               // Number of kills this level
3805 	ps->num_kills_total=INTEL_SHORT(pd->num_kills_total);               // Number of kills total
3806 	ps->num_robots_level=INTEL_SHORT(pd->num_robots_level);             // Number of initial robots this level
3807 	ps->num_robots_total=INTEL_SHORT(pd->num_robots_total);             // Number of robots total
3808 	ps->hostages_rescued_total=INTEL_SHORT(pd->hostages_rescued_total); // Total number of hostages rescued.
3809 	ps->hostages_total=INTEL_SHORT(pd->hostages_total);                 // Total number of hostages.
3810 	ps->hostages_on_board=pd->hostages_on_board;                        // Number of hostages on ship.
3811 }
3812 
use_netplayer_stats(player * ps,netplayer_stats * pd)3813 void use_netplayer_stats( player * ps, netplayer_stats *pd )
3814 {
3815 	int i;
3816 
3817 	ps->flags = INTEL_INT(pd->flags);                       // Powerup flags, see below...
3818 	ps->energy = (fix)INTEL_INT((int)pd->energy);           // Amount of energy remaining.
3819 	ps->shields = (fix)INTEL_INT((int)pd->shields);         // shields remaining (protection)
3820 	ps->lives = pd->lives;                                  // Lives remaining, 0 = game over.
3821 	ps->laser_level = pd->laser_level;                      // Current level of the laser.
3822 	ps->primary_weapon_flags=pd->primary_weapon_flags;      // bit set indicates the player has this weapon.
3823 	ps->secondary_weapon_flags=pd->secondary_weapon_flags;  // bit set indicates the player has this weapon.
3824 	for (i = 0; i < MAX_PRIMARY_WEAPONS; i++)
3825 		ps->primary_ammo[i] = INTEL_SHORT(pd->primary_ammo[i]);
3826 	for (i = 0; i < MAX_SECONDARY_WEAPONS; i++)
3827 		ps->secondary_ammo[i] = INTEL_SHORT(pd->secondary_ammo[i]);
3828 	//memcpy( ps->primary_ammo, pd->primary_ammo, MAX_PRIMARY_WEAPONS*sizeof(short) );  // How much ammo of each type.
3829 	//memcpy( ps->secondary_ammo, pd->secondary_ammo, MAX_SECONDARY_WEAPONS*sizeof(short) ); // How much ammo of each type.
3830 	ps->last_score = INTEL_INT(pd->last_score);             // Score at beginning of current level.
3831 	ps->score = INTEL_INT(pd->score);                       // Current score.
3832 	ps->cloak_time = (fix)INTEL_INT((int)pd->cloak_time);   // Time cloaked
3833 	ps->homing_object_dist = (fix)INTEL_INT((int)pd->homing_object_dist); // Distance of nearest homing object.
3834 	ps->invulnerable_time = (fix)INTEL_INT((int)pd->invulnerable_time); // Time invulnerable
3835 	ps->KillGoalCount=INTEL_SHORT(pd->KillGoalCount);
3836 	ps->net_killed_total = INTEL_SHORT(pd->net_killed_total); // Number of times killed total
3837 	ps->net_kills_total = INTEL_SHORT(pd->net_kills_total); // Number of net kills total
3838 	ps->num_kills_level = INTEL_SHORT(pd->num_kills_level); // Number of kills this level
3839 	ps->num_kills_total = INTEL_SHORT(pd->num_kills_total); // Number of kills total
3840 	ps->num_robots_level = INTEL_SHORT(pd->num_robots_level); // Number of initial robots this level
3841 	ps->num_robots_total = INTEL_SHORT(pd->num_robots_total); // Number of robots total
3842 	ps->hostages_rescued_total = INTEL_SHORT(pd->hostages_rescued_total); // Total number of hostages rescued.
3843 	ps->hostages_total = INTEL_SHORT(pd->hostages_total);   // Total number of hostages.
3844 	ps->hostages_on_board=pd->hostages_on_board;            // Number of hostages on ship.
3845 }
3846 
multi_send_drop_weapon(int objnum,int seed)3847 void multi_send_drop_weapon (int objnum,int seed)
3848 {
3849 	object *objp;
3850 	int count=0;
3851 	int ammo_count;
3852 
3853 	objp = &Objects[objnum];
3854 
3855 	ammo_count = objp->ctype.powerup_info.count;
3856 
3857 	if (objp->id == POW_OMEGA_WEAPON && ammo_count == F1_0)
3858 		ammo_count = F1_0 - 1; //make fit in short
3859 
3860 	Assert(ammo_count < F1_0); //make sure fits in short
3861 
3862 	multibuf[count++]=(char)MULTI_DROP_WEAPON;
3863 	multibuf[count++]=(char)objp->id;
3864 
3865 	*(short *) (multibuf+count)=INTEL_SHORT(Player_num); count += 2;
3866 	*(short *) (multibuf+count)=INTEL_SHORT(objnum); count += 2;
3867 	*(short *) (multibuf+count)=INTEL_SHORT(ammo_count); count += 2;
3868 	*(int *) (multibuf+count)=INTEL_INT(seed);
3869 
3870 	map_objnum_local_to_local(objnum);
3871 
3872 	if (Game_mode & GM_NETWORK)
3873 		PowerupsInMine[objp->id]++;
3874 
3875 	multi_send_data(multibuf, 12, 2);
3876 }
3877 
multi_do_drop_weapon(char * buf)3878 void multi_do_drop_weapon (char *buf)
3879 {
3880 	int pnum,ammo,objnum,remote_objnum,seed;
3881 	object *objp;
3882 	int powerup_id;
3883 
3884 	powerup_id=(int)(buf[1]);
3885 	pnum = INTEL_SHORT(*(short *)(buf+2));
3886 	remote_objnum = INTEL_SHORT(*(short *)(buf+4));
3887 	ammo = INTEL_SHORT(*(ushort *)(buf+6));
3888 	seed = INTEL_INT(*(int *)(buf+8));
3889 
3890 	objp = &Objects[Players[pnum].objnum];
3891 
3892 	objnum = spit_powerup(objp, powerup_id, seed);
3893 
3894 	map_objnum_local_to_remote(objnum, remote_objnum, pnum);
3895 
3896 	if (objnum!=-1)
3897 		Objects[objnum].ctype.powerup_info.count = ammo;
3898 
3899 	if (Game_mode & GM_NETWORK)
3900 		PowerupsInMine[powerup_id]++;
3901 
3902 	mprintf ((0,"Dropped weapon %d!\n"));
3903 
3904 }
3905 
multi_send_guided_info(object * miss,char done)3906 void multi_send_guided_info (object *miss,char done)
3907 {
3908 #ifdef MACINTOSH
3909 	shortpos sp;
3910 #endif
3911 	int count=0;
3912 
3913 	mprintf ((0,"Sending guided info!\n"));
3914 
3915 	multibuf[count++]=(char)MULTI_GUIDED;
3916 	multibuf[count++]=(char)Player_num;
3917 	multibuf[count++]=done;
3918 
3919 #ifndef MACINTOSH
3920 	create_shortpos((shortpos *)(multibuf+count), miss,0);
3921 	count+=sizeof(shortpos);
3922 #else
3923 	create_shortpos(&sp, miss, 1);
3924 	memcpy(&(multibuf[count]), (ubyte *)(sp.bytemat), 9);
3925 	count += 9;
3926 	memcpy(&(multibuf[count]), (ubyte *)&(sp.xo), 14);
3927 	count += 14;
3928 #endif
3929 
3930 	multi_send_data(multibuf, count, 0);
3931 }
3932 
multi_do_guided(char * buf)3933 void multi_do_guided (char *buf)
3934 {
3935 	char pnum=buf[1];
3936 	int count=3;
3937 	static int fun=200;
3938 #ifdef MACINTOSH
3939 	shortpos sp;
3940 #endif
3941 
3942 	if (Guided_missile[(int)pnum]==NULL)
3943 	{
3944 		if (++fun>=50)
3945 		{
3946 			mprintf ((0,"Guided missile for %s is NULL!\n",Players[(int)pnum].callsign));
3947 			fun=0;
3948 		}
3949 		return;
3950 	}
3951 	else if (++fun>=50)
3952 	{
3953 		mprintf ((0,"Got guided info for %d (%s)\n",pnum,Players[(int)pnum].callsign));
3954 		fun=0;
3955 	}
3956 
3957 	if (buf[2])
3958 	{
3959 		release_guided_missile(pnum);
3960 		return;
3961 	}
3962 
3963 
3964 	if (Guided_missile[(int)pnum]-Objects<0 || Guided_missile[(int)pnum]-Objects > Highest_object_index)
3965 	{
3966 		Int3();  // Get Jason immediately!
3967 		return;
3968 	}
3969 
3970 #ifndef MACINTOSH
3971 	extract_shortpos(Guided_missile[(int)pnum], (shortpos *)(buf+count),0);
3972 #else
3973 	memcpy((ubyte *)(sp.bytemat), (ubyte *)(buf + count), 9);
3974 	memcpy((ubyte *)&(sp.xo), (ubyte *)(buf + count + 9), 14);
3975 	extract_shortpos(Guided_missile[(int)pnum], &sp, 1);
3976 #endif
3977 
3978 	count+=sizeof (shortpos);
3979 
3980 	update_object_seg(Guided_missile[(int)pnum]);
3981 }
3982 
multi_send_stolen_items()3983 void multi_send_stolen_items ()
3984 {
3985 	int i,count=1;
3986 	multibuf[0]=MULTI_STOLEN_ITEMS;
3987 
3988 	for (i=0;i<MAX_STOLEN_ITEMS;i++)
3989 	{
3990 		multibuf[i+1]=Stolen_items[i];
3991 		mprintf ((0,"[%d]=%d ",i,Stolen_items[i]));
3992 		count++;      // So I like to break my stuff into smaller chunks, so what?
3993 	}
3994 	mprintf ((0,"\n"));
3995 	multi_send_data(multibuf, count, 1);
3996 }
3997 
multi_do_stolen_items(char * buf)3998 void multi_do_stolen_items (char *buf)
3999 {
4000 	int i;
4001 
4002 	mprintf ((0,"Recieved a stolen item packet...\n"));
4003 
4004 	for (i=0;i<MAX_STOLEN_ITEMS;i++)
4005 	{
4006 		Stolen_items[i]=buf[i+1];
4007 		mprintf ((0,"[%d]=%d ",i,Stolen_items[i]));
4008 	}
4009 	mprintf ((0,"\n"));
4010 }
4011 
4012 extern void network_send_important_packet (char *,int);
4013 
multi_send_wall_status(int wallnum,ubyte type,ubyte flags,ubyte state)4014 void multi_send_wall_status (int wallnum,ubyte type,ubyte flags,ubyte state)
4015 {
4016 	int count=0;
4017 	multibuf[count]=MULTI_WALL_STATUS;        count++;
4018 	*(short *)(multibuf+count)=INTEL_SHORT(wallnum);   count+=2;
4019 	multibuf[count]=type;                 count++;
4020 	multibuf[count]=flags;                count++;
4021 	multibuf[count]=state;                count++;
4022 
4023 #if 0
4024 	if (Game_mode & GM_NETWORK)
4025 	{
4026 		network_send_important_packet (multibuf,count);
4027 		network_send_important_packet (multibuf,count);
4028 	}
4029 	else
4030 #endif
4031 	{
4032 		multi_send_data(multibuf, count, 1); // twice, just to be sure
4033 		multi_send_data(multibuf, count, 1);
4034 	}
4035 }
multi_send_wall_status_specific(int pnum,int wallnum,ubyte type,ubyte flags,ubyte state)4036 void multi_send_wall_status_specific (int pnum,int wallnum,ubyte type,ubyte flags,ubyte state)
4037 {
4038 	// Send wall states a specific rejoining player
4039 
4040 	int count=0;
4041 
4042 	Assert (Game_mode & GM_NETWORK);
4043 	//Assert (pnum>-1 && pnum<N_players);
4044 
4045 	multibuf[count]=MULTI_WALL_STATUS;        count++;
4046 	*(short *)(multibuf+count)=INTEL_SHORT(wallnum);   count+=2;
4047 	multibuf[count]=type;                 count++;
4048 	multibuf[count]=flags;                count++;
4049 	multibuf[count]=state;                count++;
4050 
4051 	network_send_naked_packet(multibuf, count,pnum); // twice, just to be sure
4052 	network_send_naked_packet(multibuf, count,pnum);
4053 }
4054 
multi_do_wall_status(char * buf)4055 void multi_do_wall_status (char *buf)
4056 {
4057 	short wallnum;
4058 	ubyte flag,type,state;
4059 
4060 	wallnum=INTEL_SHORT( *(short *)(buf+1) );
4061 	type=buf[3];
4062 	flag=buf[4];
4063 	state=buf[5];
4064 
4065 	Assert (wallnum>=0);
4066 	Walls[wallnum].type=type;
4067 	Walls[wallnum].flags=flag;
4068 	//Assert(state <= 4);
4069 	Walls[wallnum].state=state;
4070 
4071 	if (Walls[wallnum].type==WALL_OPEN)
4072 	{
4073 		digi_kill_sound_linked_to_segment(Walls[wallnum].segnum,Walls[wallnum].sidenum,SOUND_FORCEFIELD_HUM);
4074 		//digi_kill_sound_linked_to_segment(csegp-Segments,cside,SOUND_FORCEFIELD_HUM);
4075 	}
4076 
4077 
4078 	//mprintf ((0,"Got a walls packet.\n"));
4079 }
4080 
multi_send_jason_cheat(int num)4081 void multi_send_jason_cheat (int num)
4082 {
4083 	num=num;
4084 	return;
4085 }
4086 
multi_send_kill_goal_counts()4087 void multi_send_kill_goal_counts()
4088 {
4089 	int i,count=1;
4090 	multibuf[0]=MULTI_KILLGOALS;
4091 
4092 	for (i=0;i<MAX_PLAYERS;i++)
4093 	{
4094 		*(char *)(multibuf+count)=(char)Players[i].KillGoalCount;
4095 		count++;
4096 	}
4097 
4098 	mprintf ((0,"MULTI: Sending KillGoalCounts...\n"));
4099 	multi_send_data(multibuf, count, 1);
4100 }
4101 
multi_do_kill_goal_counts(char * buf)4102 void multi_do_kill_goal_counts(char *buf)
4103 {
4104 	int i,count=1;
4105 
4106 	for (i=0;i<MAX_PLAYERS;i++)
4107 	{
4108 		Players[i].KillGoalCount=*(char *)(buf+count);
4109 		mprintf ((0,"KGC: %s has %d kills!\n",Players[i].callsign,Players[i].KillGoalCount));
4110 		count++;
4111 	}
4112 
4113 }
4114 
multi_send_heartbeat()4115 void multi_send_heartbeat ()
4116 {
4117 	if (!Netgame.PlayTimeAllowed)
4118 		return;
4119 
4120 	multibuf[0]=MULTI_HEARTBEAT;
4121 	*(fix *)(multibuf+1)=(fix)INTEL_INT(ThisLevelTime);
4122 	multi_send_data(multibuf, 5, 0);
4123 }
4124 
multi_do_heartbeat(char * buf)4125 void multi_do_heartbeat (char *buf)
4126 {
4127 	fix num;
4128 
4129 	num=(fix)INTEL_INT(*(int *)(buf+1));
4130 
4131 	ThisLevelTime=num;
4132 }
4133 
multi_check_for_killgoal_winner()4134 void multi_check_for_killgoal_winner ()
4135 {
4136 	int i,best=0,bestnum=0;
4137 	object *objp;
4138 
4139 	if (Control_center_destroyed)
4140 		return;
4141 
4142 	for (i=0;i<N_players;i++)
4143 	{
4144 		if (Players[i].KillGoalCount>best)
4145 		{
4146 			best=Players[i].KillGoalCount;
4147 			bestnum=i;
4148 		}
4149 	}
4150 
4151 	if (bestnum==Player_num)
4152 	{
4153 		HUD_init_message("You have the best score at %d kills!",best);
4154 		//Players[Player_num].shields=i2f(200);
4155 	}
4156 	else
4157 
4158 		HUD_init_message ("%s has the best score with %d kills!",Players[bestnum].callsign,best);
4159 
4160 	HUD_init_message ("The control center has been destroyed!");
4161 
4162 	objp=obj_find_first_of_type (OBJ_CNTRLCEN);
4163 	net_destroy_controlcen (objp);
4164 }
4165 
multi_send_seismic(fix start,fix end)4166 void multi_send_seismic (fix start,fix end)
4167 {
4168 	int count=1;
4169 
4170 	multibuf[0]=MULTI_SEISMIC;
4171 	*(fix *)(multibuf+count)=(fix)INTEL_INT(start); count+=(sizeof(fix));
4172 	*(fix *)(multibuf+count)=(fix)INTEL_INT(end); count+=(sizeof(fix));
4173 
4174 	multi_send_data(multibuf, count, 1);
4175 }
4176 
4177 extern fix Seismic_disturbance_start_time;
4178 extern fix Seismic_disturbance_end_time;
4179 
multi_do_seismic(char * buf)4180 void multi_do_seismic (char *buf)
4181 {
4182 	Seismic_disturbance_start_time=(fix)INTEL_INT( *(int *)(buf+1) );
4183 	Seismic_disturbance_end_time=(fix)INTEL_INT( *(int *)(buf+5) );
4184 	digi_play_sample (SOUND_SEISMIC_DISTURBANCE_START, F1_0);
4185 }
4186 
multi_send_light(int segnum,ubyte val)4187 void multi_send_light (int segnum,ubyte val)
4188 {
4189 	int count=1,i;
4190 	multibuf[0]=MULTI_LIGHT;
4191 	*(int *)(multibuf+count)=INTEL_INT(segnum); count+=(sizeof(int));
4192 	*(char *)(multibuf+count)=val; count++;
4193 	for (i=0;i<6;i++)
4194 	{
4195 		//mprintf ((0,"Sending %d!\n",Segments[segnum].sides[i].tmap_num2));
4196 		*(short *)(multibuf+count)=INTEL_SHORT(Segments[segnum].sides[i].tmap_num2); count+=2;
4197 	}
4198 	multi_send_data(multibuf, count, 1);
4199 }
multi_send_light_specific(int pnum,int segnum,ubyte val)4200 void multi_send_light_specific (int pnum,int segnum,ubyte val)
4201 {
4202 	int count=1,i;
4203 
4204 	Assert (Game_mode & GM_NETWORK);
4205 	//  Assert (pnum>-1 && pnum<N_players);
4206 
4207 	multibuf[0]=MULTI_LIGHT;
4208 	*(int *)(multibuf+count)=INTEL_INT(segnum); count+=(sizeof(int));
4209 	*(char *)(multibuf+count)=val; count++;
4210 
4211 	for (i=0;i<6;i++)
4212 	{
4213 		//mprintf ((0,"Sending %d!\n",Segments[segnum].sides[i].tmap_num2));
4214 		*(short *)(multibuf+count)=INTEL_SHORT(Segments[segnum].sides[i].tmap_num2); count+=2;
4215 	}
4216 	network_send_naked_packet(multibuf, count, pnum);
4217 }
4218 
multi_do_light(char * buf)4219 void multi_do_light (char *buf)
4220 {
4221 	int i;
4222 	int seg=INTEL_INT(*(int *)(buf+1));
4223 	ubyte sides=*(char *)(buf+5);
4224 
4225 	for (i=0;i<6;i++)
4226 	{
4227 		if ((sides & (1<<i)))
4228 		{
4229 			subtract_light (seg,i);
4230 			Segments[seg].sides[i].tmap_num2=INTEL_SHORT( *(short *)(buf+(6+(2*i))) );
4231 			//mprintf ((0,"Got %d!\n",Segments[seg].sides[i].tmap_num2));
4232 		}
4233 	}
4234 }
4235 
4236 //@@void multi_send_start_trigger(int triggernum)
4237 //@@{
4238 //@@	// Send an even to trigger something in the mine
4239 //@@
4240 //@@	int count = 0;
4241 //@@
4242 //@@	multibuf[count] = MULTI_START_TRIGGER;          count += 1;
4243 //@@	multibuf[count] = Player_num;                   count += 1;
4244 //@@	multibuf[count] = (ubyte)triggernum;            count += 1;
4245 //@@
4246 //@@	//mprintf ((0,"Sending start trigger %d\n",triggernum));
4247 //@@	multi_send_data(multibuf, count, 2);
4248 //@@}
4249 //@@void multi_do_start_trigger(char *buf)
4250 //@@{
4251 //@@	int pnum = buf[1];
4252 //@@	int trigger = buf[2];
4253 //@@
4254 //@@	//mprintf ((0,"MULTI doing start trigger!\n"));
4255 //@@
4256 //@@	if ((pnum < 0) || (pnum >= N_players) || (pnum == Player_num))
4257 //@@	{
4258 //@@		Int3(); // Got trigger from illegal playernum
4259 //@@		return;
4260 //@@	}
4261 //@@	if ((trigger < 0) || (trigger >= Num_triggers))
4262 //@@	{
4263 //@@		Int3(); // Illegal trigger number in multiplayer
4264 //@@		return;
4265 //@@	}
4266 //@@
4267 //@@	if (!(Triggers[trigger].flags & TF_SPRUNG))
4268 //@@		check_trigger_sub(trigger, pnum,0);
4269 //@@}
4270 
4271 
multi_do_flags(char * buf)4272 void multi_do_flags (char *buf)
4273 {
4274 	char pnum=buf[1];
4275 	uint flags=INTEL_INT( *(uint *)(buf+2) );
4276 
4277 	if (pnum!=Player_num)
4278 		Players[(int)pnum].flags=flags;
4279 }
4280 
multi_send_flags(char pnum)4281 void multi_send_flags (char pnum)
4282 {
4283 	multibuf[0]=MULTI_FLAGS;
4284 	multibuf[1]=pnum;
4285 	*(uint *)(multibuf+2)=INTEL_INT(Players[(int)pnum].flags);
4286 
4287 	multi_send_data(multibuf, 6, 1);
4288 }
4289 
multi_send_drop_blobs(char pnum)4290 void multi_send_drop_blobs (char pnum)
4291 {
4292 	multibuf[0]=MULTI_DROP_BLOB;
4293 	multibuf[1]=pnum;
4294 
4295 	multi_send_data(multibuf, 2, 0);
4296 }
4297 
multi_do_drop_blob(char * buf)4298 void multi_do_drop_blob (char *buf)
4299 {
4300 	char pnum=buf[1];
4301 	drop_afterburner_blobs (&Objects[Players[(int)pnum].objnum], 2, i2f(5)/2, -1);
4302 }
4303 
multi_send_powerup_update()4304 void multi_send_powerup_update ()
4305 {
4306 	int i;
4307 
4308 
4309 	multibuf[0]=MULTI_POWERUP_UPDATE;
4310 	for (i=0;i<MAX_POWERUP_TYPES;i++)
4311 		multibuf[i+1]=MaxPowerupsAllowed[i];
4312 
4313 	multi_send_data(multibuf, MAX_POWERUP_TYPES+1, 1);
4314 }
multi_do_powerup_update(char * buf)4315 void multi_do_powerup_update (char *buf)
4316 {
4317 	int i;
4318 
4319 	for (i=0;i<MAX_POWERUP_TYPES;i++)
4320 		if (buf[i+1]>MaxPowerupsAllowed[i])
4321 			MaxPowerupsAllowed[i]=buf[i+1];
4322 }
4323 
4324 extern active_door ActiveDoors[];
4325 extern int Num_open_doors;          // Number of open doors
4326 
multi_send_active_door(char i)4327 void multi_send_active_door (char i)
4328 {
4329 	int count;
4330 
4331 	multibuf[0]=MULTI_ACTIVE_DOOR;
4332 	multibuf[1]=i;
4333 	multibuf[2]=Num_open_doors;
4334 	count = 3;
4335 #ifndef MACINTOSH
4336 	memcpy ((char *)(&multibuf[3]),&ActiveDoors[(int)i],sizeof(struct active_door));
4337 	count += sizeof(active_door);
4338 #else
4339 	*(int *)(multibuf + count) = INTEL_INT(ActiveDoors[i].n_parts);                 count += 4;
4340 	*(short *)(multibuf + count) = INTEL_SHORT(ActiveDoors[i].front_wallnum[0]);    count += 2;
4341 	*(short *)(multibuf + count) = INTEL_SHORT(ActiveDoors[i].front_wallnum[1])     count += 2;
4342 	*(short *)(multibuf + count) = INTEL_SHORT(ActiveDoors[i].back_wallnum[0]);     count += 2;
4343 	*(short *)(multibuf + count) = INTEL_SHORT(ActiveDoors[i].back_wallnum[1]);     count += 2;
4344 	*(int *)(multibuf + count) = INTEL_INT(ActiveDoors[i].time);                    count += 4;
4345 #endif
4346 	//multi_send_data (multibuf,sizeof(struct active_door)+3,1);
4347 	multi_send_data (multibuf,count,1);
4348 }
4349 
multi_do_active_door(char * buf)4350 void multi_do_active_door (char *buf)
4351 {
4352 	int count;
4353 	char i=multibuf[1];
4354 	Num_open_doors=buf[2];
4355 
4356 	count = 3;
4357 #ifndef MACINTOSH
4358 	memcpy (&ActiveDoors[(int)i],buf+count,sizeof(struct active_door));
4359 #else
4360 	ActiveDoors[i].n_parts = INTEL_INT( *(int *)(buf+count) );              count += 4;
4361 	ActiveDoors[i].front_wallnum[0] = INTEL_SHORT( *(short *)(buf+count) ); count +=2;
4362 	ActiveDoors[i].front_wallnum[1] = INTEL_SHORT( *(short *)(buf+count) ); count +=2;
4363 	ActiveDoors[i].back_wallnum[0] = INTEL_SHORT( *(short *)(buf+count) );  count +=2;
4364 	ActiveDoors[i].back_wallnum[1] = INTEL_SHORT( *(short *)(buf+count) );  count +=2;
4365 	ActiveDoors[i].time = INTEL_INT( *(int *)(buf+count) );                 count += 4;
4366 #endif
4367 }
4368 
multi_send_sound_function(char whichfunc,char sound)4369 void multi_send_sound_function (char whichfunc,char sound)
4370 {
4371 	int count=0;
4372 
4373 	multibuf[0]=MULTI_SOUND_FUNCTION;   count++;
4374 	multibuf[1]=Player_num;             count++;
4375 	multibuf[2]=whichfunc;              count++;
4376 #ifndef MACINTOSH
4377 	*(uint *)(multibuf+count)=sound;    count++;
4378 #else
4379 	multibuf[3] = sound; count++;       // this would probably work on the PC as well.  Jason?
4380 #endif
4381 	multi_send_data (multibuf,4,0);
4382 }
4383 
4384 #define AFTERBURNER_LOOP_START  20098
4385 #define AFTERBURNER_LOOP_END    25776
4386 
multi_do_sound_function(char * buf)4387 void multi_do_sound_function (char *buf)
4388 {
4389 	// for afterburner
4390 
4391 	char pnum,whichfunc;
4392 	int sound;
4393 
4394 	if (Players[Player_num].connected!=1)
4395 		return;
4396 
4397 	pnum=buf[1];
4398 	whichfunc=buf[2];
4399 	sound=buf[3];
4400 
4401 	if (whichfunc==0)
4402 		digi_kill_sound_linked_to_object (Players[(int)pnum].objnum);
4403 	else if (whichfunc==3)
4404 		digi_link_sound_to_object3( sound, Players[(int)pnum].objnum, 1,F1_0, i2f(256), AFTERBURNER_LOOP_START, AFTERBURNER_LOOP_END);
4405 }
4406 
multi_send_capture_bonus(char pnum)4407 void multi_send_capture_bonus (char pnum)
4408 {
4409 	Assert (Game_mode & GM_CAPTURE);
4410 
4411 	multibuf[0]=MULTI_CAPTURE_BONUS;
4412 	multibuf[1]=pnum;
4413 
4414 	multi_send_data (multibuf,2,1);
4415 	multi_do_capture_bonus (multibuf);
4416 }
multi_send_orb_bonus(char pnum)4417 void multi_send_orb_bonus (char pnum)
4418 {
4419 	Assert (Game_mode & GM_HOARD);
4420 
4421 	multibuf[0]=MULTI_ORB_BONUS;
4422 	multibuf[1]=pnum;
4423 	multibuf[2]=Players[Player_num].secondary_ammo[PROXIMITY_INDEX];
4424 
4425 	multi_send_data (multibuf,3,1);
4426 	multi_do_orb_bonus (multibuf);
4427 }
multi_do_capture_bonus(char * buf)4428 void multi_do_capture_bonus(char *buf)
4429 {
4430 	// Figure out the results of a network kills and add it to the
4431 	// appropriate player's tally.
4432 
4433 	char pnum=buf[1];
4434 	int TheGoal;
4435 
4436 	kmatrix_kills_changed = 1;
4437 
4438 	if (pnum==Player_num)
4439 		HUD_init_message("You have Scored!");
4440 	else
4441 		HUD_init_message("%s has Scored!",Players[(int)pnum].callsign);
4442 
4443 	if (pnum==Player_num)
4444 		digi_play_sample (SOUND_HUD_YOU_GOT_GOAL,F1_0*2);
4445 	else if (get_team(pnum)==TEAM_RED)
4446 		digi_play_sample (SOUND_HUD_RED_GOT_GOAL,F1_0*2);
4447 	else
4448 		digi_play_sample (SOUND_HUD_BLUE_GOT_GOAL,F1_0*2);
4449 
4450 	Players[(int)pnum].flags &= ~(PLAYER_FLAGS_FLAG);  // Clear capture flag
4451 
4452 	team_kills[get_team(pnum)] += 5;
4453 	Players[(int)pnum].net_kills_total += 5;
4454 	Players[(int)pnum].KillGoalCount+=5;
4455 
4456 	if (Netgame.KillGoal>0)
4457 	{
4458 		TheGoal=Netgame.KillGoal*5;
4459 
4460 		if (Players[(int)pnum].KillGoalCount>=TheGoal)
4461 		{
4462 			if (pnum==Player_num)
4463 			{
4464 				HUD_init_message("You reached the kill goal!");
4465 				Players[Player_num].shields=i2f(200);
4466 			}
4467 			else
4468 				HUD_init_message ("%s has reached the kill goal!",Players[(int)pnum].callsign);
4469 
4470 			HUD_init_message ("The control center has been destroyed!");
4471 			net_destroy_controlcen (obj_find_first_of_type (OBJ_CNTRLCEN));
4472 		}
4473 	}
4474 
4475 	multi_sort_kill_list();
4476 	multi_show_player_list();
4477 }
4478 
GetOrbBonus(char num)4479 int GetOrbBonus (char num)
4480 {
4481 	int bonus;
4482 
4483 	bonus=num*(num+1)/2;
4484 	return (bonus);
4485 }
4486 
multi_do_orb_bonus(char * buf)4487 void multi_do_orb_bonus(char *buf)
4488 {
4489 	// Figure out the results of a network kills and add it to the
4490 	// appropriate player's tally.
4491 
4492 	char pnum=buf[1];
4493 	int TheGoal;
4494 	int bonus=GetOrbBonus (buf[2]);
4495 
4496 	kmatrix_kills_changed = 1;
4497 
4498 	if (pnum==Player_num)
4499 		HUD_init_message("You have scored %d points!",bonus);
4500 	else
4501 		HUD_init_message("%s has scored with %d orbs!",Players[(int)pnum].callsign,buf[2]);
4502 
4503 	if (pnum==Player_num)
4504 		digi_start_sound_queued (SOUND_HUD_YOU_GOT_GOAL,F1_0*2);
4505 	else if (Game_mode & GM_TEAM)
4506 	{
4507 		if (get_team(pnum)==TEAM_RED)
4508 			digi_play_sample (SOUND_HUD_RED_GOT_GOAL,F1_0*2);
4509 		else
4510 			digi_play_sample (SOUND_HUD_BLUE_GOT_GOAL,F1_0*2);
4511 	}
4512 	else
4513 		digi_play_sample (SOUND_OPPONENT_HAS_SCORED,F1_0*2);
4514 
4515 	if (bonus>PhallicLimit)
4516 	{
4517 		if (pnum==Player_num)
4518 			HUD_init_message ("You have the record with %d points!",bonus);
4519 		else
4520 			HUD_init_message ("%s has the record with %d points!",Players[(int)pnum].callsign,bonus);
4521 		digi_play_sample (SOUND_BUDDY_MET_GOAL,F1_0*2);
4522 		PhallicMan=pnum;
4523 		PhallicLimit=bonus;
4524 	}
4525 
4526 	Players[(int)pnum].flags &= ~(PLAYER_FLAGS_FLAG);  // Clear orb flag
4527 
4528 	team_kills[get_team(pnum)] += bonus;
4529 	Players[(int)pnum].net_kills_total += bonus;
4530 	Players[(int)pnum].KillGoalCount+=bonus;
4531 
4532 	team_kills[get_team(pnum)]%=1000;
4533 	Players[(int)pnum].net_kills_total%=1000;
4534 	Players[(int)pnum].KillGoalCount%=1000;
4535 
4536 	if (Netgame.KillGoal>0)
4537 	{
4538 		TheGoal=Netgame.KillGoal*5;
4539 
4540 		if (Players[(int)pnum].KillGoalCount>=TheGoal)
4541 		{
4542 			if (pnum==Player_num)
4543 			{
4544 				HUD_init_message("You reached the kill goal!");
4545 				Players[Player_num].shields=i2f(200);
4546 			}
4547 			else
4548 				HUD_init_message ("%s has reached the kill goal!",Players[(int)pnum].callsign);
4549 
4550 			HUD_init_message ("The control center has been destroyed!");
4551 			net_destroy_controlcen (obj_find_first_of_type (OBJ_CNTRLCEN));
4552 		}
4553 	}
4554 	multi_sort_kill_list();
4555 	multi_show_player_list();
4556 }
4557 
multi_send_got_flag(char pnum)4558 void multi_send_got_flag (char pnum)
4559 {
4560 	multibuf[0]=MULTI_GOT_FLAG;
4561 	multibuf[1]=pnum;
4562 
4563 	digi_start_sound_queued (SOUND_HUD_YOU_GOT_FLAG,F1_0*2);
4564 
4565 	multi_send_data (multibuf,2,1);
4566 	multi_send_flags (Player_num);
4567 }
4568 
4569 int SoundHacked=0;
4570 digi_sound ReversedSound;
4571 
multi_send_got_orb(char pnum)4572 void multi_send_got_orb (char pnum)
4573 {
4574 	multibuf[0]=MULTI_GOT_ORB;
4575 	multibuf[1]=pnum;
4576 
4577 	digi_play_sample (SOUND_YOU_GOT_ORB,F1_0*2);
4578 
4579 	multi_send_data (multibuf,2,1);
4580 	multi_send_flags (Player_num);
4581 }
4582 
multi_do_got_flag(char * buf)4583 void multi_do_got_flag (char *buf)
4584 {
4585 	char pnum=buf[1];
4586 
4587 	if (pnum==Player_num)
4588 		digi_start_sound_queued (SOUND_HUD_YOU_GOT_FLAG,F1_0*2);
4589 	else if (get_team(pnum)==TEAM_RED)
4590 		digi_start_sound_queued (SOUND_HUD_RED_GOT_FLAG,F1_0*2);
4591 	else
4592 		digi_start_sound_queued (SOUND_HUD_BLUE_GOT_FLAG,F1_0*2);
4593 	Players[(int)pnum].flags|=PLAYER_FLAGS_FLAG;
4594 	HUD_init_message ("%s picked up a flag!",Players[(int)pnum].callsign);
4595 }
multi_do_got_orb(char * buf)4596 void multi_do_got_orb (char *buf)
4597 {
4598 	char pnum=buf[1];
4599 
4600 	Assert (Game_mode & GM_HOARD);
4601 
4602 	if (Game_mode & GM_TEAM)
4603 	{
4604 		if (get_team(pnum)==get_team(Player_num))
4605 			digi_play_sample (SOUND_FRIEND_GOT_ORB,F1_0*2);
4606 		else
4607 			digi_play_sample (SOUND_OPPONENT_GOT_ORB,F1_0*2);
4608     }
4609 	else
4610 		digi_play_sample (SOUND_OPPONENT_GOT_ORB,F1_0*2);
4611 
4612 	Players[(int)pnum].flags|=PLAYER_FLAGS_FLAG;
4613 	HUD_init_message ("%s picked up an orb!",Players[(int)pnum].callsign);
4614 }
4615 
4616 
DropOrb()4617 void DropOrb ()
4618 {
4619 	int objnum,seed;
4620 
4621 	if (!(Game_mode & GM_HOARD))
4622 		Int3(); // How did we get here? Get Leighton!
4623 
4624 	if (!Players[Player_num].secondary_ammo[PROXIMITY_INDEX])
4625 	{
4626 		HUD_init_message("No orbs to drop!");
4627 		return;
4628 	}
4629 
4630 	seed = d_rand();
4631 
4632 	objnum = spit_powerup(ConsoleObject,POW_HOARD_ORB,seed);
4633 
4634 	if (objnum<0)
4635 		return;
4636 
4637 	HUD_init_message("Orb dropped!");
4638 	digi_play_sample (SOUND_DROP_WEAPON,F1_0);
4639 
4640 	if ((Game_mode & GM_HOARD) && objnum>-1)
4641 		multi_send_drop_flag(objnum,seed);
4642 
4643 	Players[Player_num].secondary_ammo[PROXIMITY_INDEX]--;
4644 
4645 	// If empty, tell everyone to stop drawing the box around me
4646 	if (Players[Player_num].secondary_ammo[PROXIMITY_INDEX]==0)
4647 		multi_send_flags (Player_num);
4648 }
4649 
DropFlag()4650 void DropFlag ()
4651 {
4652 	int objnum,seed;
4653 
4654 	if (!(Game_mode & GM_CAPTURE) && !(Game_mode & GM_HOARD))
4655 		return;
4656 	if (Game_mode & GM_HOARD)
4657 	{
4658 		DropOrb();
4659 		return;
4660 	}
4661 
4662 	if (!(Players[Player_num].flags & PLAYER_FLAGS_FLAG))
4663 	{
4664 		HUD_init_message("No flag to drop!");
4665 		return;
4666 	}
4667 
4668 
4669 	HUD_init_message("Flag dropped!");
4670 	digi_play_sample (SOUND_DROP_WEAPON,F1_0);
4671 
4672 	seed = d_rand();
4673 
4674 	if (get_team (Player_num)==TEAM_RED)
4675 		objnum = spit_powerup(ConsoleObject,POW_FLAG_BLUE,seed);
4676 	else
4677 		objnum = spit_powerup(ConsoleObject,POW_FLAG_RED,seed);
4678 
4679 	if (objnum<0)
4680 		return;
4681 
4682 	if ((Game_mode & GM_CAPTURE) && objnum>-1)
4683 		multi_send_drop_flag(objnum,seed);
4684 
4685 	Players[Player_num].flags &=~(PLAYER_FLAGS_FLAG);
4686 }
4687 
4688 
multi_send_drop_flag(int objnum,int seed)4689 void multi_send_drop_flag (int objnum,int seed)
4690 {
4691 	object *objp;
4692 	int count=0;
4693 
4694 	objp = &Objects[objnum];
4695 
4696 	multibuf[count++]=(char)MULTI_DROP_FLAG;
4697 	multibuf[count++]=(char)objp->id;
4698 
4699 	*(short *) (multibuf+count)=INTEL_SHORT(Player_num); count += 2;
4700 	*(short *) (multibuf+count)=INTEL_SHORT(objnum); count += 2;
4701 	*(short *) (multibuf+count)=INTEL_SHORT(objp->ctype.powerup_info.count); count += 2;
4702 	*(int *) (multibuf+count)=INTEL_INT(seed);
4703 
4704 	map_objnum_local_to_local(objnum);
4705 
4706 	if (!(Game_mode & GM_HOARD))
4707 		if (Game_mode & GM_NETWORK)
4708 			PowerupsInMine[objp->id]++;
4709 
4710 	multi_send_data(multibuf, 12, 2);
4711 }
4712 
multi_do_drop_flag(char * buf)4713 void multi_do_drop_flag (char *buf)
4714 {
4715 	int pnum,ammo,objnum,remote_objnum,seed;
4716 	object *objp;
4717 	int powerup_id;
4718 
4719 	powerup_id=buf[1];
4720 	pnum=INTEL_SHORT( *(short *)(buf+2) );
4721 	remote_objnum=INTEL_SHORT( *(short *)(buf+4) );
4722 	ammo=INTEL_SHORT( *(short *)(buf+6) );
4723 	seed=INTEL_INT( *(int *)(buf+8) );
4724 
4725 	objp = &Objects[Players[pnum].objnum];
4726 
4727 	objnum = spit_powerup(objp, powerup_id, seed);
4728 
4729 	map_objnum_local_to_remote(objnum, remote_objnum, pnum);
4730 
4731 	if (objnum!=-1)
4732 		Objects[objnum].ctype.powerup_info.count = ammo;
4733 
4734 	if (!(Game_mode & GM_HOARD))
4735 	{
4736 		if (Game_mode & GM_NETWORK)
4737 			PowerupsInMine[powerup_id]++;
4738 		Players[pnum].flags &= ~(PLAYER_FLAGS_FLAG);
4739 	}
4740 	mprintf ((0,"Dropped flag %d!\n"));
4741 
4742 }
4743 
multi_bad_restore()4744 void multi_bad_restore ()
4745 {
4746 	Function_mode = FMODE_MENU;
4747 	nm_messagebox(NULL, 1, TXT_OK,
4748 	              "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.");
4749 	Function_mode = FMODE_GAME;
4750 	multi_quit_game = 1;
4751 	multi_leave_menu = 1;
4752 	multi_reset_stuff();
4753 }
4754 
4755 extern int robot_controlled[MAX_ROBOTS_CONTROLLED];
4756 extern int robot_agitation[MAX_ROBOTS_CONTROLLED];
4757 extern fix robot_controlled_time[MAX_ROBOTS_CONTROLLED];
4758 extern fix robot_last_send_time[MAX_ROBOTS_CONTROLLED];
4759 extern fix robot_last_message_time[MAX_ROBOTS_CONTROLLED];
4760 extern int robot_send_pending[MAX_ROBOTS_CONTROLLED];
4761 extern int robot_fired[MAX_ROBOTS_CONTROLLED];
4762 extern byte robot_fire_buf[MAX_ROBOTS_CONTROLLED][18+3];
4763 
4764 
multi_send_robot_controls(char pnum)4765 void multi_send_robot_controls (char pnum)
4766 {
4767 	int count=2;
4768 
4769 	mprintf ((0,"Sending ROBOT_CONTROLS!!!\n"));
4770 
4771 	multibuf[0]=MULTI_ROBOT_CONTROLS;
4772 	multibuf[1]=pnum;
4773 	memcpy (&(multibuf[count]),&robot_controlled,MAX_ROBOTS_CONTROLLED*4);
4774 	count+=(MAX_ROBOTS_CONTROLLED*4);
4775 	memcpy (&(multibuf[count]),&robot_agitation,MAX_ROBOTS_CONTROLLED*4);
4776 	count+=(MAX_ROBOTS_CONTROLLED*4);
4777 	memcpy (&(multibuf[count]),&robot_controlled_time,MAX_ROBOTS_CONTROLLED*4);
4778 	count+=(MAX_ROBOTS_CONTROLLED*4);
4779 	memcpy (&(multibuf[count]),&robot_last_send_time,MAX_ROBOTS_CONTROLLED*4);
4780 	count+=(MAX_ROBOTS_CONTROLLED*4);
4781 	memcpy (&(multibuf[count]),&robot_last_message_time,MAX_ROBOTS_CONTROLLED*4);
4782 	count+=(MAX_ROBOTS_CONTROLLED*4);
4783 	memcpy (&(multibuf[count]),&robot_send_pending,MAX_ROBOTS_CONTROLLED*4);
4784 	count+=(MAX_ROBOTS_CONTROLLED*4);
4785 	memcpy (&(multibuf[count]),&robot_fired,MAX_ROBOTS_CONTROLLED*4);
4786 	count+=(MAX_ROBOTS_CONTROLLED*4);
4787 
4788 	network_send_naked_packet (multibuf,142,pnum);
4789 }
multi_do_robot_controls(char * buf)4790 void multi_do_robot_controls(char *buf)
4791 {
4792 	int count=2;
4793 
4794 	mprintf ((0,"Recieved ROBOT_CONTROLS!!!\n"));
4795 
4796 	if (buf[1]!=Player_num)
4797 	{
4798 		Int3(); // Get Jason!  Recieved a coop_sync that wasn't ours!
4799 		return;
4800 	}
4801 
4802 	memcpy (&robot_controlled,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
4803 	count+=(MAX_ROBOTS_CONTROLLED*4);
4804 	memcpy (&robot_agitation,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
4805 	count+=(MAX_ROBOTS_CONTROLLED*4);
4806 	memcpy (&robot_controlled_time,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
4807 	count+=(MAX_ROBOTS_CONTROLLED*4);
4808 	memcpy (&robot_last_send_time,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
4809 	count+=(MAX_ROBOTS_CONTROLLED*4);
4810 	memcpy (&robot_last_message_time,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
4811 	count+=(MAX_ROBOTS_CONTROLLED*4);
4812 	memcpy (&robot_send_pending,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
4813 	count+=(MAX_ROBOTS_CONTROLLED*4);
4814 	memcpy (&robot_fired,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
4815 	count+=(MAX_ROBOTS_CONTROLLED*4);
4816 }
4817 
4818 #define POWERUPADJUSTS 5
4819 int PowerupAdjustMapping[]={11,19,39,41,44};
4820 
multi_powerup_is_4pack(int id)4821 int multi_powerup_is_4pack (int id)
4822 {
4823 	int i;
4824 
4825 	for (i=0;i<POWERUPADJUSTS;i++)
4826 		if (id==PowerupAdjustMapping[i])
4827 			return (1);
4828 	return (0);
4829 }
4830 
multi_powerup_is_allowed(int id)4831 int multi_powerup_is_allowed(int id)
4832 {
4833 	if (id == POW_INVULNERABILITY && !Netgame.DoInvulnerability)
4834 		return (0);
4835 	if (id == POW_CLOAK && !Netgame.DoCloak)
4836 		return (0);
4837 	if (id == POW_AFTERBURNER && !Netgame.DoAfterburner)
4838 		return (0);
4839 	if (id == POW_FUSION_WEAPON &&  !Netgame.DoFusions)
4840 		return (0);
4841 	if (id == POW_PHOENIX_WEAPON && !Netgame.DoPhoenix)
4842 		return (0);
4843 	if (id == POW_HELIX_WEAPON && !Netgame.DoHelix)
4844 		return (0);
4845 	if (id == POW_MEGA_WEAPON && !Netgame.DoMegas)
4846 		return (0);
4847 	if (id == POW_SMARTBOMB_WEAPON && !Netgame.DoSmarts)
4848 		return (0);
4849 	if (id == POW_GAUSS_WEAPON && !Netgame.DoGauss)
4850 		return (0);
4851 	if (id == POW_VULCAN_WEAPON && !Netgame.DoVulcan)
4852 		return (0);
4853 	if (id == POW_PLASMA_WEAPON && !Netgame.DoPlasma)
4854 		return (0);
4855 	if (id == POW_OMEGA_WEAPON && !Netgame.DoOmega)
4856 		return (0);
4857 	if (id == POW_SUPER_LASER && !Netgame.DoSuperLaser)
4858 		return (0);
4859 	if (id == POW_PROXIMITY_WEAPON && !Netgame.DoProximity)
4860 		return (0);
4861 	if (id==POW_VULCAN_AMMO && (!Netgame.DoVulcan && !Netgame.DoGauss))
4862 		return (0);
4863 	if (id == POW_SPREADFIRE_WEAPON && !Netgame.DoSpread)
4864 		return (0);
4865 	if (id == POW_SMART_MINE && !Netgame.DoSmartMine)
4866 		return (0);
4867 	if (id == POW_SMISSILE1_1 &&  !Netgame.DoFlash)
4868 		return (0);
4869 	if (id == POW_SMISSILE1_4 &&  !Netgame.DoFlash)
4870 		return (0);
4871 	if (id == POW_GUIDED_MISSILE_1 &&  !Netgame.DoGuided)
4872 		return (0);
4873 	if (id == POW_GUIDED_MISSILE_4 &&  !Netgame.DoGuided)
4874 		return (0);
4875 	if (id == POW_EARTHSHAKER_MISSILE &&  !Netgame.DoEarthShaker)
4876 		return (0);
4877 	if (id == POW_MERCURY_MISSILE_1 &&  !Netgame.DoMercury)
4878 		return (0);
4879 	if (id == POW_MERCURY_MISSILE_4 &&  !Netgame.DoMercury)
4880 		return (0);
4881 	if (id == POW_CONVERTER &&  !Netgame.DoConverter)
4882 		return (0);
4883 	if (id == POW_AMMO_RACK &&  !Netgame.DoAmmoRack)
4884 		return (0);
4885 	if (id == POW_HEADLIGHT &&  !Netgame.DoHeadlight)
4886 		return (0);
4887 	if (id == POW_LASER &&  !Netgame.DoLaserUpgrade)
4888 		return (0);
4889 	if (id == POW_HOMING_AMMO_1 &&  !Netgame.DoHoming)
4890 		return (0);
4891 	if (id == POW_HOMING_AMMO_4 &&  !Netgame.DoHoming)
4892 		return (0);
4893 	if (id == POW_QUAD_FIRE &&  !Netgame.DoQuadLasers)
4894 		return (0);
4895 	if (id == POW_FLAG_BLUE && !(Game_mode & GM_CAPTURE))
4896 		return (0);
4897 	if (id == POW_FLAG_RED && !(Game_mode & GM_CAPTURE))
4898 		return (0);
4899 
4900 	return (1);
4901 }
4902 
multi_send_finish_game()4903 void multi_send_finish_game ()
4904 {
4905 	multibuf[0]=MULTI_FINISH_GAME;
4906 	multibuf[1]=Player_num;
4907 
4908 	multi_send_data (multibuf,2,1);
4909 }
4910 
4911 
4912 extern void do_final_boss_hacks();
multi_do_finish_game(char * buf)4913 void multi_do_finish_game (char *buf)
4914 {
4915 	if (buf[0]!=MULTI_FINISH_GAME)
4916 		return;
4917 
4918 	if (Current_level_num!=Last_level)
4919 		return;
4920 
4921 	do_final_boss_hacks();
4922 }
4923 
multi_send_trigger_specific(char pnum,char trig)4924 void multi_send_trigger_specific (char pnum,char trig)
4925 {
4926 	multibuf[0] = MULTI_START_TRIGGER;
4927 	multibuf[1] = trig;
4928 
4929 	network_send_naked_packet(multibuf, 2, pnum);
4930 }
multi_do_start_trigger(char * buf)4931 void multi_do_start_trigger (char *buf)
4932 {
4933 	Triggers[(int)buf[1]].flags |=TF_DISABLED;
4934 }
4935 
4936 extern char *RankStrings[];
4937 
multi_add_lifetime_kills()4938 void multi_add_lifetime_kills ()
4939 {
4940 	// This function adds a kill to lifetime stats of this player, and possibly
4941 	// gives a promotion.  If so, it will tell everyone else
4942 
4943 	int oldrank;
4944 
4945 	if (!Game_mode & GM_NETWORK)
4946 		return;
4947 
4948 	oldrank=GetMyNetRanking();
4949 
4950 	Netlife_kills++;
4951 
4952 	if (oldrank!=GetMyNetRanking())
4953 	{
4954 		multi_send_ranking();
4955 		if (!FindArg("-norankings"))
4956 		{
4957 			HUD_init_message ("You have been promoted to %s!",RankStrings[GetMyNetRanking()]);
4958 			digi_play_sample (SOUND_BUDDY_MET_GOAL,F1_0*2);
4959 			NetPlayers.players[Player_num].rank=GetMyNetRanking();
4960 		}
4961 	}
4962 	write_player_file();
4963 }
4964 
multi_add_lifetime_killed()4965 void multi_add_lifetime_killed ()
4966 {
4967 	// This function adds a "killed" to lifetime stats of this player, and possibly
4968 	// gives a demotion.  If so, it will tell everyone else
4969 
4970 	int oldrank;
4971 
4972 	if (!Game_mode & GM_NETWORK)
4973 		return;
4974 
4975 	oldrank=GetMyNetRanking();
4976 
4977 	Netlife_killed++;
4978 
4979 	if (oldrank!=GetMyNetRanking())
4980 	{
4981 		multi_send_ranking();
4982 		NetPlayers.players[Player_num].rank=GetMyNetRanking();
4983 
4984 		if (!FindArg("-norankings"))
4985 			HUD_init_message ("You have been demoted to %s!",RankStrings[GetMyNetRanking()]);
4986 
4987 	}
4988 	write_player_file();
4989 
4990 }
4991 
multi_send_ranking()4992 void multi_send_ranking ()
4993 {
4994 	multibuf[0]=(char)MULTI_RANK;
4995 	multibuf[1]=(char)Player_num;
4996 	multibuf[2]=(char)GetMyNetRanking();
4997 
4998 	multi_send_data (multibuf,3,1);
4999 }
5000 
multi_do_ranking(char * buf)5001 void multi_do_ranking (char *buf)
5002 {
5003 	char rankstr[20];
5004 	char pnum=buf[1];
5005 	char rank=buf[2];
5006 
5007 	if (NetPlayers.players[(int)pnum].rank<rank)
5008 		strcpy (rankstr,"promoted");
5009 	else if (NetPlayers.players[(int)pnum].rank>rank)
5010 		strcpy (rankstr,"demoted");
5011 	else
5012 		return;
5013 
5014 	NetPlayers.players[(int)pnum].rank=rank;
5015 
5016 	if (!FindArg("-norankings"))
5017 		HUD_init_message ("%s has been %s to %s!",Players[(int)pnum].callsign,rankstr,RankStrings[(int)rank]);
5018 }
multi_send_modem_ping()5019 void multi_send_modem_ping ()
5020 {
5021 	multibuf[0]=MULTI_MODEM_PING;
5022 	multi_send_data (multibuf,1,1);
5023 }
multi_send_modem_ping_return()5024 void multi_send_modem_ping_return ()
5025 {
5026 	multibuf[0]=MULTI_MODEM_PING_RETURN;
5027 	multi_send_data (multibuf,1,1);
5028 }
5029 
multi_do_modem_ping_return()5030 void  multi_do_modem_ping_return ()
5031 {
5032 	if (PingLaunchTime==0)
5033 	{
5034 		mprintf ((0,"Got invalid PING RETURN from opponent!\n"));
5035 		return;
5036 	}
5037 
5038 	PingReturnTime=timer_get_fixed_seconds();
5039 
5040 	HUD_init_message ("Ping time for opponent is %d ms!",f2i(fixmul(PingReturnTime-PingLaunchTime,i2f(1000))));
5041 	PingLaunchTime=0;
5042 }
5043 
5044 
multi_quick_sound_hack(int num)5045 void multi_quick_sound_hack (int num)
5046 {
5047 	int length,i;
5048 	num = digi_xlat_sound(num);
5049 	length=GameSounds[num].length;
5050 	ReversedSound.data=(ubyte *)d_malloc (length);
5051 	ReversedSound.length=length;
5052 
5053 	for (i=0;i<length;i++)
5054 		ReversedSound.data[i]=GameSounds[num].data[length-i-1];
5055 
5056 	SoundHacked=1;
5057 }
5058 
multi_send_play_by_play(int num,int spnum,int dpnum)5059 void multi_send_play_by_play (int num,int spnum,int dpnum)
5060 {
5061 	if (!(Game_mode & GM_HOARD))
5062 		return;
5063 
5064 	return;
5065 	multibuf[0]=MULTI_PLAY_BY_PLAY;
5066 	multibuf[1]=(char)num;
5067 	multibuf[2]=(char)spnum;
5068 	multibuf[3]=(char)dpnum;
5069 	multi_send_data (multibuf,4,1);
5070 	multi_do_play_by_play (multibuf);
5071 }
5072 
multi_do_play_by_play(char * buf)5073 void multi_do_play_by_play (char *buf)
5074 {
5075 	int whichplay=buf[1];
5076 	int spnum=buf[2];
5077 	int dpnum=buf[3];
5078 
5079 	if (!(Game_mode & GM_HOARD))
5080 	{
5081 		Int3(); // Get Leighton, something bad has happened.
5082 		return;
5083 	}
5084 
5085 	switch (whichplay)
5086 	{
5087 	case 0: // Smacked!
5088 		HUD_init_message ("Ouch! %s has been smacked by %s!",Players[dpnum].callsign,Players[spnum].callsign);
5089 		break;
5090 	case 1: // Spanked!
5091 		HUD_init_message ("Haha! %s has been spanked by %s!",Players[dpnum].callsign,Players[spnum].callsign);
5092 		break;
5093 	default:
5094 		Int3();
5095 	}
5096 }
5097 
5098 ///
5099 /// CODE TO LOAD HOARD DATA
5100 ///
5101 
5102 
init_bitmap(grs_bitmap * bm,int w,int h,int flags,ubyte * data)5103 void init_bitmap(grs_bitmap *bm,int w,int h,int flags,ubyte *data)
5104 {
5105 	bm->bm_x = bm->bm_y = 0;
5106 	bm->bm_w = bm->bm_rowsize = w;
5107 	bm->bm_h = h;
5108 	bm->bm_type = BM_LINEAR;
5109 	bm->bm_flags = flags;
5110 	bm->bm_data = data;
5111 	bm->bm_handle = 0;
5112 	bm->avg_color = 0;
5113 }
5114 
5115 grs_bitmap Orb_icons[2];
5116 
5117 int Hoard_goal_eclip;
5118 
init_hoard_data()5119 void init_hoard_data()
5120 {
5121 	static int first_time=1;
5122 	static int orb_vclip;
5123 	int n_orb_frames,n_goal_frames;
5124 	int orb_w,orb_h;
5125 	int icon_w,icon_h;
5126 	ubyte palette[256*3];
5127 	CFILE *ifile;
5128 	int i,save_pos;
5129 	extern int Num_bitmap_files,Num_effects,Num_sound_files;
5130 
5131 	ifile = cfopen("hoard.ham","rb");
5132 	if (ifile == NULL)
5133 		Error("can't open <hoard.ham>");
5134 
5135 	n_orb_frames = cfile_read_short(ifile);
5136 	orb_w = cfile_read_short(ifile);
5137 	orb_h = cfile_read_short(ifile);
5138 	save_pos = cftell(ifile);
5139 	cfseek(ifile,sizeof(palette)+n_orb_frames*orb_w*orb_h,SEEK_CUR);
5140 	n_goal_frames = cfile_read_short(ifile);
5141 	cfseek(ifile,save_pos,SEEK_SET);
5142 
5143 	if (first_time) {
5144 		ubyte *bitmap_data;
5145 		int bitmap_num=Num_bitmap_files;
5146 
5147 		//Allocate memory for bitmaps
5148 		MALLOC( bitmap_data, ubyte, n_orb_frames*orb_w*orb_h + n_goal_frames*64*64 );
5149 
5150 		//Create orb vclip
5151 		orb_vclip = Num_vclips++;
5152 		Assert(Num_vclips <= VCLIP_MAXNUM);
5153 		Vclip[orb_vclip].play_time = F1_0/2;
5154 		Vclip[orb_vclip].num_frames = n_orb_frames;
5155 		Vclip[orb_vclip].frame_time = Vclip[orb_vclip].play_time / Vclip[orb_vclip].num_frames;
5156 		Vclip[orb_vclip].flags = 0;
5157 		Vclip[orb_vclip].sound_num = -1;
5158 		Vclip[orb_vclip].light_value = F1_0;
5159 		for (i=0;i<n_orb_frames;i++) {
5160 			Vclip[orb_vclip].frames[i].index = bitmap_num;
5161 			init_bitmap(&GameBitmaps[bitmap_num],orb_w,orb_h,BM_FLAG_TRANSPARENT,bitmap_data);
5162 			bitmap_data += orb_w*orb_h;
5163 			bitmap_num++;
5164 			Assert(bitmap_num < MAX_BITMAP_FILES);
5165 		}
5166 
5167 		//Create obj powerup
5168 		Powerup_info[POW_HOARD_ORB].vclip_num = orb_vclip;
5169 		Powerup_info[POW_HOARD_ORB].hit_sound = -1; //Powerup_info[POW_SHIELD_BOOST].hit_sound;
5170 		Powerup_info[POW_HOARD_ORB].size = Powerup_info[POW_SHIELD_BOOST].size;
5171 		Powerup_info[POW_HOARD_ORB].light = Powerup_info[POW_SHIELD_BOOST].light;
5172 
5173 		//Create orb goal wall effect
5174 		Hoard_goal_eclip = Num_effects++;
5175 		Assert(Num_effects < MAX_EFFECTS);
5176 		Effects[Hoard_goal_eclip] = Effects[94];        //copy from blue goal
5177 		Effects[Hoard_goal_eclip].changing_wall_texture = NumTextures;
5178 		Effects[Hoard_goal_eclip].vc.num_frames=n_goal_frames;
5179 
5180 		TmapInfo[NumTextures] = TmapInfo[find_goal_texture(TMI_GOAL_BLUE)];
5181 		TmapInfo[NumTextures].eclip_num = Hoard_goal_eclip;
5182 		TmapInfo[NumTextures].flags = TMI_GOAL_HOARD;
5183 		NumTextures++;
5184 		Assert(NumTextures < MAX_TEXTURES);
5185 		for (i=0;i<n_goal_frames;i++) {
5186 			Effects[Hoard_goal_eclip].vc.frames[i].index = bitmap_num;
5187 			init_bitmap(&GameBitmaps[bitmap_num],64,64,0,bitmap_data);
5188 			bitmap_data += 64*64;
5189 			bitmap_num++;
5190 			Assert(bitmap_num < MAX_BITMAP_FILES);
5191 		}
5192 
5193 	}
5194 
5195 	//Load and remap bitmap data for orb
5196 	cfread(palette,3,256,ifile);
5197 	for (i=0;i<n_orb_frames;i++) {
5198 		grs_bitmap *bm = &GameBitmaps[Vclip[orb_vclip].frames[i].index];
5199 		cfread(bm->bm_data,1,orb_w*orb_h,ifile);
5200 		gr_remap_bitmap_good( bm, palette, 255, -1 );
5201 	}
5202 
5203 	//Load and remap bitmap data for goal texture
5204 	cfile_read_short(ifile);        //skip frame count
5205 	cfread(palette,3,256,ifile);
5206 	for (i=0;i<n_goal_frames;i++) {
5207 		grs_bitmap *bm = &GameBitmaps[Effects[Hoard_goal_eclip].vc.frames[i].index];
5208 		cfread(bm->bm_data,1,64*64,ifile);
5209 		gr_remap_bitmap_good( bm, palette, 255, -1 );
5210 	}
5211 
5212 	//Load and remap bitmap data for HUD icons
5213 	for (i=0;i<2;i++) {
5214 		icon_w = cfile_read_short(ifile);
5215 		icon_h = cfile_read_short(ifile);
5216 		if (first_time) {
5217 			ubyte *bitmap_data;
5218 			MALLOC( bitmap_data, ubyte, icon_w*icon_h );
5219 			init_bitmap(&Orb_icons[i],icon_w,icon_h,BM_FLAG_TRANSPARENT,bitmap_data);
5220 		}
5221 		cfread(palette,3,256,ifile);
5222 		cfread(Orb_icons[i].bm_data,1,icon_w*icon_h,ifile);
5223 		gr_remap_bitmap_good( &Orb_icons[i], palette, 255, -1 );
5224 	}
5225 
5226 	if (first_time) {
5227 
5228 		//Load sounds for orb game
5229 
5230 		for (i=0;i<4;i++) {
5231 			int len;
5232 
5233 			len = cfile_read_int(ifile);        //get 11k len
5234 
5235 			if (digi_sample_rate == SAMPLE_RATE_22K) {
5236 				cfseek(ifile,len,SEEK_CUR);     //skip over 11k sample
5237 				len = cfile_read_int(ifile);    //get 22k len
5238 			}
5239 
5240 			GameSounds[Num_sound_files+i].length = len;
5241 			GameSounds[Num_sound_files+i].data = d_malloc(len);
5242 			cfread(GameSounds[Num_sound_files+i].data,1,len,ifile);
5243 
5244 			if (digi_sample_rate == SAMPLE_RATE_11K) {
5245 				len = cfile_read_int(ifile);    //get 22k len
5246 				cfseek(ifile,len,SEEK_CUR);     //skip over 22k sample
5247 			}
5248 
5249 			Sounds[SOUND_YOU_GOT_ORB+i] = Num_sound_files+i;
5250 			AltSounds[SOUND_YOU_GOT_ORB+i] = Sounds[SOUND_YOU_GOT_ORB+i];
5251 		}
5252 	}
5253 
5254 	cfclose(ifile);
5255 
5256 	first_time = 0;
5257 }
5258 
5259 void
multi_process_data(char * buf,int len)5260 multi_process_data(char *buf, int len)
5261 {
5262 	// Take an entire message (that has already been checked for validity,
5263 	// if necessary) and act on it.
5264 
5265 	int type;
5266 	len = len;
5267 
5268 	type = buf[0];
5269 
5270 	if (type > MULTI_MAX_TYPE)
5271 	{
5272 		mprintf((1, "multi_process_data: invalid type %d.\n", type));
5273 		Int3();
5274 		return;
5275 	}
5276 
5277 
5278 #ifdef NETPROFILING
5279 	TTRecv[type]++;
5280 	fprintf (RecieveLogFile,"Packet type: %d Len:%d TT=%d\n",type,len,TTRecv[type]);
5281 	fflush (RecieveLogFile);
5282 #endif
5283 
5284 	switch(type)
5285 	{
5286 	case MULTI_POSITION:
5287 		if (!Endlevel_sequence) multi_do_position(buf); break;
5288 	case MULTI_REAPPEAR:
5289 		if (!Endlevel_sequence) multi_do_reappear(buf); break;
5290 	case MULTI_FIRE:
5291 		if (!Endlevel_sequence) multi_do_fire(buf); break;
5292 	case MULTI_KILL:
5293 		multi_do_kill(buf); break;
5294 	case MULTI_REMOVE_OBJECT:
5295 		if (!Endlevel_sequence) multi_do_remobj(buf); break;
5296 	case MULTI_PLAYER_DROP:
5297 	case MULTI_PLAYER_EXPLODE:
5298 		if (!Endlevel_sequence) multi_do_player_explode(buf); break;
5299 	case MULTI_MESSAGE:
5300 		if (!Endlevel_sequence) multi_do_message(buf); break;
5301 	case MULTI_QUIT:
5302 		if (!Endlevel_sequence) multi_do_quit(buf); break;
5303 	case MULTI_BEGIN_SYNC:
5304 		break;
5305 	case MULTI_CONTROLCEN:
5306 		if (!Endlevel_sequence) multi_do_controlcen_destroy(buf); break;
5307 	case MULTI_POWERUP_UPDATE:
5308 		if (!Endlevel_sequence) multi_do_powerup_update(buf); break;
5309 	case MULTI_SOUND_FUNCTION:
5310 		multi_do_sound_function(buf); break;
5311 	case MULTI_MARKER:
5312 		if (!Endlevel_sequence) multi_do_drop_marker (buf); break;
5313 	case MULTI_DROP_WEAPON:
5314 		if (!Endlevel_sequence) multi_do_drop_weapon(buf); break;
5315 	case MULTI_DROP_FLAG:
5316 		if (!Endlevel_sequence) multi_do_drop_flag(buf); break;
5317 	case MULTI_GUIDED:
5318 		if (!Endlevel_sequence) multi_do_guided (buf); break;
5319 	case MULTI_STOLEN_ITEMS:
5320 		if (!Endlevel_sequence) multi_do_stolen_items(buf); break;
5321 	case MULTI_WALL_STATUS:
5322 		if (!Endlevel_sequence) multi_do_wall_status(buf); break;
5323 	case MULTI_HEARTBEAT:
5324 		if (!Endlevel_sequence) multi_do_heartbeat (buf); break;
5325 	case MULTI_SEISMIC:
5326 		if (!Endlevel_sequence) multi_do_seismic (buf); break;
5327 	case MULTI_LIGHT:
5328 		if (!Endlevel_sequence) multi_do_light (buf); break;
5329 	case MULTI_KILLGOALS:
5330 
5331 		if (!Endlevel_sequence) multi_do_kill_goal_counts (buf); break;
5332 	case MULTI_ENDLEVEL_START:
5333 		if (!Endlevel_sequence) multi_do_escape(buf); break;
5334 	case MULTI_END_SYNC:
5335 		break;
5336 	case MULTI_CLOAK:
5337 		if (!Endlevel_sequence) multi_do_cloak(buf); break;
5338 	case MULTI_DECLOAK:
5339 		if (!Endlevel_sequence) multi_do_decloak(buf); break;
5340 	case MULTI_DOOR_OPEN:
5341 		if (!Endlevel_sequence) multi_do_door_open(buf); break;
5342 	case MULTI_CREATE_EXPLOSION:
5343 		if (!Endlevel_sequence) multi_do_create_explosion(buf); break;
5344 	case MULTI_CONTROLCEN_FIRE:
5345 		if (!Endlevel_sequence) multi_do_controlcen_fire(buf); break;
5346 	case MULTI_CREATE_POWERUP:
5347 		if (!Endlevel_sequence) multi_do_create_powerup(buf); break;
5348 	case MULTI_PLAY_SOUND:
5349 		if (!Endlevel_sequence) multi_do_play_sound(buf); break;
5350 	case MULTI_CAPTURE_BONUS:
5351 		if (!Endlevel_sequence) multi_do_capture_bonus(buf); break;
5352 	case MULTI_ORB_BONUS:
5353 		if (!Endlevel_sequence) multi_do_orb_bonus(buf); break;
5354 	case MULTI_GOT_FLAG:
5355 		if (!Endlevel_sequence) multi_do_got_flag(buf); break;
5356 	case MULTI_GOT_ORB:
5357 		if (!Endlevel_sequence) multi_do_got_orb(buf); break;
5358 	case MULTI_PLAY_BY_PLAY:
5359 		if (!Endlevel_sequence) multi_do_play_by_play(buf); break;
5360 	case MULTI_RANK:
5361 		if (!Endlevel_sequence) multi_do_ranking (buf); break;
5362 	case MULTI_MODEM_PING:
5363 		if (!Endlevel_sequence) multi_send_modem_ping_return(); break;
5364 	case MULTI_MODEM_PING_RETURN:
5365 		if (!Endlevel_sequence) multi_do_modem_ping_return(); break;
5366 #ifndef SHAREWARE
5367 	case MULTI_FINISH_GAME:
5368 		multi_do_finish_game(buf); break;  // do this one regardless of endsequence
5369 	case MULTI_ROBOT_CONTROLS:
5370 		if (!Endlevel_sequence) multi_do_robot_controls(buf); break;
5371 	case MULTI_ROBOT_CLAIM:
5372 		if (!Endlevel_sequence) multi_do_claim_robot(buf); break;
5373 	case MULTI_ROBOT_POSITION:
5374 		if (!Endlevel_sequence) multi_do_robot_position(buf); break;
5375 	case MULTI_ROBOT_EXPLODE:
5376 		if (!Endlevel_sequence) multi_do_robot_explode(buf); break;
5377 	case MULTI_ROBOT_RELEASE:
5378 		if (!Endlevel_sequence) multi_do_release_robot(buf); break;
5379 	case MULTI_ROBOT_FIRE:
5380 		if (!Endlevel_sequence) multi_do_robot_fire(buf); break;
5381 #endif
5382 	case MULTI_SCORE:
5383 		if (!Endlevel_sequence) multi_do_score(buf); break;
5384 	case MULTI_CREATE_ROBOT:
5385 		if (!Endlevel_sequence) multi_do_create_robot(buf); break;
5386 	case MULTI_TRIGGER:
5387 		if (!Endlevel_sequence) multi_do_trigger(buf); break;
5388 	case MULTI_START_TRIGGER:
5389 		if (!Endlevel_sequence) multi_do_start_trigger(buf); break;
5390 	case MULTI_FLAGS:
5391 		if (!Endlevel_sequence) multi_do_flags(buf); break;
5392 	case MULTI_DROP_BLOB:
5393 		if (!Endlevel_sequence) multi_do_drop_blob(buf); break;
5394 	case MULTI_ACTIVE_DOOR:
5395 		if (!Endlevel_sequence) multi_do_active_door(buf); break;
5396 	case MULTI_BOSS_ACTIONS:
5397 		if (!Endlevel_sequence) multi_do_boss_actions(buf); break;
5398 	case MULTI_CREATE_ROBOT_POWERUPS:
5399 		if (!Endlevel_sequence) multi_do_create_robot_powerups(buf); break;
5400 	case MULTI_HOSTAGE_DOOR:
5401 		if (!Endlevel_sequence) multi_do_hostage_door_status(buf); break;
5402 	case MULTI_SAVE_GAME:
5403 		if (!Endlevel_sequence) multi_do_save_game(buf); break;
5404 	case MULTI_RESTORE_GAME:
5405 		if (!Endlevel_sequence) multi_do_restore_game(buf); break;
5406 	case MULTI_REQ_PLAYER:
5407 		if (!Endlevel_sequence) multi_do_req_player(buf); break;
5408 	case MULTI_SEND_PLAYER:
5409 		if (!Endlevel_sequence) multi_do_send_player(buf); break;
5410 
5411 	default:
5412 		mprintf((1, "Invalid type in multi_process_input().\n"));
5413 		Int3();
5414 	}
5415 }
5416