void initial_status::dock(object *objp, int dockpoint, object *other_objp, int other_dockpoint) { if (objp == NULL || other_objp == NULL) return; if (dockpoint < 0 || other_dockpoint < 0) return; dock_function_info dfi; // do the docking (do it in reverse so that the current object stays put) ai_dock_with_object(other_objp, other_dockpoint, objp, dockpoint, AIDO_DOCK_NOW); // unmark the handled flag in preparation for the next step dock_evaluate_all_docked_objects(objp, &dfi, initial_status_unmark_dock_handled_flag); // move all other objects to catch up with it dock_move_docked_objects(objp); // set the dock leader dock_evaluate_all_docked_objects(objp, &dfi, initial_status_mark_dock_leader_helper); // if no leader, mark me if (dfi.maintained_variables.int_value == 0) Ships[objp->instance].flags.set(Ship::Ship_Flags::Dock_leader); }
float dock_calc_docked_speed(object *objp) { // ditto with speed dock_function_info dfi; dock_evaluate_all_docked_objects(objp, &dfi, dock_find_max_speed_helper); return dfi.maintained_variables.float_value; }
float dock_calc_docked_fspeed(object *objp) { // *sigh*... the docked fspeed is simply the max fspeed of all docked objects dock_function_info dfi; dock_evaluate_all_docked_objects(objp, &dfi, dock_find_max_fspeed_helper); return dfi.maintained_variables.float_value; }
int dock_count_total_docked_objects(object *objp) { dock_function_info dfi; dock_evaluate_all_docked_objects(objp, &dfi, dock_count_total_docked_objects_helper); return dfi.maintained_variables.int_value; }
bool dock_check_find_docked_object(object *objp, object *other_objp) { dock_function_info dfi; dfi.parameter_variables.objp_value = other_objp; dock_evaluate_all_docked_objects(objp, &dfi, dock_check_find_docked_object_helper); return dfi.maintained_variables.bool_value; }
float dock_calc_total_docked_mass(object *objp) { Assert(objp != NULL); dock_function_info dfi; dock_evaluate_all_docked_objects(objp, &dfi, dock_calc_total_docked_mass_helper); return dfi.maintained_variables.float_value; }
void dock_calc_docked_center_of_mass(vec3d *dest, object *objp) { vm_vec_zero(dest); dock_function_info dfi; dfi.maintained_variables.vecp_value = dest; dock_evaluate_all_docked_objects(objp, &dfi, dock_calc_docked_center_of_mass_helper); // overall center of mass = weighted sum of centers of mass divided by total mass vm_vec_scale(dest, (1.0f / dfi.maintained_variables.float_value)); }
void dock_calc_docked_center(vec3d *dest, object *objp) { vm_vec_zero(dest); dock_function_info dfi; dfi.maintained_variables.vecp_value = dest; dock_evaluate_all_docked_objects(objp, &dfi, dock_calc_docked_center_helper); // overall center = sum of centers divided by sum of objects vm_vec_scale(dest, (1.0f / (float) dfi.maintained_variables.int_value)); }
float dock_calc_max_semilatus_rectum_parallel_to_axis(object *objp, axis_type axis) { Assert(objp != NULL); vec3d local_line_end; vec3d *world_line_start, world_line_end; dock_function_info dfi; // to calculate the semilatus rectum, we need a directrix that will be parallel to the axis // the first endpoint is simply the position of the object world_line_start = &objp->pos; // the second endpoint extends in the axis direction vm_vec_zero(&local_line_end); switch(axis) { case X_AXIS: local_line_end.xyz.x = 1.0f; break; case Y_AXIS: local_line_end.xyz.y = 1.0f; break; case Z_AXIS: local_line_end.xyz.z = 1.0f; break; default: Int3(); return 0.0f; } // rotate and move the endpoint to go through the axis of the actual object vm_vec_rotate(&world_line_end, &local_line_end, &objp->orient); vm_vec_add2(&world_line_end, &objp->pos); // now we have a unit vector starting at the object's position and pointing along the chosen axis // (although the length doesn't matter, as it's calculated as an endless line) // now determine the semilatus rectum // set parameters and call function for the semilatus rectum squared dfi.parameter_variables.vecp_value = world_line_start; dfi.parameter_variables.vecp_value2 = &world_line_end; dock_evaluate_all_docked_objects(objp, &dfi, dock_calc_max_semilatus_rectum_squared_parallel_to_directrix_helper); // the semilatus rectum is the square root of our result return fl_sqrt(dfi.maintained_variables.float_value); }
void dock_move_docked_objects(object *objp) { Assert(objp != NULL); if ((objp->type != OBJ_SHIP) && (objp->type != OBJ_START)) return; if (!object_is_docked(objp)) return; // has this object (by extension, this group of docked objects) been handled already? if (objp->flags[Object::Object_Flags::Docked_already_handled]) return; Assert((objp->instance >= 0) && (objp->instance < MAX_SHIPS)); dock_function_info dfi; object *fastest_objp; // in FRED, objp is the object everyone moves with if (Fred_running) { fastest_objp = objp; } else { // find the object with the highest max speed dock_evaluate_all_docked_objects(objp, &dfi, dock_find_max_speed_helper); fastest_objp = dfi.maintained_variables.objp_value; // if we have no max speed, just use the first one if (fastest_objp == NULL) fastest_objp = objp; } // start a tree with that object as the parent... do NOT use the überfunction for this, // because we must use a tree for the parent ancestry to work correctly // we don't need a bit array because OF_DOCKED_ALREADY_HANDLED takes care of it // and must persist for the entire game frame // start evaluating the tree, starting with the fastest object having no parent dock_move_docked_children_tree(fastest_objp, NULL); }