int group_task_specific_retaliation_checks (entity *group, entity *aggressor, int assisted) { entity *task, *objective; task_roe_types roe; entity_sides side; vec3d *group_pos, *objective_pos, *aggressor_pos; int sx, sz; ASSERT (get_comms_model () == COMMS_MODEL_SERVER); ASSERT (group); ASSERT (aggressor); if (get_local_entity_int_value (group, INT_TYPE_AIRCRAFT_GROUP)) { task = get_local_group_primary_task (group); if (!task) { return FALSE; } if (get_local_entity_int_value (aggressor, INT_TYPE_PLAYER) != ENTITY_PLAYER_AI) { return TRUE; } roe = get_local_entity_int_value (task, INT_TYPE_RULES_OF_ENGAGEMENT); switch (roe) { case TASK_ROE_NONE: { // // FALSE if aggressor is within target area (stop RECON missions from destroying objectives) // if (get_local_entity_int_value (task, INT_TYPE_ENTITY_SUB_TYPE) == ENTITY_SUB_TYPE_TASK_RECON) { objective = get_local_entity_parent (task, LIST_TYPE_TASK_DEPENDENT); if (objective) { objective_pos = get_local_entity_vec3d_ptr (objective, VEC3D_TYPE_POSITION); ASSERT (objective_pos); aggressor_pos = get_local_entity_vec3d_ptr (aggressor, VEC3D_TYPE_POSITION); ASSERT (aggressor_pos); if (get_sqr_2d_range (aggressor_pos, objective_pos) < ((2.0 * KILOMETRE) * (2.0 * KILOMETRE))) { ai_log ("(RETALIATE CHECK) ROE NONE - Failed (Aggressor at target area)"); return FALSE; } } } // // Retaliate if no-one else coming to assist, AND (mission complete OR aggressor in friendly territory) // if (!assisted) { if (get_local_entity_int_value (task, INT_TYPE_TASK_COMPLETED) != TASK_INCOMPLETE) { ai_log ("(RETALIATE CHECK) ROE NONE - Task Complete"); return TRUE; } side = get_local_entity_int_value (group, INT_TYPE_SIDE); group_pos = get_local_entity_vec3d_ptr (group, VEC3D_TYPE_POSITION); ASSERT (group_pos); get_x_sector (sx, group_pos->x); get_z_sector (sz, group_pos->z); if (get_local_sector_side_ratio (sx, sz, side) > 0.5) { ai_log ("(RETALIATE CHECK) ROE NONE - Friendly Territory"); return TRUE; } } ai_log ("(RETALIATE CHECK) ROE NONE - Failed Checks"); break; } case TASK_ROE_OBJECTIVE: { // // Retaliate if no-one else coming to assist, OR primary task completed // if (!assisted) { ai_log ("(RETALIATE CHECK) ROE OBJECTIVE - No Assistance"); return TRUE; } if (get_local_entity_int_value (task, INT_TYPE_TASK_COMPLETED) != TASK_INCOMPLETE) { ai_log ("(RETALIATE CHECK) ROE OBJECTIVE - Task Complete"); return TRUE; } ai_log ("(RETALIATE CHECK) ROE OBJECTIVE - Failed Checks"); break; } case TASK_ROE_ALL: { // // Always retaliate // ai_log ("(RETALIATE CHECK) ROE ALL"); return TRUE; } } return FALSE; } else { return TRUE; } }
unsigned int assign_engage_tasks_to_group (entity *group, unsigned int valid_members) { entity *task, *guide, *target, *member, *single_member, *persuer, **guide_list; unsigned int member_number; int best_count, best_guide, loop, criteria, task_count, *assigned_count; float range, *priority; vec3d *member_pos, *target_pos; ASSERT (group); ASSERT (get_comms_model () == COMMS_MODEL_SERVER); if (!valid_members) { return valid_members; } // // count up engage tasks // task_count = 0; guide = get_local_entity_first_child (group, LIST_TYPE_GUIDE_STACK); while (guide) { if (get_local_entity_int_value (guide, INT_TYPE_VALID_GUIDE_MEMBERS) == TASK_ASSIGN_NO_MEMBERS) { task = get_local_entity_parent (guide, LIST_TYPE_GUIDE); ASSERT (task); ASSERT (get_local_entity_int_value (task, INT_TYPE_ENTITY_SUB_TYPE) == ENTITY_SUB_TYPE_TASK_ENGAGE); if (get_local_entity_int_value (task, INT_TYPE_TASK_TERMINATED) == TASK_TERMINATED_IN_PROGRESS) { task_count ++; } } guide = get_local_entity_child_succ (guide, LIST_TYPE_GUIDE_STACK); } #if DEBUG_MODULE debug_log ("ENGAGE: =========================="); debug_log ("ENGAGE: %d suitable tasks", task_count); #endif if (task_count == 0) { return valid_members; } ////////////////////////////////////////////////////////////////// // // prioritize engage tasks // ////////////////////////////////////////////////////////////////// // // get target priority // guide_list = (entity * *) malloc_fast_mem (sizeof (entity *) * task_count); priority = (float *) malloc_fast_mem (sizeof (float) * task_count); assigned_count = (int *) malloc_fast_mem (sizeof (int) * task_count); #if DEBUG_MODULE debug_log ("ENGAGE: ======RAW LIST======"); #endif single_member = NULL; // check if we have a single member, if so assign that member to single_member for (member = get_local_entity_first_child (group, LIST_TYPE_MEMBER); member; member = get_local_entity_child_succ (member, LIST_TYPE_MEMBER)) { member_number = (1 << get_local_entity_int_value (member, INT_TYPE_GROUP_MEMBER_NUMBER)); if (member_number & valid_members) { if (single_member) // we already have a valid member, so there is more than one { single_member = NULL; break; } else single_member = member; } } loop = 0; guide = get_local_entity_first_child (group, LIST_TYPE_GUIDE_STACK); while (guide) { if (get_local_entity_int_value (guide, INT_TYPE_VALID_GUIDE_MEMBERS) == TASK_ASSIGN_NO_MEMBERS) { task = get_local_entity_parent (guide, LIST_TYPE_GUIDE); ASSERT (task); ASSERT (get_local_entity_int_value (task, INT_TYPE_ENTITY_SUB_TYPE) == ENTITY_SUB_TYPE_TASK_ENGAGE); if (get_local_entity_int_value (task, INT_TYPE_TASK_TERMINATED) == TASK_TERMINATED_IN_PROGRESS) { target = get_local_entity_parent (task, LIST_TYPE_TASK_DEPENDENT); ASSERT (target); if (!target) { notify_local_entity (ENTITY_MESSAGE_TASK_TERMINATED, task, group, TASK_TERMINATED_ABORTED); free_mem (guide_list); free_mem (priority); free_mem (assigned_count); return valid_members; } guide_list [loop] = guide; if (get_local_entity_int_value (group, INT_TYPE_AIRCRAFT_GROUP)) { priority [loop] = get_local_entity_float_value (target, FLOAT_TYPE_TARGET_PRIORITY_AIR_ATTACK); } else { priority [loop] = get_local_entity_float_value (target, FLOAT_TYPE_TARGET_PRIORITY_GROUND_ATTACK); } #if DEBUG_MODULE debug_log ("ENGAGE: (%d) Target : %s, Priority %f", loop, get_local_entity_string (target, STRING_TYPE_FULL_NAME), priority [loop]); #endif loop ++; } } guide = get_local_entity_child_succ (guide, LIST_TYPE_GUIDE_STACK); } ASSERT (loop == task_count); // // sort the tasks according to their priority // quicksort_entity_list (guide_list, task_count, priority); #if DEBUG_MODULE debug_log ("ENGAGE: ======SORTED======"); for (loop = 0; loop < task_count; loop ++) { task = get_local_entity_parent (guide_list [loop], LIST_TYPE_GUIDE); target = get_local_entity_parent (task, LIST_TYPE_TASK_DEPENDENT); debug_log ("ENGAGE: (%d) Target : %s (%d), Priority %f", loop, get_local_entity_string (target, STRING_TYPE_FULL_NAME), get_local_entity_index (target), priority [loop]); } #endif // // consider other entities attacking the same targets // memset (assigned_count, 0, sizeof (int) * task_count); for (loop = 0; loop < task_count; loop ++) { task = get_local_entity_parent (guide_list [loop], LIST_TYPE_GUIDE); target = get_local_entity_parent (task, LIST_TYPE_TASK_DEPENDENT); persuer = get_local_entity_first_child (target, LIST_TYPE_TARGET); while (persuer) { assigned_count [loop] ++; persuer = get_local_entity_child_succ (persuer, LIST_TYPE_TARGET); } } ////////////////////////////////////////////////////////////////// // // assign new engage tasks // // for each member, run through the task list (most important first) // try to assign one member per task, but as tasks run out group members can "team-up" // ////////////////////////////////////////////////////////////////// member = get_local_entity_first_child (group, LIST_TYPE_MEMBER); while ((member) && (valid_members)) { // // Only assign AI entities to ENGAGE tasks // if (get_local_entity_int_value (member, INT_TYPE_PLAYER) == ENTITY_PLAYER_AI) { if (get_local_entity_int_value (member, INT_TYPE_ENGAGE_ENEMY)) { member_number = (1 << get_local_entity_int_value (member, INT_TYPE_GROUP_MEMBER_NUMBER)); if (member_number & valid_members) { member_pos = get_local_entity_vec3d_ptr (member, VEC3D_TYPE_POSITION); if (get_local_entity_int_value (member, INT_TYPE_IDENTIFY_AIRCRAFT)) { criteria = BEST_WEAPON_CRITERIA_MINIMAL; } else { criteria = BEST_WEAPON_RANGE_CHECK | BEST_WEAPON_LOS_CHECK; } best_guide = -1; best_count = INT_MAX; for (loop = 0; loop < task_count; loop ++) { if (assigned_count [loop] < best_count) { guide = guide_list [loop]; task = get_local_entity_parent (guide, LIST_TYPE_GUIDE); target = get_local_entity_parent (task, LIST_TYPE_TASK_DEPENDENT); if (target == member) { // // Don't try to attack yourself ! // continue; } // // Range Check // if (criteria & BEST_WEAPON_RANGE_CHECK) { // range handled by weapon selection range = 0.0; } else { target_pos = get_local_entity_vec3d_ptr (target, VEC3D_TYPE_POSITION); range = get_sqr_2d_range (target_pos, member_pos); } if (range < MAX_ENGAGE_RANGE) { // // Weapon Check // if (get_best_weapon_for_target (member, target, criteria) != ENTITY_SUB_TYPE_WEAPON_NO_WEAPON) { best_count = assigned_count [loop]; best_guide = loop; } } } } if (best_guide != -1) { guide = guide_list [best_guide]; task = get_local_entity_parent (guide, LIST_TYPE_GUIDE); if (assign_new_task_to_group_member (group, member, task, NULL)) { valid_members &= (~member_number); assigned_count [best_guide] ++; #if DEBUG_MODULE debug_log ("ENGAGE: Assigning %s (%d) to target %s (%d)", get_local_entity_string (member, STRING_TYPE_FULL_NAME), get_local_entity_index (member), get_local_entity_string (target, STRING_TYPE_FULL_NAME), get_local_entity_index (target)); #endif } } else { #if DEBUG_MODULE debug_log ("ENGAGE: Couldn't assign %s (%d) to engage task", get_local_entity_string (member, STRING_TYPE_FULL_NAME), get_local_entity_index (member)); #endif } } } } member = get_local_entity_child_succ (member, LIST_TYPE_MEMBER); } free_mem (guide_list); free_mem (priority); free_mem (assigned_count); return valid_members; }
entity *regen_update (entity *en) { regen_management_element *m1; entity_sub_types member_type, group_type; entity *wp, *task, *group, *member, *building, *force_en, *landing, *keysite; unsigned int member_number; int reserve_count; force *force_raw; regen *raw; regen_list_element *e1; raw = (regen *) get_local_entity_data (en); wp = get_local_entity_parent (en, LIST_TYPE_CURRENT_WAYPOINT); task = get_local_entity_parent (wp, LIST_TYPE_WAYPOINT); landing = get_local_entity_parent (task, LIST_TYPE_UNASSIGNED_TASK); keysite = get_local_entity_parent (landing, LIST_TYPE_LANDING_SITE); force_en = get_local_force_entity ((entity_sides) raw->side); force_raw = (force *) get_local_entity_data (force_en); group_type = NUM_ENTITY_SUB_TYPE_GROUPS; m1 = ®en_manager [raw->side][raw->sub_type]; // // is there anything in the regen queues? // if (m1->count == 0) { return NULL; } // // Can regen operate // building = raw->member_root.first_child; if ((!get_local_entity_int_value (building, INT_TYPE_ALIVE)) || (get_local_entity_int_value (keysite, INT_TYPE_KEYSITE_USABLE_STATE) != KEYSITE_STATE_USABLE)) { #if DEBUG_MODULE debug_log ("RG_UPDT: keysite %s too damaged to regen", get_local_entity_string (keysite, STRING_TYPE_KEYSITE_NAME)); #endif return NULL; } e1 = ®en_queue [raw->side][raw->sub_type][m1->front]; ASSERT (e1->type != -1); ASSERT (e1->sub_type != -1); ASSERT (e1->group != -1); // is there a reserve of this type? if ((e1->type == ENTITY_TYPE_FIXED_WING) || (e1->type == ENTITY_TYPE_HELICOPTER)) { reserve_count = force_raw->force_info_reserve_hardware[aircraft_database[e1->sub_type].force_info_catagory]; } else { reserve_count = force_raw->force_info_reserve_hardware[vehicle_database[e1->sub_type].force_info_catagory]; } if (reserve_count <= 0) { return NULL; } #if DEBUG_MODULE debug_log ("RG_UPDT: Trying to Regen %s Sub Type %d at %s - reserve count %d", get_entity_type_name (e1->type), e1->sub_type, get_local_entity_string (keysite, STRING_TYPE_KEYSITE_NAME), reserve_count); #endif // // Don't regen if PLAYER landed there // group = get_local_entity_first_child (keysite, LIST_TYPE_KEYSITE_GROUP); while (group) { member = get_local_entity_first_child (group, LIST_TYPE_MEMBER); while (member) { if (get_local_entity_int_value (member, INT_TYPE_PLAYER) != ENTITY_PLAYER_AI) { if (get_local_entity_int_value (member, INT_TYPE_LANDED)) { #if DEBUG_MODULE debug_log ("RG_UPDT: PLAYER landed at keysite %s, can't regen", get_local_entity_string (keysite, STRING_TYPE_KEYSITE_NAME)); #endif return NULL; } } member = get_local_entity_child_succ (member, LIST_TYPE_MEMBER); } group = get_local_entity_child_succ (group, LIST_TYPE_KEYSITE_GROUP); } group_type = e1->group; member_type = e1->sub_type; //////////////////////////////////////////////////////////////////////////// // Dont regen people or transport aircraft in apache havoc campaign as airport might not be correct (landing routes etc) //////////////////////////////////////////////////////////////////////////// if (get_local_entity_int_value (get_session_entity (), INT_TYPE_CAMPAIGN_REQUIRES_APACHE_HAVOC)) { switch (get_local_entity_int_value (en, INT_TYPE_ENTITY_SUB_TYPE)) { case ENTITY_SUB_TYPE_REGEN_PEOPLE: { #if DEBUG_MODULE debug_log ("RG_UPDT: Stopping Regening People - wrong warzone"); #endif return NULL; } case ENTITY_SUB_TYPE_REGEN_FIXED_WING: { if (group_database [group_type].default_landing_type == ENTITY_SUB_TYPE_LANDING_FIXED_WING_TRANSPORT) { #if DEBUG_MODULE debug_log ("RG_UPDT: Stopping Regening Transport aircraft - wrong warzone"); #endif return NULL; } } } } //////////////////////////////////////////////////////////////////////////// // Dont regen people or transport aircraft in apache havoc campaign as airport might not be correct (landing routes etc) //////////////////////////////////////////////////////////////////////////// if (group_type != NUM_ENTITY_SUB_TYPE_GROUPS) { int route_node; entity *building, *member, *guide, *group = NULL; group = create_landing_faction_members (keysite, member_type, group_type, 1, wp, &raw->position); if (group) { // // Assign closest route_node (only needed for routed vehicles) // if (get_local_entity_int_value (group, INT_TYPE_FRONTLINE)) { route_node = get_closest_side_road_node ((entity_sides) get_local_entity_int_value (group, INT_TYPE_SIDE), &raw->position, 5 * KILOMETRE); set_client_server_entity_int_value (group, INT_TYPE_ROUTE_NODE, route_node); } // // // member = get_local_entity_first_child (group, LIST_TYPE_MEMBER); // // close members doors // close_client_server_entity_cargo_doors (member); close_client_server_entity_loading_doors (member); // // open building doors // building = get_local_entity_first_child (en, LIST_TYPE_MEMBER); open_client_server_entity_loading_doors (building); set_local_entity_float_value (building, FLOAT_TYPE_LOADING_DOOR_TIMER, 30.0); // // create guide entity for task (TEST) // // Debug for Transport aircraft. // Locate nearest Transport landing wp and insert into it if (group_database [group_type].default_landing_type == ENTITY_SUB_TYPE_LANDING_FIXED_WING_TRANSPORT) { float range, best_range; entity *transport_wp, *transport_task, *transport_landing; best_range = 999999999.0; transport_landing = get_local_entity_landing_entity (keysite, ENTITY_SUB_TYPE_LANDING_FIXED_WING_TRANSPORT); if (transport_landing) { transport_task = get_local_landing_entity_task (transport_landing, ENTITY_SUB_TYPE_TASK_LANDING); ASSERT (transport_task); transport_wp = get_local_entity_first_child (transport_task, LIST_TYPE_WAYPOINT); ASSERT (transport_wp); while (transport_wp) { range = get_sqr_2d_range (get_local_entity_vec3d_ptr (transport_wp, VEC3D_TYPE_POSITION), get_local_entity_vec3d_ptr (building, VEC3D_TYPE_POSITION)); if (range < best_range) { wp = transport_wp; task = transport_task; best_range = range; } transport_wp = get_local_entity_child_succ (transport_wp, LIST_TYPE_WAYPOINT); } } } // Debug for Transport aircraft. member_number = get_local_entity_int_value (member, INT_TYPE_GROUP_MEMBER_NUMBER); guide = create_client_server_guide_entity (task, wp, (1 << member_number)); attach_group_to_guide_entity (group, guide); attach_group_member_to_guide_entity (member, guide); //#if DEBUG_MODULE { entity *keysite; keysite = get_local_entity_parent (landing, LIST_TYPE_LANDING_SITE); member = get_local_entity_first_child (group, LIST_TYPE_MEMBER); debug_log ("RG_UPDT: %s creating %s (%d) at keysite %s free landing sites %d, reserved %d, lock %d, available lock: %d", entity_side_names [get_local_entity_int_value (keysite, INT_TYPE_SIDE)], get_local_entity_type_name (member), get_local_entity_index (member), get_local_entity_string (keysite, STRING_TYPE_KEYSITE_NAME), get_local_entity_int_value (landing, INT_TYPE_FREE_LANDING_SITES), get_local_entity_int_value (landing, INT_TYPE_RESERVED_LANDING_SITES), get_local_entity_int_value (landing, INT_TYPE_LANDING_LOCK), check_available_landing_route_lock (landing) ); if ((e1->type == ENTITY_TYPE_FIXED_WING) || (e1->type == ENTITY_TYPE_HELICOPTER)) { debug_log("%s reserves left: %d", force_info_catagory_names[aircraft_database[e1->sub_type].force_info_catagory], force_raw->force_info_reserve_hardware[aircraft_database[e1->sub_type].force_info_catagory] ); } else { debug_log("%s reserves left: %d", force_info_catagory_names[vehicle_database[e1->sub_type].force_info_catagory], force_raw->force_info_reserve_hardware[vehicle_database[e1->sub_type].force_info_catagory] ); } } //#endif #if DEBUG_MODULE switch (e1->type) { case ENTITY_TYPE_FIXED_WING: case ENTITY_TYPE_HELICOPTER: { ASSERT (regen_ac_debug[e1->sub_type] > 0); break; } case ENTITY_TYPE_ROUTED_VEHICLE: case ENTITY_TYPE_SHIP_VEHICLE: case ENTITY_TYPE_PERSON: { ASSERT (regen_vh_debug[e1->sub_type] > 0); break; } default: { debug_fatal ("RG_UPDT: Unknown entity type for debug"); } } #endif // update markers regen_queue_use ((entity_sides) raw->side, (raw->sub_type)); return member; } } else { #if DEBUG_MODULE >= 2 debug_log ("RG_UPDT: not creating anything at keysite %s free landing sites %d, reserved %d, lock %d", get_local_entity_string (keysite, STRING_TYPE_KEYSITE_NAME), get_local_entity_int_value (landing, INT_TYPE_FREE_LANDING_SITES), get_local_entity_int_value (landing, INT_TYPE_RESERVED_LANDING_SITES), check_available_landing_route_lock (landing)); #endif } return NULL; }