mirror of
https://github.com/Cesarus85/ringfall-mjolnir-vr.git
synced 2026-10-23 06:00:25 +02:00
Reconstruct remaining actors functions
This commit is contained in:
1 parent
b106613588
commit
94de711dc1
9 files changed
+1094
-17
No files matched your search
@@ -631,10 +631,6 @@ short actor_select_firing_position(
|
||||
struct actions_firing_position_search_workspace *workspace,
|
||||
boolean *position_flags);
|
||||
|
||||
void actor_clear_discarded_firing_positions(
|
||||
long actor_index,
|
||||
boolean temporary_only);
|
||||
|
||||
void actor_discard_firing_position(
|
||||
long actor_index,
|
||||
short firing_position_index,
|
||||
|
||||
@@ -9,7 +9,7 @@ struct actor_starting_location;
|
||||
long actor_place(
|
||||
long actor_variant_definition_index,
|
||||
long encounter_index,
|
||||
short squad_index,
|
||||
long squad_index,
|
||||
struct actor_starting_location *starting_location,
|
||||
boolean upgrade_major,
|
||||
short initial_variant);
|
||||
|
||||
+919
-5
@@ -298,8 +298,11 @@ symbols in this file:
|
||||
#include "encounters.h"
|
||||
#include "cseries/errors.h"
|
||||
#include "game/game.h"
|
||||
#include "game/game_allegiance.h"
|
||||
#include "game/players.h"
|
||||
#include "items/equipment_definitions.h"
|
||||
#include "items/projectiles.h"
|
||||
#include "items/weapons.h"
|
||||
#include "objects/damage.h"
|
||||
#include "saved games/game_state.h"
|
||||
#include "scenario/scenario.h"
|
||||
@@ -345,6 +348,25 @@ enum actor_default_state
|
||||
enum
|
||||
{
|
||||
_rgb_color_interpolation_hsv_bit = 0,
|
||||
_ai_reference_squad_bit = 15,
|
||||
};
|
||||
|
||||
/* vehicle_definition.flags; the shared vehicle tag header has not yet
|
||||
* reconstructed these AI-facing constants. */
|
||||
enum
|
||||
{
|
||||
_vehicle_ai_weapon_cannot_rotate_bit = 8,
|
||||
_vehicle_ai_driver_enable_bit = 11,
|
||||
_vehicle_ai_driver_flying_bit,
|
||||
_vehicle_ai_driver_nondirectional_bit,
|
||||
_vehicle_ai_driver_hovering_bit,
|
||||
};
|
||||
|
||||
/* projectile_datum.flags; projectiles.c currently owns the otherwise private
|
||||
* enum, so actors keeps the shared January bit spelling local for now. */
|
||||
enum
|
||||
{
|
||||
_projectile_will_super_explode_bit = 7,
|
||||
};
|
||||
|
||||
/* January names these limits in its assert and error strings; the shared
|
||||
@@ -445,6 +467,20 @@ enum
|
||||
((struct swarm_component_datum *)datum_get( \
|
||||
swarm_component_data, (index)))
|
||||
|
||||
/* These object chains are polymorphic. The accessors preserve January's
|
||||
* broad verification masks while giving each use site the complete layout it
|
||||
* needs after checking object.type. */
|
||||
#define actor_parent_vehicle_candidate_get(index) \
|
||||
((struct unit_datum *)object_get(index))
|
||||
#define actor_swarm_member_get(index) \
|
||||
((struct biped_datum *)object_get_and_verify_type( \
|
||||
(index), \
|
||||
_object_mask_unit))
|
||||
#define actor_attached_threat_get(index) \
|
||||
((struct projectile_datum *)object_get(index))
|
||||
|
||||
#define realcmp(a, b) (fabs((a) - (b)) < _real_epsilon)
|
||||
|
||||
#define prop_orphaned(prop) \
|
||||
((prop)->state >= _prop_state_uninspected_orphan && \
|
||||
(prop)->state <= _prop_state_inspected_orphan)
|
||||
@@ -521,10 +557,13 @@ typedef char actor_datum_meta_first_prop_index_offset_assert[
|
||||
struct vehicle_definition
|
||||
{
|
||||
struct unit_definition unit;
|
||||
byte __unknown2F0[0x94];
|
||||
unsigned long flags;
|
||||
byte __unknown2F4[0x90];
|
||||
real ai_destination_radius;
|
||||
};
|
||||
|
||||
typedef char vehicle_definition_flags_offset_assert[
|
||||
offsetof(struct vehicle_definition, flags) == 0x2F0 ? 1 : -1];
|
||||
typedef char vehicle_definition_ai_destination_radius_offset_assert[
|
||||
offsetof(struct vehicle_definition, ai_destination_radius) == 0x384 ? 1 : -1];
|
||||
|
||||
@@ -539,12 +578,16 @@ struct ai_globals_service_data
|
||||
boolean time_given_this_frame;
|
||||
short last_highest_service_timer;
|
||||
short current_highest_service_timer;
|
||||
byte reserved008[0x3AC];
|
||||
boolean grenades_enabled;
|
||||
};
|
||||
|
||||
typedef char ai_globals_service_data_time_given_offset_assert[
|
||||
offsetof(struct ai_globals_service_data, time_given_this_frame) == 0x3 ? 1 : -1];
|
||||
typedef char ai_globals_service_data_current_highest_offset_assert[
|
||||
offsetof(struct ai_globals_service_data, current_highest_service_timer) == 0x6 ? 1 : -1];
|
||||
typedef char ai_globals_service_data_grenades_enabled_offset_assert[
|
||||
offsetof(struct ai_globals_service_data, grenades_enabled) == 0x3B4 ? 1 : -1];
|
||||
|
||||
/* ai_profile.c owns the profile globals; actors bumps only the January
|
||||
* authenticated per-tick meters, so model the 0x88-byte meter records that
|
||||
@@ -570,10 +613,8 @@ typedef char ai_profile_meter_globals_units_active_offset_assert[
|
||||
|
||||
/* ---------- prototypes */
|
||||
|
||||
/* January keeps this function private to ACTORS.C. Its body remains one of
|
||||
* this object's explicitly unwritten functions, so the forward declaration
|
||||
* stays TU-local until the static definition is reconstructed. */
|
||||
void actor_input_update(
|
||||
/* January keeps this function private to ACTORS.C. */
|
||||
static void actor_input_update(
|
||||
long actor_index);
|
||||
|
||||
/* ---------- globals */
|
||||
@@ -1558,6 +1599,419 @@ void actor_input_sample_position(
|
||||
return;
|
||||
}
|
||||
|
||||
static void actor_input_update(
|
||||
long actor_index)
|
||||
{
|
||||
struct actor_datum *actor = actor_get(actor_index);
|
||||
struct actor_definition *actor_definition =
|
||||
actor_definition_get(actor->meta.definition_index);
|
||||
|
||||
if (actor->meta.swarm)
|
||||
{
|
||||
struct swarm_datum *swarm = swarm_get(actor->meta.swarm_cache_index);
|
||||
real_point3d *swarm_center = &swarm->swarm_center;
|
||||
long component_index;
|
||||
|
||||
*swarm_center = *global_origin3d;
|
||||
for (
|
||||
component_index = 0;
|
||||
(short)component_index < swarm->unit_count;
|
||||
component_index++)
|
||||
{
|
||||
struct swarm_component_datum *component =
|
||||
swarm_component_get(
|
||||
swarm->component_indices[(short)component_index]);
|
||||
long component_datum_index =
|
||||
swarm->component_indices[(short)component_index];
|
||||
long unit_index = swarm->unit_indices[(short)component_index];
|
||||
struct biped_datum *member = actor_swarm_member_get(unit_index);
|
||||
struct swarm_component_datum *sampled_component =
|
||||
swarm_component_get(component_datum_index);
|
||||
long surface_index = NONE;
|
||||
|
||||
if (member->object.type == _object_type_biped)
|
||||
{
|
||||
surface_index = member->biped.support_surface_index;
|
||||
}
|
||||
|
||||
object_get_origin(unit_index, &sampled_component->position);
|
||||
sampled_component->surface_index = surface_index;
|
||||
swarm_center->x += component->position.x;
|
||||
swarm_center->y += component->position.y;
|
||||
swarm_center->z += component->position.z;
|
||||
}
|
||||
|
||||
if (swarm->unit_count > 0)
|
||||
{
|
||||
scale_vector3d(
|
||||
(real_vector3d *)swarm_center,
|
||||
1.f / (real)swarm->unit_count,
|
||||
(real_vector3d *)swarm_center);
|
||||
}
|
||||
|
||||
csmemset(&actor->input.position, 0, sizeof(actor->input));
|
||||
actor->input.vehicle_index = NONE;
|
||||
actor->input.pathfinding_surface_index = NONE;
|
||||
|
||||
if (actor->meta.swarm_unit_index == NONE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
actor_input_sample_position(
|
||||
actor_index,
|
||||
actor->meta.swarm_unit_index,
|
||||
&actor->input.position);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
struct unit_datum *unit = unit_get(actor->meta.unit_index);
|
||||
long vehicle_index = unit->object.parent_object_index;
|
||||
struct unit_datum *vehicle = vehicle_index == NONE
|
||||
? NULL
|
||||
: actor_parent_vehicle_candidate_get(vehicle_index);
|
||||
real_point3d center_of_mass;
|
||||
|
||||
actor_input_sample_position(
|
||||
actor_index,
|
||||
actor->meta.unit_index,
|
||||
&actor->input.position);
|
||||
unit_get_center_of_mass(actor->meta.unit_index, ¢er_of_mass);
|
||||
actor->input.underwater = scenario_location_underwater(
|
||||
&actor->input.position.body_location,
|
||||
¢er_of_mass,
|
||||
NULL);
|
||||
actor->state.flying =
|
||||
TEST_FLAG(actor_definition->flags, _actor_definition_flying_bit);
|
||||
|
||||
if (vehicle && vehicle->object.type == _object_type_vehicle)
|
||||
{
|
||||
struct vehicle_definition *vehicle_definition =
|
||||
vehicle_specific_definition_get(vehicle->definition_index);
|
||||
|
||||
actor->input.vehicle_index = vehicle_index;
|
||||
actor->input.vehicle_gunner_bombardment = FALSE;
|
||||
actor->input.vehicle_gunner = FALSE;
|
||||
actor->input.vehicle_driver_type = _actor_vehicle_driver_none;
|
||||
|
||||
if (vehicle->unit.driver_object_index == actor->meta.unit_index)
|
||||
{
|
||||
unsigned long vehicle_flags = vehicle_definition->flags;
|
||||
|
||||
actor->input.vehicle_driver_type =
|
||||
_actor_vehicle_driver_unknown;
|
||||
if (TEST_FLAG(vehicle_flags, _vehicle_ai_driver_enable_bit))
|
||||
{
|
||||
if (TEST_FLAG(vehicle_flags, _vehicle_ai_driver_flying_bit))
|
||||
{
|
||||
actor->state.flying = TRUE;
|
||||
actor->input.vehicle_driver_type =
|
||||
_actor_vehicle_driver_directional_flying;
|
||||
}
|
||||
else if (TEST_FLAG(
|
||||
vehicle_flags,
|
||||
_vehicle_ai_driver_nondirectional_bit))
|
||||
{
|
||||
actor->input.vehicle_driver_type =
|
||||
TEST_FLAG(vehicle_flags, _vehicle_ai_driver_hovering_bit)
|
||||
? _actor_vehicle_driver_hovering_ground
|
||||
: _actor_vehicle_driver_nondirectional_ground;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vehicle->unit.gunner_object_index == actor->meta.unit_index)
|
||||
{
|
||||
actor->input.vehicle_gunner = TRUE;
|
||||
actor->input.vehicle_gunner_bombardment =
|
||||
actor_combat_get_firing_variant_definition(actor_index)->
|
||||
ranged_combat.weapon_bombardment_range > 0.f;
|
||||
}
|
||||
|
||||
actor->input.vehicle_passenger =
|
||||
actor->input.vehicle_driver_type <=
|
||||
_actor_vehicle_driver_unknown;
|
||||
|
||||
if (vehicle->unit.fake_encounter_index != NONE)
|
||||
{
|
||||
long actor_encounter_index = actor->meta.encounter_index;
|
||||
boolean migrate = FALSE;
|
||||
|
||||
if (DATUM_INDEX_TO_ABSOLUTE_INDEX(actor_encounter_index) ==
|
||||
vehicle->unit.fake_encounter_index)
|
||||
{
|
||||
if (vehicle->unit.fake_squad_index != NONE &&
|
||||
actor->meta.squad_index != vehicle->unit.fake_squad_index)
|
||||
{
|
||||
struct encounter_datum *encounter =
|
||||
encounter_get(actor_encounter_index);
|
||||
|
||||
migrate = TRUE;
|
||||
if (encounter->follow_target_type > 0)
|
||||
{
|
||||
struct squad_datum *actor_squad =
|
||||
encounter_get_squad(
|
||||
encounter,
|
||||
actor->meta.squad_index);
|
||||
struct squad_datum *vehicle_squad =
|
||||
encounter_get_squad(
|
||||
encounter,
|
||||
vehicle->unit.fake_squad_index);
|
||||
|
||||
if (actor_squad->automatic_migration_target)
|
||||
{
|
||||
migrate =
|
||||
vehicle_squad->automatic_migration_target == FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
migrate = TRUE;
|
||||
}
|
||||
|
||||
if (migrate)
|
||||
{
|
||||
if (!actor->meta.stored_prevehicle_encounter)
|
||||
{
|
||||
actor->meta.prevehicle_encounter_index =
|
||||
actor_encounter_index;
|
||||
actor->meta.prevehicle_squad_index =
|
||||
actor->meta.squad_index;
|
||||
actor->meta.stored_prevehicle_encounter = TRUE;
|
||||
|
||||
if (actor_encounter_index != NONE)
|
||||
{
|
||||
encounter_get(actor_encounter_index)->
|
||||
is_prevehicle_encounter = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
actor_change_encounter(
|
||||
actor_index,
|
||||
vehicle->unit.fake_encounter_index,
|
||||
vehicle->unit.fake_squad_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
boolean stored_prevehicle_encounter =
|
||||
actor->meta.stored_prevehicle_encounter;
|
||||
|
||||
actor->input.vehicle_index = NONE;
|
||||
actor->input.vehicle_driver_type = _actor_vehicle_driver_none;
|
||||
actor->input.vehicle_passenger = FALSE;
|
||||
actor->input.vehicle_gunner = FALSE;
|
||||
|
||||
if (stored_prevehicle_encounter)
|
||||
{
|
||||
actor_change_encounter(
|
||||
actor_index,
|
||||
actor->meta.prevehicle_encounter_index,
|
||||
actor->meta.prevehicle_squad_index);
|
||||
actor->meta.stored_prevehicle_encounter = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (actor->meta.encounter_index != NONE)
|
||||
{
|
||||
struct actor_debug_info *actor_debug_info =
|
||||
&actor_debug_array[DATUM_INDEX_TO_ABSOLUTE_INDEX(actor_index)];
|
||||
struct encounter_definition *encounter_definition =
|
||||
TAG_BLOCK_GET_ELEMENT(
|
||||
&global_scenario_get()->ai_encounters,
|
||||
DATUM_INDEX_TO_ABSOLUTE_INDEX(
|
||||
actor->meta.encounter_index),
|
||||
struct encounter_definition);
|
||||
if ((actor->state.flying &&
|
||||
!TEST_FLAG(
|
||||
encounter_definition->flags,
|
||||
_encounter_3d_firing_positions_bit)) ||
|
||||
(!actor->state.flying &&
|
||||
TEST_FLAG(
|
||||
encounter_definition->flags,
|
||||
_encounter_3d_firing_positions_bit)))
|
||||
{
|
||||
if (actor_debug_info->firing_position_type_mismatch_ticks < 150)
|
||||
{
|
||||
actor_debug_info->firing_position_type_mismatch_ticks++;
|
||||
if (actor_debug_info->firing_position_type_mismatch_ticks == 150)
|
||||
{
|
||||
if (actor->state.flying)
|
||||
{
|
||||
error(
|
||||
_error_silent,
|
||||
"actor %s is flying but was placed in a non-3d-firing-position encounter (%s)",
|
||||
tag_get_name(actor->meta.definition_index),
|
||||
encounter_definition->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
error(
|
||||
_error_silent,
|
||||
"actor %s is not flying but was placed in a 3d-firing-position encounter (%s)",
|
||||
tag_get_name(actor->meta.definition_index),
|
||||
encounter_definition->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
actor_debug_info->firing_position_type_mismatch_ticks = 0;
|
||||
}
|
||||
}
|
||||
|
||||
actor->input.burning_to_death = unit->unit.flaming_death_delay > 0;
|
||||
actor->input.melee_attacker_attached = FALSE;
|
||||
actor->input.delayed_attached_projectile_index = NONE;
|
||||
|
||||
{
|
||||
long threat_index = unit->object.first_child_object_index;
|
||||
|
||||
while (threat_index != NONE)
|
||||
{
|
||||
struct projectile_datum *threat =
|
||||
actor_attached_threat_get(threat_index);
|
||||
|
||||
if (threat->object.type == _object_type_biped &&
|
||||
game_team_is_enemy(
|
||||
actor->meta.team_index,
|
||||
threat->object.owner_team_index))
|
||||
{
|
||||
actor->input.melee_attacker_attached = TRUE;
|
||||
}
|
||||
else if (threat->object.type == _object_type_projectile &&
|
||||
(TEST_FLAG(
|
||||
threat->projectile.flags,
|
||||
_projectile_will_super_explode_bit) ||
|
||||
(actor->danger_zone.danger_type ==
|
||||
_actor_danger_zone_projectile &&
|
||||
threat_index == actor->danger_zone.object_index)))
|
||||
{
|
||||
actor->input.delayed_attached_projectile_index =
|
||||
threat_index;
|
||||
}
|
||||
|
||||
threat_index = threat->object.next_object_index;
|
||||
}
|
||||
}
|
||||
|
||||
actor->input.in_midair = FALSE;
|
||||
actor->input.pathfinding_surface_index = NONE;
|
||||
if (unit->object.type == _object_type_biped &&
|
||||
actor->input.vehicle_index == NONE)
|
||||
{
|
||||
struct biped_datum *biped = biped_get(actor->meta.unit_index);
|
||||
|
||||
if (biped->biped.airborne_ticks >= 6)
|
||||
{
|
||||
actor->input.in_midair = TRUE;
|
||||
}
|
||||
actor->input.pathfinding_surface_index =
|
||||
biped->biped.pathfinding_surface_index;
|
||||
actor->input.pathfinding_point = biped->biped.pathfinding_point;
|
||||
}
|
||||
|
||||
unit_get_facing_vector(
|
||||
actor->input.vehicle_driver_type > _actor_vehicle_driver_none
|
||||
? actor->input.vehicle_index
|
||||
: actor->meta.unit_index,
|
||||
&actor->input.facing_vector);
|
||||
if (!actor->state.flying)
|
||||
{
|
||||
if (normalize2d((real_vector2d *)&actor->input.facing_vector) > 0.f)
|
||||
{
|
||||
actor->input.facing_vector.k = 0.f;
|
||||
}
|
||||
else
|
||||
{
|
||||
actor->input.facing_vector = *global_forward3d;
|
||||
}
|
||||
}
|
||||
|
||||
if (actor->input.vehicle_gunner)
|
||||
{
|
||||
struct unit_datum *gunner_vehicle =
|
||||
vehicle_get(actor->input.vehicle_index);
|
||||
struct vehicle_definition *gunner_vehicle_definition =
|
||||
vehicle_specific_definition_get(
|
||||
gunner_vehicle->definition_index);
|
||||
|
||||
if (TEST_FLAG(
|
||||
gunner_vehicle_definition->flags,
|
||||
_vehicle_ai_weapon_cannot_rotate_bit))
|
||||
{
|
||||
unit_get_facing_vector(
|
||||
actor->meta.unit_index,
|
||||
&actor->input.aiming_vector);
|
||||
}
|
||||
else
|
||||
{
|
||||
actor->input.aiming_vector =
|
||||
gunner_vehicle->unit.aiming_vector;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
actor->input.aiming_vector = unit->unit.aiming_vector;
|
||||
}
|
||||
|
||||
actor->input.looking_vector = unit->unit.looking_vector;
|
||||
normalize3d(cross_product3d(
|
||||
global_up3d,
|
||||
&actor->input.looking_vector,
|
||||
&actor->input.looking_left_vector));
|
||||
cross_product3d(
|
||||
&actor->input.looking_vector,
|
||||
&actor->input.looking_left_vector,
|
||||
&actor->input.looking_up_vector);
|
||||
|
||||
match_assert_valid_real_normal3d(
|
||||
"c:\\halo\\SOURCE\\ai\\actors.c",
|
||||
3313,
|
||||
&actor->input.facing_vector);
|
||||
match_assert_valid_real_normal3d(
|
||||
"c:\\halo\\SOURCE\\ai\\actors.c",
|
||||
3314,
|
||||
&actor->input.aiming_vector);
|
||||
match_assert_valid_real_normal3d(
|
||||
"c:\\halo\\SOURCE\\ai\\actors.c",
|
||||
3315,
|
||||
&actor->input.looking_vector);
|
||||
|
||||
if (!actor->state.flying)
|
||||
{
|
||||
match_vassert(
|
||||
"c:\\halo\\SOURCE\\ai\\actors.c",
|
||||
3318,
|
||||
valid_real_normal2d(
|
||||
(real_vector2d *)&actor->input.facing_vector),
|
||||
csprintf(
|
||||
temporary,
|
||||
"%s: assert_valid_real_normal2d(%f, %f)",
|
||||
"(real_vector2d *) &actor->input.facing_vector",
|
||||
actor->input.facing_vector.i,
|
||||
actor->input.facing_vector.j));
|
||||
match_assert(
|
||||
"c:\\halo\\SOURCE\\ai\\actors.c",
|
||||
3319,
|
||||
realcmp(actor->input.facing_vector.k, 0.0f));
|
||||
}
|
||||
|
||||
actor->input.body_vitality = unit->object.body_vitality;
|
||||
actor->input.shield_vitality = unit->object.shield_vitality;
|
||||
actor->input.recent_body_damage = unit->object.recent_body_damage;
|
||||
actor->input.recent_shield_damage = unit->object.recent_shield_damage;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void actor_clear_orders(
|
||||
long actor_index)
|
||||
{
|
||||
@@ -1840,6 +2294,157 @@ void actor_unit_control_stop_animation_impulse(
|
||||
return;
|
||||
}
|
||||
|
||||
long actor_new(
|
||||
long actor_variant_definition_index)
|
||||
{
|
||||
struct actor_variant_definition *actor_variant_definition;
|
||||
struct actor_definition *actor_definition;
|
||||
struct actor_debug_info *actor_debug_info;
|
||||
struct actor_datum *actor;
|
||||
long actor_definition_index;
|
||||
long actor_index = NONE;
|
||||
|
||||
if (actor_variant_definition_index != NONE)
|
||||
{
|
||||
actor_variant_definition = actor_variant_definition_get(actor_variant_definition_index);
|
||||
actor_definition_index = actor_variant_definition->actor_reference.index;
|
||||
if (actor_definition_index != NONE)
|
||||
{
|
||||
actor_definition = actor_definition_get(actor_definition_index);
|
||||
actor_index = datum_new(actor_data);
|
||||
if (actor_index != NONE)
|
||||
{
|
||||
actor = actor_get(actor_index);
|
||||
actor->meta.swarm = TEST_FLAG(actor_definition->flags, _actor_definition_swarm_actor_bit);
|
||||
actor->meta.variant_definition_index = actor_variant_definition_index;
|
||||
actor->meta.definition_index = actor_definition_index;
|
||||
actor->meta.type = actor_definition->type;
|
||||
actor->meta.unit_index = NONE;
|
||||
actor->meta.unique_leader = FALSE;
|
||||
actor->meta.encounter_index = NONE;
|
||||
actor->meta.squad_index = NONE;
|
||||
actor->meta.platoon_index = NONE;
|
||||
actor->meta.encounterless = FALSE;
|
||||
actor->meta.disconnected_encounter_index = NONE;
|
||||
actor->meta.disconnected_squad_index = NONE;
|
||||
actor->meta.swarm_unit_count = 0;
|
||||
actor->meta.swarm_original_unit_count = 0;
|
||||
actor->meta.swarm_unit_index = NONE;
|
||||
actor->meta.swarm_cache_index = NONE;
|
||||
actor->meta.frozen = TRUE;
|
||||
actor->meta.active = FALSE;
|
||||
actor->meta.last_active_time = NONE;
|
||||
actor->meta.dormant = TRUE;
|
||||
actor->meta.dormant_desire = TRUE;
|
||||
actor->meta.service_timer = 0;
|
||||
actor->meta.first_prop_index = NONE;
|
||||
actor->meta.interesting_orphan_index = NONE;
|
||||
actor->firing_positions.current_position_index = NONE;
|
||||
actor->state.initial_state = NONE;
|
||||
actor->state.default_state = NONE;
|
||||
actor->state.last_default_state_time = NONE;
|
||||
actor->state.command_list_immediate = FALSE;
|
||||
actor->state.command_list_index = NONE;
|
||||
actor->state.last_command_list_time = NONE;
|
||||
actor->state.action = _actor_action_none;
|
||||
actor->state.mode = _actor_mode_alert;
|
||||
actor->state.combat_status = _actor_combat_status_none;
|
||||
actor->state.artificial_combat_status = _actor_combat_status_none;
|
||||
actor->state.suspicion_combat_status = _actor_combat_status_none;
|
||||
actor->state.uncertain_combat_timer = NONE;
|
||||
actor->state.searching = FALSE;
|
||||
actor->state.flying = TEST_FLAG(actor_definition->flags, _actor_definition_flying_bit);
|
||||
actor->input.pathfinding_surface_index = NONE;
|
||||
actor->input.vehicle_index = NONE;
|
||||
actor->external_orders.defending = FALSE;
|
||||
actor->external_orders.pursuit_is_coordinator = FALSE;
|
||||
actor->external_orders.pursuit_group_prop_index = NONE;
|
||||
actor->external_orders.desired_target_type = _actor_target_none;
|
||||
actor->external_orders.conversation_index = NONE;
|
||||
|
||||
csmemset(&actor->emotions, 0, sizeof(actor->emotions));
|
||||
actor->emotions.last_active_cover_seeking_time = NONE;
|
||||
actor->emotions.last_melee_check_time = NONE;
|
||||
actor->emotions.last_melee_attack_time = NONE;
|
||||
actor->emotions.last_defensive_cover_seeking_time = NONE;
|
||||
actor->emotions.last_vehicle_check_time = NONE;
|
||||
actor->emotions.last_vehicle_charge_time = NONE;
|
||||
actor->emotions.last_flee_failed_time = NONE;
|
||||
actor->emotions.corpse_ignore_time = NONE;
|
||||
actor->emotions.unopposable_friend_ignore_time = NONE;
|
||||
actor->emotions.unopposable_retreat_prop_index = NONE;
|
||||
actor->emotions.unopposable_retreat_start_time = NONE;
|
||||
actor->emotions.original_body_vitality = 1.f;
|
||||
actor->emotions.vehicle_ignore_index = NONE;
|
||||
actor->emotions.vehicle_ignore_time = NONE;
|
||||
actor->emotions.flee_with_friends_disable_time = NONE;
|
||||
|
||||
if (actor_definition->moving.glass_ignorance_chance > 0.f)
|
||||
{
|
||||
actor->emotions.ignorant_of_broken_surfaces =
|
||||
real_seed_random(get_global_random_seed_address()) <
|
||||
actor_definition->moving.glass_ignorance_chance;
|
||||
}
|
||||
|
||||
actor->orders.look.primary_priority = _primary_priority_none;
|
||||
actor->orders.move.destination.destination_type = _destination_none;
|
||||
actor->control.path.destination_orders.destination_type = _destination_none;
|
||||
actor->control.path.destination_orders.ignore_target_object_index = NONE;
|
||||
actor->control.path.destination.surface_index = NONE;
|
||||
csmemset(&actor->control.path.path, 0, sizeof(actor->control.path.path));
|
||||
actor->control.moving = FALSE;
|
||||
actor->control.moving_forced_by_aiming = FALSE;
|
||||
actor->control.fire_state = _actor_fire_state_holding;
|
||||
actor->control.fire_state_timer = 0;
|
||||
actor->control.burst_disable_timer = 0;
|
||||
actor->control.trigger_delay_timer = 0;
|
||||
actor->control.blocked_communication_timer = 0;
|
||||
actor->control.current_fire_target_timer = 0;
|
||||
actor->control.current_fire_target_prop_index = NONE;
|
||||
actor->control.grenade_last_check_time = NONE;
|
||||
actor->control.grenade_current_prop_index = NONE;
|
||||
csmemset(
|
||||
actor->control.vector_avoidance_clear_times,
|
||||
NONE,
|
||||
sizeof(actor->control.vector_avoidance_clear_times));
|
||||
actor->control.vector_avoidance_current_direction = NONE;
|
||||
actor->control.vector_avoidance_sharp_turn_timer = NONE;
|
||||
actor->control.secondary_look_type = _secondary_look_none;
|
||||
actor->control.secondary_look_timer = 0;
|
||||
actor->control.desired_aiming_vector = *global_forward3d;
|
||||
actor->control.desired_facing_vector = *global_forward3d;
|
||||
actor->control.desired_looking_vector = *global_forward3d;
|
||||
actor->control.idle_vocalization_combat = FALSE;
|
||||
actor->control.idle_vocalization_timer = TICKS_PER_SECOND;
|
||||
actor->target.target_type = _actor_target_none;
|
||||
actor->target.target_prop_index = NONE;
|
||||
actor->target.target_last_visible_time = NONE;
|
||||
actor->target.since_any_target_visible_timer = NONE;
|
||||
actor_clear_discarded_firing_positions(actor_index, FALSE);
|
||||
actor->firing_positions.pursuit_prop_index = NONE;
|
||||
|
||||
actor_debug_info =
|
||||
&actor_debug_array[DATUM_INDEX_TO_ABSOLUTE_INDEX(actor_index)];
|
||||
csmemset(actor_debug_info, 0, sizeof(*actor_debug_info));
|
||||
actor_debug_info->last_path_refresh = NONE;
|
||||
actor_debug_info->last_projectile_aiming_time = NONE;
|
||||
actor_debug_info->last_vehicle_avoidance_time = NONE;
|
||||
actor_debug_info->last_melee_time = NONE;
|
||||
actor_debug_info->grenade_eval_time = NONE;
|
||||
actor_debug_info->danger_avoidance_time = NONE;
|
||||
actor_debug_info->charge_last_time = NONE;
|
||||
actor_debug_info->field_19C = NONE;
|
||||
actor_debug_info->vision_last_time = NONE;
|
||||
actor_debug_info->num_debug_evaluations = NONE;
|
||||
|
||||
actor_type_initialize(actor_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return actor_index;
|
||||
}
|
||||
|
||||
void actor_customize_unit(
|
||||
long actor_variant_definition_index,
|
||||
long unit_index)
|
||||
@@ -2120,6 +2725,177 @@ long actor_create_for_unit(
|
||||
return actor_index;
|
||||
}
|
||||
|
||||
long actor_place(
|
||||
long actor_variant_definition_index,
|
||||
long encounter_index,
|
||||
long squad_index,
|
||||
struct actor_starting_location *starting_location,
|
||||
boolean upgrade_major,
|
||||
short initial_variant)
|
||||
{
|
||||
struct actor_variant_definition *actor_variant_definition;
|
||||
struct actor_definition *actor_definition;
|
||||
struct object_placement_data placement_data;
|
||||
char encounter_name[256];
|
||||
long unit_index;
|
||||
|
||||
match_assert("c:\\halo\\SOURCE\\ai\\actors.c", 603, starting_location);
|
||||
objects_garbage_collection();
|
||||
|
||||
actor_variant_definition =
|
||||
actor_variant_definition_get(actor_variant_definition_index);
|
||||
if (upgrade_major)
|
||||
{
|
||||
actor_variant_definition_index =
|
||||
actor_variant_definition->major_upgrade_reference.index;
|
||||
match_assert(
|
||||
"c:\\halo\\SOURCE\\ai\\actors.c",
|
||||
613,
|
||||
actor_variant_definition_index != NONE);
|
||||
actor_variant_definition =
|
||||
actor_variant_definition_get(actor_variant_definition_index);
|
||||
}
|
||||
|
||||
actor_definition =
|
||||
actor_definition_get(actor_variant_definition->actor_reference.index);
|
||||
object_placement_data_new(
|
||||
&placement_data,
|
||||
actor_variant_definition->unit_reference.index,
|
||||
NONE);
|
||||
placement_data.position = starting_location->position;
|
||||
vector3d_from_angle(&placement_data.forward, starting_location->facing);
|
||||
placement_data.variant_number = initial_variant;
|
||||
|
||||
unit_index = object_new(&placement_data);
|
||||
if (unit_index == NONE)
|
||||
{
|
||||
if (encounter_index == NONE)
|
||||
{
|
||||
csstrcpy(encounter_name, "<encounterless>");
|
||||
}
|
||||
else
|
||||
{
|
||||
ai_index_to_string(
|
||||
DATUM_INDEX_NEW(
|
||||
DATUM_INDEX_TO_ABSOLUTE_INDEX(encounter_index),
|
||||
FLAG(_ai_reference_squad_bit) |
|
||||
(squad_index & UNSIGNED_CHAR_MAX)),
|
||||
global_scenario_get(),
|
||||
encounter_name,
|
||||
sizeof(encounter_name));
|
||||
}
|
||||
|
||||
error(
|
||||
_error_silent,
|
||||
"WARNING: cannot create unit for actor %s %s",
|
||||
tag_name_strip_path(tag_get_name(actor_variant_definition_index)),
|
||||
encounter_name);
|
||||
|
||||
return NONE;
|
||||
}
|
||||
|
||||
if (encounter_index != NONE)
|
||||
{
|
||||
struct encounter_definition *encounter_definition =
|
||||
TAG_BLOCK_GET_ELEMENT(
|
||||
&global_scenario_get()->ai_encounters,
|
||||
DATUM_INDEX_TO_ABSOLUTE_INDEX(encounter_index),
|
||||
struct encounter_definition);
|
||||
|
||||
if (encounter_definition)
|
||||
{
|
||||
/* Validate the squad reference before customization. */
|
||||
(void)TAG_BLOCK_GET_ELEMENT(
|
||||
&encounter_definition->squads,
|
||||
squad_index,
|
||||
struct squad_definition);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
long actor_index;
|
||||
boolean swarm =
|
||||
TEST_FLAG(actor_definition->flags, _actor_definition_swarm_actor_bit);
|
||||
boolean initially_braindead = FALSE;
|
||||
short initial_state = actor_default_state_none;
|
||||
short default_state = actor_default_state_none;
|
||||
|
||||
actor_customize_unit(actor_variant_definition_index, unit_index);
|
||||
|
||||
if (encounter_index != NONE)
|
||||
{
|
||||
struct encounter_definition *encounter_definition =
|
||||
TAG_BLOCK_GET_ELEMENT(
|
||||
&global_scenario_get()->ai_encounters,
|
||||
DATUM_INDEX_TO_ABSOLUTE_INDEX(encounter_index),
|
||||
struct encounter_definition);
|
||||
struct squad_definition *squad_definition = TAG_BLOCK_GET_ELEMENT(
|
||||
&encounter_definition->squads,
|
||||
squad_index,
|
||||
struct squad_definition);
|
||||
|
||||
initial_state = squad_definition->initial_state;
|
||||
default_state = squad_definition->default_state;
|
||||
initially_braindead =
|
||||
TEST_FLAG(encounter_definition->flags, _encounter_braindead_bit);
|
||||
}
|
||||
|
||||
if (starting_location->initial_state > actor_default_state_none)
|
||||
{
|
||||
initial_state = starting_location->initial_state;
|
||||
}
|
||||
if (starting_location->default_state > actor_default_state_none)
|
||||
{
|
||||
default_state = starting_location->default_state;
|
||||
}
|
||||
|
||||
actor_index = actor_create_for_unit(
|
||||
swarm,
|
||||
unit_index,
|
||||
actor_variant_definition_index,
|
||||
encounter_index,
|
||||
squad_index,
|
||||
FALSE,
|
||||
NONE,
|
||||
initially_braindead,
|
||||
initial_state,
|
||||
default_state,
|
||||
starting_location->command_list_index,
|
||||
starting_location->noncombat_sequence_id);
|
||||
if (actor_index == NONE)
|
||||
{
|
||||
if (encounter_index == NONE)
|
||||
{
|
||||
csstrcpy(encounter_name, "<encounterless>");
|
||||
}
|
||||
else
|
||||
{
|
||||
ai_index_to_string(
|
||||
DATUM_INDEX_NEW(
|
||||
DATUM_INDEX_TO_ABSOLUTE_INDEX(encounter_index),
|
||||
FLAG(_ai_reference_squad_bit) |
|
||||
(squad_index & UNSIGNED_CHAR_MAX)),
|
||||
global_scenario_get(),
|
||||
encounter_name,
|
||||
sizeof(encounter_name));
|
||||
}
|
||||
|
||||
error(
|
||||
_error_silent,
|
||||
"WARNING: cannot create actor %s %s",
|
||||
tag_name_strip_path(tag_get_name(actor_variant_definition_index)),
|
||||
encounter_name);
|
||||
object_delete(unit_index);
|
||||
}
|
||||
else
|
||||
{
|
||||
actor_verify_activation(actor_index);
|
||||
}
|
||||
|
||||
return actor_index;
|
||||
}
|
||||
}
|
||||
|
||||
short actors_spawn_from_unit(
|
||||
long unit_index,
|
||||
long actor_variant_definition_index,
|
||||
@@ -2559,6 +3335,144 @@ void actor_kill(
|
||||
return;
|
||||
}
|
||||
|
||||
void actor_died(
|
||||
long actor_index)
|
||||
{
|
||||
struct actor_datum *actor = actor_get(actor_index);
|
||||
struct actor_variant_definition *actor_variant_definition =
|
||||
actor_variant_definition_get(actor->meta.variant_definition_index);
|
||||
long encounter_index = actor->meta.encounter_index;
|
||||
struct unit_datum *unit;
|
||||
|
||||
if (actor->state.mode == _actor_mode_combat &&
|
||||
actor->state.combat_status >= _actor_combat_status_investigate)
|
||||
{
|
||||
unit = unit_get(actor->meta.unit_index);
|
||||
if (unit_controllable(actor->meta.unit_index) &&
|
||||
unit_inventory_get_weapon(
|
||||
actor->meta.unit_index,
|
||||
(word)unit_get(actor->meta.unit_index)->unit.current_weapon_index) != NONE &&
|
||||
unit->unit.weapon_drop_delay_ticks > 0)
|
||||
{
|
||||
real death_wildfire_chance;
|
||||
|
||||
if (actor_variant_definition->ranged_combat.death_wildfire_chance < 0.1f)
|
||||
{
|
||||
death_wildfire_chance = 0.1f;
|
||||
}
|
||||
else if (actor_variant_definition->ranged_combat.death_wildfire_chance > 0.6f)
|
||||
{
|
||||
death_wildfire_chance = 0.6f;
|
||||
}
|
||||
else
|
||||
{
|
||||
death_wildfire_chance = actor_variant_definition->ranged_combat.death_wildfire_chance;
|
||||
}
|
||||
|
||||
if (actor->emotions.berserk ||
|
||||
(actor->control.current_fire_target_type > _actor_fire_target_none &&
|
||||
actor->control.current_fire_target_distance < 3.f))
|
||||
{
|
||||
real boosted_chance = MIN(death_wildfire_chance * 4.f, 0.6f);
|
||||
|
||||
death_wildfire_chance = MAX(death_wildfire_chance, boosted_chance);
|
||||
}
|
||||
|
||||
if (real_seed_random(get_global_random_seed_address()) < death_wildfire_chance)
|
||||
{
|
||||
real death_wildfire_time;
|
||||
|
||||
if (actor_variant_definition->ranged_combat.death_wildfire_time == 0.f)
|
||||
{
|
||||
death_wildfire_time = real_random_range(0.8f, 1.3f);
|
||||
}
|
||||
else if (actor_variant_definition->ranged_combat.death_wildfire_time < 0.8f)
|
||||
{
|
||||
death_wildfire_time = 0.8f;
|
||||
}
|
||||
else if (actor_variant_definition->ranged_combat.death_wildfire_time > 1.3f)
|
||||
{
|
||||
death_wildfire_time = 1.3f;
|
||||
}
|
||||
else
|
||||
{
|
||||
death_wildfire_time = actor_variant_definition->ranged_combat.death_wildfire_time;
|
||||
}
|
||||
|
||||
{
|
||||
short control_ticks = (short)(death_wildfire_time * TICKS_PER_SECOND);
|
||||
|
||||
unit_persistent_control(
|
||||
actor->meta.unit_index,
|
||||
control_ticks,
|
||||
FLAG(_unit_control_weapon_primary_trigger_bit));
|
||||
unit->unit.weapon_drop_delay_ticks = (char)control_ticks;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unit = unit_get(actor->meta.unit_index);
|
||||
{
|
||||
real grenade_roll = real_seed_random(get_global_random_seed_address());
|
||||
long weapon_index = unit_inventory_get_weapon(
|
||||
actor->meta.unit_index,
|
||||
unit_get(actor->meta.unit_index)->unit.current_weapon_index);
|
||||
|
||||
if (!ai_globals->grenades_enabled ||
|
||||
grenade_roll < actor_variant_definition->items.dont_drop_grenades_chance)
|
||||
{
|
||||
csmemset(unit->unit.grenade_counts, 0, sizeof(unit->unit.grenade_counts));
|
||||
}
|
||||
|
||||
if (weapon_index != NONE)
|
||||
{
|
||||
if (actor_variant_definition->items.weapon_loaded_lower_bound > 0.f ||
|
||||
actor_variant_definition->items.weapon_loaded_upper_bound > 0.f)
|
||||
{
|
||||
real weapon_loaded_upper_bound =
|
||||
actor_variant_definition->items.weapon_loaded_upper_bound;
|
||||
real weapon_loaded_lower_bound =
|
||||
actor_variant_definition->items.weapon_loaded_lower_bound;
|
||||
real amount = real_seed_random_range(
|
||||
get_global_random_seed_address(),
|
||||
weapon_loaded_lower_bound,
|
||||
weapon_loaded_upper_bound);
|
||||
|
||||
weapon_set_current_amount(weapon_index, amount);
|
||||
}
|
||||
|
||||
if (actor_variant_definition->items.weapon_ammo_lower_bound > 0 ||
|
||||
actor_variant_definition->items.weapon_ammo_upper_bound > 0)
|
||||
{
|
||||
short rounds[2];
|
||||
|
||||
csmemset(rounds, 0, sizeof(rounds));
|
||||
{
|
||||
short weapon_ammo_upper_bound =
|
||||
actor_variant_definition->items.weapon_ammo_upper_bound + 1;
|
||||
short weapon_ammo_lower_bound =
|
||||
actor_variant_definition->items.weapon_ammo_lower_bound;
|
||||
|
||||
rounds[0] = seed_random_range(
|
||||
get_global_random_seed_address(),
|
||||
weapon_ammo_lower_bound,
|
||||
weapon_ammo_upper_bound);
|
||||
}
|
||||
weapon_set_total_rounds(weapon_index, rounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actor_delete(actor_index, TRUE);
|
||||
if (encounter_index != NONE)
|
||||
{
|
||||
encounter_update_status(encounter_index);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void actor_swarm_unit_died(
|
||||
long actor_index,
|
||||
long unit_index)
|
||||
|
||||
@@ -865,6 +865,10 @@ long actor_create_for_unit(
|
||||
short default_state,
|
||||
short initial_command_list_index,
|
||||
char noncombat_sequence_id);
|
||||
|
||||
void actor_clear_discarded_firing_positions(
|
||||
long actor_index,
|
||||
boolean clear_temporary_only);
|
||||
short actors_spawn_from_unit(
|
||||
long unit_index,
|
||||
long actor_variant_definition_index,
|
||||
|
||||
@@ -514,7 +514,7 @@ struct actor_debug_info
|
||||
real vision_last_maximum_distance;
|
||||
real vision_last_perception_factor;
|
||||
short num_debug_evaluations;
|
||||
short evaluation_mode;
|
||||
short firing_position_type_mismatch_ticks;
|
||||
};
|
||||
|
||||
/* ---------- prototypes/AI_DEBUG.C */
|
||||
|
||||
@@ -18,7 +18,7 @@ header included in hcex build.
|
||||
|
||||
enum
|
||||
{
|
||||
// only the two bits ai_debug.c reads are named; the rest are unidentified
|
||||
_encounter_braindead_bit = 4,
|
||||
_encounter_3d_firing_positions_bit = 5,
|
||||
_encounter_manual_structure_bsp_index_bit = 6,
|
||||
};
|
||||
@@ -150,16 +150,33 @@ struct encounter_definition
|
||||
struct tag_block player_starting_locations;
|
||||
};
|
||||
|
||||
// element of squad_definition.starting_locations; the 0x1C size comes from the
|
||||
// call site and the field at 0x18 from the string "reset the actor variant in
|
||||
// all %d starting locations"
|
||||
// element of squad_definition.starting_locations
|
||||
struct actor_starting_location
|
||||
{
|
||||
unsigned char __unknown00[0x18];
|
||||
real_point3d position;
|
||||
real facing;
|
||||
short cluster_index;
|
||||
signed char noncombat_sequence_id;
|
||||
byte flags;
|
||||
short default_state;
|
||||
short initial_state;
|
||||
short actor_variant_index;
|
||||
word pad;
|
||||
short command_list_index;
|
||||
};
|
||||
|
||||
typedef char actor_starting_location_size_assert[
|
||||
sizeof(struct actor_starting_location) == 0x1C ? 1 : -1];
|
||||
typedef char actor_starting_location_noncombat_sequence_id_offset_assert[
|
||||
offsetof(struct actor_starting_location, noncombat_sequence_id) == 0x12 ? 1 : -1];
|
||||
typedef char actor_starting_location_default_state_offset_assert[
|
||||
offsetof(struct actor_starting_location, default_state) == 0x14 ? 1 : -1];
|
||||
typedef char actor_starting_location_initial_state_offset_assert[
|
||||
offsetof(struct actor_starting_location, initial_state) == 0x16 ? 1 : -1];
|
||||
typedef char actor_starting_location_actor_variant_index_offset_assert[
|
||||
offsetof(struct actor_starting_location, actor_variant_index) == 0x18 ? 1 : -1];
|
||||
typedef char actor_starting_location_command_list_index_offset_assert[
|
||||
offsetof(struct actor_starting_location, command_list_index) == 0x1A ? 1 : -1];
|
||||
|
||||
struct platoon_definition
|
||||
{
|
||||
char name[TAG_STRING_LENGTH+1];
|
||||
|
||||
@@ -262,6 +262,9 @@ boolean weapon_new(long weapon_index);
|
||||
void weapon_export_function_values(long weapon_index);
|
||||
|
||||
void weapon_set_total_rounds(long weapon_index, short *rounds_array);
|
||||
void weapon_set_current_amount(
|
||||
long weapon_index,
|
||||
real current_amount);
|
||||
|
||||
void weapon_build_weapon_interface_state(long weapon_index, struct weapon_interface_state *state);
|
||||
|
||||
|
||||
Reference in new issue
Block a user