// evaluate a kill in dogfight by a netplayer
void multi_df_eval_kill(net_player *killer, object *dead_obj)
{
	int dead_index = -1;
	
	// if we're not in dogfight mode, do nothing
	if(!(Netgame.type_flags & NG_TYPE_DOGFIGHT)){
		return;
	}

	// sanity checks
	if((killer == NULL) || (dead_obj == NULL) || (killer->m_player == NULL)){
		return;
	}
	
	// try and find the dead player
	dead_index = multi_find_player_by_object(dead_obj);
	if(dead_index < 0){
		return;
	}
	Assert(dead_index < MAX_PLAYERS);
	if(dead_index == NET_PLAYER_INDEX(killer)){
		return;
	}

	// update his kills
	killer->m_player->stats.m_dogfight_kills[dead_index]++;
}
/**
 * Deal with weapon-ship hit stuff.
 * Separated from check_collision routine below because of multiplayer reasons.
 */
void ship_weapon_do_hit_stuff(object *pship_obj, object *weapon_obj, vec3d *world_hitpos, vec3d *hitpos, int quadrant_num, int submodel_num, vec3d /*not a pointer intentionaly*/ hit_dir)
{
    weapon	*wp = &Weapons[weapon_obj->instance];
    weapon_info *wip = &Weapon_info[wp->weapon_info_index];
    ship *shipp = &Ships[pship_obj->instance];
    float damage;
    vec3d force;

    vec3d worldNormal;
    model_instance_find_world_dir(&worldNormal, &hit_dir, shipp->model_instance_num, submodel_num, &pship_obj->orient);

    // Apply hit & damage & stuff to weapon
    weapon_hit(weapon_obj, pship_obj,  world_hitpos, quadrant_num, &worldNormal);

    if (wip->damage_time >= 0.0f && wp->lifeleft <= wip->damage_time) {
        if (wip->atten_damage >= 0.0f) {
            damage = (((wip->damage - wip->atten_damage) * (wp->lifeleft / wip->damage_time)) + wip->atten_damage);
        } else {
            damage = wip->damage * (wp->lifeleft / wip->damage_time);
        }
    } else {
        damage = wip->damage;
    }

    // deterine whack whack
    float		blast = wip->mass;
    vm_vec_copy_scale(&force, &weapon_obj->phys_info.vel, blast );

    // send player pain packet
    if ( (MULTIPLAYER_MASTER) && !(shipp->flags[Ship::Ship_Flags::Dying]) ) {
        int np_index = multi_find_player_by_object(pship_obj);

        // if this is a player ship
        if((np_index >= 0) && (np_index != MY_NET_PLAYER_NUM) && (wip->subtype == WP_LASER)) {
            send_player_pain_packet(&Net_players[np_index], wp->weapon_info_index, wip->damage * weapon_get_damage_scale(wip, weapon_obj, pship_obj), &force, hitpos, quadrant_num);
        }
    }

    ship_apply_local_damage(pship_obj, weapon_obj, world_hitpos, damage, quadrant_num, CREATE_SPARKS, submodel_num);

    // let the hud shield gauge know when Player or Player target is hit
    hud_shield_quadrant_hit(pship_obj, quadrant_num);

    // Let wingman status gauge know a wingman ship was hit
    if ( (Ships[pship_obj->instance].wing_status_wing_index >= 0) && ((Ships[pship_obj->instance].wing_status_wing_pos >= 0)) ) {
        hud_wingman_status_start_flash(shipp->wing_status_wing_index, shipp->wing_status_wing_pos);
    }

    // Apply a wack.  This used to be inside of ship_hit... duh! Ship_hit
    // is to apply damage, not physics, so I moved it here.
    // don't apply whack for multiplayer_client from laser - will occur with pain packet
    if (!((wip->subtype == WP_LASER) && MULTIPLAYER_CLIENT) ) {
        // apply a whack
        ship_apply_whack( &force, hitpos, pship_obj );
    }

}
// process a text string entered by the local player
void multi_msg_eval_text_msg()
{
	int player_index;
	
	// if its a 0 length string, don't do anything
	if(strlen(Multi_msg_text) <= 0){
		return;
	}

	// evaluate any special commands here
	if(multi_msg_check_command(Multi_msg_text)){
		return;
	}

	// get the player if in MSG_TARGET mode
	if(Multi_msg_mode == MULTI_MSG_TARGET){
		if(Player_ai->target_objnum != -1){			
			player_index = multi_find_player_by_object(&Objects[Player_ai->target_objnum]);
			if(player_index != -1){
				// send the chat packet
				send_game_chat_packet(Net_player, Multi_msg_text, Multi_msg_mode, &Net_players[player_index]);

				// echo the message locally
				multi_msg_display_mission_text(Multi_msg_text, MY_NET_PLAYER_NUM);
			}
		}
	}
	// all other modes
	else {
		// send the chat packet
		send_game_chat_packet(Net_player, Multi_msg_text, Multi_msg_mode, NULL);

		// echo the message locally
		multi_msg_display_mission_text(Multi_msg_text, MY_NET_PLAYER_NUM);
	}
}
//evaluate a kill on a weapon, right now this is only called on bombs. -Halleck
int scoring_eval_kill_on_weapon(object *weapon_obj, object *other_obj) {
	float max_damage_pct;		// the pct% of total damage the max damage object did
	int max_damage_index;		// the index into the dying ship's damage_ship[] array corresponding the greatest amount of damage
	int killer_sig;				// signature of the guy getting credit for the kill (or -1 if none)
	int idx,net_player_num;
	player *plr;					// pointer to a player struct if it was a player who got the kill
	net_player *net_plr = NULL;
	net_player *dead_plr = NULL;
	float scoring_scale_by_damage = 1;	// percentage to scale the killer's score by if we score based on the amount of damage caused
	int kill_score; 

	weapon *dead_wp;						// the weapon that was killed
	weapon_info *dead_wip;				// info on the weapon that was killed

	if((weapon_obj->instance < 0) || (weapon_obj->instance >= MAX_WEAPONS)){
		return -1;
	}
    
	dead_wp = &Weapons[weapon_obj->instance]; //assign the dead weapon
	dead_wip = &Weapon_info[dead_wp->weapon_info_index];

	// multiplayer clients bail here
	if(MULTIPLAYER_CLIENT){
		return -1;
	}

	// we don't evaluate kills on anything except weapons
	if(weapon_obj->type != OBJ_WEAPON){
		return -1;	
	}

	// we don't evaluate kills on anything except bombs, currently. -Halleck
	if(!(dead_wip->wi_flags & WIF_BOMB))  {
		return -1;
	}

	// clear out invalid damager ships
	for(idx=0; idx<MAX_DAMAGE_SLOTS; idx++){
		if((dead_wp->damage_ship_id[idx] >= 0) && (ship_get_by_signature(dead_wp->damage_ship_id[idx]) < 0)){
			dead_wp->damage_ship[idx] = 0.0f;
			dead_wp->damage_ship_id[idx] = -1;
		}
	}
			
	// determine which object did the most damage to the dying object, and how much damage that was
	max_damage_index = -1;
	for(idx=0;idx<MAX_DAMAGE_SLOTS;idx++){
		// bogus ship
		if(dead_wp->damage_ship_id[idx] < 0){
			continue;
		}

		// if this slot did more damage then the next highest slot
		if((max_damage_index == -1) || (dead_wp->damage_ship[idx] > dead_wp->damage_ship[max_damage_index])){
			max_damage_index = idx;
		}			
	}
	
	// doh
	if((max_damage_index < 0) || (max_damage_index >= MAX_DAMAGE_SLOTS)){
		return -1;
	}

	// the pct of total damage applied to this ship
	max_damage_pct = dead_wp->damage_ship[max_damage_index] / dead_wp->total_damage_received;
    
	CLAMP(max_damage_pct, 0.0f, 1.0f);

	// only evaluate if the max damage % is high enough to record a kill and it was done by a valid object
	if((max_damage_pct >= Kill_percentage) && (dead_wp->damage_ship_id[max_damage_index] >= 0)){
		// set killer_sig for this ship to the signature of the guy who gets credit for the kill
		killer_sig = dead_wp->damage_ship_id[max_damage_index];

		// set the scale value if we only award 100% score for 100% damage
		if (The_mission.ai_profile->flags & AIPF_KILL_SCORING_SCALES_WITH_DAMAGE) {
			scoring_scale_by_damage = max_damage_pct;
		}

		// null this out for now
		plr = NULL;
		net_plr = NULL;

		// get the player (whether single or multiplayer)
		net_player_num = -1;

		if(Game_mode & GM_MULTIPLAYER){
			net_player_num = multi_find_player_by_signature(killer_sig);
			if(net_player_num != -1){
				plr = Net_players[net_player_num].m_player;
				net_plr = &Net_players[net_player_num];
			}
		} else {
			if(Objects[Player->objnum].signature == killer_sig){
				plr = Player;
			}
		}		

		// if we found a valid player, evaluate some kill details
		if(plr != NULL){
			//int si_index;

			// bogus
			if((plr->objnum < 0) || (plr->objnum >= MAX_OBJECTS)){
				return -1;
			}			

			// get the ship info index of the ship type of this kill.  we need to take ship
			// copies into account here.
			//si_index = dead_wp->weapon_info_index;

			// if he killed a guy on his own team increment his bonehead kills
			if((Ships[Objects[plr->objnum].instance].team == dead_wp->team) && !MULTI_DOGFIGHT ){
				if (!(The_mission.flags & MISSION_FLAG_NO_TRAITOR)) {
					plr->stats.m_bonehead_kills++;
					kill_score = -(int)(dead_wip->score * scoring_get_scale_factor());
					plr->stats.m_score += kill_score;

					if(net_plr != NULL ) {
						multi_team_maybe_add_score(-(dead_wip->score), net_plr->p_info.team);
					}
				}
			} 
			// otherwise increment his valid kill count and score
			else {
				// dogfight mode
				if(MULTI_DOGFIGHT && (multi_find_player_by_object(weapon_obj) < 0)){
					// don't add a kill for dogfight kills on non-players
				} else {

					// bombs don't scale with difficulty at the moment. If we change this we want to *scoring_get_scale_factor() too
					kill_score = (int)(dead_wip->score * scoring_scale_by_damage);

					plr->stats.m_score += kill_score;  					
					hud_gauge_popup_start(HUD_KILLS_GAUGE);

#ifdef SCORING_DEBUG
					char kill_score_text[1024] = "";
					sprintf(kill_score_text, "SCORING : %s killed a ship worth %i points and gets %i pts for the kill", plr->callsign, dead_wip->score, kill_score);	
					if (MULTIPLAYER_MASTER) {
						send_game_chat_packet(Net_player, kill_score_text, MULTI_MSG_ALL);
					}
					HUD_printf(kill_score_text);
					mprintf((kill_score_text));
#endif

					// multiplayer
					if(net_plr != NULL){
						multi_team_maybe_add_score(dead_wip->score , net_plr->p_info.team);

						// award teammates % of score value for big ship kills
						// not in dogfight tho
						// and not if there is no assist threshold (as otherwise assists could get higher scores than kills)
						/* Below is N/A. -Halleck
						if (!(Netgame.type_flags & NG_TYPE_DOGFIGHT) && (Ship_info[dead_wp->ship_info_index].flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP))) {
							for (idx=0; idx<MAX_PLAYERS; idx++) {
								if (MULTI_CONNECTED(Net_players[idx]) && (Net_players[idx].p_info.team == net_plr->p_info.team) && (&Net_players[idx] != net_plr)) {
									assist_score = (int)(dead_wip->score * The_mission.ai_profile->assist_award_percentage_scale[Game_skill_level]);
									Net_players[idx].m_player->stats.m_score += assist_score;

#ifdef SCORING_DEBUG
									// DEBUG CODE TO TEST NEW SCORING
									char score_text[1024] = "";
									sprintf(score_text, "SCORING : All team mates get %d pts for helping kill the capship", assist_score);
									send_game_chat_packet(Net_player, score_text, MULTI_MSG_ALL);
									HUD_printf(score_text);
									mprintf((score_text));
#endif
								}
							}
						}
						*/

						// death message
						if((Net_player != NULL) && (Net_player->flags & NETINFO_FLAG_AM_MASTER) && (net_plr != NULL) && (dead_plr != NULL) && (net_plr->m_player != NULL) && (dead_plr->m_player != NULL)){
							char dead_text[1024] = "";

							sprintf(dead_text, "%s gets the kill for %s", net_plr->m_player->callsign, dead_plr->m_player->callsign);							
							send_game_chat_packet(Net_player, dead_text, MULTI_MSG_ALL, NULL, NULL, 2);
							HUD_printf(dead_text);
						}
					}
				}
			}
				
			// increment his all-encompassing kills
			/*Not really a kill. -Halleck
			plr->stats.m_kills[si_index]++;
			plr->stats.m_kill_count++;			
			
			// update everyone on this guy's kills if this is multiplayer
			if(MULTIPLAYER_MASTER && (net_player_num != -1)){
				// send appropriate stats
				if(Netgame.type_flags & NG_TYPE_DOGFIGHT){
					// evaluate dogfight kills
					multi_df_eval_kill(&Net_players[net_player_num], weapon_obj);

					// update stats
					send_player_stats_block_packet(&Net_players[net_player_num], STATS_DOGFIGHT_KILLS);
				} else {
					send_player_stats_block_packet(&Net_players[net_player_num], STATS_MISSION_KILLS);
				}				
			}
			*/
		}
	} else {
		// set killer_sig for this ship to -1, indicating no one got the kill for it
		killer_sig = -1;
	}		
		
	// pass in the guy who got the credit for the kill (if any), so that he doesn't also
	// get credit for an assist
	/* TODO: ADD ASSIST CALC BACK IN. -Halleck
	scoring_eval_assists(dead_wp,killer_sig, is_enemy_player);	
	*/

#ifdef SCORING_DEBUG

	if (Game_mode & GM_MULTIPLAYER) {
		char buf[256];
		sprintf(Scoring_debug_text, "SCORING : %s killed.\nDamage by ship:\n\n", dead_wip->name);

		// show damage done by player
		for (int i=0; i<MAX_DAMAGE_SLOTS; i++) {
			int net_player_num = multi_find_player_by_signature(dead_wp->damage_ship_id[i]);
			if (net_player_num != -1) {
				plr = Net_players[net_player_num].m_player;
				sprintf(buf, "%s: %f", plr->callsign, dead_wp->damage_ship[i]);

				if (dead_wp->damage_ship_id[i] == killer_sig ) {
					strcat_s(buf, "  KILLER\n");
				} else {
					strcat_s(buf, "\n");
				}

				strcat_s(Scoring_debug_text, buf);	
			}
		}
		mprintf ((Scoring_debug_text)); 
	}
#endif

	return max_damage_index; 
}
// eval a hit on an object (for primary and secondary hit purposes)
void scoring_eval_hit(object *hit_obj, object *other_obj,int from_blast)
{	
	// multiplayer clients bail here
	if(MULTIPLAYER_CLIENT){
		return;
	}

	// only evaluate hits on ships, asteroids, and weapons! -Halleck
	if((hit_obj->type != OBJ_SHIP) && (hit_obj->type != OBJ_ASTEROID) && (hit_obj->type != OBJ_WEAPON)){ 
		return;
	}

	// if the other_obj == NULL, we can't evaluate where it came from, so bail here
	if(other_obj == NULL){
		return;
	}

	// other bogus situtations
	if(other_obj->instance < 0){
		return;
	}
	
	if((other_obj->type == OBJ_WEAPON) && !(Weapons[other_obj->instance].weapon_flags & WF_ALREADY_APPLIED_STATS)){		
		// bogus weapon
		if(other_obj->instance >= MAX_WEAPONS){
			return;
		}

		// bogus parent
		if(other_obj->parent < 0){
			return;
		}
		if(other_obj->parent >= MAX_OBJECTS){
			return;
		}
		if(Objects[other_obj->parent].type != OBJ_SHIP){
			return;
		}
		if((Objects[other_obj->parent].instance < 0) || (Objects[other_obj->parent].instance >= MAX_SHIPS)){
			return;
		}		

		//Only evaluate hits on bomb weapons. -Halleck
		bool hit_obj_is_bomb = false;

		if(hit_obj->type == OBJ_WEAPON){

			//Hit weapon is bogus
			if (hit_obj->instance >= MAX_WEAPONS) {
				return;
			}	

			hit_obj_is_bomb = (Weapon_info[Weapons[hit_obj->instance].weapon_info_index].wi_flags & WIF_BOMB) ? true : false;

			//If it's not a bomb but just a regular weapon, we don't care about it (for now, at least.) -Halleck
			if (!hit_obj_is_bomb) {
				return;
			}
		}

		int is_bonehead = 0;
		int sub_type = Weapon_info[Weapons[other_obj->instance].weapon_info_index].subtype;

		// determine if this was a bonehead hit or not
		if(hit_obj->type == OBJ_SHIP){
		   is_bonehead = Ships[hit_obj->instance].team==Ships[Objects[other_obj->parent].instance].team ? 1 : 0;
		} else if (hit_obj_is_bomb) {
			is_bonehead = Weapons[hit_obj->instance].team==Ships[Objects[other_obj->parent].instance].team ? 1 : 0;
		}
		// can't have a bonehead hit on an asteroid
		else {
			is_bonehead = 0;
		}

		// set the flag indicating that we've already applied a "stats" hit for this weapon
		// Weapons[other_obj->instance].weapon_flags |= WF_ALREADY_APPLIED_STATS;

		// in multiplayer -- only the server records the stats
		if( Game_mode & GM_MULTIPLAYER ) {
			if ( Net_player->flags & NETINFO_FLAG_AM_MASTER ) {
				int player_num;

				// get the player num of the parent object.  A player_num of -1 means that the
				// parent of this object was not a player
				player_num = multi_find_player_by_object( &Objects[other_obj->parent] );
				if ( player_num != -1 ) {
					switch(sub_type) {
					case WP_LASER : 
						if(is_bonehead){
							Net_players[player_num].m_player->stats.mp_bonehead_hits++;
						} else {
							Net_players[player_num].m_player->stats.mp_shots_hit++; 
						}

						// Assert( Net_players[player_num].player->stats.mp_shots_hit <= Net_players[player_num].player->stats.mp_shots_fired );
						break;
					case WP_MISSILE :
						// friendly hit, once it hits a friendly, its done
						if(is_bonehead){					
							if(!from_blast){
								Net_players[player_num].m_player->stats.ms_bonehead_hits++;
							}					
						}
						// hostile hit
						else {
							// if its a bomb, count every bit of damage it does
							if(Weapon_info[Weapons[other_obj->instance].weapon_info_index].wi_flags & WIF_BOMB){
								// once we get impact damage, stop keeping track of it
								Net_players[player_num].m_player->stats.ms_shots_hit++;
							}
							// if its not a bomb, only count impact damage
							else {
								if(!from_blast){
									Net_players[player_num].m_player->stats.ms_shots_hit++;
								}	
							}				
						}
					default : 
						break;
					}
				}
			}
		} else {
			if(Player_obj == &(Objects[other_obj->parent])){
			switch(sub_type){
			case WP_LASER : 
				if(is_bonehead){
					Player->stats.mp_bonehead_hits++;
				} else {
					Player->stats.mp_shots_hit++; 
				}
				break;
			case WP_MISSILE :
				// friendly hit, once it hits a friendly, its done
				if(is_bonehead){					
					if(!from_blast){
						Player->stats.ms_bonehead_hits++;
					}					
				}
				// hostile hit
				else {
					// if its a bomb, count every bit of damage it does
					if(Weapon_info[Weapons[other_obj->instance].weapon_info_index].wi_flags & WIF_BOMB){
						// once we get impact damage, stop keeping track of it
						Player->stats.ms_shots_hit++;
					}
					// if its not a bomb, only count impact damage
					else {
						if(!from_blast){
							Player->stats.ms_shots_hit++;
						}
					}
				}				
				break;
			default : 
				break;
			}
			}
		}
	}
}
//evaluate a kill on a weapon, right now this is only called on bombs. -Halleck
int scoring_eval_kill_on_weapon(object *weapon_obj, object *other_obj) {
	int killer_sig;				// signature of the guy getting credit for the kill (or -1 if none)
	int net_player_num;
	player *plr;					// pointer to a player struct if it was a player who got the kill
	net_player *net_plr = NULL;
	int kill_score; 

	// multiplayer clients bail here
	if(MULTIPLAYER_CLIENT){
		return -1;
	}

	// we don't evaluate kills on anything except weapons
	// also make sure there was a killer, and that it was a ship
	if((weapon_obj->type != OBJ_WEAPON) || (weapon_obj->instance < 0) || (weapon_obj->instance >= MAX_WEAPONS)
			|| (other_obj == nullptr) || (other_obj->type != OBJ_WEAPON) || (other_obj->instance < 0) || (other_obj->instance >= MAX_WEAPONS)
			|| (other_obj->parent == -1) || (Objects[other_obj->parent].type != OBJ_SHIP)) {
		return -1;
	}
    
	weapon *dead_wp = &Weapons[weapon_obj->instance];	// the weapon that was killed
	weapon_info *dead_wip = &Weapon_info[dead_wp->weapon_info_index];	// info on the weapon that was killed

	// we don't evaluate kills on anything except bombs, currently. -Halleck
	if(!(dead_wip->wi_flags & WIF_BOMB))  {
		return -1;
	}

	// set killer_sig for this weapon to the signature of the guy who gets credit for the kill
	killer_sig = Objects[other_obj->parent].signature;

	// only evaluate if the kill was done by a valid object
	if(killer_sig >= 0) {
		// null this out for now
		plr = NULL;
		net_plr = NULL;

		// get the player (whether single or multiplayer)
		net_player_num = -1;

		if(Game_mode & GM_MULTIPLAYER){
			net_player_num = multi_find_player_by_signature(killer_sig);
			if(net_player_num != -1){
				plr = Net_players[net_player_num].m_player;
				net_plr = &Net_players[net_player_num];
			}
		} else {
			if(Objects[Player->objnum].signature == killer_sig){
				plr = Player;
			}
		}

		// if we found a valid player, evaluate some kill details
		if(plr != NULL){
			// bogus
			if((plr->objnum < 0) || (plr->objnum >= MAX_OBJECTS)){
				return -1;
			}

			// if he killed a bomb on his own team increment his bonehead kills
			if((Ships[Objects[plr->objnum].instance].team == dead_wp->team) && !MULTI_DOGFIGHT ){
				if (!(The_mission.flags & MISSION_FLAG_NO_TRAITOR)) {
					plr->stats.m_bonehead_kills++;
					kill_score = -(int)(dead_wip->score * scoring_get_scale_factor());
					plr->stats.m_score += kill_score;

					if(net_plr != NULL ) {
						multi_team_maybe_add_score(-(dead_wip->score), net_plr->p_info.team);
					}
				}
			} 
			// otherwise increment his valid kill count and score
			else {
				// dogfight mode
				if(MULTI_DOGFIGHT && (multi_find_player_by_object(weapon_obj) < 0)){
					// don't add a kill for dogfight kills on non-players
				} else {

					// bombs don't scale with difficulty at the moment. If we change this we want to *scoring_get_scale_factor()
					kill_score = dead_wip->score;

					plr->stats.m_score += kill_score;  					
					hud_gauge_popup_start(HUD_KILLS_GAUGE);

#ifdef SCORING_DEBUG
					char kill_score_text[1024] = "";
					sprintf(kill_score_text, "SCORING : %s killed a bomb worth %i points and gets %i pts for the kill", plr->callsign, dead_wip->score, kill_score);	
					if (MULTIPLAYER_MASTER) {
						send_game_chat_packet(Net_player, kill_score_text, MULTI_MSG_ALL);
					}
					HUD_printf(kill_score_text);
					mprintf((kill_score_text));
#endif

					// multiplayer
					if(net_plr != NULL){
						multi_team_maybe_add_score(dead_wip->score , net_plr->p_info.team);
					}
				}
			}
		}
	}

#ifdef SCORING_DEBUG

	if (Game_mode & GM_MULTIPLAYER) {
		sprintf(Scoring_debug_text, "SCORING : %s killed.\nKilled by player:\n", dead_wip->name);

		int net_player_num = multi_find_player_by_signature(killer_sig);
		if (net_player_num != -1) {
			plr = Net_players[net_player_num].m_player;
			char buf[256];
			sprintf(buf, "    %s\n", plr->callsign);

			strcat_s(Scoring_debug_text, buf);
		}
		mprintf ((Scoring_debug_text)); 
	}
#endif

	return killer_sig; 
}
示例#7
0
// 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;
	}
}
// function to actually deal with weapon-ship hit stuff.  separated from check_collision routine below
// because of multiplayer reasons.
void ship_weapon_do_hit_stuff(object *ship_obj, object *weapon_obj, vec3d *world_hitpos, vec3d *hitpos, int quadrant_num, int submodel_num, vec3d /*not a pointer intentionaly*/ hit_dir)
{
	weapon	*wp = &Weapons[weapon_obj->instance];
	weapon_info	*wip = &Weapon_info[wp->weapon_info_index];
	ship *shipp = &Ships[ship_obj->instance];	
	float damage;
	vec3d force;		

	// Apply hit & damage & stuff to weapon
	weapon_hit(weapon_obj, ship_obj,  world_hitpos);

	damage = wip->damage;

	// deterine whack whack
	float		blast = wip->mass;
	vm_vec_copy_scale(&force, &weapon_obj->phys_info.vel, blast );	

	// send player pain packet
	if ( (MULTIPLAYER_MASTER) && !(shipp->flags & SF_DYING) ){
		int np_index = multi_find_player_by_object(ship_obj);

		// if this is a player ship
		if((np_index >= 0) && (np_index != MY_NET_PLAYER_NUM) && (wip->subtype == WP_LASER)){
			send_player_pain_packet(&Net_players[np_index], wp->weapon_info_index, wip->damage * weapon_get_damage_scale(wip, weapon_obj, ship_obj), &force, hitpos);
		}
	}	

	ship_apply_local_damage(ship_obj, weapon_obj, world_hitpos, damage, quadrant_num, CREATE_SPARKS, submodel_num);

	// let the hud shield gauge know when Player or Player target is hit
	hud_shield_quadrant_hit(ship_obj, quadrant_num);

	// Let wingman status gauge know a wingman ship was hit
	if ( (Ships[ship_obj->instance].wing_status_wing_index >= 0) && ((Ships[ship_obj->instance].wing_status_wing_pos >= 0)) ) {
		hud_wingman_status_start_flash(shipp->wing_status_wing_index, shipp->wing_status_wing_pos);
	}

	// Apply a wack.  This used to be inside of ship_hit... duh! Ship_hit
	// is to apply damage, not physics, so I moved it here.
	// don't apply whack for multiplayer_client from laser - will occur with pain packet
	if (!((wip->subtype == WP_LASER) && MULTIPLAYER_CLIENT) ) {		
		// apply a whack		
		ship_apply_whack( &force, hitpos, ship_obj );
	}

	if( (quadrant_num == -1) && Cmdline_decals ){
		weapon_info	*wip = &Weapon_info[Weapons[weapon_obj->instance].weapon_info_index];
		decal_point dec;
		dec.orient = weapon_obj->orient;
		vec3d hit_fvec;
		vm_vec_negate(&hit_dir);
		vm_vec_avg(&hit_fvec, &hit_dir, &weapon_obj->orient.vec.fvec);
		vm_vec_normalize(&hit_fvec);
		dec.orient.vec.fvec = hit_fvec;
		vm_fix_matrix(&dec.orient);
		dec.pnt.xyz = hitpos->xyz;
		dec.radius = wip->decal_rad;

		if ( (dec.radius > 0) && (wip->decal_texture.bitmap_id > -1) )
			decal_create(ship_obj, &dec, submodel_num, wip->decal_texture.bitmap_id, wip->decal_backface_texture.bitmap_id, wip->decal_glow_texture_id, wip->decal_burn_texture_id, wip->decal_burn_time);
	}
	

}