void update_anti_aircraft_weapon_fire (entity *en) { anti_aircraft *raw; int continue_burst_fire; float launch_angle_error; vec3d *weapon_vector, *weapon_to_target_vector; ASSERT (en); ASSERT (get_comms_model () == COMMS_MODEL_SERVER); raw = get_local_entity_data (en); // // check valid selected weapon // if (raw->vh.selected_weapon == ENTITY_SUB_TYPE_WEAPON_NO_WEAPON) { raw->vh.weapon_burst_timer = 0.0; return; } // // check selected weapon is ready // if (!raw->vh.selected_weapon_system_ready) { if (raw->vh.weapon_burst_timer > 0.0) { pause_client_server_continuous_weapon_sound_effect (en, raw->vh.selected_weapon); } return; } // // check valid target // if (!raw->vh.mob.target_link.parent) { if (raw->vh.weapon_burst_timer > 0.0) { pause_client_server_continuous_weapon_sound_effect (en, raw->vh.selected_weapon); } return; } // // check within max launch angle error // if (!get_local_entity_int_value (en, INT_TYPE_WEAPON_AND_TARGET_VECTORS_VALID)) { if (raw->vh.weapon_burst_timer > 0.0) { pause_client_server_continuous_weapon_sound_effect (en, raw->vh.selected_weapon); } return; } weapon_vector = get_local_entity_vec3d_ptr (en, VEC3D_TYPE_WEAPON_VECTOR); ASSERT (weapon_vector); weapon_to_target_vector = get_local_entity_vec3d_ptr (en, VEC3D_TYPE_WEAPON_TO_TARGET_VECTOR); ASSERT (weapon_to_target_vector); launch_angle_error = acos (get_3d_unit_vector_dot_product (weapon_vector, weapon_to_target_vector)); if (fabs (launch_angle_error) > weapon_database[raw->vh.selected_weapon].max_launch_angle_error) { if (raw->vh.weapon_burst_timer > 0.0) { pause_client_server_continuous_weapon_sound_effect (en, raw->vh.selected_weapon); } return; } // // update burst // continue_burst_fire = FALSE; if (raw->vh.weapon_burst_timer > 0.0) { raw->vh.weapon_burst_timer -= get_delta_time (); if (raw->vh.weapon_burst_timer > 0.0) { continue_burst_fire = TRUE; } else { pause_client_server_continuous_weapon_sound_effect (en, raw->vh.selected_weapon); } } // // fire weapon // if (raw->vh.ready_to_fire || continue_burst_fire) { if (!get_local_entity_int_value (get_session_entity (), INT_TYPE_SUPPRESS_AI_FIRE)) { launch_client_server_weapon (en, raw->vh.selected_weapon); } } }
void update_weapon_lock_type (target_acquisition_systems system) { entity *source, *target; entity_sub_types selected_weapon_type; float target_range, theta, weapon_min_range, weapon_max_range; vec3d *source_position, *target_position, *weapon_vector, *weapon_to_target_vector; //////////////////////////////////////// // // WEAPON_LOCK_NO_ACQUIRE // //////////////////////////////////////// if (system == TARGET_ACQUISITION_SYSTEM_OFF) { weapon_lock_type = WEAPON_LOCK_NO_ACQUIRE; return; } //////////////////////////////////////// // // WEAPON_LOCK_NO_WEAPON // //////////////////////////////////////// source = get_gunship_entity (); selected_weapon_type = get_local_entity_int_value (source, INT_TYPE_SELECTED_WEAPON); if (selected_weapon_type == ENTITY_SUB_TYPE_WEAPON_NO_WEAPON) { weapon_lock_type = WEAPON_LOCK_NO_WEAPON; return; } //////////////////////////////////////// // // WEAPON_LOCK_NO_TARGET // //////////////////////////////////////// target = get_local_entity_parent (source, LIST_TYPE_TARGET); if (!target) { weapon_lock_type = WEAPON_LOCK_NO_TARGET; return; } //////////////////////////////////////// // // WEAPON_LOCK_INVALID_TARGET // //////////////////////////////////////// // // infra-red air-to-air weapons require an airborne target // if (weapon_database[selected_weapon_type].guidance_type == WEAPON_GUIDANCE_TYPE_PASSIVE_INFRA_RED) { if (weapon_database[selected_weapon_type].weapon_class & WEAPON_CLASS_AIR_TO_AIR) { if (!get_local_entity_int_value (target, INT_TYPE_AIRBORNE_AIRCRAFT)) { weapon_lock_type = WEAPON_LOCK_INVALID_TARGET; return; } } } //////////////////////////////////////// // // WEAPON_LOCK_SEEKER_LIMIT // //////////////////////////////////////// // // if guided weapon check target is inside the seeker limit // if (weapon_database[selected_weapon_type].guidance_type != WEAPON_GUIDANCE_TYPE_NONE) { update_entity_weapon_system_weapon_and_target_vectors (source); if (get_local_entity_int_value (source, INT_TYPE_WEAPON_AND_TARGET_VECTORS_VALID)) { weapon_vector = get_local_entity_vec3d_ptr (source, VEC3D_TYPE_WEAPON_VECTOR); weapon_to_target_vector = get_local_entity_vec3d_ptr (source, VEC3D_TYPE_WEAPON_TO_TARGET_VECTOR); theta = get_3d_unit_vector_dot_product (weapon_vector, weapon_to_target_vector); theta = fabs (acos (theta)); if (theta > weapon_database[selected_weapon_type].max_launch_angle_error) { weapon_lock_type = WEAPON_LOCK_SEEKER_LIMIT; return; } } else { // // this should never happen // debug_colour_log (DEBUG_COLOUR_RED, "WARNING! Target and weapon vectors are not valid"); } } //////////////////////////////////////// // // WEAPON_LOCK_NO_LOS // //////////////////////////////////////// // // if air or ground radar then check line of sight // if ((system == TARGET_ACQUISITION_SYSTEM_GROUND_RADAR) || (system == TARGET_ACQUISITION_SYSTEM_AIR_RADAR)) { if (!get_local_entity_int_value (target, INT_TYPE_GUNSHIP_RADAR_LOS_CLEAR)) { weapon_lock_type = WEAPON_LOCK_NO_LOS; return; } } //////////////////////////////////////// // // WEAPON_LOCK_NO_BORESIGHT // //////////////////////////////////////// // // a boresight_weapon will be an unguided weapon so the seeker limit test is not being repeated here // if (weapon_database[selected_weapon_type].boresight_weapon) { update_entity_weapon_system_weapon_and_target_vectors (source); if (get_local_entity_int_value (source, INT_TYPE_WEAPON_AND_TARGET_VECTORS_VALID)) { weapon_vector = get_local_entity_vec3d_ptr (source, VEC3D_TYPE_WEAPON_VECTOR); weapon_to_target_vector = get_local_entity_vec3d_ptr (source, VEC3D_TYPE_WEAPON_TO_TARGET_VECTOR); theta = get_3d_unit_vector_dot_product (weapon_vector, weapon_to_target_vector); theta = fabs (acos (theta)); if (theta > rad (1.0)) { weapon_lock_type = WEAPON_LOCK_NO_BORESIGHT; return; } } else { // // this should never happen // debug_colour_log (DEBUG_COLOUR_RED, "WARNING! Target and weapon vectors are not valid"); } } //////////////////////////////////////// // // WEAPON_LOCK_MIN_RANGE // WEAPON_LOCK_MAX_RANGE // //////////////////////////////////////// source_position = get_local_entity_vec3d_ptr (source, VEC3D_TYPE_POSITION); target_position = get_local_entity_vec3d_ptr (target, VEC3D_TYPE_POSITION); target_range = get_3d_range (source_position, target_position); weapon_min_range = weapon_database[selected_weapon_type].min_range; if (weapon_database[selected_weapon_type].hellfire_flight_profile) { if (get_local_entity_int_value (source, INT_TYPE_LOCK_ON_AFTER_LAUNCH)) { weapon_min_range = weapon_database[selected_weapon_type].min_range_loal; } } if (target_range < weapon_min_range) { weapon_lock_type = WEAPON_LOCK_MIN_RANGE; return; } weapon_max_range = weapon_database[selected_weapon_type].max_range; if (weapon_database[selected_weapon_type].hellfire_flight_profile) { if (get_local_entity_int_value (source, INT_TYPE_LOCK_ON_AFTER_LAUNCH)) { weapon_max_range = weapon_database[selected_weapon_type].max_range_loal; } } if (target_range > weapon_max_range) { weapon_lock_type = WEAPON_LOCK_MAX_RANGE; return; } //////////////////////////////////////// // // WEAPON_LOCK_VALID // //////////////////////////////////////// weapon_lock_type = WEAPON_LOCK_VALID; }
static void update_threat_warning_display (void) { entity *source, *threat; int above = FALSE, overshot, threat_active; float dx, dy, dz, theta, threat_bearing, threat_range, threat_velocity, time_to_impact, source_heading, length, cos_error; threat_types threat_type; vec3d *source_position, *threat_position, uvec_threat_to_target; matrix3x3 *attitude; clear_threat_warning_display_lamps (); if (hind_damage.threat_warning_display || hind_damage.radar_warning_system) { return; } threat = get_local_entity_first_child (get_gunship_entity (), LIST_TYPE_TARGET); if (threat) { source = get_gunship_entity (); source_position = get_local_entity_vec3d_ptr (source, VEC3D_TYPE_POSITION); source_heading = get_local_entity_float_value (source, FLOAT_TYPE_HEADING); while (threat) { entity_sub_types sub_type = get_local_entity_int_value(threat, INT_TYPE_ENTITY_SUB_TYPE); float max_range = 10.0; threat_type = (threat_types) get_local_entity_int_value (threat, INT_TYPE_THREAT_TYPE); // // check threat is active // if (get_local_entity_int_value (threat, INT_TYPE_IDENTIFY_VEHICLE)) { max_range = vehicle_database[sub_type].air_scan_range; threat_active = get_local_entity_int_value (threat, INT_TYPE_RADAR_ON); } else if (get_local_entity_int_value (threat, INT_TYPE_IDENTIFY_AIRCRAFT)) { max_range = aircraft_database[sub_type].air_scan_range; threat_active = get_local_entity_int_value (threat, INT_TYPE_RADAR_ON); } else if (get_local_entity_int_value (threat, INT_TYPE_IDENTIFY_WEAPON)) { weapon_guidance_types guidance = weapon_database[sub_type].guidance_type; threat_active = guidance == WEAPON_GUIDANCE_TYPE_ACTIVE_RADAR; if (guidance == WEAPON_GUIDANCE_TYPE_ACTIVE_RADAR || guidance == WEAPON_GUIDANCE_TYPE_SEMI_ACTIVE_RADAR) { hind_lamps.threat_warning_missile_lh_lock = 1; hind_lamps.threat_warning_missile_rh_lock = 1; } max_range = weapon_database[sub_type].max_range; } #if 0 switch (threat_type) { //////////////////////////////////////// case THREAT_TYPE_INVALID: //////////////////////////////////////// { threat_active = FALSE; break; } //////////////////////////////////////// case THREAT_TYPE_RF_MISSILE: //////////////////////////////////////// { ASSERT(get_local_entity_int_value (threat, INT_TYPE_IDENTIFY_WEAPON)); if (!hind_damage.radar_warning_system) { threat_active = TRUE; } else { threat_active = FALSE; } break; } //////////////////////////////////////// case THREAT_TYPE_IR_MISSILE: //////////////////////////////////////// { threat_active = FALSE; break; } //////////////////////////////////////// case THREAT_TYPE_LASER_MISSILE: //////////////////////////////////////// { threat_active = FALSE; break; } //////////////////////////////////////// case THREAT_TYPE_AIRBORNE_RADAR: //////////////////////////////////////// { if (!hind_damage.radar_warning_system) { threat_active = get_local_entity_int_value (threat, INT_TYPE_RADAR_ON); } else { threat_active = FALSE; } break; } //////////////////////////////////////// case THREAT_TYPE_SAM: //////////////////////////////////////// { if (!hind_damage.radar_warning_system) { threat_active = get_local_entity_int_value (threat, INT_TYPE_RADAR_ON); } else { threat_active = FALSE; } break; } //////////////////////////////////////// case THREAT_TYPE_AAA: //////////////////////////////////////// { if (!hind_damage.radar_warning_system) { threat_active = get_local_entity_int_value (threat, INT_TYPE_RADAR_ON); } else { threat_active = FALSE; } break; } //////////////////////////////////////// case THREAT_TYPE_EARLY_WARNING_RADAR: //////////////////////////////////////// { if (!hind_damage.radar_warning_system) { threat_active = get_local_entity_int_value (threat, INT_TYPE_RADAR_ON); } else { threat_active = FALSE; } break; } //////////////////////////////////////// default: //////////////////////////////////////// { debug_fatal ("Invalid threat type = %d", threat_type); break; } } #endif if (threat_active) { // // get threat direction wrt aircraft datum // threat_position = get_local_entity_vec3d_ptr (threat, VEC3D_TYPE_POSITION); dx = threat_position->x - source_position->x; dy = threat_position->y - source_position->y; dz = threat_position->z - source_position->z; threat_range = sqrt ((dx * dx) + (dy * dy) + (dz * dz)); above = dy > 0.0; threat_bearing = atan2 (dx, dz); theta = threat_bearing - source_heading; if (theta > rad (180.0)) { theta -= rad (360.0); } else if (theta < rad (-180.0)) { theta += rad (360.0); } // // if missile threat then guard against 'overshot target' to prevent spurious indications // if ((threat_type == THREAT_TYPE_RF_MISSILE) || (threat_type == THREAT_TYPE_IR_MISSILE) || (threat_type == THREAT_TYPE_LASER_MISSILE)) { threat_velocity = get_local_entity_float_value (threat, FLOAT_TYPE_VELOCITY); time_to_impact = threat_range / max (threat_velocity, 1.0f); overshot = FALSE; if (time_to_impact < 1.0) { uvec_threat_to_target.x = source_position->x - threat_position->x; uvec_threat_to_target.y = source_position->y - threat_position->y; uvec_threat_to_target.z = source_position->z - threat_position->z; length = get_3d_vector_magnitude (&uvec_threat_to_target); if (length > 1.0) { normalise_3d_vector_given_magnitude (&uvec_threat_to_target, length); attitude = get_local_entity_attitude_matrix_ptr (threat); cos_error = get_3d_unit_vector_dot_product ((vec3d *) &((*attitude) [2][0]), &uvec_threat_to_target); if (cos_error < 0.0) { overshot = TRUE; } } else { overshot = TRUE; } } if (!overshot) { light_threat_bearing_lamp (theta); light_signal_strength_lamps(threat_range, max_range); hind_lamps.threat_warning_radar_type_1 = 1; if (above) hind_lamps.threat_warning_missile_above = 1; else hind_lamps.threat_warning_missile_below = 1; } } else { light_threat_bearing_lamp (theta); light_signal_strength_lamps(threat_range, max_range); if (above) hind_lamps.threat_warning_missile_above = 1; else hind_lamps.threat_warning_missile_below = 1; if (threat_type == THREAT_TYPE_AIRBORNE_RADAR) hind_lamps.threat_warning_radar_type_1 = 1; else { if (max_range <= 4000.0) // short range hind_lamps.threat_warning_radar_type_4 = 1; else if (max_range <= 10000.0) // medium range hind_lamps.threat_warning_radar_type_3 = 1; else // long range hind_lamps.threat_warning_radar_type_2 = 1; } } } threat = get_local_entity_child_succ (threat, LIST_TYPE_TARGET); } } }