/* ACTOR_PERCEPTION.C symbols in this file: 0001D8C0 00d0: _actor_perception_acknowledge (0000) 0001D990 00f0: _actor_get_perception_knowledge (0000) 0001DA80 0140: _actor_get_vision_distances (0000) 0001DBC0 0040: _code_0001dbc0 (0000) 0001DC00 00f0: _code_0001dc00 (0000) 0001DCF0 0230: _actor_perception_desire_prop (0000) 0001DF20 00a0: _actor_perception_find_prop_pathfinding_location (0000) 0001DFC0 00c0: _actor_perception_find_killer_prop_index (0000) 0001E080 0010: _arctangent (0000) 0001E090 00f0: _actor_perception_find_recent_damaging_prop_index (0000) 0001E180 0050: _actor_perception_forget_recent_damage (0000) 0001E1D0 0060: _actor_perception_retreat_successful (0000) 0001E230 00f0: _actor_compute_prop_unopposable (0000) 0001E320 03a0: _actor_compute_prop_target_weight (0000) 0001E6C0 0200: _actor_situation_update_target_status (0000) 0001E8C0 0140: _actor_situation_combat_status_update (0000) 0001EA00 04f0: _actor_situation_update (0000) 0001EEF0 00f0: _actor_situation_try_new_target (0000) 0001EFE0 01b0: _actor_perception_friend_prop_is_attacking (0000) 0001F190 0190: _actor_perception_aiming_vector_test_blockage (0000) 0001F320 0150: _actor_emotion_flee_with_friends (0000) 0001F470 0080: _code_0001f470 (0000) 0001F4F0 0070: _code_0001f4f0 (0000) 0001F560 04f0: _code_0001f560 (0000) 0001FA50 00b0: _actor_berserk (0000) 0001FB00 0360: _actor_visibility_at_point (0000) 0001FE60 0240: _actor_audibility_at_point (0000) 000200A0 0170: _actor_perception_find_sense_position (0000) 00020210 01f0: _code_00020210 (0000) 00020400 0380: _prop_position_refresh (0000) 00020780 0210: _code_00020780 (0000) 00020990 05c0: _code_00020990 (0000) 00020F50 0180: _actor_expected_acknowledgement (0000) 000210D0 0090: _actor_perception_unreachable (0000) 00021160 0060: _actor_perception_tried_to_uncover (0000) 000211C0 0060: _actor_perception_tried_to_search (0000) 00021220 00a0: _actor_perception_abandoned_search (0000) 000212C0 0680: _actor_emotion_update (0000) 00021940 0110: _actor_perception_become_acknowledged (0000) 00021A50 0e60: _prop_status_refresh (0000) 000228B0 06d0: _code_000228b0 (0000) 00022F80 0310: _actor_perception_create_orphan_from_friend (0000) 00023290 0970: _code_00023290 (0000) 00023C00 1270: _actor_perception_update (0000) 00245AB8 0038: _global_combat_status_table (0000) _global_acknowledgement_speeds (0018) 00245AF0 0020: ??_C@_0CA@OIEKNKJL@prop?9?$DOorphan_prop_index?5?$DN?$DN?5NONE?$AA@ (0000) 00245B10 0018: ??_C@_0BI@EKGDDPPJ@prop_acknowledged?$CIprop?$CJ?$AA@ (0000) 00245B28 0027: ??_C@_0CH@HJCPLECH@prop?9?$DOowner_actor_index?5?$DN?$DN?5actor@ (0000) 00245B50 0025: ??_C@_0CF@BOOBPIOF@c?3?2halo?2SOURCE?2ai?2actor_percepti@ (0000) 00245B78 0004: __real@42100000 (0000) 00245B7C 0004: __real@43610000 (0000) 00245B80 0004: __real@44c80000 (0000) 00245B84 0022: ??_C@_0CC@ECCIDOIG@damaging_prop_index?5?$CB?$DN?50x0000000@ (0000) 00245BA8 0014: ??_C@_0BE@JCINMMJG@prop_orphaned?$CIprop?$CJ?$AA@ (0000) 00245BBC 0013: ??_C@_0BD@GACNHPJP@target_prop?9?$DOenemy?$AA@ (0000) 00245BD0 005f: ??_C@_0FP@LFCAOKBD@?$CIactor?9?$DOtarget?4target_type?5?$DO?$DN?50?$CJ@ (0000) 00245C30 003a: ??_C@_0DK@BNBOMGMC@?$CIactor_type?5?$DO?$DN?50?$CJ?5?$CG?$CG?5?$CIactor_type@ (0000) 00245C6C 0010: ??_C@_0BA@NODDFKHB@new_prop?9?$DOenemy?$AA@ (0000) 00245C80 004c: ??_C@_0EM@HGNPMJBO@prop_acknowledged?$CIfriend_prop?$CJ?5?$CG@ (0000) 00245CCC 0004: __real@bf4ccccd (0000) 00245CD0 0004: __real@3f9ae148 (0000) 00245CD4 0004: __real@3eb851ec (0000) 00245CD8 0004: __real@bf490fdb (0000) 00245CDC 0004: __real@3f060a92 (0000) 00245CE0 0004: __real@3e19999a (0000) 00245CE4 0004: __real@3fd55555 (0000) 00245CE8 0004: __real@40010204 (0000) 00245CEC 0004: __real@3ee66666 (0000) 00245CF0 0018: ??_C@_0BI@GICPJHMO@best_unit_index?5?$CB?$DN?5NONE?$AA@ (0000) 00245D08 0025: ??_C@_0CF@GHOKMPCH@actor?9?$DOmeta?4swarm_unit_index?5?$CB?$DN?5@ (0000) 00245D30 0021: ??_C@_0CB@MPKGJDOK@actor?9?$DOmeta?4swarm_unit_count?5?$DO?50@ (0000) 00245D54 003b: ??_C@_0DL@MCFLLIBG@?$CIexisting_unit_index?5?$DN?$DN?5NONE?$CJ?5?$HM?$HM@ (0000) 00245D90 0004: __real@40100000 (0000) 00245D94 0018: ??_C@_0BI@LJGDFJPJ@swarm_actor?9?$DOmeta?4swarm?$AA@ (0000) 00245DAC 0004: __real@3a91a2b4 (0000) 00245DB0 002f: ??_C@_0CP@MPBEBNC@object?9?$DOobject?4type?5?$DN?$DN?5_object_t@ (0000) 00245DE0 0004: __real@383a69dc (0000) 00245DE8 00c6: ??_C@_0MG@IKFAABEC@?$CIactor?9?$DOdanger_zone?4danger_type?5@ (0000) 00245EB0 0008: __real@3ff8000000000000 (0000) 00245EB8 0015: ??_C@_0BF@NEEODENG@?$CBprop_orphaned?$CIprop?$CJ?$AA@ (0000) 00245ED0 0008: __real@bfa7a8d000000000 (0000) 00245ED8 0004: __real@3f680347 (0000) 00245EDC 0004: __real@3f7e147b (0000) 00245EE0 0004: __real@bb5a740e (0000) 00245EE4 0004: __real@bc888889 (0000) 00245EE8 0004: __real@bd088889 (0000) 00245EEC 0004: __real@3c888889 (0000) 00245EF0 0004: __real@3b5a740e (0000) 00245EF4 0006: ??_C@_05KKADFBMH@?$CBdead?$AA@ (0000) 00245EFC 0038: ??_C@_0DI@GEDMEBOM@current_orphan?9?$DOparent_prop_inde@ (0000) 00245F34 0038: ??_C@_0DI@CJNILOBC@current_prop?9?$DOorphan_prop_index?5@ (0000) 00245F6C 0031: ??_C@_0DB@FLDFMNOK@current_orphan?9?$DOowner_actor_inde@ (0000) 00245FA0 002f: ??_C@_0CP@JODIIBNI@current_prop?9?$DOowner_actor_index?5@ (0000) 00245FD0 001e: ??_C@_0BO@PHJOMEBD@prop_orphaned?$CIcurrent_orphan?$CJ?$AA@ (0000) 00245FF0 0022: ??_C@_0CC@OGFEAFJH@prop_unacknowledged?$CIcurrent_prop@ (0000) 00246014 003c: ??_C@_0DM@LBOGCEIF@actor_perception_refresh?5overflo@ (0000) 00246050 0008: ??_C@_07BJLCCHPO@friends?$AA@ (0000) 00246058 0008: ??_C@_07OMOEAPJD@enemies?$AA@ (0000) 00246060 0004: __real@3f31c71c (0000) 00246064 000c: ??_C@_0M@JMHOJBDN@?$CBprop?9?$DOdead?$AA@ (0000) 00246070 0020: ??_C@_0CA@JNPJKEOJ@prop?9?$DOparent_prop_index?5?$CB?$DN?5NONE?$AA@ (0000) 00246090 0017: ??_C@_0BH@IAHDHPJP@new_state?$CB?$DNprop?9?$DOstate?$AA@ (0000) 002460A8 0012: ??_C@_0BC@COANDKJL@?$CFs?3?5become?5aware?$CB?$AA@ (0000) 002460C0 0041: ??_C@_0EB@HOGHONEE@?5?5awareness?5delta?3?5?$CF?42f?5?$CIcurrent@ (0000) 00246104 002b: ??_C@_0CL@DNKONGGM@?$CFs?3?5knowledge?5?$CFs?5percep?5?$CFs?5?9?$DO?5aw@ (0000) 00246130 000d: ??_C@_0N@OCHNCJBI@unmistakable?$AA@ (0000) 00246140 0005: ??_C@_04PLMLMMEO@full?$AA@ (0000) 00246148 0008: ??_C@_07JHIHCBKH@partial?$AA@ (0000) 00246150 0009: ??_C@_08GMLBJMKA@definite?$AA@ (0000) 0024615C 000a: ??_C@_09HJLAOOGF@searching?$AA@ (0000) 00246168 0008: ??_C@_07IFJEFPGA@instant?$AA@ (0000) 00246170 0006: ??_C@_05DAFACFLE@never?$AA@ (0000) 00246178 0051: ??_C@_0FB@GKMFLAFD@?$CIprop?9?$DOperception?5?$DO?$DN?50?$CJ?5?$CG?$CG?5?$CIprop@ (0000) 002461D0 004c: ??_C@_0EM@LBLHCEME@?$CIknowledge_type?5?$DO?$DN?50?$CJ?5?$CG?$CG?5?$CIknowle@ (0000) 0024621C 0018: ??_C@_0BI@PALENGAG@?$CFs?3?5stop?5becoming?5aware?$AA@ (0000) 00246234 001a: ??_C@_0BK@OHGMLFML@?$CFs?3?5start?5to?5become?5aware?$AA@ (0000) 00246250 0024: ??_C@_0CE@DMMCLDJG@?$CBrefresh_status?5?$HM?$HM?5refresh_posit@ (0000) 00246274 0031: ??_C@_0DB@OOOKPDMG@parent_prop?9?$DOorphan_prop_index?5?$DN@ (0000) 002462A8 002b: ??_C@_0CL@GMGBPAA@prop?9?$DOunopposable_casualties_inf@ (0000) 002B6AE0 0004: _data_002b6ae0 (0000) */ /* ---------- headers */ #include "cseries.h" #include "actor_definitions.h" #include "actors.h" #include "ai_debug.h" #include "ai_profile.h" #include "encounters.h" #include "game/game.h" #include "items/projectile_definitions.h" #include "items/weapon_definitions.h" #include "math/integer_math.h" #include "props.h" #include "scenario/scenario.h" #include "structures/structure_bsp_definitions.h" #include "units/bipeds.h" #include "units/units.h" #include "units/unit_definitions.h" #include "units/vehicle_definitions.h" #include "units/vehicles.h" #include "units/biped_definitions.h" /* ---------- constants */ enum { _actor_danger_zone_suicide = 1, _actor_danger_zone_projectile, _actor_danger_zone_vehicle = 3 }; /* ---------- macros */ /* * January's Actor Perception names these shared HCEX actor slots * differently. Keep the aliases typed through actor_datum rather than * overlaying the datum with an incompatible structure type. */ #define actor_perception_preferred_target_prop_index(actor) \ ((actor)->meta.interesting_orphan_index) #define actor_perception_target_weight_combat_status(actor) \ ((actor)->state.combat_status) #define actor_perception_audibility_combat_status(actor) \ ((actor)->state.mode) #define actor_perception_distance_squared2d(a, b, delta_x, delta_y) \ ((delta_x) = (b)->x - (a)->x, \ (delta_y) = (b)->y - (a)->y, \ (delta_x) * (delta_x) + (delta_y) * (delta_y)) /* ---------- structures */ union actor_perception_prop_actor_slot { long actor_index; struct { byte padding[3]; boolean too_far; }; }; struct actor_perception_swarm_component_view { short identifier; word flags; real_point3d position; byte __unknown010[SWARM_COMPONENT_DATUM_SIZE - 0x10]; }; struct actor_perception_ai_debug_state_view { byte __unknown000[6]; boolean perception_ignore_player_props; boolean perception_blind_player_props; byte __unknown008[3]; boolean perception_blind_all_props; boolean perception_deaf_all_props; byte __unknown00D[0x94]; boolean perception_trace_player_awareness; }; struct actor_perception_debug_info_view { byte __unknown0000[0x6578]; short perception_awareness_speed; short evaluation_mode; }; struct ai_profile_prop_counters { byte __unknown000[0x4C8]; short dead_acknowledged; byte __unknown4CA[0x86]; short dead_orphan; byte __unknown552[0x86]; short dead_unacknowledged; byte __unknown5DA[0x86]; short enemy_acknowledged; byte __unknown662[0x86]; short enemy_orphan; byte __unknown6EA[0x86]; short enemy_unacknowledged; byte __unknown772[0x86]; short friend_acknowledged; byte __unknown7FA[0x86]; short friend_orphan; byte __unknown882[0x86]; short friend_unacknowledged; byte __unknown90A[0x5D6]; }; struct ai_profile_globals { long __unknown0; boolean enabled; byte __unknown5[7]; union { byte map_data[0xEE0]; struct ai_profile_prop_counters perception; } data; }; #define swarm_component_get(index) \ ((struct actor_perception_swarm_component_view *)datum_get( \ swarm_component_data, (index))) #define actor_perception_ai_debug_get() \ ((struct actor_perception_ai_debug_state_view *)&ai_debug) #define actor_perception_debug_get(index) \ ((struct actor_perception_debug_info_view *)&actor_debug_array[(index)]) #define actor_perception_object_get(index) \ ((struct object_datum *)object_get_and_verify_type( \ (index), _object_mask_all)) /* * January actor/prop fields whose HCEX-derived shared structure positions do * not agree with this executable. Keep the executable-specific view local * until the complete January layouts are recovered. */ struct actor_danger_zone_view { short danger_type; short hostility; short acknowledgement_timer; boolean currently_perceived; boolean noticed_danger; boolean allow_dive_evasion; boolean communicated; boolean attached_to_us; byte __unknown00B; long object_index; long owner_unit_index; real danger_radius; real_point3d initial_position; real_vector3d initial_velocity; real_point3d position; real_vector3d velocity; real_point3d predict_danger_position; real current_distance_from_actor; real bounding_sphere_radius; real_point3d bounding_sphere_center; short predicted_impact_ticks; byte __unknown06A[2]; }; struct actor_perception_actor_view { byte __unknown000[4]; short type; boolean swarm; boolean frozen; boolean active; byte __unknown009[0xA]; boolean dormant; byte __unknown014[4]; long unit_index; byte __unknown01C[8]; long swarm_unit_index; long swarm_cache_index; byte __unknown02C[8]; long encounter_index; byte __unknown038[2]; short encounter_squad_index; short encounter_platoon_index; short team; byte __unknown040[0x14]; long preferred_target_prop_index; long definition_index; long variant_definition_index; byte __unknown060[0xA]; short combat_status; short friend_state; short artificial_combat_status; short suspicion_combat_status; short target_combat_status; short transient_combat_status; long transient_combat_status_time; long combat_status_timer; long certain_combat_status_timer; long combat_status_decay_timer; long uncertain_combat_status_timer; boolean combat_status_high; byte __unknown08D[0x1B]; short friend_fighting_count; byte __unknown0AA[0x9A]; long body_leaf_index; short body_cluster_index; byte __unknown14A[0xE]; long vehicle_index; boolean in_midair; boolean underwater; byte __unknown15E[3]; boolean flying; boolean long_orphan_inspection; byte __unknown163[0x69]; boolean corpse_interest_inhibited; byte __unknown1CD[7]; short danger_relationship_type; byte __unknown1D6[2]; union { long danger_relationship_handle; struct { byte __unknown1D8[2]; byte danger_relationship_variant; byte __unknown1DB; }; }; byte __unknown1DC[0x10]; char nearby_fighting_friend_count; boolean searching; byte __unknown1EE[0x14]; boolean vehicle_passenger; byte __unknown203[0x65]; union { short target_type; struct { short target_type; } target; }; byte __unknown26A[2]; long target_last_visible_time; long target_prop_index; byte __unknown274[8]; boolean target_outside_active_area; byte __unknown27D[3]; struct actor_danger_zone_view danger_zone; byte __unknown2EC[0x1C]; short active_threat_count; byte __unknown30A[0x40]; short pending_combat_status; long pending_combat_status_time; byte __unknown350[0x27]; boolean sighted_friendly_player; boolean berserk; byte __unknown379[0x27]; long corpse_ignore_time; byte __unknown3A4[4]; short unopposable_retreat_timer; byte __unknown3AA[2]; long unopposable_retreat_prop_index; }; struct actor_perception_prop_view { byte __unknown000[4]; long owner_actor_index; byte __unknown008[4]; long orphan_prop_index; short type; short team_index; boolean swarm; byte __unknown015[3]; long unit_index; long actor_index; real suicide_radius; short state; short timer; long swarm_unit_selected_time; real awareness; short perception_result; short visibility_result; short audibility_result; short ineffability_result; short line_of_sight_result; short orphan_lifespan_ticks; short orphan_inspection_ticks; byte __unknown03E[2]; real_vector3d orphan_hint_vector; short ticks_until_orphan; boolean orphan_corpse_cheated; byte __unknown04F; real target_weight; real look_interest; real last_idle_look_interest; long last_idle_look_time; boolean enemy; boolean ally; boolean ally_status_changed; boolean in_use; boolean refresh_stimuli; byte __unknown065; short perception; short perception_decay_ticks; short required_ticks; short ticks_since_damage; byte __unknown06E[2]; real damage_inflicted_on_me; boolean currently_damaging_me; byte __unknown075; short dead_ticks; short visible_ticks; byte __unknown07A[2]; long last_perceived_time; real_point3d last_perceived_body_position; long last_visible_time; real_point3d last_visible_head_position; short unreachable_ticks; byte __unknown09E[2]; long last_unreachable_time; boolean unopposable_enemy; byte __unknown0A5[1]; short unopposable_casualties_inflicted; short unopposable_casualty_decay_timer; short unopposable_trigger_hysteresis; short unopposable_trigger_timer; short unopposable_trigger_threshold; short ticks_since_definitely_located; byte __unknown0B2[2]; long definite_knowledge_source_actor; boolean definitely_located; boolean tried_to_uncover; boolean tried_to_search; boolean abandoned_search; real_point3d body_position; real_point3d center_of_mass; real_vector3d velocity; real_vector3d actor_to_prop; long pathfinding_surface_index; real_point3d pathfinding_point; struct location body_location; real_point3d head_position; long vehicle_index; long attached_to_unit_index; boolean underwater; byte __unknown119[3]; real distance; char lighting; char quantized_distance; char quantized_facing; char quantized_speed; char quantized_closing_speed; char child_units_attached; boolean delay_requirement_decision; boolean dead; boolean really_dead; boolean just_killed; boolean just_became_visible; boolean fighting; boolean in_combat; boolean noncombat; boolean player; boolean shooting; boolean flying; boolean active_camouflage; boolean flashlight; boolean ignore; boolean preferred_target; boolean vehicle_gunner; boolean dangerous_vehicle_driver; }; struct actor_perception_encounter_view { byte __unknown000[0x40]; boolean force_blind; boolean deaf; boolean blind; byte __unknown043[1]; boolean stand_down; boolean enemy_target; byte __unknown046[0xA]; long postcombat_timer; byte __unknown054[4]; long corpse_ignore_time; }; struct actor_perception_unit_view { byte __unknown000[0x3D0]; short parent_seat_index; }; struct actor_perception_target_unit_view { byte __unknown000[0xB6]; byte active_region_flags; }; struct actor_perception_status_unit_view { byte __unknown000[0x1B4]; unsigned long status_flags; }; struct actor_target_weight_weapon_definition_view { byte __unknown000[0x40C]; real minimum_target_range; }; struct actor_emotion_priority_counts_view { byte __unknown000[0x1EE]; char priority_counts[12]; }; struct actor_perception_projectile_datum_view { byte __unknown000[0x1DC]; byte attachment_flags; }; struct actor_perception_vehicle_definition_view { byte __unknown000[4]; real bounding_radius; byte __unknown008[0x2E8]; byte danger_zone_flags; }; struct actor_perception_projectile_view { byte __unknown000[0x1F0]; real time_remaining; real arming_rate; }; struct actor_perception_communication_context { short source_team; short destination_team; boolean enemy; }; struct actor_perception_responsible_unit_view { byte __unknown000[0x68]; short team; }; struct actor_situation_counts { char enemy_count; char enemy_very_close_count; char enemy_priority_counts[10]; char fighting_enemy_count; char priority_two_count; char priority_three_count; char priority_four_count; char priority_five_count; char priority_six_count; char priority_seven_count; char priority_eight_count; char close_friend_count; char close_active_friend_count; char close_active_dangerous_friend_count; char close_friend_type_counts[16]; char close_active_friend_type_counts[16]; char visible_friend_count; char visible_active_friend_count; char visible_friend_type_counts[16]; char visible_active_friend_type_counts[16]; char audible_friend_count; char audible_active_friend_count; char audible_friend_type_counts[16]; char audible_active_friend_type_counts[16]; }; struct actor_situation_actor_view { byte __unknown000[4]; short type; byte __unknown006[0x66]; short combat_status; byte __unknown06E[0x17E]; struct actor_situation_counts counts; byte __unknown267[1]; short target_type; byte __unknown26A[2]; long target_last_visible_time; long target_prop_index; byte __unknown274[0x104]; boolean berserk; }; struct actor_situation_prop_view { byte __unknown000[0x18]; long unit_index; byte __unknown01C[8]; short state; byte __unknown026[0xC]; short combat_status; byte __unknown034[4]; short perception; byte __unknown03A[0x16]; real target_weight; byte __unknown054[0xC]; boolean enemy; byte __unknown061[0x13]; boolean recent_damage; byte __unknown075[0x27]; short combat_status_detail; byte __unknown09E[0x7E]; real distance; byte __unknown120[2]; char visibility; byte __unknown123[4]; boolean dead; byte __unknown128[5]; boolean active; byte __unknown12E[1]; boolean friend_attack_result; byte __unknown130[5]; boolean dangerous_vehicle_driver; }; struct actor_situation_unit_view { byte __unknown000[0x1A4]; long actor_index; byte __unknown1A8[0x20]; long player_index; }; struct actor_orphan_prop_view { byte __unknown000[4]; long owner_actor_index; long next_prop_index; long related_prop_index; short type; short team_index; boolean swarm; byte __unknown015[3]; long unit_index; long actor_index; byte __unknown020[4]; short state; byte __unknown026[0x16]; short orphan_inspection_ticks; byte __unknown03E[0x12]; real target_weight; byte __unknown054[0x50]; boolean unopposable_enemy; byte __unknown0A5[0xB]; short ticks_since_definitely_located; byte __unknown0B2[2]; long definite_knowledge_source_actor; boolean definitely_located; }; struct actor_perception_refresh_entry { long unit_index; long prop_index; real priority; }; /* * code_00023290 maintains separate enemy and friend candidate lists on its * stack. Each list has two 16-bit counters followed by 128 12-byte entries. */ struct actor_perception_refresh_list { short accepted_count; short entry_count; struct actor_perception_refresh_entry entries[128]; }; struct actor_perception_refresh_locals { struct object_cluster_iterator cluster_iterator; short dead_ticks; byte __unknown00A[2]; real suicide_radius; struct actor_perception_actor_view *actor; short visible_ticks; byte __unknown016[2]; long unit_index; struct prop_iterator iterator; struct actor_perception_actor_view *current_actor; union { struct structure_bsp *structure_bsp; short target_count; } bsp_or_target; boolean in_use; byte __unknown02D[3]; boolean dead; byte __unknown031[3]; unsigned long *cluster_pvs; }; typedef char actor_perception_actor_view_target_prop_index_offset_assert[ offsetof(struct actor_perception_actor_view, target_prop_index) == 0x270 ? 1 : -1]; typedef char actor_perception_actor_view_team_offset_assert[ offsetof(struct actor_perception_actor_view, team) == 0x3E ? 1 : -1]; typedef char actor_perception_actor_view_definition_index_offset_assert[ offsetof(struct actor_perception_actor_view, definition_index) == 0x58 ? 1 : -1]; typedef char actor_perception_actor_view_preferred_prop_offset_assert[ offsetof(struct actor_perception_actor_view, preferred_target_prop_index) == 0x54 ? 1 : -1]; typedef char actor_perception_actor_view_variant_definition_offset_assert[ offsetof(struct actor_perception_actor_view, variant_definition_index) == 0x5C ? 1 : -1]; typedef char actor_perception_actor_view_underwater_offset_assert[ offsetof(struct actor_perception_actor_view, underwater) == 0x15D ? 1 : -1]; typedef char actor_perception_actor_view_berserk_offset_assert[ offsetof(struct actor_perception_actor_view, berserk) == 0x378 ? 1 : -1]; typedef char actor_perception_actor_view_orphan_inspection_offset_assert[ offsetof(struct actor_perception_actor_view, long_orphan_inspection) == 0x162 ? 1 : -1]; typedef char actor_perception_actor_view_sighted_friend_offset_assert[ offsetof(struct actor_perception_actor_view, sighted_friendly_player) == 0x377 ? 1 : -1]; typedef char actor_perception_actor_view_danger_zone_offset_assert[ offsetof(struct actor_perception_actor_view, danger_zone) == 0x280 ? 1 : -1]; typedef char actor_perception_actor_view_active_offset_assert[ offsetof(struct actor_perception_actor_view, active) == 0x8 ? 1 : -1]; typedef char actor_perception_actor_view_dormant_offset_assert[ offsetof(struct actor_perception_actor_view, dormant) == 0x13 ? 1 : -1]; typedef char actor_perception_actor_view_encounter_index_offset_assert[ offsetof(struct actor_perception_actor_view, encounter_index) == 0x34 ? 1 : -1]; typedef char actor_perception_actor_view_swarm_unit_index_offset_assert[ offsetof(struct actor_perception_actor_view, swarm_unit_index) == 0x24 ? 1 : -1]; typedef char actor_perception_actor_view_swarm_cache_index_offset_assert[ offsetof(struct actor_perception_actor_view, swarm_cache_index) == 0x28 ? 1 : -1]; typedef char actor_perception_actor_view_body_cluster_index_offset_assert[ offsetof(struct actor_perception_actor_view, body_cluster_index) == 0x148 ? 1 : -1]; typedef char actor_perception_actor_view_vehicle_index_offset_assert[ offsetof(struct actor_perception_actor_view, vehicle_index) == 0x158 ? 1 : -1]; typedef char actor_perception_actor_view_corpse_interest_inhibited_offset_assert[ offsetof(struct actor_perception_actor_view, corpse_interest_inhibited) == 0x1CC ? 1 : -1]; typedef char actor_perception_actor_view_corpse_ignore_time_offset_assert[ offsetof(struct actor_perception_actor_view, corpse_ignore_time) == 0x3A0 ? 1 : -1]; typedef char actor_perception_prop_view_unopposable_enemy_offset_assert[ offsetof(struct actor_perception_prop_view, unopposable_enemy) == 0xA4 ? 1 : -1]; typedef char actor_perception_actor_view_active_threat_count_offset_assert[ offsetof(struct actor_perception_actor_view, active_threat_count) == 0x308 ? 1 : -1]; typedef char actor_perception_actor_view_target_combat_status_offset_assert[ offsetof(struct actor_perception_actor_view, target_combat_status) == 0x72 ? 1 : -1]; typedef char actor_perception_actor_view_pending_combat_status_offset_assert[ offsetof(struct actor_perception_actor_view, pending_combat_status) == 0x34A ? 1 : -1]; typedef char actor_perception_actor_view_nearby_fighting_friend_count_offset_assert[ offsetof(struct actor_perception_actor_view, nearby_fighting_friend_count) == 0x1EC ? 1 : -1]; typedef char actor_perception_prop_view_in_combat_offset_assert[ offsetof(struct actor_perception_prop_view, in_combat) == 0x12C ? 1 : -1]; typedef char actor_perception_prop_swarm_offset_assert[ offsetof(struct prop_datum, swarm) == 0x14 ? 1 : -1]; typedef char actor_perception_prop_unit_index_offset_assert[ offsetof(struct prop_datum, unit_index) == 0x18 ? 1 : -1]; typedef char actor_perception_prop_actor_index_offset_assert[ offsetof(struct prop_datum, actor_index) == 0x1C ? 1 : -1]; typedef char actor_perception_prop_enemy_offset_assert[ offsetof(struct prop_datum, enemy) == 0x60 ? 1 : -1]; typedef char actor_perception_prop_body_position_offset_assert[ offsetof(struct prop_datum, body_position) == 0xBC ? 1 : -1]; typedef char actor_perception_prop_dead_offset_assert[ offsetof(struct prop_datum, dead) == 0x127 ? 1 : -1]; typedef char actor_perception_prop_view_vehicle_gunner_offset_assert[ offsetof(struct actor_perception_prop_view, vehicle_gunner) == 0x135 ? 1 : -1]; typedef char actor_perception_prop_view_player_offset_assert[ offsetof(struct actor_perception_prop_view, player) == 0x12E ? 1 : -1]; typedef char actor_perception_prop_view_perception_result_offset_assert[ offsetof(struct actor_perception_prop_view, perception_result) == 0x30 ? 1 : -1]; typedef char actor_perception_prop_view_dangerous_vehicle_driver_offset_assert[ offsetof(struct actor_perception_prop_view, dangerous_vehicle_driver) == 0x136 ? 1 : -1]; typedef char actor_perception_swarm_component_position_offset_assert[ offsetof(struct actor_perception_swarm_component_view, position) == 4 ? 1 : -1]; typedef char actor_perception_status_unit_flags_offset_assert[ offsetof(struct actor_perception_status_unit_view, status_flags) == 0x1B4 ? 1 : -1]; typedef char actor_perception_target_unit_active_region_offset_assert[ offsetof(struct actor_perception_target_unit_view, active_region_flags) == 0xB6 ? 1 : -1]; typedef char actor_target_weight_definition_melee_velocity_offset_assert[ offsetof(struct actor_definition, berserk.melee_leap_velocity) == 0x38C ? 1 : -1]; typedef char actor_target_weight_variant_melee_range_offset_assert[ offsetof(struct actor_variant_definition, ranged_combat.melee_range) == 0x160 ? 1 : -1]; typedef char actor_target_weight_variant_berserk_melee_range_offset_assert[ offsetof(struct actor_variant_definition, ranged_combat.berserk_melee_range) == 0x170 ? 1 : -1]; typedef char actor_target_weight_firing_maximum_range_offset_assert[ offsetof(struct actor_variant_definition, ranged_combat.maximum_firing_range) == 0x74 ? 1 : -1]; typedef char actor_target_weight_firing_combat_range_offset_assert[ offsetof(struct actor_variant_definition, ranged_combat.combat_range_upper_bound) == 0xA0 ? 1 : -1]; typedef char actor_target_weight_weapon_minimum_range_offset_assert[ offsetof(struct actor_target_weight_weapon_definition_view, minimum_target_range) == 0x40C ? 1 : -1]; typedef char actor_perception_preferred_target_prop_index_offset_assert[ offsetof(struct actor_datum, meta.interesting_orphan_index) == 0x54 ? 1 : -1]; typedef char actor_perception_audibility_combat_status_offset_assert[ offsetof(struct actor_datum, state.mode) == 0x6A ? 1 : -1]; typedef char actor_perception_target_weight_combat_status_offset_assert[ offsetof(struct actor_datum, state.combat_status) == 0x6E ? 1 : -1]; typedef char actor_emotion_actor_unit_offset_assert[ offsetof(struct actor_datum, meta.unit_index) == 0x18 ? 1 : -1]; typedef char actor_emotion_actor_definition_offset_assert[ offsetof(struct actor_datum, meta.definition_index) == 0x58 ? 1 : -1]; typedef char actor_emotion_actor_combat_status_offset_assert[ offsetof(struct actor_datum, state.combat_status) == 0x6E ? 1 : -1]; typedef char actor_emotion_actor_body_position_offset_assert[ offsetof(struct actor_datum, input.position.body_position) == 0x12C ? 1 : -1]; typedef char actor_emotion_actor_body_vitality_offset_assert[ offsetof(struct actor_datum, input.body_vitality) == 0x1B8 ? 1 : -1]; typedef char actor_emotion_actor_external_orders_offset_assert[ offsetof(struct actor_datum, external_orders) == 0x1C8 ? 1 : -1]; typedef char actor_emotion_actor_target_offset_assert[ offsetof(struct actor_datum, target.target_type) == 0x268 ? 1 : -1]; typedef char actor_emotion_actor_emotions_offset_assert[ offsetof(struct actor_datum, emotions) == 0x350 ? 1 : -1]; typedef char actor_emotion_actor_firing_position_offset_assert[ offsetof(struct actor_datum, firing_positions.current_position_index) == 0x3B8 ? 1 : -1]; typedef char actor_emotion_actor_control_moving_offset_assert[ offsetof(struct actor_datum, control.moving) == 0x504 ? 1 : -1]; typedef char actor_emotion_actor_control_vector_offset_assert[ offsetof(struct actor_datum, control.moving_towards_vector) == 0x518 ? 1 : -1]; typedef char actor_emotion_priority_counts_offset_assert[ offsetof(struct actor_emotion_priority_counts_view, priority_counts) == 0x1EE ? 1 : -1]; typedef char actor_emotion_definition_crouch_type_offset_assert[ offsetof(struct actor_definition, defensive.defensive_crouch_type) == 0x2F8 ? 1 : -1]; typedef char actor_emotion_definition_attacking_threshold_offset_assert[ offsetof(struct actor_definition, defensive.defensive_threshold_attacking) == 0x2FC ? 1 : -1]; typedef char actor_emotion_definition_defending_threshold_offset_assert[ offsetof(struct actor_definition, defensive.defensive_threshold_defending) == 0x300 ? 1 : -1]; typedef char actor_emotion_definition_minimum_stand_offset_assert[ offsetof(struct actor_definition, defensive.defensive_crouch_min_stand_time) == 0x304 ? 1 : -1]; typedef char actor_emotion_definition_minimum_crouch_offset_assert[ offsetof(struct actor_definition, defensive.defensive_crouch_min_crouch_time) == 0x308 ? 1 : -1]; typedef char actor_perception_ai_debug_ignore_players_offset_assert[ offsetof(struct actor_perception_ai_debug_state_view, perception_ignore_player_props) == 6 ? 1 : -1]; typedef char actor_perception_ai_debug_blind_players_offset_assert[ offsetof(struct actor_perception_ai_debug_state_view, perception_blind_player_props) == 7 ? 1 : -1]; typedef char actor_perception_ai_debug_blind_all_offset_assert[ offsetof(struct actor_perception_ai_debug_state_view, perception_blind_all_props) == 11 ? 1 : -1]; typedef char actor_perception_ai_debug_deaf_all_offset_assert[ offsetof(struct actor_perception_ai_debug_state_view, perception_deaf_all_props) == 12 ? 1 : -1]; typedef char actor_perception_ai_debug_trace_offset_assert[ offsetof(struct actor_perception_ai_debug_state_view, perception_trace_player_awareness) == 0xA1 ? 1 : -1]; typedef char actor_perception_debug_awareness_speed_offset_assert[ offsetof(struct actor_perception_debug_info_view, perception_awareness_speed) == 0x6578 ? 1 : -1]; typedef char actor_perception_projectile_attachment_flags_offset_assert[ offsetof(struct actor_perception_projectile_datum_view, attachment_flags) == 0x1DC ? 1 : -1]; typedef char actor_perception_source_unit_sound_offset_assert[ offsetof(struct unit_definition, unit.constant_sound) == 0x182 ? 1 : -1]; typedef char actor_perception_source_actor_target_offset_assert[ offsetof(struct actor_datum, target.target_type) == 0x268 ? 1 : -1]; typedef char actor_perception_source_actor_shooting_offset_assert[ offsetof(struct actor_datum, orders.combat.shoot_at_target) == 0x454 ? 1 : -1]; typedef char actor_perception_actor_weapon_range_offset_assert[ offsetof(struct actor_datum, control.weapon_maximum_range) == 0x608 ? 1 : -1]; typedef char actor_perception_definition_melee_range_offset_assert[ offsetof(struct actor_definition, berserk.melee_attack_range) == 0x37C ? 1 : -1]; typedef char actor_perception_profile_size_assert[ sizeof(struct ai_profile_globals) == 0xEEC ? 1 : -1]; typedef char actor_perception_profile_dead_acknowledged_offset_assert[ offsetof(struct ai_profile_globals, data.perception.dead_acknowledged) == 0x4D4 ? 1 : -1]; typedef char actor_perception_profile_dead_orphan_offset_assert[ offsetof(struct ai_profile_globals, data.perception.dead_orphan) == 0x55C ? 1 : -1]; typedef char actor_perception_profile_dead_unacknowledged_offset_assert[ offsetof(struct ai_profile_globals, data.perception.dead_unacknowledged) == 0x5E4 ? 1 : -1]; typedef char actor_perception_profile_enemy_acknowledged_offset_assert[ offsetof(struct ai_profile_globals, data.perception.enemy_acknowledged) == 0x66C ? 1 : -1]; typedef char actor_perception_profile_enemy_orphan_offset_assert[ offsetof(struct ai_profile_globals, data.perception.enemy_orphan) == 0x6F4 ? 1 : -1]; typedef char actor_perception_profile_enemy_unacknowledged_offset_assert[ offsetof(struct ai_profile_globals, data.perception.enemy_unacknowledged) == 0x77C ? 1 : -1]; typedef char actor_perception_profile_friend_acknowledged_offset_assert[ offsetof(struct ai_profile_globals, data.perception.friend_acknowledged) == 0x804 ? 1 : -1]; typedef char actor_perception_profile_friend_orphan_offset_assert[ offsetof(struct ai_profile_globals, data.perception.friend_orphan) == 0x88C ? 1 : -1]; typedef char actor_perception_profile_friend_unacknowledged_offset_assert[ offsetof(struct ai_profile_globals, data.perception.friend_unacknowledged) == 0x914 ? 1 : -1]; typedef char actor_perception_vehicle_definition_radius_offset_assert[ offsetof(struct actor_perception_vehicle_definition_view, bounding_radius) == 4 ? 1 : -1]; typedef char actor_perception_vehicle_definition_danger_zone_offset_assert[ offsetof(struct actor_perception_vehicle_definition_view, danger_zone_flags) == 0x2F0 ? 1 : -1]; typedef char actor_perception_responsible_unit_team_offset_assert[ offsetof(struct actor_perception_responsible_unit_view, team) == 0x68 ? 1 : -1]; typedef char actor_perception_encounter_view_blind_offset_assert[ offsetof(struct actor_perception_encounter_view, blind) == 0x42 ? 1 : -1]; typedef char actor_perception_encounter_view_stand_down_offset_assert[ offsetof(struct actor_perception_encounter_view, stand_down) == 0x44 ? 1 : -1]; typedef char actor_perception_encounter_view_enemy_target_offset_assert[ offsetof(struct actor_perception_encounter_view, enemy_target) == 0x45 ? 1 : -1]; typedef char actor_perception_encounter_view_postcombat_timer_offset_assert[ offsetof(struct actor_perception_encounter_view, postcombat_timer) == 0x50 ? 1 : -1]; typedef char actor_perception_encounter_view_corpse_ignore_time_offset_assert[ offsetof(struct actor_perception_encounter_view, corpse_ignore_time) == 0x58 ? 1 : -1]; typedef char actor_visibility_variant_modified_vision_range_offset_assert[ offsetof(struct actor_variant_definition, ranged_combat.modified_vision_range) == 0x150 ? 1 : -1]; typedef char actor_visibility_debug_info_size_assert[ sizeof(struct actor_debug_info) == 0x657C ? 1 : -1]; typedef char actor_visibility_debug_info_last_time_offset_assert[ offsetof(struct actor_debug_info, vision_last_time) == 0x656C ? 1 : -1]; typedef char actor_situation_counts_size_assert[ sizeof(struct actor_situation_counts) == 0x7B ? 1 : -1]; typedef char actor_situation_actor_view_counts_offset_assert[ offsetof(struct actor_situation_actor_view, counts) == 0x1EC ? 1 : -1]; typedef char actor_situation_actor_view_target_prop_index_offset_assert[ offsetof(struct actor_situation_actor_view, target_prop_index) == 0x270 ? 1 : -1]; typedef char actor_situation_actor_view_berserk_offset_assert[ offsetof(struct actor_situation_actor_view, berserk) == 0x378 ? 1 : -1]; typedef char actor_situation_prop_view_target_weight_offset_assert[ offsetof(struct actor_situation_prop_view, target_weight) == 0x50 ? 1 : -1]; typedef char actor_situation_prop_view_distance_offset_assert[ offsetof(struct actor_situation_prop_view, distance) == 0x11C ? 1 : -1]; typedef char actor_situation_unit_view_actor_index_offset_assert[ offsetof(struct actor_situation_unit_view, actor_index) == 0x1A4 ? 1 : -1]; typedef char actor_situation_unit_view_player_index_offset_assert[ offsetof(struct actor_situation_unit_view, player_index) == 0x1C8 ? 1 : -1]; typedef char actor_orphan_prop_view_related_prop_index_offset_assert[ offsetof(struct actor_orphan_prop_view, related_prop_index) == 0xC ? 1 : -1]; typedef char actor_orphan_prop_view_orphan_inspection_ticks_offset_assert[ offsetof(struct actor_orphan_prop_view, orphan_inspection_ticks) == 0x3C ? 1 : -1]; typedef char actor_orphan_prop_view_target_weight_offset_assert[ offsetof(struct actor_orphan_prop_view, target_weight) == 0x50 ? 1 : -1]; typedef char actor_orphan_prop_view_unopposable_enemy_offset_assert[ offsetof(struct actor_orphan_prop_view, unopposable_enemy) == 0xA4 ? 1 : -1]; typedef char actor_orphan_prop_view_definite_source_offset_assert[ offsetof(struct actor_orphan_prop_view, definite_knowledge_source_actor) == 0xB4 ? 1 : -1]; typedef char actor_orphan_prop_view_definitely_located_offset_assert[ offsetof(struct actor_orphan_prop_view, definitely_located) == 0xB8 ? 1 : -1]; typedef char actor_danger_zone_view_size_assert[ sizeof(struct actor_danger_zone_view) == 0x6C ? 1 : -1]; typedef char actor_danger_zone_view_object_index_offset_assert[ offsetof(struct actor_danger_zone_view, object_index) == 0xC ? 1 : -1]; typedef char actor_danger_zone_view_danger_radius_offset_assert[ offsetof(struct actor_danger_zone_view, danger_radius) == 0x14 ? 1 : -1]; typedef char actor_danger_zone_view_initial_position_offset_assert[ offsetof(struct actor_danger_zone_view, initial_position) == 0x18 ? 1 : -1]; typedef char actor_danger_zone_view_initial_velocity_offset_assert[ offsetof(struct actor_danger_zone_view, initial_velocity) == 0x24 ? 1 : -1]; typedef char actor_danger_zone_view_position_offset_assert[ offsetof(struct actor_danger_zone_view, position) == 0x30 ? 1 : -1]; typedef char actor_danger_zone_view_projected_position_offset_assert[ offsetof(struct actor_danger_zone_view, predict_danger_position) == 0x48 ? 1 : -1]; typedef char actor_danger_zone_view_distance_offset_assert[ offsetof(struct actor_danger_zone_view, current_distance_from_actor) == 0x54 ? 1 : -1]; typedef char actor_danger_zone_view_midpoint_offset_assert[ offsetof(struct actor_danger_zone_view, bounding_sphere_center) == 0x5C ? 1 : -1]; typedef char actor_danger_zone_view_impact_ticks_offset_assert[ offsetof(struct actor_danger_zone_view, predicted_impact_ticks) == 0x68 ? 1 : -1]; typedef char actor_perception_refresh_entry_size_assert[ sizeof(struct actor_perception_refresh_entry) == 0xC ? 1 : -1]; typedef char actor_perception_refresh_list_entries_offset_assert[ offsetof(struct actor_perception_refresh_list, entries) == 4 ? 1 : -1]; typedef char actor_perception_refresh_list_size_assert[ sizeof(struct actor_perception_refresh_list) == 0x604 ? 1 : -1]; /* * Runtime perception values in the January actor definition. The shared * HCEX-derived definition still labels two of these slots as unused. */ struct actor_perception_definition_view { unsigned long flags; byte __unknown004[0x18]; real maximum_vision_angle; real central_vision_angle; byte __unknown024[4]; real peripheral_distance; real maximum_peripheral_distance; }; /* ---------- prototypes */ long code_0001dbc0( void const *a, void const *b); void actor_situation_update_target_status( long actor_index); void actor_situation_combat_status_update( long actor_index); short actor_action_class( long actor_index); real actor_compute_prop_target_weight( long actor_index, long prop_index); boolean actor_compute_prop_unopposable( long actor_index, long prop_index); void actor_stimulus_prop_acknowledged( long actor_index, long prop_index, long stimulus, boolean initial_acknowledgement); long ai_get_responsible_unit( long object_index, boolean include_self); long vehicle_find_pathfinding_surface_index( long vehicle_index, real_point3d *position); long biped_find_pathfinding_surface_index( long biped_index, real_point3d *position); boolean actor_attacking_target( long actor_index, real_vector3d *attack_vector); void ai_communication_event( short type, long unit_index, long prop_index, long object_index, long position_index, long structure_index, void const *context); void actor_discard_firing_position( long actor_index, short firing_position_index, boolean temporary); boolean actor_type_flood_desire_shamble( long actor_index); void actor_stimulus_noticed_danger_zone( long actor_index, short danger_type, short hostility, long object_index, real_point3d const *position); void actor_stimulus_prop_just_killed( long actor_index, long prop_index); void actor_stimulus_prop_sighted( long actor_index, long prop_index, boolean initial_acknowledgement); void actor_stimulus_enter_combat_found_body( long actor_index, long prop_index); void actor_stimulus_enter_combat_perceived_enemy( long actor_index, long prop_index); static long code_00020210( long swarm_actor_index, long actor_index, long existing_unit_index, boolean mark, struct actor_position_data const *position); static boolean code_00020780( long actor_index, long vehicle_index, boolean mark, struct actor_position_data const *position); void code_00023290( long actor_index); void code_000228b0( long actor_index, long object_index, struct actor_perception_refresh_list *friend_list, struct actor_perception_refresh_list *enemy_list); struct actor_variant_definition *actor_combat_get_firing_variant_definition( long actor_index); void *actor_get_weapon_definition( long actor_index); void actor_input_sample_position( long actor_index, long unit_index, struct actor_position_data *position); boolean vehicle_causes_collision_damage( long vehicle_index); boolean game_team_is_enemy( short team_index0, short team_index1); boolean actor_expected_acknowledgement( long actor_index, long prop_index); short ai_test_line_of_sight( struct actor_position_data const *position, short source_cluster_index, real_point3d const *target_position, short target_cluster_index, short mode, boolean ignore_blockers, long vehicle_index, boolean actor_in_vehicle); short actor_visibility_at_point( long actor_index, struct actor_position_data const *position, real_point3d const *target_position, char lighting, short line_of_sight, boolean use_maximum_distance, boolean target_is_player, short perception_knowledge); short actor_audibility_at_point( long actor_index, struct actor_position_data const *position, real_point3d const *source_position, struct location const *source_location, short source_type, real scale, short line_of_sight); static boolean code_0001dc00( long actor_index, long object_index, real suicide_radius, real distance, boolean enemy, boolean visible); real actor_look_compute_prop_interest( long actor_index, long prop_index); static __inline boolean prop_acknowledged( struct prop_datum const *prop) { return prop->state >= _prop_state_becoming_unacknowledged && prop->state <= _prop_state_acknowledged; } static __inline void actor_perception_midpoint3d( real_point3d const *p0, real_point3d const *p1, real_point3d *result) { result->x = (p0->x + p1->x) * 0.5f; result->y = (p0->y + p1->y) * 0.5f; result->z = (p0->z + p1->z) * 0.5f; return; } /* ---------- globals */ extern struct ai_profile_globals ai_profile; short const global_combat_status_table[NUMBER_OF_ACTOR_TARGET_TYPES] = { 0, 0, 0, 1, 2, 2, 3, 4, 5, 5, 7, 7 }; short const global_acknowledgement_speeds[4][4] = { { 0, 0, 1, 3 }, { 0, 1, 2, 3 }, { 0, 2, 3, 4 }, { 0, 3, 4, 4 } }; long data_002b6ae0 = NONE; /* ---------- public code */ boolean actor_perception_desire_prop( long actor_index, short prop_type, long unit_index, union actor_perception_prop_actor_slot prop_actor, boolean in_use, boolean player, boolean enemy, boolean dead, short dead_ticks, real suicide_radius, real distance_squared, short required_ticks, boolean *too_far_reference) { struct actor_perception_actor_view *actor = (struct actor_perception_actor_view *)actor_get(actor_index); struct actor_perception_actor_view *related_actor; boolean desire = dead; if (prop_actor.actor_index == NONE) related_actor = NULL; else related_actor = (struct actor_perception_actor_view *)actor_get( prop_actor.actor_index); prop_actor.too_far = FALSE; if ((!enemy || dead) && prop_type >= 4 && prop_type <= 5) { desire = FALSE; } else if (player) { desire = TRUE; } else if (related_actor && (!related_actor->active || related_actor->dormant)) { desire = FALSE; } else if (prop_type == NONE && (in_use || required_ticks > 0)) { desire = TRUE; } else if (distance_squared > 1600.0f) { desire = FALSE; } else if (dead) { desire = TRUE; if (actor->encounter_index != NONE) { struct actor_perception_encounter_view *encounter = (struct actor_perception_encounter_view *) encounter_get(actor->encounter_index); struct unit_datum *unit = unit_get(unit_index); long ignore_time = encounter->corpse_ignore_time; boolean inactive_encounter; if (ignore_time <= actor->corpse_ignore_time) ignore_time = actor->corpse_ignore_time; if (ignore_time != NONE && (unit->unit.time_of_death == NONE || unit->unit.time_of_death < ignore_time)) { desire = FALSE; } inactive_encounter = !encounter->enemy_target && !encounter->stand_down && !encounter->blind; if (!desire) goto done; if (inactive_encounter) { if (distance_squared < 225.0f) { desire = TRUE; goto done; } desire = FALSE; goto done; } } if (suicide_radius > 0.0f) { desire = TRUE; } else if (enemy && dead_ticks > 150) { desire = FALSE; } else if (actor_action_class(actor_index) > 1) { desire = FALSE; } else { real maximum_distance_squared = 16.0f; if (!enemy && actor->combat_status < 3) maximum_distance_squared = 64.0f; desire = distance_squared < maximum_distance_squared; } } else { if (enemy) { desire = TRUE; prop_actor.too_far = distance_squared > 36.0f; } else { desire = distance_squared < 225.0f; if (actor->artificial_combat_status >= 4) prop_actor.too_far = TRUE; else if (actor->corpse_interest_inhibited) prop_actor.too_far = FALSE; else prop_actor.too_far = distance_squared > 16.0f; } } done: if (too_far_reference) *too_far_reference = prop_actor.too_far; return desire; } void actor_perception_acknowledge( long actor_index, long prop_index, long stimulus, boolean initial_acknowledgement) { struct prop_datum *prop = prop_get(prop_index); #line 1037 "c:\\halo\\SOURCE\\ai\\actor_perception.c" assert(prop->owner_actor_index == actor_index); assert(prop_acknowledged(prop)); #line 1039 "c:\\halo\\SOURCE\\ai\\actor_perception.c" vassert(prop->orphan_prop_index == NONE, "prop->orphan_prop_index == NONE"); #line 300 "source\\ai\\actor_perception.c" prop->tried_to_search = FALSE; prop->tried_to_uncover = FALSE; prop->abandoned_search = FALSE; prop->refresh_stimuli = TRUE; actor_stimulus_prop_acknowledged( actor_index, prop_index, stimulus, initial_acknowledgement); return; } long actor_get_perception_knowledge( long actor_index, long prop_index) { struct actor_perception_actor_view *actor = (struct actor_perception_actor_view *)actor_get(actor_index); if (prop_index != NONE) { struct actor_perception_prop_view *prop = (struct actor_perception_prop_view *)prop_get(prop_index); #line 1394 "c:\\halo\\SOURCE\\ai\\actor_perception.c" assert(prop->owner_actor_index == actor_index); #line 390 "source\\ai\\actor_perception.c" if (prop->state >= 2 && prop->state <= 3) return 3; if (prop->perception == 1 || prop->perception == 2) return 3; if (!prop->enemy && (!prop->dead || actor->combat_status >= 3)) { return 3; } if (prop->orphan_prop_index != NONE) { struct actor_perception_prop_view *orphan = (struct actor_perception_prop_view *)prop_get( prop->orphan_prop_index); long result = (orphan->definitely_located != FALSE) + 2; if ((short)result != NONE) return result; } } if (actor->artificial_combat_status >= 2) return 2; return actor->combat_status >= 3; } void actor_get_vision_distances( long actor_index, real maximum_vision_distance, real perception_factor, real horizontal_angle, real *full_distance_reference, real *partial_distance_reference) { struct actor_datum *actor = actor_get(actor_index); struct actor_perception_definition_view const *definition = (struct actor_perception_definition_view const *) actor_definition_get(actor->meta.definition_index); real full_distance; real partial_distance; if (horizontal_angle > definition->peripheral_distance) { partial_distance = 0.0f; full_distance = 0.0f; } else { real maximum_distance = maximum_vision_distance * perception_factor; real peripheral_distance = perception_factor * definition->maximum_peripheral_distance; real minimum_full_distance = 0.7f * maximum_distance; real minimum_partial_distance = 0.7f * peripheral_distance; if (minimum_partial_distance > 3.5f) minimum_partial_distance = 3.5f; if (horizontal_angle > definition->central_vision_angle) { partial_distance = peripheral_distance; full_distance = minimum_partial_distance; } else { real maximum_vision_angle = definition->maximum_vision_angle; real full_vision_angle = 0.8f * maximum_vision_angle; if (horizontal_angle < maximum_vision_angle) { partial_distance = maximum_distance; } else { real interpolation = (horizontal_angle - maximum_vision_angle) / (definition->central_vision_angle - maximum_vision_angle); partial_distance = (1.0f - interpolation) * maximum_distance + peripheral_distance * interpolation; } if (horizontal_angle < full_vision_angle) { full_distance = minimum_full_distance; } else { real interpolation = (horizontal_angle - full_vision_angle) / (definition->central_vision_angle - full_vision_angle); full_distance = (1.0f - interpolation) * minimum_full_distance + minimum_partial_distance * interpolation; } } } *partial_distance_reference = partial_distance; *full_distance_reference = full_distance; return; } void actor_situation_update_target_status( long actor_index) { struct actor_perception_actor_view *actor = (struct actor_perception_actor_view *)actor_get(actor_index); if (actor->target_prop_index == NONE) { actor->target_type = 0; actor->target_last_visible_time = NONE; actor->target_outside_active_area = FALSE; } else { struct actor_perception_prop_view *target_prop = (struct actor_perception_prop_view *)prop_get( actor->target_prop_index); struct actor_perception_target_unit_view *target_unit = (struct actor_perception_target_unit_view *) unit_get(target_prop->unit_index); short target_type; #line 4291 "c:\\halo\\SOURCE\\ai\\actor_perception.c" assert(target_prop->enemy); #line 510 "source\\ai\\actor_perception.c" switch (target_prop->state) { case _prop_state_unacknowledged: target_type = 0; actor->target_prop_index = NONE; actor->target_last_visible_time = NONE; break; case _prop_state_becoming_acknowledged: target_type = 1; break; case _prop_state_becoming_unacknowledged: case _prop_state_acknowledged: if (target_prop->dead) target_type = 2; else if (target_prop->currently_damaging_me) target_type = 11; else if (target_prop->visibility_result >= 2) target_type = 10; else if (target_prop->line_of_sight_result != 0 && target_prop->line_of_sight_result != 1) { target_type = 7; } else if (target_prop->quantized_facing <= 2 && target_prop->distance < 6.f) { target_type = 9; } else { target_type = 8; } break; case _prop_state_inspected_orphan: if (target_prop->dead) target_type = 2; else target_type = target_prop->abandoned_search ? 3 : 4; break; case _prop_state_uninspected_orphan: target_type = (target_prop->definitely_located != FALSE) + 5; break; default: display_assert( NULL, "c:\\halo\\SOURCE\\ai\\actor_perception.c", 4362, TRUE); system_exit(-1); break; } actor->target_type = target_type; if (target_prop->state >= _prop_state_becoming_unacknowledged && target_prop->state <= _prop_state_acknowledged) { actor->target_outside_active_area = !target_prop->dead; if (target_prop->visibility_result > 0) actor->target_last_visible_time = target_prop->last_visible_time; } else { actor->target_outside_active_area = !TEST_FLAG( target_unit->active_region_flags, 2); } } return; } real actor_compute_prop_target_weight( long actor_index, long prop_index) { struct actor_datum *actor = actor_get(actor_index); struct prop_datum *prop = prop_get(prop_index); struct actor_definition *actor_definition; struct actor_variant_definition *variant_definition; struct actor_variant_definition *firing_variant; struct actor_target_weight_weapon_definition_view *weapon_definition; short range_weight; short knowledge_weight = 0; struct { long target_weight; long preferred_weight; real bonus_weight; } weights; if (prop->ignore || !prop->enemy || (prop->state >= 0 && prop->state <= 1) || (prop->dead && prop->dead_ticks >= 150) || prop->type == 15) { return 0.0f; } actor_definition = actor_definition_get(actor->meta.definition_index); variant_definition = actor_variant_definition_get(actor->meta.variant_definition_index); weights.target_weight = 0; weights.preferred_weight = 0; weights.bonus_weight = 0.0f; if (actor->meta.swarm) { range_weight = 0; goto range_weight_done; } if (prop->unreachable_ticks > 0) { range_weight = 0; goto range_weight_done; } if (!actor_has_ranged_weapon(actor_index)) { real maximum_range; if (actor->emotions.berserk) maximum_range = variant_definition->ranged_combat.melee_range; else maximum_range = variant_definition->ranged_combat.berserk_melee_range; if (prop->distance < 2.0f) { range_weight = 5; if (prop->state != _prop_state_inspected_orphan) goto range_weight_done; } if (prop->vehicle_index != NONE) range_weight = 0; else if (prop->flying && actor_definition->berserk.melee_leap_velocity == 0.0f) range_weight = 0; else if (prop->underwater != actor->input.underwater) range_weight = 1; else if (prop->distance < maximum_range) range_weight = 3; else goto ranged_weapon_range_two; } else { weapon_definition = (struct actor_target_weight_weapon_definition_view *) actor_get_weapon_definition(actor_index); firing_variant = actor_combat_get_firing_variant_definition(actor_index); if (weapon_definition != NULL && prop->distance < weapon_definition->minimum_target_range) { ranged_weapon_range_two: range_weight = 2; goto range_weight_done; } if (prop->underwater != actor->input.underwater) { range_weight = 2; goto range_weight_done; } if (prop->distance < 2.0f) { range_weight = 5; if (prop->state != _prop_state_inspected_orphan) goto range_weight_done; } if (prop->distance < firing_variant->ranged_combat.combat_range_upper_bound) range_weight = 3; else if (prop->distance < firing_variant->ranged_combat.maximum_firing_range) range_weight = 2; else range_weight = 1; } range_weight_done: if (prop->dead) knowledge_weight = 1; else { if (!actor->meta.swarm && prop->currently_damaging_me && prop->unreachable_ticks == 0) { knowledge_weight = 6; } else if (prop->state >= 2 && prop->state <= 3) { if (actor->meta.swarm) knowledge_weight = 4; else if (prop->unreachable_ticks > 0) { knowledge_weight = 3; } else if (prop->line_of_sight != 0 && prop->line_of_sight != 1) { knowledge_weight = 3; } /* Preserve January's quantized-facing read at +0x122. */ else if (prop->shooting && prop->quantized_facing <= 1) { knowledge_weight = 5; } else knowledge_weight = 4; } else { if (prop->state < _prop_state_uninspected_orphan || prop->state > _prop_state_inspected_orphan) { display_assert( "prop_orphaned(prop)", "c:\\halo\\SOURCE\\ai\\actor_perception.c", 4230, TRUE); system_exit(-1); } if (prop->definitely_located) knowledge_weight = 3; else knowledge_weight = (prop->state == _prop_state_uninspected_orphan) + 1; } } if (actor->target.target_prop_index == NONE) { if (prop->player || prop_index == actor_perception_preferred_target_prop_index(actor)) { weights.bonus_weight = 3.0f; } } else if (prop_index == actor->target.target_prop_index && actor_perception_target_weight_combat_status(actor) >= 3) { weights.target_weight = 1; } if (prop->preferred_target) weights.preferred_weight = 2; weights.target_weight = ((short)weights.target_weight + (short)weights.preferred_weight) + (knowledge_weight + range_weight); /* Preserve January's swapped target/distance scale constants. */ return weights.target_weight * 10.0f + (5.0f / (prop->distance * 0.1f + 1.0f) + weights.bonus_weight); } struct actor_emotion_priority_prop_view { byte __unknown000[0x24]; short state; byte __unknown026[0xC]; short combat_status; byte __unknown034[0x40]; boolean recent_damage; byte __unknown075[0x2F]; boolean unopposable; byte __unknown0A5[0x7D]; char visibility; byte __unknown123[0xC]; boolean friend_attacking; }; typedef char actor_emotion_priority_prop_state_offset_assert[ offsetof(struct actor_emotion_priority_prop_view, state) == 0x24 ? 1 : -1]; typedef char actor_emotion_priority_prop_combat_status_offset_assert[ offsetof(struct actor_emotion_priority_prop_view, combat_status) == 0x32 ? 1 : -1]; typedef char actor_emotion_priority_prop_recent_damage_offset_assert[ offsetof(struct actor_emotion_priority_prop_view, recent_damage) == 0x74 ? 1 : -1]; typedef char actor_emotion_priority_prop_unopposable_offset_assert[ offsetof(struct actor_emotion_priority_prop_view, unopposable) == 0xA4 ? 1 : -1]; typedef char actor_emotion_priority_prop_visibility_offset_assert[ offsetof(struct actor_emotion_priority_prop_view, visibility) == 0x122 ? 1 : -1]; typedef char actor_emotion_priority_prop_friend_attacking_offset_assert[ offsetof(struct actor_emotion_priority_prop_view, friend_attacking) == 0x12F ? 1 : -1]; static long code_0001f4f0( long prop_index) { struct actor_emotion_priority_prop_view *prop; long priority; prop = (struct actor_emotion_priority_prop_view *)prop_get(prop_index); priority = 0; if (prop->state >= _prop_state_becoming_unacknowledged && prop->state <= _prop_state_acknowledged && prop->unopposable) { if (prop->recent_damage) { priority = 4; } else if (prop->friend_attacking) { priority = (prop->visibility <= 1) + 2; } else if (prop->combat_status >= 2) { priority = 1; } } return priority; } struct actor_emotion_prop_view; struct actor_emotion_target { short priority; short pad; long prop_index; long unit_index; struct actor_emotion_prop_view *prop; short count; short pad2; real minimum_distance_squared; long closest_unit_index; }; struct actor_emotion_actor_view { byte __unknown000[0x58]; long definition_index; byte __unknown05C[0x348]; long last_emotion_target_time; short emotion_target_ticks; byte __unknown3AA[2]; long emotion_target_prop_index; long emotion_target_time; }; struct actor_emotion_definition_view { byte __unknown000[0x268]; short normal_threshold; short vehicle_threshold; short player_threshold; byte __unknown26E[2]; real trigger_delay_lower; real trigger_delay_upper; short casualty_threshold; short friend_threshold; byte __unknown27C[0xC]; real target_duration_lower; real target_duration_upper; }; struct actor_emotion_prop_view { byte __unknown000[0x18]; long unit_index; long actor_index; byte __unknown020[4]; short state; byte __unknown026[0xC]; short combat_status; byte __unknown034[0x2C]; boolean enemy; byte __unknown061[0x13]; boolean recent_damage; byte __unknown075[3]; short dead_ticks; byte __unknown07A[0x2A]; boolean unopposable; byte __unknown0A5; short unopposable_casualties; short unopposable_casualty_decay_timer; short emotion_trigger_ticks; short emotion_trigger_age; short emotion_trigger_threshold; byte __unknown0B0[0x6C]; real distance; byte __unknown120[2]; char visibility; byte __unknown123[0xB]; boolean player; boolean friend_attacking; byte __unknown130[5]; boolean vehicle_gunner; boolean dangerous_vehicle_driver; }; typedef char actor_emotion_target_size_assert[ sizeof(struct actor_emotion_target) == 0x1C ? 1 : -1]; typedef char actor_emotion_actor_last_time_offset_assert[ offsetof(struct actor_emotion_actor_view, last_emotion_target_time) == 0x3A4 ? 1 : -1]; typedef char actor_emotion_actor_ticks_offset_assert[ offsetof(struct actor_emotion_actor_view, emotion_target_ticks) == 0x3A8 ? 1 : -1]; typedef char actor_emotion_actor_prop_offset_assert[ offsetof(struct actor_emotion_actor_view, emotion_target_prop_index) == 0x3AC ? 1 : -1]; typedef char actor_emotion_prop_distance_offset_assert[ offsetof(struct actor_emotion_prop_view, distance) == 0x11C ? 1 : -1]; typedef char actor_emotion_prop_driver_offset_assert[ offsetof(struct actor_emotion_prop_view, dangerous_vehicle_driver) == 0x136 ? 1 : -1]; static short code_0001f470( struct actor_emotion_target *targets, long unit_index, long actor_index, short *target_count, short maximum_target_count) { short count; short target_index = NONE; short index; count = *target_count; for (index = 0; index < count; index++) { if (targets[index].unit_index == unit_index) { target_index = index; break; } } if (target_index == NONE && count < maximum_target_count) { *target_count = count + 1; targets[count].priority = 0; targets[count].prop_index = NONE; targets[count].unit_index = NONE; targets[count].prop = NULL; targets[count].count = 0; targets[count].minimum_distance_squared = FLT_MAX; targets[count].closest_unit_index = NONE; target_index = count; } return target_index; } short actor_visibility_at_point( long actor_index, struct actor_position_data const *position, real_point3d const *target_position, char lighting, short line_of_sight, boolean use_maximum_distance, boolean target_is_player, short perception_knowledge) { long result = 0; if (line_of_sight == 0 || line_of_sight == 1) { struct actor_datum *actor = actor_get(actor_index); struct actor_definition *definition = actor_definition_get(actor->meta.definition_index); struct actor_variant_definition *firing_variant = actor_combat_get_firing_variant_definition(actor_index); real maximum_distance = definition->perception.maximum_vision_distance; real_vector3d direction; real distance_squared; real full_distance; real partial_distance; if (firing_variant->ranged_combat.modified_vision_range > 0.0f) { maximum_distance = firing_variant->ranged_combat.modified_vision_range; } { real knowledge_factor = 1.0f; switch (perception_knowledge) { case 0: knowledge_factor = 0.4f; break; case 1: knowledge_factor = 0.6f; break; case 2: knowledge_factor = 0.8f; break; case 3: knowledge_factor = 1.0f; break; default: display_assert( "!\"unreachable\"", "c:\\halo\\SOURCE\\ai\\actor_perception.c", 1268, TRUE); system_exit(-1); break; } maximum_distance *= knowledge_factor; } { vector_from_points3d( &position->head_position, target_position, &direction); distance_squared = magnitude_squared3d(&direction); if (distance_squared < maximum_distance * maximum_distance) { real perception_factor = 1.0f; if (!TEST_FLAG(definition->flags, 0)) { switch (lighting) { case 0: perception_factor = 0.3f; break; case 1: perception_factor = 0.7f; break; } } { real fog = scenario_fog_at_point( &position->body_location, &position->head_position, target_position); if (fog > 0.8f) { perception_factor = 0.15f; } else { if (fog > 0.2f) { perception_factor = (0.8f - fog) * perception_factor * 1.6666666f; } if (perception_factor > 0.15f) goto perception_factor_ready; perception_factor = 0.15f; } } perception_factor_ready: { struct actor_debug_info *debug = &actor_debug_array[ DATUM_INDEX_TO_ABSOLUTE_INDEX(actor_index)]; if (target_is_player) { debug->vision_last_time = game_time_get(); debug->vision_last_maximum_distance = maximum_distance; debug->vision_last_perception_factor = perception_factor; } } { real visible_distance = perception_factor * maximum_distance; real visible_distance_i = visible_distance; real visible_distance_j = visible_distance; if (distance_squared < visible_distance_i * visible_distance_j) { if (!actor->meta.swarm && use_maximum_distance) { real_vector3d facing; real pitch; facing.i = dot_product3d( &direction, &actor->input.looking_vector); facing.j = dot_product3d( &direction, &actor->input.looking_left_vector); facing.k = dot_product3d( &direction, &actor->input.looking_up_vector); pitch = arctangent( facing.k, square_root( facing.i * facing.i + facing.j * facing.j)); if (pitch > 0.5235988f || pitch < -0.7853982f) { full_distance = 0.0f; visible_distance = 0.0f; } else { actor_get_vision_distances( actor_index, maximum_distance, perception_factor, fabs(arctangent( facing.j, facing.i)), &full_distance, &partial_distance); visible_distance = partial_distance; } } else { full_distance = 0.7f * visible_distance; } if (line_of_sight == 0 && distance_squared < full_distance * full_distance) { result = distance_squared < 36.0f ? 3 : 2; } else if (distance_squared < visible_distance * visible_distance) { result = 1; } } } } } } return result; } short actor_audibility_at_point( long actor_index, struct actor_position_data const *position, real_point3d const *source_position, struct location const *source_location, short source_type, real scale, short line_of_sight) { struct actor_datum *actor = actor_get(actor_index); struct actor_definition *definition = actor_definition_get(actor->meta.definition_index); short result = 0; if (source_type != 0 && position->body_location.cluster_index != NONE && source_location->cluster_index != NONE) { real maximum_distance = definition->perception.hearing_distance; real encoded_distance = -1.0f; real audible_distance = -1.0f; real_vector3d direction; real distance_squared; vector_from_points3d( &position->head_position, source_position, &direction); distance_squared = magnitude_squared3d(&direction); if (dot_product3d( &direction, &position->body_facing) < 0.0f) { maximum_distance *= 0.8f; } if (actor_perception_audibility_combat_status(actor) == 2) { maximum_distance *= 0.7f; } else if (actor_perception_audibility_combat_status(actor) == 1) { maximum_distance *= 0.4f; } if (source_type == 4) maximum_distance *= 0.2f; else if (source_type == 1) maximum_distance *= 0.45f; else if (source_type == 3) maximum_distance *= 0.7f; if (scenario_location_deafening(&position->body_location) || scenario_location_deafening(source_location)) { maximum_distance *= 0.25f; } if (line_of_sight != 0 && line_of_sight != 1) maximum_distance *= 0.7f; if (distance_squared < maximum_distance * maximum_distance) { char encoded_sound_distance = (char)structure_bsp_get_cluster_encoded_sound_distance( global_structure_bsp_get(), source_location->cluster_index, position->body_location.cluster_index); if (!(encoded_sound_distance & FLAG(7))) { encoded_distance = ((byte)encoded_sound_distance & ~FLAG(7)) * 2.015748f; audible_distance = encoded_distance * 2.0f; audible_distance = MAX( audible_distance, square_root(distance_squared)); if (audible_distance < maximum_distance) result = (source_type >= 3) + 2; } } { struct actor_debug_info *debug = &actor_debug_array[ DATUM_INDEX_TO_ABSOLUTE_INDEX(actor_index)]; debug->field_A8 = maximum_distance; debug->field_A4 = TRUE; debug->field_A6 = result; debug->field_B0 = encoded_distance; debug->field_AC = square_root(distance_squared); debug->field_B4 = audible_distance; } } return result; } void code_0001f560( long actor_index) { struct actor_emotion_target targets[16]; struct actor_emotion_actor_view *actor; struct prop_iterator iterator; short target_count; long target_prop_index; struct actor_emotion_definition_view *definition; struct actor_emotion_prop_view *prop; actor = (struct actor_emotion_actor_view *)actor_get(actor_index); definition = (struct actor_emotion_definition_view *) actor_definition_get(actor->definition_index); target_count = 0; prop_iterator_new(&iterator, actor_index); prop = (struct actor_emotion_prop_view *) prop_iterator_next(&iterator); while (prop != NULL) { short priority = (short)code_0001f4f0(iterator.index); if (priority > 0) goto add_direct_emotion_target; goto consider_friend_emotion_target; add_direct_emotion_target: { short target_index = (short)code_0001f470( targets, prop->unit_index, actor_index, &target_count, NUMBEROF(targets)); if (target_index != NONE) { struct actor_emotion_target *target = &targets[target_index]; if (target->priority < priority) { target->prop_index = iterator.index; target->unit_index = prop->unit_index; target->prop = prop; target->priority = priority; } } } goto next_emotion_prop; consider_friend_emotion_target: if (prop->state >= _prop_state_becoming_unacknowledged && prop->state <= _prop_state_acknowledged && !prop->enemy && prop->actor_index != NONE && prop->distance < 8.0f) { struct actor_emotion_actor_view *friend_actor = (struct actor_emotion_actor_view *)actor_get(prop->actor_index); if (friend_actor->emotion_target_ticks != 0 && friend_actor->emotion_target_prop_index != NONE && (actor->last_emotion_target_time == NONE || actor->last_emotion_target_time <= friend_actor->emotion_target_time)) { struct actor_emotion_prop_view *friend_target_prop = (struct actor_emotion_prop_view *)prop_get( friend_actor->emotion_target_prop_index); target_prop_index = prop_get_active_by_unit_index( actor_index, friend_target_prop->unit_index); if (target_prop_index != NONE) { struct actor_emotion_prop_view *target_prop = (struct actor_emotion_prop_view *) prop_get(target_prop_index); if (target_prop->state >= _prop_state_becoming_unacknowledged && target_prop->state <= _prop_state_acknowledged && target_prop->unopposable) { short target_index = (short)code_0001f470( targets, friend_target_prop->unit_index, actor_index, &target_count, NUMBEROF(targets)); if (target_index != NONE) { struct actor_emotion_target *target = &targets[target_index]; real distance_squared = friend_target_prop->distance * friend_target_prop->distance; target->count++; if (distance_squared < target->minimum_distance_squared) { target->minimum_distance_squared = distance_squared; target->closest_unit_index = prop->actor_index; } if (target->prop_index == NONE) { target->prop_index = target_prop_index; target->unit_index = target_prop->unit_index; target->prop = target_prop; } } } } } } next_emotion_prop: prop = (struct actor_emotion_prop_view *) prop_iterator_next(&iterator); } if (target_count > 0) { short target_index; for (target_index = 0; target_index < target_count; target_index++) { struct actor_emotion_target *target = &targets[target_index]; struct actor_emotion_prop_view *target_prop = target->prop; short threshold = definition->normal_threshold; boolean player_triggered = FALSE; if (target_prop->vehicle_gunner || target_prop->dangerous_vehicle_driver) { threshold = definition->vehicle_threshold; } if (target_prop->player && definition->player_threshold > 0 && definition->player_threshold < threshold) { threshold = definition->player_threshold; } if (threshold > 0 && target->priority >= threshold) { if (target_prop->player) player_triggered = TRUE; else target_prop->emotion_trigger_ticks = 22; } else if (target_prop->player) { target_prop->emotion_trigger_ticks = 22; } if (target_prop->emotion_trigger_ticks > 0) { if (target_prop->emotion_trigger_age == 0) { target_prop->emotion_trigger_threshold = (short)(real_seed_random_range( get_global_random_seed_address(), definition->trigger_delay_lower, definition->trigger_delay_upper) * 30.0f); } target_prop->emotion_trigger_ticks--; target_prop->emotion_trigger_age++; } if (target_prop->dead_ticks >= 45 || target->priority >= 4) { if (target_prop->emotion_trigger_threshold > 0 && target_prop->emotion_trigger_age >= target_prop->emotion_trigger_threshold) { target->priority = MAX(target->priority, 7); } if (player_triggered) target->priority = MAX(target->priority, 8); if (definition->casualty_threshold > 0 && target_prop->unopposable_casualties >= definition->casualty_threshold) { target->priority = MAX(target->priority, 9); } if (definition->friend_threshold > 0 && target->count >= definition->friend_threshold) { target->priority = MAX(target->priority, 6); } } } } if (actor->emotion_target_ticks > 0) { actor->emotion_target_ticks--; if (actor->emotion_target_ticks == 0) { actor->last_emotion_target_time = game_time_get(); return; } } else { long best_prop_index = NONE; short best_priority = 5; short target_index; for (target_index = 0; target_index < target_count; target_index++) { if (targets[target_index].priority > best_priority && targets[target_index].prop_index != NONE) { best_priority = targets[target_index].priority; best_prop_index = targets[target_index].prop_index; } } if (best_prop_index != NONE) { actor->emotion_target_ticks = (short)(real_seed_random_range( get_global_random_seed_address(), definition->target_duration_lower, definition->target_duration_upper) * 30.0f); actor->emotion_target_prop_index = best_prop_index; actor->emotion_target_time = game_time_get(); } } return; } void actor_berserk( long actor_index, boolean berserk) { struct actor_datum *actor = actor_get(actor_index); if (berserk != actor->emotions.berserk) { actor->emotions.berserk = berserk; actor->emotions.played_berserk_sound = FALSE; if (actor->meta.swarm) { long object_index; for (object_index = actor->meta.swarm_unit_index; object_index != NONE;) { struct unit_datum *unit = unit_get(object_index); SET_FLAG( unit->object.damage_flags, _object_melee_attack_inhibited_bit, TRUE); object_index = unit->unit.swarm_next_unit_index; } } else { struct unit_datum *unit = unit_get(actor->meta.unit_index); SET_FLAG( unit->unit.flags, 7, berserk); } if (berserk) actor->emotions.forced_to_charge = TRUE; } return; } long actor_perception_find_killer_prop_index( long actor_index, long prop_index, boolean enemies_only) { struct prop_datum *prop = prop_get(prop_index); struct unit_datum *unit = unit_get(prop->unit_index); long killer_prop_index = NONE; long most_recent_damage_time = 0; short attacker_index; for (attacker_index = 0; attacker_index < MAXIMUM_ATTACKERS_PER_UNIT; attacker_index++) { long *attacker_object_index = &unit->unit.attackers[attacker_index].object_index; long damage_time = attacker_object_index[-2]; long unit_index = ai_get_responsible_unit( *attacker_object_index, TRUE); if (unit_index != NONE) { long current_prop_index = prop_get_active_by_unit_index( actor_index, unit_index); if (current_prop_index != NONE) { struct prop_datum *current_prop = prop_get(current_prop_index); if (current_prop->state >= _prop_state_becoming_unacknowledged && current_prop->state <= _prop_state_acknowledged && (current_prop->enemy || !enemies_only) && damage_time > most_recent_damage_time) { killer_prop_index = current_prop_index; most_recent_damage_time = damage_time; } } } } return killer_prop_index; } long actor_perception_find_recent_damaging_prop_index( long actor_index, boolean enemies_only) { struct actor_perception_actor_view *actor = (struct actor_perception_actor_view *)actor_get(actor_index); long damaging_prop_index = NONE; if (actor->unit_index != NONE) { struct unit_datum *unit = unit_get(actor->unit_index); unsigned long most_recent_damage_time = 0; short attacker_index; for (attacker_index = 0; attacker_index < MAXIMUM_ATTACKERS_PER_UNIT; attacker_index++) { struct unit_attacker *attacker = &unit->unit.attackers[attacker_index]; long unit_index = ai_get_responsible_unit( attacker->object_index, TRUE); if (unit_index != NONE) { long current_prop_index = prop_get_active_by_unit_index( actor_index, unit_index); if (current_prop_index != NONE) { struct prop_datum *current_prop = prop_get(current_prop_index); if (current_prop->state >= _prop_state_becoming_unacknowledged && current_prop->state <= _prop_state_acknowledged && (current_prop->enemy || !enemies_only) && attacker->game_time_stamp > most_recent_damage_time) { damaging_prop_index = current_prop_index; most_recent_damage_time = attacker->game_time_stamp; } } } } #line 3726 "c:\\halo\\SOURCE\\ai\\actor_perception.c" assert(damaging_prop_index != 0x00000000); #line 500 "source\\ai\\actor_perception.c" } return damaging_prop_index; } void actor_perception_forget_recent_damage( long actor_index) { struct prop_iterator iterator; struct prop_datum *prop; prop_iterator_new(&iterator, actor_index); prop = prop_iterator_next(&iterator); while (prop != NULL) { prop->currently_damaging_me = FALSE; prop->ticks_since_damage = NONE; prop = prop_iterator_next(&iterator); } return; } void actor_perception_retreat_successful( long actor_index) { struct prop_iterator iterator; struct prop_datum *prop; actor_get(actor_index); prop_iterator_new(&iterator, actor_index); prop = prop_iterator_next(&iterator); while (prop != NULL) { prop->unopposable_trigger_hysteresis = 0; prop->unopposable_trigger_threshold = 0; prop->unopposable_trigger_timer = 0; prop = prop_iterator_next(&iterator); } return; } boolean actor_compute_prop_unopposable( long actor_index, long prop_index) { struct actor_perception_actor_view *actor = (struct actor_perception_actor_view *)actor_get(actor_index); struct actor_perception_prop_view *prop = (struct actor_perception_prop_view *)prop_get(prop_index); short type = prop->state; boolean result = FALSE; if (type >= 2 && type <= 3 && prop->enemy && !prop->dead) { if (prop->unreachable_ticks != 0 && (actor->target_prop_index == prop_index || !actor->searching)) { result = TRUE; } else if ((prop->vehicle_gunner || prop->dangerous_vehicle_driver) && !actor->flying && !actor->vehicle_passenger) { result = TRUE; } else if (prop->type == 15) { result = TRUE; } } if (prop->unopposable_enemy && !result) { prop->unopposable_trigger_hysteresis = 0; prop->unopposable_trigger_threshold = 0; prop->unopposable_trigger_timer = 0; } if (type >= 2 && type <= 3 && !result && actor->unopposable_retreat_timer > 0 && actor->unopposable_retreat_prop_index == prop_index) { actor->unopposable_retreat_timer = 0; actor->unopposable_retreat_prop_index = NONE; } prop->unopposable_enemy = result; return result; } void actor_perception_find_prop_pathfinding_location( long actor_index, long prop_index) { struct actor_perception_prop_view *prop = (struct actor_perception_prop_view *)prop_get(prop_index); #line 3585 "c:\\halo\\SOURCE\\ai\\actor_perception.c" assert(prop->owner_actor_index == actor_index); #line 510 "source\\ai\\actor_perception.c" if (prop->pathfinding_surface_index == NONE) { if (prop->vehicle_index != NONE) { prop->pathfinding_surface_index = vehicle_find_pathfinding_surface_index( prop->vehicle_index, &prop->pathfinding_point); return; } if (biped_try_and_get(prop->unit_index)) { prop->pathfinding_surface_index = biped_find_pathfinding_surface_index( prop->unit_index, &prop->pathfinding_point); } } return; } void actor_perception_tried_to_uncover( long actor_index, long prop_index) { if (prop_index != NONE) { struct actor_datum *actor = actor_get(actor_index); struct prop_datum *prop = prop_get(prop_index); prop->tried_to_uncover = TRUE; if (prop_index != actor->target.target_prop_index) { } else { actor_situation_update_target_status(actor_index); actor_situation_combat_status_update(actor_index); } } return; } void actor_perception_tried_to_search( long actor_index, long prop_index) { if (prop_index != NONE) { struct actor_datum *actor = actor_get(actor_index); struct prop_datum *prop = prop_get(prop_index); prop->tried_to_search = TRUE; if (prop_index != actor->target.target_prop_index) { } else { actor_situation_update_target_status(actor_index); actor_situation_combat_status_update(actor_index); } } return; } void actor_perception_abandoned_search( long actor_index, long prop_index) { if (prop_index == NONE) { struct actor_datum *actor = actor_get(actor_index); actor->firing_positions.pursuit_positions_count = 0; actor->firing_positions.pursuit_fired_at_orphan = FALSE; actor->firing_positions.pursuit_communicated_lost_contact = FALSE; actor->state.artificial_combat_status = 0; actor->state.suspicion_combat_status = 0; actor_situation_combat_status_update(actor_index); } else { struct actor_datum *actor = actor_get(actor_index); struct prop_datum *prop = prop_get(prop_index); if (prop->state == _prop_state_uninspected_orphan) prop->state = _prop_state_inspected_orphan; prop->abandoned_search = TRUE; if (prop_index != actor->target.target_prop_index) { } else { actor_situation_update_target_status(actor_index); actor_situation_combat_status_update(actor_index); } } return; } void actor_perception_unreachable( long actor_index, long prop_index, boolean unreachable) { struct actor_datum *actor = actor_get(actor_index); struct prop_datum *prop = prop_get(prop_index); if (unreachable) { if (prop->unreachable_ticks == 0) prop->unreachable_ticks = 1; prop->last_unreachable_time = game_time_get(); } else { prop->unreachable_ticks = 0; prop->last_unreachable_time = NONE; } prop->unopposable_enemy = actor_compute_prop_unopposable(actor_index, prop_index); prop->target_weight = actor_compute_prop_target_weight(actor_index, prop_index); return; } boolean actor_perception_become_acknowledged( long actor_index, long prop_index, boolean *expected_acknowledgement_out) { struct actor_perception_prop_view *prop = (struct actor_perception_prop_view *)prop_get(prop_index); boolean result = FALSE; boolean expected_acknowledgement = FALSE; if (prop->state < 2 || prop->state > 3) { long orphaned = prop->orphan_prop_index != NONE; expected_acknowledgement = actor_expected_acknowledgement(actor_index, prop_index); if (orphaned) { struct actor_perception_prop_view *orphan = (struct actor_perception_prop_view *)prop_get( prop->orphan_prop_index); prop->target_weight = orphan->target_weight; prop->look_interest = orphan->look_interest; prop->last_idle_look_interest = orphan->last_idle_look_interest; prop->last_idle_look_time = orphan->last_idle_look_time; prop->unreachable_ticks = orphan->unreachable_ticks; prop->last_unreachable_time = orphan->last_unreachable_time; prop->unopposable_enemy = orphan->unopposable_enemy; prop->unopposable_casualties_inflicted = orphan->unopposable_casualties_inflicted; prop->unopposable_casualty_decay_timer = orphan->unopposable_casualty_decay_timer; actor_switch_props( actor_index, prop->orphan_prop_index, prop_index); prop_delete(actor_index, prop->orphan_prop_index); prop->orphan_prop_index = NONE; } prop->state = 3; actor_perception_acknowledge( actor_index, prop_index, orphaned, expected_acknowledgement); result = TRUE; } if (expected_acknowledgement_out) *expected_acknowledgement_out = expected_acknowledgement; return result; } boolean actor_expected_acknowledgement( long actor_index, long prop_index) { struct actor_perception_actor_view *actor = (struct actor_perception_actor_view *)actor_get(actor_index); struct actor_perception_prop_view *prop = (struct actor_perception_prop_view *)prop_get(prop_index); struct prop_iterator iterator; struct actor_perception_prop_view *current_prop; boolean result = FALSE; real delta_x; real delta_y; #line 3613 "c:\\halo\\SOURCE\\ai\\actor_perception.c" match_vassert( __FILE__, __LINE__, !(prop->state >= _prop_state_uninspected_orphan && prop->state <= _prop_state_inspected_orphan), "!prop_orphaned(prop)"); #line 790 "source\\ai\\actor_perception.c" prop_iterator_new(&iterator, actor_index); current_prop = (struct actor_perception_prop_view *)prop_iterator_next(&iterator); while (current_prop != NULL) { if (iterator.index != prop_index && (current_prop->unit_index == prop->unit_index || current_prop->actor_index == prop->actor_index || (prop->enemy && current_prop->enemy && ((current_prop->state >= _prop_state_uninspected_orphan && current_prop->state <= _prop_state_inspected_orphan) || (current_prop->state >= _prop_state_becoming_unacknowledged && current_prop->state <= _prop_state_acknowledged)))) && actor_perception_distance_squared2d( ¤t_prop->body_position, &prop->body_position, delta_x, delta_y) < 6.25f && fabs(current_prop->body_position.z - prop->body_position.z) < 1.5f && dot_product3d( ¤t_prop->actor_to_prop, &prop->actor_to_prop) > 0.5f) { result = TRUE; } current_prop = (struct actor_perception_prop_view *)prop_iterator_next( &iterator); } return result; } void actor_perception_find_sense_position( long actor_index, real_point3d const *position, long unused, struct actor_position_data *sense_position) { struct actor_datum *actor = actor_get(actor_index); if (actor->meta.swarm) { struct swarm_datum *swarm = swarm_get(actor->meta.swarm_cache_index); real best_distance_squared = FLT_MAX; long best_unit_index = NONE; short unit_index; #line 1637 "c:\\halo\\SOURCE\\ai\\actor_perception.c" assert(actor->meta.swarm_unit_count > 0); #line 1634 "c:\\halo\\SOURCE\\ai\\actor_perception.c" match_vassert( __FILE__, __LINE__, actor->meta.swarm_unit_index != NONE, "actor->meta.swarm_unit_index != NONE"); #line 970 "source\\ai\\actor_perception.c" for (unit_index = 0; unit_index < swarm->unit_count; unit_index++) { struct actor_perception_swarm_component_view *component = swarm_component_get(swarm->component_indices[unit_index]); real distance_squared = distance_squared3d(&component->position, position); if (distance_squared < best_distance_squared) { best_distance_squared = distance_squared; best_unit_index = swarm->unit_indices[unit_index]; } } #line 1651 "c:\\halo\\SOURCE\\ai\\actor_perception.c" match_vassert( __FILE__, __LINE__, best_unit_index != NONE, "best_unit_index != NONE"); #line 990 "source\\ai\\actor_perception.c" actor_input_sample_position( actor_index, best_unit_index, sense_position); } else { *sense_position = actor->input.position; } return; } static long code_00020210( long swarm_actor_index, long actor_index, long existing_unit_index, boolean mark, struct actor_position_data const *position) { struct actor_datum *swarm_actor = actor_get(swarm_actor_index); long best_unit_index = NONE; #line 1677 "c:\\halo\\SOURCE\\ai\\actor_perception.c" assert(swarm_actor->meta.swarm); #line 1001 "source\\ai\\actor_perception.c" if (swarm_actor->meta.swarm_cache_index != NONE) { struct swarm_datum *swarm = swarm_get(swarm_actor->meta.swarm_cache_index); real best_distance_squared = FLT_MAX; short unit_index; for (unit_index = 0; unit_index < swarm->unit_count; unit_index++) { struct actor_perception_swarm_component_view *component = swarm_component_get(swarm->component_indices[unit_index]); real distance_squared = distance_squared3d( &component->position, &position->body_position); if (TEST_FLAG(component->flags, 1)) { distance_squared *= 2.25f; } else if (swarm->unit_indices[unit_index] == existing_unit_index) { distance_squared *= 0.36f; } if (distance_squared < best_distance_squared) { best_distance_squared = distance_squared; best_unit_index = swarm->unit_indices[unit_index]; } if (mark) { object_mark_function(swarm->unit_indices[unit_index]); } } } else { long unit_index = swarm_actor->meta.swarm_unit_index; real best_distance_squared = FLT_MAX; while (unit_index != NONE) { struct unit_datum *unit = unit_get(unit_index); real_point3d origin; real distance_squared; object_get_origin(unit_index, &origin); distance_squared = distance_squared3d(&origin, &position->body_position); if (unit_index == existing_unit_index) { distance_squared *= 0.36f; } if (distance_squared < best_distance_squared) { best_distance_squared = distance_squared; best_unit_index = unit_index; } if (mark) { object_mark_function(unit_index); } unit_index = unit->unit.swarm_next_unit_index; } } #line 1749 "c:\\halo\\SOURCE\\ai\\actor_perception.c" match_vassert( __FILE__, __LINE__, existing_unit_index == NONE || best_unit_index != NONE, "(existing_unit_index == NONE) || (best_unit_index != NONE)"); #line 1090 "source\\ai\\actor_perception.c" return best_unit_index; } void prop_position_refresh( long actor_index, long prop_index, struct actor_position_data *position, boolean refresh_position, boolean refresh_vehicle) { struct actor_datum *actor = actor_get(actor_index); if (actor->meta.active) { long current_prop_index = prop_index; struct prop_datum *prop = prop_get(current_prop_index); struct unit_datum *unit = unit_get(prop->unit_index); if (!refresh_position && prop->state >= _prop_state_uninspected_orphan && prop->state <= _prop_state_inspected_orphan) { boolean corpse_stopped; if (prop->orphan_corpse_cheated) { goto update_actor_to_prop; } if (TEST_FLAG(unit->object.damage_flags, 2) && ((struct actor_perception_unit_view *)unit) ->parent_seat_index == 0 && prop->perception == 0 && magnitude_squared3d(&unit->object.translational_velocity) < 0.010000000707805157f) { corpse_stopped = TRUE; } else { corpse_stopped = FALSE; } if (actor->target.target_prop_index == current_prop_index && (!prop->tried_to_uncover || !prop->tried_to_search)) { goto update_actor_to_prop; } if (!corpse_stopped) { goto update_actor_to_prop; } prop->orphan_corpse_cheated = TRUE; prop->dead = TRUE; } if (prop->swarm && prop->actor_index != NONE && refresh_vehicle) { long current_time = game_time_get(); if (prop->swarm_unit_selected_time + 90 <= current_time) { long new_unit_index; prop->swarm_unit_selected_time = current_time; new_unit_index = code_00020210( prop->actor_index, actor_index, prop->unit_index, FALSE, &actor->input.position); if (new_unit_index != prop->unit_index) { prop->unit_index = new_unit_index; unit = unit_get(new_unit_index); if (prop->state >= _prop_state_uninspected_orphan && prop->state <= _prop_state_inspected_orphan) { struct prop_datum *parent_prop = prop_get(prop->orphan_prop_index); parent_prop->unit_index = prop->unit_index; } else if (prop->orphan_prop_index != NONE) { struct prop_datum *parent_prop = prop_get(prop->orphan_prop_index); parent_prop->unit_index = prop->unit_index; } } } } unit_get_head_position(prop->unit_index, &prop->head_position); object_get_origin(prop->unit_index, &prop->body_position); unit_get_center_of_mass(prop->unit_index, &prop->center_of_mass); prop->velocity = unit->object.translational_velocity; prop->pathfinding_surface_index = NONE; prop->body_location = actor_perception_object_get( object_get_ultimate_parent(prop->unit_index)) ->object.location; prop->underwater = scenario_location_underwater( &prop->body_location, &prop->center_of_mass, NULL); prop->vehicle_index = NONE; prop->vehicle_gunner = FALSE; prop->dangerous_vehicle_driver = FALSE; prop->attached_to_unit_index = NONE; if (unit->object.parent_object_index != NONE) { struct object_datum *parent = actor_perception_object_get( unit->object.parent_object_index); if (parent->object.type == _object_type_vehicle) { struct unit_datum *vehicle = (struct unit_datum *)parent; prop->vehicle_index = unit->object.parent_object_index; prop->vehicle_gunner = vehicle->unit.gunner_object_index == prop->unit_index || prop->type == 15; prop->dangerous_vehicle_driver = vehicle->unit.driver_object_index == prop->unit_index && vehicle_causes_collision_damage(prop->vehicle_index); } else if (((1 << parent->object.type) & 3) != 0) { prop->attached_to_unit_index = unit->object.parent_object_index; } } prop->child_units_attached = 0; { long child_object_index = unit->object.first_child_object_index; while (child_object_index != NONE) { struct object_datum *child = actor_perception_object_get(child_object_index); if (((1 << child->object.type) & _object_mask_unit) != 0) { prop->child_units_attached++; } child_object_index = child->object.next_object_index; } } update_actor_to_prop: actor_perception_find_sense_position( actor_index, &prop->body_position, current_prop_index, position); vector_from_points3d( &position->body_position, &prop->body_position, &prop->actor_to_prop); prop->distance = normalize3d(&prop->actor_to_prop); if (prop->distance == 0.0f) { prop->actor_to_prop = *global_forward3d; } } return; } static boolean code_00020780( long actor_index, long vehicle_index, boolean mark, struct actor_position_data const *position) { struct actor_perception_actor_view *actor = (struct actor_perception_actor_view *)actor_get(actor_index); boolean result = FALSE; if (actor->vehicle_index == NONE) { struct unit_datum *vehicle = vehicle_get(vehicle_index); struct actor_perception_vehicle_definition_view *vehicle_definition = (struct actor_perception_vehicle_definition_view *) vehicle_definition_get(vehicle->definition_index); if (TEST_FLAG(vehicle_definition->danger_zone_flags, 7) && magnitude_squared3d(&vehicle->object.translational_velocity) > 0.0011111111380159855f) { real_point3d vehicle_origin; struct actor_position_data sampled_position; real distance; object_get_origin(vehicle_index, &vehicle_origin); if (position == NULL) { actor_perception_find_sense_position( actor_index, &vehicle_origin, NONE, &sampled_position); position = &sampled_position; } distance = distance3d(&position->body_position, &vehicle_origin); if (distance < vehicle_definition->bounding_radius + 10.0f) { if (actor->danger_zone.danger_type < _actor_danger_zone_vehicle || (actor->danger_zone.danger_type == _actor_danger_zone_vehicle && actor->danger_zone.object_index != vehicle_index && distance < actor->danger_zone .current_distance_from_actor)) { struct actor_perception_responsible_unit_view *responsible_unit; csmemset( &actor->danger_zone, 0, sizeof(actor->danger_zone)); actor->danger_zone.object_index = vehicle_index; actor->danger_zone.danger_type = _actor_danger_zone_vehicle; actor->danger_zone.owner_unit_index = vehicle->unit.driver_object_index; actor->danger_zone.danger_radius = vehicle_definition->bounding_radius; actor->danger_zone.initial_position = vehicle_origin; actor->danger_zone.initial_velocity = vehicle->object.translational_velocity; actor->danger_zone.acknowledgement_timer = 20; actor->danger_zone.currently_perceived = mark; actor->danger_zone.hostility = 0; if (actor->danger_zone.owner_unit_index != NONE) { responsible_unit = (struct actor_perception_responsible_unit_view *) unit_get( vehicle->unit .driver_object_index); if (!game_team_is_enemy( actor->team, responsible_unit->team)) { actor->danger_zone.hostility = 1; } } result = TRUE; } } } } return result; } /* * January caller skeleton used while reconstructing the full status refresh. * Keep the real call expression active so VC7 can derive code_00020780's * private EAX argument from its actual translation-unit context. */ void code_000228b0( long actor_index, long object_index, struct actor_perception_refresh_list *enemy_list, struct actor_perception_refresh_list *friend_list) { struct { struct actor_datum *actor; struct object_datum *current_object; } pointers; #define actor pointers.actor #define current_object pointers.current_object actor = actor_get(actor_index); while (object_index != NONE) { current_object = actor_perception_object_get(object_index); if (object_mark_function(object_index)) { if (current_object->object.type == _object_type_biped) { struct unit_datum *unit = (struct unit_datum *)current_object; struct actor_position_data position; struct actor_perception_actor_view *unit_actor; struct actor_perception_actor_view *current_actor; struct actor_perception_refresh_list *list; struct unit_definition *unit_definition; real_point3d origin; real distance_squared; real suicide_radius; long unit_index; long unit_actor_index; long prop_index; short dead_ticks; boolean player; boolean enemy; boolean dead; boolean candidate; object_get_origin(object_index, &origin); actor_perception_find_sense_position( actor_index, &origin, NONE, &position); unit_actor_index = unit->unit.swarm_actor_index; if (unit_actor_index != NONE) { unit_index = code_00020210( unit_actor_index, actor_index, NONE, TRUE, &position); if (unit_index != NONE) { unit = unit_get(unit_index); object_get_origin(unit_index, &origin); } } else { unit_actor_index = unit->unit.actor_index; unit_index = object_index; } if (unit_index == NONE || unit_actor_index == actor_index) goto object_done; unit_definition = unit_definition_get(unit->definition_index); player = unit->unit.player_index != NONE; enemy = game_team_is_enemy( actor->meta.team_index, unit->object.owner_team_index); if (!TEST_FLAG(unit->object.damage_flags, _object_dead_bit) || unit->unit.feign_death_timer != 0) { dead = FALSE; dead_ticks = 0; } else { dead = TRUE; if (unit->unit.time_of_death == NONE) dead_ticks = 0x7FFF; else dead_ticks = (short)game_time_get() - (short)unit->unit.time_of_death; } suicide_radius = unit_definition->unit.ai_danger_radius; distance_squared = distance_squared3d( &origin, &position.body_position); if (suicide_radius > 0.0f && (dead || unit->unit.animation.state == 0x1E)) { code_0001dc00( actor_index, unit_index, suicide_radius, square_root(distance_squared), enemy, FALSE); } current_actor = (struct actor_perception_actor_view *)actor_get( actor_index); unit_actor = unit_actor_index == NONE ? NULL : (struct actor_perception_actor_view *)actor_get( unit_actor_index); candidate = FALSE; if (player) goto choose_list; if (unit_actor != NULL && (!unit_actor->active || unit_actor->dormant)) { goto object_done; } if (distance_squared > 1600.0f) goto object_done; if (dead) { boolean interest_allowed = TRUE; boolean encounter_clear = FALSE; if (current_actor->encounter_index != NONE) { struct actor_perception_encounter_view *encounter = (struct actor_perception_encounter_view *) encounter_get(current_actor->encounter_index); struct unit_datum *corpse_unit = unit_get(unit_index); long ignore_time = encounter->corpse_ignore_time; if (ignore_time <= current_actor->corpse_ignore_time) ignore_time = current_actor->corpse_ignore_time; if (ignore_time != NONE && (corpse_unit->unit.time_of_death == NONE || corpse_unit->unit.time_of_death < ignore_time)) { interest_allowed = FALSE; } encounter_clear = !encounter->enemy_target && !encounter->stand_down && !encounter->blind; } if (!interest_allowed) goto object_done; if (encounter_clear) { if (distance_squared < 225.0f) goto choose_list; goto object_done; } goto corpse_fallback; } goto live_unit; choose_list: list = enemy ? enemy_list : friend_list; if (candidate) { #line 2966 "c:\\halo\\SOURCE\\ai\\actor_perception.c" assert(!dead); #line 3258 "source\\ai\\actor_perception.c" if (list->entry_count < 128) { list->entries[list->entry_count].prop_index = NONE; list->entries[list->entry_count].unit_index = unit_index; list->entries[list->entry_count].priority = distance_squared; list->entry_count++; } goto object_done; } goto create_prop; corpse_fallback: if (suicide_radius > 0.0f) goto choose_list; if ((!enemy || dead_ticks <= 150) && actor_action_class(actor_index) <= 1) { real maximum_distance_squared = 16.0f; if (!enemy && current_actor->combat_status < 3) maximum_distance_squared = 64.0f; if (distance_squared < maximum_distance_squared) goto choose_list; } goto object_done; live_unit: if (enemy) { candidate = distance_squared > 36.0f; goto choose_list; } if (distance_squared >= 225.0f) goto object_done; if (current_actor->combat_status >= 4) { candidate = TRUE; } else if (!current_actor->corpse_interest_inhibited && distance_squared > 16.0f) { candidate = TRUE; } goto choose_list; create_prop: prop_index = prop_new_unacknowledged( actor_index, unit_index, enemy); if (prop_index != NONE) { prop_position_refresh( actor_index, prop_index, &position, FALSE, FALSE); if (!dead) list->accepted_count++; } } else if (current_object->object.type == _object_type_vehicle) { struct unit_datum *vehicle = (struct unit_datum *)current_object; if (vehicle->unit.driver_object_index == NONE) { code_00020780( actor_index, object_index, FALSE, NULL); } } else if (current_object->object.type == _object_type_projectile) { struct actor_perception_projectile_datum_view *projectile = (struct actor_perception_projectile_datum_view *) current_object; struct projectile_definition *projectile_definition = projectile_definition_get( current_object->definition_index); if (projectile_definition->projectile.danger_radius > 0.0f && (current_object->object.parent_object_index == NONE || TEST_FLAG(projectile->attachment_flags, 5))) { struct actor_position_data position; real_point3d origin; real distance; object_get_origin(object_index, &origin); actor_perception_find_sense_position( actor_index, &origin, NONE, &position); distance = distance3d( &origin, &position.body_position); if (distance < projectile_definition->projectile.danger_radius + 10.0f && (actor->danger_zone.danger_type < 2 || (actor->danger_zone.danger_type == 2 && actor->danger_zone.object_index != object_index && distance < actor->danger_zone .current_distance_from_actor))) { long owner_unit_index = NONE; struct object_datum *owner_object = NULL; csmemset( &actor->danger_zone, 0, sizeof(actor->danger_zone)); actor->danger_zone.danger_type = 2; actor->danger_zone.object_index = object_index; actor->danger_zone.danger_radius = projectile_definition->projectile.danger_radius; actor->danger_zone.initial_position = origin; actor->danger_zone.initial_velocity = current_object->object.translational_velocity; actor->danger_zone.acknowledgement_timer = 30; actor->danger_zone.currently_perceived = FALSE; actor->danger_zone.hostility = 0; if (current_object->object.owner_object_index != NONE) { owner_object = object_try_and_get( current_object->object.owner_object_index); } if (owner_object != NULL && TEST_FLAG( _object_mask_unit, owner_object->object.type)) { owner_unit_index = current_object->object.owner_object_index; if (actor->meta.unit_index == NONE || owner_unit_index != actor->meta.unit_index) { if (!game_team_is_enemy( actor->meta.team_index, current_object->object.owner_team_index)) { actor->danger_zone.hostility = 1; } } else { actor->danger_zone.hostility = 2; } } actor->danger_zone.owner_unit_index = owner_unit_index; } } } } object_done: if (current_object->object.first_child_object_index != NONE) { code_000228b0( actor_index, current_object->object.first_child_object_index, enemy_list, friend_list); } object_index = current_object->object.next_object_index; } return; #undef actor #undef current_object } boolean actor_perception_create_orphan_from_friend( long actor_index, long unit_index, long source_actor_index, long friend_prop_index) { struct actor_orphan_prop_view *current_prop; struct actor_position_data position; long current_prop_index; long current_orphan_index; boolean result; result = TRUE; current_prop_index = prop_get_base_by_unit_index( actor_index, unit_index, TRUE, FALSE); if (current_prop_index == NONE) goto done; current_prop = (struct actor_orphan_prop_view *)prop_get(current_prop_index); if (current_prop->state >= _prop_state_becoming_unacknowledged && current_prop->state <= _prop_state_acknowledged) { result = FALSE; } else if (current_prop->related_prop_index != NONE) { struct actor_orphan_prop_view *current_orphan; boolean refresh_position; current_orphan_index = current_prop->related_prop_index; current_orphan = (struct actor_orphan_prop_view *) prop_get(current_orphan_index); refresh_position = FALSE; #line 3759 "c:\\halo\\SOURCE\\ai\\actor_perception.c" match_vassert( __FILE__, __LINE__, current_prop->state >= _prop_state_unacknowledged && current_prop->state <= _prop_state_becoming_acknowledged, "prop_unacknowledged(current_prop)"); #line 3760 "c:\\halo\\SOURCE\\ai\\actor_perception.c" match_vassert( __FILE__, __LINE__, current_orphan->state >= _prop_state_uninspected_orphan && current_orphan->state <= _prop_state_inspected_orphan, "prop_orphaned(current_orphan)"); #line 3762 "c:\\halo\\SOURCE\\ai\\actor_perception.c" match_vassert( __FILE__, __LINE__, current_prop->owner_actor_index == actor_index, "current_prop->owner_actor_index == actor_index"); #line 3763 "c:\\halo\\SOURCE\\ai\\actor_perception.c" match_vassert( __FILE__, __LINE__, current_orphan->owner_actor_index == actor_index, "current_orphan->owner_actor_index == actor_index"); #line 3764 "c:\\halo\\SOURCE\\ai\\actor_perception.c" match_vassert( __FILE__, __LINE__, current_prop->related_prop_index == current_orphan_index, "current_prop->orphan_prop_index == current_orphan_index"); #line 3765 "c:\\halo\\SOURCE\\ai\\actor_perception.c" match_vassert( __FILE__, __LINE__, current_orphan->related_prop_index == current_prop_index, "current_orphan->parent_prop_index == current_prop_index"); #line 545 "source\\ai\\actor_perception.c" if (friend_prop_index != NONE) { prop_orphan_update_information( actor_index, current_orphan_index, friend_prop_index); current_prop->unit_index = current_orphan->unit_index; } else { current_orphan->state = _prop_state_uninspected_orphan; current_orphan->orphan_inspection_ticks = 0; refresh_position = TRUE; } prop_position_refresh( actor_index, current_orphan_index, &position, refresh_position, TRUE); prop_status_refresh( actor_index, current_orphan_index, &position); current_prop_index = current_orphan_index; current_prop = (struct actor_orphan_prop_view *) prop_get(current_orphan_index); } else { #line 3802 "c:\\halo\\SOURCE\\ai\\actor_perception.c" match_vassert( __FILE__, __LINE__, current_prop->state >= _prop_state_unacknowledged && current_prop->state <= _prop_state_becoming_acknowledged, "prop_unacknowledged(current_prop)"); #line 586 "source\\ai\\actor_perception.c" if (friend_prop_index != NONE) { current_prop_index = prop_orphan_from_friend( actor_index, current_prop_index, friend_prop_index); if (current_prop_index != NONE) { struct actor_orphan_prop_view *new_prop = (struct actor_orphan_prop_view *) prop_get(current_prop_index); new_prop->unit_index = current_prop->unit_index; new_prop->actor_index = current_prop->actor_index; new_prop->swarm = current_prop->swarm; } } else { prop_position_refresh( actor_index, current_prop_index, &position, FALSE, FALSE); current_prop_index = prop_orphan_transition( actor_index, current_prop_index); } if (current_prop_index == NONE) { result = FALSE; goto done; } current_prop = (struct actor_orphan_prop_view *) prop_get(current_prop_index); } if (current_prop != NULL) { if (source_actor_index == NONE || (friend_prop_index != NONE && ((struct actor_situation_prop_view *) prop_get(friend_prop_index))->combat_status >= 2)) { current_prop->definitely_located = TRUE; current_prop->ticks_since_definitely_located = 0; current_prop->definite_knowledge_source_actor = source_actor_index; } current_prop->unopposable_enemy = actor_compute_prop_unopposable( actor_index, current_prop_index); current_prop->target_weight = actor_compute_prop_target_weight( actor_index, current_prop_index); } done: return result; } boolean actor_emotion_flee_with_friends( long actor_index, real *desire_to_flee) { struct actor_perception_actor_view *actor = (struct actor_perception_actor_view *)actor_get(actor_index); struct prop_iterator iterator; struct actor_perception_prop_view *prop; short fighting_friend_count = 0; short fleeing_friend_count = 0; real modifier; prop_iterator_new(&iterator, actor_index); prop = (struct actor_perception_prop_view *)prop_iterator_next(&iterator); while (prop != NULL) { if (prop->state >= _prop_state_becoming_unacknowledged && prop->state <= _prop_state_acknowledged && !prop->enemy && prop->type == actor->type && prop->actor_index != NONE) { struct actor_perception_actor_view *friend_actor = (struct actor_perception_actor_view *)actor_get( prop->actor_index); if (friend_actor->active_threat_count > 0 || (friend_actor->friend_state == 4 && friend_actor->friend_fighting_count > 0)) { fighting_friend_count++; } else if (prop->in_combat) { fleeing_friend_count++; } } prop = (struct actor_perception_prop_view *)prop_iterator_next( &iterator); } if (fighting_friend_count > 1) return TRUE; if (fleeing_friend_count > 1) modifier = 1.0f - (fleeing_friend_count - 1) * 0.25f; else modifier = 1.0f + (1 - fleeing_friend_count) * 0.5f; *desire_to_flee *= PIN(modifier, 0.0f, 2.0f); return FALSE; } boolean actor_situation_try_new_target( long actor_index, long new_prop_index) { struct actor_perception_actor_view *actor = (struct actor_perception_actor_view *)actor_get(actor_index); struct actor_perception_prop_view *new_prop = (struct actor_perception_prop_view *)prop_get(new_prop_index); struct actor_perception_prop_view *target_prop; boolean result = FALSE; if (actor->target_prop_index == NONE) target_prop = NULL; else target_prop = (struct actor_perception_prop_view *)prop_get( actor->target_prop_index); new_prop->target_weight = actor_compute_prop_target_weight(actor_index, new_prop_index); if (new_prop->target_weight > 0.0f) { #line 4685 "c:\\halo\\SOURCE\\ai\\actor_perception.c" assert(new_prop->enemy); #line 700 "source\\ai\\actor_perception.c" if (!target_prop || new_prop->target_weight >= target_prop->target_weight) { actor->target_type = 0; actor->target_prop_index = new_prop_index; actor->target_last_visible_time = NONE; actor_situation_update_target_status(actor_index); actor_situation_combat_status_update(actor_index); result = TRUE; } } return result; } /* ---------- private code */ long code_0001dbc0( void const *a, void const *b) { real a_value = ((real const *)a)[2]; real b_value = ((real const *)b)[2]; if (a_value < b_value) return -1; if (a_value > b_value) return 1; return 0; } static boolean code_0001dc00( long actor_index, long object_index, real suicide_radius, real distance, boolean enemy, boolean visible) { struct actor_perception_actor_view *actor = (struct actor_perception_actor_view *)actor_get(actor_index); struct actor_danger_zone_view *danger_zone; boolean result = FALSE; if (suicide_radius + 10.0f > distance) { danger_zone = &actor->danger_zone; if (actor->danger_zone.danger_type < 1 || (actor->danger_zone.danger_type == 1 && actor->danger_zone.object_index != object_index && distance < actor->danger_zone.current_distance_from_actor)) { struct unit_datum *unit = unit_get(object_index); memset( danger_zone, 0, sizeof(*danger_zone)); actor->danger_zone.danger_type = 1; actor->danger_zone.object_index = object_index; actor->danger_zone.danger_radius = suicide_radius; object_get_origin( object_index, &actor->danger_zone.initial_position); actor->danger_zone.initial_velocity = unit->object.translational_velocity; actor->danger_zone.acknowledgement_timer = 6; actor->danger_zone.currently_perceived = visible; actor->danger_zone.hostility = !enemy; result = TRUE; } } return result; }