// evaluate a certain function for all docked objects void dock_evaluate_all_docked_objects(object *objp, dock_function_info *infop, void (*function)(object *, dock_function_info *)) { Assert((objp != NULL) && (infop != NULL) && (function != NULL)); // not docked? if (!object_is_docked(objp)) { // call the function for just the one object function(objp, infop); return; } // we only have two objects docked if (dock_check_docked_one_on_one(objp)) { // call the function for the first object, and return if instructed function(objp, infop); if (infop->early_return_condition) return; // call the function for the second object, and return if instructed function(objp->dock_list->docked_objp, infop); if (infop->early_return_condition) return; } // we have multiple objects docked and we're treating them as a hub else if (dock_check_assume_hub()) { // get the hub object *hub_objp = dock_get_hub(objp); // call the function for the hub, and return if instructed function(hub_objp, infop); if (infop->early_return_condition) return; // iterate through all docked objects for (dock_instance *ptr = hub_objp->dock_list; ptr != NULL; ptr = ptr->next) { // call the function for this object, and return if instructed function(ptr->docked_objp, infop); if (infop->early_return_condition) return; } } // we have multiple objects docked and we must treat them as a tree else { // create a bit array to mark the objects we check ubyte *visited_bitstring = (ubyte *) vm_malloc(calculate_num_bytes(MAX_OBJECTS)); // clear it memset(visited_bitstring, 0, calculate_num_bytes(MAX_OBJECTS)); // start evaluating the tree dock_evaluate_tree(objp, infop, function, visited_bitstring); // destroy the bit array vm_free(visited_bitstring); visited_bitstring = NULL; } }
object *dock_get_first_docked_object(object *objp) { // are we docked? if (!object_is_docked(objp)) return NULL; return objp->dock_list->docked_objp; }
void initial_status::undock(object *objp1, object *objp2) { vec3d v; int ship_num, other_ship_num; if (objp1 == NULL || objp2 == NULL) return; vm_vec_sub(&v, &objp2->pos, &objp1->pos); vm_vec_normalize(&v); ship_num = get_ship_from_obj(OBJ_INDEX(objp1)); other_ship_num = get_ship_from_obj(OBJ_INDEX(objp2)); if (ship_class_compare(Ships[ship_num].ship_info_index, Ships[other_ship_num].ship_info_index) <= 0) vm_vec_scale_add2(&objp2->pos, &v, objp2->radius * 2.0f); else vm_vec_scale_add2(&objp1->pos, &v, objp1->radius * -2.0f); ai_do_objects_undocked_stuff(objp1, objp2); // check to see if one of these ships has an arrival cue of false. If so, then // reset it back to default value of true. be sure to correctly update before // and after setting data. // Goober5000 - but don't reset it if it's part of a wing! Ship_editor_dialog.update_data(1); if ( Ships[ship_num].arrival_cue == Locked_sexp_false && Ships[ship_num].wingnum < 0 ) { Ships[ship_num].arrival_cue = Locked_sexp_true; } else if ( Ships[other_ship_num].arrival_cue == Locked_sexp_false && Ships[other_ship_num].wingnum < 0 ) { Ships[other_ship_num].arrival_cue = Locked_sexp_true; } // if this ship is no longer docked, ensure its dock leader flag is clear if (!object_is_docked(&Objects[Ships[ship_num].objnum])) Ships[ship_num].flags.remove(Ship::Ship_Flags::Dock_leader); // same for the other ship if (!object_is_docked(&Objects[Ships[other_ship_num].objnum])) Ships[other_ship_num].flags.remove(Ship::Ship_Flags::Dock_leader); Ship_editor_dialog.initialize_data(1); }
void dock_undock_all(object *objp) { Assert(objp != NULL); while (object_is_docked(objp)) { object* dockee = dock_get_first_docked_object(objp); dock_undock_objects(objp, dockee); } }
object *dock_get_hub(object *objp) { Assert(dock_check_assume_hub() && object_is_docked(objp)); // if our dock list contains only one object, it must be the hub if (objp->dock_list->next == NULL) { return dock_get_first_docked_object(objp); } // otherwise we are the hub else { return objp; } }
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); }
// evaluate a certain function for all docked objects void dock_evaluate_all_docked_objects(p_object *objp, p_dock_function_info *infop, void (*function)(p_object *, p_dock_function_info *)) { Assert((objp != NULL) && (infop != NULL) && (function != NULL)); // not docked? if (!object_is_docked(objp)) { // call the function for just the one object function(objp, infop); return; } // we only have two objects docked if (dock_check_docked_one_on_one(objp)) { // call the function for the first object, and return if instructed function(objp, infop); if (infop->early_return_condition) return; // call the function for the second object, and return if instructed function(objp->dock_list->docked_objp, infop); if (infop->early_return_condition) return; } // NOTE - never treat a group of parse objects as a hub... it cuts down on bugs, and it's // not needed because it's not time-critical // we have multiple objects docked and we must treat them as a tree else { // create a bit array to mark the objects we check ubyte *visited_bitstring = (ubyte *) vm_malloc(calculate_num_bytes(Parse_objects.size())); // clear it memset(visited_bitstring, 0, calculate_num_bytes(Parse_objects.size())); // start evaluating the tree dock_evaluate_tree(objp, infop, function, visited_bitstring); // destroy the bit array vm_free(visited_bitstring); visited_bitstring = NULL; } }
bool dock_check_docked_one_on_one(object *objp) { // we must be docked if (!object_is_docked(objp)) return false; // our dock list must contain only one object if (objp->dock_list->next != NULL) return false; // the other guy's dock list must contain only one object if (dock_get_first_docked_object(objp)->dock_list->next != NULL) return false; // debug check to make sure that we're docked to each other Assert(objp == dock_get_first_docked_object(objp)->dock_list->docked_objp); // success return true; }
void dock_dock_docked_objects(p_object *objp) { if (!object_is_docked(objp)) return; // has this object (by extension, this group of docked objects) been handled already? if (objp->flags[Mission::Parse_Object_Flags::Already_handled]) return; Assert(objp->flags[Mission::Parse_Object_Flags::SF_Dock_leader]); p_dock_function_info dfi; // 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 P2_ALREADY_HANDLED takes care of it // start evaluating the tree, starting with the dock leader dock_dock_docked_children_tree(objp, NULL); }
void emp_process_ship(ship *shipp) { object *objp; ai_info *aip; Assert(shipp != NULL); if(shipp == NULL){ return; } Assert(shipp->objnum >= 0); if(shipp->objnum < 0){ return; } objp = &Objects[shipp->objnum]; // if the emp intensity is < 0, there is no effect if(shipp->emp_intensity < 0.0f){ shipp->emp_intensity = -1.0f; return; } // reduce the emp effect shipp->emp_intensity -= shipp->emp_decr * flFrametime; // multiplayer clients should bail here if(MULTIPLAYER_CLIENT){ return; } // if this is a player ship, don't do anything wacky if(objp->flags & OF_PLAYER_SHIP){ return; } // lose lock time, etc, etc. Assert(shipp->ai_index >= 0); aip = &Ai_info[shipp->ai_index]; aip->aspect_locked_time = 0.0f; // hasn't gotten aspect lock at all aip->current_target_is_locked = 0; // isn't locked on his current target aip->ai_flags &= ~AIF_SEEK_LOCK; aip->nearest_locked_object = -1; // nothing near me, so I won't launch countermeasures // if he's not a fighter or bomber, bail now if(!(Ship_info[shipp->ship_info_index].flags & (SIF_FIGHTER | SIF_BOMBER))){ return; } // if he's docked, or ordered to not move, bail now if (object_is_docked(objp) || (aip->mode == AIM_STILL) || (aip->mode == AIM_PLAY_DEAD)){ return; } // pick targets randomly and wackily so that the ship flies crazily :) if(((int)f2fl(Missiontime) + (int)(EMP_INTENSITY_MAX * shipp->emp_intensity)) % mod_val == 0){ int ship_lookup = ship_get_random_team_ship(iff_get_attackee_mask(shipp->team)); // if we got a valid ship object to target if((ship_lookup >= 0) && (Ships[ship_lookup].objnum >= 0) && !(Objects[Ships[ship_lookup].objnum].flags & OF_PROTECTED)){ // attack the object ai_attack_object(objp, &Objects[Ships[ship_lookup].objnum], NULL); } } }