mirror of
https://github.com/astromaddie/HaloCE-VR.git
synced 2026-10-28 11:00:17 +01:00
Integrate coherent B3, P2/K17 prerequisites, completed K1-K16 + S, and the independent profile/effects rulings. Five gains and two explicitly approved B3 debits: net +3 strict functions, +2770 meaningful/+2800 padded bytes (+2774 progress credit). No additional losses; Halo objects 394 to 396 and data unchanged. Clean rebuild, identical 8252-row stable sweep, 68 valid parks, admission/provider checks, 467-unit warning comparison, unchanged fake scan, and 1318 tests passed. Preserve canonical helper recoveries and unrelated work. Full evidence and disclosures in docs/object_matching_logs/astra_five_function_reconciliation_20260928.md.
700 lines
21 KiB
C
700 lines
21 KiB
C
/*
|
|
AIM_ASSIST.C
|
|
|
|
symbols in this file:
|
|
00093C00 0050:
|
|
_compute_attenuation (0000)
|
|
00093C50 0030:
|
|
_compute_composite_attenuation (0000)
|
|
00093C80 00f0:
|
|
_unit_get_aim_assist_parameters (0000)
|
|
00093D70 00a0:
|
|
_compare_targets (0000)
|
|
00093E10 0010:
|
|
_reciprocal_square_root (0000)
|
|
00093E20 0060:
|
|
_limit3d (0000)
|
|
00093E80 0020:
|
|
_set_real_euler_angles2d (0000)
|
|
00093EA0 00f0:
|
|
_aim_assist_clear_line_of_sight (0000)
|
|
00093F90 01a0:
|
|
_object_compute_autoaim_target (0000)
|
|
00094130 01a0:
|
|
_aim_assist_compute_target (0000)
|
|
000942D0 0110:
|
|
_autoaim_compute_target (0000)
|
|
000943E0 0190:
|
|
_find_aim_assist_targets_recursive (0000)
|
|
00094570 0130:
|
|
_find_aim_assist_targets (0000)
|
|
000946A0 0100:
|
|
_aim_assist (0000)
|
|
000947A0 0340:
|
|
_player_aim_projectile (0000)
|
|
00094AE0 0170:
|
|
_local_player_aim_assist (0000)
|
|
0025AC3C 0021:
|
|
??_C@_0CB@CDDNCJJI@c?3?2halo?2SOURCE?2game?2aim_assist?4c@ (0000)
|
|
0025AC60 0004:
|
|
__real@43000000 (0000)
|
|
*/
|
|
|
|
/* ---------- headers */
|
|
|
|
#include "cseries.h"
|
|
#include "game/aim_assist.h"
|
|
|
|
#include "camera/director.h"
|
|
#include "camera/observer.h"
|
|
#include "game/game.h"
|
|
#include "game/game_allegiance.h"
|
|
#include "game/game_globals.h"
|
|
#include "game/players.h"
|
|
#include "math/real_math_cones.h"
|
|
#include "items/weapon_definitions.h"
|
|
#include "items/weapons.h"
|
|
#include "objects/objects.h"
|
|
#include "physics/collision_usage.h"
|
|
#include "physics/collisions.h"
|
|
#include "scenario/scenario.h"
|
|
#include "structures/structure_bsp_definitions.h"
|
|
#include "structures/structures.h"
|
|
#include "tag_files/tag_groups.h"
|
|
#include "units/biped_definitions.h"
|
|
#include "units/bipeds.h"
|
|
#include "units/unit_definitions.h"
|
|
#include "units/units.h"
|
|
|
|
/* ---------- constants */
|
|
|
|
enum
|
|
{
|
|
MAXIMUM_AIM_ASSIST_TARGETS= 64,
|
|
MAXIMUM_AIM_ASSIST_CLUSTERS= 512,
|
|
MAXIMUM_AIM_ASSIST_OBJECTS= 2048
|
|
};
|
|
|
|
/* ---------- macros */
|
|
|
|
/* ---------- structures */
|
|
|
|
struct aim_assist_target
|
|
{
|
|
long object_index;
|
|
real_point3d position;
|
|
real_vector3d vector;
|
|
real_vector3d direction;
|
|
real distance;
|
|
real angle;
|
|
real autoaim_level;
|
|
real magnetism_level;
|
|
};
|
|
|
|
/* ---------- prototypes */
|
|
|
|
__inline real compute_attenuation(
|
|
real variable,
|
|
real maximum);
|
|
real compute_composite_attenuation(
|
|
real distance,
|
|
real maximum_distance,
|
|
real angle,
|
|
real maximum_angle);
|
|
static boolean unit_get_aim_assist_parameters(
|
|
long unit_index,
|
|
short zoom_level,
|
|
struct aim_assist_parameters *parameters);
|
|
static int compare_targets(
|
|
void const *target0,
|
|
void const *target1);
|
|
static void object_compute_autoaim_target(
|
|
long object_index,
|
|
real_point3d const *position,
|
|
real_vector3d const *direction,
|
|
real_point3d *target);
|
|
static short find_aim_assist_targets_recursive(
|
|
struct aim_assist_parameters const *parameters,
|
|
long object_index,
|
|
real_point3d const *position,
|
|
real_vector3d const *direction,
|
|
real distance,
|
|
real angle_sine,
|
|
real angle_cosine,
|
|
long ignore_object_index,
|
|
short ignore_team_index,
|
|
short maximum_target_count,
|
|
struct aim_assist_target *targets);
|
|
static short find_aim_assist_targets(
|
|
struct aim_assist_parameters const *parameters,
|
|
short cluster_index,
|
|
real_point3d const *position,
|
|
real_vector3d const *direction,
|
|
long ignore_object_index,
|
|
short ignore_team_index,
|
|
short maximum_target_count,
|
|
struct aim_assist_target *targets);
|
|
|
|
/* ---------- globals */
|
|
|
|
/* ---------- code (definitions in January object order) */
|
|
|
|
__inline real compute_attenuation(
|
|
real variable,
|
|
real maximum)
|
|
{
|
|
real half_maximum= maximum*0.5f;
|
|
|
|
if (variable>=maximum)
|
|
{
|
|
return 0.f;
|
|
}
|
|
|
|
if (variable<=half_maximum)
|
|
{
|
|
return 1.f;
|
|
}
|
|
|
|
return (maximum - variable) / (maximum - half_maximum);
|
|
}
|
|
|
|
real compute_composite_attenuation(
|
|
real distance,
|
|
real maximum_distance,
|
|
real angle,
|
|
real maximum_angle)
|
|
{
|
|
return compute_attenuation(distance, maximum_distance) * compute_attenuation(angle, maximum_angle);
|
|
}
|
|
|
|
static boolean unit_get_aim_assist_parameters(
|
|
long unit_index,
|
|
short zoom_level,
|
|
struct aim_assist_parameters *parameters)
|
|
{
|
|
if (unit_index!=NONE)
|
|
{
|
|
struct unit_datum *unit= unit_get(unit_index);
|
|
long weapon_index= unit_inventory_get_weapon(unit_index, unit->unit.current_weapon_index);
|
|
|
|
if (weapon_index!=NONE)
|
|
{
|
|
struct weapon_datum *weapon= weapon_get(weapon_index);
|
|
struct weapon_definition *weapon_definition= weapon_definition_get(weapon->definition_index);
|
|
|
|
if (zoom_level!=NONE || !TEST_FLAG(weapon_definition->weapon.flags, _weapon_aim_assists_only_when_zoomed_bit))
|
|
{
|
|
real magnification= weapon_get_zoom_magnification(weapon_index, zoom_level);
|
|
real inverse_magnification= 1.f/magnification;
|
|
|
|
parameters->autoaim_angle= weapon_definition->weapon.aim_assist_parameters.autoaim_angle*inverse_magnification;
|
|
parameters->autoaim_distance= weapon_definition->weapon.aim_assist_parameters.autoaim_distance*magnification;
|
|
parameters->magnetism_angle= weapon_definition->weapon.aim_assist_parameters.magnetism_angle*inverse_magnification;
|
|
parameters->magnetism_distance= weapon_definition->weapon.aim_assist_parameters.magnetism_distance*magnification;
|
|
parameters->deviation_angle= MAX(weapon_definition->weapon.aim_assist_parameters.deviation_angle,
|
|
weapon_definition->weapon.aim_assist_parameters.autoaim_angle)*inverse_magnification;
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static int compare_targets(
|
|
void const *target0,
|
|
void const *target1)
|
|
{
|
|
struct aim_assist_target const *first= target0;
|
|
struct aim_assist_target const *second= target1;
|
|
|
|
if (first->autoaim_level>second->autoaim_level) return -1;
|
|
if (first->autoaim_level<second->autoaim_level) return 1;
|
|
|
|
if (first->magnetism_level>second->magnetism_level) return -1;
|
|
if (first->magnetism_level<second->magnetism_level) return 1;
|
|
|
|
if (first->distance<second->distance) return -1;
|
|
if (first->distance>second->distance) return 1;
|
|
|
|
if (first->angle<second->angle) return -1;
|
|
if (first->angle>second->angle) return 1;
|
|
|
|
return DATUM_INDEX_TO_ABSOLUTE_INDEX(first->object_index) - DATUM_INDEX_TO_ABSOLUTE_INDEX(second->object_index);
|
|
}
|
|
|
|
boolean aim_assist_clear_line_of_sight(
|
|
real_point3d const *point0,
|
|
real_point3d const *point1,
|
|
long ignore_object_index,
|
|
long target_object_index)
|
|
{
|
|
boolean clear = FALSE;
|
|
real_vector3d vector;
|
|
struct collision_result collision;
|
|
long ignore_parent_index;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\game\\aim_assist.c",
|
|
350,
|
|
global_current_collision_user_depth < MAXIMUM_COLLISION_USER_STACK_DEPTH);
|
|
global_current_collision_users[global_current_collision_user_depth++] = _collision_user_aim_assist;
|
|
|
|
ignore_parent_index = object_get_ultimate_parent(ignore_object_index);
|
|
vector.i = point1->x - point0->x;
|
|
vector.j = point1->y - point0->y;
|
|
vector.k = point1->z - point0->z;
|
|
|
|
if (!collision_test_vector(
|
|
_collision_test_for_line_of_sight_flags,
|
|
point0,
|
|
&vector,
|
|
ignore_parent_index,
|
|
&collision))
|
|
{
|
|
clear = TRUE;
|
|
}
|
|
else if (collision.type == _collision_result_object &&
|
|
object_get_ultimate_parent(collision.object_index) ==
|
|
object_get_ultimate_parent(target_object_index))
|
|
{
|
|
clear = TRUE;
|
|
}
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\game\\aim_assist.c",
|
|
367,
|
|
global_current_collision_user_depth > 1);
|
|
--global_current_collision_user_depth;
|
|
|
|
return clear;
|
|
}
|
|
|
|
static void object_compute_autoaim_target(
|
|
long object_index,
|
|
real_point3d const *position,
|
|
real_vector3d const *direction,
|
|
real_point3d *target)
|
|
{
|
|
real width;
|
|
|
|
// closest point on the pill axis to the aiming line
|
|
{
|
|
real_point3d base;
|
|
real_vector3d height, normal;
|
|
real normal_magnitude_squared;
|
|
|
|
biped_get_autoaim_pill(object_index, &base, &height, &width);
|
|
normal.i= height.j*direction->k - height.k*direction->j;
|
|
normal.j= height.k*direction->i - height.i*direction->k;
|
|
normal.k= height.i*direction->j - height.j*direction->i;
|
|
normal_magnitude_squared= magnitude_squared3d(&normal);
|
|
if (normal_magnitude_squared>0.f)
|
|
{
|
|
real_vector3d offset, cross;
|
|
real t;
|
|
|
|
vector_from_points3d(&base, position, &offset);
|
|
cross_product3d(&offset, direction, &cross);
|
|
t= PIN(dot_product3d(&cross, &normal)/normal_magnitude_squared, 0.f, 1.f);
|
|
target->x= height.i*t + base.x;
|
|
target->y= height.j*t + base.y;
|
|
target->z= height.k*t + base.z;
|
|
}
|
|
else
|
|
{
|
|
*target= base;
|
|
}
|
|
}
|
|
|
|
// pull the target toward the aiming line by at most the pill width
|
|
{
|
|
real_vector3d offset, perpendicular;
|
|
real projection;
|
|
|
|
vector_from_points3d(position, target, &offset);
|
|
projection= -dot_product3d(&offset, direction);
|
|
perpendicular.i= direction->i*projection + offset.i;
|
|
perpendicular.j= direction->j*projection + offset.j;
|
|
perpendicular.k= direction->k*projection + offset.k;
|
|
limit3d(&perpendicular, width);
|
|
target->x-= perpendicular.i;
|
|
target->y-= perpendicular.j;
|
|
target->z-= perpendicular.k;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
boolean aim_assist_compute_target(
|
|
struct aim_assist_parameters const *parameters,
|
|
long object_index,
|
|
real_point3d const *position,
|
|
real_vector3d const *direction,
|
|
struct aim_assist_target *target)
|
|
{
|
|
real cosine, angle;
|
|
|
|
target->object_index= object_index;
|
|
object_compute_autoaim_target(object_index, position, direction, &target->position);
|
|
vector_from_points3d(position, &target->position, &target->vector);
|
|
target->direction= target->vector;
|
|
target->distance= normalize3d(&target->direction);
|
|
cosine= dot_product3d(direction, &target->direction);
|
|
angle= arccosine(PIN(cosine, -1.f, 1.f));
|
|
target->angle= angle;
|
|
|
|
if (parameters)
|
|
{
|
|
target->autoaim_level= compute_composite_attenuation(target->distance, parameters->autoaim_distance,
|
|
angle, parameters->autoaim_angle);
|
|
target->magnetism_level= compute_composite_attenuation(target->distance, parameters->magnetism_distance,
|
|
angle, parameters->magnetism_angle);
|
|
if (target->magnetism_level>0.f)
|
|
{
|
|
struct unit_datum *unit= unit_get(target->object_index);
|
|
struct unit_definition *definition= unit_definition_get(unit->definition_index);
|
|
|
|
if (TEST_FLAG(definition->unit.flags, _unit_is_inconsequential_bit))
|
|
{
|
|
target->magnetism_level*= TAG_BLOCK_GET_ELEMENT(&scenario_get_game_globals()->player_control, 0,
|
|
struct game_globals_player_control)->magnetism_inconsequential_target_scale;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
target->autoaim_level= 0.f;
|
|
target->magnetism_level= 0.f;
|
|
}
|
|
|
|
return target->autoaim_level>0.f || target->magnetism_level>0.f;
|
|
}
|
|
|
|
boolean autoaim_compute_target(
|
|
long object_index,
|
|
real_point3d const *position,
|
|
real_vector3d const *direction,
|
|
long unit_index,
|
|
real_point3d *target_position,
|
|
real_vector3d *target_direction,
|
|
real *target_distance,
|
|
real *target_angle)
|
|
{
|
|
boolean result= FALSE;
|
|
|
|
object_compute_autoaim_target(object_index, position, direction, target_position);
|
|
if (aim_assist_clear_line_of_sight(position, target_position, unit_index, object_index))
|
|
{
|
|
vector_from_points3d(position, target_position, target_direction);
|
|
*target_distance= normalize3d(target_direction);
|
|
if (*target_distance!=0.f)
|
|
{
|
|
*target_angle= arccosine(PIN(dot_product3d(direction, target_direction), -1.f, 1.f));
|
|
result= TRUE;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static short find_aim_assist_targets_recursive(
|
|
struct aim_assist_parameters const *parameters,
|
|
long object_index,
|
|
real_point3d const *position,
|
|
real_vector3d const *direction,
|
|
real distance,
|
|
real angle_sine,
|
|
real angle_cosine,
|
|
long ignore_object_index,
|
|
short ignore_team_index,
|
|
short maximum_target_count,
|
|
struct aim_assist_target *targets)
|
|
{
|
|
short target_count= 0;
|
|
|
|
do
|
|
{
|
|
struct object_datum *object= object_get(object_index);
|
|
|
|
if (TEST_FLAG(_object_mask_unit, object->object.type) &&
|
|
!TEST_FLAG(object->object.flags, _object_invisible_bit) &&
|
|
unit_get(object_index)->unit.active_camouflage<1.f &&
|
|
sphere_intersects_cone3d(&object->object.bounding_sphere_center, object->object.bounding_sphere_radius,
|
|
position, direction, distance, angle_sine, angle_cosine))
|
|
{
|
|
if (TEST_FLAG(_object_mask_biped, object->object.type) &&
|
|
!TEST_FLAG(object->object.damage_flags, _object_dead_bit) &&
|
|
object_index!=ignore_object_index &&
|
|
game_team_is_enemy(ignore_team_index, object->object.owner_team_index) &&
|
|
!TEST_FLAG(biped_definition_get(object->definition_index)->unit.flags, _unit_ignored_by_autoaiming_bit))
|
|
{
|
|
struct aim_assist_target target;
|
|
|
|
if (aim_assist_compute_target(parameters, object_index, position, direction, &target) &&
|
|
target_count<maximum_target_count)
|
|
{
|
|
targets[target_count++]= target;
|
|
}
|
|
}
|
|
|
|
if (object->object.first_child_object_index!=NONE && target_count<maximum_target_count)
|
|
{
|
|
target_count+= find_aim_assist_targets_recursive(parameters, object->object.first_child_object_index,
|
|
position, direction, distance, angle_sine, angle_cosine, ignore_object_index, ignore_team_index,
|
|
maximum_target_count - target_count, &targets[target_count]);
|
|
}
|
|
}
|
|
|
|
object_index= object->object.next_object_index;
|
|
}
|
|
while (object_index!=NONE && target_count<maximum_target_count);
|
|
|
|
return target_count;
|
|
}
|
|
|
|
static short find_aim_assist_targets(
|
|
struct aim_assist_parameters const *parameters,
|
|
short cluster_index,
|
|
real_point3d const *position,
|
|
real_vector3d const *direction,
|
|
long ignore_object_index,
|
|
short ignore_team_index,
|
|
short maximum_target_count,
|
|
struct aim_assist_target *targets)
|
|
{
|
|
short target_count= 0;
|
|
real distance= MAX(parameters->autoaim_distance, parameters->magnetism_distance);
|
|
real angle= MAX(parameters->autoaim_angle, parameters->magnetism_angle);
|
|
|
|
if (distance>0.f && angle>0.f)
|
|
{
|
|
real angle_sine= sine(angle);
|
|
real angle_cosine= cosine(angle);
|
|
short cluster_indices[MAXIMUM_AIM_ASSIST_CLUSTERS];
|
|
long object_indices[MAXIMUM_AIM_ASSIST_OBJECTS];
|
|
short cluster_count= structure_clusters_in_cone(cluster_index, position, direction, distance, angle_sine, angle_cosine,
|
|
NUMBEROF(cluster_indices), cluster_indices);
|
|
short object_count= objects_in_clusters_by_indices(FLAG(0), cluster_count, cluster_indices,
|
|
NUMBEROF(object_indices), object_indices); // collideable objects only
|
|
short object_number;
|
|
|
|
for (object_number= 0; object_number<object_count; ++object_number)
|
|
{
|
|
long object_index= object_indices[object_number];
|
|
|
|
target_count+= find_aim_assist_targets_recursive(parameters, object_index, position, direction,
|
|
distance, angle_sine, angle_cosine, ignore_object_index, ignore_team_index,
|
|
maximum_target_count - target_count, &targets[target_count]);
|
|
if (target_count>=maximum_target_count)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return target_count;
|
|
}
|
|
|
|
boolean aim_assist(
|
|
struct aim_assist_parameters const *parameters,
|
|
real_point3d const *position,
|
|
real_vector3d const *direction,
|
|
long ignore_object_index,
|
|
short ignore_team_index,
|
|
struct aim_assist_target *target)
|
|
{
|
|
if (scenario_leaf_index_from_point(position)!=NONE)
|
|
{
|
|
short cluster_index= TAG_BLOCK_GET_ELEMENT(
|
|
&global_structure_bsp_get()->leaves,
|
|
scenario_leaf_index_from_point(position) & LONG_MAX,
|
|
struct structure_leaf)->cluster_index;
|
|
|
|
if (cluster_index!=NONE)
|
|
{
|
|
struct aim_assist_target targets[MAXIMUM_AIM_ASSIST_TARGETS];
|
|
short target_count= find_aim_assist_targets(parameters, cluster_index, position, direction,
|
|
ignore_object_index, ignore_team_index, NUMBEROF(targets), targets);
|
|
|
|
if (target_count>0)
|
|
{
|
|
short target_index;
|
|
|
|
qsort(targets, target_count, sizeof(struct aim_assist_target), compare_targets);
|
|
for (target_index= 0; target_index<target_count; ++target_index)
|
|
{
|
|
if (aim_assist_clear_line_of_sight(position, &targets[target_index].position,
|
|
ignore_object_index, targets[target_index].object_index))
|
|
{
|
|
*target= targets[target_index];
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
long player_aim_projectile(
|
|
long player_index,
|
|
real_point3d const *position,
|
|
real_vector3d *direction)
|
|
{
|
|
long target_object_index= NONE;
|
|
struct player_datum *player= player_get(player_index);
|
|
long aiming_unit_index= unit_get_aiming_unit_index(player->unit_index);
|
|
struct aim_assist_parameters parameters;
|
|
|
|
match_assert_valid_real_normal3d(
|
|
"c:\\halo\\SOURCE\\game\\aim_assist.c",
|
|
77,
|
|
direction);
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\game\\aim_assist.c",
|
|
79,
|
|
global_current_collision_user_depth < MAXIMUM_COLLISION_USER_STACK_DEPTH);
|
|
global_current_collision_users[global_current_collision_user_depth++] = _collision_user_aim_assist;
|
|
|
|
if (unit_get_aim_assist_parameters(aiming_unit_index, unit_get_zoom_level(aiming_unit_index), ¶meters))
|
|
{
|
|
real_point3d camera_position;
|
|
real_vector3d camera_direction;
|
|
real_vector3d target_direction;
|
|
real_vector3d collision_direction;
|
|
real autoaim_level;
|
|
|
|
director_camera_deterministic(player->unit_index, &camera_position, &camera_direction);
|
|
target_direction= *direction;
|
|
autoaim_level= 0.f;
|
|
|
|
{
|
|
struct aim_assist_target target;
|
|
|
|
if (aim_assist(¶meters, &camera_position, &camera_direction, player->unit_index, player->team_index, &target))
|
|
{
|
|
vector_from_points3d(position, &target.position, &target_direction);
|
|
if (normalize3d(&target_direction)==0.f)
|
|
{
|
|
target_direction= *direction;
|
|
}
|
|
|
|
autoaim_level= target.autoaim_level;
|
|
target_object_index= target.object_index;
|
|
}
|
|
}
|
|
|
|
/* Trace from the camera at the aiming unit's distance along the camera direction. */
|
|
{
|
|
real_vector3d camera_vector;
|
|
struct collision_result collision;
|
|
real_vector3d camera_to_unit;
|
|
real_vector3d camera_displacement;
|
|
struct unit_datum *unit= unit_get(aiming_unit_index);
|
|
real camera_to_unit_distance;
|
|
|
|
vector_from_points3d(&unit->object.position, &camera_position, &camera_to_unit);
|
|
camera_to_unit_distance= magnitude3d(&camera_to_unit);
|
|
camera_displacement= camera_direction;
|
|
normalize3d(&camera_displacement);
|
|
scale_vector3d(&camera_displacement, camera_to_unit_distance, &camera_displacement);
|
|
set_real_point3d(&camera_position, camera_position.x + camera_displacement.i,
|
|
camera_position.y + camera_displacement.j, camera_position.z + camera_displacement.k);
|
|
scale_vector3d(&camera_direction, 128.f, &camera_vector);
|
|
collision_test_vector(_collision_test_for_projectiles_flags, &camera_position, &camera_vector,
|
|
player->unit_index, &collision);
|
|
|
|
vector_from_points3d(position, &collision.point, &collision_direction);
|
|
if (normalize3d(&collision_direction)==0.f)
|
|
{
|
|
collision_direction= *direction;
|
|
}
|
|
}
|
|
|
|
/* Blend toward the autoaim target, then pin inside the deviation cone. */
|
|
{
|
|
real_vector3d desired_direction;
|
|
|
|
fast_normals_interpolate(&collision_direction, &target_direction, autoaim_level, &desired_direction);
|
|
pin_normal_to_cone3d(&desired_direction, direction, sine(parameters.deviation_angle),
|
|
cosine(parameters.deviation_angle), direction);
|
|
}
|
|
}
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\game\\aim_assist.c",
|
|
140,
|
|
global_current_collision_user_depth > 1);
|
|
--global_current_collision_user_depth;
|
|
|
|
player->aim_assist_unit_index= target_object_index;
|
|
player->aim_assist_timestamp= game_time_get();
|
|
|
|
return target_object_index;
|
|
}
|
|
|
|
long local_player_aim_assist(
|
|
short local_player_index,
|
|
real *autoaim_level,
|
|
real *magnetism_level,
|
|
real_euler_angles2d *target_angular_position,
|
|
real_euler_angles2d *target_angular_velocity)
|
|
{
|
|
long target_index= NONE;
|
|
director_perspective perspective= director_get_perspective(local_player_index);
|
|
|
|
*autoaim_level= 0.f;
|
|
*magnetism_level= 0.f;
|
|
set_real_euler_angles2d(target_angular_position, 0.f, 0.f);
|
|
set_real_euler_angles2d(target_angular_velocity, 0.f, 0.f);
|
|
|
|
if (perspective==_director_perspective_first_person || perspective==_director_perspective_third_person)
|
|
{
|
|
struct player_datum *player= player_get(local_player_get_player_index(local_player_index));
|
|
long aiming_unit_index= unit_get_aiming_unit_index(player->unit_index);
|
|
struct aim_assist_parameters parameters;
|
|
|
|
if (unit_get_aim_assist_parameters(aiming_unit_index, player_control_get_zoom_level(local_player_index), ¶meters))
|
|
{
|
|
struct observer_result const *camera= observer_get_camera(local_player_index);
|
|
struct aim_assist_target target;
|
|
|
|
if (aim_assist(¶meters, &camera->position, &camera->forward, aiming_unit_index, player->team_index, &target))
|
|
{
|
|
real_vector3d velocity, target_velocity, magnetism_velocity;
|
|
|
|
*autoaim_level= target.autoaim_level;
|
|
*magnetism_level= target.magnetism_level;
|
|
euler_angles2d_from_vector3d(target_angular_position, &target.vector);
|
|
|
|
object_get_velocities(player->unit_index, &velocity, NULL);
|
|
object_get_velocities(target.object_index, &target_velocity, NULL);
|
|
subtract_vectors3d(&target_velocity, &velocity, &magnetism_velocity);
|
|
|
|
{
|
|
real_vector3d const *relative_position= &target.vector;
|
|
real_vector3d const *relative_velocity= &magnetism_velocity;
|
|
real horizontal_distance_squared= relative_position->i*relative_position->i +
|
|
relative_position->j*relative_position->j;
|
|
real horizontal_distance= square_root(horizontal_distance_squared);
|
|
|
|
target_angular_velocity->yaw= (relative_position->i*relative_velocity->j -
|
|
relative_position->j*relative_velocity->i)/horizontal_distance_squared;
|
|
target_angular_velocity->pitch= (horizontal_distance*relative_velocity->k -
|
|
relative_position->k/horizontal_distance*(relative_position->i*relative_velocity->i +
|
|
relative_position->j*relative_velocity->j))/(relative_position->k*relative_position->k +
|
|
horizontal_distance_squared);
|
|
}
|
|
|
|
target_index= target.object_index;
|
|
}
|
|
}
|
|
}
|
|
|
|
return target_index;
|
|
}
|