// 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; }
// 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); } }