// process an incoming respawn info packet void multi_respawn_process_packet(ubyte *data, header *hinfo) { ubyte code,cur_link_status; char cur_primary_bank,cur_secondary_bank; ushort net_sig,ship_ets; short player_id; int player_index; vector v; char parse_name[1024] = ""; int offset = HEADER_LENGTH; // determine who send the packet player_index = find_player_id(hinfo->id); if(player_index == -1){ nprintf(("Network","Couldn't find player for processing respawn packet!\n")); } // get the opcode GET_DATA(code); // do something based upon the opcode switch((int)code){ case AI_RESPAWN_NOTICE: p_object *pobjp; GET_USHORT( net_sig ); pobjp = mission_parse_get_arrival_ship( net_sig ); Assert( pobjp != NULL ); multi_respawn_ai( pobjp ); break; case RESPAWN_BROADCAST: // get the respawn data GET_USHORT(net_sig); get_vector_data( data, &offset, v ); GET_SHORT(player_id); GET_DATA(cur_primary_bank); GET_DATA(cur_secondary_bank); GET_DATA(cur_link_status); GET_USHORT(ship_ets); GET_STRING(parse_name); player_index = find_player_id(player_id); if(player_index == -1){ nprintf(("Network","Couldn't find player to respawn!\n")); break; } // create the ship and assign its position, net_signature, and class // respawn the player multi_respawn_player(&Net_players[player_index], cur_primary_bank, cur_secondary_bank, cur_link_status, ship_ets, net_sig, parse_name, &v); // if this is for me, I should jump back into gameplay if(&Net_players[player_index] == Net_player){ extern int Player_multi_died_check; Player_multi_died_check = -1; gameseq_post_event(GS_EVENT_ENTER_GAME); } break; case RESPAWN_REQUEST: // determine whether he wants to respawn as an observer or not GET_DATA(code); nprintf(("Network","Received respawn request\n")); if(player_index == -1){ nprintf(("Network","Received respawn request from unknown player!\n")); break; } // make sure he's not making an invalid request if((code == 0) && !(Net_players[player_index].flags & NETINFO_FLAG_RESPAWNING)){ nprintf(("Network","Received respawn request from player who shouldn't be respawning!\n")); Int3(); break; } else if((code == 1) && !(Net_players[player_index].flags & NETINFO_FLAG_LIMBO)){ nprintf(("Network","Received respawn observer request from a player who shouldn't be respawning as an observer!\n")); Int3(); break; } // otherwise perform the operation // respawn the guy as an observer if(code){ multi_respawn_make_observer(&Net_players[player_index]); } // respawn him as normal else { // create his new ship, and change him from respawning to respawned Assert(Net_players[player_index].p_info.p_objp != NULL); if(Net_players[player_index].p_info.p_objp != NULL){ multi_respawn_player(&Net_players[player_index], Net_players[player_index].s_info.cur_primary_bank, Net_players[player_index].s_info.cur_secondary_bank,Net_players[player_index].s_info.cur_link_status, Net_players[player_index].s_info.ship_ets, 0, Net_players[player_index].p_info.p_objp->name); } } break; } PACKET_SET_SIZE(); }
// check to see if a net player needs to be respawned void multi_respawn_check(object *objp) { int player_index; net_player *pl = NULL; p_object *pobjp; // get the parse object since we are storing all data for the respawns in the parse object pobjp = mission_parse_get_arrival_ship( objp->net_signature ); // the server should check against all players if(Net_player->flags & NETINFO_FLAG_AM_MASTER){ player_index = multi_find_player_by_object(objp); if(player_index != -1){ pl = &Net_players[player_index]; } } // clients should just check against themselves else if(objp == Player_obj){ pl = Net_player; } // if this ship isn't a player ship, then maybe it is an AI ship which should get respawed. Only respawn // on the server, then send message to respawn on client. if( pl == NULL ) { // try and find the parse object with this net signature. If we found it, and it's a player start // position, respawn it. if ( Net_player->flags & NETINFO_FLAG_AM_MASTER ) { if ( !pobjp ){ return; } // if we need to respawn this ai ship, add him to a list of ships to get respawned if ( (pobjp->flags & P_OF_PLAYER_START) && (pobjp->respawn_count < Netgame.respawn) && !(Netgame.type_flags & NG_TYPE_DOGFIGHT) ){ int i; for (i = 0; i < MAX_AI_RESPAWNS; i++ ) { if ( Ai_respawns[i].pobjp == NULL ) { Ai_respawns[i].pobjp = pobjp; Ai_respawns[i].timestamp = timestamp(AI_RESPAWN_TIME); break; } } Assert( i < MAX_AI_RESPAWNS ); } } return; } else { // reset his datarate timestamp extern int OO_gran; pl->s_info.rate_stamp = timestamp( (int)(1000.0f / (float)OO_gran) ); } Assert( pl != NULL ); Assert( pobjp ); // we have a player, and we should have a record of it. // mark the player as in the state of respawning if( (pobjp->respawn_count < Netgame.respawn) || (Netgame.type_flags & NG_TYPE_DOGFIGHT) ){ pl->flags |= NETINFO_FLAG_RESPAWNING; } // otherwise mark the player as being in limbo else { pl->flags |= NETINFO_FLAG_LIMBO; } }
// respawn the passed player with the passed ship object and weapon link settings void multi_respawn_player(net_player *pl, char cur_primary_bank, char cur_secondary_bank, ubyte cur_link_status, ushort ship_ets, ushort net_sig, char *parse_name, vector *pos) { int objnum; object *objp; ship *shipp; p_object *pobjp; // try and find the parse object pobjp = mission_parse_get_arrival_ship(parse_name); Assert(pobjp != NULL); if(pobjp == NULL){ return; } objnum = multi_respawn_common_stuff(pobjp); Assert( objnum != -1 ); objp = &Objects[objnum]; shipp = &Ships[objp->instance]; // this is a player, so mark him as a player, objp->flags |= OF_PLAYER_SHIP; objp->flags &= ~OF_COULD_BE_PLAYER; // server should mark this player as invulerable for a short time if ( MULTIPLAYER_MASTER ) { objp->flags |= OF_INVULNERABLE; pl->s_info.invul_timestamp = timestamp(RESPAWN_INVUL_TIMESTAMP); multi_respawn_place( objp, shipp->team ); } // reset his datarate timestamp extern int OO_gran; pl->s_info.rate_stamp = timestamp( (int)(1000.0f / (float)OO_gran) ); // set some player information pl->player->objnum = objnum; if ( pl == Net_player ) { // this is a hack to ensure that old (dead) player ships are destroyed, since at this point he's actually an OBJ_GHOST Player_obj->flags |= OF_SHOULD_BE_DEAD; obj_delete(OBJ_INDEX(Player_obj)); Player_obj = objp; Player_ship = shipp; Player_ai = &Ai_info[Player_ship->ai_index]; // get rid of the annoying HUD dead message text. HUD_init_fixed_text(); } // clients bash net signature if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){ objp->net_signature = net_sig; } // restore the correct weapon bank selections shipp->weapons.current_primary_bank = (int)cur_primary_bank; shipp->weapons.current_secondary_bank = (int)cur_secondary_bank; if(cur_link_status & (1<<0)){ shipp->flags |= SF_PRIMARY_LINKED; } else { shipp->flags &= ~(SF_PRIMARY_LINKED); } if(cur_link_status & (1<<1)){ shipp->flags |= SF_SECONDARY_DUAL_FIRE; } else { shipp->flags &= ~(SF_SECONDARY_DUAL_FIRE); } Assert( ship_ets != 0 ); // find dave or allender // restore the correct ets settings shipp->shield_recharge_index = ((ship_ets & 0x0f00) >> 8); // weapon ets shipp->weapon_recharge_index = ((ship_ets & 0x00f0) >> 4); // engine ets shipp->engine_recharge_index = (ship_ets & 0x000f); // if this is a dogfight mission, make him TEAM_TRAITOR if(Netgame.type_flags & NG_TYPE_DOGFIGHT){ shipp->team = TEAM_TRAITOR; } // maybe bash ship position if(pos != NULL){ objp->pos = *pos; } // unset his respawning flag pl->flags &= ~(NETINFO_FLAG_RESPAWNING | NETINFO_FLAG_LIMBO); // blast his control and button info clear memset(&pl->player->bi, 0, sizeof(pl->player->bi)); memset(&pl->player->ci, 0, sizeof(pl->player->ci)); // if this is me, clear accum button info if(pl == Net_player){ // clear multiplayer button info extern button_info Multi_ship_status_bi; memset(&Multi_ship_status_bi, 0, sizeof(button_info)); } // notify other players of the respawn if ( MULTIPLAYER_MASTER ){ multi_respawn_broadcast(pl); } }
// respawn the passed player with the passed ship object and weapon link settings void multi_respawn_player(net_player *pl, char cur_primary_bank, char cur_secondary_bank, ubyte cur_link_status, ushort ship_ets, ushort net_sig, char *parse_name, vec3d *pos) { int objnum; object *objp; ship *shipp; p_object *pobjp; // try and find the parse object pobjp = mission_parse_get_arrival_ship(parse_name); Assert(pobjp != NULL); if(pobjp == NULL){ return; } objnum = multi_respawn_common_stuff(pobjp); Assert( objnum != -1 ); objp = &Objects[objnum]; shipp = &Ships[objp->instance]; // this is a player, so mark him as a player, objp->flags.set(Object::Object_Flags::Player_ship); objp->flags.remove(Object::Object_Flags::Could_be_player); // server should mark this player as invulerable for a short time if ( MULTIPLAYER_MASTER ) { objp->flags.set(Object::Object_Flags::Invulnerable); pl->s_info.invul_timestamp = timestamp(RESPAWN_INVUL_TIMESTAMP); multi_respawn_place( objp, shipp->team ); } // reset his datarate timestamp extern int OO_gran; pl->s_info.rate_stamp = timestamp( (int)(1000.0f / (float)OO_gran) ); // set some player information pl->m_player->objnum = objnum; if ( pl == Net_player ) { object *oldplr = Player_obj; Player_obj = objp; Player_ship = shipp; Player_ai = &Ai_info[Player_ship->ai_index]; // this is a hack to ensure that old (dead) player ships are destroyed, since at this point he's actually an OBJ_GHOST oldplr->flags.set(Object::Object_Flags::Should_be_dead); obj_delete(OBJ_INDEX(oldplr)); // get rid of the annoying HUD dead message text. HUD_init_fixed_text(); } // clients bash net signature if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){ objp->net_signature = net_sig; } // restore the correct weapon bank selections shipp->weapons.current_primary_bank = (int)cur_primary_bank; shipp->weapons.current_secondary_bank = (int)cur_secondary_bank; if(cur_link_status & (1<<0)){ shipp->flags.set(Ship::Ship_Flags::Primary_linked); } else { shipp->flags.remove(Ship::Ship_Flags::Primary_linked); } if(cur_link_status & (1<<1)){ shipp->flags.set(Ship::Ship_Flags::Secondary_dual_fire); } else { shipp->flags.remove(Ship::Ship_Flags::Secondary_dual_fire); } Assert( ship_ets != 0 ); // find dave or allender // restore the correct ets settings shipp->shield_recharge_index = ((ship_ets & 0x0f00) >> 8); // weapon ets shipp->weapon_recharge_index = ((ship_ets & 0x00f0) >> 4); // engine ets shipp->engine_recharge_index = (ship_ets & 0x000f); // give the current bank a half-second timestamp so that we don't fire immediately unpon respawn shipp->weapons.next_secondary_fire_stamp[shipp->weapons.current_secondary_bank] = timestamp(500); // if this is a dogfight mission, make him TEAM_TRAITOR if(Netgame.type_flags & NG_TYPE_DOGFIGHT){ shipp->team = Iff_traitor; } // maybe bash ship position if(pos != NULL){ objp->pos = *pos; } // unset his respawning flag pl->flags &= ~(NETINFO_FLAG_RESPAWNING | NETINFO_FLAG_LIMBO); // blast his control and button info clear memset(&pl->m_player->bi, 0, sizeof(pl->m_player->bi)); memset(&pl->m_player->ci, 0, sizeof(pl->m_player->ci)); // set throttle based on initial velocity specified in mission (the vel gets calculated // like a percentage of our max speed, so we can just use it as-is for the throttle) pl->m_player->ci.forward_cruise_percent = (float)pobjp->initial_velocity; CLAMP(pl->m_player->ci.forward_cruise_percent, 0.0f, 100.0f); // if this is me, clear accum button info if(pl == Net_player){ // clear multiplayer button info extern button_info Multi_ship_status_bi; memset(&Multi_ship_status_bi, 0, sizeof(button_info)); } // notify other players of the respawn if ( MULTIPLAYER_MASTER ){ multi_respawn_broadcast(pl); } }