mirror of
https://github.com/Cesarus85/ringfall-mjolnir-vr.git
synced 2026-10-24 10:00:31 +02:00
1124 lines
28 KiB
C
1124 lines
28 KiB
C
/*
|
|
ACTOR_COMBAT.C
|
|
|
|
symbols in this file:
|
|
0000F590 0090:
|
|
_code_0000f590 (0000)
|
|
0000F620 0030:
|
|
_actor_combat_fire_wildly (0000)
|
|
0000F650 0040:
|
|
_actor_combat_disable_bursts (0000)
|
|
0000F690 0030:
|
|
_actor_firing_blindly (0000)
|
|
0000F6C0 0040:
|
|
_actor_combat_currently_firing_burst (0000)
|
|
0000F700 0040:
|
|
_actor_get_weapon_definition (0000)
|
|
0000F740 00c0:
|
|
_actor_get_weapon_vector (0000)
|
|
0000F800 0080:
|
|
_actor_combat_get_firing_variant_definition (0000)
|
|
0000F880 00a0:
|
|
_code_0000f880 (0000)
|
|
0000F920 0040:
|
|
_code_0000f920 (0000)
|
|
0000F960 0020:
|
|
_fast_ftol (0000)
|
|
0000F980 0010:
|
|
_sine (0000)
|
|
0000F990 0010:
|
|
_cosine (0000)
|
|
0000F9A0 0010:
|
|
_tangent (0000)
|
|
0000F9B0 0020:
|
|
_cross_product2d (0000)
|
|
0000F9D0 0030:
|
|
_add_vectors3d (0000)
|
|
0000FA00 0020:
|
|
_random_boolean (0000)
|
|
0000FA20 0020:
|
|
_valid_real (0000)
|
|
0000FA40 0160:
|
|
_actor_combat_find_nearby_target (0000)
|
|
0000FBA0 00b0:
|
|
_code_0000fba0 (0000)
|
|
0000FC50 00d0:
|
|
_code_0000fc50 (0000)
|
|
0000FD20 01c0:
|
|
_actor_combat_reaim_grenade (0000)
|
|
0000FEE0 0110:
|
|
_actor_combat_build_grenade_trajectory (0000)
|
|
0000FFF0 0100:
|
|
_actor_combat_find_grenade_target (0000)
|
|
000100F0 0370:
|
|
_actor_combat_check_collateral_damage (0000)
|
|
00010460 0120:
|
|
_actor_combat_plan_grenade_trajectory (0000)
|
|
00010580 0040:
|
|
_valid_realcmp (0000)
|
|
000105C0 0060:
|
|
_valid_real_normal3d (0000)
|
|
00010620 00b0:
|
|
_code_00010620 (0000)
|
|
000106D0 02d0:
|
|
_actor_aim_projectile (0000)
|
|
000109A0 07b0:
|
|
_code_000109a0 (0000)
|
|
00011150 0060:
|
|
_actor_combat_retarget_grenade (0000)
|
|
000111B0 0220:
|
|
_actor_aim_grenade (0000)
|
|
000113D0 1240:
|
|
_actor_combat_update (0000)
|
|
002444A0 000e:
|
|
??_C@_0O@HEGILGAC@weapon_vector?$AA@ (0000)
|
|
002444B0 0021:
|
|
??_C@_0CB@NKOAMEKE@c?3?2halo?2SOURCE?2ai?2actor_combat?4c@ (0000)
|
|
002444D4 0035:
|
|
??_C@_0DF@COLBENAC@burst_geometry_reference?5?$CG?$CG?5firi@ (0000)
|
|
0024450C 0004:
|
|
__real@3dcccccd (0000)
|
|
00244510 0004:
|
|
__real@3fd9999a (0000)
|
|
00244514 0016:
|
|
??_C@_0BG@ODFAEBCF@projectile_definition?$AA@ (0000)
|
|
00244530 0042:
|
|
??_C@_0EC@CDIDOCJH@grenade_origin?5?$CG?$CG?5desired_impact@ (0000)
|
|
00244574 0004:
|
|
__real@3e4ccccd (0000)
|
|
00244578 0008:
|
|
__real@3f50624de0000000 (0000)
|
|
00244580 0043:
|
|
??_C@_0ED@MKICAFGB@actor?9?$DOcontrol?4current_fire_targ@ (0000)
|
|
002445C4 002b:
|
|
??_C@_0CL@GJIEKICC@?$CFs?3?5assert_valid_real_normal3d?$CI?$CF@ (0000)
|
|
002445F0 0007:
|
|
??_C@_06NBFPPGEG@vector?$AA@ (0000)
|
|
002445F8 0004:
|
|
__real@3f490fdb (0000)
|
|
002445FC 003b:
|
|
??_C@_0DL@NNPMKEAI@?$CFs?3?5proj?5?$CF?41f?5rof?5?$CF?41f?5dmg?1s?5?$CF?41@ (0000)
|
|
00244638 0020:
|
|
??_C@_0CA@FHOKFHD@?$CFs?3?5manual?5damage?5modifier?5?$CF?42f?$AA@ (0000)
|
|
00244658 0010:
|
|
??_C@_0BA@FHPPJCFM@?$CGnew_aim_vector?$AA@ (0000)
|
|
00244668 0021:
|
|
??_C@_0CB@CPANGHMG@?$CGactor?9?$DOcontrol?4burst_aim_vector@ (0000)
|
|
0024468C 000f:
|
|
??_C@_0P@DBEDAMI@aiming_success?$AA@ (0000)
|
|
0024469C 0012:
|
|
??_C@_0BC@CHLPMLFC@?$CBhold_burst_start?$AA@ (0000)
|
|
002446B0 0025:
|
|
??_C@_0CF@EHKIDLPJ@new_state?$CB?$DNactor?9?$DOcontrol?4fire_s@ (0000)
|
|
002446D8 0018:
|
|
??_C@_0BI@MMOBPCCM@firing_decision?5?$DN?$DN?5NONE?$AA@ (0000)
|
|
002446F0 0004:
|
|
__real@3f3504f3 (0000)
|
|
002446F4 0004:
|
|
__real@3e3377ed (0000)
|
|
002446F8 004b:
|
|
??_C@_0EL@FHBLJBEG@actor?9?$DOcontrol?4current_fire_targ@ (0000)
|
|
00244744 0015:
|
|
??_C@_0BF@GLLAMKHP@weapon_index?5?$CB?$DN?5NONE?$AA@ (0000)
|
|
0024475C 0036:
|
|
??_C@_0DG@EHGBJHNC@actor?9?$DOcontrol?4current_fire_targ@ (0000)
|
|
*/
|
|
|
|
/* ---------- headers */
|
|
|
|
#define cosine cosine_inline
|
|
#define sine sine_inline
|
|
#define tangent tangent_inline
|
|
#define cross_product2d cross_product2d_inline
|
|
#define normalize2d normalize2d_inline
|
|
#define normalize3d normalize3d_inline
|
|
#define add_vectors3d add_vectors3d_inline
|
|
#define point_from_line3d actor_combat_point_from_line3d_inline
|
|
#define vector_from_points3d actor_combat_vector_from_points3d_inline
|
|
#define magnitude_squared3d actor_combat_magnitude_squared3d_inline
|
|
#define distance_squared3d actor_combat_distance_squared3d_inline
|
|
#define real_random_range actor_combat_real_random_range_inline
|
|
#define collision_test_line actor_combat_collision_test_line_inline
|
|
#include "cseries.h"
|
|
|
|
#include "ai.h"
|
|
#include "ai_debug.h"
|
|
#include "actor_definitions.h"
|
|
#include "actors.h"
|
|
#include "encounters.h"
|
|
#include "props.h"
|
|
#include "items/projectile_definitions.h"
|
|
#include "items/projectiles.h"
|
|
#include "items/weapon_definitions.h"
|
|
#include "items/weapons.h"
|
|
#include "game/game_globals.h"
|
|
#include "game/game.h"
|
|
#include "physics/collisions.h"
|
|
#include "scenario/scenario.h"
|
|
#include "units/vehicle_definitions.h"
|
|
#include "units/vehicles.h"
|
|
#undef collision_test_line
|
|
#undef real_random_range
|
|
#undef distance_squared3d
|
|
#undef magnitude_squared3d
|
|
#undef vector_from_points3d
|
|
#undef point_from_line3d
|
|
#undef add_vectors3d
|
|
#undef normalize3d
|
|
#undef normalize2d
|
|
#undef cross_product2d
|
|
#undef cosine
|
|
#undef sine
|
|
#undef tangent
|
|
|
|
/* ---------- constants */
|
|
|
|
enum
|
|
{
|
|
_actor_fire_target_none = 0,
|
|
_actor_fire_target_prop,
|
|
|
|
_vehicle_ai_weapon_cannot_rotate_bit = 8,
|
|
|
|
MAXIMUM_COLLATERAL_DAMAGE_ACTORS = 32,
|
|
};
|
|
|
|
/* ---------- macros */
|
|
|
|
#define GRENADE_AIMING_ANGLE_COSINE 0.8660254f
|
|
#define GRENADE_AIMING_ANGLE_SINE 0.5f
|
|
#define actor_combat_vehicle_definition_get(index) \
|
|
((struct actor_combat_vehicle_definition_view *)vehicle_specific_definition_get(index))
|
|
|
|
/* ---------- structures */
|
|
|
|
struct encounter_actor_iterator
|
|
{
|
|
long encounter_index;
|
|
long index;
|
|
long next_index;
|
|
};
|
|
|
|
struct actor_combat_vehicle_definition_view
|
|
{
|
|
byte __unknown0[0x2F0];
|
|
unsigned long flags;
|
|
};
|
|
|
|
typedef char actor_combat_vehicle_definition_flags_offset_assert[
|
|
offsetof(struct actor_combat_vehicle_definition_view, flags) == 0x2F0 ? 1 : -1];
|
|
|
|
/* ---------- prototypes */
|
|
|
|
static void actor_combat_find_nearby_target(
|
|
real_point3d *target_point,
|
|
real miss_distance);
|
|
static void actor_get_weapon_vector(
|
|
long actor_index,
|
|
real_vector3d *weapon_vector);
|
|
/* The owner declarations in actions.h are macro-renamed while importing the
|
|
* January inline set; restore the external names after that schedule ends. */
|
|
real normalize2d(
|
|
real_vector2d *vector);
|
|
real normalize3d(
|
|
real_vector3d *vector);
|
|
static boolean actor_combat_build_grenade_trajectory(
|
|
short grenade_type_index,
|
|
real_point3d const *grenade_origin,
|
|
real velocity_max,
|
|
real_point3d const *desired_impact_point,
|
|
real *target_ballistic_fraction_min,
|
|
boolean lob,
|
|
real_vector3d *aim_vector,
|
|
real *aim_speed,
|
|
real *aim_ticks,
|
|
real_vector3d *aim_velocity,
|
|
real *aim_gravity);
|
|
static boolean actor_combat_reaim_grenade(
|
|
long actor_index,
|
|
real_point3d const *grenade_origin);
|
|
static boolean actor_combat_retarget_grenade(
|
|
long actor_index,
|
|
real_point3d const *desired_grenade_target);
|
|
|
|
/* ---------- globals */
|
|
|
|
/* ---------- public code */
|
|
|
|
void actor_combat_fire_wildly(
|
|
long actor_index,
|
|
short fire_ticks)
|
|
{
|
|
struct actor_datum *actor = actor_get(actor_index);
|
|
|
|
actor->control.fire_state = _actor_fire_state_wild;
|
|
actor->control.fire_state_timer = fire_ticks;
|
|
|
|
return;
|
|
}
|
|
|
|
void actor_combat_disable_bursts(
|
|
long actor_index,
|
|
long disable_timer)
|
|
{
|
|
struct actor_datum *actor = actor_get(actor_index);
|
|
|
|
actor->control.burst_disable_timer =
|
|
MAX(actor->control.burst_disable_timer, disable_timer);
|
|
|
|
return;
|
|
}
|
|
|
|
boolean actor_firing_blindly(
|
|
long actor_index)
|
|
{
|
|
struct actor_datum *actor = actor_get(actor_index);
|
|
|
|
return actor->control.fire_state == _actor_fire_state_wild;
|
|
}
|
|
|
|
boolean actor_combat_currently_firing_burst(
|
|
long actor_index)
|
|
{
|
|
struct actor_datum *actor = actor_get(actor_index);
|
|
boolean result = FALSE;
|
|
|
|
if (actor->control.current_fire_target_type > _actor_fire_target_none)
|
|
{
|
|
result = actor->control.fire_state == _actor_fire_state_bursting;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
struct weapon_definition *actor_get_weapon_definition(
|
|
long actor_index)
|
|
{
|
|
struct weapon_definition *result = NULL;
|
|
long weapon_index = actor_get_weapon(actor_index);
|
|
|
|
if (weapon_index != NONE)
|
|
{
|
|
struct weapon_datum *weapon = weapon_get(weapon_index);
|
|
result = weapon_definition_get(weapon->definition_index);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static void actor_get_weapon_vector(
|
|
long actor_index,
|
|
real_vector3d *weapon_vector)
|
|
{
|
|
struct actor_datum *actor = actor_get(actor_index);
|
|
long unit_index = actor->meta.unit_index;
|
|
boolean have_vector = FALSE;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\ai\\actor_combat.c",
|
|
1166,
|
|
weapon_vector);
|
|
|
|
if (actor->input.vehicle_gunner)
|
|
{
|
|
struct unit_datum *vehicle = vehicle_get(actor->input.vehicle_index);
|
|
struct actor_combat_vehicle_definition_view *vehicle_definition =
|
|
actor_combat_vehicle_definition_get(vehicle->definition_index);
|
|
|
|
unit_index = actor->input.vehicle_index;
|
|
if (TEST_FLAG(
|
|
vehicle_definition->flags,
|
|
_vehicle_ai_weapon_cannot_rotate_bit))
|
|
{
|
|
*weapon_vector = vehicle->object.forward;
|
|
have_vector = TRUE;
|
|
}
|
|
}
|
|
|
|
if (!have_vector)
|
|
{
|
|
unit_get(unit_index);
|
|
unit_get_aiming_vector(unit_index, weapon_vector);
|
|
unit_clip_to_aiming_bounds(unit_index, weapon_vector, TRUE);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
struct actor_variant_definition *actor_combat_get_firing_variant_definition(
|
|
long actor_index)
|
|
{
|
|
struct actor_datum *actor = actor_get(actor_index);
|
|
struct actor_variant_definition *firing_variant_definition =
|
|
actor_variant_definition_get(actor->meta.variant_definition_index);
|
|
long weapon_index = actor_get_weapon(actor_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 (weapon_definition != NULL &&
|
|
weapon_definition->weapon.ai_firing_parameters.index != NONE)
|
|
{
|
|
firing_variant_definition = actor_variant_definition_get(
|
|
weapon_definition->weapon.ai_firing_parameters.index);
|
|
}
|
|
}
|
|
|
|
return firing_variant_definition;
|
|
}
|
|
|
|
real sine(
|
|
real angle)
|
|
{
|
|
return sin(angle);
|
|
}
|
|
|
|
real cosine(
|
|
real angle)
|
|
{
|
|
return cos(angle);
|
|
}
|
|
|
|
real tangent(
|
|
real angle)
|
|
{
|
|
return tan(angle);
|
|
}
|
|
|
|
real cross_product2d(
|
|
real_vector2d const *a,
|
|
real_vector2d const *b)
|
|
{
|
|
return a->i*b->j - a->j*b->i;
|
|
}
|
|
|
|
real_vector3d *add_vectors3d(
|
|
real_vector3d const *a,
|
|
real_vector3d const *b,
|
|
real_vector3d *result)
|
|
{
|
|
result->i = a->i+b->i;
|
|
result->j = a->j+b->j;
|
|
result->k = a->k+b->k;
|
|
|
|
return result;
|
|
}
|
|
|
|
static void actor_combat_find_nearby_target(
|
|
real_point3d *target_point,
|
|
real miss_distance)
|
|
{
|
|
real_point3d above;
|
|
real_point3d target;
|
|
real_vector3d direction;
|
|
struct collision_result collision;
|
|
|
|
/* Keep January's inlined real-math schedule without materializing the
|
|
* header helpers as actor_combat-owned COMDATs. */
|
|
above.x = global_up3d->i*1.5f + target_point->x;
|
|
above.y = global_up3d->j*1.5f + target_point->y;
|
|
above.z = global_up3d->k*1.5f + target_point->z;
|
|
vector3d_from_angle(
|
|
&direction,
|
|
real_seed_random_range(get_global_random_seed_address(), -_pi, _pi));
|
|
target.x = direction.i*miss_distance + above.x;
|
|
target.y = direction.j*miss_distance + above.y;
|
|
target.z = direction.k*miss_distance + above.z;
|
|
|
|
{
|
|
real_vector3d collision_vector;
|
|
|
|
collision_vector.i = above.x - target_point->x;
|
|
collision_vector.j = above.y - target_point->y;
|
|
collision_vector.k = above.z - target_point->z;
|
|
if (collision_test_vector(
|
|
FLAG(_collision_test_front_facing_surfaces_bit) |
|
|
FLAG(_collision_test_back_facing_surfaces_bit) |
|
|
FLAG(_collision_test_structure_bit),
|
|
target_point,
|
|
&collision_vector,
|
|
NONE,
|
|
&collision))
|
|
{
|
|
above = *target_point;
|
|
}
|
|
}
|
|
|
|
{
|
|
real_vector3d collision_vector;
|
|
|
|
collision_vector.i = target.x - above.x;
|
|
collision_vector.j = target.y - above.y;
|
|
collision_vector.k = target.z - above.z;
|
|
if (collision_test_vector(
|
|
FLAG(_collision_test_front_facing_surfaces_bit) |
|
|
FLAG(_collision_test_back_facing_surfaces_bit) |
|
|
FLAG(_collision_test_structure_bit),
|
|
&above,
|
|
&collision_vector,
|
|
NONE,
|
|
&collision))
|
|
{
|
|
real distance = MAX(0.0f, collision.t*miss_distance - 0.1f);
|
|
|
|
target.x = direction.i*distance + above.x;
|
|
target.y = direction.j*distance + above.y;
|
|
target.z = direction.k*distance + above.z;
|
|
}
|
|
}
|
|
|
|
*target_point = target;
|
|
|
|
return;
|
|
}
|
|
|
|
static boolean actor_combat_reaim_grenade(
|
|
long actor_index,
|
|
real_point3d const *grenade_origin)
|
|
{
|
|
struct actor_datum *actor = actor_get(actor_index);
|
|
struct actor_variant_definition *variant_definition =
|
|
actor_variant_definition_get(actor->meta.variant_definition_index);
|
|
short grenade_type_index = variant_definition->grenade_combat.grenade_type;
|
|
struct game_globals_grenade *grenade = TAG_BLOCK_GET_ELEMENT(
|
|
&scenario_get_game_globals()->grenades,
|
|
grenade_type_index,
|
|
struct game_globals_grenade);
|
|
struct projectile_definition *projectile_definition = NULL;
|
|
real aim_gravity;
|
|
real_vector2d aim_vector2d;
|
|
real_vector3d aim_vector;
|
|
real aim_speed;
|
|
real aim_ticks;
|
|
boolean linear;
|
|
boolean result = FALSE;
|
|
|
|
if (grenade && grenade->projectile.index != NONE)
|
|
{
|
|
projectile_definition =
|
|
projectile_definition_get(grenade->projectile.index);
|
|
}
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\ai\\actor_combat.c",
|
|
1731,
|
|
projectile_definition);
|
|
|
|
if (projectile_aim(
|
|
projectile_definition,
|
|
grenade_origin,
|
|
&actor->control.grenade_current_target,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&actor->control.grenade_current_aim_speed,
|
|
actor->control.grenade_current_lob,
|
|
&aim_vector,
|
|
&aim_speed,
|
|
&aim_ticks,
|
|
NULL,
|
|
&linear))
|
|
{
|
|
aim_vector2d.i = aim_vector.i;
|
|
aim_vector2d.j = aim_vector.j;
|
|
|
|
if (normalize2d(&aim_vector2d) > 0.0f &&
|
|
aim_vector2d.i*actor->input.facing_vector.i +
|
|
aim_vector2d.j*actor->input.facing_vector.j >
|
|
GRENADE_AIMING_ANGLE_COSINE)
|
|
{
|
|
real_vector3d aim_velocity;
|
|
|
|
aim_velocity.i = aim_vector.i*aim_speed;
|
|
aim_velocity.j = aim_vector.j*aim_speed;
|
|
aim_velocity.k = aim_vector.k*aim_speed;
|
|
|
|
aim_gravity = linear ?
|
|
0.0f :
|
|
projectile_get_ballistic_acceleration(projectile_definition);
|
|
|
|
if (ai_test_ballistic_line_of_fire(
|
|
actor_index,
|
|
grenade_origin,
|
|
aim_ticks,
|
|
&aim_velocity,
|
|
aim_gravity,
|
|
actor->control.grenade_current_ignore_object_index,
|
|
actor->input.vehicle_index != NONE))
|
|
{
|
|
actor->control.grenade_current_aim_vector = aim_vector;
|
|
actor->control.grenade_current_aim_speed = aim_speed;
|
|
result = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static boolean actor_combat_build_grenade_trajectory(
|
|
short grenade_type_index,
|
|
real_point3d const *grenade_origin,
|
|
real velocity_max,
|
|
real_point3d const *desired_impact_point,
|
|
real *target_ballistic_fraction_min,
|
|
boolean lob,
|
|
real_vector3d *aim_vector,
|
|
real *aim_speed,
|
|
real *aim_ticks,
|
|
real_vector3d *aim_velocity,
|
|
real *aim_gravity)
|
|
{
|
|
boolean result = FALSE;
|
|
struct game_globals_grenade *grenade;
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\ai\\actor_combat.c",
|
|
1780,
|
|
grenade_origin && desired_impact_point && aim_vector && aim_speed);
|
|
|
|
grenade = TAG_BLOCK_GET_ELEMENT(
|
|
&scenario_get_game_globals()->grenades,
|
|
grenade_type_index,
|
|
struct game_globals_grenade);
|
|
|
|
if (grenade && grenade->projectile.index != NONE)
|
|
{
|
|
struct projectile_definition *projectile_definition =
|
|
projectile_definition_get(grenade->projectile.index);
|
|
|
|
if (projectile_definition)
|
|
{
|
|
boolean linear = FALSE;
|
|
|
|
if (projectile_aim(
|
|
projectile_definition,
|
|
grenade_origin,
|
|
desired_impact_point,
|
|
&velocity_max,
|
|
NULL,
|
|
target_ballistic_fraction_min,
|
|
NULL,
|
|
FALSE,
|
|
aim_vector,
|
|
aim_speed,
|
|
aim_ticks,
|
|
NULL,
|
|
&linear))
|
|
{
|
|
result = TRUE;
|
|
|
|
if (aim_velocity)
|
|
{
|
|
real speed = *aim_speed;
|
|
|
|
aim_velocity->i = speed*aim_vector->i;
|
|
aim_velocity->j = speed*aim_vector->j;
|
|
aim_velocity->k = speed*aim_vector->k;
|
|
}
|
|
|
|
if (aim_gravity)
|
|
{
|
|
*aim_gravity = linear ?
|
|
0.0f :
|
|
projectile_get_ballistic_acceleration(projectile_definition);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
boolean actor_combat_find_grenade_target(
|
|
long actor_index,
|
|
real_point3d *grenade_target,
|
|
long *grenade_target_prop_index,
|
|
long *grenade_ignore_object_index)
|
|
{
|
|
struct actor_datum *actor = actor_get(actor_index);
|
|
struct actor_variant_definition *variant_definition =
|
|
actor_variant_definition_get(actor->meta.variant_definition_index);
|
|
boolean result = FALSE;
|
|
|
|
if (actor->target.target_prop_index != NONE)
|
|
{
|
|
struct prop_datum *prop = prop_get(actor->target.target_prop_index);
|
|
|
|
if (prop->enemy &&
|
|
!prop->dead &&
|
|
((prop->state >= _prop_state_becoming_unacknowledged &&
|
|
prop->state <= _prop_state_acknowledged) ||
|
|
prop->state == _prop_state_uninspected_orphan) &&
|
|
prop->distance > variant_definition->grenade_combat.grenade_range_lower_bound &&
|
|
prop->distance < variant_definition->grenade_combat.grenade_range_upper_bound)
|
|
{
|
|
*grenade_target = prop->body_position;
|
|
grenade_target->z += 0.2f;
|
|
*grenade_target_prop_index = actor->target.target_prop_index;
|
|
*grenade_ignore_object_index = prop->vehicle_index;
|
|
result = TRUE;
|
|
|
|
if (actor->external_orders.playfighting)
|
|
{
|
|
actor_combat_find_nearby_target(grenade_target, 1.5f);
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
boolean actor_combat_check_collateral_damage(
|
|
long actor_index,
|
|
real enemy_radius,
|
|
real collateral_damage_radius,
|
|
real_point3d const *test_point,
|
|
short *threat_count)
|
|
{
|
|
struct actor_datum *actor = actor_get(actor_index);
|
|
boolean result;
|
|
short threats;
|
|
short counted_actor_count;
|
|
long counted_actor_indices[MAXIMUM_COLLATERAL_DAMAGE_ACTORS];
|
|
|
|
/* Preserve the original tag validation before iterating combat state. */
|
|
actor_variant_definition_get(actor->meta.variant_definition_index);
|
|
result = TRUE;
|
|
threats = 0;
|
|
counted_actor_count = 0;
|
|
|
|
{
|
|
struct prop_iterator prop_iterator;
|
|
struct prop_datum *prop;
|
|
|
|
prop_iterator_new(&prop_iterator, actor_index);
|
|
for (prop = prop_iterator_next(&prop_iterator);
|
|
prop;
|
|
prop = prop_iterator_next(&prop_iterator))
|
|
{
|
|
if (prop->state >= _prop_state_becoming_unacknowledged &&
|
|
prop->state <= _prop_state_acknowledged &&
|
|
!prop->dead)
|
|
{
|
|
if (prop->enemy)
|
|
{
|
|
real_vector3d displacement;
|
|
|
|
displacement.i = test_point->x - prop->body_position.x;
|
|
displacement.j = test_point->y - prop->body_position.y;
|
|
displacement.k = test_point->z - prop->body_position.z;
|
|
if (displacement.i*displacement.i +
|
|
displacement.j*displacement.j +
|
|
displacement.k*displacement.k <
|
|
enemy_radius*enemy_radius)
|
|
{
|
|
if (prop->player)
|
|
{
|
|
threats += 10;
|
|
}
|
|
else if (prop->vehicle_index != NONE)
|
|
{
|
|
threats += 5;
|
|
}
|
|
else if (prop->actor_index != NONE)
|
|
{
|
|
if (counted_actor_count < NUMBEROF(counted_actor_indices))
|
|
{
|
|
counted_actor_indices[counted_actor_count++] = prop->actor_index;
|
|
}
|
|
|
|
if (prop->swarm)
|
|
{
|
|
threats += actor_get(prop->actor_index)->meta.swarm_unit_count;
|
|
}
|
|
else
|
|
{
|
|
threats++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (collateral_damage_radius > 0.0f)
|
|
{
|
|
real_vector3d displacement;
|
|
|
|
displacement.i = test_point->x - prop->body_position.x;
|
|
displacement.j = test_point->y - prop->body_position.y;
|
|
displacement.k = test_point->z - prop->body_position.z;
|
|
if (displacement.i*displacement.i +
|
|
displacement.j*displacement.j +
|
|
displacement.k*displacement.k <
|
|
collateral_damage_radius*collateral_damage_radius)
|
|
{
|
|
result = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (enemy_radius > 0.0f && actor->target.target_prop_index != NONE)
|
|
{
|
|
struct prop_datum *target_prop = prop_get(actor->target.target_prop_index);
|
|
|
|
if (target_prop->actor_index != NONE)
|
|
{
|
|
struct actor_datum *target_actor = actor_get(target_prop->actor_index);
|
|
|
|
if (target_actor->meta.encounter_index != NONE)
|
|
{
|
|
struct encounter_actor_iterator actor_iterator;
|
|
struct actor_datum *enemy_actor;
|
|
|
|
encounter_actor_iterator_new(
|
|
&actor_iterator,
|
|
target_actor->meta.encounter_index);
|
|
for (enemy_actor = encounter_actor_iterator_next(&actor_iterator);
|
|
enemy_actor;
|
|
enemy_actor = encounter_actor_iterator_next(&actor_iterator))
|
|
{
|
|
short index;
|
|
boolean already_counted = FALSE;
|
|
|
|
for (index = 0; index < counted_actor_count; index++)
|
|
{
|
|
if (counted_actor_indices[index] == actor_iterator.index)
|
|
{
|
|
already_counted = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!already_counted)
|
|
{
|
|
real_vector3d displacement;
|
|
|
|
displacement.i = test_point->x -
|
|
enemy_actor->input.position.body_position.x;
|
|
displacement.j = test_point->y -
|
|
enemy_actor->input.position.body_position.y;
|
|
displacement.k = test_point->z -
|
|
enemy_actor->input.position.body_position.z;
|
|
if (displacement.i*displacement.i +
|
|
displacement.j*displacement.j +
|
|
displacement.k*displacement.k <
|
|
enemy_radius*enemy_radius)
|
|
{
|
|
if (enemy_actor->meta.swarm)
|
|
{
|
|
threats += enemy_actor->meta.swarm_unit_count;
|
|
}
|
|
else
|
|
{
|
|
threats++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (result && actor->meta.encounter_index != NONE && collateral_damage_radius > 0.0f)
|
|
{
|
|
struct encounter_actor_iterator actor_iterator;
|
|
struct actor_datum *friend_actor;
|
|
|
|
encounter_actor_iterator_new(
|
|
&actor_iterator,
|
|
actor->meta.encounter_index);
|
|
for (friend_actor = encounter_actor_iterator_next(&actor_iterator);
|
|
friend_actor;
|
|
friend_actor = encounter_actor_iterator_next(&actor_iterator))
|
|
{
|
|
real_vector3d displacement;
|
|
|
|
displacement.i = test_point->x -
|
|
friend_actor->input.position.body_position.x;
|
|
displacement.j = test_point->y -
|
|
friend_actor->input.position.body_position.y;
|
|
displacement.k = test_point->z -
|
|
friend_actor->input.position.body_position.z;
|
|
if (displacement.i*displacement.i +
|
|
displacement.j*displacement.j +
|
|
displacement.k*displacement.k <
|
|
collateral_damage_radius*collateral_damage_radius)
|
|
{
|
|
result = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (threat_count)
|
|
{
|
|
*threat_count = threats;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
boolean actor_combat_plan_grenade_trajectory(
|
|
long actor_index,
|
|
short trajectory_type,
|
|
real_point3d const *grenade_target,
|
|
long grenade_target_prop_index,
|
|
long grenade_ignore_object_index)
|
|
{
|
|
struct actor_datum *actor = actor_get(actor_index);
|
|
struct actor_variant_definition *variant_definition =
|
|
actor_variant_definition_get(actor->meta.variant_definition_index);
|
|
real_point3d grenade_origin = actor->input.position.head_position;
|
|
real_vector3d aim_vector;
|
|
real_vector3d aim_velocity;
|
|
real aim_speed;
|
|
real aim_ticks;
|
|
real aim_gravity;
|
|
boolean result = FALSE;
|
|
|
|
if (actor_combat_build_grenade_trajectory(
|
|
variant_definition->grenade_combat.grenade_type,
|
|
&grenade_origin,
|
|
variant_definition->grenade_combat.grenade_maximum_velocity,
|
|
grenade_target,
|
|
NULL,
|
|
FALSE,
|
|
&aim_vector,
|
|
&aim_speed,
|
|
&aim_ticks,
|
|
&aim_velocity,
|
|
&aim_gravity) &&
|
|
ai_test_ballistic_line_of_fire(
|
|
actor_index,
|
|
&grenade_origin,
|
|
aim_ticks,
|
|
&aim_velocity,
|
|
aim_gravity,
|
|
grenade_ignore_object_index,
|
|
actor->input.vehicle_index != NONE))
|
|
{
|
|
actor->control.grenade_current_target = *grenade_target;
|
|
actor->control.grenade_current_prop_index = grenade_target_prop_index;
|
|
actor->control.grenade_current_ignore_object_index = grenade_ignore_object_index;
|
|
actor->control.grenade_current_aim_vector = aim_vector;
|
|
actor->control.grenade_current_aim_speed = aim_speed;
|
|
actor->control.grenade_current_lob = FALSE;
|
|
|
|
result = TRUE;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
long actor_aim_projectile(
|
|
long actor_index,
|
|
real_point3d const *origin,
|
|
real_vector3d *vector,
|
|
real *error_reference)
|
|
{
|
|
struct actor_datum *actor = actor_get(actor_index);
|
|
long target_unit_index = NONE;
|
|
|
|
if (actor->control.fire_state == _actor_fire_state_bursting)
|
|
{
|
|
struct actor_debug_info *actor_debug_info =
|
|
&actor_debug_array[DATUM_INDEX_TO_ABSOLUTE_INDEX(actor_index)];
|
|
real_vector3d weapon_vector;
|
|
real alignment;
|
|
|
|
actor_debug_info->last_projectile_aiming_time = game_time_get();
|
|
|
|
if (actor->control.current_fire_target_type == _actor_fire_target_prop &&
|
|
actor->control.current_fire_target_prop_index != NONE)
|
|
{
|
|
struct prop_datum *prop =
|
|
prop_get(actor->control.current_fire_target_prop_index);
|
|
|
|
if (prop->state >= _prop_state_becoming_unacknowledged &&
|
|
prop->state <= _prop_state_acknowledged)
|
|
{
|
|
target_unit_index = prop->unit_index;
|
|
}
|
|
}
|
|
|
|
match_assert(
|
|
"c:\\halo\\SOURCE\\ai\\actor_combat.c",
|
|
1071,
|
|
vector);
|
|
|
|
actor_debug_info->field_60 = actor->control.burst_aim_by_vector;
|
|
actor_debug_info->field_64 = *origin;
|
|
|
|
if (actor->control.burst_aim_by_vector)
|
|
{
|
|
*vector = actor->control.burst_aim_vector;
|
|
}
|
|
else
|
|
{
|
|
real_point3d const *burst_target = &actor->control.burst_target;
|
|
|
|
actor_debug_info->field_7C = *burst_target;
|
|
vector->i = burst_target->x - origin->x;
|
|
vector->j = burst_target->y - origin->y;
|
|
vector->k = burst_target->z - origin->z;
|
|
normalize3d(vector);
|
|
}
|
|
|
|
match_assert_valid_real_normal3d(
|
|
"c:\\halo\\SOURCE\\ai\\actor_combat.c",
|
|
1090,
|
|
vector);
|
|
actor_debug_info->field_70 = *vector;
|
|
|
|
actor_get_weapon_vector(actor_index, &weapon_vector);
|
|
alignment = dot_product3d(&weapon_vector, vector);
|
|
if (alignment < GRENADE_AIMING_ANGLE_COSINE)
|
|
{
|
|
real_vector3d rotation_axis;
|
|
boolean aiming_success = TRUE;
|
|
|
|
cross_product3d(&weapon_vector, vector, &rotation_axis);
|
|
if (normalize3d(&rotation_axis) == 0.0f)
|
|
{
|
|
perpendicular3d(&weapon_vector, &rotation_axis);
|
|
if (normalize3d(&rotation_axis) == 0.0f)
|
|
{
|
|
aiming_success = FALSE;
|
|
}
|
|
}
|
|
|
|
*vector = weapon_vector;
|
|
if (aiming_success)
|
|
{
|
|
rotate_vector_about_axis(
|
|
vector,
|
|
&rotation_axis,
|
|
GRENADE_AIMING_ANGLE_SINE,
|
|
GRENADE_AIMING_ANGLE_COSINE);
|
|
}
|
|
|
|
actor_debug_info->field_98 = weapon_vector;
|
|
actor_debug_info->field_88 = TRUE;
|
|
actor_debug_info->field_8C = *vector;
|
|
}
|
|
else
|
|
{
|
|
actor_debug_info->field_88 = FALSE;
|
|
}
|
|
|
|
*error_reference = actor->control.burst_error;
|
|
}
|
|
|
|
return target_unit_index;
|
|
}
|
|
|
|
static boolean actor_combat_retarget_grenade(
|
|
long actor_index,
|
|
real_point3d const *desired_grenade_target)
|
|
{
|
|
struct actor_datum *actor = actor_get(actor_index);
|
|
struct actor_variant_definition *variant_definition =
|
|
actor_variant_definition_get(actor->meta.variant_definition_index);
|
|
boolean result = FALSE;
|
|
|
|
if (actor_combat_check_collateral_damage(
|
|
actor_index,
|
|
variant_definition->grenade_combat.enemy_radius,
|
|
variant_definition->grenade_combat.collateral_damage_radius,
|
|
desired_grenade_target,
|
|
NULL))
|
|
{
|
|
actor->control.grenade_current_target = *desired_grenade_target;
|
|
result = TRUE;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
long actor_aim_grenade(
|
|
long actor_index,
|
|
real_point3d const *origin,
|
|
real_vector3d *vector)
|
|
{
|
|
struct actor_datum *actor = actor_get(actor_index);
|
|
real_vector3d aim_vector;
|
|
long target_unit_index = NONE;
|
|
|
|
if (actor->control.grenade_current_prop_index != NONE)
|
|
{
|
|
struct prop_datum *prop = prop_get(actor->control.grenade_current_prop_index);
|
|
|
|
if (prop->state >= _prop_state_becoming_unacknowledged &&
|
|
prop->state <= _prop_state_acknowledged)
|
|
{
|
|
target_unit_index = prop->unit_index;
|
|
}
|
|
|
|
if (prop->state < _prop_state_unacknowledged ||
|
|
prop->state > _prop_state_becoming_acknowledged)
|
|
{
|
|
aim_vector.n[0] = prop->body_position.x;
|
|
aim_vector.n[1] = prop->body_position.y;
|
|
aim_vector.n[2] = prop->body_position.z + 0.2f;
|
|
actor_combat_retarget_grenade(
|
|
actor_index,
|
|
(real_point3d const *)&aim_vector);
|
|
}
|
|
}
|
|
|
|
actor_combat_reaim_grenade(actor_index, origin);
|
|
|
|
if (actor->input.vehicle_index == NONE)
|
|
{
|
|
real_vector2d aim_vector2d;
|
|
|
|
aim_vector = actor->control.grenade_current_aim_vector;
|
|
aim_vector2d.i = aim_vector.i;
|
|
aim_vector2d.j = aim_vector.j;
|
|
|
|
if (normalize2d(&aim_vector2d) > 0.0f &&
|
|
aim_vector2d.i*actor->input.facing_vector.i +
|
|
aim_vector2d.j*actor->input.facing_vector.j <
|
|
GRENADE_AIMING_ANGLE_COSINE)
|
|
{
|
|
boolean counterclockwise =
|
|
aim_vector2d.j*actor->input.facing_vector.i -
|
|
aim_vector2d.i*actor->input.facing_vector.j > 0.0f;
|
|
real_vector3d new_aim_vector = actor->input.facing_vector;
|
|
real magnitude;
|
|
|
|
rotate_vector_about_axis(
|
|
&new_aim_vector,
|
|
global_up3d,
|
|
(counterclockwise ? 1 : -1)*GRENADE_AIMING_ANGLE_SINE,
|
|
GRENADE_AIMING_ANGLE_COSINE);
|
|
|
|
magnitude = square_root(
|
|
aim_vector.i*aim_vector.i + aim_vector.j*aim_vector.j);
|
|
new_aim_vector.i *= magnitude;
|
|
new_aim_vector.j *= magnitude;
|
|
new_aim_vector.k = aim_vector.k;
|
|
|
|
match_assert_valid_real_normal3d(
|
|
"c:\\halo\\SOURCE\\ai\\actor_combat.c",
|
|
1865,
|
|
&new_aim_vector);
|
|
|
|
aim_vector = new_aim_vector;
|
|
}
|
|
}
|
|
|
|
vector->i = aim_vector.i*actor->control.grenade_current_aim_speed;
|
|
vector->j = aim_vector.j*actor->control.grenade_current_aim_speed;
|
|
vector->k = aim_vector.k*actor->control.grenade_current_aim_speed;
|
|
|
|
return target_unit_index;
|
|
}
|
|
|
|
/* ---------- private code */
|