Files
Cesarus85--ringfall-mjolnir-vr/source/ai/ai_debug.c
T
Jonas Volman 4277f892c1 Admit audited Claude reconstruction gains
Retain 18 strict exact-function gains across Actions, Actor Combat, Decals, Game Engine, Object Lights, and Bipeds after removing donor bodies that regressed exact objects, emitted unowned code, or violated source-credibility rules. Name authenticated private symbols, move declarations to owner headers, record honest residual parks, and preserve units.obj at 189/189.
2026-08-31 20:42:01 -07:00

6291 lines
170 KiB
C

/*
AI_DEBUG.C
*/
/* ---------- headers */
#include "cseries.h"
#include "ai_debug.h"
#include "actions.h"
#include "actors.h"
#include "actor_definitions.h"
#include "actor_types.h"
#include "ai.h"
#include "ai_communication.h"
#include "ai_profile.h"
#include "ai_scenario_definitions.h"
#include "encounters.h"
#include "props.h"
#include "camera/director.h"
#include "camera/observer.h"
#include "editor/editor_stubs.h"
#include "game/game.h"
#include "game/player_control.h"
#include "game/players.h"
#include "memory/data.h"
#include "objects/damage.h"
#include "physics/collision_bsp_definitions.h"
#include "physics/collisions.h"
#include "rasterizer/rasterizer.h"
#include "render/render_debug.h"
#include "scenario/scenario.h"
#include "scenario/scenario_definitions.h"
#include "structures/structure_bsp_definitions.h"
#include "text/draw_string.h"
#include "units/bipeds.h"
#include "units/dialogue_definitions.h"
#include "units/biped_definitions.h"
#include "units/units.h"
#include "units/unit_definitions.h"
/* ---------- constants */
/* ---------- macros */
#define actor_debug_print_threat(actor, threat_type, string, color) \
if (actor->situation.specific_threats[threat_type]) \
{ \
render_debug_string_at_point( \
TRUE, \
ai_debug_drawstack(), \
csprintf( \
temporary, \
string, \
(actor)->situation.specific_threats[threat_type], \
(actor)->situation.cumulative_threats[threat_type]), \
color); \
}
/* ---------- structures */
struct ai_debug_speech_list
{
char const *name;
short vocalization_type;
boolean all;
};
struct ai_debug_spatial_effect
{
short type;
short field_02;
real_point3d point;
long time;
};
struct ai_debug_enterable_vehicle
{
long object_index;
real distance;
short team_flags;
short actor_type_flags;
short actor_count;
word pad;
long actor_index[6];
};
struct ai_debug_globals_view
{
boolean ai_active;
boolean initialized_for_new_map;
char __unknown02[0x12E];
short spatial_effect_head;
short spatial_effect_tail;
struct ai_debug_spatial_effect spatial_effect[32];
boolean field_3B4;
char __unknown3B5[1];
short enterable_vehicle_count;
struct ai_debug_enterable_vehicle enterable_vehicle[32];
short field_8B8;
char __unknown8BA[0x22];
};
struct ai_debug_profile_map_data
{
byte __unknown000[0xB28];
short field_B34;
byte __unknownB2A[0x3B6];
};
struct ai_debug_profile_globals_view
{
long __unknown0;
boolean enabled;
byte __unknown5[7];
struct ai_debug_profile_map_data map_data;
};
struct encounter_actor_iterator
{
long encounter_index;
long actor_index;
long next_actor_index;
};
struct actor_iterator
{
struct data_iterator encounter_iterator;
boolean encounterless_actors_done;
boolean active_only;
word pad;
long actor_index;
long next_actor_index;
};
typedef char ai_debug_enterable_vehicle_size_assert[
sizeof(struct ai_debug_enterable_vehicle) == 0x28 ? 1 : -1];
typedef char ai_debug_globals_spatial_effect_offset_assert[
offsetof(struct ai_debug_globals_view, spatial_effect) == 0x134 ? 1 : -1];
typedef char ai_debug_globals_enterable_vehicle_offset_assert[
offsetof(struct ai_debug_globals_view, enterable_vehicle) == 0x3B8 ? 1 : -1];
typedef char ai_debug_globals_size_assert[
sizeof(struct ai_debug_globals_view) == 0x8DC ? 1 : -1];
typedef char ai_debug_profile_map_data_size_assert[
sizeof(struct ai_debug_profile_map_data) == 0xEE0 ? 1 : -1];
typedef char ai_debug_profile_map_data_offset_assert[
offsetof(struct ai_debug_profile_globals_view, map_data) == 0x0C ? 1 : -1];
typedef char ai_debug_profile_field_B34_offset_assert[
offsetof(struct ai_debug_profile_globals_view, map_data.field_B34) == 0xB34 ? 1 : -1];
typedef char ai_debug_actor_iterator_size_assert[
sizeof(struct actor_iterator) == 0x1C ? 1 : -1];
/* ---------- prototypes */
void ai_debug_drawstack_setup(
union real_point3d const *drawstack_base);
static real_point3d *ai_debug_drawstack(
void);
static void ai_debug_highlight_unit(
long unit_index,
boolean render_exclusive,
union real_argb_color const *color);
static void ai_debug_render_path_nodes(
struct path_state *path_state,
boolean bsp_access_allowed,
boolean render_all_nodes,
boolean render_polygons,
boolean render_costs,
boolean render_closest);
static void ai_debug_render_surface(
struct structure_bsp const *structure_bsp,
long surface_index,
real offset,
union real_argb_color const *color);
static void ai_debug_render_actor(
long actor_index,
boolean render_exclusive,
long *history_start_time);
static void ai_debug_render_path_storage(
struct path_debug_storage *path);
static void code_00037890(
real_point3d const *start,
real_argb_color const *color,
short step_count,
struct path_step *steps);
static void code_00037af0(
void);
static void code_00037bc0(
void);
static void code_00037fa0(
void);
static void code_000383d0(
void);
static void code_00038de0(
void);
static void code_00038f30(
void);
static void code_00039e10(
void);
static long code_00038280(
void);
static void code_00039e80(
void);
static void code_0003a2e0(
void);
static void code_0003af00(
void);
static void code_000386a0(
void);
static void code_00039060(
void);
static void code_00041120(
void);
static void code_000411d0(
boolean render_inactive_actors);
static void code_00041220(
long encounter_index);
static void code_00039990(
struct path_node *node,
real_point3d const *previous_point,
struct structure_bsp const *structure_bsp,
boolean render_surfaces,
struct path_state *state,
struct path_node const *previous_node,
real_argb_color const *line_color,
real_argb_color const *surface_color,
real_argb_color const *distance_color,
real_argb_color const *weight_color,
real_argb_color const *cost_color,
real_argb_color const *attractor_color);
static void code_0003a910(
struct path_state *state,
boolean render_surfaces,
boolean render_all_nodes,
boolean render_polygons,
boolean render_costs,
boolean render_closest);
void actor_iterator_new(
struct actor_iterator *iterator,
boolean active_only);
struct actor_datum *actor_iterator_next(
struct actor_iterator *iterator);
/* ---------- globals */
struct ai_debug_state ai_debug;
extern struct ai_debug_globals_view *ai_globals;
extern struct ai_debug_profile_globals_view ai_profile;
struct actor_debug_info *actor_debug_array = NULL;
struct path_debug_storage *actor_path_debug_array = NULL;
static short global_ai_debug_path_render_id = 0;
real_point3d global_ai_debug_drawstack_next_position;
real_point3d global_ai_debug_drawstack_last_position;
real global_ai_debug_drawstack_height;
real_argb_color global_temporary_render_color;
long global_ai_debug_firing_position_color_count = NONE;
static char const *postcombat_type_strings[NUMBER_OF_ACTOR_POSTCOMBAT_ACTIONS] =
{
"none",
"alone",
"unscathed",
"wounded",
"massacre",
"triumph",
"run-to",
"check-enemy",
"check-friend",
"shoot-corpse",
"celebrate"
};
static long global_ai_debug_selected_squad_index = NONE;
static long global_ai_debug_selected_squad_time = NONE;
static unsigned long global_ai_debug_activation_cluster_bit_vector[16];
const real_argb_color global_ai_debug_firing_position_colors[] =
{
{ { 1.f, 1.f, 0.f, 1.f } },
{ { 1.f, 0.f, 1.f, 1.f } },
{ { 1.f, 1.f, 0.5f, 0.f } },
{ { 1.f, 0.f, 1.f, 0.5f } },
{ { 1.f, 0.5f, 0.f, 1.f } },
{ { 1.f, 1.f, 0.f, 0.5f } },
{ { 1.f, 0.5f, 1.f, 0.f } },
{ { 1.f, 0.f, 0.5f, 1.f } },
{ { 1.f, 0.5f, 0.f, 0.f } },
{ { 1.f, 0.f, 0.5f, 0.f } },
{ { 1.f, 0.f, 0.f, 0.5f } },
{ { 1.f, 1.f, 1.f, 0.5f } },
{ { 1.f, 1.f, 0.5f, 1.f } },
{ { 1.f, 0.5f, 1.f, 1.f } },
{ { 1.f, 0.5f, 0.5f, 0.f } },
{ { 1.f, 0.f, 0.5f, 0.5f } },
{ { 1.f, 0.5f, 0.f, 0.5f } },
{ { REAL_MAX, REAL_MAX, REAL_MAX, REAL_MAX } }
};
/* ---------- public code */
void ai_debug_initialize(
void)
{
memset(&ai_debug, 0, sizeof(ai_debug));
ai_debug.selected_actor_index = NONE;
ai_debug.selected_squad_index = NONE;
ai_debug.last_render_id = 1;
ai_debug.render = TRUE;
actor_debug_array = actor_debug_array==NULL ? (struct actor_debug_info *)debug_malloc(sizeof(*actor_debug_array) * MAXIMUM_NUMBER_OF_ACTORS, FALSE, "c:\\halo\\SOURCE\\ai\\ai_debug.c", 147) : actor_debug_array;
actor_path_debug_array = actor_path_debug_array==NULL ? (struct path_debug_storage *)debug_malloc(sizeof(*actor_path_debug_array) * MAXIMUM_NUMBER_OF_ACTOR_PATHS, FALSE, "c:\\halo\\SOURCE\\ai\\ai_debug.c", 148) : actor_path_debug_array;
match_assert("c:\\halo\\SOURCE\\ai\\ai_debug.c", 150, actor_debug_array && actor_path_debug_array);
return;
}
void ai_debug_dispose(
void)
{
if (actor_debug_array)
{
debug_free(actor_debug_array, "c:\\halo\\SOURCE\\ai\\ai_debug.c", 160);
actor_debug_array = NULL;
}
if (actor_path_debug_array)
{
debug_free(actor_path_debug_array, "c:\\halo\\SOURCE\\ai\\ai_debug.c", 166);
actor_path_debug_array = NULL;
}
return;
}
void ai_debug_dispose_from_old_map(
void)
{
struct scenario *scenario = global_scenario_try_and_get();
if (scenario && ai_debug.selected_squad_index!=NONE)
{
struct encounter_definition* encounter = TAG_BLOCK_GET_ELEMENT(
&scenario->ai_encounters,
DATUM_INDEX_TO_ABSOLUTE_INDEX(ai_debug.selected_squad_index),
struct encounter_definition);
strncpy(ai_debug.selected_squad_name, encounter->name, NUMBEROF(ai_debug.selected_squad_name));
ai_debug.selected_squad_name[NUMBEROF(ai_debug.selected_squad_name)-1] = '\0';
}
else
{
strcpy(ai_debug.selected_squad_name, "");
}
return;
}
void ai_debug_clear_storage(
void)
{
match_assert("c:\\halo\\SOURCE\\ai\\ai_debug.c", 208, actor_debug_array);
memset(actor_debug_array, 0, sizeof(*actor_debug_array) * MAXIMUM_NUMBER_OF_ACTORS);
match_assert("c:\\halo\\SOURCE\\ai\\ai_debug.c", 211, actor_path_debug_array)
memset(actor_path_debug_array, 0, sizeof(*actor_path_debug_array) * MAXIMUM_NUMBER_OF_ACTOR_PATHS);
return;
}
void ai_debug_actor_deleted(
long actor_index)
{
short path_index;
for (path_index = 0; path_index<MAXIMUM_NUMBER_OF_ACTOR_PATHS; ++path_index)
{
struct path_debug_storage *path = &actor_path_debug_array[path_index];
if (path->valid)
{
if (path->actor_index==actor_index)
{
path->valid = FALSE;
}
}
}
return;
}
struct path_debug_storage *ai_debug_get_last_path(
long actor_index)
{
short path_index;
short found_path_index = NONE;
long found_path_time = NONE;
for (path_index = 0; path_index<MAXIMUM_NUMBER_OF_ACTOR_PATHS; ++path_index)
{
struct path_debug_storage const *path = &actor_path_debug_array[path_index];
if (path->valid && path->actor_index==actor_index && path->path_time>found_path_time)
{
found_path_index = path_index;
found_path_time = path->path_time;
}
}
return found_path_index==NONE ? NULL : &actor_path_debug_array[found_path_index];
}
boolean ai_debug_highlight_cluster(
short index,
real_argb_color const **highlight_color)
{
boolean result = FALSE;
if (ai_debug.render_encounter_activeregion && ai_debug.selected_squad_index!=NONE)
{
if (global_ai_debug_selected_squad_time != game_time_get() ||
global_ai_debug_selected_squad_index != ai_debug.selected_squad_index)
{
encounter_compute_activation_cluster_bit_vector(
ai_debug.selected_squad_index,
FALSE,
SIZEOF_BITS(global_ai_debug_activation_cluster_bit_vector),
0,
global_ai_debug_activation_cluster_bit_vector);
global_ai_debug_selected_squad_time = game_time_get();
global_ai_debug_selected_squad_index = ai_debug.selected_squad_index;
}
match_assert("c:\\halo\\SOURCE\\ai\\ai_debug.c", 4133, highlight_color);
if (BIT_VECTOR_TEST_FLAG(global_ai_debug_activation_cluster_bit_vector, index))
{
if (encounter_get(ai_debug.selected_squad_index)->active)
{
*highlight_color = global_real_argb_yellow;
}
else
{
*highlight_color = global_real_argb_blue;
}
}
else
{
*highlight_color = global_real_argb_grey;
}
result = TRUE;
}
return result;
}
void ai_debug_render(
void)
{
if (ai_globals->initialized_for_new_map)
{
global_ai_debug_string_position = rasterizer_globals.reserved04.frame_bounds.y1 - 20;
ai_debug.last_render_id = (ai_debug.last_render_id + 1)%1000;
if (ai_debug.selected_actor_index!=NONE)
{
ai_debug.selected_squad_index = actor_get(ai_debug.selected_actor_index)->meta.encounter_index;
}
if (ai_debug.select_this_actor)
{
code_00039e10();
}
if (ai_debug.render)
{
if (ai_debug.render_lineoffire)
{
code_00037af0();
}
if (ai_debug.render_lineofsight)
{
code_00037fa0();
}
if (ai_debug.render_ballistic_lineoffire)
{
code_00037bc0();
}
if (ai_debug.selected_squad_index!=NONE)
{
code_00041220(ai_debug.selected_squad_index);
}
if (ai_debug.selected_actor_index!=NONE)
{
ai_debug_render_actor(ai_debug.selected_actor_index, TRUE, NULL);
}
if (ai_debug.path)
{
code_0003af00();
}
if (ai_debug.render_paths_failed)
{
code_00041120();
}
if (ai_debug.render_aiming_validity)
{
code_000383d0();
}
if (ai_debug.render_all_actors)
{
code_000411d0(ai_debug.render_inactive_actors);
}
if (ai_debug.render_speech || ai_debug.print_speech || ai_debug.render_dialogue_variants)
{
code_00039e80();
}
if (ai_debug.render_idle_look)
{
code_00038de0();
}
if (ai_debug.render_spatial_effects)
{
code_00038f30();
}
if (ai_debug.render_vehicles_enterable)
{
code_0003a2e0();
}
}
}
return;
}
/* ---------- private code */
static void ai_debug_drawstack_setup(
real_point3d const *drawstack_base)
{
real_vector3d vector_to_stack;
struct observer_result const *camera = observer_get_camera(0);
global_ai_debug_drawstack_last_position = *drawstack_base;
global_ai_debug_drawstack_next_position = global_ai_debug_drawstack_last_position;
if (camera)
{
vector_from_points3d(&global_ai_debug_drawstack_last_position, &camera->position, &vector_to_stack);
global_ai_debug_drawstack_height = magnitude3d(&vector_to_stack) / 40.f;
}
else
{
global_ai_debug_drawstack_height = 0.05f;
}
return;
}
static real_point3d *ai_debug_drawstack(
void)
{
global_ai_debug_drawstack_last_position = global_ai_debug_drawstack_next_position;
global_ai_debug_drawstack_next_position.x = global_up3d->i*global_ai_debug_drawstack_height + global_ai_debug_drawstack_last_position.x;
global_ai_debug_drawstack_next_position.y = global_up3d->j*global_ai_debug_drawstack_height + global_ai_debug_drawstack_last_position.y;
global_ai_debug_drawstack_next_position.z = global_up3d->k*global_ai_debug_drawstack_height + global_ai_debug_drawstack_last_position.z;
return &global_ai_debug_drawstack_last_position;
}
static void code_00039990(
struct path_node *node,
real_point3d const *previous_point,
struct structure_bsp const *structure_bsp,
boolean render_surfaces,
struct path_state *state,
struct path_node const *previous_node,
real_argb_color const *line_color,
real_argb_color const *surface_color,
real_argb_color const *distance_color,
real_argb_color const *weight_color,
real_argb_color const *cost_color,
real_argb_color const *attractor_color)
{
real_point3d position;
real height;
real_point3d const *entry_point;
struct observer_result const *camera = observer_get_camera(0);
position.x = (previous_point->x + node->entry_point.x)*0.5f;
entry_point = &node->entry_point;
position.y = (previous_point->y + entry_point->y)*0.5f;
position.z = (previous_point->z + entry_point->z)*0.5f;
position.x = global_up3d->i*0.1f + position.x;
position.y = global_up3d->j*0.1f + position.y;
position.z = global_up3d->k*0.1f + position.z;
if (camera)
{
real_vector3d v;
height = magnitude3d(vector_from_points3d(&position, &camera->position, &v))*0.025f;
}
else
{
height = 0.05f;
}
if (line_color)
{
render_debug_line_offset(TRUE, entry_point, previous_point, line_color, 0.03f);
render_debug_tick(TRUE, entry_point, global_up3d, 0.02f, line_color);
if (!previous_node)
{
render_debug_tick(TRUE, previous_point, global_up3d, 0.02f, line_color);
}
}
if (surface_color && render_surfaces)
{
ai_debug_render_surface(structure_bsp, node->surface_index, 0.f, surface_color);
}
if (distance_color)
{
render_debug_string_at_point(TRUE, &position,
csprintf(temporary, "%.1f", node->linear_distance_to_entry_point),
distance_color);
position.x = global_up3d->i*height + position.x;
position.y = global_up3d->j*height + position.y;
position.z = global_up3d->k*height + position.z;
}
if (attractor_color && node->closest_distance_to_attractor<REAL_MAX)
{
real_point3d point = node->closest_point_to_attractor;
real point_height;
if (camera)
{
real_vector3d v;
point_height = magnitude3d(vector_from_points3d(&point, &camera->position, &v))*0.025f;
}
else
{
point_height = 0.05f;
}
render_debug_point(TRUE, &node->closest_point_to_attractor, 0.15f, attractor_color);
point_from_line3d(&point, global_up3d, point_height+0.15f, &point);
render_debug_string_at_point(TRUE, &point,
csprintf(temporary, "%.1f", node->closest_distance_to_attractor),
attractor_color);
}
if (state && state->input.attractor_valid)
{
real closest_distance = REAL_MAX;
real weight = path_attractor_weight(state, entry_point, previous_point,
&closest_distance);
if (weight_color)
{
render_debug_string_at_point(TRUE, &position,
csprintf(temporary, "%.1f", closest_distance), global_real_argb_yellow);
position.x = global_up3d->i*height + position.x;
position.y = global_up3d->j*height + position.y;
position.z = global_up3d->k*height + position.z;
}
if (cost_color && weight>0.f)
{
render_debug_string_at_point(TRUE, &position,
csprintf(temporary, "%.1f", state->input.attractor_weight),
global_real_argb_red);
}
}
return;
}
static void ai_debug_highlight_unit(
long unit_index,
boolean render_exclusive,
union real_argb_color const *color)
{
struct biped_datum *biped = biped_try_and_get(unit_index);
if (biped)
{
real_point3d base;
real width;
real pill_height;
struct unit_datum *unit = unit_try_and_get(biped->object.parent_object_index);
if (unit && unit->unit.driver_object_index==unit_index)
{
object_get_bounding_sphere(biped->object.parent_object_index, &base, &width);
pill_height = 0.f;
}
else
{
biped_get_physics_pill(unit_index, &base, &pill_height, &width);
}
if (render_exclusive && pill_height>0.f)
{
real_vector3d height;
set_real_vector3d(&height, 0.f, 0.f, pill_height);
render_debug_pill(TRUE, &base, &height, width, color);
}
else
{
render_debug_sphere(TRUE, &base, 0.75f * width, color);
}
if (render_exclusive)
{
render_debug_point(TRUE, &base, 1.8f * width, color);
}
}
return;
}
/* Render the path-node overlays selected by the caller. */
static void ai_debug_render_path_nodes(
struct path_state *path_state,
boolean bsp_access_allowed,
boolean render_all_nodes,
boolean render_polygons,
boolean render_costs,
boolean render_closest)
{
real_argb_color const *attractor_distance_color;
real_argb_color const *closest_color;
real_point3d temp_point2;
real_argb_color const *polygon_color;
real_argb_color const *cost_color;
real_argb_color const *attractor_weight_color;
real_point3d temp_point;
static short current_traverse_index;
return;
}
static void ai_debug_render_surface(
struct structure_bsp const *structure_bsp,
long surface_index,
real offset,
union real_argb_color const *color)
{
struct collision_bsp const *collision_bsp = TAG_BLOCK_GET_ELEMENT(&structure_bsp->collision_bsp, 0, struct collision_bsp);
struct collision_surface const *collision_surface = TAG_BLOCK_GET_ELEMENT(&collision_bsp->surfaces, surface_index, struct collision_surface);
long edge_index = collision_surface->first_edge_index;
do
{
struct collision_edge const *edge = TAG_BLOCK_GET_ELEMENT(&collision_bsp->edges, edge_index, struct collision_edge);
const boolean next_index_belongs_to_surface = edge->surface_indices[1] == surface_index;
struct collision_vertex const *point0 = TAG_BLOCK_GET_ELEMENT(&collision_bsp->vertices, edge->vertex_indices[0], struct collision_vertex);
struct collision_vertex const *point1 = TAG_BLOCK_GET_ELEMENT(&collision_bsp->vertices, edge->vertex_indices[1], struct collision_vertex);
render_debug_line_offset(TRUE, &point0->point, &point1->point, color, offset + 0.015f);
edge_index = edge->edge_indices[next_index_belongs_to_surface];
}
while (edge_index!=collision_surface->first_edge_index);
return;
}
static void ai_debug_render_actor(
long actor_index,
boolean render_exclusive,
long *history_start_time)
{
struct actor_datum* actor = actor_get(actor_index);
struct actor_debug_info *actor_debug_info = &actor_debug_array[DATUM_INDEX_TO_ABSOLUTE_INDEX(actor_index)];
if (actor_debug_info->last_render_id!=ai_debug.last_render_id)
{
struct actor_definition *actor_definition = actor_definition_get(actor->meta.definition_index);
struct actor_variant_definition *actor_variant_definition = actor_variant_definition_get(actor->meta.variant_definition_index);
struct path_debug_storage *path = ai_debug_get_last_path(actor_index);
struct unit_datum *unit = NULL;
struct unit_definition *unit_definition = NULL;
/* Get unit info if the actor has an associated unit */
if (actor->meta.unit_index!=NONE)
{
unit = unit_get(actor->meta.unit_index);
unit_definition = unit_definition_get(unit->definition_index);
}
actor_debug_info->last_render_id = ai_debug.last_render_id;
/* Set history start time */
if (history_start_time)
{
if (actor->state.combat_status>=2 && actor->target.target_prop_index!=NONE)
{
struct prop_datum *prop = prop_get(actor->target.target_prop_index);
if (*history_start_time==NONE || prop->last_perceived_time<*history_start_time)
{
*history_start_time = prop->last_perceived_time;
}
}
}
/* Stack setup */
{
real_point3d stack_base;
point_from_line3d(&actor->input.position.head_position, global_up3d, 0.1f, &stack_base);
ai_debug_drawstack_setup(&stack_base);
}
/* Unit highlighting */
if (actor->meta.swarm)
{
if (actor->meta.swarm_cache_index!=NONE)
{
short unit_num;
struct swarm_datum *swarm = swarm_get(actor->meta.swarm_cache_index);
for (unit_num = 0; unit_num<swarm->unit_count; ++unit_num)
{
ai_debug_highlight_unit(swarm->unit_indices[unit_num], render_exclusive, actor_action_debug_color(actor_index));
}
}
}
else
{
ai_debug_highlight_unit(actor->meta.unit_index, render_exclusive, actor_action_debug_color(actor_index));
}
/* Line of fire crouching status */
if (ai_debug.render_lineoffire_crouching &&
(TEST_FLAG(actor_definition->flags, _actor_definition_crouch_in_line_of_fire_bit) ||
TEST_FLAG(actor_definition->flags, _actor_definition_avoid_friend_line_of_fire_bit)))
{
/* Blocking messages */
if (actor->emotions.crouch_blocking_line_of_fire ||
actor->emotions.crouch_friends_in_line_of_fire ||
actor->emotions.crouch_blocking_player_line_of_fire)
{
char const *blocking_type;
char const *blocking_mode = actor->emotions.crouch_friends_in_line_of_fire ? "friends-blocking" : "";
if (actor->emotions.crouch_blocking_player_line_of_fire)
{
blocking_type = "blocking-player ";
}
else
{
blocking_type = actor->emotions.crouch_blocking_line_of_fire ? "blocking " : "";
}
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "%s%s", blocking_type, blocking_mode),
global_real_argb_orange);
}
/* Moving into fire */
if (actor->emotions.moving_into_player_line_of_fire ||
actor->emotions.moving_into_fire_timer > 0)
{
char const *string = actor->emotions.moving_into_player_line_of_fire ? "moving-into-fire" : "";
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "%sforce-stop %d", string, actor->emotions.moving_into_fire_timer),
global_real_argb_pink);
}
}
/* Player aiming blocked */
if (ai_debug.render_player_aiming_blocked)
{
struct prop_datum *prop;
struct prop_iterator iterator;
real_vector3d aiming_vector;
short blockage_type = 0;
boolean player_prop_found = FALSE;
prop_iterator_new(&iterator, actor_index);
while (prop = prop_iterator_next(&iterator))
{
if (prop->state >= _prop_state_becoming_unacknowledged &&
prop->state <= _prop_state_acknowledged &&
!prop->enemy)
{
if (prop->player)
{
short v0;
player_prop_found = TRUE;
unit_get_aiming_vector(prop->unit_index, &aiming_vector);
v0 = actor_perception_aiming_vector_test_blockage(
&prop->body_position,
&aiming_vector,
&actor->input.position.body_position,
NULL);
if (blockage_type <= v0)
{
blockage_type = v0;
}
}
}
}
if (player_prop_found)
{
switch (blockage_type)
{
case 0:
render_debug_string_at_point(TRUE, ai_debug_drawstack(), "not-occluding-player", global_real_argb_green);
break;
case 1:
render_debug_string_at_point(TRUE, ai_debug_drawstack(), "occluding-player", global_real_argb_blue);
break;
case 2:
render_debug_string_at_point(TRUE, ai_debug_drawstack(), "blocking-player", global_real_argb_red);
break;
default:
render_debug_string_at_point(TRUE, ai_debug_drawstack(), "aiming occlusion error", global_real_argb_pink);
break;
}
}
}
/* Vector avoidance */
if (ai_debug.render_vector_avoidance &&
actor_debug_info->field_19C != NONE &&
actor_debug_info->field_19C + TICKS_PER_SECOND>game_time_get())
{
short i;
short j;
/* Avoidance rays */
if (ai_debug.render_vector_avoidance_rays)
{
short ray_index;
for (ray_index = 0; ray_index<ACTOR_MAXIMUM_AVOIDANCE_RAYS; ++ray_index)
{
real_argb_color const *color = global_real_argb_white;
switch (actor_debug_info->avoidance_type[ray_index])
{
case _actor_vector_avoidance_obstructed_object:
color = global_real_argb_magenta;
break;
case _actor_vector_avoidance_obstructed_structure:
color = global_real_argb_red;
break;
}
if (actor_debug_info->avoidance_type[ray_index]>0)
{
real_point3d point0;
real_point3d point1;
point_from_line3d(
&actor_debug_info->ray_origin[ray_index],
&actor_debug_info->ray_direction[ray_index],
actor_debug_info->collision_t[ray_index],
&point0);
point_from_line3d(
&actor_debug_info->ray_origin[ray_index],
&actor_debug_info->ray_direction[ray_index],
1.f,
&point1);
render_debug_line(TRUE, &actor_debug_info->ray_origin[ray_index], &point0, global_real_argb_white);
render_debug_point(TRUE, &point0, 0.2f, color);
render_debug_line(TRUE, &point0, &point1, color);
if (ai_debug.render_vector_avoidance_sense_t)
{
point_from_line3d(&point0, global_up3d, 0.25f, &point0);
render_debug_string_at_point(
TRUE,
&point0,
csprintf(temporary, "%.3f", actor_debug_info->collision_t[ray_index]),
color);
}
}
else
{
render_debug_vector(
TRUE,
&actor_debug_info->ray_origin[ray_index],
&actor_debug_info->ray_direction[ray_index],
1.f,
global_real_argb_white);
}
}
}
/* Avoidance rays */
for (i = 0; i < 8; ++i)
{
for (j = 0; j < 2; ++j)
{
if (ai_debug.render_vector_avoidance_rays)
{
real_argb_color const *color = global_real_argb_white;
switch (actor_debug_info->field_62F8[i][j])
{
case 1:
color = global_real_argb_aqua;
break;
case 2:
color = global_real_argb_yellow;
break;
}
if (actor_debug_info->field_62F8[i][j]>0)
{
real_point3d point0;
real_point3d point1;
point_from_line3d(
&actor_debug_info->field_6358[i][j],
&actor_debug_info->field_6418[i][j],
actor_debug_info->avoid_t[i][j],
&point0);
point_from_line3d(
&actor_debug_info->field_6358[i][j],
&actor_debug_info->field_6418[i][j],
1.f,
&point1);
render_debug_line(TRUE, &actor_debug_info->field_6358[i][j], &point0, global_real_argb_blue);
render_debug_point(TRUE, &point0, 0.2f, color);
render_debug_line(TRUE, &point0, &point1, color);
if (ai_debug.render_vector_avoidance_avoid_t)
{
point_from_line3d(&point0, global_up3d, 0.25f, &point0);
render_debug_string_at_point(
TRUE,
&point0,
csprintf(
temporary,
"%.3f",
actor_debug_info->avoid_t[i][j]),
global_real_argb_blue);
}
}
else
{
render_debug_vector(
TRUE,
&actor_debug_info->field_6358[i][j],
&actor_debug_info->field_6418[i][j],
1.f,
color);
if (ai_debug.render_vector_avoidance_clear_time)
{
real_point3d point;
point_from_line3d(&actor_debug_info->field_6358[i][j], &actor_debug_info->field_6418[i][j], 0.1f, &point);
point_from_line3d(&point, global_up3d, 0.15f, &point);
render_debug_string_at_point(
TRUE,
&point,
csprintf(
temporary,
"c%d",
actor->control.vector_avoidance_clear_times[i][j]),
global_real_argb_white);
}
}
}
/* Avoidance weights */
if (ai_debug.render_vector_avoidance_weights && j==1)
{
real_point3d point;
point_from_line3d(
&actor_debug_info->field_6358[i][j],
&actor_debug_info->field_6418[i][j],
0.25f,
&point);
point_from_line3d(&point, global_up3d, 0.15f, &point);
render_debug_string_at_point(
TRUE,
&point,
csprintf(
temporary,
"%d: w%.2f",
i,
actor_debug_info->field_64D8[i]),
global_real_argb_green);
}
}
}
/* Avoidance intermediate */
if (ai_debug.render_vector_avoidance_intermediate)
{
real_vector3d direction;
real_argb_color const *color = actor_debug_info->field_6550 ? global_real_argb_magenta : global_real_argb_cyan;
render_debug_vector(TRUE, &actor_debug_info->avoidance_data.origin, &actor_debug_info->field_6524, 5.f, global_real_argb_yellow);
render_debug_vector(TRUE, &actor_debug_info->avoidance_data.origin, &actor_debug_info->field_6530, 1.f, global_real_argb_purple);
actor_move_get_avoidance_direction(&actor_debug_info->avoidance_data, actor_debug_info->field_6500, &direction);
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "best %.2f at %d", actor_debug_info->field_64FC, actor_debug_info->field_6500),
color);
render_debug_vector(TRUE, &actor_debug_info->avoidance_data.origin, &direction, 2.f, color);
actor_move_get_avoidance_direction(&actor_debug_info->avoidance_data, actor_debug_info->field_6504, &direction);
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "curr ~%.2f at %.2f", actor_debug_info->field_6508, actor_debug_info->field_6504),
global_real_argb_green);
render_debug_vector(TRUE, &actor_debug_info->avoidance_data.origin, &direction, 2.0, global_real_argb_green);
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "danger %.2f turncos %.2f", actor_debug_info->sign_no_danger, actor_debug_info->field_6510),
global_real_argb_yellow);
if (actor_debug_info->field_6551)
{
actor_move_transform_avoidance_vector(&actor_debug_info->avoidance_data, &actor_debug_info->avoidance_vector, &direction);
render_debug_vector(TRUE, &actor_debug_info->avoidance_data.origin, &direction, 2.0, global_real_argb_darkgreen);
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(
temporary,
"turn angvel %.2f danger %.2f bonus %.2f",
actor_debug_info->field_6558,
actor_debug_info->field_6568,
actor_debug_info->field_6554),
global_real_argb_darkgreen);
}
}
/* Avoidance objects */
if (ai_debug.render_vector_avoidance_objects)
{
short avoidance_object_index;
for (avoidance_object_index = 0; avoidance_object_index<actor_debug_info->avoidance_data.avoidance_object_count; ++avoidance_object_index)
{
real_vector3d height;
set_real_vector3d(&height, 0.f, 0.f, actor_debug_info->avoidance_data.avoidance_objects[avoidance_object_index].height);
render_debug_pill(
TRUE,
&actor_debug_info->avoidance_data.avoidance_objects[avoidance_object_index].base,
&height,
actor_debug_info->avoidance_data.avoidance_objects[avoidance_object_index].width,
global_real_argb_aqua);
}
}
{
boolean found_player = FALSE;
switch (actor_debug_info->field_653C)
{
case 0:
sprintf(temporary, "clear");
break;
case 1:
sprintf(temporary, "sensed at %f, turn %f", actor_debug_info->field_651C, actor_debug_info->field_6520);
found_player = TRUE;
break;
case 2:
sprintf(temporary, "sign no-danger %f < %f", actor_debug_info->sign_no_danger, 1.3f);
break;
case 3:
sprintf(temporary, "sign too-far cosangle %f < %f", actor_debug_info->sign_too_far_cosangle, 0.5f);
break;
case 4:
sprintf(temporary, "sign rotated %f", actor_debug_info->sign_rotated);
found_player = TRUE;
break;
case 5:
sprintf(temporary, "sharp new-turn");
found_player = TRUE;
break;
case 6:
sprintf(temporary, "sharp change-dir");
found_player = TRUE;
break;
case 7:
sprintf(temporary, "sharp continue");
found_player = TRUE;
break;
default:
sprintf(temporary, "<error>");
break;
}
render_debug_string_at_point(TRUE, ai_debug_drawstack(), temporary, global_real_argb_orange);
if (found_player)
{
render_debug_vector(TRUE, &actor_debug_info->avoidance_data.origin, &actor_debug_info->field_6540, 1.f, global_real_argb_pink);
render_debug_string_at_point(TRUE, ai_debug_drawstack(), csprintf(temporary, "move emergency %.2f", actor_debug_info->field_654C), global_real_argb_pink);
}
}
}
/* Activation */
if (ai_debug.render_activation)
{
{
char encounterbuf[256];
real_argb_color const *encounter_color;
if (actor->meta.encounter_index!=NONE)
{
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);
struct encounter_datum *encounter = encounter_get(actor->meta.encounter_index);
boolean outside_current_bsp = FALSE;
if (encounter_definition->runtime_structure_bsp_reference_index==NONE)
{
encounter_color = global_real_argb_green;
sprintf(encounterbuf, "%s (no-bsp)", encounter_definition->name);
}
else
{
outside_current_bsp = encounter_definition->runtime_structure_bsp_reference_index!=global_structure_bsp_index;
sprintf(encounterbuf, "%s (bsp %d)", encounter_definition->name, encounter_definition->runtime_structure_bsp_reference_index);
}
if (encounter->active)
{
encounter_color = global_real_argb_green;
}
else if (outside_current_bsp)
{
encounter_color = global_real_argb_red;
}
else
{
encounter_color = global_real_argb_purple;
}
}
else
{
encounter_color = global_real_argb_blue;
sprintf(encounterbuf, "encounterless");
}
render_debug_string_at_point(TRUE, ai_debug_drawstack(), encounterbuf, encounter_color);
}
{
real_argb_color const *actor_color = actor_activation_debug_color(actor_index);
long unit_index = actor->meta.unit_index;
short unit_count = 0;
struct swarm_datum *swarm = NULL;
struct observer_result const *camera = observer_get_camera(0);
unsigned long const *pvs = players_get_combined_pvs();
if (actor->meta.swarm && actor->meta.swarm_cache_index!=NONE)
{
swarm = swarm_get(actor->meta.swarm_cache_index);
}
while (TRUE)
{
if (unit_index!=NONE)
{
real_vector3d offset_vector;
real_point3d base_point;
short cluster_index;
unit_get_head_position(unit_index, &base_point);
point_from_line3d(&base_point, global_up3d, 0.2f, &base_point);
if (camera==NULL)
{
offset_vector = *global_forward3d;
}
else
{
cross_product3d(&camera->forward, global_up3d, &offset_vector);
if (normalize3d(&offset_vector)==0.f)
{
offset_vector = *global_forward3d;
}
}
{
struct object_datum const *ultimate_parent = object_get(object_get_ultimate_parent(unit_index));
cluster_index = ultimate_parent->object.location.cluster_index;
}
if (cluster_index==NONE)
{
real_point3d p0;
real_point3d p1;
real_point3d p2;
real_point3d p3;
p0.x = base_point.x+offset_vector.i*0.1f;
p0.y = base_point.y+offset_vector.j*0.1f;
p0.z = base_point.z+offset_vector.k*0.1f;
p1.x = base_point.x-offset_vector.i*0.1f;
p1.y = base_point.y-offset_vector.j*0.1f;
p1.z = base_point.z-offset_vector.k*0.1f;
point_from_line3d(&p0, global_up3d, 0.2f, &p2);
point_from_line3d(&p1, global_up3d, 0.2f, &p3);
render_debug_line(TRUE, &p0, &p2, actor_color);
render_debug_line(TRUE, &p2, &p3, actor_color);
render_debug_line(TRUE, &p3, &p1, actor_color);
render_debug_line(TRUE, &p1, &p0, actor_color);
}
else if (BIT_VECTOR_TEST_FLAG(pvs, cluster_index))
{
real_point3d p0;
real_point3d p1;
real_point3d p2;
real_point3d p3;
point_from_line3d(&base_point, global_up3d, 0.2f, &p0);
p1.x = base_point.x+global_up3d->i*0.1f;
p1.y = base_point.y+global_up3d->j*0.1f;
p1.z = base_point.z+global_up3d->k*0.1f;
p3.x = p1.x+offset_vector.i*0.1f;
p3.y = p1.y+offset_vector.j*0.1f;
p3.z = p1.z+offset_vector.k*0.1f;
p2.x = p1.x-offset_vector.i*0.1f;
p2.y = p1.y-offset_vector.j*0.1f;
p2.z = p1.z-offset_vector.k*0.1f;
render_debug_line(TRUE, &base_point, &p3, actor_color);
render_debug_line(TRUE, &p3, &p0, actor_color);
render_debug_line(TRUE, &p0, &p2, actor_color);
render_debug_line(TRUE, &p2, &base_point, actor_color);
}
else
{
real_point3d p0;
real_point3d p1;
real_point3d p2;
real_point3d p3;
p0.x = base_point.x+offset_vector.i*0.1f;
p0.y = base_point.y+offset_vector.j*0.1f;
p0.z = base_point.z+offset_vector.k*0.1f;
p1.x = base_point.x-offset_vector.i*0.1f;
p1.y = base_point.y-offset_vector.j*0.1f;
p1.z = base_point.z-offset_vector.k*0.1f;
point_from_line3d(&p0, global_up3d, 0.2f, &p2);
point_from_line3d(&p1, global_up3d, 0.2f, &p3);
render_debug_line(TRUE, &p0, &p3, actor_color);
render_debug_line(TRUE, &p2, &p1, actor_color);
}
}
if (!swarm || unit_count >= swarm->unit_count)
{
break;
}
unit_index = swarm->unit_indices[unit_count++];
}
}
}
/* Support surfaces */
if (ai_debug.render_support_surfaces)
{
struct swarm_datum *swarm = NULL;
long unit_index = NONE;
short unit_num = 0;
if (!actor->meta.swarm || actor->meta.swarm_cache_index==NONE)
{
unit_index = actor->meta.unit_index;
}
else
{
swarm = swarm_get(actor->meta.swarm_cache_index);
if (swarm->unit_count>0)
{
unit_index = swarm->unit_indices[0];
}
}
while (unit_index!=NONE)
{
struct biped_datum *biped = biped_try_and_get(unit_index);
if (!biped || biped->biped.support_surface_index==NONE)
{
real_point3d origin;
object_get_origin(unit_index, &origin);
render_debug_sphere(TRUE, &origin, 0.3f, global_real_argb_pink);
if (!actor->meta.swarm)
{
if (actor->input.pathfinding_surface_index==NONE)
{
render_debug_sphere(TRUE, &actor->input.position.body_position, 0.4f, global_real_argb_red);
}
else
{
render_debug_sphere(TRUE, &actor->input.pathfinding_point, 0.4f, global_real_argb_orange);
ai_debug_render_surface(global_structure_bsp_get(), actor->input.pathfinding_surface_index, 0.f, global_real_argb_orange);
}
}
}
else
{
ai_debug_render_surface(global_structure_bsp_get(), biped->biped.support_surface_index, 0.f, global_real_argb_pink);
}
++unit_num;
unit_index = NONE;
if (swarm && unit_num<swarm->unit_count)
{
unit_index = swarm->unit_indices[unit_num];
}
}
}
/* Vitality */
if (ai_debug.render_vitality)
{
if (actor->input.body_vitality>0.f)
{
render_debug_string_at_point(TRUE, ai_debug_drawstack(), csprintf(temporary, "body %3.2f", actor->input.body_vitality), global_real_argb_red);
}
if (actor->input.shield_vitality>0.f)
{
render_debug_string_at_point(TRUE, ai_debug_drawstack(), csprintf(temporary, "shld %3.2f", actor->input.shield_vitality), global_real_argb_blue);
}
}
/* Damage */
if (ai_debug.render_recent_damage)
{
if (actor->input.recent_body_damage>0.f)
{
render_debug_string_at_point(TRUE, ai_debug_drawstack(), csprintf(temporary, "b/dmg %3.2f", actor->input.recent_body_damage), global_real_argb_yellow);
}
if (actor->input.recent_shield_damage>0.f)
{
render_debug_string_at_point(TRUE, ai_debug_drawstack(), csprintf(temporary, "s/dmg %3.2f", actor->input.recent_shield_damage), global_real_argb_green);
}
}
/* Cover seeking */
if (ai_debug.render_active_cover_seeking && actor_debug_info->field_B8)
{
const char *strings[8] =
{
"wrongaction",
"visibletarget",
"repeattimer",
"visibletimer",
"shielded",
"unavailable",
"success",
"panic"
};
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "%s %d %.2f", strings[actor_debug_info->field_BA], actor_debug_info->field_BC, actor_debug_info->field_C0),
global_real_argb_yellow);
}
/* Threats */
if (ai_debug.render_threats && actor->situation.known_enemies)
{
render_debug_string_at_point(TRUE, ai_debug_drawstack(), csprintf(temporary, "enemy %d", actor->situation.known_enemies), global_real_argb_red);
actor_debug_print_threat(actor, _actor_threat_visible, "vis %d/%d", global_real_argb_white);
actor_debug_print_threat(actor, _actor_threat_visible_facing_me, "facing %d/%d", global_real_argb_lightblue);
actor_debug_print_threat(actor, _actor_threat_visible_aiming_at_me, "aim at %d/%d", global_real_argb_blue);
actor_debug_print_threat(actor, _actor_threat_shooting, "shoot %d/%d", global_real_argb_yellow);
actor_debug_print_threat(actor, _actor_threat_shooting_near_me, "s/near %d/%d", global_real_argb_orange);
actor_debug_print_threat(actor, _actor_threat_shooting_at_me, "s/at me %d/%d", global_real_argb_red);
actor_debug_print_threat(actor, _actor_threat_extremely_close_to_me, "ex.close %d/%d", global_real_argb_magenta);
actor_debug_print_threat(actor, _actor_threat_damaging_me, "dmging %d/%d", global_real_argb_magenta);
}
/* Emotions */
if (ai_debug.render_emotions)
{
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "dngr %3.2f/%3.2f", actor->emotions.instantaneous_danger, actor->emotions.perceived_danger),
global_real_argb_yellow);
if (actor->emotions.unopposable_retreat_timer>0)
{
real_point3d position;
struct prop_datum *prop = prop_get(actor->emotions.unopposable_retreat_prop_index);
point_from_line3d(&actor->input.position.head_position, global_up3d, 0.05f, &position);
render_debug_string_at_point(TRUE, ai_debug_drawstack(), csprintf(temporary, "retreat t%d", actor->emotions.unopposable_retreat_timer), global_real_argb_red);
render_debug_line(TRUE, &position, &prop->head_position, global_real_argb_red);
}
if (TEST_FLAG(actor_definition->flags, _actor_definition_fixed_crouch_facing_bit))
{
char const *string;
if (actor->control.desire_stationary_facing)
{
if (actor->control.fixed_stationary_facing)
{
render_debug_string_at_point(TRUE, ai_debug_drawstack(), "fixed-facing", global_real_argb_orange);
render_debug_vector(TRUE, &actor->input.position.head_position, &actor->control.fixed_stationary_facing_vector, 1.5f, global_real_argb_orange);
}
else
{
render_debug_string_at_point(TRUE, ai_debug_drawstack(), "desire-fixed-facing", global_real_argb_orange);
}
}
else
{
render_debug_string_at_point(TRUE, ai_debug_drawstack(), csprintf(temporary, "nostationary%s", actor->control.moving ? " (moving)" : ""), global_real_argb_orange);
}
}
}
/* Teams */
if (ai_debug.render_teams)
{
char const *teams[NUMBER_OF_SOLO_CAMPAIGN_TEAMS] =
{
"default",
"player",
"human",
"covenant",
"flood",
"sentinel",
"unused6",
"unused7",
"unused8",
"unused9"
};
render_debug_string_at_point(TRUE, ai_debug_drawstack(), actor->meta.team_index==NONE ? "none" : teams[actor->meta.team_index], global_real_argb_green);
}
/* Player ratings */
if (ai_debug.render_player_ratings && actor->meta.unit_index!=NONE)
{
real player_rating = ai_communication_get_player_rating(actor->meta.unit_index, TRUE, NULL, NULL);
render_debug_string_at_point(TRUE, ai_debug_drawstack(), csprintf(temporary, "%.1f", player_rating), player_rating==0.f ? global_real_argb_blue : global_real_argb_white);
}
/* Audibility */
if (ai_debug.render_audibility && actor_debug_info->field_A4)
{
real_argb_color const *color;
char const *aud_type;
char textstring[512];
if (actor_debug_info->field_A6==0)
{
color = global_real_argb_red;
aud_type = "none";
}
else if(actor_debug_info->field_A6==1)
{
color = global_real_argb_blue;
aud_type = "part";
}
else
{
color = global_real_argb_green;
aud_type = "full";
}
sprintf(textstring, "aud/%s %.1fp/%.1fd", aud_type, actor_debug_info->field_A8, actor_debug_info->field_AC);
if (actor_debug_info->field_B0!=-1.f)
{
strcat(textstring, csprintf(temporary, "/%.1fs/%.1ff", actor_debug_info->field_B0, actor_debug_info->field_B4));
}
render_debug_string_at_point(TRUE, ai_debug_drawstack(), textstring, color);
}
/* Props */
if (ai_debug.render_props || ai_debug.render_props_web)
{
struct prop_datum *prop;
struct prop_iterator iterator;
real_point3d prop_start_point;
short dead_count = 0;
short friend_count = 0;
short enemy_count = 0;
short orphan_count = 0;
short total_count = 0;
point_from_line3d(&actor->input.position.head_position, global_up3d, 0.2f, &prop_start_point);
prop_iterator_new(&iterator, actor_index);
while (prop = prop_iterator_next(&iterator))
{
++total_count;
if (prop->dead)
{
++dead_count;
}
else if (
prop->state>=_prop_state_uninspected_orphan &&
prop->state<=_prop_state_inspected_orphan)
{
match_assert("c:\\halo\\SOURCE\\ai\\ai_debug.c", 2230, prop->enemy);
++orphan_count;
}
else
{
if (prop->enemy)
{
++enemy_count;
}
else
{
++friend_count;
}
}
if ((render_exclusive || ai_debug.render_props_web) &&
(prop->enemy || !ai_debug.render_props_no_friends))
{
real_argb_color const *color;
real_point3d origin;
real_point3d string_point;
point_from_line3d(&prop->head_position, global_up3d, 0.2, &string_point);
switch (prop->state)
{
case 2:
case 3:
render_debug_line(TRUE, &prop_start_point, &prop->head_position, global_real_argb_yellow);
break;
case 1:
set_real_point3d(
&origin,
((1.f-prop->awareness)*prop_start_point.x) + (prop->awareness*prop->head_position.x),
((1.f-prop->awareness)*prop_start_point.y) + (prop->awareness*prop->head_position.y),
((1.f-prop->awareness)*prop_start_point.z) + (prop->awareness*prop->head_position.z)
);
render_debug_line(TRUE, &prop_start_point, &origin, global_real_argb_yellow);
render_debug_line(TRUE, &origin, &prop->head_position, global_real_argb_black);
break;
case 0:
render_debug_line(TRUE, &prop_start_point, &prop->head_position, global_real_argb_black);
break;
case 4:
case 5:
color = iterator.index==actor->meta.interesting_orphan_index ? global_real_argb_purple : global_real_argb_blue;
render_debug_line(TRUE, &prop_start_point, &prop->head_position, color);
if (!prop->definitely_located)
{
real_vector3d hint_vector;
real_argb_color const *alt_color = prop->state==_prop_state_uninspected_orphan ? global_real_argb_yellow : global_real_argb_blue;
set_real_vector3d(&hint_vector, prop->orphan_hint_vector.i, prop->orphan_hint_vector.j, 0.f);
render_debug_sphere(TRUE, &prop->head_position, 0.2f, alt_color);
render_debug_vector(TRUE, &prop->head_position, &hint_vector, 1.f, alt_color);
}
break;
default:
break;
}
point_from_line3d(&prop_start_point, global_up3d, 0.03f, &prop_start_point);
if (prop->required_ticks>0 ||
prop->state>=_prop_state_uninspected_orphan && prop->state<=_prop_state_inspected_orphan)
{
if (prop->required_ticks>0)
{
sprintf(temporary, "r%d ", prop->required_ticks);
}
else
{
strcpy(temporary, "");
}
if (prop->state>=_prop_state_uninspected_orphan && prop->state<=_prop_state_inspected_orphan)
{
char temp[256];
strcpy(temp, temporary);
sprintf(temporary, "%so%d ", temp, prop->orphan_lifespan_ticks);
}
if (prop->state==_prop_state_uninspected_orphan)
{
char temp[256];
strcpy(temp, temporary);
sprintf(temporary, "%si%d ", temp, prop->orphan_inspection_ticks);
}
render_debug_string_at_point(TRUE, &string_point, temporary, global_real_argb_pink);
point_from_line3d(&string_point, global_up3d, 0.05f, &string_point);
}
if (ai_debug.render_props_unreachable)
{
real_argb_color const *color;
if (prop->ignore)
{
color = global_real_argb_blue;
}
else
{
color = prop->preferred_target ? global_real_argb_pink : global_real_argb_red;
}
render_debug_string_at_point(TRUE, &string_point, csprintf(temporary, "%.2f", prop->target_weight), color);
point_from_line3d(&string_point, global_up3d, 0.05f, &string_point);
if (iterator.index==actor->target.target_prop_index)
{
render_debug_string_at_point(TRUE, &string_point, "target", global_real_argb_white);
point_from_line3d(&string_point, global_up3d, 0.05f, &string_point);
}
}
if (ai_debug.render_props_unopposable && prop->unreachable_ticks>0)
{
long time = prop->last_unreachable_time!=NONE ? game_time_get()-prop->last_unreachable_time : NONE;
render_debug_string_at_point(
TRUE,
&string_point,
csprintf(temporary, "unr %d %d", prop->unreachable_ticks, time),
global_real_argb_darkgreen);
point_from_line3d(&string_point, global_up3d, 0.05f, &string_point);
}
if (ai_debug.render_props_target_weight && prop->unopposable_enemy)
{
sprintf(
temporary,
"unopp c%d(%d) t%d",
prop->unopposable_casualties_inflicted,
prop->unopposable_casualty_decay_timer,
prop->unopposable_trigger_timer);
if (prop->unopposable_trigger_timer>0)
{
char string[256];
sprintf(string, "/%d h%d", prop->unopposable_trigger_threshold, prop->unopposable_trigger_hysteresis);
strcat(temporary, string);
}
render_debug_string_at_point(TRUE, &string_point, temporary, global_real_argb_pink);
point_from_line3d(&string_point, global_up3d, 0.05f, &string_point);
render_debug_line(TRUE, &prop_start_point, &prop->head_position, global_real_argb_pink);
point_from_line3d(&prop_start_point, global_up3d, 0.03f, &prop_start_point);
}
}
}
if (ai_debug.render_props_target_weight && actor->emotions.unopposable_retreat_timer>0)
{
real_point3d p0;
struct prop_datum const *retreating_prop = prop_get(actor->emotions.unopposable_retreat_prop_index);
point_from_line3d(&actor->input.position.head_position, global_up3d, 0.03f, &p0);
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "retreat t%d", actor->emotions.unopposable_retreat_timer),
global_real_argb_red);
render_debug_line(TRUE, &p0, &retreating_prop->head_position, global_real_argb_red);
}
if (render_exclusive || ai_debug.render_props_web)
{
sprintf(temporary, "d%d o%d e%d f%d", dead_count, orphan_count, enemy_count, friend_count);
}
else
{
sprintf(temporary, "%d", total_count);
}
render_debug_string_at_point(TRUE, ai_debug_drawstack(), temporary, global_real_argb_green);
}
if (ai_debug.render_secondary_looking && actor->control.secondary_look_type>0)
{
char const *direction_specification_type_strings[NUMBER_OF_DIRECTION_SPECIFICATION_TYPES] =
{
"move",
"prop",
"targ",
"point",
"vector",
"danger",
NULL
};
char const *secondary_look_type_strings[NUMBER_OF_SECONDARY_LOOK_TYPES] =
{
"none",
"noise",
"moving",
"impact",
"ack",
"bumped",
"deton",
"shoot",
"comm",
"comm/d",
"combat",
"damage",
"danger",
"script"
};
char const *secondary_look_priotity_strings[NUMBER_OF_SECONDARY_LOOK_PRIORITIES] =
{
"none",
"def",
"i/look",
"i/aim",
"aim",
"turn/a",
"stop/a",
"over",
"over/f"
};
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(
temporary,
"%s %s %s %d",
direction_specification_type_strings[actor->control.secondary_look_direction.type],
secondary_look_type_strings[actor->control.secondary_look_type],
secondary_look_priotity_strings[actor->control.secondary_look_priority],
actor->control.secondary_look_timer),
global_real_argb_magenta);
switch (actor->control.secondary_look_direction.type)
{
case _direction_specification_prop:
{
struct prop_datum *prop = prop_get(actor->control.secondary_look_direction.prop_index);
render_debug_line(
TRUE,
&actor->input.position.head_position,
&prop->head_position,
global_real_argb_magenta);
break;
}
case _direction_specification_target:
if (actor->target.target_prop_index!=NONE)
{
struct prop_datum *prop = prop_get(actor->target.target_prop_index);
render_debug_line(
TRUE,
&actor->input.position.head_position,
&prop->head_position,
global_real_argb_magenta);
}
break;
case _direction_specification_point:
render_debug_line(
TRUE,
&actor->input.position.head_position,
&actor->control.secondary_look_direction.point,
global_real_argb_magenta);
break;
case _direction_specification_vector:
{
real_point3d aim_pos;
point_from_line3d(
&actor->input.position.head_position,
&actor->control.secondary_look_direction.vector,
1.f,
&aim_pos);
render_debug_line(
TRUE,
&actor->input.position.head_position,
&aim_pos,
global_real_argb_magenta);
break;
}
default:
break;
}
}
/* Pursuit */
if (ai_debug.render_pursuit)
{
struct pursuit_location const *location = actor_get_pursuit_location(actor_index);
if (location)
{
if (location->type==0 && actor->target.target_prop_index!=NONE)
{
struct prop_datum *prop = prop_get(actor->target.target_prop_index);
render_debug_line(TRUE, &actor->input.position.head_position, &prop->body_position, actor_action_debug_color(actor_index));
}
else
{
if (location->type==1)
{
render_debug_line(TRUE, &actor->input.position.head_position, &location->position, actor_action_debug_color(actor_index));
}
}
}
}
/* Aiming vectors */
if (render_exclusive && ai_debug.render_aiming_vectors)
{
if (actor->meta.unit_index!=NONE)
{
real_point3d p0;
real_point3d p1;
real_vector3d forward;
point_from_line3d(&actor->input.position.head_position, global_up3d, 0.01f, &p0);
point_from_line3d(&actor->input.position.head_position, &actor->control.desired_facing_vector, 1.5f, &p1);
point_from_line3d(&p1, global_up3d, 0.01f, &p1);
render_debug_line(TRUE, &p0, &p1, global_real_argb_orange);
point_from_line3d(&actor->input.position.head_position, &actor->control.desired_aiming_vector, 1.4f, &p1);
point_from_line3d(&p1, global_up3d, 0.02f, &p1);
render_debug_line(TRUE, &p0, &p1, global_real_argb_green);
point_from_line3d(&actor->input.position.head_position, &actor->control.desired_looking_vector, 1.3f, &p1);
point_from_line3d(&p1, global_up3d, 0.03f, &p1);
render_debug_line(TRUE, &p0, &p1, global_real_argb_cyan);
p0.x = actor->input.position.head_position.x-global_up3d->i*0.04f;
p0.y = actor->input.position.head_position.y-global_up3d->j*0.04f;
p0.z = actor->input.position.head_position.z-global_up3d->k*0.04f;
unit_get_facing_vector(actor->meta.unit_index, &forward);
render_debug_vector(TRUE, &p0, &forward, 1.f, global_real_argb_red);
render_debug_vector(TRUE, &p0, &unit->unit.aiming_vector, 1.f, global_real_argb_darkgreen);
render_debug_vector(TRUE, &p0, &unit->unit.looking_vector, 1.f, global_real_argb_blue);
if (unit->object.type==_object_type_biped && unit->object.parent_object_index==NONE)
{
real_vector3d throttle_vector;
struct biped_definition *biped_definition = biped_definition_get(unit->definition_index);
unit_get_facing_vector(actor->meta.unit_index, &forward);
if (TEST_FLAG(biped_definition->biped.flags, _biped_flying_bit))
{
real_vector3d left;
real_vector3d up;
biped_build_flying_axes(&forward, &left, &up);
throttle_vector.i = forward.i*actor->output.throttle.i +
left.i*actor->output.throttle.j + up.i*actor->output.throttle.k;
throttle_vector.j = forward.j*actor->output.throttle.i +
left.j*actor->output.throttle.j + up.j*actor->output.throttle.k;
throttle_vector.k = forward.k*actor->output.throttle.i +
left.k*actor->output.throttle.j + up.k*actor->output.throttle.k;
}
else
{
real_vector3d v;
set_real_vector3d(&v, -forward.j, forward.i, 0.f);
throttle_vector.i = forward.i*actor->output.throttle.i +
v.i*actor->output.throttle.j;
throttle_vector.j = forward.j*actor->output.throttle.i +
v.j*actor->output.throttle.j;
throttle_vector.k = forward.k*actor->output.throttle.i +
v.k*actor->output.throttle.j;
}
point_from_line3d(&actor->input.position.body_position, global_up3d, 0.1f, &p0);
render_debug_vector(TRUE, &p0, &throttle_vector, 1.6f, global_real_argb_pink);
}
}
}
/* Gun positions */
if (ai_debug.render_gun_positions && actor->meta.unit_index!=NONE)
{
real_point3d estimated_position;
real_vector3d *gun_offset = NULL;
real_argb_color const *color = global_real_argb_red;
real_vector3d desired_facing = actor->input.aiming_vector;
real_vector2d desired_facing_horizontal;
desired_facing_horizontal.i = desired_facing.i;
desired_facing_horizontal.j = desired_facing.j;
if (normalize2d(&desired_facing_horizontal)>0.f)
{
desired_facing.i = desired_facing_horizontal.i;
desired_facing.j = desired_facing_horizontal.j;
desired_facing.k = 0.f;
}
else
{
desired_facing = actor->input.facing_vector;
}
if (actor->control.crouching)
{
if (magnitude_squared3d(&actor_variant_definition->ranged_combat.gun_offset_crouch)>_real_epsilon)
{
gun_offset = &actor_variant_definition->ranged_combat.gun_offset_crouch;
color = global_real_argb_magenta;
}
else
{
if (magnitude_squared3d(&actor_definition->perception.gun_offset_crouch)>_real_epsilon)
{
gun_offset = &actor_definition->perception.gun_offset_crouch;
color = global_real_argb_pink;
}
}
}
else
{
if (magnitude_squared3d(&actor_variant_definition->ranged_combat.gun_offset_stand)>_real_epsilon)
{
gun_offset = &actor_variant_definition->ranged_combat.gun_offset_stand;
color = global_real_argb_magenta;
}
else
{
if (magnitude_squared3d(&actor_definition->perception.gun_offset_stand)>_real_epsilon)
{
gun_offset = &actor_definition->perception.gun_offset_stand;
color = global_real_argb_pink;
}
}
}
if (gun_offset==NULL)
{
estimated_position = actor->input.position.head_position;
}
else
{
unit_estimate_position(
actor->meta.unit_index,
_unit_estimate_gun_position,
&actor->input.position.body_position,
&desired_facing,
gun_offset,
&estimated_position);
}
render_debug_vector(TRUE, &estimated_position, &actor->input.aiming_vector, 1.f, color);
}
/* Targets */
if ((ai_debug.render_targets || ai_debug.render_targets_last_visible) &&
actor->target.target_type!=0 &&
actor->target.target_prop_index!=NONE)
{
real_point3d actor_target_position;
real_point3d prop_target_position;
struct prop_datum *prop = prop_get(actor->target.target_prop_index);
real_argb_color const *target_color = global_real_argb_white;
switch (actor->target.target_type-1)
{
case _actor_target_partial_enemy:
target_color = global_real_argb_grey;
break;
case _actor_target_dead_enemy:
target_color = global_real_argb_green;
break;
case _actor_target_disregarded_orphan:
target_color = global_real_argb_salmon;
break;
case _actor_target_inspected_orphan:
target_color = global_real_argb_blue;
break;
case _actor_target_uninspected_orphan:
target_color = global_real_argb_lightblue;
break;
case _actor_target_definite_orphan:
target_color = global_real_argb_cyan;
break;
case _actor_target_acknowledged_enemy:
target_color = global_real_argb_purple;
break;
case _actor_target_clear_line_of_sight_enemy:
target_color = global_real_argb_yellow;
break;
case _actor_target_potentially_dangerous_enemy:
target_color = global_real_argb_orange;
break;
case _actor_target_visible_enemy:
target_color = global_real_argb_red;
break;
case _actor_target_damaging_enemy:
target_color = global_real_argb_magenta;
break;
default:
match_vassert("c:\\halo\\SOURCE\\ai\\ai_debug.c", 2653, FALSE, NULL);
}
point_from_line3d(&actor->input.position.head_position, global_down3d, 0.01f, &actor_target_position);
point_from_line3d(&prop->head_position, global_down3d, 0.01f, &prop_target_position);
render_debug_line(TRUE, &actor_target_position, &prop_target_position, target_color);
if (ai_debug.render_targets_last_visible && prop->last_visible_time!=NONE)
{
render_debug_sphere(TRUE, &prop->last_visible_head_position, 0.2f, target_color);
}
if (prop->unreachable_ticks>0 && (!ai_debug.render_props || !ai_debug.render_props_unopposable))
{
long time = prop->last_unreachable_time!=NONE ? game_time_get()-prop->last_unreachable_time : NONE;
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "unr %d %d", prop->unreachable_ticks, time),
global_real_argb_darkgreen);
}
}
/* States */
if (ai_debug.render_states)
{
struct observer_result const *camera = observer_get_camera(0);
if (camera)
{
real_point3d position;
point_from_line3d(&camera->position, &camera->forward, 0.05f, &position);
render_debug_line(TRUE, &position, &actor->input.position.head_position, actor_action_debug_color(actor_index));
}
}
/* Current state */
if (ai_debug.render_current_state)
{
if (actor->meta.encounter_index!=NONE)
{
struct encounter_datum *encounter = encounter_get(actor->meta.encounter_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);
struct squad_definition *squad_definition = TAG_BLOCK_GET_ELEMENT(
&encounter_definition->squads,
actor->meta.squad_index,
struct squad_definition);
struct squad_datum *squad = encounter_get_squad(encounter, actor->meta.squad_index);
if (squad->delay_timer>0)
{
if (squad->delay_timer_started)
{
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "delaying %d", squad->delay_timer),
global_real_argb_green);
}
else
{
if (TEST_FLAG(squad_definition->flags, _squad_delay_forever_bit))
{
render_debug_string_at_point(TRUE, ai_debug_drawstack(), "delay forever", global_real_argb_green);
}
else
{
render_debug_string_at_point(TRUE, ai_debug_drawstack(), "delay not triggered", global_real_argb_green);
}
}
}
}
switch (actor->state.action)
{
case _actor_action_flee:
if (actor->state.action_data.flee.has_approach_point>0)
{
render_debug_sphere(TRUE, &actor->state.action_data.flee.approach_point, 0.25f, actor_action_debug_color(actor_index));
}
break;
case _actor_action_fight:
if (actor->state.action_data.alert.move_position_order>0)
{
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "change %d", actor->state.action_data.alert.move_position_order),
actor_action_debug_color(actor_index));
}
break;
case _actor_action_guard:
if (actor->state.action_data.guard.wait_ticks>0)
{
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "wait %d", actor->state.action_data.guard.wait_ticks),
actor_action_debug_color(actor_index));
}
if (actor->state.action_data.guard.look_ticks>0)
{
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "look %d", actor->state.action_data.guard.look_ticks),
actor_action_debug_color(actor_index));
}
if (actor->state.action_data.guard.cower)
{
if (actor->state.action_data.guard.cower_from_retreat)
{
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "retreat %d", actor->emotions.unopposable_retreat_timer),
actor_action_debug_color(actor_index));
}
else
{
char const *string = actor->state.action_data.guard.cower_panicked ? "panic" : "hide";
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "%s %d", string, actor->state.action_data.guard.cower_ticks),
actor_action_debug_color(actor_index));
}
}
if (actor->state.action_data.guard.has_guard_direction)
{
render_debug_vector(
TRUE,
&actor->input.position.head_position,
&actor->state.action_data.guard.guard_direction,
2.5f,
actor_action_debug_color(actor_index));
}
break;
case _actor_action_uncover:
case _actor_action_search:
{
struct pursuit_location *pursuit_location = actor_get_pursuit_location(actor_index);
long delay = 0;
match_assert("c:\\halo\\SOURCE\\ai\\ai_debug.c", 2773, pursuit_location != NULL);
if (pursuit_location->type==_pursuit_location_target)
{
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "targ(%d)", actor->firing_positions.pursuit_positions_count),
actor_action_debug_color(actor_index));
}
else if (pursuit_location->type==_pursuit_location_position)
{
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "pt(%d)", actor->firing_positions.pursuit_positions_count),
actor_action_debug_color(actor_index));
}
else
{
render_debug_string_at_point(1, ai_debug_drawstack(), "undirected", actor_action_debug_color(actor_index));
}
if (actor->state.action==_actor_action_uncover)
{
delay = actor->state.action_data.uncover.uncover_remaining_time;
}
else if (actor->state.action==_actor_action_search)
{
if (120-actor->state.action_data.search.search_failure_timer<=actor->state.action_data.search.search_remaining_time)
{
delay = 120-actor->state.action_data.search.search_failure_timer;
}
else
{
delay = actor->state.action_data.search.search_remaining_time;
}
}
render_debug_string_at_point(TRUE, ai_debug_drawstack(), csprintf(temporary, "delay %d", delay), actor_action_debug_color(actor_index));
break;
}
case _actor_action_vehicle:
if (actor->state.action_data.vehicle.started_entry)
{
render_debug_string_at_point(TRUE, ai_debug_drawstack(), "entering", global_real_argb_darkgreen);
}
else
{
char buffer[256];
strcpy(buffer, "");
if (actor->state.action_data.vehicle.currently_correct_facing)
{
strcat(buffer, "facing-ok ");
}
if (actor->state.action_data.vehicle.currently_within_range)
{
strcat(buffer, "range-ok ");
}
if (actor->state.action_data.vehicle.fake_entry_potential_timer>0)
{
strcat(buffer, csprintf(temporary, "fake-entry %d ", actor->state.action_data.vehicle.fake_entry_potential_timer));
}
if (actor_path_has_path(actor_index))
{
if (actor_path_at_destination(actor_index))
{
strcat(buffer, "destination-");
}
strcat(buffer, "moving ");
}
if (actor->state.action_data.vehicle.lock_facing)
{
strcat(buffer, "locked ");
}
render_debug_string_at_point(TRUE, ai_debug_drawstack(), buffer, global_real_argb_darkgreen);
}
render_debug_line(
TRUE,
&actor->input.position.body_position,
&actor->state.action_data.vehicle.destination_point,
global_real_argb_darkgreen);
render_debug_vector(
TRUE,
&actor->state.action_data.vehicle.destination_point,
&actor->state.action_data.vehicle.destination_facing,
1.f,
global_real_argb_yellow);
break;
case _actor_action_charge:
switch (actor->state.action_data.charge.goal)
{
case _charge_goal_close_range:
render_debug_string_at_point(TRUE, ai_debug_drawstack(), "charge", global_real_argb_red);
break;
case _charge_goal_stalking:
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(
temporary,
"stalk%s %s disc%d",
actor->state.action_data.charge.stalking_catch_target ? " catchtarget" : "",
actor->state.action_data.charge.stalking_currently_exposed ? " exposed" : "",
actor->state.action_data.charge.stalking_discovery_timer),
global_real_argb_blue);
break;
case _charge_goal_melee:
render_debug_string_at_point(TRUE, ai_debug_drawstack(), "melee", global_real_argb_red);
break;
case _charge_goal_melee_leaping:
render_debug_string_at_point(TRUE, ai_debug_drawstack(), "melee-leap", global_real_argb_red);
break;
case _charge_goal_vehicle_strafing:
render_debug_string_at_point(TRUE, ai_debug_drawstack(), "strafe", global_real_argb_red);
break;
case _charge_goal_vehicle_ramming:
render_debug_string_at_point(TRUE, ai_debug_drawstack(), "ramming", global_real_argb_red);
break;
default:
break;
}
if (actor->emotions.berserk)
{
render_debug_string_at_point(TRUE, ai_debug_drawstack(), "berserk", global_real_argb_red);
}
break;
case _actor_action_obey:
{
struct ai_command_definition *command = NULL;
if (actor->state.action_data.obey.command_list_index!=NONE)
{
struct ai_command_list_definition const* command_list = TAG_BLOCK_GET_ELEMENT(
&global_scenario_get()->ai_command_lists,
actor->state.action_data.obey.command_list_index,
struct ai_command_list_definition);
if (!actor->meta.swarm)
{
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(
temporary,
"command-list %s: #%d of #%d",
command_list->name,
actor->state.action_data.obey.simple_control.current_command_index+1,
command_list->commands.count),
global_real_argb_purple);
if (actor->state.action_data.obey.simple_control.current_command_index<command_list->commands.count)
{
command = TAG_BLOCK_GET_ELEMENT(
&command_list->commands,
actor->state.action_data.obey.simple_control.current_command_index,
struct ai_command_definition);
}
if (TEST_FLAG(actor->state.action_data.obey.simple_control.metadata_flags, _obey_metadata_commands_finished_bit))
{
render_debug_string_at_point(TRUE, ai_debug_drawstack(), "finished", global_real_argb_purple);
}
if (command)
{
boolean v427 = FALSE;
boolean v426 = FALSE;
boolean v425 = FALSE;
boolean v424 = FALSE;
switch (command->atom_type)
{
case _ai_atom_go_to:
v427 = TRUE;
v426 = TRUE;
break;
case _ai_atom_go_to_and_face:
v427 = TRUE;
v426 = TRUE;
v425 = TRUE;
break;
case _ai_atom_move_direction:
v426 = TRUE;
v424 = TRUE;
break;
case _ai_atom_look:
case _ai_atom_shoot:
case _ai_atom_grenade:
v426 = TRUE;
break;
default:
break;
}
if (v427)
{
if (actor->state.action_data.charge.melee_suicide)
{
render_debug_sphere(
TRUE,
&actor->state.action_data.obey.complex_control.destination_point,
actor->state.action_data.obey.complex_control.destination_radius_valid ?
actor->state.action_data.obey.complex_control.destination_radius :
0.5f,
global_real_argb_purple);
}
}
if (v426)
{
if (command->point1_index>=0 &&
command->point1_index<command_list->points.count)
{
real_point3d position;
struct ai_command_point_definition const *point = TAG_BLOCK_GET_ELEMENT(
&command_list->points,
command->point1_index,
struct ai_command_point_definition);
render_debug_line(
TRUE,
&actor->input.position.head_position,
&point->position,
global_real_argb_purple);
point_from_line3d(&point->position, global_up3d, 0.1f, &position);
render_debug_string_at_point(
TRUE,
&position,
csprintf(temporary, "%d", command->point1_index),
global_real_argb_purple);
}
else
{
if (v424 && command->parameter2>=0.f && command->parameter2<360.f)
{
real_vector3d v;
vector3d_from_angle(&v, command->parameter2);
render_debug_vector(TRUE, &actor->input.position.head_position, &v, 1.5f, global_real_argb_purple);
}
else
{
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "error: invalid point 1 specified (%d)", command->point1_index),
global_real_argb_purple);
}
}
}
if (v425)
{
if (command->point2_index>=0 &&
command->point2_index<command_list->points.count)
{
real_point3d position;
struct ai_command_point_definition const *point = TAG_BLOCK_GET_ELEMENT(
&command_list->points,
command->point2_index,
struct ai_command_point_definition);
render_debug_line(
TRUE,
&actor->input.position.head_position,
&point->position,
global_real_argb_purple);
point_from_line3d(&point->position, global_up3d, 0.1f, &position);
render_debug_string_at_point(1, &position, csprintf(temporary, "%d", command->point2_index), global_real_argb_purple);
}
else
{
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "error: invalid point 2 specified (%d)", command->point2_index),
global_real_argb_purple);
}
}
}
}
if (command)
{
action_obey_describe_command(global_scenario_get(), command, temporary, NUMBEROF(temporary));
render_debug_string_at_point(TRUE, ai_debug_drawstack(), temporary, global_real_argb_purple);
}
}
break;
}
default:
break;
}
}
/* Shooting */
if (ai_debug.render_shooting)
{
if (actor_debug_info->firing_decision!=_firing_no_target)
{
char const *string = actor_move_animation_busy(actor_index) ? "busy " : "";
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(
temporary,
"%srof %.1f err %.1f dmg %.1f blk %d",
string,
actor_debug_info->shooting_rof,
actor->control.burst_error,
actor->control.burst_damage_modifier,
actor->control.blocked_communication_timer),
global_real_argb_white);
if (actor->emotions.berserk)
{
render_debug_string_at_point(TRUE, ai_debug_drawstack(), "berserk", global_real_argb_yellow);
}
else if (actor->control.firing_at_new_target)
{
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(
temporary,
"newtarget %d",
actor_variant_definition->ranged_combat.new_target_pattern_time*TICKS_PER_SECOND-
actor->control.current_fire_target_timer
),
global_real_argb_blue);
}
else if (actor->control.firing_while_moving)
{
render_debug_string_at_point(TRUE, ai_debug_drawstack(), "moving", global_real_argb_green);
}
switch (actor->control.fire_state)
{
case _actor_fire_state_none:
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
"none",
global_real_argb_red);
break;
case _actor_fire_state_holding:
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "delay %d", actor->control.fire_state_timer),
global_real_argb_red);
break;
case _actor_fire_state_bursting:
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "burst %d", actor->control.fire_state_timer),
global_real_argb_red);
break;
case _actor_fire_state_pausing:
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "pause %d", actor->control.fire_state_timer),
global_real_argb_red);
break;
case _actor_fire_state_wild:
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "wildfire %d", actor->control.fire_state_timer),
global_real_argb_red);
break;
default:
match_vassert("c:\\halo\\SOURCE\\ai\\ai_debug.c", 3081, FALSE, NULL);
break;
}
}
if (VALID_INDEX(actor_debug_info->firing_decision, NUMBER_OF_ACTOR_DEBUG_FIRING_DECISIONS))
{
char const *firing_decision_names[NUMBER_OF_ACTOR_DEBUG_FIRING_DECISIONS] =
{
"firing disabled",
"animation busy",
"wrong target",
"no target",
"outside active region",
"not visible",
"outside range",
"blocked",
"first burst align",
"first burst delay",
"burst pause align",
"burst pause",
"firing wildly",
"bursting",
"in midair",
"not crouching",
"not standing",
"not stationary",
"underwater",
"minimum range"
};
render_debug_string_at_point(TRUE, ai_debug_drawstack(), firing_decision_names[actor_debug_info->firing_decision], global_real_argb_blue);
}
}
/* Grenade decisions */
if (ai_debug.render_grenade_decisions)
{
if (actor_debug_info->grenade_eval_time!=NONE &&
actor_debug_info->grenade_eval_time+7 >= game_time_get())
{
switch (actor_debug_info->grenade_decision)
{
case _grenade_vehicle:
csstrcpy(temporary, "in vehicle");
break;
case _grenade_unit_busy:
csstrcpy(temporary, "unit busy");
break;
case _grenade_being_hurt:
sprintf(temporary, "dmg %.2f", actor_debug_info->grenade_current_damage);
break;
case _grenade_no_grenades:
csstrcpy(temporary, "no grenades");
break;
case _grenade_random_failed:
sprintf(
temporary,
"random %.2f > %.2f",
actor_debug_info->grenade_random_value,
actor_debug_info->grenade_random_chance);
break;
case _grenade_encounter_timeout:
sprintf(temporary, "encounter time %d", actor_debug_info->grenade_encounter_timeout_ticks);
break;
case _grenade_target_failed:
csstrcpy(temporary, "no target");
break;
case _grenade_not_enough_enemies:
sprintf(
temporary,
"not enough enemy %d < %d",
actor_debug_info->grenade_enemy_count,
actor_debug_info->grenade_required_enemy_count);
break;
case _grenade_collateral_damage:
csstrcpy(temporary, "collateral dmg");
break;
case _grenade_trajectory_failed:
csstrcpy(temporary, "no trajectory");
break;
case _grenade_success:
csstrcpy(temporary, "success");
break;
default:
csstrcpy(temporary, "<unknown>");
break;
}
render_debug_string_at_point(TRUE, ai_debug_drawstack(), temporary, global_real_argb_pink);
}
if (actor->control.grenade_trying_to_throw)
{
real damage = unit==NULL ? 0.f : unit->object.current_body_damage;
char const *string = actor->meta.unit_index==NONE || !unit_is_busy(actor->meta.unit_index) ? "not-" : "";
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "trying: %sbusy dmg %.1f", string, damage),
global_real_argb_pink);
}
}
/* Danger zones */
if (ai_debug.render_danger_zones && actor->danger_zone.danger_type>0)
{
real_argb_color const *color;
if (actor->danger_zone.currently_perceived)
{
if (actor->danger_zone.acknowledgement_timer>0)
{
color = global_real_argb_white;
}
else
{
if (actor->danger_zone.noticed_danger)
{
color = global_real_argb_yellow;
}
else
{
color = global_real_argb_blue;
}
}
}
else
{
color = global_real_argb_darkgreen;
}
render_debug_line(TRUE, &actor->input.position.head_position, &actor->danger_zone.position, color);
render_debug_sphere(TRUE, &actor->danger_zone.position, actor->danger_zone.danger_radius, global_real_argb_red);
render_debug_vector(TRUE, &actor->danger_zone.position, &actor->danger_zone.velocity, 45.f, global_real_argb_red);
render_debug_sphere(
TRUE,
&actor->danger_zone.bounding_sphere_center,
actor->danger_zone.bounding_sphere_radius,
global_real_argb_orange);
if (actor->danger_zone.danger_type==_actor_unopposable_danger_shooting)
{
char const *string = actor->danger_zone.projectile.time_until_explosion==NONE ?
"NONE" :
csprintf(temporary, "%d", actor->danger_zone.projectile.time_until_explosion);
render_debug_string_at_point(
TRUE,
&actor->danger_zone.position,
string,
color);
}
if (actor->danger_zone.danger_type==_actor_unopposable_danger_visible)
{
char const *string = actor->danger_zone.projectile.time_until_explosion==NONE ?
"NONE" :
csprintf(temporary, "%d", actor->danger_zone.projectile.time_until_explosion);
render_debug_string_at_point(
TRUE,
&actor->danger_zone.position,
string,
color);
}
if (actor_debug_info->danger_avoidance_time!=NONE)
{
if (actor_debug_info->danger_avoidance_time+15 >= game_time_get())
{
boolean avoiding;
if (actor_debug_info->danger_abandoned_path)
{
render_debug_string_at_point(TRUE, ai_debug_drawstack(), "discarded fp", global_real_argb_magenta);
}
avoiding = TRUE;
switch (actor_debug_info->danger_decision)
{
case _danger_avoidance_none:
avoiding = FALSE;
break;
case _danger_avoidance_unnoticed:
strcpy(temporary, "unnoticed");
break;
case _danger_avoidance_animation_busy:
strcpy(temporary, "animation busy");
break;
case _danger_avoidance_vehicle:
strcpy(temporary, "in vehicle");
break;
case _danger_avoidance_far_away:
sprintf(
temporary,
"far away (%.1f > %.1f)",
actor_debug_info->danger_far_dist,
actor_debug_info->danger_far_radius);
break;
case _danger_avoidance_outside_zone:
sprintf(
temporary,
"outside (%.1f > %.1f)",
actor_debug_info->danger_zone_dist,
actor_debug_info->danger_zone_radius);
break;
case _danger_avoidance_evasion_disallowed:
strcpy(temporary, "evasion not allowed");
break;
case _danger_avoidance_no_safe_direction:
strcpy(temporary, "no safe direction");
break;
case _danger_avoidance_no_desire:
if (actor_debug_info->danger_intersect_time==REAL_MAX)
{
strcpy(temporary, "no desire (no int'n)");
}
else
{
sprintf(temporary, "no desire (int'n %.1f)", actor_debug_info->danger_intersect_time);
}
break;
case _danger_avoidance_can_avoid:
strcpy(temporary, "can avoid");
break;
case _danger_avoidance_imminent_explosion:
strcpy(temporary, "imminent explosion");
break;
case _danger_avoidance_imminent_impact:
strcpy(temporary, "imminent impact");
break;
case _danger_avoidance_no_animation:
strcpy(temporary, "no animation");
break;
case _danger_avoidance_attached_to_us:
strcpy(temporary, "attached to us");
break;
default:
strcpy(temporary, "<error>");
break;
}
if (avoiding)
{
render_debug_string_at_point(TRUE, ai_debug_drawstack(), temporary, global_real_argb_magenta);
}
}
}
if (actor_debug_info->dive_decision_time!=NONE &&
actor_debug_info->dive_decision_time+15 >= game_time_get())
{
switch (actor_debug_info->dive_decision)
{
case _dive_not_attempted:
csstrcpy(temporary, "not attempted");
break;
case _dive_cannot_move:
csstrcpy(temporary, "cannot move");
break;
case _dive_no_animation:
csstrcpy(temporary, "animation unavailable");
break;
case _dive_animation_failure:
csstrcpy(temporary, "animation failed");
break;
case _dive_success:
csstrcpy(temporary, "success");
break;
default:
csstrcpy(temporary, "<error>");
break;
}
render_debug_string_at_point(TRUE, ai_debug_drawstack(), temporary, global_real_argb_purple);
}
}
/* Trigger */
if (ai_debug.render_trigger && TEST_FLAG(actor->output.control_flags, _unit_control_weapon_primary_trigger_bit))
{
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "trigger %.1f", actor->output.analog_primary_trigger),
global_real_argb_yellow);
}
/* Control */
if (ai_debug.render_control && actor->meta.unit_index!=NONE)
{
short control_flag_bit;
const char *control_flag_names[NUMBER_OF_UNIT_CONTROL_FLAGS] =
{
"crouch",
"jump",
"user1",
"user2",
"light",
"exactfacing",
"action",
"equipment",
"lookdontturn",
"forcealert",
"reload",
"trigger",
"trigger2",
"grenade"
};
short flag_count = NUMBER_OF_UNIT_CONTROL_FLAGS;
short count = 0;
strcpy(temporary, "");
for (control_flag_bit = 0; control_flag_bit<NUMBER_OF_UNIT_CONTROL_FLAGS; ++control_flag_bit)
{
if (TEST_FLAG(actor->output.control_flags, control_flag_bit))
{
if (count > 0)
{
strcat(temporary, " ");
}
if (control_flag_bit<NUMBER_OF_UNIT_CONTROL_FLAGS)
{
strcat(temporary, control_flag_names[control_flag_bit]);
}
else
{
char string[72];
sprintf(string, "<unknown %d>", control_flag_bit);
strcat(temporary, string);
}
++count;
}
}
if (count>0)
{
render_debug_string_at_point(TRUE, ai_debug_drawstack(), temporary, global_real_argb_yellow);
}
count = 0;
strcpy(temporary, "");
for (control_flag_bit = 0; control_flag_bit<NUMBER_OF_UNIT_CONTROL_FLAGS; ++control_flag_bit)
{
if (TEST_FLAG(actor->output.persistent_control_flags, control_flag_bit))
{
if (count > 0)
{
csstrcat(temporary, " ");
}
if (control_flag_bit<NUMBER_OF_UNIT_CONTROL_FLAGS)
{
strcat(temporary, control_flag_names[control_flag_bit]);
}
else
{
char string[72];
sprintf(string, "<unknown %d>", control_flag_bit);
strcat(temporary, string);
}
++count;
}
}
if (count>0)
{
char string[72];
sprintf(string, ": persistent %d", actor->output.persistent_control_ticks);
strcat(temporary, string);
render_debug_string_at_point(TRUE, ai_debug_drawstack(), temporary, global_real_argb_orange);
}
{
const char *movement_type_strings[NUMBER_OF_ACTOR_MOVEMENT_TYPES] =
{
"noncombat",
"asleep",
"combat",
"flee",
NULL
};
const char *aiming_speed_names[NUMBER_OF_UNIT_AIMING_SPEEDS] =
{
"alert",
"casual"
};
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(), csprintf(
temporary,
"m-%s a-%s",
movement_type_strings[actor->output.movement_type],
aiming_speed_names[actor->output.aiming_speed]),
global_real_argb_magenta);
}
if (TEST_FLAG(actor->output.control_flags, _unit_control_weapon_primary_trigger_bit))
{
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "analog %.2f", actor->output.analog_primary_trigger),
global_real_argb_cyan);
}
if (actor->output.animation.impulse!=NONE)
{
real_point3d base_point;
real_vector3d alignment_vector_3d;
point_from_line3d(&actor->input.position.body_position, global_up3d, 0.2f, &base_point);
alignment_vector_3d = actor->control.current_fire_target_aim_vector;
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "animation %d", actor->output.animation.impulse),
global_real_argb_pink);
render_debug_vector(
TRUE,
&base_point,
&alignment_vector_3d,
1.f,
global_real_argb_pink);
}
{
real_point3d p0;
real_point3d p1;
point_from_line3d(&actor->input.position.head_position, global_up3d, 0.01f, &p0);
point_from_line3d(&actor->input.position.head_position, &actor->output.facing_vector, 1.3f, &p1);
point_from_line3d(&p1, global_up3d, 0.01f, &p1);
render_debug_line(TRUE, &p0, &p1, global_real_argb_red);
point_from_line3d(&actor->input.position.head_position, &actor->output.aiming_vector, 1.2f, &p1);
point_from_line3d(&p1, global_up3d, 0.02f, &p1);
render_debug_line(TRUE, &p0, &p1, global_real_argb_green);
point_from_line3d(&actor->input.position.head_position, &actor->output.looking_vector, 1.1f, &p1);
point_from_line3d(&p1, global_up3d, 0.03f, &p1);
render_debug_line(TRUE, &p0, &p1, global_real_argb_blue);
if (unit->object.type==_object_type_biped && unit->object.parent_object_index==NONE)
{
real_vector3d throttle_vector;
real_vector3d facing_vector;
real_vector3d right_facing_vector;
struct biped_definition const *biped_definition = biped_definition_get(unit->definition_index);
unit_get_facing_vector(actor->meta.unit_index, &facing_vector);
if (TEST_FLAG(biped_definition->biped.flags, _biped_flying_bit))
{
real_vector3d left_vector;
real_vector3d up_vector;
biped_build_flying_axes(&facing_vector, &left_vector, &up_vector);
throttle_vector.i = facing_vector.i*actor->output.throttle.i +
left_vector.i*actor->output.throttle.j + up_vector.i*actor->output.throttle.k;
throttle_vector.j = facing_vector.j*actor->output.throttle.i +
left_vector.j*actor->output.throttle.j + up_vector.j*actor->output.throttle.k;
throttle_vector.k = facing_vector.k*actor->output.throttle.i +
left_vector.k*actor->output.throttle.j + up_vector.k*actor->output.throttle.k;
}
else
{
set_real_vector3d(&right_facing_vector, -facing_vector.j, facing_vector.i, 0.f);
throttle_vector.i = facing_vector.i*actor->output.throttle.i +
right_facing_vector.i*actor->output.throttle.j;
throttle_vector.j = facing_vector.j*actor->output.throttle.i +
right_facing_vector.j*actor->output.throttle.j;
throttle_vector.k = facing_vector.k*actor->output.throttle.i +
right_facing_vector.k*actor->output.throttle.j;
}
point_from_line3d(&actor->input.position.body_position, global_up3d, 0.1f, &p0);
render_debug_vector(TRUE, &p0, &throttle_vector, 1.6f, global_real_argb_purple);
}
}
}
/* Charge decisions */
if (ai_debug.render_charge_decisions &&
actor_debug_info->charge_last_time!=NONE &&
actor_debug_info->charge_last_time+TICKS_PER_SECOND >= game_time_get())
{
switch (actor_debug_info->charge_decision)
{
case _charge_vehicle_success:
csstrcpy(temporary, "vehicle-success");
break;
case _charge_vehicle_not_driver:
csstrcpy(temporary, "vehicle-notdriver");
break;
case _charge_melee_swarm_cant:
csstrcpy(temporary, "melee-swarmcan't");
break;
case _charge_melee_inhibited:
csstrcpy(temporary, "melee-inhibited");
break;
case _charge_melee_notarget:
csstrcpy(temporary, "melee-notarget");
break;
case _charge_melee_no_animation:
sprintf(temporary, "melee-noanimation (%sairborne)", actor_debug_info->field_198 ? "" : "not-");
break;
case _charge_melee_cannot_move:
sprintf(temporary, "melee-cannotmove (%f)", actor_debug_info->field_194);
break;
case _charge_melee_success:
sprintf(temporary, "melee-success (%sairborne)", actor_debug_info->field_198 ? "" : "not-");
break;
case _charge_stalking_success:
csstrcpy(temporary, "stalking-success");
break;
case _charge_close_success:
csstrcpy(temporary, "close-success");
break;
default:
sprintf(temporary, "<unknown charge-setup decision %d>", actor_debug_info->charge_decision);
break;
}
render_debug_string_at_point(TRUE, ai_debug_drawstack(), temporary, global_real_argb_red);
}
/* Melee check */
if (ai_debug.render_melee_check &&
actor_debug_info->last_melee_time!=NONE &&
actor_debug_info->last_melee_time+TICKS_PER_SECOND >= game_time_get())
{
render_debug_vector(TRUE, &actor_debug_info->field_108, &actor_debug_info->field_114, 1.5f, global_real_argb_red);
render_debug_point(TRUE, &actor_debug_info->field_120, 0.2f, global_real_argb_red);
if (!actor_debug_info->field_139)
{
real_vector3d v;
real_point3d p0;
real_point3d p1;
real_point3d p2;
render_debug_line(TRUE, &actor_debug_info->field_120, &actor_debug_info->field_13C, global_real_argb_purple);
render_debug_sphere(TRUE, &actor_debug_info->field_13C, 0.2f, global_real_argb_purple);
point_from_line3d(&actor_debug_info->field_108, &actor_debug_info->field_12C, actor_debug_info->field_14C, &p0);
render_debug_line(TRUE, &actor_debug_info->field_108, &p0, global_real_argb_green);
point_from_line3d(&actor_debug_info->field_108, &actor_debug_info->field_12C, actor_debug_info->field_148, &p1);
perpendicular3d(&actor_debug_info->field_12C, &v);
p0.x = p1.x + v.i*0.3f;
p0.y = p1.y + v.j*0.3f;
p0.z = p1.z + v.k*0.3f;
p2.x = p1.x - v.i*0.3f;
p2.y = p1.y - v.j*0.3f;
p2.z = p1.z - v.k*0.3f;
render_debug_line(TRUE, &p0, &p2, global_real_argb_green);
}
if (actor_debug_info->field_138)
{
render_debug_vector(TRUE, &actor_debug_info->field_108, &actor_debug_info->field_12C, 2.f, actor_debug_info->field_139 ? global_real_argb_yellow : global_real_argb_purple);
}
else
{
render_debug_vector(TRUE, &actor_debug_info->field_108, &actor_debug_info->field_12C, 2.f, global_real_argb_white);
}
}
/* Vehicle avoidance */
if (ai_debug.render_vehicle_avoidance &&
actor_debug_info->last_vehicle_avoidance_time!=NONE &&
actor_debug_info->last_vehicle_avoidance_time+TICKS_PER_SECOND >= game_time_get())
{
real_point3d p0;
real_point3d p1;
real_point3d p2;
real_vector3d v0;
render_debug_line(TRUE, &actor_debug_info->field_C8, &actor_debug_info->field_E4, global_real_argb_green);
render_debug_sphere(TRUE, &actor_debug_info->field_D4, actor_debug_info->field_E0, global_real_argb_yellow);
p1 = actor_debug_info->field_E4;
p0 = p1;
p0.x = p1.x - 0.2f;
p1.x = p1.x + 0.2f;
render_debug_line(TRUE, &p0, &p1, global_real_argb_red);
p0.x = p0.x + 0.2f;
p1.x = p1.x - 0.2f;
p0.y = p0.y - 0.2f;
p1.y = p1.y + 0.2f;
render_debug_line(TRUE, &p0, &p1, global_real_argb_red);
p0.y = p0.y + 0.2f;
p1.y = p1.y - 0.2f;
p0.z = p0.z - 0.2f;
p1.z = p1.z + 0.2f;
render_debug_line(TRUE, &p0, &p1, global_real_argb_red);
vector_from_points3d(&actor_debug_info->field_C8, &actor_debug_info->field_E4, &v0);
point_from_line3d(&actor_debug_info->field_C8, &v0, actor_debug_info->field_F0, &p2);
p1 = p2;
p0 = p2;
p0.x = p2.x - 0.2f;
p1.x = p2.x + 0.2f;
render_debug_line(TRUE, &p0, &p1, global_real_argb_blue);
p0.x = p0.x + 0.2f;
p1.x = p1.x - 0.2f;
p0.y = p0.y - 0.2f;
p1.y = p1.y + 0.2f;
render_debug_line(TRUE, &p0, &p1, global_real_argb_blue);
p0.y = p0.y + 0.2f;
p1.y = p1.y - 0.2f;
p0.z = p0.z - 0.2f;
p1.z = p1.z + 0.2f;
render_debug_line(TRUE, &p0, &p1, global_real_argb_blue);
if (actor_debug_info->field_F4)
{
render_debug_line(TRUE, &actor_debug_info->field_D4, &actor_debug_info->field_F8, global_real_argb_yellow);
render_debug_line(TRUE, &actor_debug_info->field_C8, &actor_debug_info->field_F8, global_real_argb_red);
p1 = actor_debug_info->field_F8;
p0 = p1;
p0.x = p1.x - 0.2f;
p1.x = p1.x + 0.2f;
render_debug_line(TRUE, &p0, &p1, global_real_argb_blue);
p0.x = p0.x + 0.2f;
p1.x = p1.x - 0.2f;
p0.y = p0.y - 0.2f;
p1.y = p1.y + 0.2f;
render_debug_line(TRUE, &p0, &p1, global_real_argb_blue);
p0.y = p0.y + 0.2f;
p1.y = p1.y - 0.2f;
p0.z = p0.z - 0.2f;
p1.z = p1.z + 0.2f;
render_debug_line(TRUE, &p0, &p1, global_real_argb_blue);
}
}
/* Projectile aiming */
if (ai_debug.render_projectile_aiming &&
actor_debug_info->last_projectile_aiming_time!=NONE &&
actor_debug_info->last_projectile_aiming_time+15 >= game_time_get())
{
real_point3d p0;
real_point3d p1;
p1 = actor_debug_info->field_64;
p0 = p1;
p0.x = p1.x - 0.2f;
p1.x = p1.x + 0.2f;
render_debug_line(TRUE, &p0, &p1, global_real_argb_blue);
p0.x = p0.x + 0.2f;
p1.x = p1.x - 0.2f;
p0.y = p0.y - 0.2f;
p1.y = p1.y + 0.2f;
render_debug_line(TRUE, &p0, &p1, global_real_argb_blue);
p0.y = p0.y + 0.2f;
p1.y = p1.y - 0.2f;
p0.z = p0.z - 0.2f;
p1.z = p1.z + 0.2f;
render_debug_line(TRUE, &p0, &p1, global_real_argb_blue);
render_debug_vector(
TRUE,
&actor_debug_info->field_64,
&actor_debug_info->field_70,
2.f,
actor_debug_info->field_60 ? global_real_argb_blue : global_real_argb_red);
if (!actor_debug_info->field_60)
{
render_debug_sphere(TRUE, &actor_debug_info->field_7C, 0.2f, global_real_argb_red);
}
if (actor_debug_info->field_88)
{
render_debug_vector(
TRUE,
&actor->input.position.head_position,
&actor_debug_info->field_98,
1.f,
global_real_argb_white);
render_debug_vector(
TRUE,
&actor_debug_info->field_64,
&actor_debug_info->field_8C,
2.f,
global_real_argb_purple);
}
}
/* Burst Geometry */
if (ai_debug.render_burst_geometry && actor->control.fire_state==_actor_fire_state_bursting)
{
real_point3d p0;
real_point3d p1;
render_debug_line(TRUE, &actor->control.burst_initial_position, &actor_debug_info->burst_last_known_position, global_real_argb_green);
if (magnitude_squared3d(&actor_debug_info->burst_lead_vector)>_real_epsilon)
{
render_debug_vector(
TRUE,
&actor_debug_info->burst_tracked_position,
&actor_debug_info->burst_lead_vector,
1.f,
global_real_argb_purple);
}
p1.x = actor->control.desired_aiming_vector.i;
p1.y = actor->control.desired_aiming_vector.j;
p1.z = actor->control.desired_aiming_vector.k;
p0 = p1;
p0.x = p1.x - 0.2f;
p1.x = p1.x + 0.2f;
render_debug_line(TRUE, &p0, &p1, global_real_argb_blue);
p0.x = p0.x + 0.2f;
p1.x = p1.x - 0.2f;
p0.y = p0.y - 0.2f;
p1.y = p1.y + 0.2f;
render_debug_line(TRUE, &p0, &p1, global_real_argb_blue);
p0.y = p0.y + 0.2f;
p1.y = p1.y - 0.2f;
p0.z = p0.z - 0.2f;
p1.z = p1.z + 0.2f;
render_debug_line(TRUE, &p0, &p1, global_real_argb_blue);
render_debug_sphere(TRUE, &actor->control.burst_target, 0.1f, global_real_argb_red);
render_debug_vector(TRUE, &actor->control.burst_target, &actor->control.burst_adjustment, 5.f, global_real_argb_red);
}
/* Vision cones */
if (render_exclusive && ai_debug.render_vision_cones)
{
real max_distance;
real perception_factor;
real angle_itr;
real_point3d last_points[2][2][2];
real const angle_step = 0.08726646f;
real_argb_color const *const *colors[2] =
{
&global_real_argb_red,
&global_real_argb_blue
};
if (actor_debug_info->vision_last_time!=NONE &&
actor_debug_info->vision_last_time+15 >= game_time_get())
{
max_distance = actor_debug_info->vision_last_maximum_distance;
perception_factor = actor_debug_info->vision_last_perception_factor;
}
else
{
max_distance = actor_definition->perception.maximum_vision_distance;
perception_factor = 1.f;
}
render_debug_vector(
TRUE,
&actor->input.position.head_position,
&actor->input.looking_vector,
max_distance*perception_factor,
global_real_argb_yellow);
for (angle_itr = 0.f; angle_itr<actor_definition->perception.peripheral_vision_angle+angle_step; angle_itr+=angle_step)
{
real_vector3d direction_vector[2][2];
real_point3d current_points[2][2][2];
real full_distance_reference[2];
real partial_distance_reference;
short side_index;
short ring_index;
short height_index;
real cosine_vertical_angle[2];
real sine_vertical_angle[2];
real horizontal_angle = angle_itr>actor_definition->perception.peripheral_vision_angle ? actor_definition->perception.peripheral_vision_angle : angle_itr;
real cosine_horizontal_angle = cosine(horizontal_angle);
real sine_horizontal_angle = sine(horizontal_angle);
cosine_vertical_angle[0] = cosine(DEGREES_TO_RADIANS(30));
sine_vertical_angle[0] = sine(DEGREES_TO_RADIANS(30));
cosine_vertical_angle[1] = cosine(DEGREES_TO_RADIANS(45));
sine_vertical_angle[1] = -sine(DEGREES_TO_RADIANS(45));
for (side_index = 0; side_index<2; ++side_index)
{
for (ring_index = 0; ring_index<2; ++ring_index)
{
real_vector3d headspace_vector;
headspace_vector.i = cosine_horizontal_angle * sine_vertical_angle[ring_index];
headspace_vector.j = sine_horizontal_angle * sine_vertical_angle[ring_index] * ((real)(side_index==0 ? 1 : -1));
headspace_vector.k = cosine_vertical_angle[ring_index];
direction_vector[side_index][ring_index].i =
actor->input.looking_vector.i*headspace_vector.i +
actor->input.looking_left_vector.i*headspace_vector.j +
actor->input.looking_up_vector.i*headspace_vector.k;
direction_vector[side_index][ring_index].j =
actor->input.looking_vector.j*headspace_vector.i +
actor->input.looking_left_vector.j*headspace_vector.j +
actor->input.looking_up_vector.j*headspace_vector.k;
direction_vector[side_index][ring_index].k =
actor->input.looking_vector.k*headspace_vector.i +
actor->input.looking_left_vector.k*headspace_vector.j +
actor->input.looking_up_vector.k*headspace_vector.k;
}
}
actor_get_vision_distances(actor_index, max_distance, perception_factor, horizontal_angle, full_distance_reference, &partial_distance_reference);
for (side_index = 0; side_index < 2; ++side_index)
{
for (ring_index = 0; ring_index < 2; ++ring_index)
{
for (height_index = 0; height_index < 2; ++height_index)
{
point_from_line3d(
&actor->input.position.head_position,
&direction_vector[ring_index][height_index],
full_distance_reference[side_index],
&current_points[side_index][ring_index][height_index]);
if (angle_itr>0.f || ring_index==0)
{
render_debug_line(
TRUE,
&current_points[side_index][ring_index][height_index],
&actor->input.position.head_position,
*colors[side_index]);
}
if (angle_itr>0.f)
{
render_debug_line(
TRUE,
&last_points[side_index][ring_index][height_index],
&current_points[side_index][ring_index][height_index],
*colors[side_index]);
}
}
if (angle_itr>0.f || ring_index==0)
{
render_debug_line(TRUE, &current_points[side_index][ring_index][0], &current_points[side_index][ring_index][1], *colors[side_index]);
}
}
}
memcpy(last_points, current_points, sizeof(last_points));
}
}
/* Detailed state */
if (render_exclusive &&ai_debug.render_detailed_state)
{
struct prop_datum *prop;
struct prop_iterator iterator;
char buffer[1024];
short tabs[7] =
{
100,
175,
250,
325,
400,
475,
550
};
sprintf(buffer, "|n|n|n|n");
if (actor->meta.unit_index!=NONE)
{
sprintf(
&buffer[strlen(buffer)],
"body|t%3.2f|t[0.0,%3.2f]|nshield|t%3.2f|t[0.0,%3.2f]|n|n",
object_get_actual_body_vitality(actor->meta.unit_index, FALSE),
object_get_maximum_body_vitality(actor->meta.unit_index, FALSE),
object_get_actual_shield_vitality(actor->meta.unit_index, FALSE),
object_get_maximum_shield_vitality(actor->meta.unit_index, FALSE));
}
sprintf(&buffer[strlen(buffer)], "|ntype|tstate|tvis|taud|tlos|ttarget|tlook|n");
prop_iterator_new(&iterator, actor_index);
while (prop = prop_iterator_next(&iterator))
{
char const *states[NUMBER_OF_PROP_STATES] =
{
"-----",
"->ack",
"ack->",
" ack ",
"u/orph",
"i/orph"
};
char const *los[NUMBER_OF_AI_LINE_OF_SIGHTS] =
{
"clear",
"occl",
"f/cvr",
"to/cvr",
"obstr"
};
char const *lighting_state_strings[NUMBER_OF_PROP_LIGHTING_STATES] =
{
" (dark)",
" (dim)",
""
};
char const *perceptions[NUMBER_OF_ACTOR_PERCEPTION_TYPES] =
{
"",
"part",
"full",
NULL
};
sprintf(
&buffer[strlen(buffer)],
"%s|t%s|t%s%s|t%s|t%s|t%3.2f|t%3.2f|n",
tag_get_name(object_get(prop->unit_index)->definition_index),
states[prop->state],
perceptions[prop->visibility],
lighting_state_strings[prop->lighting],
perceptions[prop->audibility],
los[prop->line_of_sight],
prop->target_weight,
prop->look_interest);
}
draw_string_set_tab_stops(tabs, NUMBEROF(tabs));
draw_string_set_color(global_real_argb_white);
rasterizer_draw_string(NULL, NULL, NULL, 0, buffer);
draw_string_set_tab_stops(NULL, 0);
}
/* Paths */
if (ai_debug.render_paths && (!ai_debug.render_paths_selected_only || render_exclusive))
{
if (ai_debug.render_paths_current && actor_path_has_path(actor_index))
{
short step_index;
short first_index;
real_argb_color const *color;
if (actor->control.path.at_destination)
{
color = global_real_argb_yellow;
}
else
{
color = actor->control.path.path.steps_finish_path ? global_real_argb_pink : global_real_argb_purple;
}
first_index = actor->control.path.path.step_index;
render_debug_line_offset(
TRUE,
&actor->input.position.body_position,
&actor->control.path.path.steps[actor->control.path.path.step_index].point,
color,
0.1f);
for (
step_index = first_index;
step_index<actor->control.path.path.step_count;
++step_index)
{
real_point3d position;
if (step_index>first_index)
{
render_debug_line_offset(
TRUE,
&actor->control.path.path.steps[step_index-1].point,
&actor->control.path.path.steps[step_index].point,
color,
0.1f);
}
point_from_line3d(&actor->control.path.path.steps[step_index].point, global_up3d, 0.1f, &position);
render_debug_tick(TRUE, &position, global_up3d, 0.02, color);
}
{
real_point3d endpoint;
point_from_line3d(&actor->control.path.path.endpoint.point, global_up3d, 0.1f, &endpoint);
render_debug_sphere(TRUE, &endpoint, 0.15f, color);
}
if (actor_path_has_path(actor_index))
{
sprintf(
temporary,
"following path (%d/%d%s)",
actor->control.path.path.step_index,
actor->control.path.path.step_count,
actor_path_at_destination(actor_index) ? " (at destination)" : "");
}
else
{
strcpy(temporary, "no current path");
}
if (actor->emotions.ignorant_of_broken_surfaces)
{
strcat(temporary, " [ignorant]");
}
render_debug_string_at_point(TRUE, ai_debug_drawstack(), temporary, global_real_argb_orange);
if (actor_debug_info->last_path_refresh==NONE || actor_debug_info->last_path_refresh+150 < game_time_get())
{
render_debug_string_at_point(TRUE, ai_debug_drawstack(), "not refreshing path", global_real_argb_blue);
}
else
{
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(temporary, "path refreshed (%d)", game_time_get()-actor_debug_info->last_path_refresh),
global_real_argb_blue);
if (path && path->valid)
{
ai_debug_render_path_storage(path);
}
else
{
render_debug_string_at_point(TRUE, ai_debug_drawstack(), "path debugging not available", global_real_argb_red);
}
}
}
}
/* Postcombat */
if (ai_debug.render_postcombat && actor->external_orders.postcombat_type>0)
{
render_debug_string_at_point(TRUE, ai_debug_drawstack(), postcombat_type_strings[actor->external_orders.postcombat_type], global_real_argb_green);
if (actor->external_orders.postcombat_prop_index!=NONE)
{
struct prop_datum *prop = prop_get(actor->external_orders.postcombat_prop_index);
render_debug_line(TRUE, &actor->input.position.head_position, &prop->head_position, global_real_argb_green);
}
}
}
return;
}
static void code_0003a910(
struct path_state *state,
boolean render_surfaces,
boolean render_all_nodes,
boolean render_polygons,
boolean render_costs,
boolean render_closest)
{
struct path_node *node;
struct path_node *previous_node;
short node_index;
real_argb_color const *polygon_color = render_polygons ? global_real_argb_purple : NULL;
real_argb_color const *distance_color = render_costs ? global_real_argb_white : NULL;
real_argb_color const *weight_color = render_costs ? global_real_argb_yellow : NULL;
real_argb_color const *cost_color = render_costs ? global_real_argb_red : NULL;
real_argb_color const *closest_color = render_closest ? global_real_argb_yellow : NULL;
global_ai_debug_path_render_id++;
if (state->destination_valid)
{
previous_node = NULL;
node_index = path_node_from_hash_table(state, state->destination.surface_index);
while (node_index!=NONE)
{
node = path_get_node(state, node_index);
code_00039990(node,
previous_node==NULL ? &state->destination.point : &previous_node->entry_point,
state->structure, render_surfaces, state, previous_node,
global_real_argb_red, polygon_color, distance_color, weight_color,
cost_color, closest_color);
node->last_render_id = global_ai_debug_path_render_id;
node_index = node->parent_node_index;
previous_node = node;
}
}
if (render_all_nodes)
{
struct collision_bsp const *collision_bsp = TAG_BLOCK_GET_ELEMENT(
&state->structure->collision_bsp, 0, struct collision_bsp);
short index;
for (index = state->node_count-1; index>=0; index--)
{
previous_node = NULL;
node_index = index;
while (node_index!=NONE)
{
node = path_get_node(state, node_index);
if (node->last_render_id==global_ai_debug_path_render_id)
{
if (previous_node)
{
render_debug_line_offset(TRUE, &previous_node->entry_point,
&node->entry_point, global_real_argb_blue, 0.1f);
}
break;
}
{
real_point3d centre = *global_origin3d;
real_point3d const *point;
if (!previous_node)
{
if (render_surfaces)
{
struct collision_surface const *surface = TAG_BLOCK_GET_ELEMENT(
&collision_bsp->surfaces, node->surface_index,
struct collision_surface);
long edge_index = surface->first_edge_index;
long vertex_count = 0;
do
{
struct collision_edge const *edge = TAG_BLOCK_GET_ELEMENT(
&collision_bsp->edges, edge_index, struct collision_edge);
const boolean next_index_belongs_to_surface =
edge->surface_indices[1]==node->surface_index;
struct collision_vertex const *vertex = TAG_BLOCK_GET_ELEMENT(
&collision_bsp->vertices,
edge->vertex_indices[next_index_belongs_to_surface],
struct collision_vertex);
centre.x += vertex->point.x;
centre.y += vertex->point.y;
centre.z += vertex->point.z;
vertex_count++;
edge_index = edge->edge_indices[next_index_belongs_to_surface];
}
while (edge_index!=surface->first_edge_index);
centre.x /= vertex_count;
centre.y /= vertex_count;
centre.z /= vertex_count;
point = &centre;
}
else
{
centre = node->closest_point_to_attractor;
point = &centre;
}
}
else
{
point = &node->entry_point;
}
code_00039990(node, point,
state->structure, render_surfaces, state, previous_node,
global_real_argb_blue, polygon_color, distance_color, weight_color,
cost_color, closest_color);
}
node->last_render_id = global_ai_debug_path_render_id;
previous_node = node;
node_index = node->parent_node_index;
}
}
}
return;
}
static void ai_debug_render_path_storage(
struct path_debug_storage *path)
{
if (path && path->valid && path->last_render_id != ai_debug.last_render_id)
{
char const *path_traverse_result_strings[NUMBER_OF_PATH_TRAVERSE_RESULTS] =
{
"none",
"invalid start",
"not close enough",
"exhausted search",
"overflowed nodes",
"success"
};
char const *path_build_result_strings[NUMBER_OF_PATH_BUILD_RESULTS] =
{
"none",
"no destination",
"cached node missing",
"not close enough",
"obstacles blocked",
"success"
};
boolean const matching_bsp = path->structure_bsp_index==global_structure_bsp_index_get();
match_assert("c:\\halo\\SOURCE\\ai\\ai_debug.c", 3944, (path->path_traverse_result >= 0) && (path->path_traverse_result < NUMBER_OF_PATH_TRAVERSE_RESULTS));
match_assert("c:\\halo\\SOURCE\\ai\\ai_debug.c", 3945, (path->path_build_result >= 0) && (path->path_build_result < NUMBER_OF_PATH_BUILD_RESULTS));
render_debug_string_at_point(
TRUE,
ai_debug_drawstack(),
csprintf(
temporary,
"%s / %s (%d)",
path_traverse_result_strings[path->path_traverse_result],
path_build_result_strings[path->path_build_result],
game_time_get()-path->path_time),
path->path_traverse_result!=_path_traverse_result_success || path->path_build_result!=_path_build_result_success ?
global_real_argb_red :
global_real_argb_green
);
if (ai_debug.render_paths_destination)
{
if (path->path_state.destination_valid != 0)
{
render_debug_line_offset(
TRUE,
&path->path_state.input.start_point,
&path->path_state.destination.point,
global_real_argb_pink,
0.1f);
render_debug_point(TRUE, &path->path_state.destination.point, 0.3f, global_real_argb_green);
if (path->path_state.destination.target_radius > 0.f)
{
render_debug_sphere(
TRUE,
&path->path_state.destination.point,
path->path_state.destination.target_radius,
global_real_argb_green);
}
if (path->path_state.destination.surface_index!=NONE && matching_bsp)
{
ai_debug_render_surface(
path->path_state.structure,
path->path_state.destination.surface_index,
0.05f,
global_real_argb_green);
}
}
else
{
render_debug_string_at_point(TRUE, ai_debug_drawstack(), "undirected", global_real_argb_green);
}
}
if (ai_debug.render_paths_raw)
{
code_00037890(&path->path_state.input.start_point, global_real_argb_red,
path->raw_step_count, path->raw_steps);
}
if (ai_debug.render_paths_smoothed)
{
code_00037890(&path->path_state.input.start_point, global_real_argb_green,
path->smoothed_step_count, path->smoothed_steps);
}
if (ai_debug.render_paths_avoided)
{
code_00037890(&path->path_state.input.start_point, global_real_argb_blue,
path->avoided_step_count, path->avoided_steps);
}
if (ai_debug.render_paths_avoidance_segment>=0 &&
ai_debug.render_paths_avoidance_segment<path->avoidance_path_count)
{
if (ai_debug.render_paths_avoidance_obstacles)
{
render_debug_obstacles(
&path->avoidance_obstacles[ai_debug.render_paths_avoidance_segment],
path->avoidance_paths[ai_debug.render_paths_avoidance_segment].field_00);
}
if (ai_debug.render_paths_avoidance_search && matching_bsp)
{
render_debug_path(
&path->avoidance_paths[ai_debug.render_paths_avoidance_segment]);
}
}
if (ai_debug.render_paths_nodes)
{
code_0003a910(&path->path_state, matching_bsp,
ai_debug.render_paths_nodes_all, ai_debug.render_paths_nodes_polygons,
ai_debug.render_paths_nodes_costs, ai_debug.render_paths_nodes_closest);
}
path->last_render_id = ai_debug.last_render_id;
}
return;
}
void ai_debug_sound_point_set(
void)
{
return;
}
void ai_debug_lineoffire_new(
real_point3d const *start,
real_vector3d const *vector)
{
ai_debug.lineoffire_valid = TRUE;
ai_debug.lineoffire_success = FALSE;
ai_debug.lineoffire_start = *start;
ai_debug.lineoffire_vector = *vector;
ai_debug.lineoffire_pill_count = 0;
return;
}
void ai_debug_lineoffire_success(
boolean success)
{
ai_debug.lineoffire_success = success;
return;
}
void ai_debug_lineofsight_reset(
void)
{
ai_debug.lineofsight_point_count = 0;
ai_debug.lineofsight_pair_count = 0;
return;
}
void ai_debug_idle_look_clear(
long unit_index)
{
ai_debug.idle_look_valid = unit_index!=NONE;
ai_debug.idle_look_unit_index = unit_index;
ai_debug.idle_look_prop_count = 0;
return;
}
void ai_debug_lineoffire_addpill(
real_point3d const *start,
real_vector3d const *vector,
real radius,
boolean hit)
{
match_assert("c:\\halo\\SOURCE\\ai\\ai_debug.c", 4036, ai_debug.lineoffire_valid);
if (ai_debug.lineoffire_pill_count<MAXIMUM_AI_DEBUG_LINEOFFIRE_PILLS)
{
ai_debug.lineoffire_pill_hit[ai_debug.lineoffire_pill_count] = hit;
ai_debug.lineoffire_pill_start[ai_debug.lineoffire_pill_count] = *start;
ai_debug.lineoffire_pill_vector[ai_debug.lineoffire_pill_count] = *vector;
ai_debug.lineoffire_pill_radius[ai_debug.lineoffire_pill_count] = radius;
ai_debug.lineoffire_pill_count++;
}
return;
}
void ai_debug_idle_look_addprop(
long prop_index,
real weight)
{
match_assert("c:\\halo\\SOURCE\\ai\\ai_debug.c", 5062, ai_debug.idle_look_valid);
if (ai_debug.idle_look_prop_count<MAXIMUM_AI_DEBUG_IDLE_LOOK_PROPS)
{
ai_debug.idle_look_prop_index[ai_debug.idle_look_prop_count] = prop_index;
ai_debug.idle_look_prop_weight[ai_debug.idle_look_prop_count] = weight;
ai_debug.idle_look_prop_count++;
}
return;
}
static void code_00038ad0(
long name_count,
char const **names,
unsigned long *vector,
unsigned long vector_size,
short (*lookup)(char const *))
{
short set_count = 0;
short clear_count = 0;
unsigned long new_vector[BIT_VECTOR_SIZE_IN_LONGS(2048)];
long name_index;
long bit_index;
match_assert("c:\\halo\\SOURCE\\ai\\ai_debug.c", 4968, lookup);
match_assert("c:\\halo\\SOURCE\\ai\\ai_debug.c", 4969, vector_size <= 2048);
csmemset(new_vector, 0, BIT_VECTOR_SIZE_IN_BYTES(vector_size));
for (name_index = 0; name_index<name_count; name_index++)
{
short comm_type = lookup(names[name_index]);
if (comm_type!=NONE)
{
match_assert("c:\\halo\\SOURCE\\ai\\ai_debug.c", 4978, (comm_type >= 0) && (comm_type < vector_size));
BIT_VECTOR_SET_FLAG(new_vector, comm_type, TRUE);
}
else if (!csstrcmp(names[name_index], "all"))
{
csmemset(new_vector, NONE, BIT_VECTOR_SIZE_IN_BYTES(vector_size));
}
}
for (bit_index = 0; bit_index<vector_size; bit_index++)
{
if (BIT_VECTOR_TEST_FLAG(new_vector, bit_index))
{
if (BIT_VECTOR_TEST_FLAG(vector, bit_index))
{
set_count++;
}
else
{
clear_count++;
}
}
}
if (clear_count)
{
bit_vector_or(vector_size, new_vector, vector, vector);
console_printf(NULL, "set %d flags", clear_count);
}
else if (set_count)
{
bit_vector_not(vector_size, new_vector, new_vector);
bit_vector_and(vector_size, new_vector, vector, vector);
console_printf(NULL, "cleared %d flags", set_count);
}
return;
}
void ai_debug_communication_suppress(
long name_count,
char const **names)
{
code_00038ad0(name_count, names, ai_debug.communication_suppress_vector,
NUMBER_OF_AI_DEBUG_COMMUNICATION_TYPES, ai_communication_get_type_by_name);
return;
}
void ai_debug_communication_ignore(
long name_count,
char const **names)
{
code_00038ad0(name_count, names, ai_debug.communication_ignore_vector,
NUMBER_OF_AI_DEBUG_COMMUNICATION_TYPES, ai_communication_get_type_by_name);
return;
}
void ai_debug_communication_focus(
long name_count,
char const **names)
{
code_00038ad0(name_count, names, ai_debug.communication_focus_vector,
NUMBER_OF_AI_DEBUG_VOCALIZATION_TYPES, dialogue_get_vocalization_type_by_name);
return;
}
static short code_00037dd0(
real_point3d const *point,
short key)
{
long index;
for (index = 0; index<ai_debug.lineofsight_point_count; index++)
{
if (ai_debug.lineofsight_point_key[index]==key &&
distance_squared3d(point, &ai_debug.lineofsight_point[index])<0.001f*0.001f)
{
break;
}
}
if (index>=ai_debug.lineofsight_point_count)
{
if (ai_debug.lineofsight_point_count<MAXIMUM_AI_DEBUG_LINEOFSIGHT_POINTS)
{
index = ai_debug.lineofsight_point_count++;
ai_debug.lineofsight_point[index] = *point;
ai_debug.lineofsight_point_reference_count[index] = 0;
ai_debug.lineofsight_point_key[index] = key;
}
else
{
index = NONE;
if (!ai_debug.lineofsight_overflowed)
{
error(2, "ai_debug_lineofsight: overflowed point buffer (%d) with %d rays and counting",
MAXIMUM_AI_DEBUG_LINEOFSIGHT_POINTS,
ai_debug.lineofsight_pair_count);
ai_debug.lineofsight_overflowed = TRUE;
}
}
}
if (index!=NONE)
{
match_assert("c:\\halo\\SOURCE\\ai\\ai_debug.c", 4223, index <= SHORT_MAX);
ai_debug.lineofsight_point_reference_count[index]++;
}
return (short)index;
}
static long code_00037ee0(
short start_index,
short end_index)
{
long index = NONE;
if (start_index!=NONE && end_index!=NONE)
{
for (index = 0; index<ai_debug.lineofsight_pair_count; index++)
{
if (ai_debug.lineofsight_pair[index].start_index==start_index &&
ai_debug.lineofsight_pair[index].end_index==end_index)
{
break;
}
}
if (index>=ai_debug.lineofsight_pair_count)
{
if (ai_debug.lineofsight_pair_count<MAXIMUM_AI_DEBUG_LINEOFSIGHT_PAIRS)
{
index = ai_debug.lineofsight_pair_count++;
ai_debug.lineofsight_pair[index].start_index = start_index;
ai_debug.lineofsight_pair[index].end_index = end_index;
ai_debug.lineofsight_pair[index].reference_count = 0;
}
else
{
index = NONE;
if (!ai_debug.lineofsight_overflowed)
{
error(2, "ai_debug_lineofsight: overflowed ray buffer (%d) with %d points and counting",
MAXIMUM_AI_DEBUG_LINEOFSIGHT_PAIRS,
ai_debug.lineofsight_point_count);
ai_debug.lineofsight_overflowed = TRUE;
}
}
}
if (index!=NONE)
{
ai_debug.lineofsight_pair[index].reference_count++;
}
}
return index;
}
void ai_debug_lineofsight(
real_point3d const *start,
short start_key,
real_point3d const *end,
short end_key)
{
code_00037ee0(code_00037dd0(start, start_key), code_00037dd0(end, end_key));
return;
}
void ai_debug_vocalize(
char const *priority_name,
char const *vocalization_name)
{
if (ai_debug.selected_actor_index!=NONE)
{
struct actor_datum *actor = actor_get(ai_debug.selected_actor_index);
ai_debug.render_speech = TRUE;
if (actor->meta.unit_index!=NONE)
{
short priority = unit_get_speech_priority_by_name(priority_name);
short vocalization_type = dialogue_get_vocalization_type_by_name(vocalization_name);
if (priority>0 && vocalization_type!=NONE)
{
long sound_definition_index = NONE;
short speech_type = unit_test_speech(actor->meta.unit_index, priority, 1, 1, 0,
&vocalization_type, &sound_definition_index);
if (speech_type)
{
struct unit_speech_item item;
csmemset(&item, 0, sizeof(item));
item.priority = priority;
item.vocalization_type = vocalization_type;
item.sound_definition_index = sound_definition_index;
ai_communication_packet_new(&item.ai);
unit_speak(actor->meta.unit_index, speech_type, &item);
}
}
}
}
return;
}
void ai_debug_speak_list(
char const *list_name)
{
if (ai_debug.selected_actor_index!=NONE)
{
struct ai_debug_speech_list list[] =
{
{ "all", 0, TRUE },
{ "idle", 0, FALSE },
{ "involuntary", 6, FALSE },
{ "hurting people", 21, FALSE },
{ "being hurt", 29, FALSE },
{ "killing people", 49, FALSE },
{ "player kill comments", 80, FALSE },
{ "friends dying", 96, FALSE },
{ "shouting", 108, FALSE },
{ "group communication", 123, FALSE },
{ "actions", 148, FALSE },
{ "exclamations", 177, FALSE },
{ "post-combat actions", 188, FALSE },
{ "post-combat chatter", 197, FALSE },
{ NULL, NONE, FALSE }
};
struct actor_datum *actor = actor_get(ai_debug.selected_actor_index);
struct ai_debug_speech_list *entry;
for (entry = list; entry->name; entry++)
{
if (!_stricmp(entry->name, list_name))
{
break;
}
}
if (!entry->name)
{
console_printf(FALSE, "ai_speak_list: couldn't find the list '%s'... here are the known lists:", list_name);
for (entry = list; entry->name; entry++)
{
console_printf(FALSE, " %s", entry->name);
}
}
else if (actor->meta.unit_index!=NONE && entry->vocalization_type!=NONE)
{
ai_debug.render_speech = TRUE;
ai_debug.speak_valid = TRUE;
ai_debug.field_85B28 = 0;
ai_debug.field_85B21 = TRUE;
ai_debug.field_85B22 = entry->all;
ai_debug.speak_unit_index = actor->meta.unit_index;
ai_debug.speak_vocalization_type = entry->vocalization_type;
}
}
return;
}
void ai_debug_speak(
char const *vocalization_name)
{
if (ai_debug.selected_actor_index!=NONE)
{
struct actor_datum *actor = actor_get(ai_debug.selected_actor_index);
short vocalization_type = dialogue_get_vocalization_type_by_name(vocalization_name);
if (actor->meta.unit_index!=NONE && vocalization_type!=NONE)
{
ai_debug.render_speech = TRUE;
ai_debug.speak_valid = TRUE;
ai_debug.field_85B28 = 0;
ai_debug.field_85B21 = FALSE;
ai_debug.speak_unit_index = actor->meta.unit_index;
ai_debug.speak_vocalization_type = vocalization_type;
}
}
return;
}
char *ai_debug_describe_actor(
long actor_index,
long unit_index,
boolean include_squad,
char *buffer,
long bufsize)
{
char squad_string[256];
char unit_string[256];
char const *model_name;
csstrcpy(squad_string, "");
if (include_squad && actor_index!=NONE)
{
struct actor_datum *actor = actor_get(actor_index);
unit_index = actor->meta.unit_index;
if (actor->meta.encounter_index==NONE)
{
csstrcpy(squad_string, "encounterless ");
}
else
{
struct encounter_definition *encounter = TAG_BLOCK_GET_ELEMENT(
&global_scenario_get()->ai_encounters, actor->meta.encounter_index&0xffff,
struct encounter_definition);
struct squad_definition *squad = TAG_BLOCK_GET_ELEMENT(
&encounter->squads, actor->meta.squad_index, struct squad_definition);
struct platoon_definition *platoon = NULL;
if (actor->meta.platoon_index!=NONE)
{
platoon = TAG_BLOCK_GET_ELEMENT(&encounter->platoons, actor->meta.platoon_index,
struct platoon_definition);
}
if (!platoon)
{
sprintf(squad_string, "%s/%s ", encounter->name, squad->name);
}
else
{
sprintf(squad_string, "%s/(%s) %s ", encounter->name, platoon->name, squad->name);
}
}
}
model_name = "";
csstrcpy(unit_string, "");
if (unit_index!=NONE)
{
struct unit_datum *unit = unit_get(unit_index);
model_name = tag_name_strip_path(
unit_definition_get(unit->definition_index)->object.model.name);
if (unit->object.name_index!=NONE)
{
sprintf(unit_string, " (%s)", TAG_BLOCK_GET_ELEMENT(
&global_scenario_get()->object_names, unit->object.name_index,
struct scenario_object_name)->name);
}
}
_snprintf(buffer, bufsize, "%s%s%s", squad_string, model_name, unit_string);
return buffer;
}
void ai_debug_select_encounter(
long encounter_index)
{
if (ai_debug.selected_squad_index!=encounter_index)
{
ai_debug.selected_squad_index = encounter_index;
ai_debug.field_7D380 = FALSE;
csmemset(&ai_debug.field_7D384, 0, sizeof(ai_debug.field_7D384));
csmemset(ai_debug.actor_record, 0, sizeof(ai_debug.actor_record));
ai_debug_select_actor(encounter_index, NONE);
}
return;
}
void ai_debug_select_actor(
long encounter_index,
long actor_index)
{
if (ai_debug.selected_squad_index!=encounter_index || ai_debug.selected_actor_index!=actor_index)
{
struct ai_debug_actor_record *record;
long index;
ai_debug_select_encounter(encounter_index);
ai_debug.selected_actor_index = actor_index;
ai_debug.field_7D380 = FALSE;
for (record = ai_debug.actor_record, index = NUMBER_OF_AI_DEBUG_ACTOR_RECORDS; index>0; index--, record++)
{
record->field_01 = FALSE;
}
ai_debug_idle_look_clear(actor_index);
}
return;
}
void ai_debug_initialize_for_new_map(
void)
{
long encounter_index = encounter_get_by_name(ai_debug.selected_squad_name);
ai_debug_clear_storage();
ai_debug_select_actor(encounter_index, NONE);
return;
}
void ai_debug_update(
void)
{
if (ai_debug.render_lineofsight)
{
ai_debug.lineofsight_point_count = 0;
ai_debug.lineofsight_pair_count = 0;
}
if (ai_debug.path)
{
if (!ai_debug.path_start_freeze)
{
long unit_index = player_control_get_unit_index(0);
real_point3d point;
if (unit_index!=NONE && biped_try_and_get(unit_index))
{
long surface_index = biped_find_pathfinding_surface_index(unit_index, &point);
if (surface_index!=NONE)
{
ai_debug.path_start_surface_index = surface_index;
ai_debug.path_start_point = point;
ai_debug.path_start_unit_index = unit_index;
ai_debug.path_start_valid = TRUE;
}
}
}
if (!ai_debug.path_end_freeze)
{
struct observer_result const *camera = observer_get_camera(0);
if (camera)
{
struct collision_result collision;
real_vector3d down_vector;
ai_profile.map_data.field_B34++;
down_vector.i = global_down3d->i*1000.f;
down_vector.j = global_down3d->j*1000.f;
down_vector.k = global_down3d->k*1000.f;
if (collision_test_vector(0x21, &camera->position, &down_vector, NONE, &collision))
{
ai_debug.path_end_valid = TRUE;
ai_debug.path_end_point = collision.point;
ai_debug.path_end_surface_index = collision.surface_index;
ai_debug.field_4C814 = 0.f;
}
}
}
if (ai_debug.path_start_valid)
{
struct path_input input;
path_input_new(&input, 0.2f, FALSE, ai_debug.path_start_unit_index);
path_input_set_start(&input, &ai_debug.path_start_point, ai_debug.path_start_surface_index);
if (ai_debug.path_maximum_radius>0.f)
{
path_input_set_search_bounds(&input, ai_debug.path_maximum_radius);
}
if (ai_debug.path_attractor)
{
long unit_index = player_control_get_unit_index(0);
if (unit_index!=NONE)
{
real_point3d point;
real attractor_weight;
real attractor_radius;
unit_get(unit_index);
object_get_origin(unit_index, &point);
attractor_weight = ai_debug.path_attractor_weight==0.f ?
20.f : ai_debug.path_attractor_weight;
attractor_radius = ai_debug.path_attractor_radius==0.f ?
8.f : ai_debug.path_attractor_radius;
path_input_set_attractor(&input, &point, attractor_radius, NONE, attractor_weight);
}
}
path_state_new(&input, &ai_debug.path_state, &ai_debug.path_storage);
if (ai_debug.path_end_valid && !ai_debug.path_flood)
{
path_state_destination(&ai_debug.path_state, &ai_debug.path_end_point,
ai_debug.path_end_surface_index, ai_debug.path_accept_radius);
}
path_state_find(&ai_debug.path_state);
if (ai_debug.path_end_valid && ai_debug.path_flood)
{
path_state_destination(&ai_debug.path_state, &ai_debug.path_end_point,
ai_debug.path_end_surface_index, ai_debug.path_accept_radius);
}
path_state_build_path(&ai_debug.path_state, &ai_debug.field_608A8);
ai_debug.field_4C818 = TRUE;
ai_debug.path_storage.valid = TRUE;
ai_debug.path_storage.path_time = game_time_get();
ai_debug.path_storage.actor_index = NONE;
}
}
if (ai_debug.fix_defending_guard_firing_positions && game_in_editor())
{
struct scenario *scenario = global_scenario_get();
long squad_count = 0;
short encounter_index;
short squad_index;
for (encounter_index = 0; encounter_index<scenario->ai_encounters.count; encounter_index++)
{
struct encounter_definition *encounter = TAG_BLOCK_GET_ELEMENT(
&scenario->ai_encounters, encounter_index, struct encounter_definition);
for (squad_index = 0; squad_index<encounter->squads.count; squad_index++)
{
struct squad_definition *squad = TAG_BLOCK_GET_ELEMENT(
&encounter->squads, squad_index, struct squad_definition);
short group_index;
for (group_index = NUMBER_OF_FIRING_POSITION_GROUPS-1;
group_index>_firing_position_group_attacking_guard;
group_index--)
{
squad->firing_position_groups[group_index] =
squad->firing_position_groups[group_index-1];
}
squad->firing_position_groups[_firing_position_group_attacking_guard] =
squad->firing_position_groups[_firing_position_group_attacking];
squad_count++;
}
}
console_printf(FALSE, "updated all %d squads' guard positions. glory!", squad_count);
ai_debug.fix_defending_guard_firing_positions = FALSE;
}
if (ai_debug.fix_actor_variants && game_in_editor())
{
struct scenario *scenario = global_scenario_get();
long location_count = 0;
short encounter_index;
short squad_index;
short location_index;
for (encounter_index = 0; encounter_index<scenario->ai_encounters.count; encounter_index++)
{
struct encounter_definition *encounter = TAG_BLOCK_GET_ELEMENT(
&scenario->ai_encounters, encounter_index, struct encounter_definition);
for (squad_index = 0; squad_index<encounter->squads.count; squad_index++)
{
struct squad_definition *squad = TAG_BLOCK_GET_ELEMENT(
&encounter->squads, squad_index, struct squad_definition);
for (location_index = 0; location_index<squad->starting_locations.count; location_index++)
{
struct actor_starting_location *location = TAG_BLOCK_GET_ELEMENT(
&squad->starting_locations, location_index, struct actor_starting_location);
location->actor_variant_index = NONE;
location_count++;
}
}
}
console_printf(FALSE, "reset the actor variant in all %d starting locations. glory!", location_count);
ai_debug.fix_actor_variants = FALSE;
}
code_000386a0();
code_00039060();
return;
}
void ai_debug_change_selected_actor(
boolean forward)
{
struct encounter_datum *encounter = encounter_try_and_get(ai_debug.selected_squad_index);
if (!encounter)
{
console_printf(FALSE, "no encounter selected (use F2/F3)");
ai_debug_select_actor(NONE, NONE);
}
else
{
struct encounter_actor_iterator iterator;
struct actor_datum *actor;
short actor_number = 0;
encounter_actor_iterator_new(&iterator, ai_debug.selected_squad_index);
if (ai_debug.selected_actor_index!=NONE)
{
while (encounter_actor_iterator_next(&iterator))
{
if (iterator.actor_index==ai_debug.selected_actor_index)
break;
actor_number++;
}
}
if (forward)
{
actor = encounter_actor_iterator_next(&iterator);
actor_number++;
}
else
{
actor = encounter_actor_iterator_prev(&iterator);
actor_number--;
}
if (actor)
{
ai_debug_describe_actor(iterator.actor_index, NONE, TRUE, temporary, 256);
console_printf(FALSE, "actor %d/%d: %s", actor_number+1, encounter->current_count, temporary);
ai_debug_select_actor(ai_debug.selected_squad_index, iterator.actor_index);
}
else
{
console_printf(FALSE, "no more actors");
ai_debug_select_actor(ai_debug.selected_squad_index, NONE);
}
}
return;
}
void ai_debug_change_selected_encounter(
boolean forward)
{
long encounter_index = forward ?
data_next_index(encounter_data, ai_debug.selected_squad_index) :
data_prev_index(encounter_data, ai_debug.selected_squad_index);
struct encounter_datum *encounter = encounter_try_and_get(encounter_index);
if (!encounter)
{
console_printf(FALSE, "no more encounters");
ai_debug_select_encounter(NONE);
}
else
{
struct encounter_definition *encounter_definition = TAG_BLOCK_GET_ELEMENT(
&global_scenario_get()->ai_encounters, encounter_index&0xffff,
struct encounter_definition);
char bsp_string[256];
if (TEST_FLAG(encounter_definition->flags, _encounter_3d_firing_positions_bit))
{
csstrcpy(bsp_string, "3d-positions");
}
else
{
char index_string[256];
if (encounter_definition->runtime_structure_bsp_reference_index==NONE)
{
csstrcpy(index_string, "NONE");
}
else
{
sprintf(index_string, "%d", encounter_definition->runtime_structure_bsp_reference_index);
}
sprintf(bsp_string, "%s-bsp %s",
TEST_FLAG(encounter_definition->flags, _encounter_manual_structure_bsp_index_bit) ? "manual" : "auto",
index_string);
}
console_printf(FALSE, "encounter %s [%s %s] (%d actors)",
encounter_definition->name,
encounter->active ? "active" : "inactive",
bsp_string,
encounter->current_count);
ai_debug_select_encounter(encounter_index);
}
return;
}
void ai_debug_teleport_to(
long encounter_index)
{
if (encounter_index!=NONE)
{
struct encounter_definition *encounter = TAG_BLOCK_GET_ELEMENT(
&global_scenario_get()->ai_encounters, encounter_index&0xffff,
struct encounter_definition);
if (encounter->player_starting_locations.count>0)
{
struct data_iterator iterator;
struct player_datum *player;
short location_index = 0;
data_iterator_new(&iterator, player_data);
while ((player = (struct player_datum *)data_iterator_next(&iterator))!=NULL)
{
if (player->unit_index!=NONE)
{
struct encounter_player_starting_location *location = TAG_BLOCK_GET_ELEMENT(
&encounter->player_starting_locations,
location_index%encounter->player_starting_locations.count,
struct encounter_player_starting_location);
real_vector3d facing;
facing.i = cosine(location->facing);
facing.j = sine(location->facing);
facing.k = 0.f;
object_set_position(player->unit_index, &location->position, &facing, NULL);
location_index++;
}
}
}
}
return;
}
struct path_debug_storage *ai_debug_get_path_storage(
long actor_index)
{
short storage_index = NONE;
short index;
for (index = 0; index<MAXIMUM_AI_DEBUG_PATH_STORAGE; index++)
{
struct path_debug_storage *path = &actor_path_debug_array[index];
if (path->actor_index==actor_index && !path->failure)
{
storage_index = index;
break;
}
if (storage_index==NONE && !path->valid)
{
storage_index = index;
}
}
if (storage_index==NONE)
{
short oldest_index = NONE;
long oldest_time = LONG_MAX;
for (index = 0; index<MAXIMUM_AI_DEBUG_PATH_STORAGE; index++)
{
struct path_debug_storage *path = &actor_path_debug_array[index];
match_assert("c:\\halo\\SOURCE\\ai\\ai_debug.c", 291, path->valid);
if (path->path_time<oldest_time)
{
oldest_time = path->path_time;
oldest_index = index;
}
}
storage_index = oldest_index;
}
if (storage_index!=NONE)
{
struct path_debug_storage *path = &actor_path_debug_array[storage_index];
csmemset(path, 0, sizeof(struct path_debug_storage));
path->valid = TRUE;
path->actor_index = actor_index;
path->path_time = game_time_get();
return path;
}
return NULL;
}
static void code_00037af0(
void)
{
if (ai_debug.lineoffire_valid)
{
real_point3d end_point;
long index;
point_from_line3d(
&ai_debug.lineoffire_start,
&ai_debug.lineoffire_vector,
1.f,
&end_point);
render_debug_line(
TRUE,
&ai_debug.lineoffire_start,
&end_point,
ai_debug.lineoffire_success ? global_real_argb_green : global_real_argb_red);
for (index = 0; index<ai_debug.lineoffire_pill_count; index++)
{
render_debug_pill(
TRUE,
&ai_debug.lineoffire_pill_start[index],
&ai_debug.lineoffire_pill_vector[index],
ai_debug.lineoffire_pill_radius[index],
ai_debug.lineoffire_pill_hit[index] ? global_real_argb_red : global_real_argb_blue);
}
}
return;
}
static void code_00037bc0(
void)
{
if (ai_debug.ballistic_lineoffire_valid)
{
short index;
render_debug_point(
TRUE,
&ai_debug.ballistic_lineoffire_start,
0.1f,
global_real_argb_yellow);
render_debug_vector(
TRUE,
&ai_debug.ballistic_lineoffire_start,
&ai_debug.ballistic_lineoffire_vector,
1.f,
global_real_argb_yellow);
for (index = 0; index<ai_debug.ballistic_lineoffire_pill_count; index++)
{
render_debug_pill(
TRUE,
&ai_debug.ballistic_lineoffire_pill_start[index],
&ai_debug.ballistic_lineoffire_pill_end[index],
ai_debug.ballistic_lineoffire_pill_radius[index],
global_real_argb_blue);
}
for (index = 0; index<ai_debug.ballistic_lineoffire_point_count-1; index++)
{
render_debug_line(
TRUE,
&ai_debug.ballistic_lineoffire_point[index],
&ai_debug.ballistic_lineoffire_point[index+1],
ai_debug.ballistic_lineoffire_success ? global_real_argb_green :
(index==ai_debug.ballistic_lineoffire_point_count-2 ?
global_real_argb_orange : global_real_argb_red));
}
}
return;
}
static void code_00037fa0(
void)
{
long index;
long pair_index;
long reference_count;
real_argb_color const **colors[13] =
{
&global_real_argb_black,
&global_real_argb_blue,
&global_real_argb_lightblue,
&global_real_argb_cyan,
&global_real_argb_green,
&global_real_argb_purple,
&global_real_argb_salmon,
&global_real_argb_pink,
&global_real_argb_magenta,
&global_real_argb_red,
&global_real_argb_orange,
&global_real_argb_yellow,
&global_real_argb_white
};
for (index = 0; index<ai_debug.lineofsight_point_count; index++)
{
sprintf(temporary, "%d", ai_debug.lineofsight_point_reference_count[index]);
reference_count = ai_debug.lineofsight_point_reference_count[index];
render_debug_string_at_point(
TRUE,
&ai_debug.lineofsight_point[index],
temporary,
*colors[MIN(reference_count, 12)]);
}
for (pair_index = 0; pair_index<ai_debug.lineofsight_pair_count; pair_index++)
{
struct ai_debug_lineofsight_pair *pair;
reference_count = ai_debug.lineofsight_pair[pair_index].reference_count;
pair = &ai_debug.lineofsight_pair[pair_index];
render_debug_line(
TRUE,
&ai_debug.lineofsight_point[pair->start_index],
&ai_debug.lineofsight_point[pair->end_index],
*colors[MIN(reference_count, 12)]);
}
return;
}
static void code_000383d0(
void)
{
if (ai_debug.field_859F4!=ai_debug.selected_actor_index)
{
ai_debug.field_859F4 = ai_debug.selected_actor_index;
ai_debug.field_859F9 = FALSE;
ai_debug.field_859F8 = FALSE;
}
if (ai_debug.field_859F4!=NONE)
{
struct actor_datum *actor = actor_get(ai_debug.field_859F4);
struct observer_result const *camera = observer_get_camera(0);
if (camera)
{
real_point3d *head_position = &actor->input.position.head_position;
real_vector3d vector;
vector.i = camera->position.x - head_position->x;
vector.j = camera->position.y - head_position->y;
vector.k = camera->position.z - head_position->z;
if (normalize3d(&vector)>0.f)
{
boolean aiming_valid;
boolean looking_valid;
actor_looking_test_validity(ai_debug.field_859F4, &vector,
&aiming_valid, &looking_valid);
if (aiming_valid)
{
ai_debug.field_859F9 = TRUE;
ai_debug.field_85A08 = vector;
}
if (looking_valid)
{
ai_debug.field_859F8 = TRUE;
ai_debug.field_859FC = vector;
}
render_debug_vector(TRUE, head_position, &vector, 1.f, global_real_argb_white);
render_debug_vector(TRUE, head_position, &actor->input.facing_vector, 1.f,
global_real_argb_red);
}
}
if (ai_debug.field_859F9)
{
real_point3d point;
point.x = global_up3d->i*0.05f + actor->input.position.head_position.x;
point.y = global_up3d->j*0.05f + actor->input.position.head_position.y;
point.z = global_up3d->k*0.05f + actor->input.position.head_position.z;
render_debug_vector(TRUE, &point, &ai_debug.field_85A08, 1.f, global_real_argb_green);
}
if (ai_debug.field_859F8)
{
real_point3d point;
point_from_line3d(&actor->input.position.head_position, global_up3d, 0.05f, &point);
render_debug_vector(TRUE, &point, &ai_debug.field_859FC, 1.f, global_real_argb_blue);
}
}
return;
}
static void code_00038de0(
void)
{
if (ai_debug.idle_look_valid)
{
struct actor_datum *actor = actor_try_and_get(ai_debug.idle_look_unit_index);
if (actor)
{
short index;
for (index = 0; index<ai_debug.idle_look_prop_count; index++)
{
struct prop_datum *prop = prop_try_and_get(ai_debug.idle_look_prop_index[index]);
if (prop)
{
real_argb_color const *color;
real_point3d point;
point_from_line3d(&actor->input.position.head_position, global_up3d, 0.05f, &point);
point_from_line3d(&point, &prop->actor_to_prop, 0.9f, &point);
if (actor->control.idle_major_active &&
actor->control.idle_major_direction.type==1 &&
actor->control.idle_major_direction.prop_index==ai_debug.idle_look_prop_index[index])
{
color = global_real_argb_yellow;
}
else
{
color = global_real_argb_white;
}
render_debug_string_at_point(TRUE, &point,
csprintf(temporary, "%.2f", ai_debug.idle_look_prop_weight[index]),
color);
}
}
}
}
return;
}
static void code_00038f30(
void)
{
long time = game_time_get();
short index = ai_globals->spatial_effect_head;
while (index!=ai_globals->spatial_effect_tail)
{
struct ai_debug_spatial_effect *effect = &ai_globals->spatial_effect[index];
if (effect->type!=NONE)
{
real_argb_color const **colors[3] =
{
&global_real_argb_blue,
&global_real_argb_yellow,
&global_real_argb_red
};
real_argb_color const *color = global_real_argb_white;
real_point3d *effect_point;
real_point3d point;
if (effect->type>=0 && effect->type<3)
{
color = *colors[effect->type];
}
effect_point = &effect->point;
render_debug_sphere(TRUE, effect_point, 0.2f, color);
point.x = global_up3d->i*0.3f + effect_point->x;
point.y = global_up3d->j*0.3f + effect_point->y;
point.z = global_up3d->k*0.3f + effect_point->z;
render_debug_string_at_point(TRUE, &point,
csprintf(temporary, "c%d t%d", effect->field_02, time - effect->time),
color);
}
index = (index+1)&31;
}
return;
}
static void code_00039e10(
void)
{
long actor_index = code_00038280();
if (actor_index!=NONE)
{
struct actor_datum *actor = actor_get(actor_index);
ai_debug_describe_actor(actor_index, NONE, TRUE, temporary, 256);
console_printf(FALSE, "selected %s", temporary);
ai_debug_select_actor(actor->meta.encounter_index, actor_index);
}
else
{
ai_debug_select_actor(NONE, NONE);
}
ai_debug.select_this_actor = FALSE;
return;
}
static void code_00039e80(
void)
{
struct object_iterator iterator;
struct unit_datum *unit;
object_iterator_new(&iterator, _object_mask_biped|_object_mask_vehicle, 0);
while ((unit = object_iterator_next(&iterator))!=NULL)
{
real_point3d head_position;
real_point3d point;
unit_get_head_position(iterator.index, &head_position);
point.x = global_up3d->i*0.1f + head_position.x;
point.y = global_up3d->j*0.1f + head_position.y;
point.z = global_up3d->k*0.1f + head_position.z;
ai_debug_drawstack_setup(&point);
if (ai_debug.render_dialogue_variants)
{
struct unit_definition *definition = unit_definition_get(unit->definition_index);
if (definition->unit.dialogue_variants.count>0)
{
char const *dialogue_name = "<none>";
short variant_number = NONE;
short index;
for (index = 0; index<definition->unit.dialogue_variants.count; index++)
{
struct unit_dialogue_variant *variant = TAG_BLOCK_GET_ELEMENT(
&definition->unit.dialogue_variants, index, struct unit_dialogue_variant);
if (variant->dialogue_index==unit->unit.dialogue_index)
{
variant_number = variant->variant_number;
break;
}
}
if (unit->unit.dialogue_index!=NONE)
{
dialogue_name = tag_name_strip_path(tag_get_name(unit->unit.dialogue_index));
}
render_debug_string_at_point(TRUE, ai_debug_drawstack(),
csprintf(temporary, "variant %d dialogue %d %s",
unit->object.variant_number, variant_number, dialogue_name),
global_real_argb_pink);
}
}
if (ai_debug.render_speech)
{
if (unit->unit.speech.current.priority>0)
{
char const *sound_name = unit->unit.speech.current.sound_definition_index==NONE ?
"NONE" : tag_name_strip_path(
tag_get_name(unit->unit.speech.current.sound_definition_index));
char const *vocalization_name = unit->unit.speech.current.vocalization_type==NONE ?
"NONE" : dialogue_get_vocalization_name(
unit->unit.speech.current.vocalization_type, FALSE);
render_debug_string_at_point(TRUE, ai_debug_drawstack(),
csprintf(temporary, "%s %s %s (%d %d)",
unit_get_speech_priority_name(unit->unit.speech.current.priority),
vocalization_name, sound_name,
unit->unit.speech.sound_timer, unit->unit.speech.post_delay_timer),
global_real_argb_white);
}
if (unit->unit.speech.queued.priority>0)
{
char const *sound_name = unit->unit.speech.queued.sound_definition_index==NONE ?
"NONE" : tag_name_strip_path(
tag_get_name(unit->unit.speech.queued.sound_definition_index));
char const *vocalization_name = unit->unit.speech.queued.vocalization_type==NONE ?
"NONE" : dialogue_get_vocalization_name(
unit->unit.speech.queued.vocalization_type, FALSE);
render_debug_string_at_point(TRUE, ai_debug_drawstack(),
csprintf(temporary, "%s %s %s",
unit_get_speech_priority_name(unit->unit.speech.queued.priority),
vocalization_name, sound_name),
global_real_argb_yellow);
}
}
if (ai_debug.print_speech && !ai_debug.render_speech)
{
short priority = unit->unit.speech.current.priority;
if (priority>0)
{
char string[512];
real_argb_color const *color;
/* the priority names are not recovered; these are the values the
target switches on */
switch (priority)
{
case 2:
case 7:
case 10:
color = global_real_argb_red;
break;
case 6:
color = global_real_argb_blue;
break;
default:
color = global_real_argb_white;
break;
}
render_debug_string_at_point(TRUE, ai_debug_drawstack(),
unit_describe_speech(iterator.index, FALSE, sizeof(string), string),
color);
}
}
}
return;
}
static void code_0003a2e0(
void)
{
/* Every loop below shares this index, including the inner loops, so the
vehicle loop resumes from the index left by the final inner loop. */
short index;
for (index = 0; index<ai_globals->enterable_vehicle_count; index++)
{
struct ai_debug_enterable_vehicle *vehicle = &ai_globals->enterable_vehicle[index];
if (unit_try_and_get(vehicle->object_index))
{
real_point3d origin;
object_get_origin(vehicle->object_index, &origin);
point_from_line3d(&origin, global_up3d, 0.5f, &origin);
ai_debug_drawstack_setup(&origin);
render_debug_string_at_point(TRUE, ai_debug_drawstack(),
csprintf(temporary, "enterable: dist %.1f", vehicle->distance),
global_real_argb_pink);
if (vehicle->team_flags)
{
char const *team_names[NUMBER_OF_SOLO_CAMPAIGN_TEAMS] =
{
"default", "player", "human", "covenant", "flood",
"sentinel", "unused6", "unused7", "unused8", "unused9"
};
sprintf(temporary, "teams:");
for (index = 0; index<NUMBER_OF_SOLO_CAMPAIGN_TEAMS; index++)
{
if (TEST_FLAG(vehicle->team_flags, index))
{
csstrcat(temporary, " ");
csstrcat(temporary, team_names[index]);
}
}
render_debug_string_at_point(TRUE, ai_debug_drawstack(), temporary,
global_real_argb_pink);
}
if (vehicle->actor_type_flags)
{
char const *actor_type_names[NUMBER_OF_ACTOR_TYPES] =
{
"elite", "jackal", "grunt", "hunter", "engineer", "assassin",
"player", "marine", "crew", "combat form", "infection form",
"carrier form", "monitor", "sentinel", "none", "mounted weapon"
};
sprintf(temporary, "actor types:");
for (index = 0; index<NUMBER_OF_ACTOR_TYPES; index++)
{
if (TEST_FLAG(vehicle->actor_type_flags, index))
{
csstrcat(temporary, " ");
csstrcat(temporary, actor_type_names[index]);
}
}
render_debug_string_at_point(TRUE, ai_debug_drawstack(), temporary,
global_real_argb_pink);
}
if (vehicle->actor_count>0)
{
char string[256];
sprintf(temporary, "actors:");
for (index = 0; index<vehicle->actor_count; index++)
{
ai_index_to_string(vehicle->actor_index[index], global_scenario_get(),
string, 256);
csstrcat(temporary, " ");
csstrcat(temporary, string);
}
render_debug_string_at_point(TRUE, ai_debug_drawstack(), temporary,
global_real_argb_pink);
}
}
}
return;
}
static void code_0003af00(
void)
{
if (ai_debug.path_start_valid && ai_debug.path_end_valid && !ai_debug.field_608A8)
{
real_argb_color const *color;
if (!ai_debug.path_flood && !ai_debug.path_state.destination_valid)
{
color = global_real_argb_blue;
}
else if (ai_debug.path_state.node_count==0)
{
color = global_real_argb_green;
}
else if (ai_debug.path_state.node_count>=PATH_NODE_LIST_SIZE)
{
color = global_real_argb_yellow;
}
else
{
color = global_real_argb_pink;
}
render_debug_line(TRUE, &ai_debug.path_start_point, &ai_debug.path_end_point, color);
}
if (ai_debug.path_storage.valid)
{
ai_debug_drawstack_setup(&ai_debug.path_storage.path_state.input.start_point);
ai_debug_render_path_storage(&ai_debug.path_storage);
}
return;
}
static void code_00041120(
void)
{
short index;
for (index = 0; index<MAXIMUM_AI_DEBUG_PATH_STORAGE; index++)
{
struct path_debug_storage *path = &actor_path_debug_array[index];
if (path->valid && path->failure)
{
char string[256];
real_point3d stack_base;
point_from_line3d(&path->path_state.input.start_point, global_up3d, 1.f, &stack_base);
ai_debug_drawstack_setup(&stack_base);
ai_debug_describe_actor(path->actor_index, NONE, TRUE, string, 256);
render_debug_string_at_point(TRUE, ai_debug_drawstack(), string, global_real_argb_red);
ai_debug_render_path_storage(path);
}
}
return;
}
static void code_000411d0(
boolean render_inactive_actors)
{
struct actor_iterator iterator;
actor_iterator_new(&iterator, !render_inactive_actors);
while (actor_iterator_next(&iterator))
{
ai_debug_render_actor(
iterator.actor_index,
iterator.actor_index==ai_debug.selected_actor_index,
NULL);
}
return;
}
static void code_00041220(
long encounter_index)
{
long owner_actor_indices[NUMBER_OF_AI_DEBUG_ACTOR_RECORDS];
struct encounter_definition *definition;
long history_start_time;
short index;
encounter_get(encounter_index);
definition = TAG_BLOCK_GET_ELEMENT(&global_scenario_get()->ai_encounters,
DATUM_INDEX_TO_ABSOLUTE_INDEX(encounter_index), struct encounter_definition);
history_start_time = NONE;
{
struct encounter_actor_iterator iterator;
encounter_actor_iterator_new(&iterator, encounter_index);
while (encounter_actor_iterator_next(&iterator))
{
boolean selected = (ai_debug.selected_actor_index==iterator.actor_index);
if (selected || ai_debug.selected_actor_index==NONE || ai_debug.render_all_actors)
{
ai_debug_render_actor(iterator.actor_index, selected, &history_start_time);
}
}
}
if (global_ai_debug_firing_position_color_count==NONE)
{
for (global_ai_debug_firing_position_color_count = 0;
global_ai_debug_firing_position_colors[global_ai_debug_firing_position_color_count].alpha<=1.f &&
global_ai_debug_firing_position_colors[global_ai_debug_firing_position_color_count].red<=1.f &&
global_ai_debug_firing_position_colors[global_ai_debug_firing_position_color_count].green<=1.f &&
global_ai_debug_firing_position_colors[global_ai_debug_firing_position_color_count].blue<=1.f;
global_ai_debug_firing_position_color_count++)
;
}
encounter_build_firing_position_owner_actor_indices(encounter_index, owner_actor_indices);
for (index = 0; index<definition->firing_positions.count; index++)
{
struct firing_position *position = TAG_BLOCK_GET_ELEMENT(&definition->firing_positions, index,
struct firing_position);
real_argb_color const *colors[MAXIMUM_NUMBER_OF_FIRING_POSITION_GROUPS];
boolean owner_flags[MAXIMUM_NUMBER_OF_FIRING_POSITION_GROUPS];
real_point3d corner[4];
long num_firing_position_colors = 0;
long *owner_actor_index;
long color_index;
real_point3d point;
corner[0].z = corner[1].z = corner[2].z = corner[3].z = position->position.z+0.05f;
corner[0].x = corner[3].x = position->position.x-0.25f;
corner[1].x = corner[2].x = position->position.x+0.25f;
corner[0].y = corner[1].y = position->position.y-0.25f;
corner[2].y = corner[3].y = position->position.y+0.25f;
csmemset(owner_flags, 0, sizeof(owner_flags));
if (ai_debug.selected_actor_index==NONE)
{
goto default_firing_position_colors;
}
if (actor_get(ai_debug.selected_actor_index)->meta.encounter_index!=
ai_debug.selected_squad_index)
{
default_firing_position_colors:
if (!game_in_editor())
{
num_firing_position_colors = 1;
colors[0] = &global_ai_debug_firing_position_colors[
position->group_index%global_ai_debug_firing_position_color_count];
}
}
else
{
real_argb_color const *const *group_color[MAXIMUM_NUMBER_OF_FIRING_POSITION_GROUPS-1] =
{
&global_real_argb_red,
&global_real_argb_orange,
&global_real_argb_green,
&global_real_argb_blue,
&global_real_argb_lightblue,
&global_real_argb_green,
&global_real_argb_aqua
};
struct actor_datum *actor = actor_get(ai_debug.selected_actor_index);
struct encounter_definition *actor_encounter = TAG_BLOCK_GET_ELEMENT(
&global_scenario_get()->ai_encounters,
DATUM_INDEX_TO_ABSOLUTE_INDEX(actor->meta.encounter_index),
struct encounter_definition);
struct squad_definition *squad = TAG_BLOCK_GET_ELEMENT(&actor_encounter->squads,
actor->meta.squad_index, struct squad_definition);
short default_attacking_group;
short default_defending_group;
short attacking_group;
short defending_group;
short current_group = actor->emotions.currently_defending ? 5 : 2;
if (TEST_FLAG(squad->firing_position_groups[current_group],
position->group_index))
{
colors[0] = global_real_argb_green;
num_firing_position_colors = 1;
}
default_attacking_group = actor->emotions.currently_defending ? 3 : 0;
default_defending_group = actor->emotions.currently_defending ? 4 : 1;
if (actor->state.searching)
{
attacking_group = default_defending_group;
defending_group = default_attacking_group;
}
else
{
attacking_group = default_attacking_group;
defending_group = default_defending_group;
}
if (TEST_FLAG(squad->firing_position_groups[attacking_group],
position->group_index))
{
colors[num_firing_position_colors++] = *group_color[attacking_group];
}
else if (TEST_FLAG(squad->firing_position_groups[defending_group],
position->group_index))
{
owner_flags[num_firing_position_colors] = TRUE;
colors[num_firing_position_colors++] = *group_color[defending_group];
}
if (TEST_FLAG(squad->firing_position_groups[6], position->group_index))
{
colors[num_firing_position_colors++] = global_real_argb_aqua;
}
if (!num_firing_position_colors)
{
colors[num_firing_position_colors++] = global_real_argb_white;
}
else
{
match_assert("c:\\halo\\SOURCE\\ai\\ai_debug.c", 964,
num_firing_position_colors < MAXIMUM_NUMBER_OF_FIRING_POSITION_GROUPS);
}
}
owner_actor_index = &owner_actor_indices[index];
if (*owner_actor_index!=NONE)
{
real_point3d polygon[4];
actor_get(*owner_actor_index);
polygon[0].z = polygon[1].z = polygon[2].z = polygon[3].z = position->position.z+0.05f;
polygon[0].x = polygon[3].x = position->position.x-0.375f;
polygon[1].x = polygon[2].x = position->position.x+0.375f;
polygon[0].y = polygon[1].y = position->position.y-0.375f;
polygon[2].y = polygon[3].y = position->position.y+0.375f;
render_debug_polygon(polygon, 4, actor_action_debug_color(*owner_actor_index));
}
if (ai_debug.render_firing_positions)
{
real_argb_color const *color = position->field_14==NONE ?
global_real_argb_red : global_real_argb_white;
real_point3d p0;
real_point3d p1;
p1 = position->position;
p0 = position->position;
p0.z = p0.z+0.5f;
p1.z = p1.z-0.5f;
render_debug_line(TRUE, &p0, &p1, color);
p0.z = p0.z-0.5f;
p1.z = p1.z+0.5f;
p0.x = p0.x-0.1f;
p1.x = p1.x+0.1f;
render_debug_line(TRUE, &p0, &p1, color);
p0.x = p0.x+0.1f;
p1.x = p1.x-0.1f;
p0.y = p0.y-0.1f;
p1.y = p1.y+0.1f;
render_debug_line(TRUE, &p0, &p1, color);
}
for (color_index = 0; color_index<num_firing_position_colors; color_index++)
{
corner[0].z = corner[1].z = corner[2].z = corner[3].z = corner[0].z+0.05f;
if (owner_flags[color_index])
{
render_debug_line(TRUE, &corner[0], &corner[2], colors[color_index]);
render_debug_line(TRUE, &corner[1], &corner[3], colors[color_index]);
}
else
{
render_debug_polygon_edges(corner, 4, colors[color_index]);
}
}
point.x = global_up3d->i*0.2f + position->position.x;
point.y = global_up3d->j*0.2f + position->position.y;
point.z = global_up3d->k*0.2f + position->position.z;
ai_debug_drawstack_setup(&point);
if (ai_debug.render_pursuit && ai_debug.actor_record[index].field_00)
{
boolean pursued = FALSE;
boolean examined;
short examined_count;
if (ai_debug.selected_actor_index!=NONE)
{
render_debug_string_at_point(TRUE, ai_debug_drawstack(),
csprintf(temporary, "%3.2f", ai_debug.actor_record[index].field_3C),
ai_debug.actor_record[index].field_34 ?
global_real_argb_white : global_real_argb_red);
}
if (ai_debug.selected_actor_index!=NONE)
{
struct pursuit_location const *location =
actor_get_pursuit_location(ai_debug.selected_actor_index);
pursued = (location && location->type==1 &&
location->firing_position_index==index);
}
examined = encounter_pursuit_position_already_examined(encounter_index,
ai_debug.selected_actor_index, index,
history_start_time==NONE ? 0 : history_start_time, &examined_count, FALSE);
if (ai_debug.selected_actor_index==NONE)
{
examined = FALSE;
}
render_debug_string_at_point(TRUE, ai_debug_drawstack(),
csprintf(temporary, "%d", examined_count),
pursued ? global_real_argb_yellow :
examined ? global_real_argb_blue : global_real_argb_white);
if (ai_debug.field_7D380 &&
ai_debug.field_7D384.field_5FC && ai_debug.field_7D384.field_043 &&
ai_debug.actor_record[index].field_01 &&
ai_debug.actor_record[index].field_34)
{
real_point3d origin;
origin.x = ai_debug.field_7D384.field_604.x+
ai_debug.actor_record[index].field_24.x;
origin.y = ai_debug.field_7D384.field_604.y+
ai_debug.actor_record[index].field_24.y;
origin.z = ai_debug.field_7D384.field_604.z+
ai_debug.actor_record[index].field_24.z;
render_debug_line(TRUE, &ai_debug.field_7D384.field_604, &origin,
global_real_argb_yellow);
render_debug_line(TRUE, &origin, &position->position, global_real_argb_green);
}
}
else if (ai_debug.render_evaluations && ai_debug.actor_record[index].field_01 &&
!ai_debug.actor_record[index].field_00 &&
ai_debug.selected_actor_index!=NONE)
{
real_argb_color const *color;
real_argb_color const *string_color = NULL;
if (!ai_debug.actor_record[index].field_34)
{
color = global_real_argb_red;
}
else if (ai_debug.actor_record[index].field_38>0.f)
{
string_color = global_real_argb_white;
color = *owner_actor_index==ai_debug.selected_actor_index ?
global_real_argb_yellow : global_real_argb_blue;
}
else
{
color = global_real_argb_white;
}
if (string_color)
{
render_debug_string_at_point(TRUE, ai_debug_drawstack(),
csprintf(temporary, "%3.2f", ai_debug.actor_record[index].field_38),
string_color);
render_debug_string_at_point(TRUE, ai_debug_drawstack(),
csprintf(temporary, "%3.2f", ai_debug.actor_record[index].field_3C), color);
}
else
{
render_debug_string_at_point(TRUE, ai_debug_drawstack(),
csprintf(temporary, "%3.2f", ai_debug.actor_record[index].field_3C), color);
}
}
}
return;
}
static void code_000386a0(
void)
{
struct unit_datum *unit;
if (!ai_debug.speak_valid)
{
return;
}
if (ai_debug.speak_unit_index==NONE)
{
return;
}
unit = unit_try_and_get(ai_debug.speak_unit_index);
if (!unit || TEST_FLAG(unit->object.damage_flags, _object_dead_bit))
{
ai_debug.speak_valid = FALSE;
return;
}
if (unit->unit.speech.current.priority!=0)
{
return;
}
if (ai_debug.field_85B28>0)
{
ai_debug.field_85B28--;
}
if (ai_debug.field_85B28!=0)
{
return;
}
if (ai_debug.speak_vocalization_type>=0 &&
ai_debug.speak_vocalization_type<NUMBER_OF_AI_DEBUG_VOCALIZATION_TYPES)
{
char const *name;
short vocalization_type = ai_debug.speak_vocalization_type;
long sound_definition_index = NONE;
short speech_type = unit_test_speech(ai_debug.speak_unit_index, 3, 0, 0, 0,
&vocalization_type, &sound_definition_index);
if (speech_type>=2)
{
struct unit_speech_item item;
csmemset(&item, 0, sizeof(item));
item.vocalization_type = vocalization_type;
item.sound_definition_index = sound_definition_index;
item.priority = 4;
item.pause_time = 15;
ai_communication_packet_new(&item.ai);
unit_speak(ai_debug.speak_unit_index, speech_type, &item);
if (sound_definition_index!=NONE)
{
char *tag_name = tag_get_name(sound_definition_index);
char *conditional = strstr(tag_name, "conditional");
name = tag_name;
if (conditional)
{
char *separator = strchr(conditional, '\\');
if (separator && ++separator)
{
name = separator;
}
}
}
else
{
name = "<none>";
}
}
else
{
name = "<none>";
}
console_printf(FALSE, "%s: %s",
dialogue_get_vocalization_name(ai_debug.speak_vocalization_type, FALSE), name);
if (ai_debug.field_85B21)
{
ai_debug.field_85B28 = 15;
do
{
ai_debug.speak_vocalization_type++;
if (csstrcmp(dialogue_get_vocalization_name(ai_debug.speak_vocalization_type, FALSE), "unused")!=0)
{
break;
}
if (!ai_debug.field_85B22)
{
ai_debug.speak_vocalization_type = NONE;
break;
}
}
while (ai_debug.speak_vocalization_type<NUMBER_OF_AI_DEBUG_VOCALIZATION_TYPES);
}
else
{
ai_debug.speak_vocalization_type = NONE;
}
}
if (ai_debug.speak_vocalization_type<0 ||
ai_debug.speak_vocalization_type>=NUMBER_OF_AI_DEBUG_VOCALIZATION_TYPES)
{
console_printf(FALSE, "speech done");
ai_debug.speak_valid = FALSE;
}
return;
}
static void code_00039060(
void)
{
short index;
short other_index;
for (index = 0; index<MAXIMUM_AI_DEBUG_PATH_STORAGE; index++)
{
struct path_debug_storage *path = &actor_path_debug_array[index];
if (path->valid && path->failure)
{
for (other_index = index+1; other_index<MAXIMUM_AI_DEBUG_PATH_STORAGE; other_index++)
{
struct path_debug_storage *other = &actor_path_debug_array[other_index];
if (other->valid && other->failure &&
other->actor_index==path->actor_index &&
distance_squared3d(&path->path_state.input.start_point, &other->path_state.input.start_point)<0.25f &&
path->path_state.destination_valid==other->path_state.destination_valid &&
(!path->path_state.destination_valid ||
distance_squared3d(&path->path_state.destination.point, &other->path_state.destination.point)<0.25f))
{
if (path->path_time<other->path_time)
{
path->valid = FALSE;
break;
}
other->valid = FALSE;
}
}
}
}
return;
}
static void code_00037890(
real_point3d const *start,
real_argb_color const *color,
short step_count,
struct path_step *steps)
{
short index;
if (step_count>0)
{
render_debug_line_offset(TRUE, start, &steps[0].point, color, 0.1f);
}
for (index = 0; index<step_count; index++)
{
if (index>0)
{
render_debug_line_offset(TRUE, &steps[index-1].point, &steps[index].point, color, 0.1f);
}
render_debug_tick(TRUE, &steps[index].point, global_up3d, 0.02f, color);
}
return;
}
static long code_00038280(
void)
{
long actor_index = NONE;
short local_player_index = NONE;
short index;
for (index = 0; index<MAXIMUM_LOCAL_PLAYERS; index++)
{
if (local_player_exists(index))
{
local_player_index = index;
break;
}
}
if (local_player_index!=NONE)
{
struct observer_result const *camera = observer_get_camera(local_player_index);
long ignore_object_index = NONE;
real_vector3d vector;
struct collision_result collision;
match_assert("c:\\halo\\SOURCE\\ai\\ai_debug.c", 4489, camera != NULL);
if (!director_get_perspective(local_player_index))
{
long player_index = local_player_get_player_index(local_player_index);
if (player_index!=NONE)
{
ignore_object_index = player_get(player_index)->unit_index;
}
}
vector.i = camera->forward.i*50.f;
vector.j = camera->forward.j*50.f;
vector.k = camera->forward.k*50.f;
if (collision_test_vector(0x81, &camera->position, &vector, ignore_object_index, &collision) &&
collision.type==3 && collision.object_index!=NONE)
{
struct unit_datum *unit = unit_try_and_get(collision.object_index);
if (unit)
{
actor_index = unit->unit.swarm_actor_index==NONE ?
unit->unit.actor_index : unit->unit.swarm_actor_index;
if (actor_index==NONE && unit->unit.driver_object_index!=NONE)
{
struct unit_datum *driver = unit_get(unit->unit.driver_object_index);
actor_index = driver->unit.swarm_actor_index!=NONE ?
driver->unit.swarm_actor_index : driver->unit.actor_index;
}
}
}
}
return actor_index;
}