entity *add_group_to_division (entity *group, entity *specified_division) { entity_sides side; int count, max_count, group_type, keysite_type, division_type, main_division_type; entity *en, *force, *keysite, *division; vec3d *group_pos; ASSERT (group); ASSERT (get_comms_model () == COMMS_MODEL_SERVER); ASSERT (!get_local_entity_parent (group, LIST_TYPE_DIVISION)); group_type = get_local_entity_int_value (group, INT_TYPE_ENTITY_SUB_TYPE); group_pos = get_local_entity_vec3d_ptr (group, VEC3D_TYPE_POSITION); if (specified_division) { division = specified_division; } else { side = (entity_sides) get_local_entity_int_value (group, INT_TYPE_SIDE); force = get_local_force_entity (side); ASSERT (force); division_type = group_database [group_type].default_group_division; ASSERT (entity_sub_type_division_valid (division_type)); main_division_type = division_database [division_type].default_group_division; ASSERT (entity_sub_type_division_valid (main_division_type)); // // Find the keysite the company should be attached to // keysite = NULL; if (get_local_entity_int_value (group, INT_TYPE_GROUP_LIST_TYPE) == LIST_TYPE_KEYSITE_GROUP) { keysite = get_local_entity_parent (group, LIST_TYPE_KEYSITE_GROUP); if (!keysite) { keysite = get_closest_keysite (NUM_ENTITY_SUB_TYPE_KEYSITES, side, group_pos, 1.0 * KILOMETRE, NULL, NULL); } ASSERT (keysite); keysite_type = get_local_entity_int_value (keysite, INT_TYPE_ENTITY_SUB_TYPE); if ((keysite_type == ENTITY_SUB_TYPE_KEYSITE_AIRBASE) || (keysite_type == ENTITY_SUB_TYPE_KEYSITE_ANCHORAGE)) { // // Use keysite landed at // } else { // // Find nearest keysite (below) // keysite = NULL; } } else { if (group_database [group_type].movement_type == MOVEMENT_TYPE_SEA) { // // Find nearest carrier // keysite = get_closest_keysite (ENTITY_SUB_TYPE_KEYSITE_ANCHORAGE, side, group_pos, 0.0, NULL, NULL); } } if (!keysite) { // // Find nearest airbase // keysite = get_closest_keysite (ENTITY_SUB_TYPE_KEYSITE_AIRBASE, side, group_pos, 0.0, NULL, NULL); if (!keysite) { // // Find nearest military base // keysite = get_closest_keysite (ENTITY_SUB_TYPE_KEYSITE_MILITARY_BASE, side, group_pos, 0.0, NULL, NULL); if (!keysite) { // // Find nearest FARP // keysite = get_closest_keysite (ENTITY_SUB_TYPE_KEYSITE_FARP, side, group_pos, 0.0, NULL, NULL); } } } ASSERT (keysite); // // Check all companies at this keysite to see if they have vacancies.... // max_count = group_database [group_type].maximum_groups_per_division; division = get_local_entity_first_child (keysite, LIST_TYPE_DIVISION_HEADQUARTERS); while (division) { if (get_local_entity_int_value (division, INT_TYPE_ENTITY_SUB_TYPE) == division_type) { if (max_count == 0) { break; } count = 0; en = get_local_entity_first_child (division, LIST_TYPE_DIVISION); while (en) { ASSERT (get_local_entity_type (en) == ENTITY_TYPE_GROUP); count ++; en = get_local_entity_child_succ (en, LIST_TYPE_DIVISION); } if (count < max_count) { break; } } division = get_local_entity_child_succ (division, LIST_TYPE_DIVISION_HEADQUARTERS); } if (division) { // // found an existing division with space available // } else { // // create a new division // entity *main_division; max_count = division_database [division_type].maximum_groups_per_division; main_division = get_local_entity_first_child (force, LIST_TYPE_DIVISION); while (main_division) { if (get_local_entity_int_value (main_division, INT_TYPE_ENTITY_SUB_TYPE) == main_division_type) { // // check division for vacancies // if (max_count == 0) { break; } count = 0; en = get_local_entity_first_child (main_division, LIST_TYPE_DIVISION); while (en) { ASSERT (get_local_entity_type (en) == ENTITY_TYPE_DIVISION); if (get_local_entity_int_value (en, INT_TYPE_ENTITY_SUB_TYPE) == division_type) { count ++; } en = get_local_entity_child_succ (en, LIST_TYPE_DIVISION); } if (count < max_count) { break; } } main_division = get_local_entity_child_succ (main_division, LIST_TYPE_DIVISION); } if (main_division) { // // found an existing division with space available // } else { // // create a new division // main_division = create_new_division (main_division_type, side, force, NULL, FALSE); } ASSERT (main_division); division = create_new_division (division_type, side, main_division, keysite, FALSE); } } ASSERT (division); set_client_server_entity_parent (group, LIST_TYPE_DIVISION, division); return division; }
int reassign_group_members_to_valid_tasks (entity *group, entity *last_task, unsigned int members_to_reassign, int engage_enemy) { entity *guide, *member, *new_task; unsigned int member_number, valid_members; ASSERT (members_to_reassign != 0); // // first see if any engage tasks can be done // if (engage_enemy) { members_to_reassign = assign_engage_tasks_to_group (group, members_to_reassign); } if (!members_to_reassign) { // // all members have successfully been allocated engage tasks - so no need to worry about rest of the task stack // return TRUE; } // // take each member in the group that requires a new task // member = get_local_entity_first_child (group, LIST_TYPE_MEMBER); while (member) { member_number = (1 << get_local_entity_int_value (member, INT_TYPE_GROUP_MEMBER_NUMBER)); if (members_to_reassign & member_number) { // // If the member gets here, then it can't be doing an engage task, hence it shouldn't have a target... (unless its a player) // if (get_local_entity_int_value (member, INT_TYPE_PLAYER) == ENTITY_PLAYER_AI) { if (get_local_entity_parent (member, LIST_TYPE_TARGET)) { set_client_server_entity_parent (member, LIST_TYPE_TARGET, NULL); } } // // Look at each task on the stack // new_task = NULL; guide = get_local_entity_first_child (group, LIST_TYPE_GUIDE_STACK); while (guide) { // // is task meant for this member ? // valid_members = get_local_entity_int_value (guide, INT_TYPE_VALID_GUIDE_MEMBERS); if (valid_members & member_number) { new_task = get_local_entity_parent (guide, LIST_TYPE_GUIDE); if (get_local_entity_int_value (new_task, INT_TYPE_TASK_TERMINATED) == TASK_TERMINATED_IN_PROGRESS) { assign_new_task_to_group_member (group, member, new_task, guide); // // clear member flag, and skip to next group member // members_to_reassign &= (~member_number); break; } } new_task = NULL; guide = get_local_entity_child_succ (guide, LIST_TYPE_GUIDE_STACK); } } member = get_local_entity_child_succ (member, LIST_TYPE_MEMBER); } return TRUE; }
int amalgamate_groups (entity *receiving_group, entity *donating_group) { entity *this_member, *member; int group_type, group_kills, group_losses, donating_group_count, receiving_group_count; ASSERT (get_comms_model () == COMMS_MODEL_SERVER); // check both groups are not doing any tasks ASSERT (get_local_entity_int_value (receiving_group, INT_TYPE_GROUP_MODE) == GROUP_MODE_IDLE); ASSERT (get_local_entity_int_value (donating_group, INT_TYPE_GROUP_MODE) == GROUP_MODE_IDLE); // check group type are the same group_type = get_local_entity_int_value (receiving_group, INT_TYPE_ENTITY_SUB_TYPE); if (group_type != get_local_entity_int_value (donating_group, INT_TYPE_ENTITY_SUB_TYPE)) { return FALSE; } ASSERT (group_database [group_type].amalgamate); ASSERT (get_local_entity_int_value (donating_group, INT_TYPE_SIDE) == get_local_entity_int_value (receiving_group, INT_TYPE_SIDE)); donating_group_count = get_local_entity_int_value (donating_group, INT_TYPE_MEMBER_COUNT); receiving_group_count = get_local_entity_int_value (receiving_group, INT_TYPE_MEMBER_COUNT); if ((donating_group_count + receiving_group_count) <= group_database [group_type].maximum_member_count) { #ifdef DEBUG //#if DEBUG_MODULE if ((get_local_entity_parent (donating_group, LIST_TYPE_KEYSITE_GROUP)) && (get_local_entity_parent (receiving_group, LIST_TYPE_KEYSITE_GROUP))) { ASSERT (get_local_entity_type (get_local_entity_parent (donating_group, LIST_TYPE_KEYSITE_GROUP)) == get_local_entity_type (get_local_entity_parent (receiving_group, LIST_TYPE_KEYSITE_GROUP))); } debug_log ("GROUP: amalgamating group %s %d (count %d) with group %s %d (count %d)", entity_sub_type_group_names [group_type], get_local_entity_index (donating_group), donating_group_count, entity_sub_type_group_names [group_type], get_local_entity_index (receiving_group), receiving_group_count); member = get_local_entity_first_child (donating_group, LIST_TYPE_MEMBER); while (member) { debug_log ("GROUP: donating group member %s (%d)", get_local_entity_string (member, STRING_TYPE_FULL_NAME), get_local_entity_index (member)); ASSERT (get_local_entity_int_value (member, INT_TYPE_OPERATIONAL_STATE) == OPERATIONAL_STATE_LANDED); member = get_local_entity_child_succ (member, LIST_TYPE_MEMBER); } member = get_local_entity_first_child (receiving_group, LIST_TYPE_MEMBER); while (member) { debug_log ("GROUP: receiving group member %s (%d)", get_local_entity_string (member, STRING_TYPE_FULL_NAME), get_local_entity_index (member)); ASSERT (get_local_entity_int_value (member, INT_TYPE_OPERATIONAL_STATE) == OPERATIONAL_STATE_LANDED); member = get_local_entity_child_succ (member, LIST_TYPE_MEMBER); } //#endif #endif member = get_local_entity_first_child (donating_group, LIST_TYPE_MEMBER); while (member) { this_member = member; member = get_local_entity_child_succ (member, LIST_TYPE_MEMBER); set_client_server_entity_parent (this_member, LIST_TYPE_MEMBER, receiving_group); } group_kills = get_local_entity_int_value (receiving_group, INT_TYPE_KILLS); group_losses = get_local_entity_int_value (receiving_group, INT_TYPE_LOSSES); group_kills += get_local_entity_int_value (donating_group, INT_TYPE_KILLS); group_losses += get_local_entity_int_value (donating_group, INT_TYPE_LOSSES); if (get_local_entity_int_value (receiving_group, INT_TYPE_KILLS) != group_kills) { set_client_server_entity_int_value (receiving_group, INT_TYPE_KILLS, group_kills); } if (get_local_entity_int_value (receiving_group, INT_TYPE_LOSSES) != group_losses) { set_client_server_entity_int_value (receiving_group, INT_TYPE_LOSSES, group_losses); } // // renumber the group members // set_group_member_numbers (receiving_group); // // place empty donating group on free list // ASSERT (get_local_entity_int_value (donating_group, INT_TYPE_MEMBER_COUNT) == 0); kill_client_server_group_entity (donating_group); #ifdef DEBUG { vec3d *pos1, *test_pos; float amalgamate_max_range = 10 * KILOMETRE; member = get_local_entity_first_child (receiving_group, LIST_TYPE_MEMBER); ASSERT (member); pos1 = get_local_entity_vec3d_ptr (member, VEC3D_TYPE_POSITION); member = get_local_entity_child_succ (member, LIST_TYPE_MEMBER); while (member) { test_pos = get_local_entity_vec3d_ptr (member, VEC3D_TYPE_POSITION); if (get_2d_range (pos1, test_pos) > amalgamate_max_range) { debug_log ("GROUP: WARNING: Amalgamated group with members (%s (%d) and %s (%d)) %f apart -------------------------", get_local_entity_string (get_local_entity_first_child (receiving_group, LIST_TYPE_MEMBER), STRING_TYPE_FULL_NAME), get_local_entity_index (get_local_entity_first_child (receiving_group, LIST_TYPE_MEMBER)), get_local_entity_string (member, STRING_TYPE_FULL_NAME), get_local_entity_index (member), get_2d_range (pos1, test_pos)); } member = get_local_entity_child_succ (member, LIST_TYPE_MEMBER); } } #endif return TRUE; } return FALSE; }
int assign_primary_task_to_group (entity *group_en, entity *task_en) { entity_sub_types task_type, group_type; entity *force, *keysite; int side, formation, air_threat, enemy_sectors; unsigned int threat; ASSERT (get_comms_model () == COMMS_MODEL_SERVER); task_type = get_local_entity_int_value (task_en, INT_TYPE_ENTITY_SUB_TYPE); ASSERT (task_database [task_type].primary_task); group_type = get_local_entity_int_value (group_en, INT_TYPE_ENTITY_SUB_TYPE); ASSERT (!get_local_group_primary_task (group_en)); if (assign_task_to_group (group_en, task_en, TASK_ASSIGN_ALL_MEMBERS)) { // // set default group formation // formation = get_local_entity_int_value (group_en, INT_TYPE_GROUP_DEFAULT_FORMATION); if (formation != get_local_entity_int_value (group_en, INT_TYPE_GROUP_FORMATION)) { set_client_server_entity_int_value (group_en, INT_TYPE_GROUP_FORMATION, formation); } // // Link to new keysite // if (get_local_entity_int_value (group_en, INT_TYPE_GROUP_LIST_TYPE) == LIST_TYPE_KEYSITE_GROUP) { keysite = ( entity * ) get_local_entity_ptr_value (task_en, PTR_TYPE_RETURN_KEYSITE); if (keysite) { set_client_server_entity_parent (group_en, LIST_TYPE_KEYSITE_GROUP, keysite); } } // // Notify Force // side = get_local_entity_int_value (group_en, INT_TYPE_SIDE); force = get_local_force_entity ( ( entity_sides ) side ); ASSERT (force); notify_local_entity (ENTITY_MESSAGE_TASK_ASSIGNED, force, task_en); // // Assess for Escort task // if (task_database [task_type].escort_required_threshold != ESCORT_NEVER) { threat = assess_task_difficulty (task_en, &air_threat, &enemy_sectors); #if DEBUG_ESCORT_TASK_CREATION debug_filtered_log ("(ASSIGN) Side %s: Assigned %s to %s, objective %s", entity_side_short_names [side], get_local_entity_string (group_en, STRING_TYPE_FULL_NAME), get_local_entity_string (task_en, STRING_TYPE_FULL_NAME), get_task_objective_string (task_en) ); debug_filtered_log ("Threat: %d (air_threat: %d, enemy_sectors: %d) - Threshold %d", threat, air_threat, enemy_sectors, task_database [task_type].escort_required_threshold); #endif if (threat >= task_database [task_type].escort_required_threshold) { create_escort_task (group_en, (threat >= ESCORT_CRITICAL), task_database [ENTITY_SUB_TYPE_TASK_ESCORT].task_priority, NULL, NULL); ai_log ("(ASSIGN) Created Escort Task for %s :- Threat %d / Threshold %d", get_local_entity_string (task_en, STRING_TYPE_FULL_NAME), threat, task_database [task_type].escort_required_threshold ); } } // // Store Start Time // set_client_server_entity_float_value (task_en, FLOAT_TYPE_START_TIME, get_local_entity_float_value (get_session_entity (), FLOAT_TYPE_ELAPSED_TIME)); // // Clear Expire Timer (now also used for destroying completed tasks) // set_local_entity_float_value (task_en, FLOAT_TYPE_EXPIRE_TIMER, 0.0); ai_log ("(ASSIGN) Side %s: Assigned %s (%d) to %s (%d) - Priority %f", entity_side_short_names [side], get_local_entity_string (group_en, STRING_TYPE_FULL_NAME), get_local_entity_safe_index (group_en), get_local_entity_string (task_en, STRING_TYPE_FULL_NAME), get_local_entity_safe_index (task_en), get_local_entity_float_value (task_en, FLOAT_TYPE_TASK_PRIORITY)); return TRUE; } return FALSE; }