/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #include #ifdef NETWORK #include #include #include #include #include #include "u_mem.h" #include "strutil.h" #include "game.h" #include "modem.h" #include "network.h" #include "multi.h" #include "object.h" #include "laser.h" #include "fuelcen.h" #include "scores.h" #include "gauges.h" #include "collide.h" #include "error.h" #include "fireball.h" #include "newmenu.h" #include "mono.h" #include "wall.h" #include "cntrlcen.h" #include "powerup.h" #include "polyobj.h" #include "bm.h" #include "endlevel.h" #include "key.h" #include "playsave.h" #include "timer.h" #include "digi.h" #include "sounds.h" #include "kconfig.h" #include "newdemo.h" #include "text.h" #include "kmatrix.h" #include "multibot.h" #include "gameseq.h" #include "physics.h" #include "config.h" #include "state.h" #include "ai.h" #include "switch.h" #include "textures.h" #include "byteswap.h" #include "sounds.h" #include "args.h" #include "d_delay.h" #include "cfile.h" #include "effects.h" void multi_reset_player_object(object *objp); void multi_reset_object_texture (object *objp); void multi_add_lifetime_killed (); void multi_add_lifetime_kills (); void multi_send_play_by_play (int num,int spnum,int dpnum); void multi_send_heartbeat (); void multi_send_modem_ping (); void multi_cap_objects (); void multi_adjust_remote_cap (int pnum); void multi_save_game(ubyte slot, uint id, char *desc); void multi_restore_game(ubyte slot, uint id); void multi_set_robot_ai(void); void multi_send_powerup_update (); void bash_to_shield (int i,char *s); void init_hoard_data(); void multi_apply_goal_textures(); int find_goal_texture (ubyte t); void multi_bad_restore (); void multi_do_capture_bonus(char *buf); void multi_do_orb_bonus(char *buf); void multi_send_drop_flag (int objnum,int seed); void multi_send_ranking (); void multi_do_play_by_play (char *buf); // // Local macros and prototypes // // LOCALIZE ME!! #define vm_angvec_zero(v) (v)->p=(v)->b=(v)->h=0 void drop_player_eggs(object *player); // from collide.c void GameLoop(int, int); // From game.c // // Global variables // extern vms_vector MarkerPoint[]; extern char MarkerMessage[16][40]; extern char MarkerOwner[16][40]; extern int MarkerObject[]; int control_invul_time = 0; int who_killed_controlcen = -1; // -1 = noone //do we draw the kill list on the HUD? int Show_kill_list = 1; int Show_reticle_name = 1; fix Show_kill_list_timer = 0; char Multi_is_guided=0; char PKilledFlags[MAX_NUM_NET_PLAYERS]; int multi_sending_message = 0; int multi_defining_message = 0; int multi_message_index = 0; char multibuf[MAX_MULTI_MESSAGE_LEN+4]; // This is where multiplayer message are built short remote_to_local[MAX_NUM_NET_PLAYERS][MAX_OBJECTS]; // Remote object number for each local object short local_to_remote[MAX_OBJECTS]; byte object_owner[MAX_OBJECTS]; // Who created each object in my universe, -1 = loaded at start int Net_create_objnums[MAX_NET_CREATE_OBJECTS]; // For tracking object creation that will be sent to remote int Net_create_loc = 0; // pointer into previous array int Network_laser_fired = 0; // How many times we shot int Network_laser_gun; // Which gun number we shot int Network_laser_flags; // Special flags for the shot int Network_laser_level; // What level short Network_laser_track; // Who is it tracking? char Network_message[MAX_MESSAGE_LEN]; char Network_message_macro[4][MAX_MESSAGE_LEN]; int Network_message_reciever=-1; int sorted_kills[MAX_NUM_NET_PLAYERS]; short kill_matrix[MAX_NUM_NET_PLAYERS][MAX_NUM_NET_PLAYERS]; int multi_goto_secret = 0; short team_kills[2]; int multi_in_menu = 0; int multi_leave_menu = 0; int multi_quit_game = 0; netgame_info Netgame; AllNetPlayers_info NetPlayers; bitmap_index multi_player_textures[MAX_NUM_NET_PLAYERS][N_PLAYER_SHIP_TEXTURES]; typedef struct netplayer_stats { ubyte message_type; ubyte Player_num; // Who am i? uint flags; // Powerup flags, see below... fix energy; // Amount of energy remaining. fix shields; // shields remaining (protection) ubyte lives; // Lives remaining, 0 = game over. ubyte laser_level; // Current level of the laser. ubyte primary_weapon_flags; // bit set indicates the player has this weapon. ubyte secondary_weapon_flags; // bit set indicates the player has this weapon. ushort primary_ammo[MAX_PRIMARY_WEAPONS]; // How much ammo of each type. ushort secondary_ammo[MAX_SECONDARY_WEAPONS]; // How much ammo of each type. int last_score; // Score at beginning of current level. int score; // Current score. fix cloak_time; // Time cloaked fix invulnerable_time; // Time invulnerable fix homing_object_dist; // Distance of nearest homing object. short KillGoalCount; short net_killed_total; // Number of times killed total short net_kills_total; // Number of net kills total short num_kills_level; // Number of kills this level short num_kills_total; // Number of kills total short num_robots_level; // Number of initial robots this level short num_robots_total; // Number of robots total ushort hostages_rescued_total; // Total number of hostages rescued. ushort hostages_total; // Total number of hostages. ubyte hostages_on_board; // Number of hostages on ship. ubyte unused[16]; } netplayer_stats; int message_length[MULTI_MAX_TYPE+1] = { 24, // POSITION 3, // REAPPEAR 8, // FIRE 5, // KILL 4, // REMOVE_OBJECT 97+9, // PLAYER_EXPLODE 37, // MESSAGE (MAX_MESSAGE_LENGTH = 40) 2, // QUIT 4, // PLAY_SOUND 41, // BEGIN_SYNC 4, // CONTROLCEN 5, // CLAIM ROBOT 4, // END_SYNC 2, // CLOAK 3, // ENDLEVEL_START 5, // DOOR_OPEN 2, // CREATE_EXPLOSION 16, // CONTROLCEN_FIRE 97+9, // PLAYER_DROP 19, // CREATE_POWERUP 9, // MISSILE_TRACK 2, // DE-CLOAK 2, // MENU_CHOICE 28, // ROBOT_POSITION (shortpos_length (23) + 5 = 28) 9, // ROBOT_EXPLODE 5, // ROBOT_RELEASE 18, // ROBOT_FIRE 6, // SCORE 6, // CREATE_ROBOT 3, // TRIGGER 10, // BOSS_ACTIONS 27, // ROBOT_POWERUPS 7, // HOSTAGE_DOOR 2+24, //SAVE_GAME (ubyte slot, uint id, char name[20]) 2+4, //RESTORE_GAME (ubyte slot, uint id) 1+1, // MULTI_REQ_PLAYER sizeof(netplayer_stats), // MULTI_SEND_PLAYER 55, // MULTI_MARKER 12, // MULTI_DROP_WEAPON #ifndef MACINTOSH 3+sizeof(shortpos), // MULTI_GUIDED, IF SHORTPOS CHANGES, CHANGE MAC VALUE BELOW #else 26, //MULTI_GUIDED IF SIZE OF SHORTPOS CHANGES, CHANGE THIS VALUE AS WELL!!!!!! #endif 11, // MULTI_STOLEN_ITEMS 6, // MULTI_WALL_STATUS 5, // MULTI_HEARTBEAT 9, // MULTI_KILLGOALS 9, // MULTI_SEISMIC 18, // MULTI_LIGHT 2, // MULTI_START_TRIGGER 6, // MULTI_FLAGS 2, // MULTI_DROP_BLOB MAX_POWERUP_TYPES+1, // MULTI_POWERUP_UPDATE sizeof(active_door)+3, // MULTI_ACTIVE_DOOR 4, // MULTI_SOUND_FUNCTION 2, // MULTI_CAPTURE_BONUS 2, // MULTI_GOT_FLAG 12, // MULTI_DROP_FLAG 142, // MULTI_ROBOT_CONTROLS 2, // MULTI_FINISH_GAME 3, // MULTI_RANK 1, // MULTI_MODEM_PING 1, // MULTI_MODEM_PING_RETURN 3, // MULTI_ORB_BONUS 2, // MULTI_GOT_ORB 12, // MULTI_DROP_ORB 4, // MULTI_PLAY_BY_PLAY }; void extract_netplayer_stats( netplayer_stats *ps, player * pd ); void use_netplayer_stats( player * ps, netplayer_stats *pd ); char PowerupsInMine[MAX_POWERUP_TYPES],MaxPowerupsAllowed[MAX_POWERUP_TYPES]; extern fix ThisLevelTime; // // Functions that replace what used to be macros // int objnum_remote_to_local(int remote_objnum, int owner) { // Map a remote object number from owner to a local object number int result; if ((owner >= N_players) || (owner < -1)) { Int3(); // Illegal! return(remote_objnum); } if (owner == -1) return(remote_objnum); if ((remote_objnum < 0) || (remote_objnum >= MAX_OBJECTS)) return(-1); result = remote_to_local[owner][remote_objnum]; if (result < 0) { mprintf((1, "Remote object owner %d number %d mapped to -1!\n", owner, remote_objnum)); return(-1); } #ifndef NDEBUG if (object_owner[result] != owner) { mprintf((1, "Remote object owner %d number %d doesn't match owner %d.\n", owner, remote_objnum, object_owner[result])); } #endif // Assert(object_owner[result] == owner); return(result); } int objnum_local_to_remote(int local_objnum, byte *owner) { // Map a local object number to a remote + owner int result; if ((local_objnum < 0) || (local_objnum > Highest_object_index)) { *owner = -1; return(-1); } *owner = object_owner[local_objnum]; if (*owner == -1) return(local_objnum); if ((*owner >= N_players) || (*owner < -1)) { Int3(); // Illegal! *owner = -1; return local_objnum; } result = local_to_remote[local_objnum]; // mprintf((0, "Local object %d mapped to owner %d objnum %d.\n", local_objnum, // *owner, result)); if (result < 0) { Int3(); // See Rob, object has no remote number! } return(result); } void map_objnum_local_to_remote(int local_objnum, int remote_objnum, int owner) { // Add a mapping from a network remote object number to a local one Assert(local_objnum > -1); Assert(remote_objnum > -1); Assert(owner > -1); Assert(owner != Player_num); Assert(local_objnum < MAX_OBJECTS); Assert(remote_objnum < MAX_OBJECTS); object_owner[local_objnum] = owner; remote_to_local[owner][remote_objnum] = local_objnum; local_to_remote[local_objnum] = remote_objnum; return; } void map_objnum_local_to_local(int local_objnum) { // Add a mapping for our locally created objects Assert(local_objnum > -1); Assert(local_objnum < MAX_OBJECTS); object_owner[local_objnum] = Player_num; remote_to_local[Player_num][local_objnum] = local_objnum; local_to_remote[local_objnum] = local_objnum; return; } // // Part 1 : functions whose main purpose in life is to divert the flow // of execution to either network or serial specific code based // on the curretn Game_mode value. // void multi_endlevel_score(void) { int old_connect=0; int i; // Show a score list to end of net players // Save connect state and change to new connect state #ifdef NETWORK if (Game_mode & GM_NETWORK) { old_connect = Players[Player_num].connected; if (Players[Player_num].connected!=3) Players[Player_num].connected = CONNECT_END_MENU; Network_status = NETSTAT_ENDLEVEL; } #endif // Do the actual screen we wish to show Function_mode = FMODE_MENU; kmatrix_view(Game_mode & GM_NETWORK); Function_mode = FMODE_GAME; // Restore connect state if (Game_mode & GM_NETWORK) { Players[Player_num].connected = old_connect; } #ifndef SHAREWARE if (Game_mode & GM_MULTI_COOP) { int i; for (i = 0; i < MaxNumNetPlayers; i++) // Reset keys Players[i].flags &= ~(PLAYER_FLAGS_BLUE_KEY | PLAYER_FLAGS_RED_KEY | PLAYER_FLAGS_GOLD_KEY); } for (i = 0; i < MaxNumNetPlayers; i++) Players[i].flags &= ~(PLAYER_FLAGS_FLAG); // Clear capture flag #endif for (i=0;i 1) { default_mission = 0; for (i=0;i= MAX_NUM_NET_PLAYERS) || (playernum < 0)) { Int3(); // Non-terminal, see Rob return; } // if (Objects[Players[playernum].objnum].type != OBJ_PLAYER) // mprintf((1, "Warning: Player %d is not currently a player.\n", playernum)); obj = &Objects[Players[playernum].objnum]; obj->type = OBJ_GHOST; obj->render_type = RT_NONE; obj->movement_type = MT_NONE; multi_reset_player_object(obj); if (Game_mode & GM_MULTI_ROBOTS) multi_strip_robots(playernum); } void multi_make_ghost_player(int playernum) { object *obj; // Assert(playernum != Player_num); // Assert(playernum < MAX_NUM_NET_PLAYERS); if ((playernum == Player_num) || (playernum >= MAX_NUM_NET_PLAYERS)) { Int3(); // Non-terminal, see rob return; } // if(Objects[Players[playernum].objnum].type != OBJ_GHOST) // mprintf((1, "Warning: Player %d is not currently a ghost.\n", playernum)); obj = &Objects[Players[playernum].objnum]; obj->type = OBJ_PLAYER; obj->movement_type = MT_PHYSICS; multi_reset_player_object(obj); } int multi_get_kill_list(int *plist) { // Returns the number of active net players and their // sorted order of kills int i; int n = 0; for (i = 0; i < N_players; i++) // if (Players[sorted_kills[i]].connected) plist[n++] = sorted_kills[i]; if (n == 0) Int3(); // SEE ROB OR MATT // memcpy(plist, sorted_kills, N_players*sizeof(int)); return(n); } void multi_sort_kill_list(void) { // Sort the kills list each time a new kill is added int kills[MAX_NUM_NET_PLAYERS]; int i; int changed = 1; for (i = 0; i < MAX_NUM_NET_PLAYERS; i++) { #ifndef SHAREWARE if (Game_mode & GM_MULTI_COOP) kills[i] = Players[i].score; else #endif if (Show_kill_list==2) { if (Players[i].net_killed_total+Players[i].net_kills_total==0) kills[i]=-1; // always draw the ones without any ratio last else kills[i]=(int)((float)((float)Players[i].net_kills_total/((float)Players[i].net_killed_total+(float)Players[i].net_kills_total))*100.0); } else kills[i] = Players[i].net_kills_total; } while (changed) { changed = 0; for (i = 0; i < N_players-1; i++) { if (kills[sorted_kills[i]] < kills[sorted_kills[i+1]]) { changed = sorted_kills[i]; sorted_kills[i] = sorted_kills[i+1]; sorted_kills[i+1] = changed; changed = 1; } } } mprintf((0, "Sorted kills %d %d.\n", sorted_kills[0], sorted_kills[1])); } extern object *obj_find_first_of_type (int); char Multi_killed_yourself=0; void multi_compute_kill(int killer, int killed) { // Figure out the results of a network kills and add it to the // appropriate player's tally. int killed_pnum, killed_type; int killer_pnum, killer_type,killer_id; int TheGoal; char killed_name[(CALLSIGN_LEN*2)+4]; char killer_name[(CALLSIGN_LEN*2)+4]; kmatrix_kills_changed = 1; Multi_killed_yourself=0; // Both object numbers are localized already! mprintf((0, "compute_kill passed: object %d killed object %d.\n", killer, killed)); if ((killed < 0) || (killed > Highest_object_index) || (killer < 0) || (killer > Highest_object_index)) { Int3(); // See Rob, illegal value passed to compute_kill; return; } killed_type = Objects[killed].type; killer_type = Objects[killer].type; killer_id = Objects[killer].id; if ((killed_type != OBJ_PLAYER) && (killed_type != OBJ_GHOST)) { Int3(); // compute_kill passed non-player object! return; } killed_pnum = Objects[killed].id; PKilledFlags[killed_pnum]=1; Assert ((killed_pnum >= 0) && (killed_pnum < N_players)); if (Game_mode & GM_TEAM) sprintf(killed_name, "%s (%s)", Players[killed_pnum].callsign, Netgame.team_name[get_team(killed_pnum)]); else sprintf(killed_name, "%s", Players[killed_pnum].callsign); if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_multi_death(killed_pnum); digi_play_sample( SOUND_HUD_KILL, F3_0 ); if (Control_center_destroyed) Players[killed_pnum].connected=3; if (killer_type == OBJ_CNTRLCEN) { Players[killed_pnum].net_killed_total++; Players[killed_pnum].net_kills_total--; if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_multi_kill(killed_pnum, -1); if (killed_pnum == Player_num) { HUD_init_message("%s %s.", TXT_YOU_WERE, TXT_KILLED_BY_NONPLAY); multi_add_lifetime_killed (); } else HUD_init_message("%s %s %s.", killed_name, TXT_WAS, TXT_KILLED_BY_NONPLAY ); return; } #ifndef SHAREWARE else if ((killer_type != OBJ_PLAYER) && (killer_type != OBJ_GHOST)) { if (killer_id==PMINE_ID && killer_type!=OBJ_ROBOT) { if (killed_pnum == Player_num) HUD_init_message("You were killed by a mine!"); else HUD_init_message("%s was killed by a mine!",killed_name); } else { if (killed_pnum == Player_num) { HUD_init_message("%s %s.", TXT_YOU_WERE, TXT_KILLED_BY_ROBOT); multi_add_lifetime_killed(); } else HUD_init_message("%s %s %s.", killed_name, TXT_WAS, TXT_KILLED_BY_ROBOT ); } Players[killed_pnum].net_killed_total++; return; } #else else if ((killer_type != OBJ_PLAYER) && (killer_type != OBJ_GHOST) && (killer_id!=PMINE_ID)) { Int3(); // Illegal killer type? return; } if (killer_id==PMINE_ID) { if (killed_pnum==Player_num) HUD_init_message("You were killed by a mine!"); else HUD_init_message("%s was killed by a mine!",killed_name); Players[killed_pnum].net_killed_total++; return; } #endif killer_pnum = Objects[killer].id; if (Game_mode & GM_TEAM) sprintf(killer_name, "%s (%s)", Players[killer_pnum].callsign, Netgame.team_name[get_team(killer_pnum)]); else sprintf(killer_name, "%s", Players[killer_pnum].callsign); // Beyond this point, it was definitely a player-player kill situation if ((killer_pnum < 0) || (killer_pnum >= N_players)) Int3(); // See rob, tracking down bug with kill HUD messages if ((killed_pnum < 0) || (killed_pnum >= N_players)) Int3(); // See rob, tracking down bug with kill HUD messages if (killer_pnum == killed_pnum) { if (!(Game_mode & GM_HOARD)) { if (Game_mode & GM_TEAM) team_kills[get_team(killed_pnum)] -= 1; Players[killed_pnum].net_killed_total += 1; Players[killed_pnum].net_kills_total -= 1; if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_multi_kill(killed_pnum, -1); } kill_matrix[killed_pnum][killed_pnum] += 1; // # of suicides if (killer_pnum == Player_num) { HUD_init_message("%s %s %s!", TXT_YOU, TXT_KILLED, TXT_YOURSELF ); Multi_killed_yourself=1; multi_add_lifetime_killed(); } else HUD_init_message("%s %s", killed_name, TXT_SUICIDE); } else { if (!(Game_mode & GM_HOARD)) { if (Game_mode & GM_TEAM) { if (get_team(killed_pnum) == get_team(killer_pnum)) team_kills[get_team(killed_pnum)] -= 1; else team_kills[get_team(killer_pnum)] += 1; } Players[killer_pnum].net_kills_total += 1; Players[killer_pnum].KillGoalCount+=1; if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_multi_kill(killer_pnum, 1); } else { if (Game_mode & GM_TEAM) { if (killed_pnum==Player_num && get_team(killed_pnum) == get_team(killer_pnum)) Multi_killed_yourself=1; } } kill_matrix[killer_pnum][killed_pnum] += 1; Players[killed_pnum].net_killed_total += 1; if (killer_pnum == Player_num) { HUD_init_message("%s %s %s!", TXT_YOU, TXT_KILLED, killed_name); multi_add_lifetime_kills(); if ((Game_mode & GM_MULTI_COOP) && (Players[Player_num].score >= 1000)) add_points_to_score(-1000); } else if (killed_pnum == Player_num) { HUD_init_message("%s %s %s!", killer_name, TXT_KILLED, TXT_YOU); multi_add_lifetime_killed(); if (Game_mode & GM_HOARD) { if (Players[Player_num].secondary_ammo[PROXIMITY_INDEX]>3) multi_send_play_by_play (1,killer_pnum,Player_num); else if (Players[Player_num].secondary_ammo[PROXIMITY_INDEX]>0) multi_send_play_by_play (0,killer_pnum,Player_num); } } else HUD_init_message("%s %s %s!", killer_name, TXT_KILLED, killed_name); } TheGoal=Netgame.KillGoal*5; if (Netgame.KillGoal>0) { if (Players[killer_pnum].KillGoalCount>=TheGoal) { if (killer_pnum==Player_num) { HUD_init_message("You reached the kill goal!"); Players[Player_num].shields=i2f(200); } else HUD_init_message ("%s has reached the kill goal!",Players[killer_pnum].callsign); HUD_init_message ("The control center has been destroyed!"); net_destroy_controlcen (obj_find_first_of_type (OBJ_CNTRLCEN)); } } multi_sort_kill_list(); multi_show_player_list(); Players[killed_pnum].flags&=(~(PLAYER_FLAGS_HEADLIGHT_ON)); // clear the killed guys flags/headlights } void multi_do_frame(void) { static int lasttime=0; int i; if (!(Game_mode & GM_MULTI)) { Int3(); return; } if ((Game_mode & GM_NETWORK) && Netgame.PlayTimeAllowed && lasttime!=f2i (ThisLevelTime)) { for (i=0;i= 0); if (Game_mode & GM_NETWORK) Assert(buf[0] > 0); if ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM)) com_send_data(buf, len, repeat); else if (Game_mode & GM_NETWORK) network_send_data(buf, len, repeat); } void multi_leave_game(void) { // if (Function_mode != FMODE_GAME) // return; if (!(Game_mode & GM_MULTI)) return; if (Game_mode & GM_NETWORK) { mprintf((0, "Sending explosion message.\n")); Net_create_loc = 0; AdjustMineSpawn(); multi_cap_objects(); drop_player_eggs(ConsoleObject); multi_send_position(Players[Player_num].objnum); multi_send_player_explode(MULTI_PLAYER_DROP); } mprintf((1, "Sending leave game.\n")); multi_send_quit(MULTI_QUIT); if ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM)) serial_leave_game(); if (Game_mode & GM_NETWORK) network_leave_game(); Game_mode |= GM_GAME_OVER; if (Function_mode!=FMODE_EXIT) Function_mode = FMODE_MENU; // N_players = 0; // change_playernum_to(0); // Viewer = ConsoleObject = &Objects[0]; } void multi_show_player_list() { if (!(Game_mode & GM_MULTI) || (Game_mode & GM_MULTI_COOP)) return; if (Show_kill_list) return; Show_kill_list_timer = F1_0*5; // 5 second timer Show_kill_list = 1; } int multi_endlevel(int *secret) { int result = 0; if ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM)) com_endlevel(secret); // an opportunity to re-sync or whatever else if (Game_mode & GM_NETWORK) result = network_endlevel(secret); return(result); } // // Part 2 : functions that act on network/serial messages and change the // the state of the game in some way. // #ifndef MACINTOSH //extern PORT *com_port; #endif int multi_menu_poll(void) { fix old_shields; int was_fuelcen_alive; int player_was_dead; was_fuelcen_alive = Control_center_destroyed; // Special polling function for in-game menus for multiplayer and serial if (! ((Game_mode & GM_MULTI) && (Function_mode == FMODE_GAME)) ) return(0); if (multi_leave_menu) return(-1); old_shields = Players[Player_num].shields; player_was_dead = Player_is_dead; multi_in_menu++; // Track level of menu nesting GameLoop( 0, 0 ); multi_in_menu--; // timer_delay(f1_0/10); changed by allender for portability d_delay(100); // delay 100 milliseconds if (Endlevel_sequence || (Control_center_destroyed && !was_fuelcen_alive) || (Player_is_dead != player_was_dead) || (Players[Player_num].shields < old_shields)) { multi_leave_menu = 1; return(-1); } if ((Control_center_destroyed) && (Countdown_seconds_left < 10)) { multi_leave_menu = 1; return(-1); } #if !defined(WINDOWS) && !defined(MACINTOSH) && (!defined(__ENV_LINUX__) && (!defined (__ENV_DJGPP__))) if ((Game_mode & GM_MODEM) && (!GetCd(com_port))) { multi_leave_menu = 1; return(-1); } #endif return(0); } void multi_define_macro(int key) { if (!(Game_mode & GM_MULTI)) return; key &= (~KEY_SHIFTED); switch(key) { case KEY_F9: multi_defining_message = 1; break; case KEY_F10: multi_defining_message = 2; break; case KEY_F11: multi_defining_message = 3; break; case KEY_F12: multi_defining_message = 4; break; default: Int3(); } if (multi_defining_message) { multi_message_index = 0; Network_message[multi_message_index] = 0; } } char feedback_result[200]; void multi_message_feedback(void) { char *colon; int found = 0; int i; if (!( ((colon = strrchr(Network_message, ':')) == NULL) || (colon-Network_message < 1) || (colon-Network_message > CALLSIGN_LEN) )) { sprintf(feedback_result, "%s ", TXT_MESSAGE_SENT_TO); if ((Game_mode & GM_TEAM) && (atoi(Network_message) > 0) && (atoi(Network_message) < 3)) { sprintf(feedback_result+strlen(feedback_result), "%s '%s'", TXT_TEAM, Netgame.team_name[atoi(Network_message)-1]); found = 1; } if (Game_mode & GM_TEAM) { for (i = 0; i < N_players; i++) { if (!strnicmp(Netgame.team_name[i], Network_message, colon-Network_message)) { if (found) strcat(feedback_result, ", "); found++; if (!(found % 4)) strcat(feedback_result, "\n"); sprintf(feedback_result+strlen(feedback_result), "%s '%s'", TXT_TEAM, Netgame.team_name[i]); } } } for (i = 0; i < N_players; i++) { if ((!strnicmp(Players[i].callsign, Network_message, colon-Network_message)) && (i != Player_num) && (Players[i].connected)) { if (found) strcat(feedback_result, ", "); found++; if (!(found % 4)) strcat(feedback_result, "\n"); sprintf(feedback_result+strlen(feedback_result), "%s", Players[i].callsign); } } if (!found) strcat(feedback_result, TXT_NOBODY); else strcat(feedback_result, "."); digi_play_sample(SOUND_HUD_MESSAGE, F1_0); Assert(strlen(feedback_result) < 200); HUD_init_message(feedback_result); // sprintf (temp,"%s",colon); // sprintf (Network_message,"%s",temp); } } void multi_send_macro(int key) { if (! (Game_mode & GM_MULTI) ) return; switch(key) { case KEY_F9: key = 0; break; case KEY_F10: key = 1; break; case KEY_F11: key = 2; break; case KEY_F12: key = 3; break; default: Int3(); } if (!Network_message_macro[key][0]) { HUD_init_message(TXT_NO_MACRO); return; } strcpy(Network_message, Network_message_macro[key]); Network_message_reciever = 100; HUD_init_message("%s '%s'", TXT_SENDING, Network_message); multi_message_feedback(); } void multi_send_message_start() { if (Game_mode&GM_MULTI) { multi_sending_message = 1; multi_message_index = 0; Network_message[multi_message_index] = 0; } } extern fix StartingShields; fix PingLaunchTime,PingReturnTime; extern void network_send_ping (ubyte); extern void network_dump_player(ubyte * server, ubyte *node, int why); extern int network_who_is_master(); extern void network_send_netgame_update(); extern char NameReturning; extern int force_cockpit_redraw; void network_dump_appletalk_player(ubyte node, ushort net, ubyte socket, int why); void multi_send_message_end() { char *mytempbuf; int i,t; Network_message_reciever = 100; if (!strnicmp (Network_message,"!Names",6)) { NameReturning=1-NameReturning; HUD_init_message ("Name returning is now %s.",NameReturning?"active":"disabled"); } else if (!strnicmp (Network_message,"Handicap:",9)) { mytempbuf=&Network_message[9]; mprintf ((0,"Networkhandi=%s\n",mytempbuf)); StartingShields=atol (mytempbuf); if (StartingShields<10) StartingShields=10; if (StartingShields>100) { sprintf (Network_message,"%s has tried to cheat!",Players[Player_num].callsign); StartingShields=100; } else sprintf (Network_message,"%s handicap is now %d",Players[Player_num].callsign,StartingShields); HUD_init_message ("Telling others of your handicap of %d!",StartingShields); StartingShields=i2f(StartingShields); } else if (!strnicmp (Network_message,"NoBombs",7)) Netgame.DoSmartMine=0; else if (!strnicmp (Network_message,"Ping:",5)) { if (Game_mode & GM_NETWORK) { int name_index=5; if (strlen(Network_message) > 5) while (Network_message[name_index] == ' ') name_index++; if (strlen(Network_message)<=name_index) { HUD_init_message ("You must specify a name to ping"); return; } for (i = 0; i < N_players; i++) if ((!strnicmp(Players[i].callsign, &Network_message[name_index], strlen(Network_message)-name_index)) && (i != Player_num) && (Players[i].connected)) { PingLaunchTime=timer_get_fixed_seconds(); network_send_ping (i); HUD_init_message("Pinging %s...",Players[i].callsign); multi_message_index = 0; multi_sending_message = 0; return; } } else // Modem/Serial ping { PingLaunchTime=timer_get_fixed_seconds(); multi_send_modem_ping (); HUD_init_message("Pinging opponent..."); multi_message_index = 0; multi_sending_message = 0; return; } } else if (!strnicmp (Network_message,"move:",5)) { mprintf ((0,"moving?\n")); if ((Game_mode & GM_NETWORK) && (Game_mode & GM_TEAM)) { int name_index=5; if (strlen(Network_message) > 5) while (Network_message[name_index] == ' ') name_index++; if (!network_i_am_master()) { HUD_init_message ("Only %s can move players!",Players[network_who_is_master()].callsign); return; } if (strlen(Network_message)<=name_index) { HUD_init_message ("You must specify a name to move"); return; } for (i = 0; i < N_players; i++) if ((!strnicmp(Players[i].callsign, &Network_message[name_index], strlen(Network_message)-name_index)) && (Players[i].connected)) { if ((Game_mode & GM_CAPTURE) && (Players[i].flags & PLAYER_FLAGS_FLAG)) { HUD_init_message ("Can't move player because s/he has a flag!"); return; } if (Netgame.team_vector & (1< 5) while (Network_message[name_index] == ' ') name_index++; if (!network_i_am_master()) { HUD_init_message ("Only %s can kick others out!",Players[network_who_is_master()].callsign); multi_message_index = 0; multi_sending_message = 0; return; } if (strlen(Network_message)<=name_index) { HUD_init_message ("You must specify a name to kick"); multi_message_index = 0; multi_sending_message = 0; return; } if (Network_message[name_index] == '#' && isdigit(Network_message[name_index+1])) { int players[MAX_NUM_NET_PLAYERS]; int listpos = Network_message[name_index+1] - '0'; mprintf ((0,"Trying to kick %d , show_kill_list=%d\n",listpos,Show_kill_list)); if (Show_kill_list==1 || Show_kill_list==2) { if (listpos == 0 || listpos >= N_players) { HUD_init_message ("Invalid player number for kick."); multi_message_index = 0; multi_sending_message = 0; return; } multi_get_kill_list(players); i = players[listpos]; if ((i != Player_num) && (Players[i].connected)) goto kick_player; } else HUD_init_message ("You cannot use # kicking with in team display."); multi_message_index = 0; multi_sending_message = 0; return; } for (i = 0; i < N_players; i++) if ((!strnicmp(Players[i].callsign, &Network_message[name_index], strlen(Network_message)-name_index)) && (i != Player_num) && (Players[i].connected)) { kick_player:; if (Network_game_type == IPX_GAME) network_dump_player(NetPlayers.players[i].network.ipx.server,NetPlayers.players[i].network.ipx.node, 7); else network_dump_appletalk_player(NetPlayers.players[i].network.appletalk.node,NetPlayers.players[i].network.appletalk.net, NetPlayers.players[i].network.appletalk.socket, 7); HUD_init_message("Dumping %s...",Players[i].callsign); multi_message_index = 0; multi_sending_message = 0; return; } } else HUD_init_message("%s '%s'", TXT_SENDING, Network_message); multi_send_message(); multi_message_feedback(); multi_message_index = 0; multi_sending_message = 0; } void multi_define_macro_end() { Assert( multi_defining_message > 0 ); strcpy( Network_message_macro[multi_defining_message-1], Network_message ); write_player_file(); multi_message_index = 0; multi_defining_message = 0; } void multi_message_input_sub( int key ) { switch( key ) { case KEY_F8: case KEY_ESC: multi_sending_message = 0; multi_defining_message = 0; game_flush_inputs(); break; case KEY_LEFT: case KEY_BACKSP: case KEY_PAD4: if (multi_message_index > 0) multi_message_index--; Network_message[multi_message_index] = 0; break; case KEY_ENTER: if ( multi_sending_message ) multi_send_message_end(); else if ( multi_defining_message ) multi_define_macro_end(); game_flush_inputs(); break; default: if ( key > 0 ) { int ascii = key_to_ascii(key); if ((ascii < 255 )) { if (multi_message_index < MAX_MESSAGE_LEN-2 ) { Network_message[multi_message_index++] = ascii; Network_message[multi_message_index] = 0; } else if ( multi_sending_message ) { int i; char * ptext, * pcolon; ptext = NULL; Network_message[multi_message_index++] = ascii; Network_message[multi_message_index] = 0; for (i=multi_message_index-1; i>=0; i-- ) { if ( Network_message[i]==32 ) { ptext = &Network_message[i+1]; Network_message[i] = 0; break; } } multi_send_message_end(); if ( ptext ) { multi_sending_message = 1; pcolon = strchr( Network_message, ':' ); if ( pcolon ) strcpy( pcolon+1, ptext ); else strcpy( Network_message, ptext ); multi_message_index = strlen( Network_message ); } } } } } } void multi_send_message_dialog(void) { newmenu_item m[1]; int choice; if (!(Game_mode&GM_MULTI)) return; Network_message[0] = 0; // Get rid of old contents m[0].type=NM_TYPE_INPUT; m[0].text = Network_message; m[0].text_len = MAX_MESSAGE_LEN-1; choice = newmenu_do( NULL, TXT_SEND_MESSAGE, 1, m, NULL ); if ((choice > -1) && (strlen(Network_message) > 0)) { Network_message_reciever = 100; HUD_init_message("%s '%s'", TXT_SENDING, Network_message); multi_message_feedback(); } } void multi_do_death(int objnum) { // Do any miscellaneous stuff for a new network player after death objnum = objnum; if (!(Game_mode & GM_MULTI_COOP)) { mprintf((0, "Setting all keys for player %d.\n", Player_num)); Players[Player_num].flags |= (PLAYER_FLAGS_RED_KEY | PLAYER_FLAGS_BLUE_KEY | PLAYER_FLAGS_GOLD_KEY); } } void multi_do_fire(char *buf) { ubyte weapon; char pnum; byte flags; //static dum=0; // Act out the actual shooting pnum = buf[1]; #ifndef MACINTOSH weapon = (int)buf[2]; #else weapon = buf[2]; #endif flags = buf[4]; Network_laser_track = INTEL_SHORT(*(short *)(buf+6)); Assert (pnum < N_players); if (Objects[Players[(int)pnum].objnum].type == OBJ_GHOST) multi_make_ghost_player(pnum); // mprintf((0,"multi_do_fire, weapon = %d\n",weapon)); if (weapon == FLARE_ADJUST) Laser_player_fire( Objects+Players[(int)pnum].objnum, FLARE_ID, 6, 1, 0); else if (weapon >= MISSILE_ADJUST) { int weapon_id,weapon_gun; weapon_id = Secondary_weapon_to_weapon_info[weapon-MISSILE_ADJUST]; weapon_gun = Secondary_weapon_to_gun_num[weapon-MISSILE_ADJUST] + (flags & 1); mprintf((0,"missile id = %d, gun = %d\n",weapon_id,weapon_gun)); if (weapon-MISSILE_ADJUST==GUIDED_INDEX) { mprintf ((0,"Missile is guided!!!\n")); Multi_is_guided=1; } Laser_player_fire( Objects+Players[(int)pnum].objnum, weapon_id, weapon_gun, 1, 0 ); } else { fix save_charge = Fusion_charge; if (weapon == FUSION_INDEX) { Fusion_charge = flags << 12; mprintf((0, "Fusion charge X%f.\n", f2fl(Fusion_charge))); } if (weapon == LASER_ID) { if (flags & LASER_QUAD) Players[(int)pnum].flags |= PLAYER_FLAGS_QUAD_LASERS; else Players[(int)pnum].flags &= ~PLAYER_FLAGS_QUAD_LASERS; } do_laser_firing(Players[(int)pnum].objnum, weapon, (int)buf[3], flags, (int)buf[5]); if (weapon == FUSION_INDEX) Fusion_charge = save_charge; } } void multi_do_message(char *buf) { char *colon; char *tilde,mesbuf[100]; int tloc,t; int loc = 2; if ((tilde=strchr (buf+loc,'$'))) // do that stupid name stuff { // why'd I put this in? Probably for the tloc=tilde-(buf+loc); // same reason you can name your guidebot mprintf ((0,"Tloc=%d\n",tloc)); if (tloc>0) strncpy (mesbuf,buf+loc,tloc); strcpy (mesbuf+tloc,Players[Player_num].callsign); strcpy (mesbuf+strlen(Players[Player_num].callsign)+tloc,buf+loc+tloc+1); strcpy (buf+loc,mesbuf); } if (((colon = strrchr(buf+loc, ':')) == NULL) || (colon-(buf+loc) < 1) || (colon-(buf+loc) > CALLSIGN_LEN)) { mesbuf[0] = 1; mesbuf[1] = BM_XRGB(28, 0, 0); strcpy(&mesbuf[2], Players[(int)buf[1]].callsign); t = strlen(mesbuf); mesbuf[t] = ':'; mesbuf[t+1] = 1; mesbuf[t+2] = BM_XRGB(0, 31, 0); mesbuf[t+3] = 0; digi_play_sample(SOUND_HUD_MESSAGE, F1_0); HUD_init_message("%s %s", mesbuf, buf+2); } else { if ( (!strnicmp(Players[Player_num].callsign, buf+loc, colon-(buf+loc))) || ((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)))) ) { mesbuf[0] = 1; mesbuf[1] = BM_XRGB(0, 32, 32); strcpy(&mesbuf[2], Players[(int)buf[1]].callsign); t = strlen(mesbuf); mesbuf[t] = ':'; mesbuf[t+1] = 1; mesbuf[t+2] = BM_XRGB(0, 31, 0); mesbuf[t+3] = 0; digi_play_sample(SOUND_HUD_MESSAGE, F1_0); HUD_init_message("%s %s", mesbuf, colon+1); } } } void multi_do_position(char *buf) { #ifdef MACINTOSH shortpos sp; #endif // This routine does only player positions, mode game only // mprintf((0, "Got position packet.\n")); int pnum = (Player_num+1)%2; Assert(&Objects[Players[pnum].objnum] != ConsoleObject); if (Game_mode & GM_NETWORK) { Int3(); // Get Jason, what the hell are we doing here? return; } #ifndef MACINTOSH extract_shortpos(&Objects[Players[pnum].objnum], (shortpos *)(buf+1),0); #else memcpy((ubyte *)(sp.bytemat), (ubyte *)(buf + 1), 9); memcpy((ubyte *)&(sp.xo), (ubyte *)(buf + 10), 14); extract_shortpos(&Objects[Players[pnum].objnum], &sp, 1); #endif if (Objects[Players[pnum].objnum].movement_type == MT_PHYSICS) set_thrust_from_velocity(&Objects[Players[pnum].objnum]); } void multi_do_reappear(char *buf) { short objnum; objnum = INTEL_SHORT(*(short *)(buf+1)); Assert(objnum >= 0); // Assert(Players[Objects[objnum].id]].objnum == objnum); // mprintf((0, "Switching rendering back on for object %d.\n", objnum)); multi_make_ghost_player(Objects[objnum].id); create_player_appearance_effect(&Objects[objnum]); PKilledFlags[Objects[objnum].id]=0; } void multi_do_player_explode(char *buf) { // Only call this for players, not robots. pnum is player number, not // Object number. object *objp; int count; int pnum; int i; char remote_created; pnum = buf[1]; #ifdef NDEBUG if ((pnum < 0) || (pnum >= N_players)) return; #else Assert(pnum >= 0); Assert(pnum < N_players); #endif #ifdef NETWORK // If we are in the process of sending objects to a new player, reset that process if (Network_send_objects) { mprintf((0, "Resetting object sync due to player explosion.\n")); Network_send_objnum = -1; } #endif // Stuff the Players structure to prepare for the explosion count = 2; Players[pnum].primary_weapon_flags = INTEL_SHORT(*(ushort *)(buf+count)); count += 2; Players[pnum].secondary_weapon_flags = INTEL_SHORT(*(ushort *)(buf+count)); count += 2; Players[pnum].laser_level = buf[count]; count++; Players[pnum].secondary_ammo[HOMING_INDEX] = buf[count]; count++; Players[pnum].secondary_ammo[CONCUSSION_INDEX] = buf[count];count++; Players[pnum].secondary_ammo[SMART_INDEX] = buf[count]; count++; Players[pnum].secondary_ammo[MEGA_INDEX] = buf[count]; count++; Players[pnum].secondary_ammo[PROXIMITY_INDEX] = buf[count]; count++; Players[pnum].secondary_ammo[SMISSILE1_INDEX] = buf[count]; count++; Players[pnum].secondary_ammo[GUIDED_INDEX] = buf[count]; count++; Players[pnum].secondary_ammo[SMART_MINE_INDEX]= buf[count]; count++; Players[pnum].secondary_ammo[SMISSILE4_INDEX] = buf[count]; count++; Players[pnum].secondary_ammo[SMISSILE5_INDEX] = buf[count]; count++; Players[pnum].primary_ammo[VULCAN_INDEX] = INTEL_SHORT(*(ushort *)(buf+count)); count += 2; Players[pnum].primary_ammo[GAUSS_INDEX] = INTEL_SHORT(*(ushort *)(buf+count)); count += 2; Players[pnum].flags = INTEL_INT(*(uint *)(buf+count)); count += 4; multi_adjust_remote_cap (pnum); objp = Objects+Players[pnum].objnum; // objp->phys_info.velocity = *(vms_vector *)(buf+16); // 12 bytes // objp->pos = *(vms_vector *)(buf+28); // 12 bytes remote_created = buf[count++]; // How many did the other guy create? Net_create_loc = 0; drop_player_eggs(objp); // Create mapping from remote to local numbering system mprintf((0, "I Created %d powerups, remote created %d.\n", Net_create_loc, remote_created)); // We now handle this situation gracefully, Int3 not required // if (Net_create_loc != remote_created) // Int3(); // Probably out of object array space, see Rob for (i = 0; i < remote_created; i++) { short s; s = INTEL_SHORT(*(short *)(buf+count)); if ((i < Net_create_loc) && (s > 0)) map_objnum_local_to_remote((short)Net_create_objnums[i], s, pnum); else if (*(short *)(buf+count) <= 0) { mprintf((0, "WARNING: Remote created object has non-valid number %d (player %d)", s, pnum)); } else { mprintf((0, "WARNING: Could not create all powerups created by player %d.\n", pnum)); } // Assert(s > 0); count += 2; } for (i = remote_created; i < Net_create_loc; i++) { mprintf((0, "WARNING: I Created more powerups than player %d, deleting.\n", pnum)); Objects[Net_create_objnums[i]].flags |= OF_SHOULD_BE_DEAD; } if (buf[0] == MULTI_PLAYER_EXPLODE) { explode_badass_player(objp); objp->flags &= ~OF_SHOULD_BE_DEAD; //don't really kill player multi_make_player_ghost(pnum); } else { create_player_appearance_effect(objp); } Players[pnum].flags &= ~(PLAYER_FLAGS_CLOAKED | PLAYER_FLAGS_INVULNERABLE | PLAYER_FLAGS_FLAG); Players[pnum].cloak_time = 0; } void multi_do_kill(char *buf) { int killer, killed; int count = 1; int pnum; pnum = (int)(buf[count]); if ((pnum < 0) || (pnum >= N_players)) { Int3(); // Invalid player number killed return; } killed = Players[pnum].objnum; count += 1; killer = INTEL_SHORT(*(short *)(buf+count)); if (killer > 0) killer = objnum_remote_to_local(killer, (byte)buf[count+2]); #ifdef SHAREWARE if ((Objects[killed].type != OBJ_PLAYER) && (Objects[killed].type != OBJ_GHOST)) { Int3(); mprintf( (1, "SOFT INT3: MULTI.C Non-player object %d of type %d killed! (JOHN)\n", killed, Objects[killed].type )); return; } #endif multi_compute_kill(killer, killed); } // Changed by MK on 10/20/94 to send NULL as object to net_destroy_controlcen if it got -1 // which means not a controlcen object, but contained in another object void multi_do_controlcen_destroy(char *buf) { byte who; short objnum; objnum = INTEL_SHORT(*(short *)(buf+1)); who = buf[3]; if (Control_center_destroyed != 1) { if ((who < N_players) && (who != Player_num)) { HUD_init_message("%s %s", Players[who].callsign, TXT_HAS_DEST_CONTROL); } else if (who == Player_num) HUD_init_message(TXT_YOU_DEST_CONTROL); else HUD_init_message(TXT_CONTROL_DESTROYED); if (objnum != -1) net_destroy_controlcen(Objects+objnum); else net_destroy_controlcen(NULL); } } void multi_do_escape(char *buf) { int objnum; objnum = Players[(int)buf[1]].objnum; digi_play_sample(SOUND_HUD_MESSAGE, F1_0); digi_kill_sound_linked_to_object (objnum); if (buf[2] == 0) { HUD_init_message("%s %s", Players[(int)buf[1]].callsign, TXT_HAS_ESCAPED); if (Game_mode & GM_NETWORK) Players[(int)buf[1]].connected = CONNECT_ESCAPE_TUNNEL; if (!multi_goto_secret) multi_goto_secret = 2; } else if (buf[2] == 1) { HUD_init_message("%s %s", Players[(int)buf[1]].callsign, TXT_HAS_FOUND_SECRET); if (Game_mode & GM_NETWORK) Players[(int)buf[1]].connected = CONNECT_FOUND_SECRET; if (!multi_goto_secret) multi_goto_secret = 1; } create_player_appearance_effect(&Objects[objnum]); multi_make_player_ghost(buf[1]); } void multi_do_remobj(char *buf) { short objnum; // which object to remove short local_objnum; byte obj_owner; // which remote list is it entered in objnum = INTEL_SHORT(*(short *)(buf+1)); obj_owner = buf[3]; Assert(objnum >= 0); if (objnum < 1) return; local_objnum = objnum_remote_to_local(objnum, obj_owner); // translate to local objnum // mprintf((0, "multi_do_remobj: %d owner %d = %d.\n", objnum, obj_owner, local_objnum)); if (local_objnum < 0) { mprintf((1, "multi_do_remobj: Could not remove referenced object.\n")); return; } if ((Objects[local_objnum].type != OBJ_POWERUP) && (Objects[local_objnum].type != OBJ_HOSTAGE)) { mprintf((1, "multi_get_remobj: tried to remove invalid type %d.\n", Objects[local_objnum].type)); return; } if (Network_send_objects && network_objnum_is_past(local_objnum)) { mprintf((0, "Resetting object sync due to object removal.\n")); Network_send_objnum = -1; } if (Objects[local_objnum].type==OBJ_POWERUP) if (Game_mode & GM_NETWORK) { if (PowerupsInMine[Objects[local_objnum].id]>0) PowerupsInMine[Objects[local_objnum].id]--; if (multi_powerup_is_4pack (Objects[local_objnum].id)) { mprintf ((0,"Hey babe! Doing that wacky 4 pack stuff.")); if (PowerupsInMine[Objects[local_objnum].id-1]-4<0) PowerupsInMine[Objects[local_objnum].id-1]=0; else PowerupsInMine[Objects[local_objnum].id-1]-=4; } mprintf ((0,"Decrementing powerups! %d\n",PowerupsInMine[Objects[local_objnum].id])); } Objects[local_objnum].flags |= OF_SHOULD_BE_DEAD; // quick and painless } void multi_do_quit(char *buf) { if (Game_mode & GM_NETWORK) { int i, n = 0; digi_play_sample( SOUND_HUD_MESSAGE, F1_0 ); HUD_init_message( "%s %s", Players[(int)buf[1]].callsign, TXT_HAS_LEFT_THE_GAME); network_disconnect_player(buf[1]); if (multi_in_menu) return; for (i = 0; i < N_players; i++) if (Players[i].connected) n++; if (n == 1) { nm_messagebox(NULL, 1, TXT_OK, TXT_YOU_ARE_ONLY); } } if ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM)) { Function_mode = FMODE_MENU; multi_quit_game = 1; multi_leave_menu = 1; nm_messagebox(NULL, 1, TXT_OK, TXT_OPPONENT_LEFT); Function_mode = FMODE_GAME; multi_reset_stuff(); } return; } void multi_do_cloak(char *buf) { int pnum; pnum = (int)(buf[1]); Assert(pnum < N_players); mprintf((0, "Cloaking player %d\n", pnum)); Players[pnum].flags |= PLAYER_FLAGS_CLOAKED; Players[pnum].cloak_time = GameTime; ai_do_cloak_stuff(); #ifndef SHAREWARE if (Game_mode & GM_MULTI_ROBOTS) multi_strip_robots(pnum); #endif if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_multi_cloak(pnum); } void multi_do_decloak(char *buf) { int pnum; pnum = (int)(buf[1]); if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_multi_decloak(pnum); } void multi_do_door_open(char *buf) { int segnum; byte side; segment *seg; wall *w; ubyte flag; segnum = INTEL_SHORT(*(short *)(buf+1)); side = buf[3]; flag= buf[4]; // mprintf((0, "Opening door on side %d of segment # %d.\n", side, segnum)); if ((segnum < 0) || (segnum > Highest_segment_index) || (side < 0) || (side > 5)) { Int3(); return; } seg = &Segments[segnum]; if (seg->sides[side].wall_num == -1) { //Opening door on illegal wall Int3(); return; } w = &Walls[seg->sides[side].wall_num]; if (w->type == WALL_BLASTABLE) { if (!(w->flags & WALL_BLASTED)) { mprintf((0, "Blasting wall by remote command.\n")); wall_destroy(seg, side); } return; } else if (w->state != WALL_DOOR_OPENING) { wall_open_door(seg, side); w->flags=flag; } else w->flags=flag; // else // mprintf((0, "Door already opening!\n")); } void multi_do_create_explosion(char *buf) { int pnum; int count = 1; pnum = buf[count++]; // mprintf((0, "Creating small fireball.\n")); create_small_fireball_on_object(&Objects[Players[pnum].objnum], F1_0, 1); } void multi_do_controlcen_fire(char *buf) { vms_vector to_target; char gun_num; short objnum; int count = 1; memcpy(&to_target, buf+count, 12); count += 12; #ifdef MACINTOSH // swap the vector to_target to_target.x = (fix)INTEL_INT((int)to_target.x); to_target.y = (fix)INTEL_INT((int)to_target.y); to_target.z = (fix)INTEL_INT((int)to_target.z); #endif gun_num = buf[count]; count += 1; objnum = INTEL_SHORT(*(short *)(buf+count)); count += 2; Laser_create_new_easy(&to_target, &Gun_pos[(int)gun_num], objnum, CONTROLCEN_WEAPON_NUM, 1); } void multi_do_create_powerup(char *buf) { short segnum; short objnum; int my_objnum; char pnum; int count = 1; vms_vector new_pos; char powerup_type; if (Endlevel_sequence || Control_center_destroyed) return; pnum = buf[count++]; powerup_type = buf[count++]; segnum = INTEL_SHORT(*(short *)(buf+count)); count+=2; objnum = INTEL_SHORT(*(short *)(buf+count)); count+=2; if ((segnum < 0) || (segnum > Highest_segment_index)) { Int3(); return; } new_pos = *(vms_vector *)(buf+count); count+=sizeof(vms_vector); #ifdef MACINTOSH new_pos.x = (fix)SWAPINT((int)new_pos.x); new_pos.y = (fix)SWAPINT((int)new_pos.y); new_pos.z = (fix)SWAPINT((int)new_pos.z); #endif Net_create_loc = 0; my_objnum = call_object_create_egg(&Objects[Players[(int)pnum].objnum], 1, OBJ_POWERUP, powerup_type); if (my_objnum < 0) { mprintf((0, "Could not create new powerup!\n")); return; } if (Network_send_objects && network_objnum_is_past(my_objnum)) { mprintf((0, "Resetting object sync due to powerup creation.\n")); Network_send_objnum = -1; } Objects[my_objnum].pos = new_pos; vm_vec_zero(&Objects[my_objnum].mtype.phys_info.velocity); obj_relink(my_objnum, segnum); map_objnum_local_to_remote(my_objnum, objnum, pnum); object_create_explosion(segnum, &new_pos, i2f(5), VCLIP_POWERUP_DISAPPEARANCE); mprintf((0, "Creating powerup type %d in segment %i.\n", powerup_type, segnum)); if (Game_mode & GM_NETWORK) PowerupsInMine[(int)powerup_type]++; } void multi_do_play_sound(char *buf) { int pnum = (int)(buf[1]); int sound_num = (int)(buf[2]); fix volume = (int)(buf[3]) << 12; if (!Players[pnum].connected) return; Assert(Players[pnum].objnum >= 0); Assert(Players[pnum].objnum <= Highest_object_index); digi_link_sound_to_object( sound_num, Players[pnum].objnum, 0, volume); } void multi_do_score(char *buf) { int pnum = (int)(buf[1]); if ((pnum < 0) || (pnum >= N_players)) { Int3(); // Non-terminal, see rob return; } if (Newdemo_state == ND_STATE_RECORDING) newdemo_record_multi_score(pnum, INTEL_INT(*(int *)(buf+2)) ); Players[pnum].score = INTEL_INT(*(int *)(buf+2)); multi_sort_kill_list(); } void multi_do_trigger(char *buf) { int pnum = (int)(buf[1]); int trigger = (int)(buf[2]); mprintf ((0,"MULTI doing trigger!\n")); if ((pnum < 0) || (pnum >= N_players) || (pnum == Player_num)) { Int3(); // Got trigger from illegal playernum return; } if ((trigger < 0) || (trigger >= Num_triggers)) { Int3(); // Illegal trigger number in multiplayer return; } check_trigger_sub(trigger, pnum,0); } void multi_do_drop_marker (char *buf) { int i; int pnum=(int)(buf[1]); int mesnum=(int)(buf[2]); vms_vector position; if (pnum==Player_num) // my marker? don't set it down cuz it might screw up the orientation return; position.x=(fix)INTEL_INT(*(int *)(buf+3)); position.y=(fix)INTEL_INT(*(int *)(buf+7)); position.z=(fix)INTEL_INT(*(int *)(buf+11)); for (i=0;i<40;i++) MarkerMessage[(pnum*2)+mesnum][i]=buf[15+i]; MarkerPoint[(pnum*2)+mesnum]=position; if (MarkerObject[(pnum*2)+mesnum] !=-1 && Objects[MarkerObject[(pnum*2)+mesnum]].type!=OBJ_NONE && MarkerObject[(pnum*2)+mesnum] !=0) obj_delete(MarkerObject[(pnum*2)+mesnum]); MarkerObject[(pnum*2)+mesnum] = drop_marker_object(&position,Objects[Players[Player_num].objnum].segnum,&Objects[Players[Player_num].objnum].orient,(pnum*2)+mesnum); strcpy (MarkerOwner[(pnum*2)+mesnum],Players[pnum].callsign); mprintf ((0,"Dropped player %d message: %s\n",pnum,MarkerMessage[(pnum*2)+mesnum])); } void multi_do_hostage_door_status(char *buf) { // Update hit point status of a door int count = 1; int wallnum; fix hps; wallnum = INTEL_SHORT(*(short *)(buf+count)); count += 2; hps = (fix)INTEL_INT(*(int *)(buf+count)); count += 4; if ((wallnum < 0) || (wallnum > Num_walls) || (hps < 0) || (Walls[wallnum].type != WALL_BLASTABLE)) { Int3(); // Non-terminal, see Rob return; } // mprintf((0, "Damaging wall number %d to %f points.\n", wallnum, f2fl(hps))); if (hps < Walls[wallnum].hps) wall_damage(&Segments[Walls[wallnum].segnum], Walls[wallnum].sidenum, Walls[wallnum].hps - hps); } void multi_do_save_game(char *buf) { int count = 1; ubyte slot; uint id; char desc[25]; slot = *(ubyte *)(buf+count); count += 1; id = INTEL_INT(*(uint *)(buf+count)); count += 4; memcpy( desc, &buf[count], 20 ); count += 20; multi_save_game( slot, id, desc ); } void multi_do_restore_game(char *buf) { int count = 1; ubyte slot; uint id; slot = *(ubyte *)(buf+count); count += 1; id = INTEL_INT(*(uint *)(buf+count)); count += 4; multi_restore_game( slot, id ); } void multi_do_req_player(char *buf) { netplayer_stats ps; ubyte player_n; // Send my netplayer_stats to everyone! player_n = *(ubyte *)(buf+1); if ( (player_n == Player_num) || (player_n == 255) ) { extract_netplayer_stats( &ps, &Players[Player_num] ); ps.Player_num = Player_num; ps.message_type = MULTI_SEND_PLAYER; // SET multi_send_data((ubyte*)&ps, sizeof(netplayer_stats), 0); } } void multi_do_send_player(char *buf) { // Got a player packet from someone!!! netplayer_stats * p; p = (netplayer_stats *)buf; Assert( p->Player_num <= N_players ); mprintf(( 0, "Got netplayer_stats for player %d (I'm %d)\n", p->Player_num, Player_num )); mprintf(( 0, "Their shields are: %d\n", f2i(p->shields) )); use_netplayer_stats( &Players[p->Player_num], p ); } void multi_reset_stuff(void) { // A generic, emergency function to solve problems that crop up // when a player exits quick-out from the game because of a // serial connection loss. Fixes several weird bugs! dead_player_end(); Players[Player_num].homing_object_dist = -F1_0; // Turn off homing sound. Dead_player_camera = 0; Endlevel_sequence = 0; reset_rear_view(); } void multi_reset_player_object(object *objp) { int i; //Init physics for a non-console player Assert(objp >= Objects); Assert(objp <= Objects+Highest_object_index); Assert((objp->type == OBJ_PLAYER) || (objp->type == OBJ_GHOST)); vm_vec_zero(&objp->mtype.phys_info.velocity); vm_vec_zero(&objp->mtype.phys_info.thrust); vm_vec_zero(&objp->mtype.phys_info.rotvel); vm_vec_zero(&objp->mtype.phys_info.rotthrust); objp->mtype.phys_info.brakes = objp->mtype.phys_info.turnroll = 0; objp->mtype.phys_info.mass = Player_ship->mass; objp->mtype.phys_info.drag = Player_ship->drag; // objp->mtype.phys_info.flags &= ~(PF_TURNROLL | PF_LEVELLING | PF_WIGGLE | PF_USES_THRUST); objp->mtype.phys_info.flags &= ~(PF_TURNROLL | PF_LEVELLING | PF_WIGGLE); //Init render info objp->render_type = RT_POLYOBJ; objp->rtype.pobj_info.model_num = Player_ship->model_num; //what model is this? objp->rtype.pobj_info.subobj_flags = 0; //zero the flags for (i=0;irtype.pobj_info.anim_angles[i]); //reset textures for this, if not player 0 multi_reset_object_texture (objp); // Clear misc objp->flags = 0; if (objp->type == OBJ_GHOST) objp->render_type = RT_NONE; } void multi_reset_object_texture (object *objp) { int id,i; if (Game_mode & GM_TEAM) id = get_team(objp->id); else id = objp->id; if (id == 0) objp->rtype.pobj_info.alt_textures=0; else { Assert(N_PLAYER_SHIP_TEXTURES == Polygon_models[objp->rtype.pobj_info.model_num].n_textures); for (i=0;irtype.pobj_info.model_num].first_texture+i]]; multi_player_textures[id-1][4] = ObjBitmaps[ObjBitmapPtrs[First_multi_bitmap_num+(id-1)*2]]; multi_player_textures[id-1][5] = ObjBitmaps[ObjBitmapPtrs[First_multi_bitmap_num+(id-1)*2+1]]; objp->rtype.pobj_info.alt_textures = id; } } extern int TTRecv[]; extern FILE *RecieveLogFile; void multi_process_bigdata(char *buf, int len) { // Takes a bunch of messages, check them for validity, // and pass them to multi_process_data. int type, sub_len, bytes_processed = 0; while( bytes_processed < len ) { type = buf[bytes_processed]; if ( (type<0) || (type>MULTI_MAX_TYPE)) { mprintf( (1, "multi_process_bigdata: Invalid packet type %d!\n", type )); return; } sub_len = message_length[type]; Assert(sub_len > 0); if ( (bytes_processed+sub_len) > len ) { mprintf( (1, "multi_process_bigdata: packet type %d too short (%d>%d)!\n", type, (bytes_processed+sub_len), len )); Int3(); return; } multi_process_data(&buf[bytes_processed], sub_len); bytes_processed += sub_len; } } // // Part 2 : Functions that send communication messages to inform the other // players of something we did. // void multi_send_fire(void) { if (!Network_laser_fired) return; multibuf[0] = (char)MULTI_FIRE; multibuf[1] = (char)Player_num; multibuf[2] = (char)Network_laser_gun; multibuf[3] = (char)Network_laser_level; multibuf[4] = (char)Network_laser_flags; multibuf[5] = (char)Network_laser_fired; *(short *)(multibuf+6) = INTEL_SHORT(Network_laser_track); multi_send_data(multibuf, 8, 0); Network_laser_fired = 0; } void multi_send_destroy_controlcen(int objnum, int player) { if (player == Player_num) HUD_init_message(TXT_YOU_DEST_CONTROL); else if ((player > 0) && (player < N_players)) HUD_init_message("%s %s", Players[player].callsign, TXT_HAS_DEST_CONTROL); else HUD_init_message(TXT_CONTROL_DESTROYED); multibuf[0] = (char)MULTI_CONTROLCEN; *(ushort *)(multibuf+1) = INTEL_SHORT(objnum); multibuf[3] = player; multi_send_data(multibuf, 4, 2); } void multi_send_drop_marker (int player,vms_vector position,char messagenum,char text[]) { int i; if (player message_length[MULTI_PLAYER_EXPLODE]) { Int3(); // See Rob } multi_send_data(multibuf, message_length[MULTI_PLAYER_EXPLODE], 2); if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) multi_send_decloak(); if (Game_mode & GM_MULTI_ROBOTS) multi_strip_robots(Player_num); } extern ubyte Secondary_weapon_to_powerup[]; extern ubyte Primary_weapon_to_powerup[]; // put a lid on how many objects will be spewed by an exploding player // to prevent rampant powerups in netgames void multi_cap_objects () { char type,flagtype; int index; if (!(Game_mode & GM_NETWORK)) return; for (index=0;index=MaxPowerupsAllowed[(int)type]) if(Players[Player_num].primary_weapon_flags & (1 << index)) { mprintf ((0,"PIM=%d MPA=%d\n",PowerupsInMine[(int)type],MaxPowerupsAllowed[(int)type])); mprintf ((0,"Killing a primary cuz there's too many! (%d)\n",(int)type)); Players[Player_num].primary_weapon_flags&=(~(1 << index)); } } // Don't do the adjustment stuff for Hoard mode if (!(Game_mode & GM_HOARD)) Players[Player_num].secondary_ammo[2]/=4; Players[Player_num].secondary_ammo[7]/=4; for (index=0;indexMaxPowerupsAllowed[(int)type]) { if (MaxPowerupsAllowed[(int)type]-PowerupsInMine[(int)type]<0) Players[Player_num].secondary_ammo[index]=0; else Players[Player_num].secondary_ammo[index]=(MaxPowerupsAllowed[(int)type]-PowerupsInMine[(int)type]); mprintf ((0,"Hey! I killed secondary type %d because PIM=%d MPA=%d\n",(int)type,PowerupsInMine[(int)type],MaxPowerupsAllowed[(int)type])); } } if (!(Game_mode & GM_HOARD)) Players[Player_num].secondary_ammo[2]*=4; Players[Player_num].secondary_ammo[7]*=4; if (Players[Player_num].laser_level > MAX_LASER_LEVEL) if (PowerupsInMine[POW_SUPER_LASER]+1 > MaxPowerupsAllowed[POW_SUPER_LASER]) Players[Player_num].laser_level=0; if (Players[Player_num].flags & PLAYER_FLAGS_QUAD_LASERS) if (PowerupsInMine[POW_QUAD_FIRE]+1 > MaxPowerupsAllowed[POW_QUAD_FIRE]) Players[Player_num].flags&=(~PLAYER_FLAGS_QUAD_LASERS); if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED) if (PowerupsInMine[POW_CLOAK]+1 > MaxPowerupsAllowed[POW_CLOAK]) Players[Player_num].flags&=(~PLAYER_FLAGS_CLOAKED); if (Players[Player_num].flags & PLAYER_FLAGS_MAP_ALL) if (PowerupsInMine[POW_FULL_MAP]+1 > MaxPowerupsAllowed[POW_FULL_MAP]) Players[Player_num].flags&=(~PLAYER_FLAGS_MAP_ALL); if (Players[Player_num].flags & PLAYER_FLAGS_AFTERBURNER) if (PowerupsInMine[POW_AFTERBURNER]+1 > MaxPowerupsAllowed[POW_AFTERBURNER]) Players[Player_num].flags&=(~PLAYER_FLAGS_AFTERBURNER); if (Players[Player_num].flags & PLAYER_FLAGS_AMMO_RACK) if (PowerupsInMine[POW_AMMO_RACK]+1 > MaxPowerupsAllowed[POW_AMMO_RACK]) Players[Player_num].flags&=(~PLAYER_FLAGS_AMMO_RACK); if (Players[Player_num].flags & PLAYER_FLAGS_CONVERTER) if (PowerupsInMine[POW_CONVERTER]+1 > MaxPowerupsAllowed[POW_CONVERTER]) Players[Player_num].flags&=(~PLAYER_FLAGS_CONVERTER); if (Players[Player_num].flags & PLAYER_FLAGS_HEADLIGHT) if (PowerupsInMine[POW_HEADLIGHT]+1 > MaxPowerupsAllowed[POW_HEADLIGHT]) Players[Player_num].flags&=(~PLAYER_FLAGS_HEADLIGHT); if (Game_mode & GM_CAPTURE) { if (Players[Player_num].flags & PLAYER_FLAGS_FLAG) { if (get_team(Player_num)==TEAM_RED) flagtype=POW_FLAG_BLUE; else flagtype=POW_FLAG_RED; if (PowerupsInMine[(int)flagtype]+1 > MaxPowerupsAllowed[(int)flagtype]) Players[Player_num].flags&=(~PLAYER_FLAGS_FLAG); } } } // adds players inventory to multi cap void multi_adjust_cap_for_player (int pnum) { char type; int index; if (!(Game_mode & GM_NETWORK)) return; for (index=0;index MAX_LASER_LEVEL) MaxPowerupsAllowed[POW_SUPER_LASER]++; if (Players[pnum].flags & PLAYER_FLAGS_QUAD_LASERS) MaxPowerupsAllowed[POW_QUAD_FIRE]++; if (Players[pnum].flags & PLAYER_FLAGS_CLOAKED) MaxPowerupsAllowed[POW_CLOAK]++; if (Players[pnum].flags & PLAYER_FLAGS_MAP_ALL) MaxPowerupsAllowed[POW_FULL_MAP]++; if (Players[pnum].flags & PLAYER_FLAGS_AFTERBURNER) MaxPowerupsAllowed[POW_AFTERBURNER]++; if (Players[pnum].flags & PLAYER_FLAGS_AMMO_RACK) MaxPowerupsAllowed[POW_AMMO_RACK]++; if (Players[pnum].flags & PLAYER_FLAGS_CONVERTER) MaxPowerupsAllowed[POW_CONVERTER]++; if (Players[pnum].flags & PLAYER_FLAGS_HEADLIGHT) MaxPowerupsAllowed[POW_HEADLIGHT]++; } void multi_adjust_remote_cap (int pnum) { char type; int index; if (!(Game_mode & GM_NETWORK)) return; for (index=0;index MAX_LASER_LEVEL) PowerupsInMine[POW_SUPER_LASER]++; if (Players[pnum].flags & PLAYER_FLAGS_QUAD_LASERS) PowerupsInMine[POW_QUAD_FIRE]++; if (Players[pnum].flags & PLAYER_FLAGS_CLOAKED) PowerupsInMine[POW_CLOAK]++; if (Players[pnum].flags & PLAYER_FLAGS_MAP_ALL) PowerupsInMine[POW_FULL_MAP]++; if (Players[pnum].flags & PLAYER_FLAGS_AFTERBURNER) PowerupsInMine[POW_AFTERBURNER]++; if (Players[pnum].flags & PLAYER_FLAGS_AMMO_RACK) PowerupsInMine[POW_AMMO_RACK]++; if (Players[pnum].flags & PLAYER_FLAGS_CONVERTER) PowerupsInMine[POW_CONVERTER]++; if (Players[pnum].flags & PLAYER_FLAGS_HEADLIGHT) PowerupsInMine[POW_HEADLIGHT]++; } void multi_send_message(void) { int loc = 0; if (Network_message_reciever != -1) { multibuf[loc] = (char)MULTI_MESSAGE; loc += 1; multibuf[loc] = (char)Player_num; loc += 1; strncpy(multibuf+loc, Network_message, MAX_MESSAGE_LEN); loc += MAX_MESSAGE_LEN; multibuf[loc-1] = '\0'; multi_send_data(multibuf, loc, 0); Network_message_reciever = -1; } } void multi_send_reappear() { multibuf[0] = (char)MULTI_REAPPEAR; *(short *)(multibuf+1) = INTEL_SHORT(Players[Player_num].objnum); multi_send_data(multibuf, 3, 2); PKilledFlags[Player_num]=0; } void multi_send_position(int objnum) { #ifdef MACINTOSH shortpos sp; #endif int count=0; if (Game_mode & GM_NETWORK) { return; } multibuf[count++] = (char)MULTI_POSITION; #ifndef MACINTOSH create_shortpos((shortpos *)(multibuf+count), Objects+objnum,0); count += sizeof(shortpos); #else create_shortpos(&sp, Objects+objnum, 1); memcpy(&(multibuf[count]), (ubyte *)(sp.bytemat), 9); count += 9; memcpy(&(multibuf[count]), (ubyte *)&(sp.xo), 14); count += 14; #endif multi_send_data(multibuf, count, 0); } void multi_send_kill(int objnum) { // I died, tell the world. int killer_objnum; int count = 0; Assert(Objects[objnum].id == Player_num); killer_objnum = Players[Player_num].killer_objnum; multi_compute_kill(killer_objnum, objnum); multibuf[0] = (char)MULTI_KILL; count += 1; multibuf[1] = Player_num; count += 1; if (killer_objnum > -1) { short s; // do it with variable since INTEL_SHORT won't work on return val from function. s = (short)objnum_local_to_remote(killer_objnum, (byte *)&multibuf[count+2]); *(short *)(multibuf+count) = INTEL_SHORT(s); } else { *(short *)(multibuf+count) = INTEL_SHORT((short)-1); multibuf[count+2] = (char)-1; } count += 3; multi_send_data(multibuf, count, 1); #ifndef SHAREWARE if (Game_mode & GM_MULTI_ROBOTS) multi_strip_robots(Player_num); #endif } void multi_send_remobj(int objnum) { // Tell the other guy to remove an object from his list byte obj_owner; short remote_objnum; if (Objects[objnum].type==OBJ_POWERUP && (Game_mode & GM_NETWORK)) { if (PowerupsInMine[Objects[objnum].id] > 0) { PowerupsInMine[Objects[objnum].id]--; if (multi_powerup_is_4pack (Objects[objnum].id)) { mprintf ((0,"Hey babe! Doing that wacky 4 pack stuff.")); if (PowerupsInMine[Objects[objnum].id-1]-4<0) PowerupsInMine[Objects[objnum].id-1]=0; else PowerupsInMine[Objects[objnum].id-1]-=4; } } } multibuf[0] = (char)MULTI_REMOVE_OBJECT; remote_objnum = objnum_local_to_remote((short)objnum, &obj_owner); *(short *)(multibuf+1) = INTEL_SHORT(remote_objnum); // Map to network objnums multibuf[3] = obj_owner; // mprintf((0, "multi_send_remobj: %d = %d owner %d.\n", objnum, remote_objnum, obj_owner)); multi_send_data(multibuf, 4, 0); if (Network_send_objects && network_objnum_is_past(objnum)) { mprintf((0, "Resetting object sync due to object removal.\n")); Network_send_objnum = -1; } } void multi_send_quit(int why) { // I am quitting the game, tell the other guy the bad news. Assert (why == MULTI_QUIT); multibuf[0] = (char)why; multibuf[1] = Player_num; multi_send_data(multibuf, 2, 1); } void multi_send_cloak(void) { // Broadcast a change in our pflags (made to support cloaking) multibuf[0] = MULTI_CLOAK; multibuf[1] = (char)Player_num; multi_send_data(multibuf, 2, 1); #ifndef SHAREWARE if (Game_mode & GM_MULTI_ROBOTS) multi_strip_robots(Player_num); #endif } void multi_send_decloak(void) { // Broadcast a change in our pflags (made to support cloaking) multibuf[0] = MULTI_DECLOAK; multibuf[1] = (char)Player_num; multi_send_data(multibuf, 2, 1); } void multi_send_door_open(int segnum, int side,ubyte flag) { // When we open a door make sure everyone else opens that door multibuf[0] = MULTI_DOOR_OPEN; *(short *)(multibuf+1) = INTEL_SHORT( (short)segnum ); multibuf[3] = (byte)side; multibuf[4] = flag; multi_send_data(multibuf, 5, 2); } extern void network_send_naked_packet (char *,short,int); void multi_send_door_open_specific(int pnum,int segnum, int side,ubyte flag) { // For sending doors only to a specific person (usually when they're joining) Assert (Game_mode & GM_NETWORK); // Assert (pnum>-1 && pnumx ); swapped_vec.y = (fix)INTEL_INT( (int)to_goal->y ); swapped_vec.z = (fix)INTEL_INT( (int)to_goal->z ); memcpy(multibuf+count, &swapped_vec, 12); count += 12; #endif multibuf[count] = (char)best_gun_num; count += 1; *(short *)(multibuf+count) = INTEL_SHORT( (short)objnum ); count += 2; // ------------ // Total = 16 multi_send_data(multibuf, count, 0); } void multi_send_create_powerup(int powerup_type, int segnum, int objnum, vms_vector *pos) { // Create a powerup on a remote machine, used for remote // placement of used powerups like missiles and cloaking // powerups. #ifdef MACINTOSH vms_vector swapped_vec; #endif int count = 0; if (Game_mode & GM_NETWORK) PowerupsInMine[powerup_type]++; multibuf[count] = MULTI_CREATE_POWERUP; count += 1; multibuf[count] = Player_num; count += 1; multibuf[count] = powerup_type; count += 1; *(short *)(multibuf+count) = INTEL_SHORT( (short)segnum ); count += 2; *(short *)(multibuf+count) = INTEL_SHORT( (short)objnum ); count += 2; #ifndef MACINTOSH *(vms_vector *)(multibuf+count) = *pos; count += sizeof(vms_vector); #else swapped_vec.x = (fix)INTEL_INT( (int)pos->x ); swapped_vec.y = (fix)INTEL_INT( (int)pos->y ); swapped_vec.z = (fix)INTEL_INT( (int)pos->z ); memcpy(multibuf+count, &swapped_vec, 12); count += 12; #endif // ----------- // Total = 19 multi_send_data(multibuf, count, 2); if (Network_send_objects && network_objnum_is_past(objnum)) { mprintf((0, "Resetting object sync due to powerup creation.\n")); Network_send_objnum = -1; } mprintf((0, "Creating powerup type %d in segment %i.\n", powerup_type, segnum)); map_objnum_local_to_local(objnum); } void multi_send_play_sound(int sound_num, fix volume) { int count = 0; multibuf[count] = MULTI_PLAY_SOUND; count += 1; multibuf[count] = Player_num; count += 1; multibuf[count] = (char)sound_num; count += 1; multibuf[count] = (char)(volume >> 12); count += 1; // ----------- // Total = 4 multi_send_data(multibuf, count, 0); } void multi_send_audio_taunt(int taunt_num) { return; // Taken out, awaiting sounds.. #if 0 int audio_taunts[4] = { SOUND_CONTROL_CENTER_WARNING_SIREN, SOUND_HOSTAGE_RESCUED, SOUND_REFUEL_STATION_GIVING_FUEL, SOUND_BAD_SELECTION }; Assert(taunt_num >= 0); Assert(taunt_num < 4); digi_play_sample( audio_taunts[taunt_num], F1_0 ); multi_send_play_sound(audio_taunts[taunt_num], F1_0); #endif } void multi_send_score(void) { // Send my current score to all other players so it will remain // synced. int count = 0; if (Game_mode & GM_MULTI_COOP) { multi_sort_kill_list(); multibuf[count] = MULTI_SCORE; count += 1; multibuf[count] = Player_num; count += 1; *(int *)(multibuf+count) = INTEL_INT( Players[Player_num].score ); count += 4; multi_send_data(multibuf, count, 0); } } void multi_send_save_game(ubyte slot, uint id, char * desc) { int count = 0; multibuf[count] = MULTI_SAVE_GAME; count += 1; multibuf[count] = slot; count += 1; // Save slot=0 *(uint *)(multibuf+count) = INTEL_INT( id ); count += 4; // Save id memcpy( &multibuf[count], desc, 20 ); count += 20; multi_send_data(multibuf, count, 2); } void multi_send_restore_game(ubyte slot, uint id) { int count = 0; multibuf[count] = MULTI_RESTORE_GAME; count += 1; multibuf[count] = slot; count += 1; // Save slot=0 *(uint *)(multibuf+count) = INTEL_INT( id ); count += 4; // Save id multi_send_data(multibuf, count, 2); } void multi_send_netplayer_stats_request(ubyte player_num) { int count = 0; multibuf[count] = MULTI_REQ_PLAYER; count += 1; multibuf[count] = player_num; count += 1; multi_send_data(multibuf, count, 0 ); } void multi_send_trigger(int triggernum) { // Send an even to trigger something in the mine int count = 0; multibuf[count] = MULTI_TRIGGER; count += 1; multibuf[count] = Player_num; count += 1; multibuf[count] = (ubyte)triggernum; count += 1; mprintf ((0,"Sending trigger %d\n",triggernum)); multi_send_data(multibuf, count, 1); // multi_send_data(multibuf, count, 1); // twice? } void multi_send_hostage_door_status(int wallnum) { // Tell the other player what the hit point status of a hostage door // should be int count = 0; Assert(Walls[wallnum].type == WALL_BLASTABLE); multibuf[count] = MULTI_HOSTAGE_DOOR; count += 1; *(short *)(multibuf+count) = INTEL_SHORT( (short)wallnum ); count += 2; *(fix *)(multibuf+count) = (fix)INTEL_INT( (int)Walls[wallnum].hps ); count += 4; // mprintf((0, "Door %d damaged by %f points.\n", wallnum, f2fl(Walls[wallnum].hps))); multi_send_data(multibuf, count, 0); } extern int ConsistencyCount; extern int Drop_afterburner_blob_flag; int PhallicLimit=0; int PhallicMan=-1; void multi_prep_level(void) { // Do any special stuff to the level required for serial games // before we begin playing in it. // Player_num MUST be set before calling this procedure. // This function must be called before checksuming the Object array, // since the resulting checksum with depend on the value of Player_num // at the time this is called. int i,ng=0; int cloak_count, inv_count; Assert(Game_mode & GM_MULTI); Assert(NumNetPlayerPositions > 0); PhallicLimit=0; PhallicMan=-1; Drop_afterburner_blob_flag=0; ConsistencyCount=0; for (i=0;i= POW_KEY_BLUE) && (Objects[i].id <= POW_KEY_GOLD)) { Objects[i].id = POW_SHIELD_BOOST; Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num; Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time; } if (Objects[i].id == POW_INVULNERABILITY) { if (inv_count >= 3 || (ng && !Netgame.DoInvulnerability)) { mprintf((0, "Bashing Invulnerability object #%i to shield.\n", i)); Objects[i].id = POW_SHIELD_BOOST; Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num; Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time; } else inv_count++; } if (Objects[i].id == POW_CLOAK) { if (cloak_count >= 3 || (ng && !Netgame.DoCloak)) { mprintf((0, "Bashing Cloak object #%i to shield.\n", i)); Objects[i].id = POW_SHIELD_BOOST; Objects[i].rtype.vclip_info.vclip_num = Powerup_info[Objects[i].id].vclip_num; Objects[i].rtype.vclip_info.frametime = Vclip[Objects[i].rtype.vclip_info.vclip_num].frame_time; } else cloak_count++; } if (Objects[i].id == POW_AFTERBURNER && ng && !Netgame.DoAfterburner) bash_to_shield (i,"afterburner"); if (Objects[i].id == POW_FUSION_WEAPON && ng && !Netgame.DoFusions) bash_to_shield (i,"fusion"); if (Objects[i].id == POW_PHOENIX_WEAPON && ng && !Netgame.DoPhoenix) bash_to_shield (i,"phoenix"); if (Objects[i].id == POW_HELIX_WEAPON && ng && !Netgame.DoHelix) bash_to_shield (i,"helix"); if (Objects[i].id == POW_MEGA_WEAPON && ng && !Netgame.DoMegas) bash_to_shield (i,"mega"); if (Objects[i].id == POW_SMARTBOMB_WEAPON && ng && !Netgame.DoSmarts) bash_to_shield (i,"smartmissile"); if (Objects[i].id == POW_GAUSS_WEAPON && ng && !Netgame.DoGauss) bash_to_shield (i,"gauss"); if (Objects[i].id == POW_VULCAN_WEAPON && ng && !Netgame.DoVulcan) bash_to_shield (i,"vulcan"); if (Objects[i].id == POW_PLASMA_WEAPON && ng && !Netgame.DoPlasma) bash_to_shield (i,"plasma"); if (Objects[i].id == POW_OMEGA_WEAPON && ng && !Netgame.DoOmega) bash_to_shield (i,"omega"); if (Objects[i].id == POW_SUPER_LASER && ng && !Netgame.DoSuperLaser) bash_to_shield (i,"superlaser"); if (Objects[i].id == POW_PROXIMITY_WEAPON && ng && !Netgame.DoProximity) bash_to_shield (i,"proximity"); // Special: Make all proximity bombs into shields if in hoard mode because // we use the proximity slot in the player struct to signify how many orbs // the player has. if (Objects[i].id == POW_PROXIMITY_WEAPON && ng && (Game_mode & GM_HOARD)) bash_to_shield (i,"proximity"); if (Objects[i].id==POW_VULCAN_AMMO && ng && (!Netgame.DoVulcan && !Netgame.DoGauss)) bash_to_shield(i,"vulcan ammo"); if (Objects[i].id == POW_SPREADFIRE_WEAPON && ng && !Netgame.DoSpread) bash_to_shield (i,"spread"); if (Objects[i].id == POW_SMART_MINE && ng && !Netgame.DoSmartMine) bash_to_shield (i,"smartmine"); if (Objects[i].id == POW_SMISSILE1_1 && ng && !Netgame.DoFlash) bash_to_shield (i,"flash"); if (Objects[i].id == POW_SMISSILE1_4 && ng && !Netgame.DoFlash) bash_to_shield (i,"flash"); if (Objects[i].id == POW_GUIDED_MISSILE_1 && ng && !Netgame.DoGuided) bash_to_shield (i,"guided"); if (Objects[i].id == POW_GUIDED_MISSILE_4 && ng && !Netgame.DoGuided) bash_to_shield (i,"guided"); if (Objects[i].id == POW_EARTHSHAKER_MISSILE && ng && !Netgame.DoEarthShaker) bash_to_shield (i,"earth"); if (Objects[i].id == POW_MERCURY_MISSILE_1 && ng && !Netgame.DoMercury) bash_to_shield (i,"Mercury"); if (Objects[i].id == POW_MERCURY_MISSILE_4 && ng && !Netgame.DoMercury) bash_to_shield (i,"Mercury"); if (Objects[i].id == POW_CONVERTER && ng && !Netgame.DoConverter) bash_to_shield (i,"Converter"); if (Objects[i].id == POW_AMMO_RACK && ng && !Netgame.DoAmmoRack) bash_to_shield (i,"Ammo rack"); if (Objects[i].id == POW_HEADLIGHT && ng && !Netgame.DoHeadlight) bash_to_shield (i,"Headlight"); if (Objects[i].id == POW_LASER && ng && !Netgame.DoLaserUpgrade) bash_to_shield (i,"Laser powerup"); if (Objects[i].id == POW_HOMING_AMMO_1 && ng && !Netgame.DoHoming) bash_to_shield (i,"Homing"); if (Objects[i].id == POW_HOMING_AMMO_4 && ng && !Netgame.DoHoming) bash_to_shield (i,"Homing"); if (Objects[i].id == POW_QUAD_FIRE && ng && !Netgame.DoQuadLasers) bash_to_shield (i,"Quad Lasers"); if (Objects[i].id == POW_FLAG_BLUE && !(Game_mode & GM_CAPTURE)) bash_to_shield (i,"Blue flag"); if (Objects[i].id == POW_FLAG_RED && !(Game_mode & GM_CAPTURE)) bash_to_shield (i,"Red flag"); } } if (Game_mode & GM_HOARD) init_hoard_data(); if ((Game_mode & GM_CAPTURE) || (Game_mode & GM_HOARD)) multi_apply_goal_textures(); multi_sort_kill_list(); multi_show_player_list(); ConsoleObject->control_type = CT_FLYING; reset_player_object(); } int Goal_blue_segnum,Goal_red_segnum; void multi_apply_goal_textures() { int i,j,tex; segment *seg; segment2 *seg2; for (i=0; i <= Highest_segment_index; i++) { seg = &Segments[i]; seg2 = &Segment2s[i]; if (seg2->special==SEGMENT_IS_GOAL_BLUE) { Goal_blue_segnum = i; if (Game_mode & GM_HOARD) tex=find_goal_texture (TMI_GOAL_HOARD); else tex=find_goal_texture (TMI_GOAL_BLUE); if (tex>-1) for (j = 0; j < 6; j++) { int v; seg->sides[j].tmap_num=tex; for (v=0;v<4;v++) seg->sides[j].uvls[v].l = i2f(100); //max out } seg2->static_light = i2f(100); //make static light bright } if (seg2->special==SEGMENT_IS_GOAL_RED) { Goal_red_segnum = i; // Make both textures the same if Hoard mode if (Game_mode & GM_HOARD) tex=find_goal_texture (TMI_GOAL_HOARD); else tex=find_goal_texture (TMI_GOAL_RED); if (tex>-1) for (j = 0; j < 6; j++) { int v; seg->sides[j].tmap_num=tex; for (v=0;v<4;v++) seg->sides[j].uvls[v].l = i2f(1000); //max out } seg2->static_light = i2f(100); //make static light bright } } } int find_goal_texture (ubyte t) { int i; for (i=0;itype==OBJ_PLAYER) || (objp->type==OBJ_GHOST)) nnp++; else if ((objp->type==OBJ_ROBOT) && (Game_mode & GM_MULTI_ROBOTS)) ; 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) ) { // Before deleting object, if it's a robot, drop it's special powerup, if any if (objp->type == OBJ_ROBOT) if (objp->contains_count && (objp->contains_type == OBJ_POWERUP)) object_create_egg(objp); obj_delete(i); } objp++; } return nnp; } void change_playernum_to( int new_Player_num ) { if (Player_num > -1) memcpy( Players[new_Player_num].callsign, Players[Player_num].callsign, CALLSIGN_LEN+1 ); Player_num = new_Player_num; } int multi_all_players_alive() { int i; for (i=0;iflags = INTEL_INT(pd->flags); // Powerup flags, see below... ps->energy = (fix)INTEL_INT(pd->energy); // Amount of energy remaining. ps->shields = (fix)INTEL_INT(pd->shields); // shields remaining (protection) ps->lives = pd->lives; // Lives remaining, 0 = game over. ps->laser_level = pd->laser_level; // Current level of the laser. ps->primary_weapon_flags=pd->primary_weapon_flags; // bit set indicates the player has this weapon. ps->secondary_weapon_flags=pd->secondary_weapon_flags; // bit set indicates the player has this weapon. for (i = 0; i < MAX_PRIMARY_WEAPONS; i++) ps->primary_ammo[i] = INTEL_SHORT(pd->primary_ammo[i]); for (i = 0; i < MAX_SECONDARY_WEAPONS; i++) ps->secondary_ammo[i] = INTEL_SHORT(pd->secondary_ammo[i]); // memcpy( ps->primary_ammo, pd->primary_ammo, MAX_PRIMARY_WEAPONS*sizeof(short) ); // How much ammo of each type. // memcpy( ps->secondary_ammo, pd->secondary_ammo, MAX_SECONDARY_WEAPONS*sizeof(short) ); // How much ammo of each type. ps->last_score=INTEL_INT(pd->last_score); // Score at beginning of current level. ps->score=INTEL_INT(pd->score); // Current score. ps->cloak_time=(fix)INTEL_INT(pd->cloak_time); // Time cloaked ps->homing_object_dist=(fix)INTEL_INT(pd->homing_object_dist); // Distance of nearest homing object. ps->invulnerable_time=(fix)INTEL_INT(pd->invulnerable_time); // Time invulnerable ps->KillGoalCount=INTEL_SHORT(pd->KillGoalCount); ps->net_killed_total=INTEL_SHORT(pd->net_killed_total); // Number of times killed total ps->net_kills_total=INTEL_SHORT(pd->net_kills_total); // Number of net kills total ps->num_kills_level=INTEL_SHORT(pd->num_kills_level); // Number of kills this level ps->num_kills_total=INTEL_SHORT(pd->num_kills_total); // Number of kills total ps->num_robots_level=INTEL_SHORT(pd->num_robots_level); // Number of initial robots this level ps->num_robots_total=INTEL_SHORT(pd->num_robots_total); // Number of robots total ps->hostages_rescued_total=INTEL_SHORT(pd->hostages_rescued_total); // Total number of hostages rescued. ps->hostages_total=INTEL_SHORT(pd->hostages_total); // Total number of hostages. ps->hostages_on_board=pd->hostages_on_board; // Number of hostages on ship. } void use_netplayer_stats( player * ps, netplayer_stats *pd ) { int i; ps->flags = INTEL_INT(pd->flags); // Powerup flags, see below... ps->energy = (fix)INTEL_INT((int)pd->energy); // Amount of energy remaining. ps->shields = (fix)INTEL_INT((int)pd->shields); // shields remaining (protection) ps->lives = pd->lives; // Lives remaining, 0 = game over. ps->laser_level = pd->laser_level; // Current level of the laser. ps->primary_weapon_flags=pd->primary_weapon_flags; // bit set indicates the player has this weapon. ps->secondary_weapon_flags=pd->secondary_weapon_flags; // bit set indicates the player has this weapon. for (i = 0; i < MAX_PRIMARY_WEAPONS; i++) ps->primary_ammo[i] = INTEL_SHORT(pd->primary_ammo[i]); for (i = 0; i < MAX_SECONDARY_WEAPONS; i++) ps->secondary_ammo[i] = INTEL_SHORT(pd->secondary_ammo[i]); // memcpy( ps->primary_ammo, pd->primary_ammo, MAX_PRIMARY_WEAPONS*sizeof(short) ); // How much ammo of each type. // memcpy( ps->secondary_ammo, pd->secondary_ammo, MAX_SECONDARY_WEAPONS*sizeof(short) ); // How much ammo of each type. ps->last_score = INTEL_INT(pd->last_score); // Score at beginning of current level. ps->score = INTEL_INT(pd->score); // Current score. ps->cloak_time = (fix)INTEL_INT((int)pd->cloak_time); // Time cloaked ps->homing_object_dist = (fix)INTEL_INT((int)pd->homing_object_dist); // Distance of nearest homing object. ps->invulnerable_time = (fix)INTEL_INT((int)pd->invulnerable_time); // Time invulnerable ps->KillGoalCount=INTEL_SHORT(pd->KillGoalCount); ps->net_killed_total = INTEL_SHORT(pd->net_killed_total); // Number of times killed total ps->net_kills_total = INTEL_SHORT(pd->net_kills_total); // Number of net kills total ps->num_kills_level = INTEL_SHORT(pd->num_kills_level); // Number of kills this level ps->num_kills_total = INTEL_SHORT(pd->num_kills_total); // Number of kills total ps->num_robots_level = INTEL_SHORT(pd->num_robots_level); // Number of initial robots this level ps->num_robots_total = INTEL_SHORT(pd->num_robots_total); // Number of robots total ps->hostages_rescued_total = INTEL_SHORT(pd->hostages_rescued_total); // Total number of hostages rescued. ps->hostages_total = INTEL_SHORT(pd->hostages_total); // Total number of hostages. ps->hostages_on_board=pd->hostages_on_board; // Number of hostages on ship. } void multi_send_drop_weapon (int objnum,int seed) { object *objp; int count=0; int ammo_count; objp = &Objects[objnum]; ammo_count = objp->ctype.powerup_info.count; if (objp->id == POW_OMEGA_WEAPON && ammo_count == F1_0) ammo_count = F1_0 - 1; //make fit in short Assert(ammo_count < F1_0); //make sure fits in short multibuf[count++]=(char)MULTI_DROP_WEAPON; multibuf[count++]=(char)objp->id; *(short *) (multibuf+count)=INTEL_SHORT(Player_num); count += 2; *(short *) (multibuf+count)=INTEL_SHORT(objnum); count += 2; *(short *) (multibuf+count)=INTEL_SHORT(ammo_count); count += 2; *(int *) (multibuf+count)=INTEL_INT(seed); map_objnum_local_to_local(objnum); if (Game_mode & GM_NETWORK) PowerupsInMine[objp->id]++; multi_send_data(multibuf, 12, 2); } void multi_do_drop_weapon (char *buf) { int pnum,ammo,objnum,remote_objnum,seed; object *objp; int powerup_id; powerup_id=(int)(buf[1]); pnum = INTEL_SHORT(*(short *)(buf+2)); remote_objnum = INTEL_SHORT(*(short *)(buf+4)); ammo = INTEL_SHORT(*(ushort *)(buf+6)); seed = INTEL_INT(*(int *)(buf+8)); objp = &Objects[Players[pnum].objnum]; objnum = spit_powerup(objp, powerup_id, seed); map_objnum_local_to_remote(objnum, remote_objnum, pnum); if (objnum!=-1) Objects[objnum].ctype.powerup_info.count = ammo; if (Game_mode & GM_NETWORK) PowerupsInMine[powerup_id]++; mprintf ((0,"Dropped weapon %d!\n")); } void multi_send_guided_info (object *miss,char done) { #ifdef MACINTOSH shortpos sp; #endif int count=0; mprintf ((0,"Sending guided info!\n")); multibuf[count++]=(char)MULTI_GUIDED; multibuf[count++]=(char)Player_num; multibuf[count++]=done; #ifndef MACINTOSH create_shortpos((shortpos *)(multibuf+count), miss,0); count+=sizeof(shortpos); #else create_shortpos(&sp, miss, 1); memcpy(&(multibuf[count]), (ubyte *)(sp.bytemat), 9); count += 9; memcpy(&(multibuf[count]), (ubyte *)&(sp.xo), 14); count += 14; #endif multi_send_data(multibuf, count, 0); } void multi_do_guided (char *buf) { char pnum=buf[1]; int count=3; static int fun=200; #ifdef MACINTOSH shortpos sp; #endif if (Guided_missile[(int)pnum]==NULL) { if (++fun>=50) { mprintf ((0,"Guided missile for %s is NULL!\n",Players[(int)pnum].callsign)); fun=0; } return; } else if (++fun>=50) { mprintf ((0,"Got guided info for %d (%s)\n",pnum,Players[(int)pnum].callsign)); fun=0; } if (buf[2]) { release_guided_missile(pnum); return; } if (Guided_missile[(int)pnum]-Objects<0 || Guided_missile[(int)pnum]-Objects > Highest_object_index) { Int3(); // Get Jason immediately! return; } #ifndef MACINTOSH extract_shortpos(Guided_missile[(int)pnum], (shortpos *)(buf+count),0); #else memcpy((ubyte *)(sp.bytemat), (ubyte *)(buf + count), 9); memcpy((ubyte *)&(sp.xo), (ubyte *)(buf + count + 9), 14); extract_shortpos(Guided_missile[(int)pnum], &sp, 1); #endif count+=sizeof (shortpos); update_object_seg(Guided_missile[(int)pnum]); } void multi_send_stolen_items () { int i,count=1; multibuf[0]=MULTI_STOLEN_ITEMS; for (i=0;i-1 && pnum=0); Walls[wallnum].type=type; Walls[wallnum].flags=flag; // Assert(state <= 4); Walls[wallnum].state=state; if (Walls[wallnum].type==WALL_OPEN) { digi_kill_sound_linked_to_segment(Walls[wallnum].segnum,Walls[wallnum].sidenum,SOUND_FORCEFIELD_HUM); // digi_kill_sound_linked_to_segment(csegp-Segments,cside,SOUND_FORCEFIELD_HUM); } // mprintf ((0,"Got a walls packet.\n")); } void multi_send_jason_cheat (int num) { num=num; return; } void multi_send_kill_goal_counts() { int i,count=1; multibuf[0]=MULTI_KILLGOALS; for (i=0;ibest) { best=Players[i].KillGoalCount; bestnum=i; } } if (bestnum==Player_num) { HUD_init_message("You have the best score at %d kills!",best); // Players[Player_num].shields=i2f(200); } else HUD_init_message ("%s has the best score with %d kills!",Players[bestnum].callsign,best); HUD_init_message ("The control center has been destroyed!"); objp=obj_find_first_of_type (OBJ_CNTRLCEN); net_destroy_controlcen (objp); } void multi_send_seismic (fix start,fix end) { int count=1; multibuf[0]=MULTI_SEISMIC; *(fix *)(multibuf+count)=(fix)INTEL_INT(start); count+=(sizeof(fix)); *(fix *)(multibuf+count)=(fix)INTEL_INT(end); count+=(sizeof(fix)); multi_send_data(multibuf, count, 1); } extern fix Seismic_disturbance_start_time; extern fix Seismic_disturbance_end_time; void multi_do_seismic (char *buf) { Seismic_disturbance_start_time=(fix)INTEL_INT( *(int *)(buf+1) ); Seismic_disturbance_end_time=(fix)INTEL_INT( *(int *)(buf+5) ); digi_play_sample (SOUND_SEISMIC_DISTURBANCE_START, F1_0); } void multi_send_light (int segnum,ubyte val) { int count=1,i; multibuf[0]=MULTI_LIGHT; *(int *)(multibuf+count)=INTEL_INT(segnum); count+=(sizeof(int)); *(char *)(multibuf+count)=val; count++; for (i=0;i<6;i++) { //mprintf ((0,"Sending %d!\n",Segments[segnum].sides[i].tmap_num2)); *(short *)(multibuf+count)=INTEL_SHORT(Segments[segnum].sides[i].tmap_num2); count+=2; } multi_send_data(multibuf, count, 1); } void multi_send_light_specific (int pnum,int segnum,ubyte val) { int count=1,i; Assert (Game_mode & GM_NETWORK); // Assert (pnum>-1 && pnum= N_players) || (pnum == Player_num)) //@@ { //@@ Int3(); // Got trigger from illegal playernum //@@ return; //@@ } //@@ if ((trigger < 0) || (trigger >= Num_triggers)) //@@ { //@@ Int3(); // Illegal trigger number in multiplayer //@@ return; //@@ } //@@ //@@ if (!(Triggers[trigger].flags & TF_SPRUNG)) //@@ check_trigger_sub(trigger, pnum,0); //@@} void multi_do_flags (char *buf) { char pnum=buf[1]; uint flags=INTEL_INT( *(uint *)(buf+2) ); if (pnum!=Player_num) Players[(int)pnum].flags=flags; } void multi_send_flags (char pnum) { multibuf[0]=MULTI_FLAGS; multibuf[1]=pnum; *(uint *)(multibuf+2)=INTEL_INT(Players[(int)pnum].flags); multi_send_data(multibuf, 6, 1); } void multi_send_drop_blobs (char pnum) { multibuf[0]=MULTI_DROP_BLOB; multibuf[1]=pnum; multi_send_data(multibuf, 2, 0); } void multi_do_drop_blob (char *buf) { char pnum=buf[1]; drop_afterburner_blobs (&Objects[Players[(int)pnum].objnum], 2, i2f(5)/2, -1); } void multi_send_powerup_update () { int i; multibuf[0]=MULTI_POWERUP_UPDATE; for (i=0;iMaxPowerupsAllowed[i]) MaxPowerupsAllowed[i]=buf[i+1]; } extern active_door ActiveDoors[]; extern int Num_open_doors; // Number of open doors void multi_send_active_door (char i) { int count; multibuf[0]=MULTI_ACTIVE_DOOR; multibuf[1]=i; multibuf[2]=Num_open_doors; count = 3; #ifndef MACINTOSH memcpy ((char *)(&multibuf[3]),&ActiveDoors[(int)i],sizeof(struct active_door)); count += sizeof(active_door); #else *(int *)(multibuf + count) = INTEL_INT(ActiveDoors[i].n_parts); count += 4; *(short *)(multibuf + count) = INTEL_SHORT(ActiveDoors[i].front_wallnum[0]); count += 2; *(short *)(multibuf + count) = INTEL_SHORT(ActiveDoors[i].front_wallnum[1]); count += 2; *(short *)(multibuf + count) = INTEL_SHORT(ActiveDoors[i].back_wallnum[0]); count += 2; *(short *)(multibuf + count) = INTEL_SHORT(ActiveDoors[i].back_wallnum[1]); count += 2; *(int *)(multibuf + count) = INTEL_INT(ActiveDoors[i].time); count += 4; #endif // multi_send_data (multibuf,sizeof(struct active_door)+3,1); multi_send_data (multibuf,count,1); } void multi_do_active_door (char *buf) { int count; char i=multibuf[1]; Num_open_doors=buf[2]; count = 3; #ifndef MACINTOSH memcpy (&ActiveDoors[(int)i],buf+count,sizeof(struct active_door)); #else ActiveDoors[i].n_parts = INTEL_INT( *(int *)(buf+count) ); count += 4; ActiveDoors[i].front_wallnum[0] = INTEL_SHORT( *(short *)(buf+count) ); count +=2; ActiveDoors[i].front_wallnum[1] = INTEL_SHORT( *(short *)(buf+count) ); count +=2; ActiveDoors[i].back_wallnum[0] = INTEL_SHORT( *(short *)(buf+count) ); count +=2; ActiveDoors[i].back_wallnum[1] = INTEL_SHORT( *(short *)(buf+count) ); count +=2; ActiveDoors[i].time = INTEL_INT( *(int *)(buf+count) ); count += 4; #endif } void multi_send_sound_function (char whichfunc,char sound) { int count=0; multibuf[0]=MULTI_SOUND_FUNCTION; count++; multibuf[1]=Player_num; count++; multibuf[2]=whichfunc; count++; #ifndef MACINTOSH *(uint *)(multibuf+count)=sound; count++; #else multibuf[3] = sound; count++; // this would probably work on the PC as well. Jason? #endif multi_send_data (multibuf,4,0); } #define AFTERBURNER_LOOP_START 20098 #define AFTERBURNER_LOOP_END 25776 void multi_do_sound_function (char *buf) { // for afterburner char pnum,whichfunc; int sound; if (Players[Player_num].connected!=1) return; pnum=buf[1]; whichfunc=buf[2]; sound=buf[3]; if (whichfunc==0) digi_kill_sound_linked_to_object (Players[(int)pnum].objnum); else if (whichfunc==3) digi_link_sound_to_object3( sound, Players[(int)pnum].objnum, 1,F1_0, i2f(256), AFTERBURNER_LOOP_START, AFTERBURNER_LOOP_END); } void multi_send_capture_bonus (char pnum) { Assert (Game_mode & GM_CAPTURE); multibuf[0]=MULTI_CAPTURE_BONUS; multibuf[1]=pnum; multi_send_data (multibuf,2,1); multi_do_capture_bonus (multibuf); } void multi_send_orb_bonus (char pnum) { Assert (Game_mode & GM_HOARD); multibuf[0]=MULTI_ORB_BONUS; multibuf[1]=pnum; multibuf[2]=Players[Player_num].secondary_ammo[PROXIMITY_INDEX]; multi_send_data (multibuf,3,1); multi_do_orb_bonus (multibuf); } void multi_do_capture_bonus(char *buf) { // Figure out the results of a network kills and add it to the // appropriate player's tally. char pnum=buf[1]; int TheGoal; kmatrix_kills_changed = 1; if (pnum==Player_num) HUD_init_message("You have Scored!"); else HUD_init_message("%s has Scored!",Players[(int)pnum].callsign); if (pnum==Player_num) digi_play_sample (SOUND_HUD_YOU_GOT_GOAL,F1_0*2); else if (get_team(pnum)==TEAM_RED) digi_play_sample (SOUND_HUD_RED_GOT_GOAL,F1_0*2); else digi_play_sample (SOUND_HUD_BLUE_GOT_GOAL,F1_0*2); Players[(int)pnum].flags &= ~(PLAYER_FLAGS_FLAG); // Clear capture flag team_kills[get_team(pnum)] += 5; Players[(int)pnum].net_kills_total += 5; Players[(int)pnum].KillGoalCount+=5; if (Netgame.KillGoal>0) { TheGoal=Netgame.KillGoal*5; if (Players[(int)pnum].KillGoalCount>=TheGoal) { if (pnum==Player_num) { HUD_init_message("You reached the kill goal!"); Players[Player_num].shields=i2f(200); } else HUD_init_message ("%s has reached the kill goal!",Players[(int)pnum].callsign); HUD_init_message ("The control center has been destroyed!"); net_destroy_controlcen (obj_find_first_of_type (OBJ_CNTRLCEN)); } } multi_sort_kill_list(); multi_show_player_list(); } int GetOrbBonus (char num) { int bonus; bonus=num*(num+1)/2; return (bonus); } void multi_do_orb_bonus(char *buf) { // Figure out the results of a network kills and add it to the // appropriate player's tally. char pnum=buf[1]; int TheGoal; int bonus=GetOrbBonus (buf[2]); kmatrix_kills_changed = 1; if (pnum==Player_num) HUD_init_message("You have scored %d points!",bonus); else HUD_init_message("%s has scored with %d orbs!",Players[(int)pnum].callsign,buf[2]); if (pnum==Player_num) digi_start_sound_queued (SOUND_HUD_YOU_GOT_GOAL,F1_0*2); else if (Game_mode & GM_TEAM) { if (get_team(pnum)==TEAM_RED) digi_play_sample (SOUND_HUD_RED_GOT_GOAL,F1_0*2); else digi_play_sample (SOUND_HUD_BLUE_GOT_GOAL,F1_0*2); } else digi_play_sample (SOUND_OPPONENT_HAS_SCORED,F1_0*2); if (bonus>PhallicLimit) { if (pnum==Player_num) HUD_init_message ("You have the record with %d points!",bonus); else HUD_init_message ("%s has the record with %d points!",Players[(int)pnum].callsign,bonus); digi_play_sample (SOUND_BUDDY_MET_GOAL,F1_0*2); PhallicMan=pnum; PhallicLimit=bonus; } Players[(int)pnum].flags &= ~(PLAYER_FLAGS_FLAG); // Clear orb flag team_kills[get_team(pnum)] += bonus; Players[(int)pnum].net_kills_total += bonus; Players[(int)pnum].KillGoalCount+=bonus; team_kills[get_team(pnum)]%=1000; Players[(int)pnum].net_kills_total%=1000; Players[(int)pnum].KillGoalCount%=1000; if (Netgame.KillGoal>0) { TheGoal=Netgame.KillGoal*5; if (Players[(int)pnum].KillGoalCount>=TheGoal) { if (pnum==Player_num) { HUD_init_message("You reached the kill goal!"); Players[Player_num].shields=i2f(200); } else HUD_init_message ("%s has reached the kill goal!",Players[(int)pnum].callsign); HUD_init_message ("The control center has been destroyed!"); net_destroy_controlcen (obj_find_first_of_type (OBJ_CNTRLCEN)); } } multi_sort_kill_list(); multi_show_player_list(); } void multi_send_got_flag (char pnum) { multibuf[0]=MULTI_GOT_FLAG; multibuf[1]=pnum; digi_start_sound_queued (SOUND_HUD_YOU_GOT_FLAG,F1_0*2); multi_send_data (multibuf,2,1); multi_send_flags (Player_num); } int SoundHacked=0; digi_sound ReversedSound; void multi_send_got_orb (char pnum) { multibuf[0]=MULTI_GOT_ORB; multibuf[1]=pnum; digi_play_sample (SOUND_YOU_GOT_ORB,F1_0*2); multi_send_data (multibuf,2,1); multi_send_flags (Player_num); } void multi_do_got_flag (char *buf) { char pnum=buf[1]; if (pnum==Player_num) digi_start_sound_queued (SOUND_HUD_YOU_GOT_FLAG,F1_0*2); else if (get_team(pnum)==TEAM_RED) digi_start_sound_queued (SOUND_HUD_RED_GOT_FLAG,F1_0*2); else digi_start_sound_queued (SOUND_HUD_BLUE_GOT_FLAG,F1_0*2); Players[(int)pnum].flags|=PLAYER_FLAGS_FLAG; HUD_init_message ("%s picked up a flag!",Players[(int)pnum].callsign); } void multi_do_got_orb (char *buf) { char pnum=buf[1]; Assert (Game_mode & GM_HOARD); if (Game_mode & GM_TEAM) { if (get_team(pnum)==get_team(Player_num)) digi_play_sample (SOUND_FRIEND_GOT_ORB,F1_0*2); else digi_play_sample (SOUND_OPPONENT_GOT_ORB,F1_0*2); } else digi_play_sample (SOUND_OPPONENT_GOT_ORB,F1_0*2); Players[(int)pnum].flags|=PLAYER_FLAGS_FLAG; HUD_init_message ("%s picked up an orb!",Players[(int)pnum].callsign); } void DropOrb () { int objnum,seed; if (!(Game_mode & GM_HOARD)) Int3(); // How did we get here? Get Leighton! if (!Players[Player_num].secondary_ammo[PROXIMITY_INDEX]) { HUD_init_message("No orbs to drop!"); return; } seed = d_rand(); objnum = spit_powerup(ConsoleObject,POW_HOARD_ORB,seed); if (objnum<0) return; HUD_init_message("Orb dropped!"); digi_play_sample (SOUND_DROP_WEAPON,F1_0); if ((Game_mode & GM_HOARD) && objnum>-1) multi_send_drop_flag(objnum,seed); Players[Player_num].secondary_ammo[PROXIMITY_INDEX]--; // If empty, tell everyone to stop drawing the box around me if (Players[Player_num].secondary_ammo[PROXIMITY_INDEX]==0) multi_send_flags (Player_num); } void DropFlag () { int objnum,seed; if (!(Game_mode & GM_CAPTURE) && !(Game_mode & GM_HOARD)) return; if (Game_mode & GM_HOARD) { DropOrb(); return; } if (!(Players[Player_num].flags & PLAYER_FLAGS_FLAG)) { HUD_init_message("No flag to drop!"); return; } HUD_init_message("Flag dropped!"); digi_play_sample (SOUND_DROP_WEAPON,F1_0); seed = d_rand(); if (get_team (Player_num)==TEAM_RED) objnum = spit_powerup(ConsoleObject,POW_FLAG_BLUE,seed); else objnum = spit_powerup(ConsoleObject,POW_FLAG_RED,seed); if (objnum<0) return; if ((Game_mode & GM_CAPTURE) && objnum>-1) multi_send_drop_flag(objnum,seed); Players[Player_num].flags &=~(PLAYER_FLAGS_FLAG); } void multi_send_drop_flag (int objnum,int seed) { object *objp; int count=0; objp = &Objects[objnum]; multibuf[count++]=(char)MULTI_DROP_FLAG; multibuf[count++]=(char)objp->id; *(short *) (multibuf+count)=INTEL_SHORT(Player_num); count += 2; *(short *) (multibuf+count)=INTEL_SHORT(objnum); count += 2; *(short *) (multibuf+count)=INTEL_SHORT(objp->ctype.powerup_info.count); count += 2; *(int *) (multibuf+count)=INTEL_INT(seed); map_objnum_local_to_local(objnum); if (!(Game_mode & GM_HOARD)) if (Game_mode & GM_NETWORK) PowerupsInMine[objp->id]++; multi_send_data(multibuf, 12, 2); } void multi_do_drop_flag (char *buf) { int pnum,ammo,objnum,remote_objnum,seed; object *objp; int powerup_id; powerup_id=buf[1]; pnum=INTEL_SHORT( *(short *)(buf+2) ); remote_objnum=INTEL_SHORT( *(short *)(buf+4) ); ammo=INTEL_SHORT( *(short *)(buf+6) ); seed=INTEL_INT( *(int *)(buf+8) ); objp = &Objects[Players[pnum].objnum]; objnum = spit_powerup(objp, powerup_id, seed); map_objnum_local_to_remote(objnum, remote_objnum, pnum); if (objnum!=-1) Objects[objnum].ctype.powerup_info.count = ammo; if (!(Game_mode & GM_HOARD)) { if (Game_mode & GM_NETWORK) PowerupsInMine[powerup_id]++; Players[pnum].flags &= ~(PLAYER_FLAGS_FLAG); } mprintf ((0,"Dropped flag %d!\n")); } void multi_bad_restore () { Function_mode = FMODE_MENU; nm_messagebox(NULL, 1, TXT_OK, "A multi-save game was restored\nthat you are missing or does not\nmatch that of the others.\nYou must rejoin if you wish to\ncontinue."); Function_mode = FMODE_GAME; multi_quit_game = 1; multi_leave_menu = 1; multi_reset_stuff(); } extern int robot_controlled[MAX_ROBOTS_CONTROLLED]; extern int robot_agitation[MAX_ROBOTS_CONTROLLED]; extern fix robot_controlled_time[MAX_ROBOTS_CONTROLLED]; extern fix robot_last_send_time[MAX_ROBOTS_CONTROLLED]; extern fix robot_last_message_time[MAX_ROBOTS_CONTROLLED]; extern int robot_send_pending[MAX_ROBOTS_CONTROLLED]; extern int robot_fired[MAX_ROBOTS_CONTROLLED]; extern byte robot_fire_buf[MAX_ROBOTS_CONTROLLED][18+3]; void multi_send_robot_controls (char pnum) { int count=2; mprintf ((0,"Sending ROBOT_CONTROLS!!!\n")); multibuf[0]=MULTI_ROBOT_CONTROLS; multibuf[1]=pnum; memcpy (&(multibuf[count]),&robot_controlled,MAX_ROBOTS_CONTROLLED*4); count+=(MAX_ROBOTS_CONTROLLED*4); memcpy (&(multibuf[count]),&robot_agitation,MAX_ROBOTS_CONTROLLED*4); count+=(MAX_ROBOTS_CONTROLLED*4); memcpy (&(multibuf[count]),&robot_controlled_time,MAX_ROBOTS_CONTROLLED*4); count+=(MAX_ROBOTS_CONTROLLED*4); memcpy (&(multibuf[count]),&robot_last_send_time,MAX_ROBOTS_CONTROLLED*4); count+=(MAX_ROBOTS_CONTROLLED*4); memcpy (&(multibuf[count]),&robot_last_message_time,MAX_ROBOTS_CONTROLLED*4); count+=(MAX_ROBOTS_CONTROLLED*4); memcpy (&(multibuf[count]),&robot_send_pending,MAX_ROBOTS_CONTROLLED*4); count+=(MAX_ROBOTS_CONTROLLED*4); memcpy (&(multibuf[count]),&robot_fired,MAX_ROBOTS_CONTROLLED*4); count+=(MAX_ROBOTS_CONTROLLED*4); network_send_naked_packet (multibuf,142,pnum); } void multi_do_robot_controls(char *buf) { int count=2; mprintf ((0,"Recieved ROBOT_CONTROLS!!!\n")); if (buf[1]!=Player_num) { Int3(); // Get Jason! Recieved a coop_sync that wasn't ours! return; } memcpy (&robot_controlled,&(buf[count]),MAX_ROBOTS_CONTROLLED*4); count+=(MAX_ROBOTS_CONTROLLED*4); memcpy (&robot_agitation,&(buf[count]),MAX_ROBOTS_CONTROLLED*4); count+=(MAX_ROBOTS_CONTROLLED*4); memcpy (&robot_controlled_time,&(buf[count]),MAX_ROBOTS_CONTROLLED*4); count+=(MAX_ROBOTS_CONTROLLED*4); memcpy (&robot_last_send_time,&(buf[count]),MAX_ROBOTS_CONTROLLED*4); count+=(MAX_ROBOTS_CONTROLLED*4); memcpy (&robot_last_message_time,&(buf[count]),MAX_ROBOTS_CONTROLLED*4); count+=(MAX_ROBOTS_CONTROLLED*4); memcpy (&robot_send_pending,&(buf[count]),MAX_ROBOTS_CONTROLLED*4); count+=(MAX_ROBOTS_CONTROLLED*4); memcpy (&robot_fired,&(buf[count]),MAX_ROBOTS_CONTROLLED*4); count+=(MAX_ROBOTS_CONTROLLED*4); } #define POWERUPADJUSTS 5 int PowerupAdjustMapping[]={11,19,39,41,44}; int multi_powerup_is_4pack (int id) { int i; for (i=0;irank) strcpy (rankstr,"demoted"); else return; NetPlayers.players[(int)pnum].rank=rank; if (!args_find("-norankings")) HUD_init_message ("%s has been %s to %s!",Players[(int)pnum].callsign,rankstr,RankStrings[(int)rank]); } void multi_send_modem_ping () { multibuf[0]=MULTI_MODEM_PING; multi_send_data (multibuf,1,1); } void multi_send_modem_ping_return () { multibuf[0]=MULTI_MODEM_PING_RETURN; multi_send_data (multibuf,1,1); } void multi_do_modem_ping_return () { if (PingLaunchTime==0) { mprintf ((0,"Got invalid PING RETURN from opponent!\n")); return; } PingReturnTime=timer_get_fixed_seconds(); HUD_init_message ("Ping time for opponent is %d ms!",f2i(fixmul(PingReturnTime-PingLaunchTime,i2f(1000)))); PingLaunchTime=0; } void multi_quick_sound_hack (int num) { int length,i; num = digi_xlat_sound(num); length=GameSounds[num].length; ReversedSound.data=(ubyte *)d_malloc (length); ReversedSound.length=length; for (i=0;ibm_x = bm->bm_y = 0; bm->bm_w = bm->bm_rowsize = w; bm->bm_h = h; bm->bm_type = BM_LINEAR; bm->bm_flags = flags; bm->bm_data = data; bm->bm_handle = 0; bm->avg_color = 0; } grs_bitmap Orb_icons[2]; int Hoard_goal_eclip; void init_hoard_data() { static int first_time=1; static int orb_vclip; int n_orb_frames,n_goal_frames; int orb_w,orb_h; int icon_w,icon_h; ubyte palette[256*3]; CFILE *ifile; int i,save_pos; extern int Num_bitmap_files,Num_effects,Num_sound_files; ifile = cfopen("hoard.ham","rb"); if (ifile == NULL) Error("can't open "); n_orb_frames = cfile_read_short(ifile); orb_w = cfile_read_short(ifile); orb_h = cfile_read_short(ifile); save_pos = cftell(ifile); cfseek(ifile,sizeof(palette)+n_orb_frames*orb_w*orb_h,SEEK_CUR); n_goal_frames = cfile_read_short(ifile); cfseek(ifile,save_pos,SEEK_SET); if (first_time) { ubyte *bitmap_data; int bitmap_num=Num_bitmap_files; //Allocate memory for bitmaps MALLOC( bitmap_data, ubyte, n_orb_frames*orb_w*orb_h + n_goal_frames*64*64 ); //Create orb vclip orb_vclip = Num_vclips++; Assert(Num_vclips <= VCLIP_MAXNUM); Vclip[orb_vclip].play_time = F1_0/2; Vclip[orb_vclip].num_frames = n_orb_frames; Vclip[orb_vclip].frame_time = Vclip[orb_vclip].play_time / Vclip[orb_vclip].num_frames; Vclip[orb_vclip].flags = 0; Vclip[orb_vclip].sound_num = -1; Vclip[orb_vclip].light_value = F1_0; for (i=0;ibm_data,1,orb_w*orb_h,ifile); gr_remap_bitmap_good( bm, palette, 255, -1 ); } //Load and remap bitmap data for goal texture cfile_read_short(ifile); //skip frame count cfread(palette,3,256,ifile); for (i=0;ibm_data,1,64*64,ifile); gr_remap_bitmap_good( bm, palette, 255, -1 ); } //Load and remap bitmap data for HUD icons for (i=0;i<2;i++) { icon_w = cfile_read_short(ifile); icon_h = cfile_read_short(ifile); if (first_time) { ubyte *bitmap_data; MALLOC( bitmap_data, ubyte, icon_w*icon_h ); init_bitmap(&Orb_icons[i],icon_w,icon_h,BM_FLAG_TRANSPARENT,bitmap_data); } cfread(palette,3,256,ifile); cfread(Orb_icons[i].bm_data,1,icon_w*icon_h,ifile); gr_remap_bitmap_good( &Orb_icons[i], palette, 255, -1 ); } if (first_time) { //Load sounds for orb game for (i=0;i<4;i++) { int len; len = cfile_read_int(ifile); //get 11k len if (digi_sample_rate == SAMPLE_RATE_22K) { cfseek(ifile,len,SEEK_CUR); //skip over 11k sample len = cfile_read_int(ifile); //get 22k len } GameSounds[Num_sound_files+i].length = len; GameSounds[Num_sound_files+i].data = d_malloc(len); cfread(GameSounds[Num_sound_files+i].data,1,len,ifile); if (digi_sample_rate == SAMPLE_RATE_11K) { len = cfile_read_int(ifile); //get 22k len cfseek(ifile,len,SEEK_CUR); //skip over 22k sample } Sounds[SOUND_YOU_GOT_ORB+i] = Num_sound_files+i; AltSounds[SOUND_YOU_GOT_ORB+i] = Sounds[SOUND_YOU_GOT_ORB+i]; } } cfclose(ifile); first_time = 0; } void multi_process_data(char *buf, int len) { // Take an entire message (that has already been checked for validity, // if necessary) and act on it. int type; len = len; type = buf[0]; if (type > MULTI_MAX_TYPE) { mprintf((1, "multi_process_data: invalid type %d.\n", type)); Int3(); return; } #ifdef NETPROFILING TTRecv[type]++; fprintf (RecieveLogFile,"Packet type: %d Len:%d TT=%d\n",type,len,TTRecv[type]); fflush (RecieveLogFile); #endif switch(type) { case MULTI_POSITION: if (!Endlevel_sequence) multi_do_position(buf); break; case MULTI_REAPPEAR: if (!Endlevel_sequence) multi_do_reappear(buf); break; case MULTI_FIRE: if (!Endlevel_sequence) multi_do_fire(buf); break; case MULTI_KILL: multi_do_kill(buf); break; case MULTI_REMOVE_OBJECT: if (!Endlevel_sequence) multi_do_remobj(buf); break; case MULTI_PLAYER_DROP: case MULTI_PLAYER_EXPLODE: if (!Endlevel_sequence) multi_do_player_explode(buf); break; case MULTI_MESSAGE: if (!Endlevel_sequence) multi_do_message(buf); break; case MULTI_QUIT: if (!Endlevel_sequence) multi_do_quit(buf); break; case MULTI_BEGIN_SYNC: break; case MULTI_CONTROLCEN: if (!Endlevel_sequence) multi_do_controlcen_destroy(buf); break; case MULTI_POWERUP_UPDATE: if (!Endlevel_sequence) multi_do_powerup_update(buf); break; case MULTI_SOUND_FUNCTION: multi_do_sound_function(buf); break; case MULTI_MARKER: if (!Endlevel_sequence) multi_do_drop_marker (buf); break; case MULTI_DROP_WEAPON: if (!Endlevel_sequence) multi_do_drop_weapon(buf); break; case MULTI_DROP_FLAG: if (!Endlevel_sequence) multi_do_drop_flag(buf); break; case MULTI_GUIDED: if (!Endlevel_sequence) multi_do_guided (buf); break; case MULTI_STOLEN_ITEMS: if (!Endlevel_sequence) multi_do_stolen_items(buf); break; case MULTI_WALL_STATUS: if (!Endlevel_sequence) multi_do_wall_status(buf); break; case MULTI_HEARTBEAT: if (!Endlevel_sequence) multi_do_heartbeat (buf); break; case MULTI_SEISMIC: if (!Endlevel_sequence) multi_do_seismic (buf); break; case MULTI_LIGHT: if (!Endlevel_sequence) multi_do_light (buf); break; case MULTI_KILLGOALS: if (!Endlevel_sequence) multi_do_kill_goal_counts (buf); break; case MULTI_ENDLEVEL_START: if (!Endlevel_sequence) multi_do_escape(buf); break; case MULTI_END_SYNC: break; case MULTI_CLOAK: if (!Endlevel_sequence) multi_do_cloak(buf); break; case MULTI_DECLOAK: if (!Endlevel_sequence) multi_do_decloak(buf); break; case MULTI_DOOR_OPEN: if (!Endlevel_sequence) multi_do_door_open(buf); break; case MULTI_CREATE_EXPLOSION: if (!Endlevel_sequence) multi_do_create_explosion(buf); break; case MULTI_CONTROLCEN_FIRE: if (!Endlevel_sequence) multi_do_controlcen_fire(buf); break; case MULTI_CREATE_POWERUP: if (!Endlevel_sequence) multi_do_create_powerup(buf); break; case MULTI_PLAY_SOUND: if (!Endlevel_sequence) multi_do_play_sound(buf); break; case MULTI_CAPTURE_BONUS: if (!Endlevel_sequence) multi_do_capture_bonus(buf); break; case MULTI_ORB_BONUS: if (!Endlevel_sequence) multi_do_orb_bonus(buf); break; case MULTI_GOT_FLAG: if (!Endlevel_sequence) multi_do_got_flag(buf); break; case MULTI_GOT_ORB: if (!Endlevel_sequence) multi_do_got_orb(buf); break; case MULTI_PLAY_BY_PLAY: if (!Endlevel_sequence) multi_do_play_by_play(buf); break; case MULTI_RANK: if (!Endlevel_sequence) multi_do_ranking (buf); break; case MULTI_MODEM_PING: if (!Endlevel_sequence) multi_send_modem_ping_return(); break; case MULTI_MODEM_PING_RETURN: if (!Endlevel_sequence) multi_do_modem_ping_return(); break; #ifndef SHAREWARE case MULTI_FINISH_GAME: multi_do_finish_game(buf); break; // do this one regardless of endsequence case MULTI_ROBOT_CONTROLS: if (!Endlevel_sequence) multi_do_robot_controls(buf); break; case MULTI_ROBOT_CLAIM: if (!Endlevel_sequence) multi_do_claim_robot(buf); break; case MULTI_ROBOT_POSITION: if (!Endlevel_sequence) multi_do_robot_position(buf); break; case MULTI_ROBOT_EXPLODE: if (!Endlevel_sequence) multi_do_robot_explode(buf); break; case MULTI_ROBOT_RELEASE: if (!Endlevel_sequence) multi_do_release_robot(buf); break; case MULTI_ROBOT_FIRE: if (!Endlevel_sequence) multi_do_robot_fire(buf); break; #endif case MULTI_SCORE: if (!Endlevel_sequence) multi_do_score(buf); break; case MULTI_CREATE_ROBOT: if (!Endlevel_sequence) multi_do_create_robot(buf); break; case MULTI_TRIGGER: if (!Endlevel_sequence) multi_do_trigger(buf); break; case MULTI_START_TRIGGER: if (!Endlevel_sequence) multi_do_start_trigger(buf); break; case MULTI_FLAGS: if (!Endlevel_sequence) multi_do_flags(buf); break; case MULTI_DROP_BLOB: if (!Endlevel_sequence) multi_do_drop_blob(buf); break; case MULTI_ACTIVE_DOOR: if (!Endlevel_sequence) multi_do_active_door(buf); break; case MULTI_BOSS_ACTIONS: if (!Endlevel_sequence) multi_do_boss_actions(buf); break; case MULTI_CREATE_ROBOT_POWERUPS: if (!Endlevel_sequence) multi_do_create_robot_powerups(buf); break; case MULTI_HOSTAGE_DOOR: if (!Endlevel_sequence) multi_do_hostage_door_status(buf); break; case MULTI_SAVE_GAME: if (!Endlevel_sequence) multi_do_save_game(buf); break; case MULTI_RESTORE_GAME: if (!Endlevel_sequence) multi_do_restore_game(buf); break; case MULTI_REQ_PLAYER: if (!Endlevel_sequence) multi_do_req_player(buf); break; case MULTI_SEND_PLAYER: if (!Endlevel_sequence) multi_do_send_player(buf); break; default: mprintf((1, "Invalid type in multi_process_input().\n")); Int3(); } } #endif