// called when a shield quadrant is struct, so we can update the timer that will draw the quadrant // as flashing // // input: // objp => object pointer for ship that has been hit // quadrant => quadrant of shield getting hit (-1 if no shield is present) void hud_shield_quadrant_hit(object *objp, int quadrant) { shield_hit_info *shi; int num; if (Game_mode & GM_STANDALONE_SERVER) return; Assertion(objp != NULL, "hud_shield_quadrant_hit() called with a NULL objp; get a coder!\n"); if ( objp->type != OBJ_SHIP ) return; hud_escort_ship_hit(objp, quadrant); hud_gauge_popup_start(HUD_TARGET_MINI_ICON); if ( OBJ_INDEX(objp) == Player_ai->target_objnum ) { shi = &Shield_hit_data[SHIELD_HIT_TARGET]; } else if ( objp == Player_obj ) { shi = &Shield_hit_data[SHIELD_HIT_PLAYER]; } else { return; } Assertion(shi->shield_hit_timers.size() > 0, "Shield hit info object for object '%s' has a size " SIZE_T_ARG " shield_hit_timers; get a coder!\n", Ships[objp->instance].ship_name, shi->shield_hit_timers.size()); Assertion(shi->hull_hit_index < (int) shi->shield_hit_timers.size(), "Shield hit info object for object '%s' has a hull_hit_index of %d (should be between 0 and " SIZE_T_ARG "); get a coder!\n", Ships[objp->instance].ship_name, shi->hull_hit_index, shi->shield_hit_timers.size() - 1); if ( quadrant >= 0 ) { if ( !(Ship_info[Ships[objp->instance].ship_info_index].flags2 & SIF2_MODEL_POINT_SHIELDS) ) num = Quadrant_xlate[quadrant]; else num = quadrant; Assertion(num < shi->hull_hit_index, "Shield hit info object for object '%s' hit on quadrant #%d, despite having a hull_hit_index of %d; get a coder!\n", Ships[objp->instance].ship_name, num, shi->hull_hit_index); shi->shield_hit_timers[num] = timestamp(SHIELD_HIT_DURATION_SHORT); } else { shi->shield_hit_timers[shi->hull_hit_index] = timestamp(SHIELD_HIT_DURATION_SHORT); hud_targetbox_start_flash(TBOX_FLASH_HULL); } }
// ---------------------------------------------------------------------- // hud_remove_ship_from_escort_index() // // Take a ship out of the escort list void hud_remove_ship_from_escort_index(int dead_index, int objnum) { int i, count, num_complete_escorts; escort_info bakup_arr[MAX_COMPLETE_ESCORT_LIST], complete_escorts[MAX_COMPLETE_ESCORT_LIST]; // remove him from escort list if ((objnum >= 0) && (Objects[objnum].type == OBJ_SHIP) && (Objects[objnum].instance >= 0)) { Ships[Objects[objnum].instance].flags &= ~SF_ESCORT; } count = 0; for (i = 0; i < Num_escort_ships; i++) { if (i != dead_index) { bakup_arr[count++] = Escort_ships[i]; } } for (i = 0; i < count; i++) { Escort_ships[i] = bakup_arr[i]; } Num_escort_ships--; Assert(Num_escort_ships >= 0); // get complete escort list hud_create_complete_escort_list(complete_escorts, &num_complete_escorts); // sort escort list by priority insertion_sort(complete_escorts, num_complete_escorts, sizeof(escort_info), escort_compare_func); // merge list merge_escort_lists(complete_escorts, num_complete_escorts); hud_gauge_popup_start(HUD_ESCORT_VIEW); }
// Called whenever a ship is hit to determine if that ship is in the escort list. If it // is, then start timers to flash the name hull/shield icon for that ship. void hud_escort_ship_hit(object *objp, int quadrant) { int num, i; shield_hit_info *shi; // no ships on the escort list in multiplayer dogfight if((Game_mode & GM_MULTIPLAYER) && (Netgame.type_flags & NG_TYPE_DOGFIGHT)){ return; } for ( i = 0; i < Num_escort_ships; i++ ) { if ( Escort_ships[i].objnum == OBJ_INDEX(objp) ) { shi = &Escort_ships[i].hit_info; num = Quadrant_xlate[quadrant]; hud_gauge_popup_start(HUD_ESCORT_VIEW); if ( quadrant >= 0 ) { shi->shield_hit_timers[num] = timestamp(SHIELD_HIT_DURATION); } else { shi->shield_hit_timers[HULL_HIT_OFFSET] = timestamp(SHIELD_HIT_DURATION); } } } }
//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; }
//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; }
// try to add a ship to the escort list, if slot available void hud_add_ship_to_escort(int objnum, int supress_feedback) { escort_info complete_escorts[MAX_COMPLETE_ESCORT_LIST]; int num_complete_escorts, idx, found; // get complete escort list hud_create_complete_escort_list(complete_escorts, &num_complete_escorts); // ensure the complete escort list is not full already if (num_complete_escorts == MAX_COMPLETE_ESCORT_LIST) { return; } // check if ship is already on complete escort list found = 0; for (idx=0; idx<num_complete_escorts; idx++) { if (complete_escorts[idx].obj_signature == Objects[objnum].signature) { found = 1; break; } } // add new ship into complete list if ( !found ) { complete_escorts[num_complete_escorts].objnum = objnum; complete_escorts[num_complete_escorts].obj_signature = Objects[objnum].signature; complete_escorts[num_complete_escorts].priority = Ships[Objects[objnum].instance].escort_priority; complete_escorts[num_complete_escorts].escort_hit_timer = 0; complete_escorts[num_complete_escorts].escort_hit_next_flash = 0; complete_escorts[num_complete_escorts].escort_show_bright = false; // add him to escort list Ships[Objects[objnum].instance].flags.set(Ship::Ship_Flags::Escort); num_complete_escorts++; } // sort escort list by priority insertion_sort(complete_escorts, num_complete_escorts, sizeof(escort_info), escort_compare_func); // merge list merge_escort_lists(complete_escorts, num_complete_escorts); // maybe do feedback if ( (Num_escort_ships == Max_escort_ships) && !supress_feedback) { found = 0; // search thru list for objnum for (idx=0; idx<Num_escort_ships; idx++) { if (Escort_ships[idx].objnum == objnum) { found = 1; break; } } if (!found) { HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Escort list is full with %d ships", 288), Num_escort_ships); snd_play( &Snds[SND_TARGET_FAIL]); } } hud_gauge_popup_start(HUD_ESCORT_VIEW); }