void get_default_virtual_cockpit_adi_angles (matrix3x3 attitude, float *heading, float *pitch, float *roll) { matrix3x3 inverse_attitude, heading_rotation, result; // // get inverse attitude (attiude * inverse attitude = identity) which aligns the ADI with the world axis // inverse_attitude[0][0] = attitude[0][0]; inverse_attitude[1][0] = attitude[0][1]; inverse_attitude[2][0] = attitude[0][2]; inverse_attitude[0][1] = attitude[1][0]; inverse_attitude[1][1] = attitude[1][1]; inverse_attitude[2][1] = attitude[1][2]; inverse_attitude[0][2] = attitude[2][0]; inverse_attitude[1][2] = attitude[2][1]; inverse_attitude[2][2] = attitude[2][2]; // // rotate heading so that the ADI pitch markings face the pilot // get_3d_transformation_matrix (heading_rotation, get_heading_from_attitude_matrix (attitude), 0.0, 0.0); multiply_matrix3x3_matrix3x3 (result, heading_rotation, inverse_attitude); *heading = get_heading_from_attitude_matrix (result); *pitch = get_pitch_from_attitude_matrix (result); *roll = get_roll_from_attitude_matrix (result); }
static void set_local_float_value (entity *en, float_types type, float value) { mobile *raw; #if DEBUG_MODULE debug_log_entity_args (ENTITY_DEBUG_LOCAL, ENTITY_DEBUG_FLOAT_VALUE, en, type, value); #endif raw = (mobile *) get_local_entity_data (en); switch (type) { //////////////////////////////////////// case FLOAT_TYPE_HEADING: //////////////////////////////////////// { matrix3x3 attitude; float pitch, roll; pitch = get_pitch_from_attitude_matrix (raw->attitude); roll = get_roll_from_attitude_matrix (raw->attitude); get_3d_transformation_matrix (attitude, value, pitch, roll); set_local_entity_attitude_matrix (en, attitude); break; } //////////////////////////////////////// case FLOAT_TYPE_HIGH_VELOCITY: case FLOAT_TYPE_LOW_VELOCITY: case FLOAT_TYPE_MEDIUM_VELOCITY: case FLOAT_TYPE_VELOCITY: case FLOAT_TYPE_VERY_HIGH_VELOCITY: //////////////////////////////////////// { raw->velocity = value; break; } //////////////////////////////////////// default: //////////////////////////////////////// { debug_fatal_invalid_float_type (en, type); break; } } }
static float get_local_float_value (entity *en, float_types type) { camera *raw; float value; raw = get_local_entity_data (en); switch (type) { //////////////////////////////////////// case FLOAT_TYPE_HEADING: //////////////////////////////////////// { value = get_heading_from_attitude_matrix (raw->attitude); break; } //////////////////////////////////////// case FLOAT_TYPE_PITCH: //////////////////////////////////////// { value = get_pitch_from_attitude_matrix (raw->attitude); break; } //////////////////////////////////////// case FLOAT_TYPE_ROLL: //////////////////////////////////////// { value = get_roll_from_attitude_matrix (raw->attitude); break; } //////////////////////////////////////// default: //////////////////////////////////////// { debug_fatal_invalid_float_type (en, type); break; } } return (value); }
static void get_local_attitude_angles (entity *en, float *heading, float *pitch, float *roll) { camera *raw; ASSERT (heading); ASSERT (pitch); ASSERT (roll); raw = get_local_entity_data (en); *heading = get_heading_from_attitude_matrix (raw->attitude); *pitch = get_pitch_from_attitude_matrix (raw->attitude); *roll = get_roll_from_attitude_matrix (raw->attitude); }
void update_vector_altitude_dynamics (void) { static float last_ground_height = 0; matrix3x3 attitude; float heading, pitch, roll, ground_height, centre_of_gravity_to_ground_distance; vec3d position, *face_normal; centre_of_gravity_to_ground_distance = get_local_entity_float_value (get_gunship_entity (), FLOAT_TYPE_CENTRE_OF_GRAVITY_TO_GROUND_DISTANCE); get_local_entity_attitude_matrix (get_gunship_entity (), attitude); ground_height = get_local_entity_float_value (get_gunship_entity (), FLOAT_TYPE_TERRAIN_ELEVATION); // // debug // if ((ground_height < -1000) || (ground_height > 32000)) { debug_log ("!!!!!!!!!!!!!! GROUND HEIGHT %f", ground_height); ground_height = last_ground_height; } // // end // last_ground_height = ground_height; current_flight_dynamics->altitude.value = current_flight_dynamics->position.y; current_flight_dynamics->altitude.min = ground_height; switch (get_local_entity_int_value (get_gunship_entity (), INT_TYPE_OPERATIONAL_STATE)) { case OPERATIONAL_STATE_LANDED: { if (current_flight_dynamics->world_velocity_y.value > 0.0) { #if DEBUG_DYNAMICS debug_log ("VECTOR DYN: takeoff !"); #endif set_local_entity_int_value (get_gunship_entity (), INT_TYPE_OPERATIONAL_STATE, OPERATIONAL_STATE_NAVIGATING); delete_local_entity_from_parents_child_list (get_gunship_entity (), LIST_TYPE_CURRENT_WAYPOINT); transmit_entity_comms_message (ENTITY_COMMS_MOBILE_TAKEOFF, get_gunship_entity ()); } else { entity *wp; vec3d wp_pos; wp = get_local_entity_parent (get_gunship_entity (), LIST_TYPE_CURRENT_WAYPOINT); if (wp) { get_local_waypoint_formation_position (get_local_entity_int_value (get_gunship_entity (), INT_TYPE_FORMATION_POSITION), wp, &wp_pos); ground_height = wp_pos.y; } current_flight_dynamics->world_velocity_y.value = max (current_flight_dynamics->world_velocity_y.value, 0.0); current_flight_dynamics->velocity_y.value = max (current_flight_dynamics->velocity_y.value, 0.0); memset (¤t_flight_dynamics->world_motion_vector, 0, sizeof (vec3d)); current_flight_dynamics->velocity_x.value = bound (current_flight_dynamics->velocity_x.value, knots_to_metres_per_second (-10), knots_to_metres_per_second (50)); current_flight_dynamics->velocity_y.value = 0; current_flight_dynamics->velocity_z.value = bound (current_flight_dynamics->velocity_z.value, knots_to_metres_per_second (-10), knots_to_metres_per_second (50)); current_flight_dynamics->position.y = ground_height + centre_of_gravity_to_ground_distance; current_flight_dynamics->altitude.value = ground_height + centre_of_gravity_to_ground_distance; heading = get_heading_from_attitude_matrix (attitude); //get_3d_terrain_face_normal (&n, current_flight_dynamics->position.x, current_flight_dynamics->position.z); face_normal = get_local_entity_ptr_value (get_gunship_entity (), PTR_TYPE_TERRAIN_FACE_NORMAL); get_3d_transformation_matrix_from_face_normal_and_heading (attitude, face_normal, heading); pitch = get_pitch_from_attitude_matrix (attitude); pitch += rad (aircraft_database [ENTITY_SUB_TYPE_AIRCRAFT_AH64D_APACHE_LONGBOW].fuselage_angle); roll = get_roll_from_attitude_matrix (attitude); get_3d_transformation_matrix (attitude, heading, pitch, roll); position.x = current_flight_dynamics->position.x; position.y = current_flight_dynamics->position.y; position.z = current_flight_dynamics->position.z; set_local_entity_vec3d (get_gunship_entity (), VEC3D_TYPE_POSITION, &position); set_local_entity_attitude_matrix (get_gunship_entity (), attitude); } break; } default: { if (current_flight_dynamics->world_velocity_y.value < 0.0) { if (current_flight_dynamics->altitude.value < current_flight_dynamics->altitude.min + centre_of_gravity_to_ground_distance) { if (get_local_entity_int_value (get_gunship_entity (), INT_TYPE_OPERATIONAL_STATE) != OPERATIONAL_STATE_LANDED) { // // need to find what wp the user is trying to land on .... // //entity //*wp; #if DEBUG_DYNAMICS debug_log ("VECTOR DYN: landed !"); #endif set_local_entity_int_value (get_gunship_entity (), INT_TYPE_OPERATIONAL_STATE, OPERATIONAL_STATE_LANDED); //transmit_entity_comms_message (ENTITY_COMMS_MOBILE_LAND, get_gunship_entity (), wp); } } } break; } } current_flight_dynamics->altitude.value = bound ( current_flight_dynamics->altitude.value, current_flight_dynamics->altitude.min, current_flight_dynamics->altitude.max); }
void save_screen_image_and_viewpoint_data (void) { char filename[100], large_image_filename[100], small_image_filename[100], viewpoint_data_filename[100]; FILE *fp; int x_sec, z_sec; // // find first screen shot index // if (!found_first_screen_shot_index) { while (TRUE) { sprintf (large_image_filename, "%sIMAGE%03d.TGA", LARGE_IMAGE_PATH, screen_shot_index); if (file_exist (large_image_filename)) { screen_shot_index++; if (screen_shot_index == 1000) { break; } } else { found_first_screen_shot_index = TRUE; break; } } } // // write screen files and viewpoint data file // if (screen_shot_index <= MAX_SCREEN_SHOT_INDEX) { sprintf (filename, "IMAGE%03d", screen_shot_index); debug_log ("Saving screen image (%s)", filename); sprintf (large_image_filename, "%s%s.TGA", LARGE_IMAGE_PATH, filename); sprintf (small_image_filename, "%s%s.TGA", SMALL_IMAGE_PATH, filename); sprintf (viewpoint_data_filename, "%s%s.TXT", VIEWPOINT_DATA_PATH, filename); //////////////////////////////////////// if (lock_screen (video_screen)) { save_tga_screen_with_thumbnail (large_image_filename, small_image_filename); unlock_screen (video_screen); } //////////////////////////////////////// fp = safe_fopen (viewpoint_data_filename, "w"); fprintf (fp, "Image viewpoint data:\n\n"); fprintf (fp, "Map : unknown\n"); fprintf (fp, "X : %.2f\n", main_vp.x); fprintf (fp, "Y : %.2f\n", main_vp.y); fprintf (fp, "Z : %.2f\n", main_vp.z); get_terrain_3d_sector (main_vp.x, main_vp.z, &x_sec, &z_sec); fprintf (fp, "X sector (3D) : %d\n", x_sec); fprintf (fp, "Z sector (3D) : %d\n", z_sec); get_x_sector (x_sec, main_vp.x); get_z_sector (z_sec, main_vp.z); fprintf (fp, "X sector (AI) : %d\n", x_sec); fprintf (fp, "Z sector (AI) : %d\n", z_sec); fprintf (fp, "Heading (degs): %.2f\n", deg (get_heading_from_attitude_matrix (main_vp.attitude))); fprintf (fp, "Pitch (degs) : %.2f\n", deg (get_pitch_from_attitude_matrix (main_vp.attitude))); fprintf (fp, "Roll (degs) : %.2f\n", deg (get_roll_from_attitude_matrix (main_vp.attitude))); safe_fclose (fp); //////////////////////////////////////// screen_shot_index++; } else { debug_colour_log (DEBUG_COLOUR_RED, "Exceeded screen image limit"); } }
void debug_log_entity_args (entity_debug_modes mode, entity_debug_args arg, entity *en, ...) { va_list pargs; //////////////////////////////////////// // // trap remote args in single player game // //////////////////////////////////////// if (!debug_log_entity_args_enabled) { return; } if (mode == ENTITY_DEBUG_REMOTE) { if (direct_play_get_comms_mode () == DIRECT_PLAY_COMMS_MODE_NONE) { return; } } //////////////////////////////////////// // // sort debug log text // //////////////////////////////////////// va_start (pargs, en); switch (arg) { //////////////////////////////////////// case ENTITY_DEBUG_ATTITUDE_ANGLES: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en, float heading, float pitch, float roll) // float heading, pitch, roll; heading = va_arg (pargs, double); pitch = va_arg (pargs, double); roll = va_arg (pargs, double); debug_log_text (mode, en, "attitude angles (h = %.3f, p = %.3f, r = %.3f)", deg (heading), deg (pitch), deg (roll)); break; } //////////////////////////////////////// case ENTITY_DEBUG_ATTITUDE_MATRIX: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en, matrix3x3 attitude) // matrix3x3 *attitude; float heading, pitch, roll; attitude = va_arg (pargs, matrix3x3 *); ASSERT (attitude); heading = get_heading_from_attitude_matrix (*attitude); pitch = get_pitch_from_attitude_matrix (*attitude); roll = get_roll_from_attitude_matrix (*attitude); debug_log_text (mode, en, "attitude matrix (h = %.3f, p = %.3f, r = %.3f)", deg (heading), deg (pitch), deg (roll)); break; } //////////////////////////////////////// case ENTITY_DEBUG_CHAR_TYPE: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en, char_types type) // char_types type; type = va_arg (pargs, char_types); debug_log_text (mode, NULL, "char type = %s", get_char_type_name (type)); break; } //////////////////////////////////////// case ENTITY_DEBUG_CHAR_VALUE: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en, char_types type, char value) // char_types type; char value; type = va_arg (pargs, char_types); value = va_arg (pargs, int); debug_log_text (mode, en, "%s = %c", get_char_type_name (type), value); break; } //////////////////////////////////////// case ENTITY_DEBUG_CREATE: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en, entity_types type, int index) // entity_types type; int index; type = va_arg (pargs, entity_types); index = va_arg (pargs, int); debug_log_text (mode, NULL, "create %s (index = %d): ", get_entity_type_name (type), index); break; } //////////////////////////////////////// case ENTITY_DEBUG_DESTROY: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en) // debug_log_text (mode, en, "destroy"); break; } //////////////////////////////////////// case ENTITY_DEBUG_DESTROY_FAMILY: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en) // debug_log_text (mode, en, "destroy family"); break; } //////////////////////////////////////// case ENTITY_DEBUG_ENTITY_ATTRIBUTE: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en, entity_attributes attr) // entity_attributes attr; attr = va_arg (pargs, entity_attributes); debug_log_text (mode, NULL, "entity attribute = %s", get_entity_attribute_name (attr)); break; } //////////////////////////////////////// case ENTITY_DEBUG_ENTITY_COMMS_MESSAGE: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en, entity_comms_messages message) // entity_comms_messages message; message = va_arg (pargs, entity_comms_messages); debug_log_text (mode, NULL, "entity comms message = %s", get_entity_comms_message_name (message)); break; } //////////////////////////////////////// case ENTITY_DEBUG_ENTITY_INDEX: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en, int index) // int index; index = va_arg (pargs, int); debug_log_text (mode, en, "entity index = %d", index); break; } //////////////////////////////////////// case ENTITY_DEBUG_ENTITY_TYPE: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en, entity_types type) // entity_types type; type = va_arg (pargs, entity_types); debug_log_text (mode, en, "entity type = %s", get_entity_type_name (type)); break; } //////////////////////////////////////// case ENTITY_DEBUG_FLOAT_TYPE: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en, float_types type) // float_types type; type = va_arg (pargs, float_types); debug_log_text (mode, NULL, "float type = %s", get_float_type_name (type)); break; } //////////////////////////////////////// case ENTITY_DEBUG_FLOAT_VALUE: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en, float_types type, float value) // float_types type; float value; type = va_arg (pargs, float_types); value = va_arg (pargs, double); debug_log_text (mode, en, "%s = %.3f", get_float_type_name (type), value); break; } //////////////////////////////////////// case ENTITY_DEBUG_INT_TYPE: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en, int_types type) // int_types type; type = va_arg (pargs, int_types); debug_log_text (mode, NULL, "int type = %s", get_int_type_name (type)); break; } //////////////////////////////////////// case ENTITY_DEBUG_INT_VALUE: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en, int_types type, int value) // int_types type; int value; type = va_arg (pargs, int_types); value = va_arg (pargs, int); debug_log_text (mode, en, "%s = %d", get_int_type_name (type), value); break; } //////////////////////////////////////// case ENTITY_DEBUG_KILL: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en) // debug_log_text (mode, en, "kill"); break; } //////////////////////////////////////// case ENTITY_DEBUG_LIST_TYPE: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en, list_types type) // list_types type; type = va_arg (pargs, list_types); debug_log_text (mode, NULL, "list type = %s", get_list_type_name (type)); break; } //////////////////////////////////////// case ENTITY_DEBUG_LIST_TYPE_CHILD_PRED: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en, list_types type, entity *child_pred) // list_types type; entity *child_pred; int index; type = va_arg (pargs, list_types); child_pred = va_arg (pargs, entity *); index = get_local_entity_safe_index (child_pred); debug_log_text (mode, en, "%s child pred index = %d", get_list_type_name (type), index); break; } //////////////////////////////////////// case ENTITY_DEBUG_LIST_TYPE_CHILD_SUCC: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en, list_types type, entity *child_succ) // list_types type; entity *child_succ; int index; type = va_arg (pargs, list_types); child_succ = va_arg (pargs, entity *); index = get_local_entity_safe_index (child_succ); debug_log_text (mode, en, "%s child succ index = %d", get_list_type_name (type), index); break; } //////////////////////////////////////// case ENTITY_DEBUG_LIST_TYPE_FIRST_CHILD: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en, list_types type, entity *first_child) // list_types type; entity *first_child; int index; type = va_arg (pargs, list_types); first_child = va_arg (pargs, entity *); index = get_local_entity_safe_index (first_child); debug_log_text (mode, en, "%s first child index = %d", get_list_type_name (type), index); break; } //////////////////////////////////////// case ENTITY_DEBUG_LIST_TYPE_PARENT: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en, list_types type, entity *parent) // list_types type; entity *parent; int index; type = va_arg (pargs, list_types); parent = va_arg (pargs, entity *); index = get_local_entity_safe_index (parent); debug_log_text (mode, en, "%s parent index = %d", get_list_type_name (type), index); break; } //////////////////////////////////////// case ENTITY_DEBUG_PTR_TYPE: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en, ptr_types type) // ptr_types type; type = va_arg (pargs, ptr_types); debug_log_text (mode, NULL, "ptr type = %s", get_ptr_type_name (type)); break; } //////////////////////////////////////// case ENTITY_DEBUG_PTR_VALUE: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en, ptr_types type, void *ptr) // ptr_types type; void *ptr; type = va_arg (pargs, ptr_types); ptr = va_arg (pargs, void *); debug_log_text (mode, en, "%s = 0x%x", get_ptr_type_name (type), ptr); break; } //////////////////////////////////////// case ENTITY_DEBUG_STRING_TYPE: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en, string_types type) // string_types type; type = va_arg (pargs, string_types); debug_log_text (mode, NULL, "string type = %s", get_string_type_name (type)); break; } //////////////////////////////////////// case ENTITY_DEBUG_STRING: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en, string_types type, char *s) // string_types type; char *s; type = va_arg (pargs, string_types); s = va_arg (pargs, char *); ASSERT (s); debug_log_text (mode, en, "%s = %s", get_string_type_name (type), s); break; } //////////////////////////////////////// case ENTITY_DEBUG_VEC3D_TYPE: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en, vec3d_types type) // vec3d_types type; type = va_arg (pargs, vec3d_types); debug_log_text (mode, NULL, "vec3d type = %s", get_vec3d_type_name (type)); break; } //////////////////////////////////////// case ENTITY_DEBUG_VEC3D: //////////////////////////////////////// { // // (entity_debug_modes mode, entity_debug_args arg, entity *en, vec3d_types type, vec3d *v) // vec3d_types type; vec3d *v; type = va_arg (pargs, vec3d_types); v = va_arg (pargs, vec3d *); ASSERT (v); if (type == VEC3D_TYPE_POSITION) { int x_sec, z_sec; get_x_sector (x_sec, v->x); get_z_sector (z_sec, v->z); debug_log_text (mode, en, "%s = (x = %.3f, y = %.3f, z = %.3f, x sec = %d, z sec = %d)", get_vec3d_type_name (type), v->x, v->y, v->z, x_sec, z_sec); } else { debug_log_text (mode, en, "%s = (x = %.3f, y = %.3f, z = %.3f)", get_vec3d_type_name (type), v->x, v->y, v->z); } break; } //////////////////////////////////////// default: //////////////////////////////////////// { debug_fatal ("Invalid entity debug arg = %d", arg); break; } } va_end (pargs); }
void ship_vehicle_death_movement (entity *en) { ship_vehicle *raw; float speed, heading, pitch, roll; vec3d *pos, *velocity, new_pos; raw = get_local_entity_data (en); // // work out new position // velocity = get_local_entity_vec3d_ptr (en, VEC3D_TYPE_MOTION_VECTOR); pos = get_local_entity_vec3d_ptr (en, VEC3D_TYPE_POSITION); new_pos.x = pos->x + (velocity->x * get_entity_movement_delta_time()); new_pos.y = pos->y + (velocity->y * get_entity_movement_delta_time()); new_pos.z = pos->z + (velocity->z * get_entity_movement_delta_time()); // // update velocity // velocity->x -= (velocity->x * 0.2 * get_entity_movement_delta_time ()); velocity->z -= (velocity->z * 0.2 * get_entity_movement_delta_time ()); velocity->y -= (SHIP_SINK_RATE * get_entity_movement_delta_time ()); speed = get_3d_vector_magnitude (velocity); set_local_entity_float_value (en, FLOAT_TYPE_VELOCITY, speed); // // update attitude // heading = get_heading_from_attitude_matrix (raw->vh.mob.attitude); pitch = get_pitch_from_attitude_matrix (raw->vh.mob.attitude); pitch += (SHIP_SINK_DELTA_PITCH_RATE * get_entity_movement_delta_time()); roll = get_roll_from_attitude_matrix (raw->vh.mob.attitude); roll += (SHIP_SINK_DELTA_ROLL_RATE * get_entity_movement_delta_time()); get_3d_transformation_matrix (raw->vh.mob.attitude, heading, pitch, roll); // // set new position // set_local_entity_vec3d (en, VEC3D_TYPE_POSITION, &new_pos); clear_ship_fires (en, ENTITY_SUB_TYPE_EFFECT_SMOKE_LIST_FIRE); clear_ship_fires (en, ENTITY_SUB_TYPE_EFFECT_SMOKE_LIST_EXPLOSION_TRAIL); // // remove ship if totally obscured (i.e. sunk) // if (get_comms_model () == COMMS_MODEL_SERVER) { struct OBJECT_3D_BOUNDS *bounding_box; vec3d d; float obscured_altitude; bounding_box = get_object_3d_bounding_box (get_local_entity_int_value (en, INT_TYPE_OBJECT_3D_SHAPE)); d.x = bounding_box->xmax - bounding_box->xmin; d.y = bounding_box->ymax - bounding_box->ymin; d.z = bounding_box->zmax - bounding_box->zmin; obscured_altitude = -(0.5 * get_3d_vector_magnitude (&d)); if (new_pos.y < obscured_altitude) { // // ship is no longer visible // destroy_client_server_entity_family (en); } } }