2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
15 * $Source: /cvs/cvsroot/d2x/main/multi.c,v $
18 * $Date: 2003-02-27 22:07:21 $
20 * FIXME: put description here
22 * $Log: not supported by cvs2svn $
23 * Revision 1.7 2002/12/31 23:19:42 btb
26 * Revision 1.6 2002/08/30 01:01:18 btb
27 * more networking fixes
29 * Revision 1.5 2001/10/23 21:53:19 bradleyb
30 * No longer #ifdef'ing out the whole file. RCS header added
90 void multi_reset_player_object(object *objp);
91 void multi_reset_object_texture (object *objp);
92 void multi_add_lifetime_killed ();
93 void multi_add_lifetime_kills ();
94 void multi_send_play_by_play (int num,int spnum,int dpnum);
95 void multi_send_heartbeat ();
96 void multi_send_modem_ping ();
97 void multi_cap_objects ();
98 void multi_adjust_remote_cap (int pnum);
99 void multi_save_game(ubyte slot, uint id, char *desc);
100 void multi_restore_game(ubyte slot, uint id);
101 void multi_set_robot_ai(void);
102 void multi_send_powerup_update ();
103 void bash_to_shield (int i,char *s);
104 void init_hoard_data();
105 void multi_apply_goal_textures();
106 int find_goal_texture (ubyte t);
107 void multi_bad_restore ();
108 void multi_do_capture_bonus(char *buf);
109 void multi_do_orb_bonus(char *buf);
110 void multi_send_drop_flag (int objnum,int seed);
111 void multi_send_ranking ();
112 void multi_do_play_by_play (char *buf);
115 // Local macros and prototypes
120 #define vm_angvec_zero(v) (v)->p=(v)->b=(v)->h=0
122 void drop_player_eggs(object *player); // from collide.c
123 void GameLoop(int, int); // From game.c
129 extern vms_vector MarkerPoint[];
130 extern char MarkerMessage[16][40];
131 extern char MarkerOwner[16][40];
132 extern int MarkerObject[];
134 int control_invul_time = 0;
135 int who_killed_controlcen = -1; // -1 = noone
137 //do we draw the kill list on the HUD?
138 int Show_kill_list = 1;
139 int Show_reticle_name = 1;
140 fix Show_kill_list_timer = 0;
142 char Multi_is_guided=0;
143 char PKilledFlags[MAX_NUM_NET_PLAYERS];
145 int multi_sending_message = 0;
146 int multi_defining_message = 0;
147 int multi_message_index = 0;
149 char multibuf[MAX_MULTI_MESSAGE_LEN+4]; // This is where multiplayer message are built
151 short remote_to_local[MAX_NUM_NET_PLAYERS][MAX_OBJECTS]; // Remote object number for each local object
152 short local_to_remote[MAX_OBJECTS];
153 byte object_owner[MAX_OBJECTS]; // Who created each object in my universe, -1 = loaded at start
155 int Net_create_objnums[MAX_NET_CREATE_OBJECTS]; // For tracking object creation that will be sent to remote
156 int Net_create_loc = 0; // pointer into previous array
157 int Network_laser_fired = 0; // How many times we shot
158 int Network_laser_gun; // Which gun number we shot
159 int Network_laser_flags; // Special flags for the shot
160 int Network_laser_level; // What level
161 short Network_laser_track; // Who is it tracking?
162 char Network_message[MAX_MESSAGE_LEN];
163 char Network_message_macro[4][MAX_MESSAGE_LEN];
164 int Network_message_reciever=-1;
165 int sorted_kills[MAX_NUM_NET_PLAYERS];
166 short kill_matrix[MAX_NUM_NET_PLAYERS][MAX_NUM_NET_PLAYERS];
167 int multi_goto_secret = 0;
169 int multi_in_menu = 0;
170 int multi_leave_menu = 0;
171 int multi_quit_game = 0;
173 netgame_info Netgame;
174 AllNetPlayers_info NetPlayers;
176 bitmap_index multi_player_textures[MAX_NUM_NET_PLAYERS][N_PLAYER_SHIP_TEXTURES];
178 typedef struct netplayer_stats {
180 ubyte Player_num; // Who am i?
181 uint flags; // Powerup flags, see below...
182 fix energy; // Amount of energy remaining.
183 fix shields; // shields remaining (protection)
184 ubyte lives; // Lives remaining, 0 = game over.
185 ubyte laser_level; // Current level of the laser.
186 ubyte primary_weapon_flags; // bit set indicates the player has this weapon.
187 ubyte secondary_weapon_flags; // bit set indicates the player has this weapon.
188 ushort primary_ammo[MAX_PRIMARY_WEAPONS]; // How much ammo of each type.
189 ushort secondary_ammo[MAX_SECONDARY_WEAPONS]; // How much ammo of each type.
190 int last_score; // Score at beginning of current level.
191 int score; // Current score.
192 fix cloak_time; // Time cloaked
193 fix invulnerable_time; // Time invulnerable
194 fix homing_object_dist; // Distance of nearest homing object.
196 short net_killed_total; // Number of times killed total
197 short net_kills_total; // Number of net kills total
198 short num_kills_level; // Number of kills this level
199 short num_kills_total; // Number of kills total
200 short num_robots_level; // Number of initial robots this level
201 short num_robots_total; // Number of robots total
202 ushort hostages_rescued_total; // Total number of hostages rescued.
203 ushort hostages_total; // Total number of hostages.
204 ubyte hostages_on_board; // Number of hostages on ship.
208 int message_length[MULTI_MAX_TYPE+1] = {
214 97+9, // PLAYER_EXPLODE
215 37, // MESSAGE (MAX_MESSAGE_LENGTH = 40)
225 2, // CREATE_EXPLOSION
226 16, // CONTROLCEN_FIRE
228 19, // CREATE_POWERUP
232 28, // ROBOT_POSITION (shortpos_length (23) + 5 = 28)
240 27, // ROBOT_POWERUPS
242 2+24, //SAVE_GAME (ubyte slot, uint id, char name[20])
243 2+4, //RESTORE_GAME (ubyte slot, uint id)
244 1+1, // MULTI_REQ_PLAYER
245 sizeof(netplayer_stats), // MULTI_SEND_PLAYER
247 12, // MULTI_DROP_WEAPON
249 3+sizeof(shortpos), // MULTI_GUIDED, IF SHORTPOS CHANGES, CHANGE MAC VALUE BELOW
251 26, //MULTI_GUIDED IF SIZE OF SHORTPOS CHANGES, CHANGE THIS VALUE AS WELL!!!!!!
253 11, // MULTI_STOLEN_ITEMS
254 6, // MULTI_WALL_STATUS
255 5, // MULTI_HEARTBEAT
256 9, // MULTI_KILLGOALS
259 2, // MULTI_START_TRIGGER
261 2, // MULTI_DROP_BLOB
262 MAX_POWERUP_TYPES+1, // MULTI_POWERUP_UPDATE
263 sizeof(active_door)+3, // MULTI_ACTIVE_DOOR
264 4, // MULTI_SOUND_FUNCTION
265 2, // MULTI_CAPTURE_BONUS
267 12, // MULTI_DROP_FLAG
268 142, // MULTI_ROBOT_CONTROLS
269 2, // MULTI_FINISH_GAME
271 1, // MULTI_MODEM_PING
272 1, // MULTI_MODEM_PING_RETURN
273 3, // MULTI_ORB_BONUS
275 12, // MULTI_DROP_ORB
276 4, // MULTI_PLAY_BY_PLAY
279 void extract_netplayer_stats( netplayer_stats *ps, player * pd );
280 void use_netplayer_stats( player * ps, netplayer_stats *pd );
281 char PowerupsInMine[MAX_POWERUP_TYPES],MaxPowerupsAllowed[MAX_POWERUP_TYPES];
282 extern fix ThisLevelTime;
285 // Functions that replace what used to be macros
288 int objnum_remote_to_local(int remote_objnum, int owner)
290 // Map a remote object number from owner to a local object number
294 if ((owner >= N_players) || (owner < -1)) {
296 return(remote_objnum);
300 return(remote_objnum);
302 if ((remote_objnum < 0) || (remote_objnum >= MAX_OBJECTS))
305 result = remote_to_local[owner][remote_objnum];
309 mprintf((1, "Remote object owner %d number %d mapped to -1!\n", owner, remote_objnum));
314 if (object_owner[result] != owner)
316 mprintf((1, "Remote object owner %d number %d doesn't match owner %d.\n", owner, remote_objnum, object_owner[result]));
319 // Assert(object_owner[result] == owner);
324 int objnum_local_to_remote(int local_objnum, byte *owner)
326 // Map a local object number to a remote + owner
330 if ((local_objnum < 0) || (local_objnum > Highest_object_index)) {
335 *owner = object_owner[local_objnum];
338 return(local_objnum);
340 if ((*owner >= N_players) || (*owner < -1)) {
346 result = local_to_remote[local_objnum];
348 // mprintf((0, "Local object %d mapped to owner %d objnum %d.\n", local_objnum,
353 Int3(); // See Rob, object has no remote number!
360 map_objnum_local_to_remote(int local_objnum, int remote_objnum, int owner)
362 // Add a mapping from a network remote object number to a local one
364 Assert(local_objnum > -1);
365 Assert(remote_objnum > -1);
367 Assert(owner != Player_num);
368 Assert(local_objnum < MAX_OBJECTS);
369 Assert(remote_objnum < MAX_OBJECTS);
371 object_owner[local_objnum] = owner;
373 remote_to_local[owner][remote_objnum] = local_objnum;
374 local_to_remote[local_objnum] = remote_objnum;
380 map_objnum_local_to_local(int local_objnum)
382 // Add a mapping for our locally created objects
384 Assert(local_objnum > -1);
385 Assert(local_objnum < MAX_OBJECTS);
387 object_owner[local_objnum] = Player_num;
388 remote_to_local[Player_num][local_objnum] = local_objnum;
389 local_to_remote[local_objnum] = local_objnum;
395 // Part 1 : functions whose main purpose in life is to divert the flow
396 // of execution to either network or serial specific code based
397 // on the curretn Game_mode value.
401 multi_endlevel_score(void)
406 // Show a score list to end of net players
408 // Save connect state and change to new connect state
410 if (Game_mode & GM_NETWORK)
412 old_connect = Players[Player_num].connected;
413 if (Players[Player_num].connected!=3)
414 Players[Player_num].connected = CONNECT_END_MENU;
415 Network_status = NETSTAT_ENDLEVEL;
420 // Do the actual screen we wish to show
422 Function_mode = FMODE_MENU;
424 kmatrix_view(Game_mode & GM_NETWORK);
426 Function_mode = FMODE_GAME;
428 // Restore connect state
430 if (Game_mode & GM_NETWORK)
432 Players[Player_num].connected = old_connect;
436 if (Game_mode & GM_MULTI_COOP)
439 for (i = 0; i < MaxNumNetPlayers; i++)
441 Players[i].flags &= ~(PLAYER_FLAGS_BLUE_KEY | PLAYER_FLAGS_RED_KEY | PLAYER_FLAGS_GOLD_KEY);
443 for (i = 0; i < MaxNumNetPlayers; i++)
444 Players[i].flags &= ~(PLAYER_FLAGS_FLAG); // Clear capture flag
448 for (i=0;i<MAX_PLAYERS;i++)
449 Players[i].KillGoalCount=0;
451 for (i=0;i<MAX_POWERUP_TYPES;i++)
453 MaxPowerupsAllowed[i]=0;
462 if ((Game_mode & GM_CAPTURE) && ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM)))
465 if (Netgame.team_vector & (1 << pnum))
472 multi_choose_mission(int *anarchy_only)
476 char *m[MAX_MISSIONS];
477 int new_mission_num = 0;
481 n_missions = build_mission_list(1);
483 if (n_missions > 1) {
486 for (i=0;i<n_missions;i++) {
487 m[i] = Mission_list[i].mission_name;
488 if ( !stricmp( m[i], config_last_mission ) )
492 ExtGameStatus=GAMESTAT_START_MULTIPLAYER_MISSION;
493 new_mission_num = newmenu_listbox1(TXT_MULTI_MISSION, n_missions, m, 1, default_mission, NULL );
495 if (new_mission_num == -1)
498 strcpy(config_last_mission, m[new_mission_num] );
500 if (!load_mission(new_mission_num)) {
501 nm_messagebox( NULL, 1, TXT_OK, TXT_MISSION_ERROR);
505 *anarchy_only = Mission_list[new_mission_num].anarchy_only_flag;
507 return(new_mission_num);
510 extern void game_disable_cheats();
517 // Reset variables for a new net game
519 memset(kill_matrix, 0, MAX_NUM_NET_PLAYERS*MAX_NUM_NET_PLAYERS*2); // Clear kill matrix
521 for (i = 0; i < MAX_NUM_NET_PLAYERS; i++)
524 Players[i].net_killed_total = 0;
525 Players[i].net_kills_total = 0;
526 Players[i].flags = 0;
527 Players[i].KillGoalCount=0;
531 for (i = 0; i < MAX_ROBOTS_CONTROLLED; i++)
533 robot_controlled[i] = -1;
534 robot_agitation[i] = 0;
539 team_kills[0] = team_kills[1] = 0;
540 Endlevel_sequence = 0;
542 multi_leave_menu = 0;
545 game_disable_cheats();
547 Dead_player_camera = 0;
551 multi_make_player_ghost(int playernum)
555 // Assert(playernum != Player_num);
556 // Assert(playernum < MAX_NUM_NET_PLAYERS);
558 if ((playernum == Player_num) || (playernum >= MAX_NUM_NET_PLAYERS) || (playernum < 0))
560 Int3(); // Non-terminal, see Rob
564 // if (Objects[Players[playernum].objnum].type != OBJ_PLAYER)
565 // mprintf((1, "Warning: Player %d is not currently a player.\n", playernum));
567 obj = &Objects[Players[playernum].objnum];
569 obj->type = OBJ_GHOST;
570 obj->render_type = RT_NONE;
571 obj->movement_type = MT_NONE;
572 multi_reset_player_object(obj);
574 if (Game_mode & GM_MULTI_ROBOTS)
575 multi_strip_robots(playernum);
579 multi_make_ghost_player(int playernum)
583 // Assert(playernum != Player_num);
584 // Assert(playernum < MAX_NUM_NET_PLAYERS);
586 if ((playernum == Player_num) || (playernum >= MAX_NUM_NET_PLAYERS))
588 Int3(); // Non-terminal, see rob
592 // if(Objects[Players[playernum].objnum].type != OBJ_GHOST)
593 // mprintf((1, "Warning: Player %d is not currently a ghost.\n", playernum));
595 obj = &Objects[Players[playernum].objnum];
597 obj->type = OBJ_PLAYER;
598 obj->movement_type = MT_PHYSICS;
599 multi_reset_player_object(obj);
602 int multi_get_kill_list(int *plist)
604 // Returns the number of active net players and their
605 // sorted order of kills
609 for (i = 0; i < N_players; i++)
610 // if (Players[sorted_kills[i]].connected)
611 plist[n++] = sorted_kills[i];
614 Int3(); // SEE ROB OR MATT
616 // memcpy(plist, sorted_kills, N_players*sizeof(int));
622 multi_sort_kill_list(void)
624 // Sort the kills list each time a new kill is added
626 int kills[MAX_NUM_NET_PLAYERS];
630 for (i = 0; i < MAX_NUM_NET_PLAYERS; i++)
633 if (Game_mode & GM_MULTI_COOP)
634 kills[i] = Players[i].score;
637 if (Show_kill_list==2)
639 if (Players[i].net_killed_total+Players[i].net_kills_total==0)
640 kills[i]=-1; // always draw the ones without any ratio last
642 kills[i]=(int)((float)((float)Players[i].net_kills_total/((float)Players[i].net_killed_total+(float)Players[i].net_kills_total))*100.0);
645 kills[i] = Players[i].net_kills_total;
651 for (i = 0; i < N_players-1; i++)
653 if (kills[sorted_kills[i]] < kills[sorted_kills[i+1]])
655 changed = sorted_kills[i];
656 sorted_kills[i] = sorted_kills[i+1];
657 sorted_kills[i+1] = changed;
662 mprintf((0, "Sorted kills %d %d.\n", sorted_kills[0], sorted_kills[1]));
665 extern object *obj_find_first_of_type (int);
666 char Multi_killed_yourself=0;
668 void multi_compute_kill(int killer, int killed)
670 // Figure out the results of a network kills and add it to the
671 // appropriate player's tally.
673 int killed_pnum, killed_type;
674 int killer_pnum, killer_type,killer_id;
676 char killed_name[(CALLSIGN_LEN*2)+4];
677 char killer_name[(CALLSIGN_LEN*2)+4];
679 kmatrix_kills_changed = 1;
680 Multi_killed_yourself=0;
682 // Both object numbers are localized already!
684 mprintf((0, "compute_kill passed: object %d killed object %d.\n", killer, killed));
686 if ((killed < 0) || (killed > Highest_object_index) || (killer < 0) || (killer > Highest_object_index))
688 Int3(); // See Rob, illegal value passed to compute_kill;
692 killed_type = Objects[killed].type;
693 killer_type = Objects[killer].type;
694 killer_id = Objects[killer].id;
696 if ((killed_type != OBJ_PLAYER) && (killed_type != OBJ_GHOST))
698 Int3(); // compute_kill passed non-player object!
702 killed_pnum = Objects[killed].id;
704 PKilledFlags[killed_pnum]=1;
706 Assert ((killed_pnum >= 0) && (killed_pnum < N_players));
708 if (Game_mode & GM_TEAM)
709 sprintf(killed_name, "%s (%s)", Players[killed_pnum].callsign, Netgame.team_name[get_team(killed_pnum)]);
711 sprintf(killed_name, "%s", Players[killed_pnum].callsign);
713 if (Newdemo_state == ND_STATE_RECORDING)
714 newdemo_record_multi_death(killed_pnum);
716 digi_play_sample( SOUND_HUD_KILL, F3_0 );
718 if (Control_center_destroyed)
719 Players[killed_pnum].connected=3;
721 if (killer_type == OBJ_CNTRLCEN)
723 Players[killed_pnum].net_killed_total++;
724 Players[killed_pnum].net_kills_total--;
726 if (Newdemo_state == ND_STATE_RECORDING)
727 newdemo_record_multi_kill(killed_pnum, -1);
729 if (killed_pnum == Player_num)
731 HUD_init_message("%s %s.", TXT_YOU_WERE, TXT_KILLED_BY_NONPLAY);
732 multi_add_lifetime_killed ();
735 HUD_init_message("%s %s %s.", killed_name, TXT_WAS, TXT_KILLED_BY_NONPLAY );
740 else if ((killer_type != OBJ_PLAYER) && (killer_type != OBJ_GHOST))
742 if (killer_id==PMINE_ID && killer_type!=OBJ_ROBOT)
744 if (killed_pnum == Player_num)
745 HUD_init_message("You were killed by a mine!");
747 HUD_init_message("%s was killed by a mine!",killed_name);
751 if (killed_pnum == Player_num)
753 HUD_init_message("%s %s.", TXT_YOU_WERE, TXT_KILLED_BY_ROBOT);
754 multi_add_lifetime_killed();
757 HUD_init_message("%s %s %s.", killed_name, TXT_WAS, TXT_KILLED_BY_ROBOT );
759 Players[killed_pnum].net_killed_total++;
763 else if ((killer_type != OBJ_PLAYER) && (killer_type != OBJ_GHOST) && (killer_id!=PMINE_ID))
765 Int3(); // Illegal killer type?
768 if (killer_id==PMINE_ID)
770 if (killed_pnum==Player_num)
771 HUD_init_message("You were killed by a mine!");
773 HUD_init_message("%s was killed by a mine!",killed_name);
775 Players[killed_pnum].net_killed_total++;
781 killer_pnum = Objects[killer].id;
783 if (Game_mode & GM_TEAM)
784 sprintf(killer_name, "%s (%s)", Players[killer_pnum].callsign, Netgame.team_name[get_team(killer_pnum)]);
786 sprintf(killer_name, "%s", Players[killer_pnum].callsign);
788 // Beyond this point, it was definitely a player-player kill situation
790 if ((killer_pnum < 0) || (killer_pnum >= N_players))
791 Int3(); // See rob, tracking down bug with kill HUD messages
792 if ((killed_pnum < 0) || (killed_pnum >= N_players))
793 Int3(); // See rob, tracking down bug with kill HUD messages
795 if (killer_pnum == killed_pnum)
797 if (!(Game_mode & GM_HOARD))
799 if (Game_mode & GM_TEAM)
800 team_kills[get_team(killed_pnum)] -= 1;
802 Players[killed_pnum].net_killed_total += 1;
803 Players[killed_pnum].net_kills_total -= 1;
805 if (Newdemo_state == ND_STATE_RECORDING)
806 newdemo_record_multi_kill(killed_pnum, -1);
808 kill_matrix[killed_pnum][killed_pnum] += 1; // # of suicides
810 if (killer_pnum == Player_num)
812 HUD_init_message("%s %s %s!", TXT_YOU, TXT_KILLED, TXT_YOURSELF );
813 Multi_killed_yourself=1;
814 multi_add_lifetime_killed();
817 HUD_init_message("%s %s", killed_name, TXT_SUICIDE);
822 if (!(Game_mode & GM_HOARD))
824 if (Game_mode & GM_TEAM)
826 if (get_team(killed_pnum) == get_team(killer_pnum))
827 team_kills[get_team(killed_pnum)] -= 1;
829 team_kills[get_team(killer_pnum)] += 1;
832 Players[killer_pnum].net_kills_total += 1;
833 Players[killer_pnum].KillGoalCount+=1;
835 if (Newdemo_state == ND_STATE_RECORDING)
836 newdemo_record_multi_kill(killer_pnum, 1);
840 if (Game_mode & GM_TEAM)
842 if (killed_pnum==Player_num && get_team(killed_pnum) == get_team(killer_pnum))
843 Multi_killed_yourself=1;
847 kill_matrix[killer_pnum][killed_pnum] += 1;
848 Players[killed_pnum].net_killed_total += 1;
849 if (killer_pnum == Player_num) {
850 HUD_init_message("%s %s %s!", TXT_YOU, TXT_KILLED, killed_name);
851 multi_add_lifetime_kills();
852 if ((Game_mode & GM_MULTI_COOP) && (Players[Player_num].score >= 1000))
853 add_points_to_score(-1000);
855 else if (killed_pnum == Player_num)
857 HUD_init_message("%s %s %s!", killer_name, TXT_KILLED, TXT_YOU);
858 multi_add_lifetime_killed();
859 if (Game_mode & GM_HOARD)
861 if (Players[Player_num].secondary_ammo[PROXIMITY_INDEX]>3)
862 multi_send_play_by_play (1,killer_pnum,Player_num);
863 else if (Players[Player_num].secondary_ammo[PROXIMITY_INDEX]>0)
864 multi_send_play_by_play (0,killer_pnum,Player_num);
868 HUD_init_message("%s %s %s!", killer_name, TXT_KILLED, killed_name);
871 TheGoal=Netgame.KillGoal*5;
873 if (Netgame.KillGoal>0)
875 if (Players[killer_pnum].KillGoalCount>=TheGoal)
877 if (killer_pnum==Player_num)
879 HUD_init_message("You reached the kill goal!");
880 Players[Player_num].shields=i2f(200);
883 HUD_init_message ("%s has reached the kill goal!",Players[killer_pnum].callsign);
885 HUD_init_message ("The control center has been destroyed!");
886 net_destroy_controlcen (obj_find_first_of_type (OBJ_CNTRLCEN));
890 multi_sort_kill_list();
891 multi_show_player_list();
892 Players[killed_pnum].flags&=(~(PLAYER_FLAGS_HEADLIGHT_ON)); // clear the killed guys flags/headlights
898 static int lasttime=0;
901 if (!(Game_mode & GM_MULTI))
907 if ((Game_mode & GM_NETWORK) && Netgame.PlayTimeAllowed && lasttime!=f2i (ThisLevelTime))
909 for (i=0;i<N_players;i++)
910 if (Players[i].connected)
914 multi_send_heartbeat();
915 lasttime=f2i(ThisLevelTime);
921 multi_send_message(); // Send any waiting messages
924 multi_leave_menu = 0;
927 if (Game_mode & GM_MULTI_ROBOTS)
929 multi_check_robot_timeout();
933 if ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM))
939 network_do_frame(0, 1);
942 if (multi_quit_game && !multi_in_menu)
945 longjmp(LeaveGame, 0);
950 multi_send_data(char *buf, int len, int repeat)
952 Assert(len == message_length[(int)buf[0]]);
953 Assert(buf[0] <= MULTI_MAX_TYPE);
954 // Assert(buf[0] >= 0);
956 if (Game_mode & GM_NETWORK)
959 if ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM))
960 com_send_data(buf, len, repeat);
961 else if (Game_mode & GM_NETWORK)
962 network_send_data(buf, len, repeat);
966 multi_leave_game(void)
969 // if (Function_mode != FMODE_GAME)
972 if (!(Game_mode & GM_MULTI))
975 if (Game_mode & GM_NETWORK)
977 mprintf((0, "Sending explosion message.\n"));
982 drop_player_eggs(ConsoleObject);
983 multi_send_position(Players[Player_num].objnum);
984 multi_send_player_explode(MULTI_PLAYER_DROP);
987 mprintf((1, "Sending leave game.\n"));
988 multi_send_quit(MULTI_QUIT);
990 if ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM))
992 if (Game_mode & GM_NETWORK)
993 network_leave_game();
995 Game_mode |= GM_GAME_OVER;
997 if (Function_mode!=FMODE_EXIT)
998 Function_mode = FMODE_MENU;
1002 // change_playernum_to(0);
1003 // Viewer = ConsoleObject = &Objects[0];
1008 multi_show_player_list()
1010 if (!(Game_mode & GM_MULTI) || (Game_mode & GM_MULTI_COOP))
1016 Show_kill_list_timer = F1_0*5; // 5 second timer
1021 multi_endlevel(int *secret)
1025 if ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM))
1026 com_endlevel(secret); // an opportunity to re-sync or whatever
1027 else if (Game_mode & GM_NETWORK)
1028 result = network_endlevel(secret);
1034 // Part 2 : functions that act on network/serial messages and change the
1035 // the state of the game in some way.
1039 //extern PORT *com_port;
1043 multi_menu_poll(void)
1046 int was_fuelcen_alive;
1047 int player_was_dead;
1049 was_fuelcen_alive = Control_center_destroyed;
1051 // Special polling function for in-game menus for multiplayer and serial
1053 if (! ((Game_mode & GM_MULTI) && (Function_mode == FMODE_GAME)) )
1056 if (multi_leave_menu)
1059 old_shields = Players[Player_num].shields;
1060 player_was_dead = Player_is_dead;
1062 multi_in_menu++; // Track level of menu nesting
1068 timer_delay(f1_0/10); // delay 100 milliseconds
1070 if (Endlevel_sequence || (Control_center_destroyed && !was_fuelcen_alive) || (Player_is_dead != player_was_dead) || (Players[Player_num].shields < old_shields))
1072 multi_leave_menu = 1;
1075 if ((Control_center_destroyed) && (Countdown_seconds_left < 10))
1077 multi_leave_menu = 1;
1082 if ((Game_mode & GM_MODEM) && (!GetCd(com_port)))
1084 multi_leave_menu = 1;
1093 multi_define_macro(int key)
1095 if (!(Game_mode & GM_MULTI))
1098 key &= (~KEY_SHIFTED);
1103 multi_defining_message = 1; break;
1105 multi_defining_message = 2; break;
1107 multi_defining_message = 3; break;
1109 multi_defining_message = 4; break;
1114 if (multi_defining_message) {
1115 multi_message_index = 0;
1116 Network_message[multi_message_index] = 0;
1121 char feedback_result[200];
1124 multi_message_feedback(void)
1130 if (!( ((colon = strrchr(Network_message, ':')) == NULL) || (colon-Network_message < 1) || (colon-Network_message > CALLSIGN_LEN) ))
1132 sprintf(feedback_result, "%s ", TXT_MESSAGE_SENT_TO);
1133 if ((Game_mode & GM_TEAM) && (atoi(Network_message) > 0) && (atoi(Network_message) < 3))
1135 sprintf(feedback_result+strlen(feedback_result), "%s '%s'", TXT_TEAM, Netgame.team_name[atoi(Network_message)-1]);
1138 if (Game_mode & GM_TEAM)
1140 for (i = 0; i < N_players; i++)
1142 if (!strnicmp(Netgame.team_name[i], Network_message, colon-Network_message))
1145 strcat(feedback_result, ", ");
1148 strcat(feedback_result, "\n");
1149 sprintf(feedback_result+strlen(feedback_result), "%s '%s'", TXT_TEAM, Netgame.team_name[i]);
1153 for (i = 0; i < N_players; i++)
1155 if ((!strnicmp(Players[i].callsign, Network_message, colon-Network_message)) && (i != Player_num) && (Players[i].connected))
1158 strcat(feedback_result, ", ");
1161 strcat(feedback_result, "\n");
1162 sprintf(feedback_result+strlen(feedback_result), "%s", Players[i].callsign);
1166 strcat(feedback_result, TXT_NOBODY);
1168 strcat(feedback_result, ".");
1170 digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
1172 Assert(strlen(feedback_result) < 200);
1174 HUD_init_message(feedback_result);
1175 // sprintf (temp,"%s",colon);
1176 // sprintf (Network_message,"%s",temp);
1182 multi_send_macro(int key)
1184 if (! (Game_mode & GM_MULTI) )
1201 if (!Network_message_macro[key][0])
1203 HUD_init_message(TXT_NO_MACRO);
1207 strcpy(Network_message, Network_message_macro[key]);
1208 Network_message_reciever = 100;
1210 HUD_init_message("%s '%s'", TXT_SENDING, Network_message);
1211 multi_message_feedback();
1216 multi_send_message_start()
1218 if (Game_mode&GM_MULTI) {
1219 multi_sending_message = 1;
1220 multi_message_index = 0;
1221 Network_message[multi_message_index] = 0;
1225 extern fix StartingShields;
1226 fix PingLaunchTime,PingReturnTime;
1228 extern void network_send_ping (ubyte);
1229 extern int network_who_is_master();
1230 extern char NameReturning;
1231 extern int force_cockpit_redraw;
1233 void network_dump_appletalk_player(ubyte node, ushort net, ubyte socket, int why);
1235 void multi_send_message_end()
1240 Network_message_reciever = 100;
1242 if (!strnicmp (Network_message,"!Names",6))
1244 NameReturning=1-NameReturning;
1245 HUD_init_message ("Name returning is now %s.",NameReturning?"active":"disabled");
1247 else if (!strnicmp (Network_message,"Handicap:",9))
1249 mytempbuf=&Network_message[9];
1250 mprintf ((0,"Networkhandi=%s\n",mytempbuf));
1251 StartingShields=atol (mytempbuf);
1252 if (StartingShields<10)
1254 if (StartingShields>100)
1256 sprintf (Network_message,"%s has tried to cheat!",Players[Player_num].callsign);
1257 StartingShields=100;
1260 sprintf (Network_message,"%s handicap is now %d",Players[Player_num].callsign,StartingShields);
1262 HUD_init_message ("Telling others of your handicap of %d!",StartingShields);
1263 StartingShields=i2f(StartingShields);
1265 else if (!strnicmp (Network_message,"NoBombs",7))
1266 Netgame.DoSmartMine=0;
1267 else if (!strnicmp (Network_message,"Ping:",5))
1269 if (Game_mode & GM_NETWORK)
1272 if (strlen(Network_message) > 5)
1273 while (Network_message[name_index] == ' ')
1276 if (strlen(Network_message)<=name_index)
1278 HUD_init_message ("You must specify a name to ping");
1282 for (i = 0; i < N_players; i++)
1283 if ((!strnicmp(Players[i].callsign, &Network_message[name_index], strlen(Network_message)-name_index)) && (i != Player_num) && (Players[i].connected))
1285 PingLaunchTime=timer_get_fixed_seconds();
1286 network_send_ping (i);
1287 HUD_init_message("Pinging %s...",Players[i].callsign);
1288 multi_message_index = 0;
1289 multi_sending_message = 0;
1293 else // Modem/Serial ping
1295 PingLaunchTime=timer_get_fixed_seconds();
1296 multi_send_modem_ping ();
1297 HUD_init_message("Pinging opponent...");
1298 multi_message_index = 0;
1299 multi_sending_message = 0;
1303 else if (!strnicmp (Network_message,"move:",5))
1305 mprintf ((0,"moving?\n"));
1307 if ((Game_mode & GM_NETWORK) && (Game_mode & GM_TEAM))
1310 if (strlen(Network_message) > 5)
1311 while (Network_message[name_index] == ' ')
1314 if (!network_i_am_master())
1316 HUD_init_message ("Only %s can move players!",Players[network_who_is_master()].callsign);
1320 if (strlen(Network_message)<=name_index)
1322 HUD_init_message ("You must specify a name to move");
1326 for (i = 0; i < N_players; i++)
1327 if ((!strnicmp(Players[i].callsign, &Network_message[name_index], strlen(Network_message)-name_index)) && (Players[i].connected))
1329 if ((Game_mode & GM_CAPTURE) && (Players[i].flags & PLAYER_FLAGS_FLAG))
1331 HUD_init_message ("Can't move player because s/he has a flag!");
1335 if (Netgame.team_vector & (1<<i))
1336 Netgame.team_vector&=(~(1<<i));
1338 Netgame.team_vector|=(1<<i);
1340 for (t=0;t<N_players;t++)
1341 if (Players[t].connected)
1342 multi_reset_object_texture (&Objects[Players[t].objnum]);
1344 network_send_netgame_update ();
1345 sprintf (Network_message,"%s has changed teams!",Players[i].callsign);
1348 HUD_init_message ("You have changed teams!");
1352 HUD_init_message ("Moving %s to other team.",Players[i].callsign);
1358 else if (!strnicmp (Network_message,"kick:",5) && (Game_mode & GM_NETWORK))
1361 if (strlen(Network_message) > 5)
1362 while (Network_message[name_index] == ' ')
1365 if (!network_i_am_master())
1367 HUD_init_message ("Only %s can kick others out!",Players[network_who_is_master()].callsign);
1368 multi_message_index = 0;
1369 multi_sending_message = 0;
1372 if (strlen(Network_message)<=name_index)
1374 HUD_init_message ("You must specify a name to kick");
1375 multi_message_index = 0;
1376 multi_sending_message = 0;
1380 if (Network_message[name_index] == '#' && isdigit(Network_message[name_index+1])) {
1381 int players[MAX_NUM_NET_PLAYERS];
1382 int listpos = Network_message[name_index+1] - '0';
1384 mprintf ((0,"Trying to kick %d , show_kill_list=%d\n",listpos,Show_kill_list));
1386 if (Show_kill_list==1 || Show_kill_list==2) {
1387 if (listpos == 0 || listpos >= N_players) {
1388 HUD_init_message ("Invalid player number for kick.");
1389 multi_message_index = 0;
1390 multi_sending_message = 0;
1393 multi_get_kill_list(players);
1394 i = players[listpos];
1395 if ((i != Player_num) && (Players[i].connected))
1398 else HUD_init_message ("You cannot use # kicking with in team display.");
1401 multi_message_index = 0;
1402 multi_sending_message = 0;
1407 for (i = 0; i < N_players; i++)
1408 if ((!strnicmp(Players[i].callsign, &Network_message[name_index], strlen(Network_message)-name_index)) && (i != Player_num) && (Players[i].connected)) {
1410 if (Network_game_type == IPX_GAME)
1411 network_dump_player(NetPlayers.players[i].network.ipx.server,NetPlayers.players[i].network.ipx.node, 7);
1413 network_dump_appletalk_player(NetPlayers.players[i].network.appletalk.node,NetPlayers.players[i].network.appletalk.net, NetPlayers.players[i].network.appletalk.socket, 7);
1415 HUD_init_message("Dumping %s...",Players[i].callsign);
1416 multi_message_index = 0;
1417 multi_sending_message = 0;
1423 HUD_init_message("%s '%s'", TXT_SENDING, Network_message);
1425 multi_send_message();
1426 multi_message_feedback();
1428 multi_message_index = 0;
1429 multi_sending_message = 0;
1432 void multi_define_macro_end()
1434 Assert( multi_defining_message > 0 );
1436 strcpy( Network_message_macro[multi_defining_message-1], Network_message );
1437 write_player_file();
1439 multi_message_index = 0;
1440 multi_defining_message = 0;
1443 void multi_message_input_sub( int key )
1448 multi_sending_message = 0;
1449 multi_defining_message = 0;
1450 game_flush_inputs();
1455 if (multi_message_index > 0)
1456 multi_message_index--;
1457 Network_message[multi_message_index] = 0;
1460 if ( multi_sending_message )
1461 multi_send_message_end();
1462 else if ( multi_defining_message )
1463 multi_define_macro_end();
1464 game_flush_inputs();
1468 int ascii = key_to_ascii(key);
1469 if ((ascii < 255 )) {
1470 if (multi_message_index < MAX_MESSAGE_LEN-2 ) {
1471 Network_message[multi_message_index++] = ascii;
1472 Network_message[multi_message_index] = 0;
1473 } else if ( multi_sending_message ) {
1475 char * ptext, * pcolon;
1477 Network_message[multi_message_index++] = ascii;
1478 Network_message[multi_message_index] = 0;
1479 for (i=multi_message_index-1; i>=0; i-- ) {
1480 if ( Network_message[i]==32 ) {
1481 ptext = &Network_message[i+1];
1482 Network_message[i] = 0;
1486 multi_send_message_end();
1488 multi_sending_message = 1;
1489 pcolon = strchr( Network_message, ':' );
1491 strcpy( pcolon+1, ptext );
1493 strcpy( Network_message, ptext );
1494 multi_message_index = strlen( Network_message );
1503 multi_send_message_dialog(void)
1508 if (!(Game_mode&GM_MULTI))
1511 Network_message[0] = 0; // Get rid of old contents
1513 m[0].type=NM_TYPE_INPUT; m[0].text = Network_message; m[0].text_len = MAX_MESSAGE_LEN-1;
1514 choice = newmenu_do( NULL, TXT_SEND_MESSAGE, 1, m, NULL );
1516 if ((choice > -1) && (strlen(Network_message) > 0)) {
1517 Network_message_reciever = 100;
1518 HUD_init_message("%s '%s'", TXT_SENDING, Network_message);
1519 multi_message_feedback();
1526 multi_do_death(int objnum)
1528 // Do any miscellaneous stuff for a new network player after death
1532 if (!(Game_mode & GM_MULTI_COOP))
1534 mprintf((0, "Setting all keys for player %d.\n", Player_num));
1535 Players[Player_num].flags |= (PLAYER_FLAGS_RED_KEY | PLAYER_FLAGS_BLUE_KEY | PLAYER_FLAGS_GOLD_KEY);
1540 multi_do_fire(char *buf)
1547 // Act out the actual shooting
1551 weapon = (int)buf[2];
1556 Network_laser_track = INTEL_SHORT(*(short *)(buf+6));
1558 Assert (pnum < N_players);
1560 if (Objects[Players[(int)pnum].objnum].type == OBJ_GHOST)
1561 multi_make_ghost_player(pnum);
1563 // mprintf((0,"multi_do_fire, weapon = %d\n",weapon));
1565 if (weapon == FLARE_ADJUST)
1566 Laser_player_fire( Objects+Players[(int)pnum].objnum, FLARE_ID, 6, 1, 0);
1567 else if (weapon >= MISSILE_ADJUST) {
1568 int weapon_id,weapon_gun;
1570 weapon_id = Secondary_weapon_to_weapon_info[weapon-MISSILE_ADJUST];
1571 weapon_gun = Secondary_weapon_to_gun_num[weapon-MISSILE_ADJUST] + (flags & 1);
1572 mprintf((0,"missile id = %d, gun = %d\n",weapon_id,weapon_gun));
1574 if (weapon-MISSILE_ADJUST==GUIDED_INDEX)
1576 mprintf ((0,"Missile is guided!!!\n"));
1580 Laser_player_fire( Objects+Players[(int)pnum].objnum, weapon_id, weapon_gun, 1, 0 );
1583 fix save_charge = Fusion_charge;
1585 if (weapon == FUSION_INDEX) {
1586 Fusion_charge = flags << 12;
1587 mprintf((0, "Fusion charge X%f.\n", f2fl(Fusion_charge)));
1589 if (weapon == LASER_ID) {
1590 if (flags & LASER_QUAD)
1591 Players[(int)pnum].flags |= PLAYER_FLAGS_QUAD_LASERS;
1593 Players[(int)pnum].flags &= ~PLAYER_FLAGS_QUAD_LASERS;
1596 do_laser_firing(Players[(int)pnum].objnum, weapon, (int)buf[3], flags, (int)buf[5]);
1598 if (weapon == FUSION_INDEX)
1599 Fusion_charge = save_charge;
1604 multi_do_message(char *buf)
1607 char *tilde,mesbuf[100];
1612 if ((tilde=strchr (buf+loc,'$'))) // do that stupid name stuff
1613 { // why'd I put this in? Probably for the
1614 tloc=tilde-(buf+loc); // same reason you can name your guidebot
1615 mprintf ((0,"Tloc=%d\n",tloc));
1618 strncpy (mesbuf,buf+loc,tloc);
1619 strcpy (mesbuf+tloc,Players[Player_num].callsign);
1620 strcpy (mesbuf+strlen(Players[Player_num].callsign)+tloc,buf+loc+tloc+1);
1621 strcpy (buf+loc,mesbuf);
1624 if (((colon = strrchr(buf+loc, ':')) == NULL) || (colon-(buf+loc) < 1) || (colon-(buf+loc) > CALLSIGN_LEN))
1627 mesbuf[1] = BM_XRGB(28, 0, 0);
1628 strcpy(&mesbuf[2], Players[(int)buf[1]].callsign);
1632 mesbuf[t+2] = BM_XRGB(0, 31, 0);
1635 digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
1636 HUD_init_message("%s %s", mesbuf, buf+2);
1640 if ( (!strnicmp(Players[Player_num].callsign, buf+loc, colon-(buf+loc))) ||
1641 ((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)))) )
1644 mesbuf[1] = BM_XRGB(0, 32, 32);
1645 strcpy(&mesbuf[2], Players[(int)buf[1]].callsign);
1649 mesbuf[t+2] = BM_XRGB(0, 31, 0);
1652 digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
1653 HUD_init_message("%s %s", mesbuf, colon+1);
1659 multi_do_position(char *buf)
1665 // This routine does only player positions, mode game only
1666 // mprintf((0, "Got position packet.\n"));
1668 int pnum = (Player_num+1)%2;
1670 Assert(&Objects[Players[pnum].objnum] != ConsoleObject);
1672 if (Game_mode & GM_NETWORK)
1674 Int3(); // Get Jason, what the hell are we doing here?
1680 extract_shortpos(&Objects[Players[pnum].objnum], (shortpos *)(buf+1),0);
1682 memcpy((ubyte *)(sp.bytemat), (ubyte *)(buf + 1), 9);
1683 memcpy((ubyte *)&(sp.xo), (ubyte *)(buf + 10), 14);
1684 extract_shortpos(&Objects[Players[pnum].objnum], &sp, 1);
1687 if (Objects[Players[pnum].objnum].movement_type == MT_PHYSICS)
1688 set_thrust_from_velocity(&Objects[Players[pnum].objnum]);
1692 multi_do_reappear(char *buf)
1696 objnum = INTEL_SHORT(*(short *)(buf+1));
1698 Assert(objnum >= 0);
1699 // Assert(Players[Objects[objnum].id]].objnum == objnum);
1701 // mprintf((0, "Switching rendering back on for object %d.\n", objnum));
1703 multi_make_ghost_player(Objects[objnum].id);
1704 create_player_appearance_effect(&Objects[objnum]);
1705 PKilledFlags[Objects[objnum].id]=0;
1709 multi_do_player_explode(char *buf)
1711 // Only call this for players, not robots. pnum is player number, not
1718 char remote_created;
1723 if ((pnum < 0) || (pnum >= N_players))
1727 Assert(pnum < N_players);
1731 // If we are in the process of sending objects to a new player, reset that process
1732 if (Network_send_objects)
1734 mprintf((0, "Resetting object sync due to player explosion.\n"));
1735 Network_send_objnum = -1;
1739 // Stuff the Players structure to prepare for the explosion
1742 Players[pnum].primary_weapon_flags = INTEL_SHORT(*(ushort *)(buf+count)); count += 2;
1743 Players[pnum].secondary_weapon_flags = INTEL_SHORT(*(ushort *)(buf+count)); count += 2;
1744 Players[pnum].laser_level = buf[count]; count++;
1745 Players[pnum].secondary_ammo[HOMING_INDEX] = buf[count]; count++;
1746 Players[pnum].secondary_ammo[CONCUSSION_INDEX] = buf[count];count++;
1747 Players[pnum].secondary_ammo[SMART_INDEX] = buf[count]; count++;
1748 Players[pnum].secondary_ammo[MEGA_INDEX] = buf[count]; count++;
1749 Players[pnum].secondary_ammo[PROXIMITY_INDEX] = buf[count]; count++;
1751 Players[pnum].secondary_ammo[SMISSILE1_INDEX] = buf[count]; count++;
1752 Players[pnum].secondary_ammo[GUIDED_INDEX] = buf[count]; count++;
1753 Players[pnum].secondary_ammo[SMART_MINE_INDEX]= buf[count]; count++;
1754 Players[pnum].secondary_ammo[SMISSILE4_INDEX] = buf[count]; count++;
1755 Players[pnum].secondary_ammo[SMISSILE5_INDEX] = buf[count]; count++;
1757 Players[pnum].primary_ammo[VULCAN_INDEX] = INTEL_SHORT(*(ushort *)(buf+count)); count += 2;
1758 Players[pnum].primary_ammo[GAUSS_INDEX] = INTEL_SHORT(*(ushort *)(buf+count)); count += 2;
1759 Players[pnum].flags = INTEL_INT(*(uint *)(buf+count)); count += 4;
1761 multi_adjust_remote_cap (pnum);
1763 objp = Objects+Players[pnum].objnum;
1765 // objp->phys_info.velocity = *(vms_vector *)(buf+16); // 12 bytes
1766 // objp->pos = *(vms_vector *)(buf+28); // 12 bytes
1768 remote_created = buf[count++]; // How many did the other guy create?
1772 drop_player_eggs(objp);
1774 // Create mapping from remote to local numbering system
1776 mprintf((0, "I Created %d powerups, remote created %d.\n", Net_create_loc, remote_created));
1778 // We now handle this situation gracefully, Int3 not required
1779 // if (Net_create_loc != remote_created)
1780 // Int3(); // Probably out of object array space, see Rob
1782 for (i = 0; i < remote_created; i++)
1786 s = INTEL_SHORT(*(short *)(buf+count));
1788 if ((i < Net_create_loc) && (s > 0))
1789 map_objnum_local_to_remote((short)Net_create_objnums[i], s, pnum);
1790 else if (*(short *)(buf+count) <= 0)
1792 mprintf((0, "WARNING: Remote created object has non-valid number %d (player %d)", s, pnum));
1796 mprintf((0, "WARNING: Could not create all powerups created by player %d.\n", pnum));
1801 for (i = remote_created; i < Net_create_loc; i++) {
1802 mprintf((0, "WARNING: I Created more powerups than player %d, deleting.\n", pnum));
1803 Objects[Net_create_objnums[i]].flags |= OF_SHOULD_BE_DEAD;
1806 if (buf[0] == MULTI_PLAYER_EXPLODE)
1808 explode_badass_player(objp);
1810 objp->flags &= ~OF_SHOULD_BE_DEAD; //don't really kill player
1811 multi_make_player_ghost(pnum);
1815 create_player_appearance_effect(objp);
1818 Players[pnum].flags &= ~(PLAYER_FLAGS_CLOAKED | PLAYER_FLAGS_INVULNERABLE | PLAYER_FLAGS_FLAG);
1819 Players[pnum].cloak_time = 0;
1823 multi_do_kill(char *buf)
1829 pnum = (int)(buf[count]);
1830 if ((pnum < 0) || (pnum >= N_players))
1832 Int3(); // Invalid player number killed
1835 killed = Players[pnum].objnum;
1838 killer = INTEL_SHORT(*(short *)(buf+count));
1840 killer = objnum_remote_to_local(killer, (byte)buf[count+2]);
1843 if ((Objects[killed].type != OBJ_PLAYER) && (Objects[killed].type != OBJ_GHOST))
1846 mprintf( (1, "SOFT INT3: MULTI.C Non-player object %d of type %d killed! (JOHN)\n", killed, Objects[killed].type ));
1851 multi_compute_kill(killer, killed);
1856 // Changed by MK on 10/20/94 to send NULL as object to net_destroy_controlcen if it got -1
1857 // which means not a controlcen object, but contained in another object
1858 void multi_do_controlcen_destroy(char *buf)
1863 objnum = INTEL_SHORT(*(short *)(buf+1));
1866 if (Control_center_destroyed != 1)
1868 if ((who < N_players) && (who != Player_num)) {
1869 HUD_init_message("%s %s", Players[who].callsign, TXT_HAS_DEST_CONTROL);
1871 else if (who == Player_num)
1872 HUD_init_message(TXT_YOU_DEST_CONTROL);
1874 HUD_init_message(TXT_CONTROL_DESTROYED);
1877 net_destroy_controlcen(Objects+objnum);
1879 net_destroy_controlcen(NULL);
1884 multi_do_escape(char *buf)
1888 objnum = Players[(int)buf[1]].objnum;
1890 digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
1891 digi_kill_sound_linked_to_object (objnum);
1895 HUD_init_message("%s %s", Players[(int)buf[1]].callsign, TXT_HAS_ESCAPED);
1896 if (Game_mode & GM_NETWORK)
1897 Players[(int)buf[1]].connected = CONNECT_ESCAPE_TUNNEL;
1898 if (!multi_goto_secret)
1899 multi_goto_secret = 2;
1901 else if (buf[2] == 1)
1903 HUD_init_message("%s %s", Players[(int)buf[1]].callsign, TXT_HAS_FOUND_SECRET);
1904 if (Game_mode & GM_NETWORK)
1905 Players[(int)buf[1]].connected = CONNECT_FOUND_SECRET;
1906 if (!multi_goto_secret)
1907 multi_goto_secret = 1;
1909 create_player_appearance_effect(&Objects[objnum]);
1910 multi_make_player_ghost(buf[1]);
1914 multi_do_remobj(char *buf)
1916 short objnum; // which object to remove
1918 byte obj_owner; // which remote list is it entered in
1920 objnum = INTEL_SHORT(*(short *)(buf+1));
1923 Assert(objnum >= 0);
1928 local_objnum = objnum_remote_to_local(objnum, obj_owner); // translate to local objnum
1930 // mprintf((0, "multi_do_remobj: %d owner %d = %d.\n", objnum, obj_owner, local_objnum));
1932 if (local_objnum < 0)
1934 mprintf((1, "multi_do_remobj: Could not remove referenced object.\n"));
1938 if ((Objects[local_objnum].type != OBJ_POWERUP) && (Objects[local_objnum].type != OBJ_HOSTAGE))
1940 mprintf((1, "multi_get_remobj: tried to remove invalid type %d.\n", Objects[local_objnum].type));
1944 if (Network_send_objects && network_objnum_is_past(local_objnum))
1946 mprintf((0, "Resetting object sync due to object removal.\n"));
1947 Network_send_objnum = -1;
1949 if (Objects[local_objnum].type==OBJ_POWERUP)
1950 if (Game_mode & GM_NETWORK)
1952 if (PowerupsInMine[Objects[local_objnum].id]>0)
1953 PowerupsInMine[Objects[local_objnum].id]--;
1955 if (multi_powerup_is_4pack (Objects[local_objnum].id))
1957 mprintf ((0,"Hey babe! Doing that wacky 4 pack stuff."));
1959 if (PowerupsInMine[Objects[local_objnum].id-1]-4<0)
1960 PowerupsInMine[Objects[local_objnum].id-1]=0;
1962 PowerupsInMine[Objects[local_objnum].id-1]-=4;
1965 mprintf ((0,"Decrementing powerups! %d\n",PowerupsInMine[Objects[local_objnum].id]));
1968 Objects[local_objnum].flags |= OF_SHOULD_BE_DEAD; // quick and painless
1973 multi_do_quit(char *buf)
1976 if (Game_mode & GM_NETWORK)
1980 digi_play_sample( SOUND_HUD_MESSAGE, F1_0 );
1982 HUD_init_message( "%s %s", Players[(int)buf[1]].callsign, TXT_HAS_LEFT_THE_GAME);
1984 network_disconnect_player(buf[1]);
1989 for (i = 0; i < N_players; i++)
1990 if (Players[i].connected) n++;
1993 nm_messagebox(NULL, 1, TXT_OK, TXT_YOU_ARE_ONLY);
1997 if ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM))
1999 Function_mode = FMODE_MENU;
2000 multi_quit_game = 1;
2001 multi_leave_menu = 1;
2002 nm_messagebox(NULL, 1, TXT_OK, TXT_OPPONENT_LEFT);
2003 Function_mode = FMODE_GAME;
2004 multi_reset_stuff();
2010 multi_do_cloak(char *buf)
2014 pnum = (int)(buf[1]);
2016 Assert(pnum < N_players);
2018 mprintf((0, "Cloaking player %d\n", pnum));
2020 Players[pnum].flags |= PLAYER_FLAGS_CLOAKED;
2021 Players[pnum].cloak_time = GameTime;
2022 ai_do_cloak_stuff();
2025 if (Game_mode & GM_MULTI_ROBOTS)
2026 multi_strip_robots(pnum);
2029 if (Newdemo_state == ND_STATE_RECORDING)
2030 newdemo_record_multi_cloak(pnum);
2034 multi_do_decloak(char *buf)
2038 pnum = (int)(buf[1]);
2040 if (Newdemo_state == ND_STATE_RECORDING)
2041 newdemo_record_multi_decloak(pnum);
2046 multi_do_door_open(char *buf)
2054 segnum = INTEL_SHORT(*(short *)(buf+1));
2058 // mprintf((0, "Opening door on side %d of segment # %d.\n", side, segnum));
2060 if ((segnum < 0) || (segnum > Highest_segment_index) || (side < 0) || (side > 5))
2066 seg = &Segments[segnum];
2068 if (seg->sides[side].wall_num == -1) { //Opening door on illegal wall
2073 w = &Walls[seg->sides[side].wall_num];
2075 if (w->type == WALL_BLASTABLE)
2077 if (!(w->flags & WALL_BLASTED))
2079 mprintf((0, "Blasting wall by remote command.\n"));
2080 wall_destroy(seg, side);
2084 else if (w->state != WALL_DOOR_OPENING)
2086 wall_open_door(seg, side);
2093 // mprintf((0, "Door already opening!\n"));
2097 multi_do_create_explosion(char *buf)
2102 pnum = buf[count++];
2104 // mprintf((0, "Creating small fireball.\n"));
2105 create_small_fireball_on_object(&Objects[Players[pnum].objnum], F1_0, 1);
2109 multi_do_controlcen_fire(char *buf)
2111 vms_vector to_target;
2116 memcpy(&to_target, buf+count, 12); count += 12;
2117 #ifdef MACINTOSH // swap the vector to_target
2118 to_target.x = (fix)INTEL_INT((int)to_target.x);
2119 to_target.y = (fix)INTEL_INT((int)to_target.y);
2120 to_target.z = (fix)INTEL_INT((int)to_target.z);
2122 gun_num = buf[count]; count += 1;
2123 objnum = INTEL_SHORT(*(short *)(buf+count)); count += 2;
2125 Laser_create_new_easy(&to_target, &Gun_pos[(int)gun_num], objnum, CONTROLCEN_WEAPON_NUM, 1);
2129 multi_do_create_powerup(char *buf)
2139 if (Endlevel_sequence || Control_center_destroyed)
2142 pnum = buf[count++];
2143 powerup_type = buf[count++];
2144 segnum = INTEL_SHORT(*(short *)(buf+count)); count+=2;
2145 objnum = INTEL_SHORT(*(short *)(buf+count)); count+=2;
2147 if ((segnum < 0) || (segnum > Highest_segment_index)) {
2152 new_pos = *(vms_vector *)(buf+count); count+=sizeof(vms_vector);
2154 new_pos.x = (fix)SWAPINT((int)new_pos.x);
2155 new_pos.y = (fix)SWAPINT((int)new_pos.y);
2156 new_pos.z = (fix)SWAPINT((int)new_pos.z);
2160 my_objnum = call_object_create_egg(&Objects[Players[(int)pnum].objnum], 1, OBJ_POWERUP, powerup_type);
2162 if (my_objnum < 0) {
2163 mprintf((0, "Could not create new powerup!\n"));
2167 if (Network_send_objects && network_objnum_is_past(my_objnum))
2169 mprintf((0, "Resetting object sync due to powerup creation.\n"));
2170 Network_send_objnum = -1;
2173 Objects[my_objnum].pos = new_pos;
2175 vm_vec_zero(&Objects[my_objnum].mtype.phys_info.velocity);
2177 obj_relink(my_objnum, segnum);
2179 map_objnum_local_to_remote(my_objnum, objnum, pnum);
2181 object_create_explosion(segnum, &new_pos, i2f(5), VCLIP_POWERUP_DISAPPEARANCE);
2182 mprintf((0, "Creating powerup type %d in segment %i.\n", powerup_type, segnum));
2184 if (Game_mode & GM_NETWORK)
2185 PowerupsInMine[(int)powerup_type]++;
2189 multi_do_play_sound(char *buf)
2191 int pnum = (int)(buf[1]);
2192 int sound_num = (int)(buf[2]);
2193 fix volume = (int)(buf[3]) << 12;
2195 if (!Players[pnum].connected)
2198 Assert(Players[pnum].objnum >= 0);
2199 Assert(Players[pnum].objnum <= Highest_object_index);
2201 digi_link_sound_to_object( sound_num, Players[pnum].objnum, 0, volume);
2205 multi_do_score(char *buf)
2207 int pnum = (int)(buf[1]);
2209 if ((pnum < 0) || (pnum >= N_players))
2211 Int3(); // Non-terminal, see rob
2215 if (Newdemo_state == ND_STATE_RECORDING)
2216 newdemo_record_multi_score(pnum, INTEL_INT(*(int *)(buf+2)) );
2218 Players[pnum].score = INTEL_INT(*(int *)(buf+2));
2220 multi_sort_kill_list();
2224 multi_do_trigger(char *buf)
2226 int pnum = (int)(buf[1]);
2227 int trigger = (int)(buf[2]);
2229 mprintf ((0,"MULTI doing trigger!\n"));
2231 if ((pnum < 0) || (pnum >= N_players) || (pnum == Player_num))
2233 Int3(); // Got trigger from illegal playernum
2236 if ((trigger < 0) || (trigger >= Num_triggers))
2238 Int3(); // Illegal trigger number in multiplayer
2241 check_trigger_sub(trigger, pnum,0);
2244 void multi_do_drop_marker (char *buf)
2247 int pnum=(int)(buf[1]);
2248 int mesnum=(int)(buf[2]);
2249 vms_vector position;
2251 if (pnum==Player_num) // my marker? don't set it down cuz it might screw up the orientation
2254 position.x=(fix)INTEL_INT(*(int *)(buf+3));
2255 position.y=(fix)INTEL_INT(*(int *)(buf+7));
2256 position.z=(fix)INTEL_INT(*(int *)(buf+11));
2259 MarkerMessage[(pnum*2)+mesnum][i]=buf[15+i];
2261 MarkerPoint[(pnum*2)+mesnum]=position;
2263 if (MarkerObject[(pnum*2)+mesnum] !=-1 && Objects[MarkerObject[(pnum*2)+mesnum]].type!=OBJ_NONE && MarkerObject[(pnum*2)+mesnum] !=0)
2264 obj_delete(MarkerObject[(pnum*2)+mesnum]);
2266 MarkerObject[(pnum*2)+mesnum] = drop_marker_object(&position,Objects[Players[Player_num].objnum].segnum,&Objects[Players[Player_num].objnum].orient,(pnum*2)+mesnum);
2267 strcpy (MarkerOwner[(pnum*2)+mesnum],Players[pnum].callsign);
2268 mprintf ((0,"Dropped player %d message: %s\n",pnum,MarkerMessage[(pnum*2)+mesnum]));
2272 void multi_do_hostage_door_status(char *buf)
2274 // Update hit point status of a door
2280 wallnum = INTEL_SHORT(*(short *)(buf+count)); count += 2;
2281 hps = (fix)INTEL_INT(*(int *)(buf+count)); count += 4;
2283 if ((wallnum < 0) || (wallnum > Num_walls) || (hps < 0) || (Walls[wallnum].type != WALL_BLASTABLE))
2285 Int3(); // Non-terminal, see Rob
2289 // mprintf((0, "Damaging wall number %d to %f points.\n", wallnum, f2fl(hps)));
2291 if (hps < Walls[wallnum].hps)
2292 wall_damage(&Segments[Walls[wallnum].segnum], Walls[wallnum].sidenum, Walls[wallnum].hps - hps);
2295 void multi_do_save_game(char *buf)
2302 slot = *(ubyte *)(buf+count); count += 1;
2303 id = INTEL_INT(*(uint *)(buf+count)); count += 4;
2304 memcpy( desc, &buf[count], 20 ); count += 20;
2306 multi_save_game( slot, id, desc );
2309 void multi_do_restore_game(char *buf)
2315 slot = *(ubyte *)(buf+count); count += 1;
2316 id = INTEL_INT(*(uint *)(buf+count)); count += 4;
2318 multi_restore_game( slot, id );
2322 void multi_do_req_player(char *buf)
2326 // Send my netplayer_stats to everyone!
2327 player_n = *(ubyte *)(buf+1);
2328 if ( (player_n == Player_num) || (player_n == 255) ) {
2329 extract_netplayer_stats( &ps, &Players[Player_num] );
2330 ps.Player_num = Player_num;
2331 ps.message_type = MULTI_SEND_PLAYER; // SET
2332 multi_send_data((ubyte*)&ps, sizeof(netplayer_stats), 0);
2336 void multi_do_send_player(char *buf)
2338 // Got a player packet from someone!!!
2339 netplayer_stats * p;
2340 p = (netplayer_stats *)buf;
2342 Assert( p->Player_num <= N_players );
2344 mprintf(( 0, "Got netplayer_stats for player %d (I'm %d)\n", p->Player_num, Player_num ));
2345 mprintf(( 0, "Their shields are: %d\n", f2i(p->shields) ));
2347 use_netplayer_stats( &Players[p->Player_num], p );
2351 multi_reset_stuff(void)
2353 // A generic, emergency function to solve problems that crop up
2354 // when a player exits quick-out from the game because of a
2355 // serial connection loss. Fixes several weird bugs!
2359 Players[Player_num].homing_object_dist = -F1_0; // Turn off homing sound.
2361 Dead_player_camera = 0;
2362 Endlevel_sequence = 0;
2367 multi_reset_player_object(object *objp)
2371 //Init physics for a non-console player
2373 Assert(objp >= Objects);
2374 Assert(objp <= Objects+Highest_object_index);
2375 Assert((objp->type == OBJ_PLAYER) || (objp->type == OBJ_GHOST));
2377 vm_vec_zero(&objp->mtype.phys_info.velocity);
2378 vm_vec_zero(&objp->mtype.phys_info.thrust);
2379 vm_vec_zero(&objp->mtype.phys_info.rotvel);
2380 vm_vec_zero(&objp->mtype.phys_info.rotthrust);
2381 objp->mtype.phys_info.brakes = objp->mtype.phys_info.turnroll = 0;
2382 objp->mtype.phys_info.mass = Player_ship->mass;
2383 objp->mtype.phys_info.drag = Player_ship->drag;
2384 // objp->mtype.phys_info.flags &= ~(PF_TURNROLL | PF_LEVELLING | PF_WIGGLE | PF_USES_THRUST);
2385 objp->mtype.phys_info.flags &= ~(PF_TURNROLL | PF_LEVELLING | PF_WIGGLE);
2389 objp->render_type = RT_POLYOBJ;
2390 objp->rtype.pobj_info.model_num = Player_ship->model_num; //what model is this?
2391 objp->rtype.pobj_info.subobj_flags = 0; //zero the flags
2392 for (i=0;i<MAX_SUBMODELS;i++)
2393 vm_angvec_zero(&objp->rtype.pobj_info.anim_angles[i]);
2395 //reset textures for this, if not player 0
2397 multi_reset_object_texture (objp);
2403 if (objp->type == OBJ_GHOST)
2404 objp->render_type = RT_NONE;
2408 void multi_reset_object_texture (object *objp)
2412 if (Game_mode & GM_TEAM)
2413 id = get_team(objp->id);
2418 objp->rtype.pobj_info.alt_textures=0;
2420 Assert(N_PLAYER_SHIP_TEXTURES == Polygon_models[objp->rtype.pobj_info.model_num].n_textures);
2422 for (i=0;i<N_PLAYER_SHIP_TEXTURES;i++)
2423 multi_player_textures[id-1][i] = ObjBitmaps[ObjBitmapPtrs[Polygon_models[objp->rtype.pobj_info.model_num].first_texture+i]];
2425 multi_player_textures[id-1][4] = ObjBitmaps[ObjBitmapPtrs[First_multi_bitmap_num+(id-1)*2]];
2426 multi_player_textures[id-1][5] = ObjBitmaps[ObjBitmapPtrs[First_multi_bitmap_num+(id-1)*2+1]];
2428 objp->rtype.pobj_info.alt_textures = id;
2435 extern int TTRecv[];
2436 extern FILE *RecieveLogFile;
2439 multi_process_bigdata(char *buf, int len)
2441 // Takes a bunch of messages, check them for validity,
2442 // and pass them to multi_process_data.
2444 int type, sub_len, bytes_processed = 0;
2446 while( bytes_processed < len ) {
2447 type = buf[bytes_processed];
2449 if ( (type<0) || (type>MULTI_MAX_TYPE)) {
2450 mprintf( (1, "multi_process_bigdata: Invalid packet type %d!\n", type ));
2453 sub_len = message_length[type];
2455 Assert(sub_len > 0);
2457 if ( (bytes_processed+sub_len) > len ) {
2458 mprintf( (1, "multi_process_bigdata: packet type %d too short (%d>%d)!\n", type, (bytes_processed+sub_len), len ));
2463 multi_process_data(&buf[bytes_processed], sub_len);
2464 bytes_processed += sub_len;
2469 // Part 2 : Functions that send communication messages to inform the other
2470 // players of something we did.
2474 multi_send_fire(void)
2476 if (!Network_laser_fired)
2479 multibuf[0] = (char)MULTI_FIRE;
2480 multibuf[1] = (char)Player_num;
2481 multibuf[2] = (char)Network_laser_gun;
2482 multibuf[3] = (char)Network_laser_level;
2483 multibuf[4] = (char)Network_laser_flags;
2484 multibuf[5] = (char)Network_laser_fired;
2486 *(short *)(multibuf+6) = INTEL_SHORT(Network_laser_track);
2488 multi_send_data(multibuf, 8, 0);
2490 Network_laser_fired = 0;
2494 multi_send_destroy_controlcen(int objnum, int player)
2496 if (player == Player_num)
2497 HUD_init_message(TXT_YOU_DEST_CONTROL);
2498 else if ((player > 0) && (player < N_players))
2499 HUD_init_message("%s %s", Players[player].callsign, TXT_HAS_DEST_CONTROL);
2501 HUD_init_message(TXT_CONTROL_DESTROYED);
2503 multibuf[0] = (char)MULTI_CONTROLCEN;
2504 *(ushort *)(multibuf+1) = INTEL_SHORT(objnum);
2505 multibuf[3] = player;
2506 multi_send_data(multibuf, 4, 2);
2509 void multi_send_drop_marker (int player,vms_vector position,char messagenum,char text[])
2513 if (player<N_players)
2515 mprintf ((0,"Sending MARKER drop!\n"));
2516 multibuf[0]=(char)MULTI_MARKER;
2517 multibuf[1]=(char)player;
2518 multibuf[2]=messagenum;
2519 *(fix *)(multibuf+3)=INTEL_INT(position.x);
2520 *(fix *)(multibuf+7)=INTEL_INT(position.y);
2521 *(fix *)(multibuf+11)=INTEL_INT(position.z);
2523 multibuf[15+i]=text[i];
2525 multi_send_data(multibuf, 55, 1);
2529 multi_send_endlevel_start(int secret)
2531 multibuf[0] = (char)MULTI_ENDLEVEL_START;
2532 multibuf[1] = Player_num;
2533 multibuf[2] = (char)secret;
2535 if ((secret) && !multi_goto_secret)
2536 multi_goto_secret = 1;
2537 else if (!multi_goto_secret)
2538 multi_goto_secret = 2;
2540 multi_send_data(multibuf, 3, 1);
2541 if (Game_mode & GM_NETWORK)
2543 Players[Player_num].connected = 5;
2544 network_send_endlevel_packet();
2549 multi_send_player_explode(char type)
2554 Assert( (type == MULTI_PLAYER_DROP) || (type == MULTI_PLAYER_EXPLODE) );
2556 multi_send_position(Players[Player_num].objnum);
2558 if (Network_send_objects)
2560 mprintf((0, "Resetting object sync due to player explosion.\n"));
2561 Network_send_objnum = -1;
2564 multibuf[count++] = type;
2565 multibuf[count++] = Player_num;
2567 *(ushort *)(multibuf+count) = INTEL_SHORT((ushort)Players[Player_num].primary_weapon_flags);
2569 *(ushort *)(multibuf+count) = INTEL_SHORT((ushort)Players[Player_num].secondary_weapon_flags);
2571 multibuf[count++] = (char)Players[Player_num].laser_level;
2573 multibuf[count++] = (char)Players[Player_num].secondary_ammo[HOMING_INDEX];
2574 multibuf[count++] = (char)Players[Player_num].secondary_ammo[CONCUSSION_INDEX];
2575 multibuf[count++] = (char)Players[Player_num].secondary_ammo[SMART_INDEX];
2576 multibuf[count++] = (char)Players[Player_num].secondary_ammo[MEGA_INDEX];
2577 multibuf[count++] = (char)Players[Player_num].secondary_ammo[PROXIMITY_INDEX];
2579 multibuf[count++] = (char)Players[Player_num].secondary_ammo[SMISSILE1_INDEX];
2580 multibuf[count++] = (char)Players[Player_num].secondary_ammo[GUIDED_INDEX];
2581 multibuf[count++] = (char)Players[Player_num].secondary_ammo[SMART_MINE_INDEX];
2582 multibuf[count++] = (char)Players[Player_num].secondary_ammo[SMISSILE4_INDEX];
2583 multibuf[count++] = (char)Players[Player_num].secondary_ammo[SMISSILE5_INDEX];
2585 *(ushort *)(multibuf+count) = INTEL_SHORT( (ushort)Players[Player_num].primary_ammo[VULCAN_INDEX] );
2587 *(ushort *)(multibuf+count) = INTEL_SHORT( (ushort)Players[Player_num].primary_ammo[GAUSS_INDEX] );
2589 *(uint *)(multibuf+count) = INTEL_INT( (uint)Players[Player_num].flags );
2592 multibuf[count++] = Net_create_loc;
2594 Assert(Net_create_loc <= MAX_NET_CREATE_OBJECTS);
2596 memset(multibuf+count, -1, MAX_NET_CREATE_OBJECTS*sizeof(short));
2598 mprintf((0, "Created %d explosion objects.\n", Net_create_loc));
2600 for (i = 0; i < Net_create_loc; i++)
2602 if (Net_create_objnums[i] <= 0) {
2603 Int3(); // Illegal value in created egg object numbers
2608 *(short *)(multibuf+count) = INTEL_SHORT( (short)Net_create_objnums[i] ); count += 2;
2610 // We created these objs so our local number = the network number
2611 map_objnum_local_to_local((short)Net_create_objnums[i]);
2616 // mprintf((1, "explode message size = %d, max = %d.\n", count, message_length[MULTI_PLAYER_EXPLODE]));
2618 if (count > message_length[MULTI_PLAYER_EXPLODE])
2623 multi_send_data(multibuf, message_length[MULTI_PLAYER_EXPLODE], 2);
2624 if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)
2625 multi_send_decloak();
2626 if (Game_mode & GM_MULTI_ROBOTS)
2627 multi_strip_robots(Player_num);
2630 extern ubyte Secondary_weapon_to_powerup[];
2631 extern ubyte Primary_weapon_to_powerup[];
2633 // put a lid on how many objects will be spewed by an exploding player
2634 // to prevent rampant powerups in netgames
2636 void multi_cap_objects ()
2641 if (!(Game_mode & GM_NETWORK))
2644 for (index=0;index<MAX_PRIMARY_WEAPONS;index++)
2646 type=Primary_weapon_to_powerup[index];
2647 if (PowerupsInMine[(int)type]>=MaxPowerupsAllowed[(int)type])
2648 if(Players[Player_num].primary_weapon_flags & (1 << index))
2650 mprintf ((0,"PIM=%d MPA=%d\n",PowerupsInMine[(int)type],MaxPowerupsAllowed[(int)type]));
2651 mprintf ((0,"Killing a primary cuz there's too many! (%d)\n",(int)type));
2652 Players[Player_num].primary_weapon_flags&=(~(1 << index));
2657 // Don't do the adjustment stuff for Hoard mode
2658 if (!(Game_mode & GM_HOARD))
2659 Players[Player_num].secondary_ammo[2]/=4;
2661 Players[Player_num].secondary_ammo[7]/=4;
2663 for (index=0;index<MAX_SECONDARY_WEAPONS;index++)
2665 if ((Game_mode & GM_HOARD) && index==PROXIMITY_INDEX)
2668 type=Secondary_weapon_to_powerup[index];
2670 if ((Players[Player_num].secondary_ammo[index]+PowerupsInMine[(int)type])>MaxPowerupsAllowed[(int)type])
2672 if (MaxPowerupsAllowed[(int)type]-PowerupsInMine[(int)type]<0)
2673 Players[Player_num].secondary_ammo[index]=0;
2675 Players[Player_num].secondary_ammo[index]=(MaxPowerupsAllowed[(int)type]-PowerupsInMine[(int)type]);
2677 mprintf ((0,"Hey! I killed secondary type %d because PIM=%d MPA=%d\n",(int)type,PowerupsInMine[(int)type],MaxPowerupsAllowed[(int)type]));
2681 if (!(Game_mode & GM_HOARD))
2682 Players[Player_num].secondary_ammo[2]*=4;
2683 Players[Player_num].secondary_ammo[7]*=4;
2685 if (Players[Player_num].laser_level > MAX_LASER_LEVEL)
2686 if (PowerupsInMine[POW_SUPER_LASER]+1 > MaxPowerupsAllowed[POW_SUPER_LASER])
2687 Players[Player_num].laser_level=0;
2689 if (Players[Player_num].flags & PLAYER_FLAGS_QUAD_LASERS)
2690 if (PowerupsInMine[POW_QUAD_FIRE]+1 > MaxPowerupsAllowed[POW_QUAD_FIRE])
2691 Players[Player_num].flags&=(~PLAYER_FLAGS_QUAD_LASERS);
2693 if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)
2694 if (PowerupsInMine[POW_CLOAK]+1 > MaxPowerupsAllowed[POW_CLOAK])
2695 Players[Player_num].flags&=(~PLAYER_FLAGS_CLOAKED);
2697 if (Players[Player_num].flags & PLAYER_FLAGS_MAP_ALL)
2698 if (PowerupsInMine[POW_FULL_MAP]+1 > MaxPowerupsAllowed[POW_FULL_MAP])
2699 Players[Player_num].flags&=(~PLAYER_FLAGS_MAP_ALL);
2701 if (Players[Player_num].flags & PLAYER_FLAGS_AFTERBURNER)
2702 if (PowerupsInMine[POW_AFTERBURNER]+1 > MaxPowerupsAllowed[POW_AFTERBURNER])
2703 Players[Player_num].flags&=(~PLAYER_FLAGS_AFTERBURNER);
2705 if (Players[Player_num].flags & PLAYER_FLAGS_AMMO_RACK)
2706 if (PowerupsInMine[POW_AMMO_RACK]+1 > MaxPowerupsAllowed[POW_AMMO_RACK])
2707 Players[Player_num].flags&=(~PLAYER_FLAGS_AMMO_RACK);
2709 if (Players[Player_num].flags & PLAYER_FLAGS_CONVERTER)
2710 if (PowerupsInMine[POW_CONVERTER]+1 > MaxPowerupsAllowed[POW_CONVERTER])
2711 Players[Player_num].flags&=(~PLAYER_FLAGS_CONVERTER);
2713 if (Players[Player_num].flags & PLAYER_FLAGS_HEADLIGHT)
2714 if (PowerupsInMine[POW_HEADLIGHT]+1 > MaxPowerupsAllowed[POW_HEADLIGHT])
2715 Players[Player_num].flags&=(~PLAYER_FLAGS_HEADLIGHT);
2717 if (Game_mode & GM_CAPTURE)
2719 if (Players[Player_num].flags & PLAYER_FLAGS_FLAG)
2721 if (get_team(Player_num)==TEAM_RED)
2722 flagtype=POW_FLAG_BLUE;
2724 flagtype=POW_FLAG_RED;
2726 if (PowerupsInMine[(int)flagtype]+1 > MaxPowerupsAllowed[(int)flagtype])
2727 Players[Player_num].flags&=(~PLAYER_FLAGS_FLAG);
2733 // adds players inventory to multi cap
2735 void multi_adjust_cap_for_player (int pnum)
2741 if (!(Game_mode & GM_NETWORK))
2744 for (index=0;index<MAX_PRIMARY_WEAPONS;index++)
2746 type=Primary_weapon_to_powerup[index];
2747 if (Players[pnum].primary_weapon_flags & (1 << index))
2748 MaxPowerupsAllowed[(int)type]++;
2751 for (index=0;index<MAX_SECONDARY_WEAPONS;index++)
2753 type=Secondary_weapon_to_powerup[index];
2754 MaxPowerupsAllowed[(int)type]+=Players[pnum].secondary_ammo[index];
2757 if (Players[pnum].laser_level > MAX_LASER_LEVEL)
2758 MaxPowerupsAllowed[POW_SUPER_LASER]++;
2760 if (Players[pnum].flags & PLAYER_FLAGS_QUAD_LASERS)
2761 MaxPowerupsAllowed[POW_QUAD_FIRE]++;
2763 if (Players[pnum].flags & PLAYER_FLAGS_CLOAKED)
2764 MaxPowerupsAllowed[POW_CLOAK]++;
2766 if (Players[pnum].flags & PLAYER_FLAGS_MAP_ALL)
2767 MaxPowerupsAllowed[POW_FULL_MAP]++;
2769 if (Players[pnum].flags & PLAYER_FLAGS_AFTERBURNER)
2770 MaxPowerupsAllowed[POW_AFTERBURNER]++;
2772 if (Players[pnum].flags & PLAYER_FLAGS_AMMO_RACK)
2773 MaxPowerupsAllowed[POW_AMMO_RACK]++;
2775 if (Players[pnum].flags & PLAYER_FLAGS_CONVERTER)
2776 MaxPowerupsAllowed[POW_CONVERTER]++;
2778 if (Players[pnum].flags & PLAYER_FLAGS_HEADLIGHT)
2779 MaxPowerupsAllowed[POW_HEADLIGHT]++;
2782 void multi_adjust_remote_cap (int pnum)
2788 if (!(Game_mode & GM_NETWORK))
2791 for (index=0;index<MAX_PRIMARY_WEAPONS;index++)
2793 type=Primary_weapon_to_powerup[index];
2794 if (Players[pnum].primary_weapon_flags & (1 << index))
2795 PowerupsInMine[(int)type]++;
2798 for (index=0;index<MAX_SECONDARY_WEAPONS;index++)
2800 type=Secondary_weapon_to_powerup[index];
2802 if ((Game_mode & GM_HOARD) && index==2)
2805 if (index==2 || index==7) // PROX or SMARTMINES? Those bastards...
2806 PowerupsInMine[(int)type]+=(Players[pnum].secondary_ammo[index]/4);
2808 PowerupsInMine[(int)type]+=Players[pnum].secondary_ammo[index];
2812 if (Players[pnum].laser_level > MAX_LASER_LEVEL)
2813 PowerupsInMine[POW_SUPER_LASER]++;
2815 if (Players[pnum].flags & PLAYER_FLAGS_QUAD_LASERS)
2816 PowerupsInMine[POW_QUAD_FIRE]++;
2818 if (Players[pnum].flags & PLAYER_FLAGS_CLOAKED)
2819 PowerupsInMine[POW_CLOAK]++;
2821 if (Players[pnum].flags & PLAYER_FLAGS_MAP_ALL)
2822 PowerupsInMine[POW_FULL_MAP]++;
2824 if (Players[pnum].flags & PLAYER_FLAGS_AFTERBURNER)
2825 PowerupsInMine[POW_AFTERBURNER]++;
2827 if (Players[pnum].flags & PLAYER_FLAGS_AMMO_RACK)
2828 PowerupsInMine[POW_AMMO_RACK]++;
2830 if (Players[pnum].flags & PLAYER_FLAGS_CONVERTER)
2831 PowerupsInMine[POW_CONVERTER]++;
2833 if (Players[pnum].flags & PLAYER_FLAGS_HEADLIGHT)
2834 PowerupsInMine[POW_HEADLIGHT]++;
2839 multi_send_message(void)
2842 if (Network_message_reciever != -1)
2844 multibuf[loc] = (char)MULTI_MESSAGE; loc += 1;
2845 multibuf[loc] = (char)Player_num; loc += 1;
2846 strncpy(multibuf+loc, Network_message, MAX_MESSAGE_LEN); loc += MAX_MESSAGE_LEN;
2847 multibuf[loc-1] = '\0';
2848 multi_send_data(multibuf, loc, 0);
2849 Network_message_reciever = -1;
2854 multi_send_reappear()
2856 multibuf[0] = (char)MULTI_REAPPEAR;
2857 *(short *)(multibuf+1) = INTEL_SHORT(Players[Player_num].objnum);
2859 multi_send_data(multibuf, 3, 2);
2860 PKilledFlags[Player_num]=0;
2864 multi_send_position(int objnum)
2871 if (Game_mode & GM_NETWORK) {
2875 multibuf[count++] = (char)MULTI_POSITION;
2877 create_shortpos((shortpos *)(multibuf+count), Objects+objnum,0);
2878 count += sizeof(shortpos);
2880 create_shortpos(&sp, Objects+objnum, 1);
2881 memcpy(&(multibuf[count]), (ubyte *)(sp.bytemat), 9);
2883 memcpy(&(multibuf[count]), (ubyte *)&(sp.xo), 14);
2887 multi_send_data(multibuf, count, 0);
2891 multi_send_kill(int objnum)
2893 // I died, tell the world.
2898 Assert(Objects[objnum].id == Player_num);
2899 killer_objnum = Players[Player_num].killer_objnum;
2901 multi_compute_kill(killer_objnum, objnum);
2903 multibuf[0] = (char)MULTI_KILL; count += 1;
2904 multibuf[1] = Player_num; count += 1;
2905 if (killer_objnum > -1) {
2906 short s; // do it with variable since INTEL_SHORT won't work on return val from function.
2908 s = (short)objnum_local_to_remote(killer_objnum, (byte *)&multibuf[count+2]);
2909 *(short *)(multibuf+count) = INTEL_SHORT(s);
2913 *(short *)(multibuf+count) = INTEL_SHORT((short)-1);
2914 multibuf[count+2] = (char)-1;
2917 multi_send_data(multibuf, count, 1);
2920 if (Game_mode & GM_MULTI_ROBOTS)
2921 multi_strip_robots(Player_num);
2926 multi_send_remobj(int objnum)
2928 // Tell the other guy to remove an object from his list
2931 short remote_objnum;
2933 if (Objects[objnum].type==OBJ_POWERUP && (Game_mode & GM_NETWORK))
2935 if (PowerupsInMine[Objects[objnum].id] > 0)
2937 PowerupsInMine[Objects[objnum].id]--;
2938 if (multi_powerup_is_4pack (Objects[objnum].id))
2940 mprintf ((0,"Hey babe! Doing that wacky 4 pack stuff."));
2942 if (PowerupsInMine[Objects[objnum].id-1]-4<0)
2943 PowerupsInMine[Objects[objnum].id-1]=0;
2945 PowerupsInMine[Objects[objnum].id-1]-=4;
2951 multibuf[0] = (char)MULTI_REMOVE_OBJECT;
2953 remote_objnum = objnum_local_to_remote((short)objnum, &obj_owner);
2955 *(short *)(multibuf+1) = INTEL_SHORT(remote_objnum); // Map to network objnums
2957 multibuf[3] = obj_owner;
2959 // mprintf((0, "multi_send_remobj: %d = %d owner %d.\n", objnum, remote_objnum, obj_owner));
2961 multi_send_data(multibuf, 4, 0);
2963 if (Network_send_objects && network_objnum_is_past(objnum))
2965 mprintf((0, "Resetting object sync due to object removal.\n"));
2966 Network_send_objnum = -1;
2971 multi_send_quit(int why)
2973 // I am quitting the game, tell the other guy the bad news.
2975 Assert (why == MULTI_QUIT);
2977 multibuf[0] = (char)why;
2978 multibuf[1] = Player_num;
2979 multi_send_data(multibuf, 2, 1);
2984 multi_send_cloak(void)
2986 // Broadcast a change in our pflags (made to support cloaking)
2988 multibuf[0] = MULTI_CLOAK;
2989 multibuf[1] = (char)Player_num;
2991 multi_send_data(multibuf, 2, 1);
2994 if (Game_mode & GM_MULTI_ROBOTS)
2995 multi_strip_robots(Player_num);
3000 multi_send_decloak(void)
3002 // Broadcast a change in our pflags (made to support cloaking)
3004 multibuf[0] = MULTI_DECLOAK;
3005 multibuf[1] = (char)Player_num;
3007 multi_send_data(multibuf, 2, 1);
3011 multi_send_door_open(int segnum, int side,ubyte flag)
3013 // When we open a door make sure everyone else opens that door
3015 multibuf[0] = MULTI_DOOR_OPEN;
3016 *(short *)(multibuf+1) = INTEL_SHORT( (short)segnum );
3017 multibuf[3] = (byte)side;
3020 multi_send_data(multibuf, 5, 2);
3023 extern void network_send_naked_packet (char *,short,int);
3026 multi_send_door_open_specific(int pnum,int segnum, int side,ubyte flag)
3028 // For sending doors only to a specific person (usually when they're joining)
3030 Assert (Game_mode & GM_NETWORK);
3031 // Assert (pnum>-1 && pnum<N_players);
3033 multibuf[0] = MULTI_DOOR_OPEN;
3034 *(short *)(multibuf+1) = INTEL_SHORT( (short)segnum );
3035 multibuf[3] = (byte)side;
3038 network_send_naked_packet(multibuf, 5, pnum);
3042 // Part 3 : Functions that change or prepare the game for multiplayer use.
3043 // Not including functions needed to syncronize or start the
3044 // particular type of multiplayer game. Includes preparing the
3045 // mines, player structures, etc.
3048 multi_send_create_explosion(int pnum)
3050 // Send all data needed to create a remote explosion
3054 multibuf[count] = MULTI_CREATE_EXPLOSION; count += 1;
3055 multibuf[count] = (byte)pnum; count += 1;
3059 multi_send_data(multibuf, count, 0);
3063 multi_send_controlcen_fire(vms_vector *to_goal, int best_gun_num, int objnum)
3066 vms_vector swapped_vec;
3070 multibuf[count] = MULTI_CONTROLCEN_FIRE; count += 1;
3072 memcpy(multibuf+count, to_goal, 12); count += 12;
3074 swapped_vec.x = (fix)INTEL_INT( (int)to_goal->x );
3075 swapped_vec.y = (fix)INTEL_INT( (int)to_goal->y );
3076 swapped_vec.z = (fix)INTEL_INT( (int)to_goal->z );
3077 memcpy(multibuf+count, &swapped_vec, 12); count += 12;
3079 multibuf[count] = (char)best_gun_num; count += 1;
3080 *(short *)(multibuf+count) = INTEL_SHORT( (short)objnum ); count += 2;
3083 multi_send_data(multibuf, count, 0);
3087 multi_send_create_powerup(int powerup_type, int segnum, int objnum, vms_vector *pos)
3089 // Create a powerup on a remote machine, used for remote
3090 // placement of used powerups like missiles and cloaking
3094 vms_vector swapped_vec;
3098 if (Game_mode & GM_NETWORK)
3099 PowerupsInMine[powerup_type]++;
3101 multibuf[count] = MULTI_CREATE_POWERUP; count += 1;
3102 multibuf[count] = Player_num; count += 1;
3103 multibuf[count] = powerup_type; count += 1;
3104 *(short *)(multibuf+count) = INTEL_SHORT( (short)segnum ); count += 2;
3105 *(short *)(multibuf+count) = INTEL_SHORT( (short)objnum ); count += 2;
3107 *(vms_vector *)(multibuf+count) = *pos; count += sizeof(vms_vector);
3109 swapped_vec.x = (fix)INTEL_INT( (int)pos->x );
3110 swapped_vec.y = (fix)INTEL_INT( (int)pos->y );
3111 swapped_vec.z = (fix)INTEL_INT( (int)pos->z );
3112 memcpy(multibuf+count, &swapped_vec, 12); count += 12;
3116 multi_send_data(multibuf, count, 2);
3118 if (Network_send_objects && network_objnum_is_past(objnum))
3120 mprintf((0, "Resetting object sync due to powerup creation.\n"));
3121 Network_send_objnum = -1;
3124 mprintf((0, "Creating powerup type %d in segment %i.\n", powerup_type, segnum));
3125 map_objnum_local_to_local(objnum);
3129 multi_send_play_sound(int sound_num, fix volume)
3132 multibuf[count] = MULTI_PLAY_SOUND; count += 1;
3133 multibuf[count] = Player_num; count += 1;
3134 multibuf[count] = (char)sound_num; count += 1;
3135 multibuf[count] = (char)(volume >> 12); count += 1;
3138 multi_send_data(multibuf, count, 0);
3142 multi_send_audio_taunt(int taunt_num)
3144 return; // Taken out, awaiting sounds..
3147 int audio_taunts[4] = {
3148 SOUND_CONTROL_CENTER_WARNING_SIREN,
3149 SOUND_HOSTAGE_RESCUED,
3150 SOUND_REFUEL_STATION_GIVING_FUEL,
3155 Assert(taunt_num >= 0);
3156 Assert(taunt_num < 4);
3158 digi_play_sample( audio_taunts[taunt_num], F1_0 );
3159 multi_send_play_sound(audio_taunts[taunt_num], F1_0);
3164 multi_send_score(void)
3166 // Send my current score to all other players so it will remain
3170 if (Game_mode & GM_MULTI_COOP) {
3171 multi_sort_kill_list();
3172 multibuf[count] = MULTI_SCORE; count += 1;
3173 multibuf[count] = Player_num; count += 1;
3174 *(int *)(multibuf+count) = INTEL_INT( Players[Player_num].score ); count += 4;
3175 multi_send_data(multibuf, count, 0);
3181 multi_send_save_game(ubyte slot, uint id, char * desc)
3185 multibuf[count] = MULTI_SAVE_GAME; count += 1;
3186 multibuf[count] = slot; count += 1; // Save slot=0
3187 *(uint *)(multibuf+count) = INTEL_INT( id ); count += 4; // Save id
3188 memcpy( &multibuf[count], desc, 20 ); count += 20;
3190 multi_send_data(multibuf, count, 2);
3194 multi_send_restore_game(ubyte slot, uint id)
3198 multibuf[count] = MULTI_RESTORE_GAME; count += 1;
3199 multibuf[count] = slot; count += 1; // Save slot=0
3200 *(uint *)(multibuf+count) = INTEL_INT( id ); count += 4; // Save id
3202 multi_send_data(multibuf, count, 2);
3206 multi_send_netplayer_stats_request(ubyte player_num)
3210 multibuf[count] = MULTI_REQ_PLAYER; count += 1;
3211 multibuf[count] = player_num; count += 1;
3213 multi_send_data(multibuf, count, 0 );
3217 multi_send_trigger(int triggernum)
3219 // Send an even to trigger something in the mine
3223 multibuf[count] = MULTI_TRIGGER; count += 1;
3224 multibuf[count] = Player_num; count += 1;
3225 multibuf[count] = (ubyte)triggernum; count += 1;
3227 mprintf ((0,"Sending trigger %d\n",triggernum));
3229 multi_send_data(multibuf, count, 1);
3230 // multi_send_data(multibuf, count, 1); // twice?
3234 multi_send_hostage_door_status(int wallnum)
3236 // Tell the other player what the hit point status of a hostage door
3241 Assert(Walls[wallnum].type == WALL_BLASTABLE);
3243 multibuf[count] = MULTI_HOSTAGE_DOOR; count += 1;
3244 *(short *)(multibuf+count) = INTEL_SHORT( (short)wallnum ); count += 2;
3245 *(fix *)(multibuf+count) = (fix)INTEL_INT( (int)Walls[wallnum].hps ); count += 4;
3247 // mprintf((0, "Door %d damaged by %f points.\n", wallnum, f2fl(Walls[wallnum].hps)));
3249 multi_send_data(multibuf, count, 0);
3252 extern int ConsistencyCount;
3253 extern int Drop_afterburner_blob_flag;
3257 void multi_prep_level(void)
3259 // Do any special stuff to the level required for serial games
3260 // before we begin playing in it.
3262 // Player_num MUST be set before calling this procedure.
3264 // This function must be called before checksuming the Object array,
3265 // since the resulting checksum with depend on the value of Player_num
3266 // at the time this is called.
3269 int cloak_count, inv_count;
3271 Assert(Game_mode & GM_MULTI);
3273 Assert(NumNetPlayerPositions > 0);
3277 Drop_afterburner_blob_flag=0;
3280 for (i=0;i<MAX_NUM_NET_PLAYERS;i++)
3283 for (i = 0; i < NumNetPlayerPositions; i++)
3285 if (i != Player_num)
3286 Objects[Players[i].objnum].control_type = CT_REMOTE;
3287 Objects[Players[i].objnum].movement_type = MT_PHYSICS;
3288 multi_reset_player_object(&Objects[Players[i].objnum]);
3289 LastPacketTime[i] = 0;
3293 for (i = 0; i < MAX_ROBOTS_CONTROLLED; i++)
3295 robot_controlled[i] = -1;
3296 robot_agitation[i] = 0;
3301 Viewer = ConsoleObject = &Objects[Players[Player_num].objnum];
3303 if (!(Game_mode & GM_MULTI_COOP))
3305 multi_delete_extra_objects(); // Removes monsters from level
3308 if (Game_mode & GM_MULTI_ROBOTS)
3310 multi_set_robot_ai(); // Set all Robot AI to types we can cope with
3313 if (Game_mode & GM_NETWORK)
3315 multi_adjust_cap_for_player(Player_num);
3316 multi_send_powerup_update();
3317 ng=1; // ng means network game
3323 for (i=0; i<=Highest_object_index; i++)
3327 if ((Objects[i].type == OBJ_HOSTAGE) && !(Game_mode & GM_MULTI_COOP))
3329 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);
3333 Objects[objnum].rtype.vclip_info.vclip_num = Powerup_info[POW_SHIELD_BOOST].vclip_num;
3334 Objects[objnum].rtype.vclip_info.frametime = Vclip[Objects[objnum].rtype.vclip_info.vclip_num].frame_time;
3335 Objects[objnum].rtype.vclip_info.framenum = 0;
3336 Objects[objnum].mtype.phys_info.drag = 512; //1024;
3337 Objects[objnum].mtype.phys_info.mass = F1_0;
3338 vm_vec_zero(&Objects[objnum].mtype.phys_info.velocity);
3343 if (Objects[i].type == OBJ_POWERUP)
3345 if (Objects[i].id == POW_EXTRA_LIFE)
3347 if (ng && !Netgame.DoInvulnerability)
3349 Objects[i].id = POW_SHIELD_BOOST;
3350 Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num;
3351 Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time;
3355 Objects[i].id = POW_INVULNERABILITY;
3356 Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num;
3357 Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time;
3362 if (!(Game_mode & GM_MULTI_COOP))
3363 if ((Objects[i].id >= POW_KEY_BLUE) && (Objects[i].id <= POW_KEY_GOLD))
3365 Objects[i].id = POW_SHIELD_BOOST;
3366 Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num;
3367 Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time;
3370 if (Objects[i].id == POW_INVULNERABILITY) {
3371 if (inv_count >= 3 || (ng && !Netgame.DoInvulnerability)) {
3372 mprintf((0, "Bashing Invulnerability object #%i to shield.\n", i));
3373 Objects[i].id = POW_SHIELD_BOOST;
3374 Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num;
3375 Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time;
3380 if (Objects[i].id == POW_CLOAK) {
3381 if (cloak_count >= 3 || (ng && !Netgame.DoCloak)) {
3382 mprintf((0, "Bashing Cloak object #%i to shield.\n", i));
3383 Objects[i].id = POW_SHIELD_BOOST;
3384 Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num;
3385 Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time;
3390 if (Objects[i].id == POW_AFTERBURNER && ng && !Netgame.DoAfterburner)
3391 bash_to_shield (i,"afterburner");
3392 if (Objects[i].id == POW_FUSION_WEAPON && ng && !Netgame.DoFusions)
3393 bash_to_shield (i,"fusion");
3394 if (Objects[i].id == POW_PHOENIX_WEAPON && ng && !Netgame.DoPhoenix)
3395 bash_to_shield (i,"phoenix");
3397 if (Objects[i].id == POW_HELIX_WEAPON && ng && !Netgame.DoHelix)
3398 bash_to_shield (i,"helix");
3400 if (Objects[i].id == POW_MEGA_WEAPON && ng && !Netgame.DoMegas)
3401 bash_to_shield (i,"mega");
3403 if (Objects[i].id == POW_SMARTBOMB_WEAPON && ng && !Netgame.DoSmarts)
3404 bash_to_shield (i,"smartmissile");
3406 if (Objects[i].id == POW_GAUSS_WEAPON && ng && !Netgame.DoGauss)
3407 bash_to_shield (i,"gauss");
3409 if (Objects[i].id == POW_VULCAN_WEAPON && ng && !Netgame.DoVulcan)
3410 bash_to_shield (i,"vulcan");
3412 if (Objects[i].id == POW_PLASMA_WEAPON && ng && !Netgame.DoPlasma)
3413 bash_to_shield (i,"plasma");
3415 if (Objects[i].id == POW_OMEGA_WEAPON && ng && !Netgame.DoOmega)
3416 bash_to_shield (i,"omega");
3418 if (Objects[i].id == POW_SUPER_LASER && ng && !Netgame.DoSuperLaser)
3419 bash_to_shield (i,"superlaser");
3421 if (Objects[i].id == POW_PROXIMITY_WEAPON && ng && !Netgame.DoProximity)
3422 bash_to_shield (i,"proximity");
3424 // Special: Make all proximity bombs into shields if in hoard mode because
3425 // we use the proximity slot in the player struct to signify how many orbs
3428 if (Objects[i].id == POW_PROXIMITY_WEAPON && ng && (Game_mode & GM_HOARD))
3429 bash_to_shield (i,"proximity");
3431 if (Objects[i].id==POW_VULCAN_AMMO && ng && (!Netgame.DoVulcan && !Netgame.DoGauss))
3432 bash_to_shield(i,"vulcan ammo");
3434 if (Objects[i].id == POW_SPREADFIRE_WEAPON && ng && !Netgame.DoSpread)
3435 bash_to_shield (i,"spread");
3436 if (Objects[i].id == POW_SMART_MINE && ng && !Netgame.DoSmartMine)
3437 bash_to_shield (i,"smartmine");
3438 if (Objects[i].id == POW_SMISSILE1_1 && ng && !Netgame.DoFlash)
3439 bash_to_shield (i,"flash");
3440 if (Objects[i].id == POW_SMISSILE1_4 && ng && !Netgame.DoFlash)
3441 bash_to_shield (i,"flash");
3442 if (Objects[i].id == POW_GUIDED_MISSILE_1 && ng && !Netgame.DoGuided)
3443 bash_to_shield (i,"guided");
3444 if (Objects[i].id == POW_GUIDED_MISSILE_4 && ng && !Netgame.DoGuided)
3445 bash_to_shield (i,"guided");
3446 if (Objects[i].id == POW_EARTHSHAKER_MISSILE && ng && !Netgame.DoEarthShaker)
3447 bash_to_shield (i,"earth");
3448 if (Objects[i].id == POW_MERCURY_MISSILE_1 && ng && !Netgame.DoMercury)
3449 bash_to_shield (i,"Mercury");
3450 if (Objects[i].id == POW_MERCURY_MISSILE_4 && ng && !Netgame.DoMercury)
3451 bash_to_shield (i,"Mercury");
3452 if (Objects[i].id == POW_CONVERTER && ng && !Netgame.DoConverter)
3453 bash_to_shield (i,"Converter");
3454 if (Objects[i].id == POW_AMMO_RACK && ng && !Netgame.DoAmmoRack)
3455 bash_to_shield (i,"Ammo rack");
3456 if (Objects[i].id == POW_HEADLIGHT && ng && !Netgame.DoHeadlight)
3457 bash_to_shield (i,"Headlight");
3458 if (Objects[i].id == POW_LASER && ng && !Netgame.DoLaserUpgrade)
3459 bash_to_shield (i,"Laser powerup");
3460 if (Objects[i].id == POW_HOMING_AMMO_1 && ng && !Netgame.DoHoming)
3461 bash_to_shield (i,"Homing");
3462 if (Objects[i].id == POW_HOMING_AMMO_4 && ng && !Netgame.DoHoming)
3463 bash_to_shield (i,"Homing");
3464 if (Objects[i].id == POW_QUAD_FIRE && ng && !Netgame.DoQuadLasers)
3465 bash_to_shield (i,"Quad Lasers");
3466 if (Objects[i].id == POW_FLAG_BLUE && !(Game_mode & GM_CAPTURE))
3467 bash_to_shield (i,"Blue flag");
3468 if (Objects[i].id == POW_FLAG_RED && !(Game_mode & GM_CAPTURE))
3469 bash_to_shield (i,"Red flag");
3473 if (Game_mode & GM_HOARD)
3476 if ((Game_mode & GM_CAPTURE) || (Game_mode & GM_HOARD))
3477 multi_apply_goal_textures();
3479 multi_sort_kill_list();
3481 multi_show_player_list();
3483 ConsoleObject->control_type = CT_FLYING;
3485 reset_player_object();
3489 int Goal_blue_segnum,Goal_red_segnum;
3491 void multi_apply_goal_textures()
3497 for (i=0; i <= Highest_segment_index; i++)
3500 seg2 = &Segment2s[i];
3502 if (seg2->special==SEGMENT_IS_GOAL_BLUE)
3505 Goal_blue_segnum = i;
3507 if (Game_mode & GM_HOARD)
3508 tex=find_goal_texture (TMI_GOAL_HOARD);
3510 tex=find_goal_texture (TMI_GOAL_BLUE);
3513 for (j = 0; j < 6; j++) {
3515 seg->sides[j].tmap_num=tex;
3517 seg->sides[j].uvls[v].l = i2f(100); //max out
3520 seg2->static_light = i2f(100); //make static light bright
3524 if (seg2->special==SEGMENT_IS_GOAL_RED)
3526 Goal_red_segnum = i;
3528 // Make both textures the same if Hoard mode
3530 if (Game_mode & GM_HOARD)
3531 tex=find_goal_texture (TMI_GOAL_HOARD);
3533 tex=find_goal_texture (TMI_GOAL_RED);
3536 for (j = 0; j < 6; j++) {
3538 seg->sides[j].tmap_num=tex;
3540 seg->sides[j].uvls[v].l = i2f(1000); //max out
3543 seg2->static_light = i2f(100); //make static light bright
3547 int find_goal_texture (ubyte t)
3551 for (i=0;i<NumTextures;i++)
3552 if (TmapInfo[i].flags & t)
3555 Int3(); // Hey, there is no goal texture for this PIG!!!!
3556 // Edit bitmaps.tbl and designate two textures to be RED and BLUE
3562 /* DPH: Moved to gameseq.c
3563 void bash_to_shield (int i,char *s)
3565 int type=Objects[i].id;
3567 mprintf((0, "Bashing %s object #%i to shield.\n",s, i));
3569 PowerupsInMine[type]=MaxPowerupsAllowed[type]=0;
3571 Objects[i].id = POW_SHIELD_BOOST;
3572 Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num;
3573 Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time;
3577 void multi_set_robot_ai(void)
3579 // Go through the objects array looking for robots and setting
3580 // them to certain supported types of NET AI behavior.
3584 // for (i = 0; i <= Highest_object_index; i++)
3586 // if (Objects[i].type == OBJ_ROBOT) {
3587 // Objects[i].ai_info.REMOTE_OWNER = -1;
3588 // if (Objects[i].ai_info.behavior == AIB_STATION)
3589 // Objects[i].ai_info.behavior = AIB_NORMAL;
3594 int multi_delete_extra_objects()
3600 // Go through the object list and remove any objects not used in
3601 // 'Anarchy!' games.
3603 // This function also prints the total number of available multiplayer
3604 // positions in this level, even though this should always be 8 or more!
3607 for (i=0;i<=Highest_object_index;i++) {
3608 if ((objp->type==OBJ_PLAYER) || (objp->type==OBJ_GHOST))
3610 else if ((objp->type==OBJ_ROBOT) && (Game_mode & GM_MULTI_ROBOTS))
3612 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) ) {
3613 // Before deleting object, if it's a robot, drop it's special powerup, if any
3614 if (objp->type == OBJ_ROBOT)
3615 if (objp->contains_count && (objp->contains_type == OBJ_POWERUP))
3616 object_create_egg(objp);
3625 void change_playernum_to( int new_Player_num )
3627 if (Player_num > -1)
3628 memcpy( Players[new_Player_num].callsign, Players[Player_num].callsign, CALLSIGN_LEN+1 );
3629 Player_num = new_Player_num;
3632 int multi_all_players_alive()
3635 for (i=0;i<N_players;i++)
3637 if (PKilledFlags[i] && Players[i].connected)
3643 void multi_initiate_save_game()
3650 if ((Endlevel_sequence) || (Control_center_destroyed))
3653 if (!multi_all_players_alive())
3655 HUD_init_message ("Can't save...all players must be alive!");
3659 // multi_send_netplayer_stats_request(255);
3664 slot = state_get_save_file(filename, desc, 1 );
3673 // Make a unique game id
3674 game_id = timer_get_fixed_seconds();
3675 game_id ^= N_players<<4;
3676 for (i=0; i<N_players; i++ )
3677 game_id ^= *(uint *)Players[i].callsign;
3678 if ( game_id == 0 ) game_id = 1; // 0 is invalid
3680 mprintf(( 1, "Game_id = %8x\n", game_id));
3681 multi_send_save_game(slot, game_id, desc );
3683 multi_save_game(slot,game_id, desc );
3686 extern int state_get_game_id(char *);
3688 void multi_initiate_restore_game()
3693 if ((Endlevel_sequence) || (Control_center_destroyed))
3696 if (!multi_all_players_alive())
3698 HUD_init_message ("Can't restore...all players must be alive!");
3703 slot = state_get_restore_file(filename,1);
3708 state_game_id=state_get_game_id (filename);
3714 multi_send_restore_game(slot,state_game_id);
3716 multi_restore_game(slot,state_game_id);
3719 void multi_save_game(ubyte slot, uint id, char *desc)
3723 if ((Endlevel_sequence) || (Control_center_destroyed))
3727 sprintf( filename, "%s.mg%d", Players[Player_num].callsign, slot );
3729 sprintf( filename, ":Players:%s.mg%d", Players[Player_num].callsign, slot );
3731 mprintf(( 0, "Save game %x on slot %d\n", id, slot ));
3732 HUD_init_message( "Saving game #%d, '%s'", slot, desc );
3735 state_save_all_sub(filename, desc, 0 );
3738 void multi_restore_game(ubyte slot, uint id)
3741 player saved_player;
3745 if ((Endlevel_sequence) || (Control_center_destroyed))
3748 mprintf(( 0, "Restore game %x from slot %d\n", id, slot ));
3749 saved_player = Players[Player_num];
3751 sprintf( filename, "%s.mg%d", Players[Player_num].callsign, slot );
3753 sprintf( filename, ":Players:%s.mg%d", Players[Player_num].callsign, slot );
3756 for (i=0;i<N_players;i++)
3757 multi_strip_robots(i);
3759 thisid=state_get_game_id (filename);
3762 multi_bad_restore ();
3766 pnum=state_restore_all_sub( filename, 1, 0 );
3768 mprintf ((0,"StateId=%d ThisID=%d\n",state_game_id,id));
3770 /* if (state_game_id != id ) {
3771 // Game doesn't match!!!
3772 nm_messagebox( "Error", 1, "Ok", "Cannot restore saved game" );
3773 Game_mode |= GM_GAME_OVER;
3774 Function_mode = FMODE_MENU;
3775 longjmp(LeaveGame, 0);
3778 change_playernum_to(pnum-1);
3779 memcpy( Players[Player_num].callsign, saved_player.callsign, CALLSIGN_LEN+1 );
3780 memcpy( Players[Player_num].net_address, saved_player.net_address, 6 );
3781 Players[Player_num].connected = saved_player.connected;
3782 Players[Player_num].n_packets_got = saved_player.n_packets_got;
3783 Players[Player_num].n_packets_sent = saved_player.n_packets_sent;
3784 Viewer = ConsoleObject = &Objects[pnum-1]; */
3788 void extract_netplayer_stats( netplayer_stats *ps, player * pd )
3792 ps->flags = INTEL_INT(pd->flags); // Powerup flags, see below...
3793 ps->energy = (fix)INTEL_INT(pd->energy); // Amount of energy remaining.
3794 ps->shields = (fix)INTEL_INT(pd->shields); // shields remaining (protection)
3795 ps->lives = pd->lives; // Lives remaining, 0 = game over.
3796 ps->laser_level = pd->laser_level; // Current level of the laser.
3797 ps->primary_weapon_flags=pd->primary_weapon_flags; // bit set indicates the player has this weapon.
3798 ps->secondary_weapon_flags=pd->secondary_weapon_flags; // bit set indicates the player has this weapon.
3799 for (i = 0; i < MAX_PRIMARY_WEAPONS; i++)
3800 ps->primary_ammo[i] = INTEL_SHORT(pd->primary_ammo[i]);
3801 for (i = 0; i < MAX_SECONDARY_WEAPONS; i++)
3802 ps->secondary_ammo[i] = INTEL_SHORT(pd->secondary_ammo[i]);
3804 // memcpy( ps->primary_ammo, pd->primary_ammo, MAX_PRIMARY_WEAPONS*sizeof(short) ); // How much ammo of each type.
3805 // memcpy( ps->secondary_ammo, pd->secondary_ammo, MAX_SECONDARY_WEAPONS*sizeof(short) ); // How much ammo of each type.
3807 ps->last_score=INTEL_INT(pd->last_score); // Score at beginning of current level.
3808 ps->score=INTEL_INT(pd->score); // Current score.
3809 ps->cloak_time=(fix)INTEL_INT(pd->cloak_time); // Time cloaked
3810 ps->homing_object_dist=(fix)INTEL_INT(pd->homing_object_dist); // Distance of nearest homing object.
3811 ps->invulnerable_time=(fix)INTEL_INT(pd->invulnerable_time); // Time invulnerable
3812 ps->KillGoalCount=INTEL_SHORT(pd->KillGoalCount);
3813 ps->net_killed_total=INTEL_SHORT(pd->net_killed_total); // Number of times killed total
3814 ps->net_kills_total=INTEL_SHORT(pd->net_kills_total); // Number of net kills total
3815 ps->num_kills_level=INTEL_SHORT(pd->num_kills_level); // Number of kills this level
3816 ps->num_kills_total=INTEL_SHORT(pd->num_kills_total); // Number of kills total
3817 ps->num_robots_level=INTEL_SHORT(pd->num_robots_level); // Number of initial robots this level
3818 ps->num_robots_total=INTEL_SHORT(pd->num_robots_total); // Number of robots total
3819 ps->hostages_rescued_total=INTEL_SHORT(pd->hostages_rescued_total); // Total number of hostages rescued.
3820 ps->hostages_total=INTEL_SHORT(pd->hostages_total); // Total number of hostages.
3821 ps->hostages_on_board=pd->hostages_on_board; // Number of hostages on ship.
3824 void use_netplayer_stats( player * ps, netplayer_stats *pd )
3828 ps->flags = INTEL_INT(pd->flags); // Powerup flags, see below...
3829 ps->energy = (fix)INTEL_INT((int)pd->energy); // Amount of energy remaining.
3830 ps->shields = (fix)INTEL_INT((int)pd->shields); // shields remaining (protection)
3831 ps->lives = pd->lives; // Lives remaining, 0 = game over.
3832 ps->laser_level = pd->laser_level; // Current level of the laser.
3833 ps->primary_weapon_flags=pd->primary_weapon_flags; // bit set indicates the player has this weapon.
3834 ps->secondary_weapon_flags=pd->secondary_weapon_flags; // bit set indicates the player has this weapon.
3835 for (i = 0; i < MAX_PRIMARY_WEAPONS; i++)
3836 ps->primary_ammo[i] = INTEL_SHORT(pd->primary_ammo[i]);
3837 for (i = 0; i < MAX_SECONDARY_WEAPONS; i++)
3838 ps->secondary_ammo[i] = INTEL_SHORT(pd->secondary_ammo[i]);
3839 // memcpy( ps->primary_ammo, pd->primary_ammo, MAX_PRIMARY_WEAPONS*sizeof(short) ); // How much ammo of each type.
3840 // memcpy( ps->secondary_ammo, pd->secondary_ammo, MAX_SECONDARY_WEAPONS*sizeof(short) ); // How much ammo of each type.
3841 ps->last_score = INTEL_INT(pd->last_score); // Score at beginning of current level.
3842 ps->score = INTEL_INT(pd->score); // Current score.
3843 ps->cloak_time = (fix)INTEL_INT((int)pd->cloak_time); // Time cloaked
3844 ps->homing_object_dist = (fix)INTEL_INT((int)pd->homing_object_dist); // Distance of nearest homing object.
3845 ps->invulnerable_time = (fix)INTEL_INT((int)pd->invulnerable_time); // Time invulnerable
3846 ps->KillGoalCount=INTEL_SHORT(pd->KillGoalCount);
3847 ps->net_killed_total = INTEL_SHORT(pd->net_killed_total); // Number of times killed total
3848 ps->net_kills_total = INTEL_SHORT(pd->net_kills_total); // Number of net kills total
3849 ps->num_kills_level = INTEL_SHORT(pd->num_kills_level); // Number of kills this level
3850 ps->num_kills_total = INTEL_SHORT(pd->num_kills_total); // Number of kills total
3851 ps->num_robots_level = INTEL_SHORT(pd->num_robots_level); // Number of initial robots this level
3852 ps->num_robots_total = INTEL_SHORT(pd->num_robots_total); // Number of robots total
3853 ps->hostages_rescued_total = INTEL_SHORT(pd->hostages_rescued_total); // Total number of hostages rescued.
3854 ps->hostages_total = INTEL_SHORT(pd->hostages_total); // Total number of hostages.
3855 ps->hostages_on_board=pd->hostages_on_board; // Number of hostages on ship.
3858 void multi_send_drop_weapon (int objnum,int seed)
3864 objp = &Objects[objnum];
3866 ammo_count = objp->ctype.powerup_info.count;
3868 if (objp->id == POW_OMEGA_WEAPON && ammo_count == F1_0)
3869 ammo_count = F1_0 - 1; //make fit in short
3871 Assert(ammo_count < F1_0); //make sure fits in short
3873 multibuf[count++]=(char)MULTI_DROP_WEAPON;
3874 multibuf[count++]=(char)objp->id;
3876 *(short *) (multibuf+count)=INTEL_SHORT(Player_num); count += 2;
3877 *(short *) (multibuf+count)=INTEL_SHORT(objnum); count += 2;
3878 *(short *) (multibuf+count)=INTEL_SHORT(ammo_count); count += 2;
3879 *(int *) (multibuf+count)=INTEL_INT(seed);
3881 map_objnum_local_to_local(objnum);
3883 if (Game_mode & GM_NETWORK)
3884 PowerupsInMine[objp->id]++;
3886 multi_send_data(multibuf, 12, 2);
3889 void multi_do_drop_weapon (char *buf)
3891 int pnum,ammo,objnum,remote_objnum,seed;
3895 powerup_id=(int)(buf[1]);
3896 pnum = INTEL_SHORT(*(short *)(buf+2));
3897 remote_objnum = INTEL_SHORT(*(short *)(buf+4));
3898 ammo = INTEL_SHORT(*(ushort *)(buf+6));
3899 seed = INTEL_INT(*(int *)(buf+8));
3901 objp = &Objects[Players[pnum].objnum];
3903 objnum = spit_powerup(objp, powerup_id, seed);
3905 map_objnum_local_to_remote(objnum, remote_objnum, pnum);
3908 Objects[objnum].ctype.powerup_info.count = ammo;
3910 if (Game_mode & GM_NETWORK)
3911 PowerupsInMine[powerup_id]++;
3913 mprintf ((0,"Dropped weapon %d!\n"));
3917 void multi_send_guided_info (object *miss,char done)
3924 mprintf ((0,"Sending guided info!\n"));
3926 multibuf[count++]=(char)MULTI_GUIDED;
3927 multibuf[count++]=(char)Player_num;
3928 multibuf[count++]=done;
3931 create_shortpos((shortpos *)(multibuf+count), miss,0);
3932 count+=sizeof(shortpos);
3934 create_shortpos(&sp, miss, 1);
3935 memcpy(&(multibuf[count]), (ubyte *)(sp.bytemat), 9);
3937 memcpy(&(multibuf[count]), (ubyte *)&(sp.xo), 14);
3941 multi_send_data(multibuf, count, 0);
3944 void multi_do_guided (char *buf)
3953 if (Guided_missile[(int)pnum]==NULL)
3957 mprintf ((0,"Guided missile for %s is NULL!\n",Players[(int)pnum].callsign));
3964 mprintf ((0,"Got guided info for %d (%s)\n",pnum,Players[(int)pnum].callsign));
3970 release_guided_missile(pnum);
3975 if (Guided_missile[(int)pnum]-Objects<0 || Guided_missile[(int)pnum]-Objects > Highest_object_index)
3977 Int3(); // Get Jason immediately!
3982 extract_shortpos(Guided_missile[(int)pnum], (shortpos *)(buf+count),0);
3984 memcpy((ubyte *)(sp.bytemat), (ubyte *)(buf + count), 9);
3985 memcpy((ubyte *)&(sp.xo), (ubyte *)(buf + count + 9), 14);
3986 extract_shortpos(Guided_missile[(int)pnum], &sp, 1);
3989 count+=sizeof (shortpos);
3991 update_object_seg(Guided_missile[(int)pnum]);
3994 void multi_send_stolen_items ()
3997 multibuf[0]=MULTI_STOLEN_ITEMS;
3999 for (i=0;i<MAX_STOLEN_ITEMS;i++)
4001 multibuf[i+1]=Stolen_items[i];
4002 mprintf ((0,"[%d]=%d ",i,Stolen_items[i]));
4003 count++; // So I like to break my stuff into smaller chunks, so what?
4006 multi_send_data(multibuf, count, 1);
4009 void multi_do_stolen_items (char *buf)
4013 mprintf ((0,"Recieved a stolen item packet...\n"));
4015 for (i=0;i<MAX_STOLEN_ITEMS;i++)
4017 Stolen_items[i]=buf[i+1];
4018 mprintf ((0,"[%d]=%d ",i,Stolen_items[i]));
4023 extern void network_send_important_packet (char *,int);
4025 void multi_send_wall_status (int wallnum,ubyte type,ubyte flags,ubyte state)
4028 multibuf[count]=MULTI_WALL_STATUS; count++;
4029 *(short *)(multibuf+count)=INTEL_SHORT(wallnum); count+=2;
4030 multibuf[count]=type; count++;
4031 multibuf[count]=flags; count++;
4032 multibuf[count]=state; count++;
4034 /* if (Game_mode & GM_NETWORK)
4036 network_send_important_packet (multibuf,count);
4037 network_send_important_packet (multibuf,count);
4041 multi_send_data(multibuf, count, 1); // twice, just to be sure
4042 multi_send_data(multibuf, count, 1);
4045 void multi_send_wall_status_specific (int pnum,int wallnum,ubyte type,ubyte flags,ubyte state)
4047 // Send wall states a specific rejoining player
4051 Assert (Game_mode & GM_NETWORK);
4052 // Assert (pnum>-1 && pnum<N_players);
4054 multibuf[count]=MULTI_WALL_STATUS; count++;
4055 *(short *)(multibuf+count)=INTEL_SHORT(wallnum); count+=2;
4056 multibuf[count]=type; count++;
4057 multibuf[count]=flags; count++;
4058 multibuf[count]=state; count++;
4060 network_send_naked_packet(multibuf, count,pnum); // twice, just to be sure
4061 network_send_naked_packet(multibuf, count,pnum);
4064 void multi_do_wall_status (char *buf)
4067 ubyte flag,type,state;
4069 wallnum=INTEL_SHORT( *(short *)(buf+1) );
4074 Assert (wallnum>=0);
4075 Walls[wallnum].type=type;
4076 Walls[wallnum].flags=flag;
4077 // Assert(state <= 4);
4078 Walls[wallnum].state=state;
4080 if (Walls[wallnum].type==WALL_OPEN)
4082 digi_kill_sound_linked_to_segment(Walls[wallnum].segnum,Walls[wallnum].sidenum,SOUND_FORCEFIELD_HUM);
4083 // digi_kill_sound_linked_to_segment(csegp-Segments,cside,SOUND_FORCEFIELD_HUM);
4087 // mprintf ((0,"Got a walls packet.\n"));
4090 void multi_send_jason_cheat (int num)
4096 void multi_send_kill_goal_counts()
4099 multibuf[0]=MULTI_KILLGOALS;
4101 for (i=0;i<MAX_PLAYERS;i++)
4103 *(char *)(multibuf+count)=(char)Players[i].KillGoalCount;
4107 mprintf ((0,"MULTI: Sending KillGoalCounts...\n"));
4108 multi_send_data(multibuf, count, 1);
4111 void multi_do_kill_goal_counts(char *buf)
4115 for (i=0;i<MAX_PLAYERS;i++)
4117 Players[i].KillGoalCount=*(char *)(buf+count);
4118 mprintf ((0,"KGC: %s has %d kills!\n",Players[i].callsign,Players[i].KillGoalCount));
4124 void multi_send_heartbeat ()
4126 if (!Netgame.PlayTimeAllowed)
4129 multibuf[0]=MULTI_HEARTBEAT;
4130 *(fix *)(multibuf+1)=(fix)INTEL_INT(ThisLevelTime);
4131 multi_send_data(multibuf, 5, 0);
4134 void multi_do_heartbeat (char *buf)
4138 num=(fix)INTEL_INT(*(int *)(buf+1));
4143 void multi_check_for_killgoal_winner ()
4145 int i,best=0,bestnum=0;
4149 if (Control_center_destroyed)
4152 for (i=0;i<N_players;i++)
4154 if (Players[i].KillGoalCount>best)
4156 best=Players[i].KillGoalCount;
4161 if (bestnum==Player_num)
4163 HUD_init_message("You have the best score at %d kills!",best);
4164 // Players[Player_num].shields=i2f(200);
4168 HUD_init_message ("%s has the best score with %d kills!",Players[bestnum].callsign,best);
4170 HUD_init_message ("The control center has been destroyed!");
4172 objp=obj_find_first_of_type (OBJ_CNTRLCEN);
4173 net_destroy_controlcen (objp);
4176 void multi_send_seismic (fix start,fix end)
4180 multibuf[0]=MULTI_SEISMIC;
4181 *(fix *)(multibuf+count)=(fix)INTEL_INT(start); count+=(sizeof(fix));
4182 *(fix *)(multibuf+count)=(fix)INTEL_INT(end); count+=(sizeof(fix));
4184 multi_send_data(multibuf, count, 1);
4187 extern fix Seismic_disturbance_start_time;
4188 extern fix Seismic_disturbance_end_time;
4190 void multi_do_seismic (char *buf)
4192 Seismic_disturbance_start_time=(fix)INTEL_INT( *(int *)(buf+1) );
4193 Seismic_disturbance_end_time=(fix)INTEL_INT( *(int *)(buf+5) );
4194 digi_play_sample (SOUND_SEISMIC_DISTURBANCE_START, F1_0);
4197 void multi_send_light (int segnum,ubyte val)
4200 multibuf[0]=MULTI_LIGHT;
4201 *(int *)(multibuf+count)=INTEL_INT(segnum); count+=(sizeof(int));
4202 *(char *)(multibuf+count)=val; count++;
4205 //mprintf ((0,"Sending %d!\n",Segments[segnum].sides[i].tmap_num2));
4206 *(short *)(multibuf+count)=INTEL_SHORT(Segments[segnum].sides[i].tmap_num2); count+=2;
4208 multi_send_data(multibuf, count, 1);
4210 void multi_send_light_specific (int pnum,int segnum,ubyte val)
4214 Assert (Game_mode & GM_NETWORK);
4215 // Assert (pnum>-1 && pnum<N_players);
4217 multibuf[0]=MULTI_LIGHT;
4218 *(int *)(multibuf+count)=INTEL_INT(segnum); count+=(sizeof(int));
4219 *(char *)(multibuf+count)=val; count++;
4223 //mprintf ((0,"Sending %d!\n",Segments[segnum].sides[i].tmap_num2));
4224 *(short *)(multibuf+count)=INTEL_SHORT(Segments[segnum].sides[i].tmap_num2); count+=2;
4226 network_send_naked_packet(multibuf, count, pnum);
4229 void multi_do_light (char *buf)
4232 int seg=INTEL_INT(*(int *)(buf+1));
4233 ubyte sides=*(char *)(buf+5);
4237 if ((sides & (1<<i)))
4239 subtract_light (seg,i);
4240 Segments[seg].sides[i].tmap_num2=INTEL_SHORT( *(short *)(buf+(6+(2*i))) );
4241 // mprintf ((0,"Got %d!\n",Segments[seg].sides[i].tmap_num2));
4246 //@@void multi_send_start_trigger(int triggernum)
4248 //@@ // Send an even to trigger something in the mine
4252 //@@ multibuf[count] = MULTI_START_TRIGGER; count += 1;
4253 //@@ multibuf[count] = Player_num; count += 1;
4254 //@@ multibuf[count] = (ubyte)triggernum; count += 1;
4256 //@@// mprintf ((0,"Sending start trigger %d\n",triggernum));
4257 //@@ multi_send_data(multibuf, count, 2);
4259 //@@void multi_do_start_trigger(char *buf)
4261 //@@ int pnum = buf[1];
4262 //@@ int trigger = buf[2];
4264 //@@// mprintf ((0,"MULTI doing start trigger!\n"));
4266 //@@ if ((pnum < 0) || (pnum >= N_players) || (pnum == Player_num))
4268 //@@ Int3(); // Got trigger from illegal playernum
4271 //@@ if ((trigger < 0) || (trigger >= Num_triggers))
4273 //@@ Int3(); // Illegal trigger number in multiplayer
4277 //@@ if (!(Triggers[trigger].flags & TF_SPRUNG))
4278 //@@ check_trigger_sub(trigger, pnum,0);
4282 void multi_do_flags (char *buf)
4285 uint flags=INTEL_INT( *(uint *)(buf+2) );
4287 if (pnum!=Player_num)
4288 Players[(int)pnum].flags=flags;
4291 void multi_send_flags (char pnum)
4293 multibuf[0]=MULTI_FLAGS;
4295 *(uint *)(multibuf+2)=INTEL_INT(Players[(int)pnum].flags);
4297 multi_send_data(multibuf, 6, 1);
4300 void multi_send_drop_blobs (char pnum)
4302 multibuf[0]=MULTI_DROP_BLOB;
4305 multi_send_data(multibuf, 2, 0);
4308 void multi_do_drop_blob (char *buf)
4311 drop_afterburner_blobs (&Objects[Players[(int)pnum].objnum], 2, i2f(5)/2, -1);
4314 void multi_send_powerup_update ()
4319 multibuf[0]=MULTI_POWERUP_UPDATE;
4320 for (i=0;i<MAX_POWERUP_TYPES;i++)
4321 multibuf[i+1]=MaxPowerupsAllowed[i];
4323 multi_send_data(multibuf, MAX_POWERUP_TYPES+1, 1);
4325 void multi_do_powerup_update (char *buf)
4329 for (i=0;i<MAX_POWERUP_TYPES;i++)
4330 if (buf[i+1]>MaxPowerupsAllowed[i])
4331 MaxPowerupsAllowed[i]=buf[i+1];
4334 extern active_door ActiveDoors[];
4335 extern int Num_open_doors; // Number of open doors
4337 void multi_send_active_door (char i)
4341 multibuf[0]=MULTI_ACTIVE_DOOR;
4343 multibuf[2]=Num_open_doors;
4346 memcpy ((char *)(&multibuf[3]),&ActiveDoors[(int)i],sizeof(struct active_door));
4347 count += sizeof(active_door);
4349 *(int *)(multibuf + count) = INTEL_INT(ActiveDoors[i].n_parts); count += 4;
4350 *(short *)(multibuf + count) = INTEL_SHORT(ActiveDoors[i].front_wallnum[0]); count += 2;
4351 *(short *)(multibuf + count) = INTEL_SHORT(ActiveDoors[i].front_wallnum[1]); count += 2;
4352 *(short *)(multibuf + count) = INTEL_SHORT(ActiveDoors[i].back_wallnum[0]); count += 2;
4353 *(short *)(multibuf + count) = INTEL_SHORT(ActiveDoors[i].back_wallnum[1]); count += 2;
4354 *(int *)(multibuf + count) = INTEL_INT(ActiveDoors[i].time); count += 4;
4356 // multi_send_data (multibuf,sizeof(struct active_door)+3,1);
4357 multi_send_data (multibuf,count,1);
4360 void multi_do_active_door (char *buf)
4364 Num_open_doors=buf[2];
4368 memcpy (&ActiveDoors[(int)i],buf+count,sizeof(struct active_door));
4370 ActiveDoors[i].n_parts = INTEL_INT( *(int *)(buf+count) ); count += 4;
4371 ActiveDoors[i].front_wallnum[0] = INTEL_SHORT( *(short *)(buf+count) ); count +=2;
4372 ActiveDoors[i].front_wallnum[1] = INTEL_SHORT( *(short *)(buf+count) ); count +=2;
4373 ActiveDoors[i].back_wallnum[0] = INTEL_SHORT( *(short *)(buf+count) ); count +=2;
4374 ActiveDoors[i].back_wallnum[1] = INTEL_SHORT( *(short *)(buf+count) ); count +=2;
4375 ActiveDoors[i].time = INTEL_INT( *(int *)(buf+count) ); count += 4;
4379 void multi_send_sound_function (char whichfunc,char sound)
4383 multibuf[0]=MULTI_SOUND_FUNCTION; count++;
4384 multibuf[1]=Player_num; count++;
4385 multibuf[2]=whichfunc; count++;
4387 *(uint *)(multibuf+count)=sound; count++;
4389 multibuf[3] = sound; count++; // this would probably work on the PC as well. Jason?
4391 multi_send_data (multibuf,4,0);
4394 #define AFTERBURNER_LOOP_START 20098
4395 #define AFTERBURNER_LOOP_END 25776
4397 void multi_do_sound_function (char *buf)
4401 char pnum,whichfunc;
4404 if (Players[Player_num].connected!=1)
4412 digi_kill_sound_linked_to_object (Players[(int)pnum].objnum);
4413 else if (whichfunc==3)
4414 digi_link_sound_to_object3( sound, Players[(int)pnum].objnum, 1,F1_0, i2f(256), AFTERBURNER_LOOP_START, AFTERBURNER_LOOP_END);
4417 void multi_send_capture_bonus (char pnum)
4419 Assert (Game_mode & GM_CAPTURE);
4421 multibuf[0]=MULTI_CAPTURE_BONUS;
4424 multi_send_data (multibuf,2,1);
4425 multi_do_capture_bonus (multibuf);
4427 void multi_send_orb_bonus (char pnum)
4429 Assert (Game_mode & GM_HOARD);
4431 multibuf[0]=MULTI_ORB_BONUS;
4433 multibuf[2]=Players[Player_num].secondary_ammo[PROXIMITY_INDEX];
4435 multi_send_data (multibuf,3,1);
4436 multi_do_orb_bonus (multibuf);
4438 void multi_do_capture_bonus(char *buf)
4440 // Figure out the results of a network kills and add it to the
4441 // appropriate player's tally.
4446 kmatrix_kills_changed = 1;
4448 if (pnum==Player_num)
4449 HUD_init_message("You have Scored!");
4451 HUD_init_message("%s has Scored!",Players[(int)pnum].callsign);
4453 if (pnum==Player_num)
4454 digi_play_sample (SOUND_HUD_YOU_GOT_GOAL,F1_0*2);
4455 else if (get_team(pnum)==TEAM_RED)
4456 digi_play_sample (SOUND_HUD_RED_GOT_GOAL,F1_0*2);
4458 digi_play_sample (SOUND_HUD_BLUE_GOT_GOAL,F1_0*2);
4460 Players[(int)pnum].flags &= ~(PLAYER_FLAGS_FLAG); // Clear capture flag
4462 team_kills[get_team(pnum)] += 5;
4463 Players[(int)pnum].net_kills_total += 5;
4464 Players[(int)pnum].KillGoalCount+=5;
4466 if (Netgame.KillGoal>0)
4468 TheGoal=Netgame.KillGoal*5;
4470 if (Players[(int)pnum].KillGoalCount>=TheGoal)
4472 if (pnum==Player_num)
4474 HUD_init_message("You reached the kill goal!");
4475 Players[Player_num].shields=i2f(200);
4478 HUD_init_message ("%s has reached the kill goal!",Players[(int)pnum].callsign);
4480 HUD_init_message ("The control center has been destroyed!");
4481 net_destroy_controlcen (obj_find_first_of_type (OBJ_CNTRLCEN));
4485 multi_sort_kill_list();
4486 multi_show_player_list();
4489 int GetOrbBonus (char num)
4493 bonus=num*(num+1)/2;
4497 void multi_do_orb_bonus(char *buf)
4499 // Figure out the results of a network kills and add it to the
4500 // appropriate player's tally.
4504 int bonus=GetOrbBonus (buf[2]);
4506 kmatrix_kills_changed = 1;
4508 if (pnum==Player_num)
4509 HUD_init_message("You have scored %d points!",bonus);
4511 HUD_init_message("%s has scored with %d orbs!",Players[(int)pnum].callsign,buf[2]);
4513 if (pnum==Player_num)
4514 digi_start_sound_queued (SOUND_HUD_YOU_GOT_GOAL,F1_0*2);
4515 else if (Game_mode & GM_TEAM)
4517 if (get_team(pnum)==TEAM_RED)
4518 digi_play_sample (SOUND_HUD_RED_GOT_GOAL,F1_0*2);
4520 digi_play_sample (SOUND_HUD_BLUE_GOT_GOAL,F1_0*2);
4523 digi_play_sample (SOUND_OPPONENT_HAS_SCORED,F1_0*2);
4525 if (bonus>PhallicLimit)
4527 if (pnum==Player_num)
4528 HUD_init_message ("You have the record with %d points!",bonus);
4530 HUD_init_message ("%s has the record with %d points!",Players[(int)pnum].callsign,bonus);
4531 digi_play_sample (SOUND_BUDDY_MET_GOAL,F1_0*2);
4536 Players[(int)pnum].flags &= ~(PLAYER_FLAGS_FLAG); // Clear orb flag
4538 team_kills[get_team(pnum)] += bonus;
4539 Players[(int)pnum].net_kills_total += bonus;
4540 Players[(int)pnum].KillGoalCount+=bonus;
4542 team_kills[get_team(pnum)]%=1000;
4543 Players[(int)pnum].net_kills_total%=1000;
4544 Players[(int)pnum].KillGoalCount%=1000;
4546 if (Netgame.KillGoal>0)
4548 TheGoal=Netgame.KillGoal*5;
4550 if (Players[(int)pnum].KillGoalCount>=TheGoal)
4552 if (pnum==Player_num)
4554 HUD_init_message("You reached the kill goal!");
4555 Players[Player_num].shields=i2f(200);
4558 HUD_init_message ("%s has reached the kill goal!",Players[(int)pnum].callsign);
4560 HUD_init_message ("The control center has been destroyed!");
4561 net_destroy_controlcen (obj_find_first_of_type (OBJ_CNTRLCEN));
4564 multi_sort_kill_list();
4565 multi_show_player_list();
4568 void multi_send_got_flag (char pnum)
4570 multibuf[0]=MULTI_GOT_FLAG;
4573 digi_start_sound_queued (SOUND_HUD_YOU_GOT_FLAG,F1_0*2);
4575 multi_send_data (multibuf,2,1);
4576 multi_send_flags (Player_num);
4580 digi_sound ReversedSound;
4582 void multi_send_got_orb (char pnum)
4584 multibuf[0]=MULTI_GOT_ORB;
4587 digi_play_sample (SOUND_YOU_GOT_ORB,F1_0*2);
4589 multi_send_data (multibuf,2,1);
4590 multi_send_flags (Player_num);
4593 void multi_do_got_flag (char *buf)
4597 if (pnum==Player_num)
4598 digi_start_sound_queued (SOUND_HUD_YOU_GOT_FLAG,F1_0*2);
4599 else if (get_team(pnum)==TEAM_RED)
4600 digi_start_sound_queued (SOUND_HUD_RED_GOT_FLAG,F1_0*2);
4602 digi_start_sound_queued (SOUND_HUD_BLUE_GOT_FLAG,F1_0*2);
4603 Players[(int)pnum].flags|=PLAYER_FLAGS_FLAG;
4604 HUD_init_message ("%s picked up a flag!",Players[(int)pnum].callsign);
4606 void multi_do_got_orb (char *buf)
4610 Assert (Game_mode & GM_HOARD);
4612 if (Game_mode & GM_TEAM)
4614 if (get_team(pnum)==get_team(Player_num))
4615 digi_play_sample (SOUND_FRIEND_GOT_ORB,F1_0*2);
4617 digi_play_sample (SOUND_OPPONENT_GOT_ORB,F1_0*2);
4620 digi_play_sample (SOUND_OPPONENT_GOT_ORB,F1_0*2);
4622 Players[(int)pnum].flags|=PLAYER_FLAGS_FLAG;
4623 HUD_init_message ("%s picked up an orb!",Players[(int)pnum].callsign);
4631 if (!(Game_mode & GM_HOARD))
4632 Int3(); // How did we get here? Get Leighton!
4634 if (!Players[Player_num].secondary_ammo[PROXIMITY_INDEX])
4636 HUD_init_message("No orbs to drop!");
4642 objnum = spit_powerup(ConsoleObject,POW_HOARD_ORB,seed);
4647 HUD_init_message("Orb dropped!");
4648 digi_play_sample (SOUND_DROP_WEAPON,F1_0);
4650 if ((Game_mode & GM_HOARD) && objnum>-1)
4651 multi_send_drop_flag(objnum,seed);
4653 Players[Player_num].secondary_ammo[PROXIMITY_INDEX]--;
4655 // If empty, tell everyone to stop drawing the box around me
4656 if (Players[Player_num].secondary_ammo[PROXIMITY_INDEX]==0)
4657 multi_send_flags (Player_num);
4664 if (!(Game_mode & GM_CAPTURE) && !(Game_mode & GM_HOARD))
4666 if (Game_mode & GM_HOARD)
4672 if (!(Players[Player_num].flags & PLAYER_FLAGS_FLAG))
4674 HUD_init_message("No flag to drop!");
4679 HUD_init_message("Flag dropped!");
4680 digi_play_sample (SOUND_DROP_WEAPON,F1_0);
4684 if (get_team (Player_num)==TEAM_RED)
4685 objnum = spit_powerup(ConsoleObject,POW_FLAG_BLUE,seed);
4687 objnum = spit_powerup(ConsoleObject,POW_FLAG_RED,seed);
4692 if ((Game_mode & GM_CAPTURE) && objnum>-1)
4693 multi_send_drop_flag(objnum,seed);
4695 Players[Player_num].flags &=~(PLAYER_FLAGS_FLAG);
4699 void multi_send_drop_flag (int objnum,int seed)
4704 objp = &Objects[objnum];
4706 multibuf[count++]=(char)MULTI_DROP_FLAG;
4707 multibuf[count++]=(char)objp->id;
4709 *(short *) (multibuf+count)=INTEL_SHORT(Player_num); count += 2;
4710 *(short *) (multibuf+count)=INTEL_SHORT(objnum); count += 2;
4711 *(short *) (multibuf+count)=INTEL_SHORT(objp->ctype.powerup_info.count); count += 2;
4712 *(int *) (multibuf+count)=INTEL_INT(seed);
4714 map_objnum_local_to_local(objnum);
4716 if (!(Game_mode & GM_HOARD))
4717 if (Game_mode & GM_NETWORK)
4718 PowerupsInMine[objp->id]++;
4720 multi_send_data(multibuf, 12, 2);
4723 void multi_do_drop_flag (char *buf)
4725 int pnum,ammo,objnum,remote_objnum,seed;
4730 pnum=INTEL_SHORT( *(short *)(buf+2) );
4731 remote_objnum=INTEL_SHORT( *(short *)(buf+4) );
4732 ammo=INTEL_SHORT( *(short *)(buf+6) );
4733 seed=INTEL_INT( *(int *)(buf+8) );
4735 objp = &Objects[Players[pnum].objnum];
4737 objnum = spit_powerup(objp, powerup_id, seed);
4739 map_objnum_local_to_remote(objnum, remote_objnum, pnum);
4742 Objects[objnum].ctype.powerup_info.count = ammo;
4744 if (!(Game_mode & GM_HOARD))
4746 if (Game_mode & GM_NETWORK)
4747 PowerupsInMine[powerup_id]++;
4748 Players[pnum].flags &= ~(PLAYER_FLAGS_FLAG);
4750 mprintf ((0,"Dropped flag %d!\n"));
4754 void multi_bad_restore ()
4756 Function_mode = FMODE_MENU;
4757 nm_messagebox(NULL, 1, TXT_OK,
4758 "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.");
4759 Function_mode = FMODE_GAME;
4760 multi_quit_game = 1;
4761 multi_leave_menu = 1;
4762 multi_reset_stuff();
4765 extern int robot_controlled[MAX_ROBOTS_CONTROLLED];
4766 extern int robot_agitation[MAX_ROBOTS_CONTROLLED];
4767 extern fix robot_controlled_time[MAX_ROBOTS_CONTROLLED];
4768 extern fix robot_last_send_time[MAX_ROBOTS_CONTROLLED];
4769 extern fix robot_last_message_time[MAX_ROBOTS_CONTROLLED];
4770 extern int robot_send_pending[MAX_ROBOTS_CONTROLLED];
4771 extern int robot_fired[MAX_ROBOTS_CONTROLLED];
4772 extern byte robot_fire_buf[MAX_ROBOTS_CONTROLLED][18+3];
4775 void multi_send_robot_controls (char pnum)
4779 mprintf ((0,"Sending ROBOT_CONTROLS!!!\n"));
4781 multibuf[0]=MULTI_ROBOT_CONTROLS;
4783 memcpy (&(multibuf[count]),&robot_controlled,MAX_ROBOTS_CONTROLLED*4);
4784 count+=(MAX_ROBOTS_CONTROLLED*4);
4785 memcpy (&(multibuf[count]),&robot_agitation,MAX_ROBOTS_CONTROLLED*4);
4786 count+=(MAX_ROBOTS_CONTROLLED*4);
4787 memcpy (&(multibuf[count]),&robot_controlled_time,MAX_ROBOTS_CONTROLLED*4);
4788 count+=(MAX_ROBOTS_CONTROLLED*4);
4789 memcpy (&(multibuf[count]),&robot_last_send_time,MAX_ROBOTS_CONTROLLED*4);
4790 count+=(MAX_ROBOTS_CONTROLLED*4);
4791 memcpy (&(multibuf[count]),&robot_last_message_time,MAX_ROBOTS_CONTROLLED*4);
4792 count+=(MAX_ROBOTS_CONTROLLED*4);
4793 memcpy (&(multibuf[count]),&robot_send_pending,MAX_ROBOTS_CONTROLLED*4);
4794 count+=(MAX_ROBOTS_CONTROLLED*4);
4795 memcpy (&(multibuf[count]),&robot_fired,MAX_ROBOTS_CONTROLLED*4);
4796 count+=(MAX_ROBOTS_CONTROLLED*4);
4798 network_send_naked_packet (multibuf,142,pnum);
4800 void multi_do_robot_controls(char *buf)
4804 mprintf ((0,"Recieved ROBOT_CONTROLS!!!\n"));
4806 if (buf[1]!=Player_num)
4808 Int3(); // Get Jason! Recieved a coop_sync that wasn't ours!
4812 memcpy (&robot_controlled,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
4813 count+=(MAX_ROBOTS_CONTROLLED*4);
4814 memcpy (&robot_agitation,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
4815 count+=(MAX_ROBOTS_CONTROLLED*4);
4816 memcpy (&robot_controlled_time,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
4817 count+=(MAX_ROBOTS_CONTROLLED*4);
4818 memcpy (&robot_last_send_time,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
4819 count+=(MAX_ROBOTS_CONTROLLED*4);
4820 memcpy (&robot_last_message_time,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
4821 count+=(MAX_ROBOTS_CONTROLLED*4);
4822 memcpy (&robot_send_pending,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
4823 count+=(MAX_ROBOTS_CONTROLLED*4);
4824 memcpy (&robot_fired,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
4825 count+=(MAX_ROBOTS_CONTROLLED*4);
4828 #define POWERUPADJUSTS 5
4829 int PowerupAdjustMapping[]={11,19,39,41,44};
4831 int multi_powerup_is_4pack (int id)
4835 for (i=0;i<POWERUPADJUSTS;i++)
4836 if (id==PowerupAdjustMapping[i])
4841 int multi_powerup_is_allowed(int id)
4843 if (id == POW_INVULNERABILITY && !Netgame.DoInvulnerability)
4845 if (id == POW_CLOAK && !Netgame.DoCloak)
4847 if (id == POW_AFTERBURNER && !Netgame.DoAfterburner)
4849 if (id == POW_FUSION_WEAPON && !Netgame.DoFusions)
4851 if (id == POW_PHOENIX_WEAPON && !Netgame.DoPhoenix)
4853 if (id == POW_HELIX_WEAPON && !Netgame.DoHelix)
4855 if (id == POW_MEGA_WEAPON && !Netgame.DoMegas)
4857 if (id == POW_SMARTBOMB_WEAPON && !Netgame.DoSmarts)
4859 if (id == POW_GAUSS_WEAPON && !Netgame.DoGauss)
4861 if (id == POW_VULCAN_WEAPON && !Netgame.DoVulcan)
4863 if (id == POW_PLASMA_WEAPON && !Netgame.DoPlasma)
4865 if (id == POW_OMEGA_WEAPON && !Netgame.DoOmega)
4867 if (id == POW_SUPER_LASER && !Netgame.DoSuperLaser)
4869 if (id == POW_PROXIMITY_WEAPON && !Netgame.DoProximity)
4871 if (id==POW_VULCAN_AMMO && (!Netgame.DoVulcan && !Netgame.DoGauss))
4873 if (id == POW_SPREADFIRE_WEAPON && !Netgame.DoSpread)
4875 if (id == POW_SMART_MINE && !Netgame.DoSmartMine)
4877 if (id == POW_SMISSILE1_1 && !Netgame.DoFlash)
4879 if (id == POW_SMISSILE1_4 && !Netgame.DoFlash)
4881 if (id == POW_GUIDED_MISSILE_1 && !Netgame.DoGuided)
4883 if (id == POW_GUIDED_MISSILE_4 && !Netgame.DoGuided)
4885 if (id == POW_EARTHSHAKER_MISSILE && !Netgame.DoEarthShaker)
4887 if (id == POW_MERCURY_MISSILE_1 && !Netgame.DoMercury)
4889 if (id == POW_MERCURY_MISSILE_4 && !Netgame.DoMercury)
4891 if (id == POW_CONVERTER && !Netgame.DoConverter)
4893 if (id == POW_AMMO_RACK && !Netgame.DoAmmoRack)
4895 if (id == POW_HEADLIGHT && !Netgame.DoHeadlight)
4897 if (id == POW_LASER && !Netgame.DoLaserUpgrade)
4899 if (id == POW_HOMING_AMMO_1 && !Netgame.DoHoming)
4901 if (id == POW_HOMING_AMMO_4 && !Netgame.DoHoming)
4903 if (id == POW_QUAD_FIRE && !Netgame.DoQuadLasers)
4905 if (id == POW_FLAG_BLUE && !(Game_mode & GM_CAPTURE))
4907 if (id == POW_FLAG_RED && !(Game_mode & GM_CAPTURE))
4913 void multi_send_finish_game ()
4915 multibuf[0]=MULTI_FINISH_GAME;
4916 multibuf[1]=Player_num;
4918 multi_send_data (multibuf,2,1);
4922 extern void do_final_boss_hacks();
4923 void multi_do_finish_game (char *buf)
4925 if (buf[0]!=MULTI_FINISH_GAME)
4928 if (Current_level_num!=Last_level)
4931 do_final_boss_hacks();
4934 void multi_send_trigger_specific (char pnum,char trig)
4936 multibuf[0] = MULTI_START_TRIGGER;
4939 network_send_naked_packet(multibuf, 2, pnum);
4941 void multi_do_start_trigger (char *buf)
4943 Triggers[(int)buf[1]].flags |=TF_DISABLED;
4946 extern char *RankStrings[];
4948 void multi_add_lifetime_kills ()
4950 // This function adds a kill to lifetime stats of this player, and possibly
4951 // gives a promotion. If so, it will tell everyone else
4955 if (!Game_mode & GM_NETWORK)
4958 oldrank=GetMyNetRanking();
4962 if (oldrank!=GetMyNetRanking())
4964 multi_send_ranking();
4965 if (!FindArg("-norankings"))
4967 HUD_init_message ("You have been promoted to %s!",RankStrings[GetMyNetRanking()]);
4968 digi_play_sample (SOUND_BUDDY_MET_GOAL,F1_0*2);
4969 NetPlayers.players[Player_num].rank=GetMyNetRanking();
4972 write_player_file();
4975 void multi_add_lifetime_killed ()
4977 // This function adds a "killed" to lifetime stats of this player, and possibly
4978 // gives a demotion. If so, it will tell everyone else
4982 if (!Game_mode & GM_NETWORK)
4985 oldrank=GetMyNetRanking();
4989 if (oldrank!=GetMyNetRanking())
4991 multi_send_ranking();
4992 NetPlayers.players[Player_num].rank=GetMyNetRanking();
4994 if (!FindArg("-norankings"))
4995 HUD_init_message ("You have been demoted to %s!",RankStrings[GetMyNetRanking()]);
4998 write_player_file();
5002 void multi_send_ranking ()
5004 multibuf[0]=(char)MULTI_RANK;
5005 multibuf[1]=(char)Player_num;
5006 multibuf[2]=(char)GetMyNetRanking();
5008 multi_send_data (multibuf,3,1);
5011 void multi_do_ranking (char *buf)
5017 if (NetPlayers.players[(int)pnum].rank<rank)
5018 strcpy (rankstr,"promoted");
5019 else if (NetPlayers.players[(int)pnum].rank>rank)
5020 strcpy (rankstr,"demoted");
5024 NetPlayers.players[(int)pnum].rank=rank;
5026 if (!FindArg("-norankings"))
5027 HUD_init_message ("%s has been %s to %s!",Players[(int)pnum].callsign,rankstr,RankStrings[(int)rank]);
5029 void multi_send_modem_ping ()
5031 multibuf[0]=MULTI_MODEM_PING;
5032 multi_send_data (multibuf,1,1);
5034 void multi_send_modem_ping_return ()
5036 multibuf[0]=MULTI_MODEM_PING_RETURN;
5037 multi_send_data (multibuf,1,1);
5040 void multi_do_modem_ping_return ()
5042 if (PingLaunchTime==0)
5044 mprintf ((0,"Got invalid PING RETURN from opponent!\n"));
5048 PingReturnTime=timer_get_fixed_seconds();
5050 HUD_init_message ("Ping time for opponent is %d ms!",f2i(fixmul(PingReturnTime-PingLaunchTime,i2f(1000))));
5055 void multi_quick_sound_hack (int num)
5058 num = digi_xlat_sound(num);
5059 length=GameSounds[num].length;
5060 ReversedSound.data=(ubyte *)d_malloc (length);
5061 ReversedSound.length=length;
5063 for (i=0;i<length;i++)
5064 ReversedSound.data[i]=GameSounds[num].data[length-i-1];
5069 void multi_send_play_by_play (int num,int spnum,int dpnum)
5071 if (!(Game_mode & GM_HOARD))
5075 multibuf[0]=MULTI_PLAY_BY_PLAY;
5076 multibuf[1]=(char)num;
5077 multibuf[2]=(char)spnum;
5078 multibuf[3]=(char)dpnum;
5079 multi_send_data (multibuf,4,1);
5080 multi_do_play_by_play (multibuf);
5082 void multi_do_play_by_play (char *buf)
5084 int whichplay=buf[1];
5088 if (!(Game_mode & GM_HOARD))
5090 Int3(); // Get Leighton, something bad has happened.
5097 HUD_init_message ("Ouch! %s has been smacked by %s!",Players[dpnum].callsign,Players[spnum].callsign);
5100 HUD_init_message ("Haha! %s has been spanked by %s!",Players[dpnum].callsign,Players[spnum].callsign);
5108 /// CODE TO LOAD HOARD DATA
5112 void init_bitmap(grs_bitmap *bm,int w,int h,int flags,ubyte *data)
5114 bm->bm_x = bm->bm_y = 0;
5115 bm->bm_w = bm->bm_rowsize = w;
5117 bm->bm_type = BM_LINEAR;
5118 bm->bm_flags = flags;
5124 grs_bitmap Orb_icons[2];
5126 int Hoard_goal_eclip;
5128 void init_hoard_data()
5130 static int first_time=1;
5131 static int orb_vclip;
5132 int n_orb_frames,n_goal_frames;
5135 ubyte palette[256*3];
5138 extern int Num_bitmap_files,Num_effects,Num_sound_files;
5140 ifile = cfopen("hoard.ham","rb");
5142 Error("can't open <hoard.dat>");
5144 n_orb_frames = cfile_read_short(ifile);
5145 orb_w = cfile_read_short(ifile);
5146 orb_h = cfile_read_short(ifile);
5147 save_pos = cftell(ifile);
5148 cfseek(ifile,sizeof(palette)+n_orb_frames*orb_w*orb_h,SEEK_CUR);
5149 n_goal_frames = cfile_read_short(ifile);
5150 cfseek(ifile,save_pos,SEEK_SET);
5154 int bitmap_num=Num_bitmap_files;
5156 //Allocate memory for bitmaps
5157 MALLOC( bitmap_data, ubyte, n_orb_frames*orb_w*orb_h + n_goal_frames*64*64 );
5160 orb_vclip = Num_vclips++;
5161 Assert(Num_vclips <= VCLIP_MAXNUM);
5162 Vclip[orb_vclip].play_time = F1_0/2;
5163 Vclip[orb_vclip].num_frames = n_orb_frames;
5164 Vclip[orb_vclip].frame_time = Vclip[orb_vclip].play_time / Vclip[orb_vclip].num_frames;
5165 Vclip[orb_vclip].flags = 0;
5166 Vclip[orb_vclip].sound_num = -1;
5167 Vclip[orb_vclip].light_value = F1_0;
5168 for (i=0;i<n_orb_frames;i++) {
5169 Vclip[orb_vclip].frames[i].index = bitmap_num;
5170 init_bitmap(&GameBitmaps[bitmap_num],orb_w,orb_h,BM_FLAG_TRANSPARENT,bitmap_data);
5171 bitmap_data += orb_w*orb_h;
5173 Assert(bitmap_num < MAX_BITMAP_FILES);
5176 //Create obj powerup
5177 Powerup_info[POW_HOARD_ORB].vclip_num = orb_vclip;
5178 Powerup_info[POW_HOARD_ORB].hit_sound = -1; //Powerup_info[POW_SHIELD_BOOST].hit_sound;
5179 Powerup_info[POW_HOARD_ORB].size = Powerup_info[POW_SHIELD_BOOST].size;
5180 Powerup_info[POW_HOARD_ORB].light = Powerup_info[POW_SHIELD_BOOST].light;
5182 //Create orb goal wall effect
5183 Hoard_goal_eclip = Num_effects++;
5184 Assert(Num_effects < MAX_EFFECTS);
5185 Effects[Hoard_goal_eclip] = Effects[94]; //copy from blue goal
5186 Effects[Hoard_goal_eclip].changing_wall_texture = NumTextures;
5187 Effects[Hoard_goal_eclip].vc.num_frames=n_goal_frames;
5189 TmapInfo[NumTextures] = TmapInfo[find_goal_texture(TMI_GOAL_BLUE)];
5190 TmapInfo[NumTextures].eclip_num = Hoard_goal_eclip;
5191 TmapInfo[NumTextures].flags = TMI_GOAL_HOARD;
5193 Assert(NumTextures < MAX_TEXTURES);
5194 for (i=0;i<n_goal_frames;i++) {
5195 Effects[Hoard_goal_eclip].vc.frames[i].index = bitmap_num;
5196 init_bitmap(&GameBitmaps[bitmap_num],64,64,0,bitmap_data);
5197 bitmap_data += 64*64;
5199 Assert(bitmap_num < MAX_BITMAP_FILES);
5204 //Load and remap bitmap data for orb
5205 cfread(palette,3,256,ifile);
5206 for (i=0;i<n_orb_frames;i++) {
5207 grs_bitmap *bm = &GameBitmaps[Vclip[orb_vclip].frames[i].index];
5208 cfread(bm->bm_data,1,orb_w*orb_h,ifile);
5209 gr_remap_bitmap_good( bm, palette, 255, -1 );
5212 //Load and remap bitmap data for goal texture
5213 cfile_read_short(ifile); //skip frame count
5214 cfread(palette,3,256,ifile);
5215 for (i=0;i<n_goal_frames;i++) {
5216 grs_bitmap *bm = &GameBitmaps[Effects[Hoard_goal_eclip].vc.frames[i].index];
5217 cfread(bm->bm_data,1,64*64,ifile);
5218 gr_remap_bitmap_good( bm, palette, 255, -1 );
5221 //Load and remap bitmap data for HUD icons
5223 icon_w = cfile_read_short(ifile);
5224 icon_h = cfile_read_short(ifile);
5227 MALLOC( bitmap_data, ubyte, icon_w*icon_h );
5228 init_bitmap(&Orb_icons[i],icon_w,icon_h,BM_FLAG_TRANSPARENT,bitmap_data);
5230 cfread(palette,3,256,ifile);
5231 cfread(Orb_icons[i].bm_data,1,icon_w*icon_h,ifile);
5232 gr_remap_bitmap_good( &Orb_icons[i], palette, 255, -1 );
5237 //Load sounds for orb game
5242 len = cfile_read_int(ifile); //get 11k len
5244 if (digi_sample_rate == SAMPLE_RATE_22K) {
5245 cfseek(ifile,len,SEEK_CUR); //skip over 11k sample
5246 len = cfile_read_int(ifile); //get 22k len
5249 GameSounds[Num_sound_files+i].length = len;
5250 GameSounds[Num_sound_files+i].data = d_malloc(len);
5251 cfread(GameSounds[Num_sound_files+i].data,1,len,ifile);
5253 if (digi_sample_rate == SAMPLE_RATE_11K) {
5254 len = cfile_read_int(ifile); //get 22k len
5255 cfseek(ifile,len,SEEK_CUR); //skip over 22k sample
5258 Sounds[SOUND_YOU_GOT_ORB+i] = Num_sound_files+i;
5259 AltSounds[SOUND_YOU_GOT_ORB+i] = Sounds[SOUND_YOU_GOT_ORB+i];
5269 multi_process_data(char *buf, int len)
5271 // Take an entire message (that has already been checked for validity,
5272 // if necessary) and act on it.
5279 if (type > MULTI_MAX_TYPE)
5281 mprintf((1, "multi_process_data: invalid type %d.\n", type));
5289 fprintf (RecieveLogFile,"Packet type: %d Len:%d TT=%d\n",type,len,TTRecv[type]);
5290 fflush (RecieveLogFile);
5295 case MULTI_POSITION:
5296 if (!Endlevel_sequence) multi_do_position(buf); break;
5297 case MULTI_REAPPEAR:
5298 if (!Endlevel_sequence) multi_do_reappear(buf); break;
5300 if (!Endlevel_sequence) multi_do_fire(buf); break;
5302 multi_do_kill(buf); break;
5303 case MULTI_REMOVE_OBJECT:
5304 if (!Endlevel_sequence) multi_do_remobj(buf); break;
5305 case MULTI_PLAYER_DROP:
5306 case MULTI_PLAYER_EXPLODE:
5307 if (!Endlevel_sequence) multi_do_player_explode(buf); break;
5309 if (!Endlevel_sequence) multi_do_message(buf); break;
5311 if (!Endlevel_sequence) multi_do_quit(buf); break;
5312 case MULTI_BEGIN_SYNC:
5314 case MULTI_CONTROLCEN:
5315 if (!Endlevel_sequence) multi_do_controlcen_destroy(buf); break;
5316 case MULTI_POWERUP_UPDATE:
5317 if (!Endlevel_sequence) multi_do_powerup_update(buf); break;
5318 case MULTI_SOUND_FUNCTION:
5319 multi_do_sound_function(buf); break;
5321 if (!Endlevel_sequence) multi_do_drop_marker (buf); break;
5322 case MULTI_DROP_WEAPON:
5323 if (!Endlevel_sequence) multi_do_drop_weapon(buf); break;
5324 case MULTI_DROP_FLAG:
5325 if (!Endlevel_sequence) multi_do_drop_flag(buf); break;
5327 if (!Endlevel_sequence) multi_do_guided (buf); break;
5328 case MULTI_STOLEN_ITEMS:
5329 if (!Endlevel_sequence) multi_do_stolen_items(buf); break;
5330 case MULTI_WALL_STATUS:
5331 if (!Endlevel_sequence) multi_do_wall_status(buf); break;
5332 case MULTI_HEARTBEAT:
5333 if (!Endlevel_sequence) multi_do_heartbeat (buf); break;
5335 if (!Endlevel_sequence) multi_do_seismic (buf); break;
5337 if (!Endlevel_sequence) multi_do_light (buf); break;
5338 case MULTI_KILLGOALS:
5340 if (!Endlevel_sequence) multi_do_kill_goal_counts (buf); break;
5341 case MULTI_ENDLEVEL_START:
5342 if (!Endlevel_sequence) multi_do_escape(buf); break;
5343 case MULTI_END_SYNC:
5346 if (!Endlevel_sequence) multi_do_cloak(buf); break;
5348 if (!Endlevel_sequence) multi_do_decloak(buf); break;
5349 case MULTI_DOOR_OPEN:
5350 if (!Endlevel_sequence) multi_do_door_open(buf); break;
5351 case MULTI_CREATE_EXPLOSION:
5352 if (!Endlevel_sequence) multi_do_create_explosion(buf); break;
5353 case MULTI_CONTROLCEN_FIRE:
5354 if (!Endlevel_sequence) multi_do_controlcen_fire(buf); break;
5355 case MULTI_CREATE_POWERUP:
5356 if (!Endlevel_sequence) multi_do_create_powerup(buf); break;
5357 case MULTI_PLAY_SOUND:
5358 if (!Endlevel_sequence) multi_do_play_sound(buf); break;
5359 case MULTI_CAPTURE_BONUS:
5360 if (!Endlevel_sequence) multi_do_capture_bonus(buf); break;
5361 case MULTI_ORB_BONUS:
5362 if (!Endlevel_sequence) multi_do_orb_bonus(buf); break;
5363 case MULTI_GOT_FLAG:
5364 if (!Endlevel_sequence) multi_do_got_flag(buf); break;
5366 if (!Endlevel_sequence) multi_do_got_orb(buf); break;
5367 case MULTI_PLAY_BY_PLAY:
5368 if (!Endlevel_sequence) multi_do_play_by_play(buf); break;
5370 if (!Endlevel_sequence) multi_do_ranking (buf); break;
5371 case MULTI_MODEM_PING:
5372 if (!Endlevel_sequence) multi_send_modem_ping_return(); break;
5373 case MULTI_MODEM_PING_RETURN:
5374 if (!Endlevel_sequence) multi_do_modem_ping_return(); break;
5376 case MULTI_FINISH_GAME:
5377 multi_do_finish_game(buf); break; // do this one regardless of endsequence
5378 case MULTI_ROBOT_CONTROLS:
5379 if (!Endlevel_sequence) multi_do_robot_controls(buf); break;
5380 case MULTI_ROBOT_CLAIM:
5381 if (!Endlevel_sequence) multi_do_claim_robot(buf); break;
5382 case MULTI_ROBOT_POSITION:
5383 if (!Endlevel_sequence) multi_do_robot_position(buf); break;
5384 case MULTI_ROBOT_EXPLODE:
5385 if (!Endlevel_sequence) multi_do_robot_explode(buf); break;
5386 case MULTI_ROBOT_RELEASE:
5387 if (!Endlevel_sequence) multi_do_release_robot(buf); break;
5388 case MULTI_ROBOT_FIRE:
5389 if (!Endlevel_sequence) multi_do_robot_fire(buf); break;
5392 if (!Endlevel_sequence) multi_do_score(buf); break;
5393 case MULTI_CREATE_ROBOT:
5394 if (!Endlevel_sequence) multi_do_create_robot(buf); break;
5396 if (!Endlevel_sequence) multi_do_trigger(buf); break;
5397 case MULTI_START_TRIGGER:
5398 if (!Endlevel_sequence) multi_do_start_trigger(buf); break;
5400 if (!Endlevel_sequence) multi_do_flags(buf); break;
5401 case MULTI_DROP_BLOB:
5402 if (!Endlevel_sequence) multi_do_drop_blob(buf); break;
5403 case MULTI_ACTIVE_DOOR:
5404 if (!Endlevel_sequence) multi_do_active_door(buf); break;
5405 case MULTI_BOSS_ACTIONS:
5406 if (!Endlevel_sequence) multi_do_boss_actions(buf); break;
5407 case MULTI_CREATE_ROBOT_POWERUPS:
5408 if (!Endlevel_sequence) multi_do_create_robot_powerups(buf); break;
5409 case MULTI_HOSTAGE_DOOR:
5410 if (!Endlevel_sequence) multi_do_hostage_door_status(buf); break;
5411 case MULTI_SAVE_GAME:
5412 if (!Endlevel_sequence) multi_do_save_game(buf); break;
5413 case MULTI_RESTORE_GAME:
5414 if (!Endlevel_sequence) multi_do_restore_game(buf); break;
5415 case MULTI_REQ_PLAYER:
5416 if (!Endlevel_sequence) multi_do_req_player(buf); break;
5417 case MULTI_SEND_PLAYER:
5418 if (!Endlevel_sequence) multi_do_send_player(buf); break;
5421 mprintf((1, "Invalid type in multi_process_input().\n"));