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.
70 void multi_reset_player_object(object *objp);
71 void multi_reset_object_texture (object *objp);
72 void multi_add_lifetime_killed ();
73 void multi_add_lifetime_kills ();
74 void multi_send_play_by_play (int num,int spnum,int dpnum);
75 void multi_send_heartbeat ();
76 void multi_send_modem_ping ();
77 void multi_cap_objects ();
78 void multi_adjust_remote_cap (int pnum);
79 void multi_save_game(ubyte slot, uint id, char *desc);
80 void multi_restore_game(ubyte slot, uint id);
81 void multi_set_robot_ai(void);
82 void multi_send_powerup_update ();
83 void bash_to_shield (int i,char *s);
84 void init_hoard_data();
85 void multi_apply_goal_textures();
86 int find_goal_texture (ubyte t);
87 void multi_bad_restore ();
88 void multi_do_capture_bonus(char *buf);
89 void multi_do_orb_bonus(char *buf);
90 void multi_send_drop_flag (int objnum,int seed);
91 void multi_send_ranking ();
92 void multi_do_play_by_play (char *buf);
95 // Local macros and prototypes
100 #define vm_angvec_zero(v) (v)->p=(v)->b=(v)->h=0
102 void reset_player_object(void); // In object.c but not in object.h
103 void drop_player_eggs(object *player); // from collide.c
104 void GameLoop(int, int); // From game.c
110 extern vms_vector MarkerPoint[];
111 extern char MarkerMessage[16][40];
112 extern char MarkerOwner[16][40];
113 extern int MarkerObject[];
115 int control_invul_time = 0;
116 int who_killed_controlcen = -1; // -1 = noone
118 //do we draw the kill list on the HUD?
119 int Show_kill_list = 1;
120 int Show_reticle_name = 1;
121 fix Show_kill_list_timer = 0;
123 char Multi_is_guided=0;
124 char PKilledFlags[MAX_NUM_NET_PLAYERS];
126 int multi_sending_message = 0;
127 int multi_defining_message = 0;
128 int multi_message_index = 0;
130 char multibuf[MAX_MULTI_MESSAGE_LEN+4]; // This is where multiplayer message are built
132 short remote_to_local[MAX_NUM_NET_PLAYERS][MAX_OBJECTS]; // Remote object number for each local object
133 short local_to_remote[MAX_OBJECTS];
134 byte object_owner[MAX_OBJECTS]; // Who created each object in my universe, -1 = loaded at start
136 int Net_create_objnums[MAX_NET_CREATE_OBJECTS]; // For tracking object creation that will be sent to remote
137 int Net_create_loc = 0; // pointer into previous array
138 int Network_laser_fired = 0; // How many times we shot
139 int Network_laser_gun; // Which gun number we shot
140 int Network_laser_flags; // Special flags for the shot
141 int Network_laser_level; // What level
142 short Network_laser_track; // Who is it tracking?
143 char Network_message[MAX_MESSAGE_LEN];
144 char Network_message_macro[4][MAX_MESSAGE_LEN];
145 int Network_message_reciever=-1;
146 int sorted_kills[MAX_NUM_NET_PLAYERS];
147 short kill_matrix[MAX_NUM_NET_PLAYERS][MAX_NUM_NET_PLAYERS];
148 int multi_goto_secret = 0;
150 int multi_in_menu = 0;
151 int multi_leave_menu = 0;
152 int multi_quit_game = 0;
154 netgame_info Netgame;
155 AllNetPlayers_info NetPlayers;
157 bitmap_index multi_player_textures[MAX_NUM_NET_PLAYERS][N_PLAYER_SHIP_TEXTURES];
159 typedef struct netplayer_stats {
161 ubyte Player_num; // Who am i?
162 uint flags; // Powerup flags, see below...
163 fix energy; // Amount of energy remaining.
164 fix shields; // shields remaining (protection)
165 ubyte lives; // Lives remaining, 0 = game over.
166 ubyte laser_level; // Current level of the laser.
167 ubyte primary_weapon_flags; // bit set indicates the player has this weapon.
168 ubyte secondary_weapon_flags; // bit set indicates the player has this weapon.
169 ushort primary_ammo[MAX_PRIMARY_WEAPONS]; // How much ammo of each type.
170 ushort secondary_ammo[MAX_SECONDARY_WEAPONS]; // How much ammo of each type.
171 int last_score; // Score at beginning of current level.
172 int score; // Current score.
173 fix cloak_time; // Time cloaked
174 fix invulnerable_time; // Time invulnerable
175 fix homing_object_dist; // Distance of nearest homing object.
177 short net_killed_total; // Number of times killed total
178 short net_kills_total; // Number of net kills total
179 short num_kills_level; // Number of kills this level
180 short num_kills_total; // Number of kills total
181 short num_robots_level; // Number of initial robots this level
182 short num_robots_total; // Number of robots total
183 ushort hostages_rescued_total; // Total number of hostages rescued.
184 ushort hostages_total; // Total number of hostages.
185 ubyte hostages_on_board; // Number of hostages on ship.
189 int message_length[MULTI_MAX_TYPE+1] = {
195 97+9, // PLAYER_EXPLODE
196 37, // MESSAGE (MAX_MESSAGE_LENGTH = 40)
206 2, // CREATE_EXPLOSION
207 16, // CONTROLCEN_FIRE
209 19, // CREATE_POWERUP
213 28, // ROBOT_POSITION (shortpos_length (23) + 5 = 28)
221 27, // ROBOT_POWERUPS
223 2+24, //SAVE_GAME (ubyte slot, uint id, char name[20])
224 2+4, //RESTORE_GAME (ubyte slot, uint id)
225 1+1, // MULTI_REQ_PLAYER
226 sizeof(netplayer_stats), // MULTI_SEND_PLAYER
228 12, // MULTI_DROP_WEAPON
230 3+sizeof(shortpos), // MULTI_GUIDED, IF SHORTPOS CHANGES, CHANGE MAC VALUE BELOW
232 26, //MULTI_GUIDED IF SIZE OF SHORTPOS CHANGES, CHANGE THIS VALUE AS WELL!!!!!!
234 11, // MULTI_STOLEN_ITEMS
235 6, // MULTI_WALL_STATUS
236 5, // MULTI_HEARTBEAT
237 9, // MULTI_KILLGOALS
240 2, // MULTI_START_TRIGGER
242 2, // MULTI_DROP_BLOB
243 MAX_POWERUP_TYPES+1, // MULTI_POWERUP_UPDATE
244 sizeof(active_door)+3, // MULTI_ACTIVE_DOOR
245 4, // MULTI_SOUND_FUNCTION
246 2, // MULTI_CAPTURE_BONUS
248 12, // MULTI_DROP_FLAG
249 142, // MULTI_ROBOT_CONTROLS
250 2, // MULTI_FINISH_GAME
252 1, // MULTI_MODEM_PING
253 1, // MULTI_MODEM_PING_RETURN
254 3, // MULTI_ORB_BONUS
256 12, // MULTI_DROP_ORB
257 4, // MULTI_PLAY_BY_PLAY
260 void extract_netplayer_stats( netplayer_stats *ps, player * pd );
261 void use_netplayer_stats( player * ps, netplayer_stats *pd );
262 char PowerupsInMine[MAX_POWERUP_TYPES],MaxPowerupsAllowed[MAX_POWERUP_TYPES];
263 extern fix ThisLevelTime;
266 // Functions that replace what used to be macros
269 int objnum_remote_to_local(int remote_objnum, int owner)
271 // Map a remote object number from owner to a local object number
275 if ((owner >= N_players) || (owner < -1)) {
277 return(remote_objnum);
281 return(remote_objnum);
283 if ((remote_objnum < 0) || (remote_objnum >= MAX_OBJECTS))
286 result = remote_to_local[owner][remote_objnum];
290 mprintf((1, "Remote object owner %d number %d mapped to -1!\n", owner, remote_objnum));
295 if (object_owner[result] != owner)
297 mprintf((1, "Remote object owner %d number %d doesn't match owner %d.\n", owner, remote_objnum, object_owner[result]));
300 // Assert(object_owner[result] == owner);
305 int objnum_local_to_remote(int local_objnum, byte *owner)
307 // Map a local object number to a remote + owner
311 if ((local_objnum < 0) || (local_objnum > Highest_object_index)) {
316 *owner = object_owner[local_objnum];
319 return(local_objnum);
321 if ((*owner >= N_players) || (*owner < -1)) {
327 result = local_to_remote[local_objnum];
329 // mprintf((0, "Local object %d mapped to owner %d objnum %d.\n", local_objnum,
334 Int3(); // See Rob, object has no remote number!
341 map_objnum_local_to_remote(int local_objnum, int remote_objnum, int owner)
343 // Add a mapping from a network remote object number to a local one
345 Assert(local_objnum > -1);
346 Assert(remote_objnum > -1);
348 Assert(owner != Player_num);
349 Assert(local_objnum < MAX_OBJECTS);
350 Assert(remote_objnum < MAX_OBJECTS);
352 object_owner[local_objnum] = owner;
354 remote_to_local[owner][remote_objnum] = local_objnum;
355 local_to_remote[local_objnum] = remote_objnum;
361 map_objnum_local_to_local(int local_objnum)
363 // Add a mapping for our locally created objects
365 Assert(local_objnum > -1);
366 Assert(local_objnum < MAX_OBJECTS);
368 object_owner[local_objnum] = Player_num;
369 remote_to_local[Player_num][local_objnum] = local_objnum;
370 local_to_remote[local_objnum] = local_objnum;
376 // Part 1 : functions whose main purpose in life is to divert the flow
377 // of execution to either network or serial specific code based
378 // on the curretn Game_mode value.
382 multi_endlevel_score(void)
386 // Show a score list to end of net players
388 // Save connect state and change to new connect state
390 if (Game_mode & GM_NETWORK)
392 old_connect = Players[Player_num].connected;
393 if (Players[Player_num].connected!=3)
394 Players[Player_num].connected = CONNECT_END_MENU;
395 Network_status = NETSTAT_ENDLEVEL;
400 // Do the actual screen we wish to show
402 Function_mode = FMODE_MENU;
404 kmatrix_view(Game_mode & GM_NETWORK);
406 Function_mode = FMODE_GAME;
408 // Restore connect state
410 if (Game_mode & GM_NETWORK)
412 Players[Player_num].connected = old_connect;
416 if (Game_mode & GM_MULTI_COOP)
419 for (i = 0; i < MaxNumNetPlayers; i++)
421 Players[i].flags &= ~(PLAYER_FLAGS_BLUE_KEY | PLAYER_FLAGS_RED_KEY | PLAYER_FLAGS_GOLD_KEY);
423 for (i = 0; i < MaxNumNetPlayers; i++)
424 Players[i].flags &= ~(PLAYER_FLAGS_FLAG); // Clear capture flag
428 for (i=0;i<MAX_PLAYERS;i++)
429 Players[i].KillGoalCount=0;
431 for (i=0;i<MAX_POWERUP_TYPES;i++)
433 MaxPowerupsAllowed[i]=0;
442 if ((Game_mode & GM_CAPTURE) && ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM)))
445 if (Netgame.team_vector & (1 << pnum))
452 multi_choose_mission(int *anarchy_only)
456 char *m[MAX_MISSIONS];
457 int new_mission_num = 0;
461 n_missions = build_mission_list(1);
463 if (n_missions > 1) {
466 for (i=0;i<n_missions;i++) {
467 m[i] = Mission_list[i].mission_name;
468 if ( !stricmp( m[i], config_last_mission ) )
472 ExtGameStatus=GAMESTAT_START_MULTIPLAYER_MISSION;
473 new_mission_num = newmenu_listbox1(TXT_MULTI_MISSION, n_missions, m, 1, default_mission, NULL );
475 if (new_mission_num == -1)
478 strcpy(config_last_mission, m[new_mission_num] );
480 if (!load_mission(new_mission_num)) {
481 nm_messagebox( NULL, 1, TXT_OK, TXT_MISSION_ERROR);
485 *anarchy_only = Mission_list[new_mission_num].anarchy_only_flag;
487 return(new_mission_num);
490 extern void game_disable_cheats();
497 // Reset variables for a new net game
499 memset(kill_matrix, 0, MAX_NUM_NET_PLAYERS*MAX_NUM_NET_PLAYERS*2); // Clear kill matrix
501 for (i = 0; i < MAX_NUM_NET_PLAYERS; i++)
504 Players[i].net_killed_total = 0;
505 Players[i].net_kills_total = 0;
506 Players[i].flags = 0;
507 Players[i].KillGoalCount=0;
511 for (i = 0; i < MAX_ROBOTS_CONTROLLED; i++)
513 robot_controlled[i] = -1;
514 robot_agitation[i] = 0;
519 team_kills[0] = team_kills[1] = 0;
520 Endlevel_sequence = 0;
522 multi_leave_menu = 0;
525 game_disable_cheats();
527 Dead_player_camera = 0;
531 multi_make_player_ghost(int playernum)
535 // Assert(playernum != Player_num);
536 // Assert(playernum < MAX_NUM_NET_PLAYERS);
538 if ((playernum == Player_num) || (playernum >= MAX_NUM_NET_PLAYERS) || (playernum < 0))
540 Int3(); // Non-terminal, see Rob
544 // if (Objects[Players[playernum].objnum].type != OBJ_PLAYER)
545 // mprintf((1, "Warning: Player %d is not currently a player.\n", playernum));
547 obj = &Objects[Players[playernum].objnum];
549 obj->type = OBJ_GHOST;
550 obj->render_type = RT_NONE;
551 obj->movement_type = MT_NONE;
552 multi_reset_player_object(obj);
554 if (Game_mode & GM_MULTI_ROBOTS)
555 multi_strip_robots(playernum);
559 multi_make_ghost_player(int playernum)
563 // Assert(playernum != Player_num);
564 // Assert(playernum < MAX_NUM_NET_PLAYERS);
566 if ((playernum == Player_num) || (playernum >= MAX_NUM_NET_PLAYERS))
568 Int3(); // Non-terminal, see rob
572 // if(Objects[Players[playernum].objnum].type != OBJ_GHOST)
573 // mprintf((1, "Warning: Player %d is not currently a ghost.\n", playernum));
575 obj = &Objects[Players[playernum].objnum];
577 obj->type = OBJ_PLAYER;
578 obj->movement_type = MT_PHYSICS;
579 multi_reset_player_object(obj);
582 int multi_get_kill_list(int *plist)
584 // Returns the number of active net players and their
585 // sorted order of kills
589 for (i = 0; i < N_players; i++)
590 // if (Players[sorted_kills[i]].connected)
591 plist[n++] = sorted_kills[i];
594 Int3(); // SEE ROB OR MATT
596 // memcpy(plist, sorted_kills, N_players*sizeof(int));
602 multi_sort_kill_list(void)
604 // Sort the kills list each time a new kill is added
606 int kills[MAX_NUM_NET_PLAYERS];
610 for (i = 0; i < MAX_NUM_NET_PLAYERS; i++)
613 if (Game_mode & GM_MULTI_COOP)
614 kills[i] = Players[i].score;
617 if (Show_kill_list==2)
619 if (Players[i].net_killed_total+Players[i].net_kills_total==0)
620 kills[i]=-1; // always draw the ones without any ratio last
622 kills[i]=(int)((float)((float)Players[i].net_kills_total/((float)Players[i].net_killed_total+(float)Players[i].net_kills_total))*100.0);
625 kills[i] = Players[i].net_kills_total;
631 for (i = 0; i < N_players-1; i++)
633 if (kills[sorted_kills[i]] < kills[sorted_kills[i+1]])
635 changed = sorted_kills[i];
636 sorted_kills[i] = sorted_kills[i+1];
637 sorted_kills[i+1] = changed;
642 mprintf((0, "Sorted kills %d %d.\n", sorted_kills[0], sorted_kills[1]));
645 extern object *obj_find_first_of_type (int);
646 char Multi_killed_yourself=0;
648 void multi_compute_kill(int killer, int killed)
650 // Figure out the results of a network kills and add it to the
651 // appropriate player's tally.
653 int killed_pnum, killed_type;
654 int killer_pnum, killer_type,killer_id;
656 char killed_name[(CALLSIGN_LEN*2)+4];
657 char killer_name[(CALLSIGN_LEN*2)+4];
659 kmatrix_kills_changed = 1;
660 Multi_killed_yourself=0;
662 // Both object numbers are localized already!
664 mprintf((0, "compute_kill passed: object %d killed object %d.\n", killer, killed));
666 if ((killed < 0) || (killed > Highest_object_index) || (killer < 0) || (killer > Highest_object_index))
668 Int3(); // See Rob, illegal value passed to compute_kill;
672 killed_type = Objects[killed].type;
673 killer_type = Objects[killer].type;
674 killer_id = Objects[killer].id;
676 if ((killed_type != OBJ_PLAYER) && (killed_type != OBJ_GHOST))
678 Int3(); // compute_kill passed non-player object!
682 killed_pnum = Objects[killed].id;
684 PKilledFlags[killed_pnum]=1;
686 Assert ((killed_pnum >= 0) && (killed_pnum < N_players));
688 if (Game_mode & GM_TEAM)
689 sprintf(killed_name, "%s (%s)", Players[killed_pnum].callsign, Netgame.team_name[get_team(killed_pnum)]);
691 sprintf(killed_name, "%s", Players[killed_pnum].callsign);
693 if (Newdemo_state == ND_STATE_RECORDING)
694 newdemo_record_multi_death(killed_pnum);
696 digi_play_sample( SOUND_HUD_KILL, F3_0 );
698 if (Control_center_destroyed)
699 Players[killed_pnum].connected=3;
701 if (killer_type == OBJ_CNTRLCEN)
703 Players[killed_pnum].net_killed_total++;
704 Players[killed_pnum].net_kills_total--;
706 if (Newdemo_state == ND_STATE_RECORDING)
707 newdemo_record_multi_kill(killed_pnum, -1);
709 if (killed_pnum == Player_num)
711 HUD_init_message("%s %s.", TXT_YOU_WERE, TXT_KILLED_BY_NONPLAY);
712 multi_add_lifetime_killed ();
715 HUD_init_message("%s %s %s.", killed_name, TXT_WAS, TXT_KILLED_BY_NONPLAY );
720 else if ((killer_type != OBJ_PLAYER) && (killer_type != OBJ_GHOST))
722 if (killer_id==PMINE_ID && killer_type!=OBJ_ROBOT)
724 if (killed_pnum == Player_num)
725 HUD_init_message("You were killed by a mine!");
727 HUD_init_message("%s was killed by a mine!",killed_name);
731 if (killed_pnum == Player_num)
733 HUD_init_message("%s %s.", TXT_YOU_WERE, TXT_KILLED_BY_ROBOT);
734 multi_add_lifetime_killed();
737 HUD_init_message("%s %s %s.", killed_name, TXT_WAS, TXT_KILLED_BY_ROBOT );
739 Players[killed_pnum].net_killed_total++;
743 else if ((killer_type != OBJ_PLAYER) && (killer_type != OBJ_GHOST) && (killer_id!=PMINE_ID))
745 Int3(); // Illegal killer type?
748 if (killer_id==PMINE_ID)
750 if (killed_pnum==Player_num)
751 HUD_init_message("You were killed by a mine!");
753 HUD_init_message("%s was killed by a mine!",killed_name);
755 Players[killed_pnum].net_killed_total++;
761 killer_pnum = Objects[killer].id;
763 if (Game_mode & GM_TEAM)
764 sprintf(killer_name, "%s (%s)", Players[killer_pnum].callsign, Netgame.team_name[get_team(killer_pnum)]);
766 sprintf(killer_name, "%s", Players[killer_pnum].callsign);
768 // Beyond this point, it was definitely a player-player kill situation
770 if ((killer_pnum < 0) || (killer_pnum >= N_players))
771 Int3(); // See rob, tracking down bug with kill HUD messages
772 if ((killed_pnum < 0) || (killed_pnum >= N_players))
773 Int3(); // See rob, tracking down bug with kill HUD messages
775 if (killer_pnum == killed_pnum)
777 if (!(Game_mode & GM_HOARD))
779 if (Game_mode & GM_TEAM)
780 team_kills[get_team(killed_pnum)] -= 1;
782 Players[killed_pnum].net_killed_total += 1;
783 Players[killed_pnum].net_kills_total -= 1;
785 if (Newdemo_state == ND_STATE_RECORDING)
786 newdemo_record_multi_kill(killed_pnum, -1);
788 kill_matrix[killed_pnum][killed_pnum] += 1; // # of suicides
790 if (killer_pnum == Player_num)
792 HUD_init_message("%s %s %s!", TXT_YOU, TXT_KILLED, TXT_YOURSELF );
793 Multi_killed_yourself=1;
794 multi_add_lifetime_killed();
797 HUD_init_message("%s %s", killed_name, TXT_SUICIDE);
802 if (!(Game_mode & GM_HOARD))
804 if (Game_mode & GM_TEAM)
806 if (get_team(killed_pnum) == get_team(killer_pnum))
807 team_kills[get_team(killed_pnum)] -= 1;
809 team_kills[get_team(killer_pnum)] += 1;
812 Players[killer_pnum].net_kills_total += 1;
813 Players[killer_pnum].KillGoalCount+=1;
815 if (Newdemo_state == ND_STATE_RECORDING)
816 newdemo_record_multi_kill(killer_pnum, 1);
820 if (Game_mode & GM_TEAM)
822 if (killed_pnum==Player_num && get_team(killed_pnum) == get_team(killer_pnum))
823 Multi_killed_yourself=1;
827 kill_matrix[killer_pnum][killed_pnum] += 1;
828 Players[killed_pnum].net_killed_total += 1;
829 if (killer_pnum == Player_num) {
830 HUD_init_message("%s %s %s!", TXT_YOU, TXT_KILLED, killed_name);
831 multi_add_lifetime_kills();
832 if ((Game_mode & GM_MULTI_COOP) && (Players[Player_num].score >= 1000))
833 add_points_to_score(-1000);
835 else if (killed_pnum == Player_num)
837 HUD_init_message("%s %s %s!", killer_name, TXT_KILLED, TXT_YOU);
838 multi_add_lifetime_killed();
839 if (Game_mode & GM_HOARD)
841 if (Players[Player_num].secondary_ammo[PROXIMITY_INDEX]>3)
842 multi_send_play_by_play (1,killer_pnum,Player_num);
843 else if (Players[Player_num].secondary_ammo[PROXIMITY_INDEX]>0)
844 multi_send_play_by_play (0,killer_pnum,Player_num);
848 HUD_init_message("%s %s %s!", killer_name, TXT_KILLED, killed_name);
851 TheGoal=Netgame.KillGoal*5;
853 if (Netgame.KillGoal>0)
855 if (Players[killer_pnum].KillGoalCount>=TheGoal)
857 if (killer_pnum==Player_num)
859 HUD_init_message("You reached the kill goal!");
860 Players[Player_num].shields=i2f(200);
863 HUD_init_message ("%s has reached the kill goal!",Players[killer_pnum].callsign);
865 HUD_init_message ("The control center has been destroyed!");
866 net_destroy_controlcen (obj_find_first_of_type (OBJ_CNTRLCEN));
870 multi_sort_kill_list();
871 multi_show_player_list();
872 Players[killed_pnum].flags&=(~(PLAYER_FLAGS_HEADLIGHT_ON)); // clear the killed guys flags/headlights
878 static int lasttime=0;
881 if (!(Game_mode & GM_MULTI))
887 if ((Game_mode & GM_NETWORK) && Netgame.PlayTimeAllowed && lasttime!=f2i (ThisLevelTime))
889 for (i=0;i<N_players;i++)
890 if (Players[i].connected)
894 multi_send_heartbeat();
895 lasttime=f2i(ThisLevelTime);
901 multi_send_message(); // Send any waiting messages
904 multi_leave_menu = 0;
907 if (Game_mode & GM_MULTI_ROBOTS)
909 multi_check_robot_timeout();
913 if ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM))
919 network_do_frame(0, 1);
922 if (multi_quit_game && !multi_in_menu)
925 longjmp(LeaveGame, 0);
930 multi_send_data(char *buf, int len, int repeat)
932 Assert(len == message_length[(int)buf[0]]);
933 Assert(buf[0] <= MULTI_MAX_TYPE);
934 // Assert(buf[0] >= 0);
936 if (Game_mode & GM_NETWORK)
939 if ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM))
940 com_send_data(buf, len, repeat);
941 else if (Game_mode & GM_NETWORK)
942 network_send_data(buf, len, repeat);
945 extern void AdjustMineSpawn();
948 multi_leave_game(void)
951 // if (Function_mode != FMODE_GAME)
954 if (!(Game_mode & GM_MULTI))
957 if (Game_mode & GM_NETWORK)
959 mprintf((0, "Sending explosion message.\n"));
964 drop_player_eggs(ConsoleObject);
965 multi_send_position(Players[Player_num].objnum);
966 multi_send_player_explode(MULTI_PLAYER_DROP);
969 mprintf((1, "Sending leave game.\n"));
970 multi_send_quit(MULTI_QUIT);
972 if ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM))
974 if (Game_mode & GM_NETWORK)
975 network_leave_game();
977 Game_mode |= GM_GAME_OVER;
979 if (Function_mode!=FMODE_EXIT)
980 Function_mode = FMODE_MENU;
984 // change_playernum_to(0);
985 // Viewer = ConsoleObject = &Objects[0];
990 multi_show_player_list()
992 if (!(Game_mode & GM_MULTI) || (Game_mode & GM_MULTI_COOP))
998 Show_kill_list_timer = F1_0*5; // 5 second timer
1003 multi_endlevel(int *secret)
1007 if ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM))
1008 com_endlevel(secret); // an opportunity to re-sync or whatever
1009 else if (Game_mode & GM_NETWORK)
1010 result = network_endlevel(secret);
1016 // Part 2 : functions that act on network/serial messages and change the
1017 // the state of the game in some way.
1021 //extern PORT *com_port;
1025 multi_menu_poll(void)
1028 int was_fuelcen_alive;
1029 int player_was_dead;
1031 was_fuelcen_alive = Control_center_destroyed;
1033 // Special polling function for in-game menus for multiplayer and serial
1035 if (! ((Game_mode & GM_MULTI) && (Function_mode == FMODE_GAME)) )
1038 if (multi_leave_menu)
1041 old_shields = Players[Player_num].shields;
1042 player_was_dead = Player_is_dead;
1044 multi_in_menu++; // Track level of menu nesting
1050 // timer_delay(f1_0/10); changed by allender for portability
1051 d_delay(100); // delay 100 milliseconds
1053 if (Endlevel_sequence || (Control_center_destroyed && !was_fuelcen_alive) || (Player_is_dead != player_was_dead) || (Players[Player_num].shields < old_shields))
1055 multi_leave_menu = 1;
1058 if ((Control_center_destroyed) && (Countdown_seconds_left < 10))
1060 multi_leave_menu = 1;
1064 #if !defined(WINDOWS) && !defined(MACINTOSH) && (!defined(__ENV_LINUX__) && (!defined (__ENV_DJGPP__)))
1065 if ((Game_mode & GM_MODEM) && (!GetCd(com_port)))
1067 multi_leave_menu = 1;
1076 multi_define_macro(int key)
1078 if (!(Game_mode & GM_MULTI))
1081 key &= (~KEY_SHIFTED);
1086 multi_defining_message = 1; break;
1088 multi_defining_message = 2; break;
1090 multi_defining_message = 3; break;
1092 multi_defining_message = 4; break;
1097 if (multi_defining_message) {
1098 multi_message_index = 0;
1099 Network_message[multi_message_index] = 0;
1104 char feedback_result[200];
1107 multi_message_feedback(void)
1113 if (!( ((colon = strrchr(Network_message, ':')) == NULL) || (colon-Network_message < 1) || (colon-Network_message > CALLSIGN_LEN) ))
1115 sprintf(feedback_result, "%s ", TXT_MESSAGE_SENT_TO);
1116 if ((Game_mode & GM_TEAM) && (atoi(Network_message) > 0) && (atoi(Network_message) < 3))
1118 sprintf(feedback_result+strlen(feedback_result), "%s '%s'", TXT_TEAM, Netgame.team_name[atoi(Network_message)-1]);
1121 if (Game_mode & GM_TEAM)
1123 for (i = 0; i < N_players; i++)
1125 if (!strnicmp(Netgame.team_name[i], Network_message, colon-Network_message))
1128 strcat(feedback_result, ", ");
1131 strcat(feedback_result, "\n");
1132 sprintf(feedback_result+strlen(feedback_result), "%s '%s'", TXT_TEAM, Netgame.team_name[i]);
1136 for (i = 0; i < N_players; i++)
1138 if ((!strnicmp(Players[i].callsign, Network_message, colon-Network_message)) && (i != Player_num) && (Players[i].connected))
1141 strcat(feedback_result, ", ");
1144 strcat(feedback_result, "\n");
1145 sprintf(feedback_result+strlen(feedback_result), "%s", Players[i].callsign);
1149 strcat(feedback_result, TXT_NOBODY);
1151 strcat(feedback_result, ".");
1153 digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
1155 Assert(strlen(feedback_result) < 200);
1157 HUD_init_message(feedback_result);
1158 // sprintf (temp,"%s",colon);
1159 // sprintf (Network_message,"%s",temp);
1165 multi_send_macro(int key)
1167 if (! (Game_mode & GM_MULTI) )
1184 if (!Network_message_macro[key][0])
1186 HUD_init_message(TXT_NO_MACRO);
1190 strcpy(Network_message, Network_message_macro[key]);
1191 Network_message_reciever = 100;
1193 HUD_init_message("%s '%s'", TXT_SENDING, Network_message);
1194 multi_message_feedback();
1199 multi_send_message_start()
1201 if (Game_mode&GM_MULTI) {
1202 multi_sending_message = 1;
1203 multi_message_index = 0;
1204 Network_message[multi_message_index] = 0;
1208 extern fix StartingShields;
1209 fix PingLaunchTime,PingReturnTime;
1211 extern void network_send_ping (ubyte);
1212 extern void network_dump_player(ubyte * server, ubyte *node, int why);
1213 extern int network_who_is_master();
1214 extern void network_send_netgame_update();
1215 extern char NameReturning;
1216 extern int force_cockpit_redraw;
1218 void network_dump_appletalk_player(ubyte node, ushort net, ubyte socket, int why);
1220 void multi_send_message_end()
1225 Network_message_reciever = 100;
1227 if (!strnicmp (Network_message,"!Names",6))
1229 NameReturning=1-NameReturning;
1230 HUD_init_message ("Name returning is now %s.",NameReturning?"active":"disabled");
1232 else if (!strnicmp (Network_message,"Handicap:",9))
1234 mytempbuf=&Network_message[9];
1235 mprintf ((0,"Networkhandi=%s\n",mytempbuf));
1236 StartingShields=atol (mytempbuf);
1237 if (StartingShields<10)
1239 if (StartingShields>100)
1241 sprintf (Network_message,"%s has tried to cheat!",Players[Player_num].callsign);
1242 StartingShields=100;
1245 sprintf (Network_message,"%s handicap is now %d",Players[Player_num].callsign,StartingShields);
1247 HUD_init_message ("Telling others of your handicap of %d!",StartingShields);
1248 StartingShields=i2f(StartingShields);
1250 else if (!strnicmp (Network_message,"NoBombs",7))
1251 Netgame.DoSmartMine=0;
1252 else if (!strnicmp (Network_message,"Ping:",5))
1254 if (Game_mode & GM_NETWORK)
1257 if (strlen(Network_message) > 5)
1258 while (Network_message[name_index] == ' ')
1261 if (strlen(Network_message)<=name_index)
1263 HUD_init_message ("You must specify a name to ping");
1267 for (i = 0; i < N_players; i++)
1268 if ((!strnicmp(Players[i].callsign, &Network_message[name_index], strlen(Network_message)-name_index)) && (i != Player_num) && (Players[i].connected))
1270 PingLaunchTime=timer_get_fixed_seconds();
1271 network_send_ping (i);
1272 HUD_init_message("Pinging %s...",Players[i].callsign);
1273 multi_message_index = 0;
1274 multi_sending_message = 0;
1278 else // Modem/Serial ping
1280 PingLaunchTime=timer_get_fixed_seconds();
1281 multi_send_modem_ping ();
1282 HUD_init_message("Pinging opponent...");
1283 multi_message_index = 0;
1284 multi_sending_message = 0;
1288 else if (!strnicmp (Network_message,"move:",5))
1290 mprintf ((0,"moving?\n"));
1292 if ((Game_mode & GM_NETWORK) && (Game_mode & GM_TEAM))
1295 if (strlen(Network_message) > 5)
1296 while (Network_message[name_index] == ' ')
1299 if (!network_i_am_master())
1301 HUD_init_message ("Only %s can move players!",Players[network_who_is_master()].callsign);
1305 if (strlen(Network_message)<=name_index)
1307 HUD_init_message ("You must specify a name to move");
1311 for (i = 0; i < N_players; i++)
1312 if ((!strnicmp(Players[i].callsign, &Network_message[name_index], strlen(Network_message)-name_index)) && (Players[i].connected))
1314 if ((Game_mode & GM_CAPTURE) && (Players[i].flags & PLAYER_FLAGS_FLAG))
1316 HUD_init_message ("Can't move player because s/he has a flag!");
1320 if (Netgame.team_vector & (1<<i))
1321 Netgame.team_vector&=(~(1<<i));
1323 Netgame.team_vector|=(1<<i);
1325 for (t=0;t<N_players;t++)
1326 if (Players[t].connected)
1327 multi_reset_object_texture (&Objects[Players[t].objnum]);
1329 network_send_netgame_update ();
1330 sprintf (Network_message,"%s has changed teams!",Players[i].callsign);
1333 HUD_init_message ("You have changed teams!");
1337 HUD_init_message ("Moving %s to other team.",Players[i].callsign);
1343 else if (!strnicmp (Network_message,"kick:",5) && (Game_mode & GM_NETWORK))
1346 if (strlen(Network_message) > 5)
1347 while (Network_message[name_index] == ' ')
1350 if (!network_i_am_master())
1352 HUD_init_message ("Only %s can kick others out!",Players[network_who_is_master()].callsign);
1353 multi_message_index = 0;
1354 multi_sending_message = 0;
1357 if (strlen(Network_message)<=name_index)
1359 HUD_init_message ("You must specify a name to kick");
1360 multi_message_index = 0;
1361 multi_sending_message = 0;
1365 if (Network_message[name_index] == '#' && isdigit(Network_message[name_index+1])) {
1366 int players[MAX_NUM_NET_PLAYERS];
1367 int listpos = Network_message[name_index+1] - '0';
1369 mprintf ((0,"Trying to kick %d , show_kill_list=%d\n",listpos,Show_kill_list));
1371 if (Show_kill_list==1 || Show_kill_list==2) {
1372 if (listpos == 0 || listpos >= N_players) {
1373 HUD_init_message ("Invalid player number for kick.");
1374 multi_message_index = 0;
1375 multi_sending_message = 0;
1378 multi_get_kill_list(players);
1379 i = players[listpos];
1380 if ((i != Player_num) && (Players[i].connected))
1383 else HUD_init_message ("You cannot use # kicking with in team display.");
1386 multi_message_index = 0;
1387 multi_sending_message = 0;
1392 for (i = 0; i < N_players; i++)
1393 if ((!strnicmp(Players[i].callsign, &Network_message[name_index], strlen(Network_message)-name_index)) && (i != Player_num) && (Players[i].connected)) {
1395 if (Network_game_type == IPX_GAME)
1396 network_dump_player(NetPlayers.players[i].network.ipx.server,NetPlayers.players[i].network.ipx.node, 7);
1398 network_dump_appletalk_player(NetPlayers.players[i].network.appletalk.node,NetPlayers.players[i].network.appletalk.net, NetPlayers.players[i].network.appletalk.socket, 7);
1400 HUD_init_message("Dumping %s...",Players[i].callsign);
1401 multi_message_index = 0;
1402 multi_sending_message = 0;
1408 HUD_init_message("%s '%s'", TXT_SENDING, Network_message);
1410 multi_send_message();
1411 multi_message_feedback();
1413 multi_message_index = 0;
1414 multi_sending_message = 0;
1417 void multi_define_macro_end()
1419 Assert( multi_defining_message > 0 );
1421 strcpy( Network_message_macro[multi_defining_message-1], Network_message );
1422 write_player_file();
1424 multi_message_index = 0;
1425 multi_defining_message = 0;
1428 void multi_message_input_sub( int key )
1433 multi_sending_message = 0;
1434 multi_defining_message = 0;
1435 game_flush_inputs();
1440 if (multi_message_index > 0)
1441 multi_message_index--;
1442 Network_message[multi_message_index] = 0;
1445 if ( multi_sending_message )
1446 multi_send_message_end();
1447 else if ( multi_defining_message )
1448 multi_define_macro_end();
1449 game_flush_inputs();
1453 int ascii = key_to_ascii(key);
1454 if ((ascii < 255 )) {
1455 if (multi_message_index < MAX_MESSAGE_LEN-2 ) {
1456 Network_message[multi_message_index++] = ascii;
1457 Network_message[multi_message_index] = 0;
1458 } else if ( multi_sending_message ) {
1460 char * ptext, * pcolon;
1462 Network_message[multi_message_index++] = ascii;
1463 Network_message[multi_message_index] = 0;
1464 for (i=multi_message_index-1; i>=0; i-- ) {
1465 if ( Network_message[i]==32 ) {
1466 ptext = &Network_message[i+1];
1467 Network_message[i] = 0;
1471 multi_send_message_end();
1473 multi_sending_message = 1;
1474 pcolon = strchr( Network_message, ':' );
1476 strcpy( pcolon+1, ptext );
1478 strcpy( Network_message, ptext );
1479 multi_message_index = strlen( Network_message );
1488 multi_send_message_dialog(void)
1493 if (!(Game_mode&GM_MULTI))
1496 Network_message[0] = 0; // Get rid of old contents
1498 m[0].type=NM_TYPE_INPUT; m[0].text = Network_message; m[0].text_len = MAX_MESSAGE_LEN-1;
1499 choice = newmenu_do( NULL, TXT_SEND_MESSAGE, 1, m, NULL );
1501 if ((choice > -1) && (strlen(Network_message) > 0)) {
1502 Network_message_reciever = 100;
1503 HUD_init_message("%s '%s'", TXT_SENDING, Network_message);
1504 multi_message_feedback();
1511 multi_do_death(int objnum)
1513 // Do any miscellaneous stuff for a new network player after death
1517 if (!(Game_mode & GM_MULTI_COOP))
1519 mprintf((0, "Setting all keys for player %d.\n", Player_num));
1520 Players[Player_num].flags |= (PLAYER_FLAGS_RED_KEY | PLAYER_FLAGS_BLUE_KEY | PLAYER_FLAGS_GOLD_KEY);
1525 multi_do_fire(char *buf)
1532 // Act out the actual shooting
1536 weapon = (int)buf[2];
1541 Network_laser_track = INTEL_SHORT(*(short *)(buf+6));
1543 Assert (pnum < N_players);
1545 if (Objects[Players[(int)pnum].objnum].type == OBJ_GHOST)
1546 multi_make_ghost_player(pnum);
1548 // mprintf((0,"multi_do_fire, weapon = %d\n",weapon));
1550 if (weapon == FLARE_ADJUST)
1551 Laser_player_fire( Objects+Players[(int)pnum].objnum, FLARE_ID, 6, 1, 0);
1552 else if (weapon >= MISSILE_ADJUST) {
1553 int weapon_id,weapon_gun;
1555 weapon_id = Secondary_weapon_to_weapon_info[weapon-MISSILE_ADJUST];
1556 weapon_gun = Secondary_weapon_to_gun_num[weapon-MISSILE_ADJUST] + (flags & 1);
1557 mprintf((0,"missile id = %d, gun = %d\n",weapon_id,weapon_gun));
1559 if (weapon-MISSILE_ADJUST==GUIDED_INDEX)
1561 mprintf ((0,"Missile is guided!!!\n"));
1565 Laser_player_fire( Objects+Players[(int)pnum].objnum, weapon_id, weapon_gun, 1, 0 );
1568 fix save_charge = Fusion_charge;
1570 if (weapon == FUSION_INDEX) {
1571 Fusion_charge = flags << 12;
1572 mprintf((0, "Fusion charge X%f.\n", f2fl(Fusion_charge)));
1574 if (weapon == LASER_ID) {
1575 if (flags & LASER_QUAD)
1576 Players[(int)pnum].flags |= PLAYER_FLAGS_QUAD_LASERS;
1578 Players[(int)pnum].flags &= ~PLAYER_FLAGS_QUAD_LASERS;
1581 do_laser_firing(Players[(int)pnum].objnum, weapon, (int)buf[3], flags, (int)buf[5]);
1583 if (weapon == FUSION_INDEX)
1584 Fusion_charge = save_charge;
1589 multi_do_message(char *buf)
1592 char *tilde,mesbuf[100];
1597 if ((tilde=strchr (buf+loc,'$'))) // do that stupid name stuff
1598 { // why'd I put this in? Probably for the
1599 tloc=tilde-(buf+loc); // same reason you can name your guidebot
1600 mprintf ((0,"Tloc=%d\n",tloc));
1603 strncpy (mesbuf,buf+loc,tloc);
1604 strcpy (mesbuf+tloc,Players[Player_num].callsign);
1605 strcpy (mesbuf+strlen(Players[Player_num].callsign)+tloc,buf+loc+tloc+1);
1606 strcpy (buf+loc,mesbuf);
1609 if (((colon = strrchr(buf+loc, ':')) == NULL) || (colon-(buf+loc) < 1) || (colon-(buf+loc) > CALLSIGN_LEN))
1612 mesbuf[1] = BM_XRGB(28, 0, 0);
1613 strcpy(&mesbuf[2], Players[(int)buf[1]].callsign);
1617 mesbuf[t+2] = BM_XRGB(0, 31, 0);
1620 digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
1621 HUD_init_message("%s %s", mesbuf, buf+2);
1625 if ( (!strnicmp(Players[Player_num].callsign, buf+loc, colon-(buf+loc))) ||
1626 ((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)))) )
1629 mesbuf[1] = BM_XRGB(0, 32, 32);
1630 strcpy(&mesbuf[2], Players[(int)buf[1]].callsign);
1634 mesbuf[t+2] = BM_XRGB(0, 31, 0);
1637 digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
1638 HUD_init_message("%s %s", mesbuf, colon+1);
1644 multi_do_position(char *buf)
1650 // This routine does only player positions, mode game only
1651 // mprintf((0, "Got position packet.\n"));
1653 int pnum = (Player_num+1)%2;
1655 Assert(&Objects[Players[pnum].objnum] != ConsoleObject);
1657 if (Game_mode & GM_NETWORK)
1659 Int3(); // Get Jason, what the hell are we doing here?
1665 extract_shortpos(&Objects[Players[pnum].objnum], (shortpos *)(buf+1),0);
1667 memcpy((ubyte *)(sp.bytemat), (ubyte *)(buf + 1), 9);
1668 memcpy((ubyte *)&(sp.xo), (ubyte *)(buf + 10), 14);
1669 extract_shortpos(&Objects[Players[pnum].objnum], &sp, 1);
1672 if (Objects[Players[pnum].objnum].movement_type == MT_PHYSICS)
1673 set_thrust_from_velocity(&Objects[Players[pnum].objnum]);
1677 multi_do_reappear(char *buf)
1681 objnum = INTEL_SHORT(*(short *)(buf+1));
1683 Assert(objnum >= 0);
1684 // Assert(Players[Objects[objnum].id]].objnum == objnum);
1686 // mprintf((0, "Switching rendering back on for object %d.\n", objnum));
1688 multi_make_ghost_player(Objects[objnum].id);
1689 create_player_appearance_effect(&Objects[objnum]);
1690 PKilledFlags[Objects[objnum].id]=0;
1694 multi_do_player_explode(char *buf)
1696 // Only call this for players, not robots. pnum is player number, not
1703 char remote_created;
1708 if ((pnum < 0) || (pnum >= N_players))
1712 Assert(pnum < N_players);
1716 // If we are in the process of sending objects to a new player, reset that process
1717 if (Network_send_objects)
1719 mprintf((0, "Resetting object sync due to player explosion.\n"));
1720 Network_send_objnum = -1;
1724 // Stuff the Players structure to prepare for the explosion
1727 Players[pnum].primary_weapon_flags = INTEL_SHORT(*(ushort *)(buf+count)); count += 2;
1728 Players[pnum].secondary_weapon_flags = INTEL_SHORT(*(ushort *)(buf+count)); count += 2;
1729 Players[pnum].laser_level = buf[count]; count++;
1730 Players[pnum].secondary_ammo[HOMING_INDEX] = buf[count]; count++;
1731 Players[pnum].secondary_ammo[CONCUSSION_INDEX] = buf[count];count++;
1732 Players[pnum].secondary_ammo[SMART_INDEX] = buf[count]; count++;
1733 Players[pnum].secondary_ammo[MEGA_INDEX] = buf[count]; count++;
1734 Players[pnum].secondary_ammo[PROXIMITY_INDEX] = buf[count]; count++;
1736 Players[pnum].secondary_ammo[SMISSILE1_INDEX] = buf[count]; count++;
1737 Players[pnum].secondary_ammo[GUIDED_INDEX] = buf[count]; count++;
1738 Players[pnum].secondary_ammo[SMART_MINE_INDEX]= buf[count]; count++;
1739 Players[pnum].secondary_ammo[SMISSILE4_INDEX] = buf[count]; count++;
1740 Players[pnum].secondary_ammo[SMISSILE5_INDEX] = buf[count]; count++;
1742 Players[pnum].primary_ammo[VULCAN_INDEX] = INTEL_SHORT(*(ushort *)(buf+count)); count += 2;
1743 Players[pnum].primary_ammo[GAUSS_INDEX] = INTEL_SHORT(*(ushort *)(buf+count)); count += 2;
1744 Players[pnum].flags = INTEL_INT(*(uint *)(buf+count)); count += 4;
1746 multi_adjust_remote_cap (pnum);
1748 objp = Objects+Players[pnum].objnum;
1750 // objp->phys_info.velocity = *(vms_vector *)(buf+16); // 12 bytes
1751 // objp->pos = *(vms_vector *)(buf+28); // 12 bytes
1753 remote_created = buf[count++]; // How many did the other guy create?
1757 drop_player_eggs(objp);
1759 // Create mapping from remote to local numbering system
1761 mprintf((0, "I Created %d powerups, remote created %d.\n", Net_create_loc, remote_created));
1763 // We now handle this situation gracefully, Int3 not required
1764 // if (Net_create_loc != remote_created)
1765 // Int3(); // Probably out of object array space, see Rob
1767 for (i = 0; i < remote_created; i++)
1771 s = INTEL_SHORT(*(short *)(buf+count));
1773 if ((i < Net_create_loc) && (s > 0))
1774 map_objnum_local_to_remote((short)Net_create_objnums[i], s, pnum);
1775 else if (*(short *)(buf+count) <= 0)
1777 mprintf((0, "WARNING: Remote created object has non-valid number %d (player %d)", s, pnum));
1781 mprintf((0, "WARNING: Could not create all powerups created by player %d.\n", pnum));
1786 for (i = remote_created; i < Net_create_loc; i++) {
1787 mprintf((0, "WARNING: I Created more powerups than player %d, deleting.\n", pnum));
1788 Objects[Net_create_objnums[i]].flags |= OF_SHOULD_BE_DEAD;
1791 if (buf[0] == MULTI_PLAYER_EXPLODE)
1793 explode_badass_player(objp);
1795 objp->flags &= ~OF_SHOULD_BE_DEAD; //don't really kill player
1796 multi_make_player_ghost(pnum);
1800 create_player_appearance_effect(objp);
1803 Players[pnum].flags &= ~(PLAYER_FLAGS_CLOAKED | PLAYER_FLAGS_INVULNERABLE | PLAYER_FLAGS_FLAG);
1804 Players[pnum].cloak_time = 0;
1808 multi_do_kill(char *buf)
1814 pnum = (int)(buf[count]);
1815 if ((pnum < 0) || (pnum >= N_players))
1817 Int3(); // Invalid player number killed
1820 killed = Players[pnum].objnum;
1823 killer = INTEL_SHORT(*(short *)(buf+count));
1825 killer = objnum_remote_to_local(killer, (byte)buf[count+2]);
1828 if ((Objects[killed].type != OBJ_PLAYER) && (Objects[killed].type != OBJ_GHOST))
1831 mprintf( (1, "SOFT INT3: MULTI.C Non-player object %d of type %d killed! (JOHN)\n", killed, Objects[killed].type ));
1836 multi_compute_kill(killer, killed);
1841 // Changed by MK on 10/20/94 to send NULL as object to net_destroy_controlcen if it got -1
1842 // which means not a controlcen object, but contained in another object
1843 void multi_do_controlcen_destroy(char *buf)
1848 objnum = INTEL_SHORT(*(short *)(buf+1));
1851 if (Control_center_destroyed != 1)
1853 if ((who < N_players) && (who != Player_num)) {
1854 HUD_init_message("%s %s", Players[who].callsign, TXT_HAS_DEST_CONTROL);
1856 else if (who == Player_num)
1857 HUD_init_message(TXT_YOU_DEST_CONTROL);
1859 HUD_init_message(TXT_CONTROL_DESTROYED);
1862 net_destroy_controlcen(Objects+objnum);
1864 net_destroy_controlcen(NULL);
1869 multi_do_escape(char *buf)
1873 objnum = Players[(int)buf[1]].objnum;
1875 digi_play_sample(SOUND_HUD_MESSAGE, F1_0);
1876 digi_kill_sound_linked_to_object (objnum);
1880 HUD_init_message("%s %s", Players[(int)buf[1]].callsign, TXT_HAS_ESCAPED);
1881 if (Game_mode & GM_NETWORK)
1882 Players[(int)buf[1]].connected = CONNECT_ESCAPE_TUNNEL;
1883 if (!multi_goto_secret)
1884 multi_goto_secret = 2;
1886 else if (buf[2] == 1)
1888 HUD_init_message("%s %s", Players[(int)buf[1]].callsign, TXT_HAS_FOUND_SECRET);
1889 if (Game_mode & GM_NETWORK)
1890 Players[(int)buf[1]].connected = CONNECT_FOUND_SECRET;
1891 if (!multi_goto_secret)
1892 multi_goto_secret = 1;
1894 create_player_appearance_effect(&Objects[objnum]);
1895 multi_make_player_ghost(buf[1]);
1899 multi_do_remobj(char *buf)
1901 short objnum; // which object to remove
1903 byte obj_owner; // which remote list is it entered in
1905 objnum = INTEL_SHORT(*(short *)(buf+1));
1908 Assert(objnum >= 0);
1913 local_objnum = objnum_remote_to_local(objnum, obj_owner); // translate to local objnum
1915 // mprintf((0, "multi_do_remobj: %d owner %d = %d.\n", objnum, obj_owner, local_objnum));
1917 if (local_objnum < 0)
1919 mprintf((1, "multi_do_remobj: Could not remove referenced object.\n"));
1923 if ((Objects[local_objnum].type != OBJ_POWERUP) && (Objects[local_objnum].type != OBJ_HOSTAGE))
1925 mprintf((1, "multi_get_remobj: tried to remove invalid type %d.\n", Objects[local_objnum].type));
1929 if (Network_send_objects && network_objnum_is_past(local_objnum))
1931 mprintf((0, "Resetting object sync due to object removal.\n"));
1932 Network_send_objnum = -1;
1934 if (Objects[local_objnum].type==OBJ_POWERUP)
1935 if (Game_mode & GM_NETWORK)
1937 if (PowerupsInMine[Objects[local_objnum].id]>0)
1938 PowerupsInMine[Objects[local_objnum].id]--;
1940 if (multi_powerup_is_4pack (Objects[local_objnum].id))
1942 mprintf ((0,"Hey babe! Doing that wacky 4 pack stuff."));
1944 if (PowerupsInMine[Objects[local_objnum].id-1]-4<0)
1945 PowerupsInMine[Objects[local_objnum].id-1]=0;
1947 PowerupsInMine[Objects[local_objnum].id-1]-=4;
1950 mprintf ((0,"Decrementing powerups! %d\n",PowerupsInMine[Objects[local_objnum].id]));
1953 Objects[local_objnum].flags |= OF_SHOULD_BE_DEAD; // quick and painless
1958 multi_do_quit(char *buf)
1961 if (Game_mode & GM_NETWORK)
1965 digi_play_sample( SOUND_HUD_MESSAGE, F1_0 );
1967 HUD_init_message( "%s %s", Players[(int)buf[1]].callsign, TXT_HAS_LEFT_THE_GAME);
1969 network_disconnect_player(buf[1]);
1974 for (i = 0; i < N_players; i++)
1975 if (Players[i].connected) n++;
1978 nm_messagebox(NULL, 1, TXT_OK, TXT_YOU_ARE_ONLY);
1982 if ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM))
1984 Function_mode = FMODE_MENU;
1985 multi_quit_game = 1;
1986 multi_leave_menu = 1;
1987 nm_messagebox(NULL, 1, TXT_OK, TXT_OPPONENT_LEFT);
1988 Function_mode = FMODE_GAME;
1989 multi_reset_stuff();
1995 multi_do_cloak(char *buf)
1999 pnum = (int)(buf[1]);
2001 Assert(pnum < N_players);
2003 mprintf((0, "Cloaking player %d\n", pnum));
2005 Players[pnum].flags |= PLAYER_FLAGS_CLOAKED;
2006 Players[pnum].cloak_time = GameTime;
2007 ai_do_cloak_stuff();
2010 if (Game_mode & GM_MULTI_ROBOTS)
2011 multi_strip_robots(pnum);
2014 if (Newdemo_state == ND_STATE_RECORDING)
2015 newdemo_record_multi_cloak(pnum);
2019 multi_do_decloak(char *buf)
2023 pnum = (int)(buf[1]);
2025 if (Newdemo_state == ND_STATE_RECORDING)
2026 newdemo_record_multi_decloak(pnum);
2031 multi_do_door_open(char *buf)
2039 segnum = INTEL_SHORT(*(short *)(buf+1));
2043 // mprintf((0, "Opening door on side %d of segment # %d.\n", side, segnum));
2045 if ((segnum < 0) || (segnum > Highest_segment_index) || (side < 0) || (side > 5))
2051 seg = &Segments[segnum];
2053 if (seg->sides[side].wall_num == -1) { //Opening door on illegal wall
2058 w = &Walls[seg->sides[side].wall_num];
2060 if (w->type == WALL_BLASTABLE)
2062 if (!(w->flags & WALL_BLASTED))
2064 mprintf((0, "Blasting wall by remote command.\n"));
2065 wall_destroy(seg, side);
2069 else if (w->state != WALL_DOOR_OPENING)
2071 wall_open_door(seg, side);
2078 // mprintf((0, "Door already opening!\n"));
2082 multi_do_create_explosion(char *buf)
2087 pnum = buf[count++];
2089 // mprintf((0, "Creating small fireball.\n"));
2090 create_small_fireball_on_object(&Objects[Players[pnum].objnum], F1_0, 1);
2094 multi_do_controlcen_fire(char *buf)
2096 vms_vector to_target;
2101 memcpy(&to_target, buf+count, 12); count += 12;
2102 #ifdef MACINTOSH // swap the vector to_target
2103 to_target.x = (fix)INTEL_INT((int)to_target.x);
2104 to_target.y = (fix)INTEL_INT((int)to_target.y);
2105 to_target.z = (fix)INTEL_INT((int)to_target.z);
2107 gun_num = buf[count]; count += 1;
2108 objnum = INTEL_SHORT(*(short *)(buf+count)); count += 2;
2110 Laser_create_new_easy(&to_target, &Gun_pos[(int)gun_num], objnum, CONTROLCEN_WEAPON_NUM, 1);
2114 multi_do_create_powerup(char *buf)
2124 if (Endlevel_sequence || Control_center_destroyed)
2127 pnum = buf[count++];
2128 powerup_type = buf[count++];
2129 segnum = INTEL_SHORT(*(short *)(buf+count)); count+=2;
2130 objnum = INTEL_SHORT(*(short *)(buf+count)); count+=2;
2132 if ((segnum < 0) || (segnum > Highest_segment_index)) {
2137 new_pos = *(vms_vector *)(buf+count); count+=sizeof(vms_vector);
2139 new_pos.x = (fix)SWAPINT((int)new_pos.x);
2140 new_pos.y = (fix)SWAPINT((int)new_pos.y);
2141 new_pos.z = (fix)SWAPINT((int)new_pos.z);
2145 my_objnum = call_object_create_egg(&Objects[Players[(int)pnum].objnum], 1, OBJ_POWERUP, powerup_type);
2147 if (my_objnum < 0) {
2148 mprintf((0, "Could not create new powerup!\n"));
2152 if (Network_send_objects && network_objnum_is_past(my_objnum))
2154 mprintf((0, "Resetting object sync due to powerup creation.\n"));
2155 Network_send_objnum = -1;
2158 Objects[my_objnum].pos = new_pos;
2160 vm_vec_zero(&Objects[my_objnum].mtype.phys_info.velocity);
2162 obj_relink(my_objnum, segnum);
2164 map_objnum_local_to_remote(my_objnum, objnum, pnum);
2166 object_create_explosion(segnum, &new_pos, i2f(5), VCLIP_POWERUP_DISAPPEARANCE);
2167 mprintf((0, "Creating powerup type %d in segment %i.\n", powerup_type, segnum));
2169 if (Game_mode & GM_NETWORK)
2170 PowerupsInMine[(int)powerup_type]++;
2174 multi_do_play_sound(char *buf)
2176 int pnum = (int)(buf[1]);
2177 int sound_num = (int)(buf[2]);
2178 fix volume = (int)(buf[3]) << 12;
2180 if (!Players[pnum].connected)
2183 Assert(Players[pnum].objnum >= 0);
2184 Assert(Players[pnum].objnum <= Highest_object_index);
2186 digi_link_sound_to_object( sound_num, Players[pnum].objnum, 0, volume);
2190 multi_do_score(char *buf)
2192 int pnum = (int)(buf[1]);
2194 if ((pnum < 0) || (pnum >= N_players))
2196 Int3(); // Non-terminal, see rob
2200 if (Newdemo_state == ND_STATE_RECORDING)
2201 newdemo_record_multi_score(pnum, INTEL_INT(*(int *)(buf+2)) );
2203 Players[pnum].score = INTEL_INT(*(int *)(buf+2));
2205 multi_sort_kill_list();
2209 multi_do_trigger(char *buf)
2211 int pnum = (int)(buf[1]);
2212 int trigger = (int)(buf[2]);
2214 mprintf ((0,"MULTI doing trigger!\n"));
2216 if ((pnum < 0) || (pnum >= N_players) || (pnum == Player_num))
2218 Int3(); // Got trigger from illegal playernum
2221 if ((trigger < 0) || (trigger >= Num_triggers))
2223 Int3(); // Illegal trigger number in multiplayer
2226 check_trigger_sub(trigger, pnum,0);
2229 void multi_do_drop_marker (char *buf)
2232 int pnum=(int)(buf[1]);
2233 int mesnum=(int)(buf[2]);
2234 vms_vector position;
2236 if (pnum==Player_num) // my marker? don't set it down cuz it might screw up the orientation
2239 position.x=(fix)INTEL_INT(*(int *)(buf+3));
2240 position.y=(fix)INTEL_INT(*(int *)(buf+7));
2241 position.z=(fix)INTEL_INT(*(int *)(buf+11));
2244 MarkerMessage[(pnum*2)+mesnum][i]=buf[15+i];
2246 MarkerPoint[(pnum*2)+mesnum]=position;
2248 if (MarkerObject[(pnum*2)+mesnum] !=-1 && Objects[MarkerObject[(pnum*2)+mesnum]].type!=OBJ_NONE && MarkerObject[(pnum*2)+mesnum] !=0)
2249 obj_delete(MarkerObject[(pnum*2)+mesnum]);
2251 MarkerObject[(pnum*2)+mesnum] = drop_marker_object(&position,Objects[Players[Player_num].objnum].segnum,&Objects[Players[Player_num].objnum].orient,(pnum*2)+mesnum);
2252 strcpy (MarkerOwner[(pnum*2)+mesnum],Players[pnum].callsign);
2253 mprintf ((0,"Dropped player %d message: %s\n",pnum,MarkerMessage[(pnum*2)+mesnum]));
2257 void multi_do_hostage_door_status(char *buf)
2259 // Update hit point status of a door
2265 wallnum = INTEL_SHORT(*(short *)(buf+count)); count += 2;
2266 hps = (fix)INTEL_INT(*(int *)(buf+count)); count += 4;
2268 if ((wallnum < 0) || (wallnum > Num_walls) || (hps < 0) || (Walls[wallnum].type != WALL_BLASTABLE))
2270 Int3(); // Non-terminal, see Rob
2274 // mprintf((0, "Damaging wall number %d to %f points.\n", wallnum, f2fl(hps)));
2276 if (hps < Walls[wallnum].hps)
2277 wall_damage(&Segments[Walls[wallnum].segnum], Walls[wallnum].sidenum, Walls[wallnum].hps - hps);
2280 void multi_do_save_game(char *buf)
2287 slot = *(ubyte *)(buf+count); count += 1;
2288 id = INTEL_INT(*(uint *)(buf+count)); count += 4;
2289 memcpy( desc, &buf[count], 20 ); count += 20;
2291 multi_save_game( slot, id, desc );
2294 void multi_do_restore_game(char *buf)
2300 slot = *(ubyte *)(buf+count); count += 1;
2301 id = INTEL_INT(*(uint *)(buf+count)); count += 4;
2303 multi_restore_game( slot, id );
2307 void multi_do_req_player(char *buf)
2311 // Send my netplayer_stats to everyone!
2312 player_n = *(ubyte *)(buf+1);
2313 if ( (player_n == Player_num) || (player_n == 255) ) {
2314 extract_netplayer_stats( &ps, &Players[Player_num] );
2315 ps.Player_num = Player_num;
2316 ps.message_type = MULTI_SEND_PLAYER; // SET
2317 multi_send_data((ubyte*)&ps, sizeof(netplayer_stats), 0);
2321 void multi_do_send_player(char *buf)
2323 // Got a player packet from someone!!!
2324 netplayer_stats * p;
2325 p = (netplayer_stats *)buf;
2327 Assert( p->Player_num <= N_players );
2329 mprintf(( 0, "Got netplayer_stats for player %d (I'm %d)\n", p->Player_num, Player_num ));
2330 mprintf(( 0, "Their shields are: %d\n", f2i(p->shields) ));
2332 use_netplayer_stats( &Players[p->Player_num], p );
2336 multi_reset_stuff(void)
2338 // A generic, emergency function to solve problems that crop up
2339 // when a player exits quick-out from the game because of a
2340 // serial connection loss. Fixes several weird bugs!
2344 Players[Player_num].homing_object_dist = -F1_0; // Turn off homing sound.
2346 Dead_player_camera = 0;
2347 Endlevel_sequence = 0;
2352 multi_reset_player_object(object *objp)
2356 //Init physics for a non-console player
2358 Assert(objp >= Objects);
2359 Assert(objp <= Objects+Highest_object_index);
2360 Assert((objp->type == OBJ_PLAYER) || (objp->type == OBJ_GHOST));
2362 vm_vec_zero(&objp->mtype.phys_info.velocity);
2363 vm_vec_zero(&objp->mtype.phys_info.thrust);
2364 vm_vec_zero(&objp->mtype.phys_info.rotvel);
2365 vm_vec_zero(&objp->mtype.phys_info.rotthrust);
2366 objp->mtype.phys_info.brakes = objp->mtype.phys_info.turnroll = 0;
2367 objp->mtype.phys_info.mass = Player_ship->mass;
2368 objp->mtype.phys_info.drag = Player_ship->drag;
2369 // objp->mtype.phys_info.flags &= ~(PF_TURNROLL | PF_LEVELLING | PF_WIGGLE | PF_USES_THRUST);
2370 objp->mtype.phys_info.flags &= ~(PF_TURNROLL | PF_LEVELLING | PF_WIGGLE);
2374 objp->render_type = RT_POLYOBJ;
2375 objp->rtype.pobj_info.model_num = Player_ship->model_num; //what model is this?
2376 objp->rtype.pobj_info.subobj_flags = 0; //zero the flags
2377 for (i=0;i<MAX_SUBMODELS;i++)
2378 vm_angvec_zero(&objp->rtype.pobj_info.anim_angles[i]);
2380 //reset textures for this, if not player 0
2382 multi_reset_object_texture (objp);
2388 if (objp->type == OBJ_GHOST)
2389 objp->render_type = RT_NONE;
2393 void multi_reset_object_texture (object *objp)
2397 if (Game_mode & GM_TEAM)
2398 id = get_team(objp->id);
2403 objp->rtype.pobj_info.alt_textures=0;
2405 Assert(N_PLAYER_SHIP_TEXTURES == Polygon_models[objp->rtype.pobj_info.model_num].n_textures);
2407 for (i=0;i<N_PLAYER_SHIP_TEXTURES;i++)
2408 multi_player_textures[id-1][i] = ObjBitmaps[ObjBitmapPtrs[Polygon_models[objp->rtype.pobj_info.model_num].first_texture+i]];
2410 multi_player_textures[id-1][4] = ObjBitmaps[ObjBitmapPtrs[First_multi_bitmap_num+(id-1)*2]];
2411 multi_player_textures[id-1][5] = ObjBitmaps[ObjBitmapPtrs[First_multi_bitmap_num+(id-1)*2+1]];
2413 objp->rtype.pobj_info.alt_textures = id;
2420 extern int TTRecv[];
2421 extern FILE *RecieveLogFile;
2424 multi_process_bigdata(char *buf, int len)
2426 // Takes a bunch of messages, check them for validity,
2427 // and pass them to multi_process_data.
2429 int type, sub_len, bytes_processed = 0;
2431 while( bytes_processed < len ) {
2432 type = buf[bytes_processed];
2434 if ( (type<0) || (type>MULTI_MAX_TYPE)) {
2435 mprintf( (1, "multi_process_bigdata: Invalid packet type %d!\n", type ));
2438 sub_len = message_length[type];
2440 Assert(sub_len > 0);
2442 if ( (bytes_processed+sub_len) > len ) {
2443 mprintf( (1, "multi_process_bigdata: packet type %d too short (%d>%d)!\n", type, (bytes_processed+sub_len), len ));
2448 multi_process_data(&buf[bytes_processed], sub_len);
2449 bytes_processed += sub_len;
2454 // Part 2 : Functions that send communication messages to inform the other
2455 // players of something we did.
2459 multi_send_fire(void)
2461 if (!Network_laser_fired)
2464 multibuf[0] = (char)MULTI_FIRE;
2465 multibuf[1] = (char)Player_num;
2466 multibuf[2] = (char)Network_laser_gun;
2467 multibuf[3] = (char)Network_laser_level;
2468 multibuf[4] = (char)Network_laser_flags;
2469 multibuf[5] = (char)Network_laser_fired;
2471 *(short *)(multibuf+6) = INTEL_SHORT(Network_laser_track);
2473 multi_send_data(multibuf, 8, 0);
2475 Network_laser_fired = 0;
2479 multi_send_destroy_controlcen(int objnum, int player)
2481 if (player == Player_num)
2482 HUD_init_message(TXT_YOU_DEST_CONTROL);
2483 else if ((player > 0) && (player < N_players))
2484 HUD_init_message("%s %s", Players[player].callsign, TXT_HAS_DEST_CONTROL);
2486 HUD_init_message(TXT_CONTROL_DESTROYED);
2488 multibuf[0] = (char)MULTI_CONTROLCEN;
2489 *(ushort *)(multibuf+1) = INTEL_SHORT(objnum);
2490 multibuf[3] = player;
2491 multi_send_data(multibuf, 4, 2);
2494 void multi_send_drop_marker (int player,vms_vector position,char messagenum,char text[])
2498 if (player<N_players)
2500 mprintf ((0,"Sending MARKER drop!\n"));
2501 multibuf[0]=(char)MULTI_MARKER;
2502 multibuf[1]=(char)player;
2503 multibuf[2]=messagenum;
2504 *(fix *)(multibuf+3)=INTEL_INT(position.x);
2505 *(fix *)(multibuf+7)=INTEL_INT(position.y);
2506 *(fix *)(multibuf+11)=INTEL_INT(position.z);
2508 multibuf[15+i]=text[i];
2510 multi_send_data(multibuf, 55, 1);
2514 multi_send_endlevel_start(int secret)
2516 multibuf[0] = (char)MULTI_ENDLEVEL_START;
2517 multibuf[1] = Player_num;
2518 multibuf[2] = (char)secret;
2520 if ((secret) && !multi_goto_secret)
2521 multi_goto_secret = 1;
2522 else if (!multi_goto_secret)
2523 multi_goto_secret = 2;
2525 multi_send_data(multibuf, 3, 1);
2526 if (Game_mode & GM_NETWORK)
2528 Players[Player_num].connected = 5;
2529 network_send_endlevel_packet();
2534 multi_send_player_explode(char type)
2539 Assert( (type == MULTI_PLAYER_DROP) || (type == MULTI_PLAYER_EXPLODE) );
2541 multi_send_position(Players[Player_num].objnum);
2543 if (Network_send_objects)
2545 mprintf((0, "Resetting object sync due to player explosion.\n"));
2546 Network_send_objnum = -1;
2549 multibuf[count++] = type;
2550 multibuf[count++] = Player_num;
2552 *(ushort *)(multibuf+count) = INTEL_SHORT((ushort)Players[Player_num].primary_weapon_flags);
2554 *(ushort *)(multibuf+count) = INTEL_SHORT((ushort)Players[Player_num].secondary_weapon_flags);
2556 multibuf[count++] = (char)Players[Player_num].laser_level;
2558 multibuf[count++] = (char)Players[Player_num].secondary_ammo[HOMING_INDEX];
2559 multibuf[count++] = (char)Players[Player_num].secondary_ammo[CONCUSSION_INDEX];
2560 multibuf[count++] = (char)Players[Player_num].secondary_ammo[SMART_INDEX];
2561 multibuf[count++] = (char)Players[Player_num].secondary_ammo[MEGA_INDEX];
2562 multibuf[count++] = (char)Players[Player_num].secondary_ammo[PROXIMITY_INDEX];
2564 multibuf[count++] = (char)Players[Player_num].secondary_ammo[SMISSILE1_INDEX];
2565 multibuf[count++] = (char)Players[Player_num].secondary_ammo[GUIDED_INDEX];
2566 multibuf[count++] = (char)Players[Player_num].secondary_ammo[SMART_MINE_INDEX];
2567 multibuf[count++] = (char)Players[Player_num].secondary_ammo[SMISSILE4_INDEX];
2568 multibuf[count++] = (char)Players[Player_num].secondary_ammo[SMISSILE5_INDEX];
2570 *(ushort *)(multibuf+count) = INTEL_SHORT( (ushort)Players[Player_num].primary_ammo[VULCAN_INDEX] );
2572 *(ushort *)(multibuf+count) = INTEL_SHORT( (ushort)Players[Player_num].primary_ammo[GAUSS_INDEX] );
2574 *(uint *)(multibuf+count) = INTEL_INT( (uint)Players[Player_num].flags );
2577 multibuf[count++] = Net_create_loc;
2579 Assert(Net_create_loc <= MAX_NET_CREATE_OBJECTS);
2581 memset(multibuf+count, -1, MAX_NET_CREATE_OBJECTS*sizeof(short));
2583 mprintf((0, "Created %d explosion objects.\n", Net_create_loc));
2585 for (i = 0; i < Net_create_loc; i++)
2587 if (Net_create_objnums[i] <= 0) {
2588 Int3(); // Illegal value in created egg object numbers
2593 *(short *)(multibuf+count) = INTEL_SHORT( (short)Net_create_objnums[i] ); count += 2;
2595 // We created these objs so our local number = the network number
2596 map_objnum_local_to_local((short)Net_create_objnums[i]);
2601 // mprintf((1, "explode message size = %d, max = %d.\n", count, message_length[MULTI_PLAYER_EXPLODE]));
2603 if (count > message_length[MULTI_PLAYER_EXPLODE])
2608 multi_send_data(multibuf, message_length[MULTI_PLAYER_EXPLODE], 2);
2609 if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)
2610 multi_send_decloak();
2611 if (Game_mode & GM_MULTI_ROBOTS)
2612 multi_strip_robots(Player_num);
2615 extern ubyte Secondary_weapon_to_powerup[];
2616 extern ubyte Primary_weapon_to_powerup[];
2618 // put a lid on how many objects will be spewed by an exploding player
2619 // to prevent rampant powerups in netgames
2621 void multi_cap_objects ()
2626 if (!(Game_mode & GM_NETWORK))
2629 for (index=0;index<MAX_PRIMARY_WEAPONS;index++)
2631 type=Primary_weapon_to_powerup[index];
2632 if (PowerupsInMine[(int)type]>=MaxPowerupsAllowed[(int)type])
2633 if(Players[Player_num].primary_weapon_flags & (1 << index))
2635 mprintf ((0,"PIM=%d MPA=%d\n",PowerupsInMine[(int)type],MaxPowerupsAllowed[(int)type]));
2636 mprintf ((0,"Killing a primary cuz there's too many! (%d)\n",(int)type));
2637 Players[Player_num].primary_weapon_flags&=(~(1 << index));
2642 // Don't do the adjustment stuff for Hoard mode
2643 if (!(Game_mode & GM_HOARD))
2644 Players[Player_num].secondary_ammo[2]/=4;
2646 Players[Player_num].secondary_ammo[7]/=4;
2648 for (index=0;index<MAX_SECONDARY_WEAPONS;index++)
2650 if ((Game_mode & GM_HOARD) && index==PROXIMITY_INDEX)
2653 type=Secondary_weapon_to_powerup[index];
2655 if ((Players[Player_num].secondary_ammo[index]+PowerupsInMine[(int)type])>MaxPowerupsAllowed[(int)type])
2657 if (MaxPowerupsAllowed[(int)type]-PowerupsInMine[(int)type]<0)
2658 Players[Player_num].secondary_ammo[index]=0;
2660 Players[Player_num].secondary_ammo[index]=(MaxPowerupsAllowed[(int)type]-PowerupsInMine[(int)type]);
2662 mprintf ((0,"Hey! I killed secondary type %d because PIM=%d MPA=%d\n",(int)type,PowerupsInMine[(int)type],MaxPowerupsAllowed[(int)type]));
2666 if (!(Game_mode & GM_HOARD))
2667 Players[Player_num].secondary_ammo[2]*=4;
2668 Players[Player_num].secondary_ammo[7]*=4;
2670 if (Players[Player_num].laser_level > MAX_LASER_LEVEL)
2671 if (PowerupsInMine[POW_SUPER_LASER]+1 > MaxPowerupsAllowed[POW_SUPER_LASER])
2672 Players[Player_num].laser_level=0;
2674 if (Players[Player_num].flags & PLAYER_FLAGS_QUAD_LASERS)
2675 if (PowerupsInMine[POW_QUAD_FIRE]+1 > MaxPowerupsAllowed[POW_QUAD_FIRE])
2676 Players[Player_num].flags&=(~PLAYER_FLAGS_QUAD_LASERS);
2678 if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)
2679 if (PowerupsInMine[POW_CLOAK]+1 > MaxPowerupsAllowed[POW_CLOAK])
2680 Players[Player_num].flags&=(~PLAYER_FLAGS_CLOAKED);
2682 if (Players[Player_num].flags & PLAYER_FLAGS_MAP_ALL)
2683 if (PowerupsInMine[POW_FULL_MAP]+1 > MaxPowerupsAllowed[POW_FULL_MAP])
2684 Players[Player_num].flags&=(~PLAYER_FLAGS_MAP_ALL);
2686 if (Players[Player_num].flags & PLAYER_FLAGS_AFTERBURNER)
2687 if (PowerupsInMine[POW_AFTERBURNER]+1 > MaxPowerupsAllowed[POW_AFTERBURNER])
2688 Players[Player_num].flags&=(~PLAYER_FLAGS_AFTERBURNER);
2690 if (Players[Player_num].flags & PLAYER_FLAGS_AMMO_RACK)
2691 if (PowerupsInMine[POW_AMMO_RACK]+1 > MaxPowerupsAllowed[POW_AMMO_RACK])
2692 Players[Player_num].flags&=(~PLAYER_FLAGS_AMMO_RACK);
2694 if (Players[Player_num].flags & PLAYER_FLAGS_CONVERTER)
2695 if (PowerupsInMine[POW_CONVERTER]+1 > MaxPowerupsAllowed[POW_CONVERTER])
2696 Players[Player_num].flags&=(~PLAYER_FLAGS_CONVERTER);
2698 if (Players[Player_num].flags & PLAYER_FLAGS_HEADLIGHT)
2699 if (PowerupsInMine[POW_HEADLIGHT]+1 > MaxPowerupsAllowed[POW_HEADLIGHT])
2700 Players[Player_num].flags&=(~PLAYER_FLAGS_HEADLIGHT);
2702 if (Game_mode & GM_CAPTURE)
2704 if (Players[Player_num].flags & PLAYER_FLAGS_FLAG)
2706 if (get_team(Player_num)==TEAM_RED)
2707 flagtype=POW_FLAG_BLUE;
2709 flagtype=POW_FLAG_RED;
2711 if (PowerupsInMine[(int)flagtype]+1 > MaxPowerupsAllowed[(int)flagtype])
2712 Players[Player_num].flags&=(~PLAYER_FLAGS_FLAG);
2718 // adds players inventory to multi cap
2720 void multi_adjust_cap_for_player (int pnum)
2726 if (!(Game_mode & GM_NETWORK))
2729 for (index=0;index<MAX_PRIMARY_WEAPONS;index++)
2731 type=Primary_weapon_to_powerup[index];
2732 if (Players[pnum].primary_weapon_flags & (1 << index))
2733 MaxPowerupsAllowed[(int)type]++;
2736 for (index=0;index<MAX_SECONDARY_WEAPONS;index++)
2738 type=Secondary_weapon_to_powerup[index];
2739 MaxPowerupsAllowed[(int)type]+=Players[pnum].secondary_ammo[index];
2742 if (Players[pnum].laser_level > MAX_LASER_LEVEL)
2743 MaxPowerupsAllowed[POW_SUPER_LASER]++;
2745 if (Players[pnum].flags & PLAYER_FLAGS_QUAD_LASERS)
2746 MaxPowerupsAllowed[POW_QUAD_FIRE]++;
2748 if (Players[pnum].flags & PLAYER_FLAGS_CLOAKED)
2749 MaxPowerupsAllowed[POW_CLOAK]++;
2751 if (Players[pnum].flags & PLAYER_FLAGS_MAP_ALL)
2752 MaxPowerupsAllowed[POW_FULL_MAP]++;
2754 if (Players[pnum].flags & PLAYER_FLAGS_AFTERBURNER)
2755 MaxPowerupsAllowed[POW_AFTERBURNER]++;
2757 if (Players[pnum].flags & PLAYER_FLAGS_AMMO_RACK)
2758 MaxPowerupsAllowed[POW_AMMO_RACK]++;
2760 if (Players[pnum].flags & PLAYER_FLAGS_CONVERTER)
2761 MaxPowerupsAllowed[POW_CONVERTER]++;
2763 if (Players[pnum].flags & PLAYER_FLAGS_HEADLIGHT)
2764 MaxPowerupsAllowed[POW_HEADLIGHT]++;
2767 void multi_adjust_remote_cap (int pnum)
2773 if (!(Game_mode & GM_NETWORK))
2776 for (index=0;index<MAX_PRIMARY_WEAPONS;index++)
2778 type=Primary_weapon_to_powerup[index];
2779 if (Players[pnum].primary_weapon_flags & (1 << index))
2780 PowerupsInMine[(int)type]++;
2783 for (index=0;index<MAX_SECONDARY_WEAPONS;index++)
2785 type=Secondary_weapon_to_powerup[index];
2787 if ((Game_mode & GM_HOARD) && index==2)
2790 if (index==2 || index==7) // PROX or SMARTMINES? Those bastards...
2791 PowerupsInMine[(int)type]+=(Players[pnum].secondary_ammo[index]/4);
2793 PowerupsInMine[(int)type]+=Players[pnum].secondary_ammo[index];
2797 if (Players[pnum].laser_level > MAX_LASER_LEVEL)
2798 PowerupsInMine[POW_SUPER_LASER]++;
2800 if (Players[pnum].flags & PLAYER_FLAGS_QUAD_LASERS)
2801 PowerupsInMine[POW_QUAD_FIRE]++;
2803 if (Players[pnum].flags & PLAYER_FLAGS_CLOAKED)
2804 PowerupsInMine[POW_CLOAK]++;
2806 if (Players[pnum].flags & PLAYER_FLAGS_MAP_ALL)
2807 PowerupsInMine[POW_FULL_MAP]++;
2809 if (Players[pnum].flags & PLAYER_FLAGS_AFTERBURNER)
2810 PowerupsInMine[POW_AFTERBURNER]++;
2812 if (Players[pnum].flags & PLAYER_FLAGS_AMMO_RACK)
2813 PowerupsInMine[POW_AMMO_RACK]++;
2815 if (Players[pnum].flags & PLAYER_FLAGS_CONVERTER)
2816 PowerupsInMine[POW_CONVERTER]++;
2818 if (Players[pnum].flags & PLAYER_FLAGS_HEADLIGHT)
2819 PowerupsInMine[POW_HEADLIGHT]++;
2824 multi_send_message(void)
2827 if (Network_message_reciever != -1)
2829 multibuf[loc] = (char)MULTI_MESSAGE; loc += 1;
2830 multibuf[loc] = (char)Player_num; loc += 1;
2831 strncpy(multibuf+loc, Network_message, MAX_MESSAGE_LEN); loc += MAX_MESSAGE_LEN;
2832 multibuf[loc-1] = '\0';
2833 multi_send_data(multibuf, loc, 0);
2834 Network_message_reciever = -1;
2839 multi_send_reappear()
2841 multibuf[0] = (char)MULTI_REAPPEAR;
2842 *(short *)(multibuf+1) = INTEL_SHORT(Players[Player_num].objnum);
2844 multi_send_data(multibuf, 3, 2);
2845 PKilledFlags[Player_num]=0;
2849 multi_send_position(int objnum)
2856 if (Game_mode & GM_NETWORK) {
2860 multibuf[count++] = (char)MULTI_POSITION;
2862 create_shortpos((shortpos *)(multibuf+count), Objects+objnum,0);
2863 count += sizeof(shortpos);
2865 create_shortpos(&sp, Objects+objnum, 1);
2866 memcpy(&(multibuf[count]), (ubyte *)(sp.bytemat), 9);
2868 memcpy(&(multibuf[count]), (ubyte *)&(sp.xo), 14);
2872 multi_send_data(multibuf, count, 0);
2876 multi_send_kill(int objnum)
2878 // I died, tell the world.
2883 Assert(Objects[objnum].id == Player_num);
2884 killer_objnum = Players[Player_num].killer_objnum;
2886 multi_compute_kill(killer_objnum, objnum);
2888 multibuf[0] = (char)MULTI_KILL; count += 1;
2889 multibuf[1] = Player_num; count += 1;
2890 if (killer_objnum > -1) {
2891 short s; // do it with variable since INTEL_SHORT won't work on return val from function.
2893 s = (short)objnum_local_to_remote(killer_objnum, (byte *)&multibuf[count+2]);
2894 *(short *)(multibuf+count) = INTEL_SHORT(s);
2898 *(short *)(multibuf+count) = INTEL_SHORT((short)-1);
2899 multibuf[count+2] = (char)-1;
2902 multi_send_data(multibuf, count, 1);
2905 if (Game_mode & GM_MULTI_ROBOTS)
2906 multi_strip_robots(Player_num);
2911 multi_send_remobj(int objnum)
2913 // Tell the other guy to remove an object from his list
2916 short remote_objnum;
2918 if (Objects[objnum].type==OBJ_POWERUP && (Game_mode & GM_NETWORK))
2920 if (PowerupsInMine[Objects[objnum].id] > 0)
2922 PowerupsInMine[Objects[objnum].id]--;
2923 if (multi_powerup_is_4pack (Objects[objnum].id))
2925 mprintf ((0,"Hey babe! Doing that wacky 4 pack stuff."));
2927 if (PowerupsInMine[Objects[objnum].id-1]-4<0)
2928 PowerupsInMine[Objects[objnum].id-1]=0;
2930 PowerupsInMine[Objects[objnum].id-1]-=4;
2936 multibuf[0] = (char)MULTI_REMOVE_OBJECT;
2938 remote_objnum = objnum_local_to_remote((short)objnum, &obj_owner);
2940 *(short *)(multibuf+1) = INTEL_SHORT(remote_objnum); // Map to network objnums
2942 multibuf[3] = obj_owner;
2944 // mprintf((0, "multi_send_remobj: %d = %d owner %d.\n", objnum, remote_objnum, obj_owner));
2946 multi_send_data(multibuf, 4, 0);
2948 if (Network_send_objects && network_objnum_is_past(objnum))
2950 mprintf((0, "Resetting object sync due to object removal.\n"));
2951 Network_send_objnum = -1;
2956 multi_send_quit(int why)
2958 // I am quitting the game, tell the other guy the bad news.
2960 Assert (why == MULTI_QUIT);
2962 multibuf[0] = (char)why;
2963 multibuf[1] = Player_num;
2964 multi_send_data(multibuf, 2, 1);
2969 multi_send_cloak(void)
2971 // Broadcast a change in our pflags (made to support cloaking)
2973 multibuf[0] = MULTI_CLOAK;
2974 multibuf[1] = (char)Player_num;
2976 multi_send_data(multibuf, 2, 1);
2979 if (Game_mode & GM_MULTI_ROBOTS)
2980 multi_strip_robots(Player_num);
2985 multi_send_decloak(void)
2987 // Broadcast a change in our pflags (made to support cloaking)
2989 multibuf[0] = MULTI_DECLOAK;
2990 multibuf[1] = (char)Player_num;
2992 multi_send_data(multibuf, 2, 1);
2996 multi_send_door_open(int segnum, int side,ubyte flag)
2998 // When we open a door make sure everyone else opens that door
3000 multibuf[0] = MULTI_DOOR_OPEN;
3001 *(short *)(multibuf+1) = INTEL_SHORT( (short)segnum );
3002 multibuf[3] = (byte)side;
3005 multi_send_data(multibuf, 5, 2);
3008 extern void network_send_naked_packet (char *,short,int);
3011 multi_send_door_open_specific(int pnum,int segnum, int side,ubyte flag)
3013 // For sending doors only to a specific person (usually when they're joining)
3015 Assert (Game_mode & GM_NETWORK);
3016 // Assert (pnum>-1 && pnum<N_players);
3018 multibuf[0] = MULTI_DOOR_OPEN;
3019 *(short *)(multibuf+1) = INTEL_SHORT( (short)segnum );
3020 multibuf[3] = (byte)side;
3023 network_send_naked_packet(multibuf, 5, pnum);
3027 // Part 3 : Functions that change or prepare the game for multiplayer use.
3028 // Not including functions needed to syncronize or start the
3029 // particular type of multiplayer game. Includes preparing the
3030 // mines, player structures, etc.
3033 multi_send_create_explosion(int pnum)
3035 // Send all data needed to create a remote explosion
3039 multibuf[count] = MULTI_CREATE_EXPLOSION; count += 1;
3040 multibuf[count] = (byte)pnum; count += 1;
3044 multi_send_data(multibuf, count, 0);
3048 multi_send_controlcen_fire(vms_vector *to_goal, int best_gun_num, int objnum)
3051 vms_vector swapped_vec;
3055 multibuf[count] = MULTI_CONTROLCEN_FIRE; count += 1;
3057 memcpy(multibuf+count, to_goal, 12); count += 12;
3059 swapped_vec.x = (fix)INTEL_INT( (int)to_goal->x );
3060 swapped_vec.y = (fix)INTEL_INT( (int)to_goal->y );
3061 swapped_vec.z = (fix)INTEL_INT( (int)to_goal->z );
3062 memcpy(multibuf+count, &swapped_vec, 12); count += 12;
3064 multibuf[count] = (char)best_gun_num; count += 1;
3065 *(short *)(multibuf+count) = INTEL_SHORT( (short)objnum ); count += 2;
3068 multi_send_data(multibuf, count, 0);
3072 multi_send_create_powerup(int powerup_type, int segnum, int objnum, vms_vector *pos)
3074 // Create a powerup on a remote machine, used for remote
3075 // placement of used powerups like missiles and cloaking
3079 vms_vector swapped_vec;
3083 if (Game_mode & GM_NETWORK)
3084 PowerupsInMine[powerup_type]++;
3086 multibuf[count] = MULTI_CREATE_POWERUP; count += 1;
3087 multibuf[count] = Player_num; count += 1;
3088 multibuf[count] = powerup_type; count += 1;
3089 *(short *)(multibuf+count) = INTEL_SHORT( (short)segnum ); count += 2;
3090 *(short *)(multibuf+count) = INTEL_SHORT( (short)objnum ); count += 2;
3092 *(vms_vector *)(multibuf+count) = *pos; count += sizeof(vms_vector);
3094 swapped_vec.x = (fix)INTEL_INT( (int)pos->x );
3095 swapped_vec.y = (fix)INTEL_INT( (int)pos->y );
3096 swapped_vec.z = (fix)INTEL_INT( (int)pos->z );
3097 memcpy(multibuf+count, &swapped_vec, 12); count += 12;
3101 multi_send_data(multibuf, count, 2);
3103 if (Network_send_objects && network_objnum_is_past(objnum))
3105 mprintf((0, "Resetting object sync due to powerup creation.\n"));
3106 Network_send_objnum = -1;
3109 mprintf((0, "Creating powerup type %d in segment %i.\n", powerup_type, segnum));
3110 map_objnum_local_to_local(objnum);
3114 multi_send_play_sound(int sound_num, fix volume)
3117 multibuf[count] = MULTI_PLAY_SOUND; count += 1;
3118 multibuf[count] = Player_num; count += 1;
3119 multibuf[count] = (char)sound_num; count += 1;
3120 multibuf[count] = (char)(volume >> 12); count += 1;
3123 multi_send_data(multibuf, count, 0);
3127 multi_send_audio_taunt(int taunt_num)
3129 return; // Taken out, awaiting sounds..
3132 int audio_taunts[4] = {
3133 SOUND_CONTROL_CENTER_WARNING_SIREN,
3134 SOUND_HOSTAGE_RESCUED,
3135 SOUND_REFUEL_STATION_GIVING_FUEL,
3140 Assert(taunt_num >= 0);
3141 Assert(taunt_num < 4);
3143 digi_play_sample( audio_taunts[taunt_num], F1_0 );
3144 multi_send_play_sound(audio_taunts[taunt_num], F1_0);
3149 multi_send_score(void)
3151 // Send my current score to all other players so it will remain
3155 if (Game_mode & GM_MULTI_COOP) {
3156 multi_sort_kill_list();
3157 multibuf[count] = MULTI_SCORE; count += 1;
3158 multibuf[count] = Player_num; count += 1;
3159 *(int *)(multibuf+count) = INTEL_INT( Players[Player_num].score ); count += 4;
3160 multi_send_data(multibuf, count, 0);
3166 multi_send_save_game(ubyte slot, uint id, char * desc)
3170 multibuf[count] = MULTI_SAVE_GAME; count += 1;
3171 multibuf[count] = slot; count += 1; // Save slot=0
3172 *(uint *)(multibuf+count) = INTEL_INT( id ); count += 4; // Save id
3173 memcpy( &multibuf[count], desc, 20 ); count += 20;
3175 multi_send_data(multibuf, count, 2);
3179 multi_send_restore_game(ubyte slot, uint id)
3183 multibuf[count] = MULTI_RESTORE_GAME; count += 1;
3184 multibuf[count] = slot; count += 1; // Save slot=0
3185 *(uint *)(multibuf+count) = INTEL_INT( id ); count += 4; // Save id
3187 multi_send_data(multibuf, count, 2);
3191 multi_send_netplayer_stats_request(ubyte player_num)
3195 multibuf[count] = MULTI_REQ_PLAYER; count += 1;
3196 multibuf[count] = player_num; count += 1;
3198 multi_send_data(multibuf, count, 0 );
3202 multi_send_trigger(int triggernum)
3204 // Send an even to trigger something in the mine
3208 multibuf[count] = MULTI_TRIGGER; count += 1;
3209 multibuf[count] = Player_num; count += 1;
3210 multibuf[count] = (ubyte)triggernum; count += 1;
3212 mprintf ((0,"Sending trigger %d\n",triggernum));
3214 multi_send_data(multibuf, count, 1);
3215 // multi_send_data(multibuf, count, 1); // twice?
3219 multi_send_hostage_door_status(int wallnum)
3221 // Tell the other player what the hit point status of a hostage door
3226 Assert(Walls[wallnum].type == WALL_BLASTABLE);
3228 multibuf[count] = MULTI_HOSTAGE_DOOR; count += 1;
3229 *(short *)(multibuf+count) = INTEL_SHORT( (short)wallnum ); count += 2;
3230 *(fix *)(multibuf+count) = (fix)INTEL_INT( (int)Walls[wallnum].hps ); count += 4;
3232 // mprintf((0, "Door %d damaged by %f points.\n", wallnum, f2fl(Walls[wallnum].hps)));
3234 multi_send_data(multibuf, count, 0);
3237 extern int ConsistencyCount;
3238 extern int Drop_afterburner_blob_flag;
3242 void multi_prep_level(void)
3244 // Do any special stuff to the level required for serial games
3245 // before we begin playing in it.
3247 // Player_num MUST be set before calling this procedure.
3249 // This function must be called before checksuming the Object array,
3250 // since the resulting checksum with depend on the value of Player_num
3251 // at the time this is called.
3254 int cloak_count, inv_count;
3256 Assert(Game_mode & GM_MULTI);
3258 Assert(NumNetPlayerPositions > 0);
3262 Drop_afterburner_blob_flag=0;
3265 for (i=0;i<MAX_NUM_NET_PLAYERS;i++)
3268 for (i = 0; i < NumNetPlayerPositions; i++)
3270 if (i != Player_num)
3271 Objects[Players[i].objnum].control_type = CT_REMOTE;
3272 Objects[Players[i].objnum].movement_type = MT_PHYSICS;
3273 multi_reset_player_object(&Objects[Players[i].objnum]);
3274 LastPacketTime[i] = 0;
3278 for (i = 0; i < MAX_ROBOTS_CONTROLLED; i++)
3280 robot_controlled[i] = -1;
3281 robot_agitation[i] = 0;
3286 Viewer = ConsoleObject = &Objects[Players[Player_num].objnum];
3288 if (!(Game_mode & GM_MULTI_COOP))
3290 multi_delete_extra_objects(); // Removes monsters from level
3293 if (Game_mode & GM_MULTI_ROBOTS)
3295 multi_set_robot_ai(); // Set all Robot AI to types we can cope with
3298 if (Game_mode & GM_NETWORK)
3300 multi_adjust_cap_for_player(Player_num);
3301 multi_send_powerup_update();
3302 ng=1; // ng means network game
3308 for (i=0; i<=Highest_object_index; i++)
3312 if ((Objects[i].type == OBJ_HOSTAGE) && !(Game_mode & GM_MULTI_COOP))
3314 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);
3318 Objects[objnum].rtype.vclip_info.vclip_num = Powerup_info[POW_SHIELD_BOOST].vclip_num;
3319 Objects[objnum].rtype.vclip_info.frametime = Vclip[Objects[objnum].rtype.vclip_info.vclip_num].frame_time;
3320 Objects[objnum].rtype.vclip_info.framenum = 0;
3321 Objects[objnum].mtype.phys_info.drag = 512; //1024;
3322 Objects[objnum].mtype.phys_info.mass = F1_0;
3323 vm_vec_zero(&Objects[objnum].mtype.phys_info.velocity);
3328 if (Objects[i].type == OBJ_POWERUP)
3330 if (Objects[i].id == POW_EXTRA_LIFE)
3332 if (ng && !Netgame.DoInvulnerability)
3334 Objects[i].id = POW_SHIELD_BOOST;
3335 Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num;
3336 Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time;
3340 Objects[i].id = POW_INVULNERABILITY;
3341 Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num;
3342 Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time;
3347 if (!(Game_mode & GM_MULTI_COOP))
3348 if ((Objects[i].id >= POW_KEY_BLUE) && (Objects[i].id <= POW_KEY_GOLD))
3350 Objects[i].id = POW_SHIELD_BOOST;
3351 Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num;
3352 Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time;
3355 if (Objects[i].id == POW_INVULNERABILITY) {
3356 if (inv_count >= 3 || (ng && !Netgame.DoInvulnerability)) {
3357 mprintf((0, "Bashing Invulnerability object #%i to shield.\n", i));
3358 Objects[i].id = POW_SHIELD_BOOST;
3359 Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num;
3360 Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time;
3365 if (Objects[i].id == POW_CLOAK) {
3366 if (cloak_count >= 3 || (ng && !Netgame.DoCloak)) {
3367 mprintf((0, "Bashing Cloak object #%i to shield.\n", i));
3368 Objects[i].id = POW_SHIELD_BOOST;
3369 Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num;
3370 Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time;
3375 if (Objects[i].id == POW_AFTERBURNER && ng && !Netgame.DoAfterburner)
3376 bash_to_shield (i,"afterburner");
3377 if (Objects[i].id == POW_FUSION_WEAPON && ng && !Netgame.DoFusions)
3378 bash_to_shield (i,"fusion");
3379 if (Objects[i].id == POW_PHOENIX_WEAPON && ng && !Netgame.DoPhoenix)
3380 bash_to_shield (i,"phoenix");
3382 if (Objects[i].id == POW_HELIX_WEAPON && ng && !Netgame.DoHelix)
3383 bash_to_shield (i,"helix");
3385 if (Objects[i].id == POW_MEGA_WEAPON && ng && !Netgame.DoMegas)
3386 bash_to_shield (i,"mega");
3388 if (Objects[i].id == POW_SMARTBOMB_WEAPON && ng && !Netgame.DoSmarts)
3389 bash_to_shield (i,"smartmissile");
3391 if (Objects[i].id == POW_GAUSS_WEAPON && ng && !Netgame.DoGauss)
3392 bash_to_shield (i,"gauss");
3394 if (Objects[i].id == POW_VULCAN_WEAPON && ng && !Netgame.DoVulcan)
3395 bash_to_shield (i,"vulcan");
3397 if (Objects[i].id == POW_PLASMA_WEAPON && ng && !Netgame.DoPlasma)
3398 bash_to_shield (i,"plasma");
3400 if (Objects[i].id == POW_OMEGA_WEAPON && ng && !Netgame.DoOmega)
3401 bash_to_shield (i,"omega");
3403 if (Objects[i].id == POW_SUPER_LASER && ng && !Netgame.DoSuperLaser)
3404 bash_to_shield (i,"superlaser");
3406 if (Objects[i].id == POW_PROXIMITY_WEAPON && ng && !Netgame.DoProximity)
3407 bash_to_shield (i,"proximity");
3409 // Special: Make all proximity bombs into shields if in hoard mode because
3410 // we use the proximity slot in the player struct to signify how many orbs
3413 if (Objects[i].id == POW_PROXIMITY_WEAPON && ng && (Game_mode & GM_HOARD))
3414 bash_to_shield (i,"proximity");
3416 if (Objects[i].id==POW_VULCAN_AMMO && ng && (!Netgame.DoVulcan && !Netgame.DoGauss))
3417 bash_to_shield(i,"vulcan ammo");
3419 if (Objects[i].id == POW_SPREADFIRE_WEAPON && ng && !Netgame.DoSpread)
3420 bash_to_shield (i,"spread");
3421 if (Objects[i].id == POW_SMART_MINE && ng && !Netgame.DoSmartMine)
3422 bash_to_shield (i,"smartmine");
3423 if (Objects[i].id == POW_SMISSILE1_1 && ng && !Netgame.DoFlash)
3424 bash_to_shield (i,"flash");
3425 if (Objects[i].id == POW_SMISSILE1_4 && ng && !Netgame.DoFlash)
3426 bash_to_shield (i,"flash");
3427 if (Objects[i].id == POW_GUIDED_MISSILE_1 && ng && !Netgame.DoGuided)
3428 bash_to_shield (i,"guided");
3429 if (Objects[i].id == POW_GUIDED_MISSILE_4 && ng && !Netgame.DoGuided)
3430 bash_to_shield (i,"guided");
3431 if (Objects[i].id == POW_EARTHSHAKER_MISSILE && ng && !Netgame.DoEarthShaker)
3432 bash_to_shield (i,"earth");
3433 if (Objects[i].id == POW_MERCURY_MISSILE_1 && ng && !Netgame.DoMercury)
3434 bash_to_shield (i,"Mercury");
3435 if (Objects[i].id == POW_MERCURY_MISSILE_4 && ng && !Netgame.DoMercury)
3436 bash_to_shield (i,"Mercury");
3437 if (Objects[i].id == POW_CONVERTER && ng && !Netgame.DoConverter)
3438 bash_to_shield (i,"Converter");
3439 if (Objects[i].id == POW_AMMO_RACK && ng && !Netgame.DoAmmoRack)
3440 bash_to_shield (i,"Ammo rack");
3441 if (Objects[i].id == POW_HEADLIGHT && ng && !Netgame.DoHeadlight)
3442 bash_to_shield (i,"Headlight");
3443 if (Objects[i].id == POW_LASER && ng && !Netgame.DoLaserUpgrade)
3444 bash_to_shield (i,"Laser powerup");
3445 if (Objects[i].id == POW_HOMING_AMMO_1 && ng && !Netgame.DoHoming)
3446 bash_to_shield (i,"Homing");
3447 if (Objects[i].id == POW_HOMING_AMMO_4 && ng && !Netgame.DoHoming)
3448 bash_to_shield (i,"Homing");
3449 if (Objects[i].id == POW_QUAD_FIRE && ng && !Netgame.DoQuadLasers)
3450 bash_to_shield (i,"Quad Lasers");
3451 if (Objects[i].id == POW_FLAG_BLUE && !(Game_mode & GM_CAPTURE))
3452 bash_to_shield (i,"Blue flag");
3453 if (Objects[i].id == POW_FLAG_RED && !(Game_mode & GM_CAPTURE))
3454 bash_to_shield (i,"Red flag");
3458 if (Game_mode & GM_HOARD)
3461 if ((Game_mode & GM_CAPTURE) || (Game_mode & GM_HOARD))
3462 multi_apply_goal_textures();
3464 multi_sort_kill_list();
3466 multi_show_player_list();
3468 ConsoleObject->control_type = CT_FLYING;
3470 reset_player_object();
3474 int Goal_blue_segnum,Goal_red_segnum;
3476 void multi_apply_goal_textures()
3482 for (i=0; i <= Highest_segment_index; i++)
3485 seg2 = &Segment2s[i];
3487 if (seg2->special==SEGMENT_IS_GOAL_BLUE)
3490 Goal_blue_segnum = i;
3492 if (Game_mode & GM_HOARD)
3493 tex=find_goal_texture (TMI_GOAL_HOARD);
3495 tex=find_goal_texture (TMI_GOAL_BLUE);
3498 for (j = 0; j < 6; j++) {
3500 seg->sides[j].tmap_num=tex;
3502 seg->sides[j].uvls[v].l = i2f(100); //max out
3505 seg2->static_light = i2f(100); //make static light bright
3509 if (seg2->special==SEGMENT_IS_GOAL_RED)
3511 Goal_red_segnum = i;
3513 // Make both textures the same if Hoard mode
3515 if (Game_mode & GM_HOARD)
3516 tex=find_goal_texture (TMI_GOAL_HOARD);
3518 tex=find_goal_texture (TMI_GOAL_RED);
3521 for (j = 0; j < 6; j++) {
3523 seg->sides[j].tmap_num=tex;
3525 seg->sides[j].uvls[v].l = i2f(1000); //max out
3528 seg2->static_light = i2f(100); //make static light bright
3532 int find_goal_texture (ubyte t)
3536 for (i=0;i<NumTextures;i++)
3537 if (TmapInfo[i].flags & t)
3540 Int3(); // Hey, there is no goal texture for this PIG!!!!
3541 // Edit bitmaps.tbl and designate two textures to be RED and BLUE
3547 /* DPH: Moved to gameseq.c
3548 void bash_to_shield (int i,char *s)
3550 int type=Objects[i].id;
3552 mprintf((0, "Bashing %s object #%i to shield.\n",s, i));
3554 PowerupsInMine[type]=MaxPowerupsAllowed[type]=0;
3556 Objects[i].id = POW_SHIELD_BOOST;
3557 Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num;
3558 Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time;
3562 void multi_set_robot_ai(void)
3564 // Go through the objects array looking for robots and setting
3565 // them to certain supported types of NET AI behavior.
3569 // for (i = 0; i <= Highest_object_index; i++)
3571 // if (Objects[i].type == OBJ_ROBOT) {
3572 // Objects[i].ai_info.REMOTE_OWNER = -1;
3573 // if (Objects[i].ai_info.behavior == AIB_STATION)
3574 // Objects[i].ai_info.behavior = AIB_NORMAL;
3579 int multi_delete_extra_objects()
3585 // Go through the object list and remove any objects not used in
3586 // 'Anarchy!' games.
3588 // This function also prints the total number of available multiplayer
3589 // positions in this level, even though this should always be 8 or more!
3592 for (i=0;i<=Highest_object_index;i++) {
3593 if ((objp->type==OBJ_PLAYER) || (objp->type==OBJ_GHOST))
3595 else if ((objp->type==OBJ_ROBOT) && (Game_mode & GM_MULTI_ROBOTS))
3597 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) ) {
3598 // Before deleting object, if it's a robot, drop it's special powerup, if any
3599 if (objp->type == OBJ_ROBOT)
3600 if (objp->contains_count && (objp->contains_type == OBJ_POWERUP))
3601 object_create_egg(objp);
3610 void change_playernum_to( int new_Player_num )
3612 if (Player_num > -1)
3613 memcpy( Players[new_Player_num].callsign, Players[Player_num].callsign, CALLSIGN_LEN+1 );
3614 Player_num = new_Player_num;
3617 int multi_all_players_alive()
3620 for (i=0;i<N_players;i++)
3622 if (PKilledFlags[i] && Players[i].connected)
3628 void multi_initiate_save_game()
3635 if ((Endlevel_sequence) || (Control_center_destroyed))
3638 if (!multi_all_players_alive())
3640 HUD_init_message ("Can't save...all players must be alive!");
3644 // multi_send_netplayer_stats_request(255);
3649 slot = state_get_save_file(filename, desc, 1 );
3658 // Make a unique game id
3659 game_id = timer_get_fixed_seconds();
3660 game_id ^= N_players<<4;
3661 for (i=0; i<N_players; i++ )
3662 game_id ^= *(uint *)Players[i].callsign;
3663 if ( game_id == 0 ) game_id = 1; // 0 is invalid
3665 mprintf(( 1, "Game_id = %8x\n", game_id));
3666 multi_send_save_game(slot, game_id, desc );
3668 multi_save_game(slot,game_id, desc );
3671 extern int state_get_game_id(char *);
3673 void multi_initiate_restore_game()
3678 if ((Endlevel_sequence) || (Control_center_destroyed))
3681 if (!multi_all_players_alive())
3683 HUD_init_message ("Can't restore...all players must be alive!");
3688 slot = state_get_restore_file(filename,1);
3693 state_game_id=state_get_game_id (filename);
3699 multi_send_restore_game(slot,state_game_id);
3701 multi_restore_game(slot,state_game_id);
3704 void multi_save_game(ubyte slot, uint id, char *desc)
3708 if ((Endlevel_sequence) || (Control_center_destroyed))
3712 sprintf( filename, "%s.mg%d", Players[Player_num].callsign, slot );
3714 sprintf( filename, ":Players:%s.mg%d", Players[Player_num].callsign, slot );
3716 mprintf(( 0, "Save game %x on slot %d\n", id, slot ));
3717 HUD_init_message( "Saving game #%d, '%s'", slot, desc );
3720 state_save_all_sub(filename, desc, 0 );
3723 void multi_restore_game(ubyte slot, uint id)
3726 player saved_player;
3730 if ((Endlevel_sequence) || (Control_center_destroyed))
3733 mprintf(( 0, "Restore game %x from slot %d\n", id, slot ));
3734 saved_player = Players[Player_num];
3736 sprintf( filename, "%s.mg%d", Players[Player_num].callsign, slot );
3738 sprintf( filename, ":Players:%s.mg%d", Players[Player_num].callsign, slot );
3741 for (i=0;i<N_players;i++)
3742 multi_strip_robots(i);
3744 thisid=state_get_game_id (filename);
3747 multi_bad_restore ();
3751 pnum=state_restore_all_sub( filename, 1, 0 );
3753 mprintf ((0,"StateId=%d ThisID=%d\n",state_game_id,id));
3755 /* if (state_game_id != id ) {
3756 // Game doesn't match!!!
3757 nm_messagebox( "Error", 1, "Ok", "Cannot restore saved game" );
3758 Game_mode |= GM_GAME_OVER;
3759 Function_mode = FMODE_MENU;
3760 longjmp(LeaveGame, 0);
3763 change_playernum_to(pnum-1);
3764 memcpy( Players[Player_num].callsign, saved_player.callsign, CALLSIGN_LEN+1 );
3765 memcpy( Players[Player_num].net_address, saved_player.net_address, 6 );
3766 Players[Player_num].connected = saved_player.connected;
3767 Players[Player_num].n_packets_got = saved_player.n_packets_got;
3768 Players[Player_num].n_packets_sent = saved_player.n_packets_sent;
3769 Viewer = ConsoleObject = &Objects[pnum-1]; */
3773 void extract_netplayer_stats( netplayer_stats *ps, player * pd )
3777 ps->flags = INTEL_INT(pd->flags); // Powerup flags, see below...
3778 ps->energy = (fix)INTEL_INT(pd->energy); // Amount of energy remaining.
3779 ps->shields = (fix)INTEL_INT(pd->shields); // shields remaining (protection)
3780 ps->lives = pd->lives; // Lives remaining, 0 = game over.
3781 ps->laser_level = pd->laser_level; // Current level of the laser.
3782 ps->primary_weapon_flags=pd->primary_weapon_flags; // bit set indicates the player has this weapon.
3783 ps->secondary_weapon_flags=pd->secondary_weapon_flags; // bit set indicates the player has this weapon.
3784 for (i = 0; i < MAX_PRIMARY_WEAPONS; i++)
3785 ps->primary_ammo[i] = INTEL_SHORT(pd->primary_ammo[i]);
3786 for (i = 0; i < MAX_SECONDARY_WEAPONS; i++)
3787 ps->secondary_ammo[i] = INTEL_SHORT(pd->secondary_ammo[i]);
3789 // memcpy( ps->primary_ammo, pd->primary_ammo, MAX_PRIMARY_WEAPONS*sizeof(short) ); // How much ammo of each type.
3790 // memcpy( ps->secondary_ammo, pd->secondary_ammo, MAX_SECONDARY_WEAPONS*sizeof(short) ); // How much ammo of each type.
3792 ps->last_score=INTEL_INT(pd->last_score); // Score at beginning of current level.
3793 ps->score=INTEL_INT(pd->score); // Current score.
3794 ps->cloak_time=(fix)INTEL_INT(pd->cloak_time); // Time cloaked
3795 ps->homing_object_dist=(fix)INTEL_INT(pd->homing_object_dist); // Distance of nearest homing object.
3796 ps->invulnerable_time=(fix)INTEL_INT(pd->invulnerable_time); // Time invulnerable
3797 ps->KillGoalCount=INTEL_SHORT(pd->KillGoalCount);
3798 ps->net_killed_total=INTEL_SHORT(pd->net_killed_total); // Number of times killed total
3799 ps->net_kills_total=INTEL_SHORT(pd->net_kills_total); // Number of net kills total
3800 ps->num_kills_level=INTEL_SHORT(pd->num_kills_level); // Number of kills this level
3801 ps->num_kills_total=INTEL_SHORT(pd->num_kills_total); // Number of kills total
3802 ps->num_robots_level=INTEL_SHORT(pd->num_robots_level); // Number of initial robots this level
3803 ps->num_robots_total=INTEL_SHORT(pd->num_robots_total); // Number of robots total
3804 ps->hostages_rescued_total=INTEL_SHORT(pd->hostages_rescued_total); // Total number of hostages rescued.
3805 ps->hostages_total=INTEL_SHORT(pd->hostages_total); // Total number of hostages.
3806 ps->hostages_on_board=pd->hostages_on_board; // Number of hostages on ship.
3809 void use_netplayer_stats( player * ps, netplayer_stats *pd )
3813 ps->flags = INTEL_INT(pd->flags); // Powerup flags, see below...
3814 ps->energy = (fix)INTEL_INT((int)pd->energy); // Amount of energy remaining.
3815 ps->shields = (fix)INTEL_INT((int)pd->shields); // shields remaining (protection)
3816 ps->lives = pd->lives; // Lives remaining, 0 = game over.
3817 ps->laser_level = pd->laser_level; // Current level of the laser.
3818 ps->primary_weapon_flags=pd->primary_weapon_flags; // bit set indicates the player has this weapon.
3819 ps->secondary_weapon_flags=pd->secondary_weapon_flags; // bit set indicates the player has this weapon.
3820 for (i = 0; i < MAX_PRIMARY_WEAPONS; i++)
3821 ps->primary_ammo[i] = INTEL_SHORT(pd->primary_ammo[i]);
3822 for (i = 0; i < MAX_SECONDARY_WEAPONS; i++)
3823 ps->secondary_ammo[i] = INTEL_SHORT(pd->secondary_ammo[i]);
3824 // memcpy( ps->primary_ammo, pd->primary_ammo, MAX_PRIMARY_WEAPONS*sizeof(short) ); // How much ammo of each type.
3825 // memcpy( ps->secondary_ammo, pd->secondary_ammo, MAX_SECONDARY_WEAPONS*sizeof(short) ); // How much ammo of each type.
3826 ps->last_score = INTEL_INT(pd->last_score); // Score at beginning of current level.
3827 ps->score = INTEL_INT(pd->score); // Current score.
3828 ps->cloak_time = (fix)INTEL_INT((int)pd->cloak_time); // Time cloaked
3829 ps->homing_object_dist = (fix)INTEL_INT((int)pd->homing_object_dist); // Distance of nearest homing object.
3830 ps->invulnerable_time = (fix)INTEL_INT((int)pd->invulnerable_time); // Time invulnerable
3831 ps->KillGoalCount=INTEL_SHORT(pd->KillGoalCount);
3832 ps->net_killed_total = INTEL_SHORT(pd->net_killed_total); // Number of times killed total
3833 ps->net_kills_total = INTEL_SHORT(pd->net_kills_total); // Number of net kills total
3834 ps->num_kills_level = INTEL_SHORT(pd->num_kills_level); // Number of kills this level
3835 ps->num_kills_total = INTEL_SHORT(pd->num_kills_total); // Number of kills total
3836 ps->num_robots_level = INTEL_SHORT(pd->num_robots_level); // Number of initial robots this level
3837 ps->num_robots_total = INTEL_SHORT(pd->num_robots_total); // Number of robots total
3838 ps->hostages_rescued_total = INTEL_SHORT(pd->hostages_rescued_total); // Total number of hostages rescued.
3839 ps->hostages_total = INTEL_SHORT(pd->hostages_total); // Total number of hostages.
3840 ps->hostages_on_board=pd->hostages_on_board; // Number of hostages on ship.
3843 void multi_send_drop_weapon (int objnum,int seed)
3849 objp = &Objects[objnum];
3851 ammo_count = objp->ctype.powerup_info.count;
3853 if (objp->id == POW_OMEGA_WEAPON && ammo_count == F1_0)
3854 ammo_count = F1_0 - 1; //make fit in short
3856 Assert(ammo_count < F1_0); //make sure fits in short
3858 multibuf[count++]=(char)MULTI_DROP_WEAPON;
3859 multibuf[count++]=(char)objp->id;
3861 *(short *) (multibuf+count)=INTEL_SHORT(Player_num); count += 2;
3862 *(short *) (multibuf+count)=INTEL_SHORT(objnum); count += 2;
3863 *(short *) (multibuf+count)=INTEL_SHORT(ammo_count); count += 2;
3864 *(int *) (multibuf+count)=INTEL_INT(seed);
3866 map_objnum_local_to_local(objnum);
3868 if (Game_mode & GM_NETWORK)
3869 PowerupsInMine[objp->id]++;
3871 multi_send_data(multibuf, 12, 2);
3874 void multi_do_drop_weapon (char *buf)
3876 int pnum,ammo,objnum,remote_objnum,seed;
3880 powerup_id=(int)(buf[1]);
3881 pnum = INTEL_SHORT(*(short *)(buf+2));
3882 remote_objnum = INTEL_SHORT(*(short *)(buf+4));
3883 ammo = INTEL_SHORT(*(ushort *)(buf+6));
3884 seed = INTEL_INT(*(int *)(buf+8));
3886 objp = &Objects[Players[pnum].objnum];
3888 objnum = spit_powerup(objp, powerup_id, seed);
3890 map_objnum_local_to_remote(objnum, remote_objnum, pnum);
3893 Objects[objnum].ctype.powerup_info.count = ammo;
3895 if (Game_mode & GM_NETWORK)
3896 PowerupsInMine[powerup_id]++;
3898 mprintf ((0,"Dropped weapon %d!\n"));
3902 void multi_send_guided_info (object *miss,char done)
3909 mprintf ((0,"Sending guided info!\n"));
3911 multibuf[count++]=(char)MULTI_GUIDED;
3912 multibuf[count++]=(char)Player_num;
3913 multibuf[count++]=done;
3916 create_shortpos((shortpos *)(multibuf+count), miss,0);
3917 count+=sizeof(shortpos);
3919 create_shortpos(&sp, miss, 1);
3920 memcpy(&(multibuf[count]), (ubyte *)(sp.bytemat), 9);
3922 memcpy(&(multibuf[count]), (ubyte *)&(sp.xo), 14);
3926 multi_send_data(multibuf, count, 0);
3929 void multi_do_guided (char *buf)
3938 if (Guided_missile[(int)pnum]==NULL)
3942 mprintf ((0,"Guided missile for %s is NULL!\n",Players[(int)pnum].callsign));
3949 mprintf ((0,"Got guided info for %d (%s)\n",pnum,Players[(int)pnum].callsign));
3955 release_guided_missile(pnum);
3960 if (Guided_missile[(int)pnum]-Objects<0 || Guided_missile[(int)pnum]-Objects > Highest_object_index)
3962 Int3(); // Get Jason immediately!
3967 extract_shortpos(Guided_missile[(int)pnum], (shortpos *)(buf+count),0);
3969 memcpy((ubyte *)(sp.bytemat), (ubyte *)(buf + count), 9);
3970 memcpy((ubyte *)&(sp.xo), (ubyte *)(buf + count + 9), 14);
3971 extract_shortpos(Guided_missile[(int)pnum], &sp, 1);
3974 count+=sizeof (shortpos);
3976 update_object_seg(Guided_missile[(int)pnum]);
3979 void multi_send_stolen_items ()
3982 multibuf[0]=MULTI_STOLEN_ITEMS;
3984 for (i=0;i<MAX_STOLEN_ITEMS;i++)
3986 multibuf[i+1]=Stolen_items[i];
3987 mprintf ((0,"[%d]=%d ",i,Stolen_items[i]));
3988 count++; // So I like to break my stuff into smaller chunks, so what?
3991 multi_send_data(multibuf, count, 1);
3994 void multi_do_stolen_items (char *buf)
3998 mprintf ((0,"Recieved a stolen item packet...\n"));
4000 for (i=0;i<MAX_STOLEN_ITEMS;i++)
4002 Stolen_items[i]=buf[i+1];
4003 mprintf ((0,"[%d]=%d ",i,Stolen_items[i]));
4008 extern void network_send_important_packet (char *,int);
4010 void multi_send_wall_status (int wallnum,ubyte type,ubyte flags,ubyte state)
4013 multibuf[count]=MULTI_WALL_STATUS; count++;
4014 *(short *)(multibuf+count)=INTEL_SHORT(wallnum); count+=2;
4015 multibuf[count]=type; count++;
4016 multibuf[count]=flags; count++;
4017 multibuf[count]=state; count++;
4019 /* if (Game_mode & GM_NETWORK)
4021 network_send_important_packet (multibuf,count);
4022 network_send_important_packet (multibuf,count);
4026 multi_send_data(multibuf, count, 1); // twice, just to be sure
4027 multi_send_data(multibuf, count, 1);
4030 void multi_send_wall_status_specific (int pnum,int wallnum,ubyte type,ubyte flags,ubyte state)
4032 // Send wall states a specific rejoining player
4036 Assert (Game_mode & GM_NETWORK);
4037 // Assert (pnum>-1 && pnum<N_players);
4039 multibuf[count]=MULTI_WALL_STATUS; count++;
4040 *(short *)(multibuf+count)=INTEL_SHORT(wallnum); count+=2;
4041 multibuf[count]=type; count++;
4042 multibuf[count]=flags; count++;
4043 multibuf[count]=state; count++;
4045 network_send_naked_packet(multibuf, count,pnum); // twice, just to be sure
4046 network_send_naked_packet(multibuf, count,pnum);
4049 void multi_do_wall_status (char *buf)
4052 ubyte flag,type,state;
4054 wallnum=INTEL_SHORT( *(short *)(buf+1) );
4059 Assert (wallnum>=0);
4060 Walls[wallnum].type=type;
4061 Walls[wallnum].flags=flag;
4062 // Assert(state <= 4);
4063 Walls[wallnum].state=state;
4065 if (Walls[wallnum].type==WALL_OPEN)
4067 digi_kill_sound_linked_to_segment(Walls[wallnum].segnum,Walls[wallnum].sidenum,SOUND_FORCEFIELD_HUM);
4068 // digi_kill_sound_linked_to_segment(csegp-Segments,cside,SOUND_FORCEFIELD_HUM);
4072 // mprintf ((0,"Got a walls packet.\n"));
4075 void multi_send_jason_cheat (int num)
4081 void multi_send_kill_goal_counts()
4084 multibuf[0]=MULTI_KILLGOALS;
4086 for (i=0;i<MAX_PLAYERS;i++)
4088 *(char *)(multibuf+count)=(char)Players[i].KillGoalCount;
4092 mprintf ((0,"MULTI: Sending KillGoalCounts...\n"));
4093 multi_send_data(multibuf, count, 1);
4096 void multi_do_kill_goal_counts(char *buf)
4100 for (i=0;i<MAX_PLAYERS;i++)
4102 Players[i].KillGoalCount=*(char *)(buf+count);
4103 mprintf ((0,"KGC: %s has %d kills!\n",Players[i].callsign,Players[i].KillGoalCount));
4109 void multi_send_heartbeat ()
4111 if (!Netgame.PlayTimeAllowed)
4114 multibuf[0]=MULTI_HEARTBEAT;
4115 *(fix *)(multibuf+1)=(fix)INTEL_INT(ThisLevelTime);
4116 multi_send_data(multibuf, 5, 0);
4119 void multi_do_heartbeat (char *buf)
4123 num=(fix)INTEL_INT(*(int *)(buf+1));
4128 void multi_check_for_killgoal_winner ()
4130 int i,best=0,bestnum=0;
4134 if (Control_center_destroyed)
4137 for (i=0;i<N_players;i++)
4139 if (Players[i].KillGoalCount>best)
4141 best=Players[i].KillGoalCount;
4146 if (bestnum==Player_num)
4148 HUD_init_message("You have the best score at %d kills!",best);
4149 // Players[Player_num].shields=i2f(200);
4153 HUD_init_message ("%s has the best score with %d kills!",Players[bestnum].callsign,best);
4155 HUD_init_message ("The control center has been destroyed!");
4157 objp=obj_find_first_of_type (OBJ_CNTRLCEN);
4158 net_destroy_controlcen (objp);
4161 void multi_send_seismic (fix start,fix end)
4165 multibuf[0]=MULTI_SEISMIC;
4166 *(fix *)(multibuf+count)=(fix)INTEL_INT(start); count+=(sizeof(fix));
4167 *(fix *)(multibuf+count)=(fix)INTEL_INT(end); count+=(sizeof(fix));
4169 multi_send_data(multibuf, count, 1);
4172 extern fix Seismic_disturbance_start_time;
4173 extern fix Seismic_disturbance_end_time;
4175 void multi_do_seismic (char *buf)
4177 Seismic_disturbance_start_time=(fix)INTEL_INT( *(int *)(buf+1) );
4178 Seismic_disturbance_end_time=(fix)INTEL_INT( *(int *)(buf+5) );
4179 digi_play_sample (SOUND_SEISMIC_DISTURBANCE_START, F1_0);
4182 void multi_send_light (int segnum,ubyte val)
4185 multibuf[0]=MULTI_LIGHT;
4186 *(int *)(multibuf+count)=INTEL_INT(segnum); count+=(sizeof(int));
4187 *(char *)(multibuf+count)=val; count++;
4190 //mprintf ((0,"Sending %d!\n",Segments[segnum].sides[i].tmap_num2));
4191 *(short *)(multibuf+count)=INTEL_SHORT(Segments[segnum].sides[i].tmap_num2); count+=2;
4193 multi_send_data(multibuf, count, 1);
4195 void multi_send_light_specific (int pnum,int segnum,ubyte val)
4199 Assert (Game_mode & GM_NETWORK);
4200 // Assert (pnum>-1 && pnum<N_players);
4202 multibuf[0]=MULTI_LIGHT;
4203 *(int *)(multibuf+count)=INTEL_INT(segnum); count+=(sizeof(int));
4204 *(char *)(multibuf+count)=val; count++;