Files
Cesarus85--ringfall-mjolnir-vr/source/interface/hud_unit.c
T
MrBruh 5a7c655a60 Testing branch review fixes
Network version 28: the host now holds a downloading machine's players out
of the game, and keeps a multiplayer map's first scripted BSP. Dynamic lights
and the flashlight stay on past the Xbox limits, and a second weapon picked
up while firing is readied. Machines of version 27 would disagree on these.

- A large co-op game's respawn fallback no longer picks a teammate who is in
  the air, outside the BSP, or riding an AI vehicle.
- A machine still downloading the map times out when it goes silent.
- Held players join through the late-join queue, so they get the same checks.
  A machine with no held players is started instead of being refused.
- The co-op teleport uses world positions, which are right for seated players.
- Overshield drain no longer cuts off a hit's flash, and hits over 0.02 flash.
- The menu XML is the generator's (Custom Edition's layout) again.
- port: markers on two new declarations.

Checked: ninja linux, android and web build; tools/harness,
test_touch_menu and test_web_build pass.
2026-10-12 20:01:49 +13:00

1374 lines
36 KiB
C

/*
HUD_UNIT.C
symbols in this file:
000C6590 0010:
_unit_hud_outline_mapper_tick (0000)
000C65A0 0010:
_unit_hud_shield_meter_mapper_tick (0000)
000C65B0 0010:
_unit_hud_shield_meter_mapper_init (0000)
000C65C0 0040:
_initialize_hud_state (0000)
000C6600 0070:
_get_hud_state (0000)
000C6670 0040:
_hud_initialize_unit_interface (0000)
000C66B0 00f0:
_hud_initialize_unit_interface_for_new_map (0000)
000C67A0 0010:
_hud_dispose_unit_interface_from_old_map (0000)
000C67B0 0010:
_hud_dispose_unit_interface (0000)
000C67C0 0030:
_scripted_hud_show_health (0000)
000C67F0 0030:
_scripted_hud_blink_health (0000)
000C6820 0030:
_scripted_hud_show_shield (0000)
000C6850 0030:
_scripted_hud_blink_shield (0000)
000C6880 0030:
_scripted_hud_show_motion_sensor (0000)
000C68B0 0030:
_scripted_hud_blink_motion_sensor (0000)
000C68E0 0220:
_hud_play_unit_sounds (0000)
000C6B00 0080:
_hud_fix_unit_data (0000)
000C6B80 0220:
_hud_update_unit_local_player (0000)
000C6DA0 02b0:
_hud_render_damage_indicators (0000)
000C7050 0040:
_hud_tick_shield (0000)
000C7090 0030:
_hud_update_unit (0000)
000C70C0 0db0:
_hud_render_unit_interface (0000)
00270268 0011:
??_C@_0BB@MIFNILGL@unit_hud_globals?$AA@ (0000)
0027027C 0024:
??_C@_0CE@ICNCJJA@c?3?2halo?2SOURCE?2interface?2hud_uni@ (0000)
002702A0 0013:
??_C@_0BD@OOGPMJCA@hud?5unit?5interface?$AA@ (0000)
002702B4 0004:
__real@3e400000 (0000)
002702B8 001d:
??_C@_0BN@FNBCLDEB@new_local_player_index?$CB?$DNNONE?$AA@ (0000)
002702D8 001d:
??_C@_0BN@NPOPPJAG@old_local_player_index?$CB?$DNNONE?$AA@ (0000)
002E4C68 0004:
?overcharge_count@?1??hud_render_unit_interface@@9@9 (0000)
00453AC0 0004:
_unit_hud_globals (0000)
*/
/* ---------- headers */
#include "cseries/cseries.h"
#include "cseries/errors.h"
#include "cutscene/cinematics.h"
#include "effects/player_effects.h"
#include "game/game.h"
#include "game/game_engine.h"
#include "game/players.h"
#include "cache/texture_cache.h"
#include "interface/hud_definitions.h"
#include "bitmaps/bitmap_color_conversion.h"
#include "interface/hud_draw.h"
#include "interface/hud.h"
#include "interface/motion_sensor.h"
#include "interface/hud_unit.h"
#include "interface/unit_hud_interface_definition.h"
#include "render/render.h"
#include "saved games/game_state.h"
#include "tag_files/tag_groups.h"
#include "units/unit_definitions.h"
#include "units/units.h"
/* ---------- constants */
enum
{
_hud_panel_health_dont_show_bit = 0,
_hud_panel_health_blink_bit,
_hud_panel_shield_dont_show_bit,
_hud_panel_shield_blink_bit,
_hud_panel_motion_sensor_dont_show_bit,
_hud_panel_motion_sensor_blink_bit
};
enum hud_damage_indicator_direction
{
_hud_damage_indicator_top = 0,
_hud_damage_indicator_left,
_hud_damage_indicator_bottom,
_hud_damage_indicator_right,
NUMBER_OF_HUD_DAMAGE_INDICATOR_DIRECTIONS
};
/* ---------- macros */
/* ---------- structures */
struct unit_hud_state
{
real last_shield_vitality;
real last_body_vitality;
real fade_time;
long last_shield_hit_time;
long last_shield_flash_time;
long last_health_flash_time;
long last_motion_sensor_flash_time;
long last_unit_index;
word auxilary_active_type_flags;
short auxilary_flash_time[1];
word sound_flags;
byte pad26[2];
long last_sound_handles[12];
};
struct unit_hud_globals
{
struct unit_hud_state hud_states[MAXIMUM_NUMBER_OF_LOCAL_PLAYERS];
long script_flags;
};
typedef char unit_hud_state_auxilary_flash_time_offset_assert[
offsetof(struct unit_hud_state, auxilary_flash_time) == 0x22 ? 1 : -1];
typedef char unit_hud_state_sound_flags_offset_assert[
offsetof(struct unit_hud_state, sound_flags) == 0x24 ? 1 : -1];
typedef char unit_hud_state_last_sound_handles_offset_assert[
offsetof(struct unit_hud_state, last_sound_handles) == 0x28 ? 1 : -1];
typedef char unit_hud_state_size_assert[
sizeof(struct unit_hud_state) == 0x58 ? 1 : -1];
typedef char unit_hud_globals_script_flags_offset_assert[
offsetof(struct unit_hud_globals, script_flags) == 0x160 ? 1 : -1];
typedef char unit_hud_globals_size_assert[
sizeof(struct unit_hud_globals) == 0x164 ? 1 : -1];
typedef char hud_scripted_globals_size_assert[
sizeof(struct hud_scripted_globals_definition) == 0x4 ? 1 : -1];
typedef char hud_messaging_parameters_definition_size_assert[
sizeof(struct hud_messaging_parameters_definition) == 0x120 ? 1 : -1];
typedef char hud_waypoint_definition_size_assert[
sizeof(struct hud_waypoint_definition) == 0x9C ? 1 : -1];
typedef char hud_multiplayer_parameters_definition_size_assert[
sizeof(struct hud_multiplayer_parameters_definition) == 0x104 ? 1 : -1];
typedef char hud_defaults_definition_size_assert[
sizeof(struct hud_defaults_definition) == 0x50 ? 1 : -1];
typedef char hud_damage_indicators_definition_indicator_bitmap_offset_assert[
offsetof(struct hud_damage_indicators_definition, indicator_bitmap) == 0x28 ? 1 : -1];
typedef char hud_damage_indicators_definition_size_assert[
sizeof(struct hud_damage_indicators_definition) == 0x50 ? 1 : -1];
typedef char hud_globals_definition_damage_indicators_offset_assert[
offsetof(struct hud_globals_definition, damage_indicators) == 0x310 ? 1 : -1];
/* ---------- prototypes */
static struct unit_hud_state *get_hud_state(
short local_player_index);
static void hud_update_unit_local_player(
short local_player_index);
/* ---------- globals */
static struct unit_hud_globals *unit_hud_globals = NULL;
/* ---------- private code */
static void unit_hud_outline_mapper_tick(
void)
{
return;
}
static void unit_hud_shield_meter_mapper_tick(
void)
{
return;
}
/* ---------- public code */
void unit_hud_shield_meter_mapper_init(
void)
{
return;
}
/* ---------- private code */
static void initialize_hud_state(
struct unit_hud_state *hud_state)
{
csmemset(
hud_state->auxilary_flash_time,
NONE,
sizeof(hud_state->auxilary_flash_time));
hud_state->last_body_vitality = -1.0f;
hud_state->last_shield_vitality = -1.0f;
hud_state->last_health_flash_time = NONE;
hud_state->last_motion_sensor_flash_time = NONE;
hud_state->fade_time = -1.0f;
hud_state->last_unit_index = NONE;
return;
}
static struct unit_hud_state *get_hud_state(
short local_player_index)
{
match_assert(
"c:\\halo\\SOURCE\\interface\\hud_unit.c",
0x106,
local_player_index>=0 &&
local_player_index<MAXIMUM_NUMBER_OF_LOCAL_PLAYERS);
match_assert(
"c:\\halo\\SOURCE\\interface\\hud_unit.c",
0x107,
unit_hud_globals);
return &unit_hud_globals->hud_states[local_player_index];
}
/* ---------- public code */
void hud_initialize_unit_interface(
void)
{
unit_hud_globals = game_state_malloc(
"hud unit interface",
NULL,
sizeof(*unit_hud_globals));
match_assert(
"c:\\halo\\SOURCE\\interface\\hud_unit.c",
0x110,
unit_hud_globals);
return;
}
void hud_initialize_unit_interface_for_new_map(
void)
{
short local_player_index;
struct unit_hud_state *hud_state;
match_assert(
"c:\\halo\\SOURCE\\interface\\hud_unit.c",
0x11B,
unit_hud_globals);
csmemset(
unit_hud_globals,
0,
sizeof(*unit_hud_globals));
for (local_player_index = 0;
local_player_index < MAXIMUM_NUMBER_OF_LOCAL_PLAYERS;
local_player_index++)
{
hud_state = get_hud_state(local_player_index);
initialize_hud_state(hud_state);
hud_state->sound_flags = 0;
csmemset(
hud_state->last_sound_handles,
NONE,
sizeof(hud_state->last_sound_handles));
}
return;
}
void hud_dispose_unit_interface_from_old_map(
void)
{
return;
}
void hud_dispose_unit_interface(
void)
{
return;
}
void hud_fix_unit_data(
short old_local_player_index,
short new_local_player_index)
{
struct unit_hud_state *old_hud_state;
struct unit_hud_state *new_hud_state;
match_assert(
"c:\\halo\\SOURCE\\interface\\hud_unit.c",
0x1AB,
old_local_player_index!=NONE);
match_assert(
"c:\\halo\\SOURCE\\interface\\hud_unit.c",
0x1AC,
new_local_player_index!=NONE);
old_hud_state = get_hud_state(old_local_player_index);
new_hud_state = get_hud_state(new_local_player_index);
*new_hud_state = *old_hud_state;
return;
}
void scripted_hud_show_health(
boolean show)
{
SET_FLAG(
unit_hud_globals->script_flags,
_hud_panel_health_dont_show_bit,
!show);
return;
}
void scripted_hud_blink_health(
boolean blink)
{
SET_FLAG(
unit_hud_globals->script_flags,
_hud_panel_health_blink_bit,
blink);
return;
}
void scripted_hud_show_shield(
boolean show)
{
SET_FLAG(
unit_hud_globals->script_flags,
_hud_panel_shield_dont_show_bit,
!show);
return;
}
void scripted_hud_blink_shield(
boolean blink)
{
SET_FLAG(
unit_hud_globals->script_flags,
_hud_panel_shield_blink_bit,
blink);
return;
}
void scripted_hud_show_motion_sensor(
boolean show)
{
SET_FLAG(
unit_hud_globals->script_flags,
_hud_panel_motion_sensor_dont_show_bit,
!show);
return;
}
void scripted_hud_blink_motion_sensor(
boolean blink)
{
SET_FLAG(
unit_hud_globals->script_flags,
_hud_panel_motion_sensor_blink_bit,
blink);
return;
}
/* port: the scripts' show and blink flags, for network co-op
(port/linux/game/network_coop.c) */
long hud_unit_port_script_flags(
void)
{
return unit_hud_globals->script_flags;
}
void hud_unit_port_set_script_flags(
long flags)
{
unit_hud_globals->script_flags = flags;
}
void hud_play_unit_sounds(
struct player_datum const *player,
boolean show_hud)
{
struct unit_hud_state *hud_state = get_hud_state(player->local_player_index);
long unit_index = player->unit_index;
if (unit_index == NONE)
unit_index = hud_state->last_unit_index;
{
struct unit_datum *unit = unit_try_and_get(unit_index);
if (unit == NULL)
return;
{
struct unit_definition const *unit_definition =
unit_definition_get(unit->definition_index);
long active_hud_index = unit_definition_get_active_hud_index(
unit_definition,
local_player_count() > 1);
if (active_hud_index == NONE)
return;
{
struct unit_hud_interface_definition const *hud_definition =
unit_hud_interface_definition_get(active_hud_index);
unsigned long sound_flags = 0;
if (TEST_FLAG(unit->object.flags, _object_on_media_bit) ||
!(unit->object.body_vitality > 0.0f))
{
hud_state->last_unit_index = NONE;
}
else if (show_hud && !cinematic_in_progress())
{
if (hud_state->last_shield_vitality != -1.0f &&
game_engine_has_shield(local_player_get_player_index(
player->local_player_index)))
{
if (!TEST_FLAG(
unit_hud_globals->script_flags,
_hud_panel_shield_dont_show_bit))
{
sound_flags = TEST_FLAG(
unit->object.damage_flags,
_object_shield_charging_bit);
SET_FLAG(
sound_flags,
_unit_hud_shield_damage,
hud_state->last_shield_vitality >
unit->object.shield_vitality);
SET_FLAG(
sound_flags,
_unit_hud_shield_low,
unit->object.shield_vitality < 0.25f &&
unit->object.shield_vitality > 0.0f);
SET_FLAG(
sound_flags,
_unit_hud_shield_empty,
unit->object.shield_vitality == 0.0f);
}
}
if (!TEST_FLAG(
unit_hud_globals->script_flags,
_hud_panel_health_dont_show_bit))
{
SET_FLAG(
sound_flags,
_unit_hud_health_low,
unit->object.body_vitality < 0.25f);
SET_FLAG(
sound_flags,
_unit_hud_health_empty,
TEST_FLAG(unit->object.damage_flags, _object_dead_bit));
SET_FLAG(
sound_flags,
_unit_hud_minor_damage,
hud_state->last_body_vitality >
unit->object.body_vitality &&
hud_state->last_body_vitality -
unit->object.body_vitality < 0.1875f);
SET_FLAG(
sound_flags,
_unit_hud_major_damage,
hud_state->last_body_vitality -
unit->object.body_vitality >= 0.1875f);
}
}
hud_play_sound(
player->local_player_index,
sound_flags,
&hud_definition->warning_sounds,
hud_state->last_sound_handles,
&hud_state->sound_flags,
(short)NUMBEROF(hud_state->last_sound_handles));
}
}
}
return;
}
/* ---------- private code */
static void hud_update_unit_local_player(
short local_player_index)
{
long return_eip = get_return_eip();
long stack_buffer[STACK_BUFFER_LENGTH];
csmemset(stack_buffer, 0x62, sizeof(stack_buffer));
if (local_player_get_player_index(local_player_index) != NONE)
{
long unit_index = player_get(
local_player_get_player_index(local_player_index))->unit_index;
if (unit_index != NONE)
{
struct unit_datum *unit = unit_get(unit_index);
struct unit_hud_state *hud_state = get_hud_state(local_player_index);
if (hud_state->last_body_vitality == -1.0f)
hud_state->last_body_vitality = unit->object.body_vitality;
if (hud_state->last_shield_vitality == -1.0f)
hud_state->last_shield_vitality = unit->object.shield_vitality;
if (hud_state->last_shield_vitality > unit->object.shield_vitality)
{
real shield_drop = hud_state->last_shield_vitality - unit->object.shield_vitality;
/* port: the host drains an overshield by about 0.00074 a tick
and moves this meter's memory with it (hud_tick_shield). A
client does not drain shields. The lower value arrived as a
hit, so the meter flashed and the shield damage sound played
for the whole overshield. A small step from past full is that
drain (no more than about 25 ticks of it). A larger step is a
hit, and the meter still flashes. The step is closed here, so
one late packet cannot leave the meter a little behind and keep
the flash going, and a hit's flash already fading goes on
fading, as when the shield holds still. */
if (hud_state->last_shield_vitality > 1.0f && shield_drop <= 0.02f)
{
hud_state->last_shield_vitality = unit->object.shield_vitality;
if (hud_state->fade_time > 0.0f)
{
hud_state->fade_time +=
(real)(game_time_get() - hud_state->last_shield_hit_time) *
(1.0f / TICKS_PER_SECOND);
}
hud_state->last_shield_hit_time = game_time_get();
}
else
{
if (hud_state->fade_time < 0.0f || hud_state->fade_time > 1.0f)
hud_state->last_shield_hit_time = game_time_get();
if (game_time_get() - hud_state->last_shield_hit_time < 15)
{
hud_state->fade_time = 0.0f;
}
else
{
hud_state->last_shield_vitality = unit->object.shield_vitality;
hud_state->fade_time +=
(real)(game_time_get() - hud_state->last_shield_hit_time) *
(1.0f / TICKS_PER_SECOND);
hud_state->last_shield_hit_time = game_time_get();
}
}
}
else if (hud_state->last_shield_vitality < unit->object.shield_vitality)
{
hud_state->last_shield_vitality = unit->object.shield_vitality;
hud_state->fade_time = -1.0f;
hud_state->last_shield_hit_time = game_time_get();
}
else
{
hud_state->last_shield_vitality = unit->object.shield_vitality;
if (hud_state->fade_time > 0.0f)
{
hud_state->fade_time +=
(real)(game_time_get() - hud_state->last_shield_hit_time) *
(1.0f / TICKS_PER_SECOND);
}
hud_state->last_shield_hit_time = game_time_get();
}
}
}
if (cinematic_in_progress())
{
long player_index = local_player_get_player_index(local_player_index);
if (player_index != NONE)
{
hud_play_unit_sounds(
player_get(player_index),
hud_scripted_globals->show_hud);
}
}
match_assert_stack_frame("c:\\halo\\SOURCE\\interface\\hud_unit.c", 0x201);
return;
}
/* ---------- public code */
void hud_render_damage_indicators(
short local_player_index)
{
long unit_index;
if (local_player_index == NONE)
return;
if (local_player_get_player_index(local_player_index) == NONE)
{
unit_index = NONE;
}
else
{
unit_index = player_get(
local_player_get_player_index(local_player_index))->unit_index;
}
if (unit_try_and_get(unit_index))
{
struct hud_damage_indicators_definition *definition =
&hud_globals->damage_indicators;
real theta = 0.0f;
real_point2d screen_position = { 0 };
real scale = hud_globals_get_scale(local_player_count() > 1);
byte damage_indicators[NUMBER_OF_HUD_DAMAGE_INDICATOR_DIRECTIONS];
short direction;
player_effect_get_damage_indicators(
local_player_index,
damage_indicators);
for (direction = 0;
direction < NUMBER_OF_HUD_DAMAGE_INDICATOR_DIRECTIONS;
direction++)
{
if (damage_indicators[direction] > 0 &&
damage_indicators[direction] < TICKS_PER_SECOND)
{
long bitmap_group_index;
short sequence_index;
struct bitmap_data const *bitmap;
real_rectangle2d const *clip;
switch (direction)
{
case _hud_damage_indicator_top:
theta = _pi;
screen_position.y = (real)(
render.camera.window_bounds.y0 +
definition->top_offset);
screen_position.x = (real)(
(render.camera.viewport_bounds.x0 +
render.camera.viewport_bounds.x1) / 2);
break;
case _hud_damage_indicator_left:
theta = _pi / 2.0f;
screen_position.x = (real)(
render.camera.window_bounds.x0 +
definition->left_offset);
screen_position.y = (real)(
(render.camera.viewport_bounds.y0 +
render.camera.viewport_bounds.y1) / 2);
break;
case _hud_damage_indicator_bottom:
theta = 0.0f;
screen_position.y = (real)(
render.camera.window_bounds.y1 -
definition->bottom_offset);
screen_position.x = (real)(
(render.camera.viewport_bounds.x0 +
render.camera.viewport_bounds.x1) / 2);
break;
case _hud_damage_indicator_right:
theta = 3.0f * _pi / 2.0f;
screen_position.x = (real)(
render.camera.window_bounds.x1 -
definition->right_offset);
screen_position.y = (real)(
(render.camera.viewport_bounds.y0 +
render.camera.viewport_bounds.y1) / 2);
break;
default:
match_assert(
"c:\\halo\\SOURCE\\interface\\hud_unit.c",
0x400,
!"unreachable");
break;
}
screen_position.x -= (real)render.camera.viewport_bounds.x0;
screen_position.y -= (real)render.camera.viewport_bounds.y0;
bitmap_group_index = definition->indicator_bitmap.index;
if (local_player_count() > 1)
sequence_index = definition->multiplayer_sequence_index;
else
sequence_index = definition->sequence_index;
bitmap = NULL;
clip = NULL;
hud_retrieve_bitmap_and_bounding_rect(
bitmap_group_index,
sequence_index,
0,
&bitmap,
&clip);
if (bitmap &&
_texture_cache_bitmap_get_hardware_format(
(struct bitmap_data *)bitmap,
FALSE,
TRUE))
{
point2d corner;
corner.x = (short)(long)screen_position.x;
corner.y = (short)(long)screen_position.y;
hud_draw_bitmap_direct(
bitmap,
_hud_anchor_center,
&corner,
clip,
scale,
theta,
definition->color,
FALSE);
}
}
}
}
else
{
player_effect_clear_damage_indicators(local_player_index);
}
return;
}
/* ---------- public code */
void hud_tick_shield(
long player_index,
real amount)
{
short local_player_index = player_get(player_index)->local_player_index;
if (local_player_index != NONE)
get_hud_state(local_player_index)->last_shield_vitality -= amount;
return;
}
void hud_update_unit(
void)
{
short local_player_index = local_player_get_next(NONE);
while (local_player_index != NONE)
{
hud_update_unit_local_player(local_player_index);
local_player_index = local_player_get_next(local_player_index);
}
return;
}
/* ---------- public code */
void hud_render_unit_interface(
struct player_datum *player)
{
static long overcharge_count = 4;
long return_eip = get_return_eip();
long stack_buffer[STACK_BUFFER_LENGTH];
csmemset(stack_buffer, 0x62, sizeof(stack_buffer));
match_assert(
"c:\\halo\\SOURCE\\interface\\hud_unit.c",
0x209,
player->local_player_index==render.local_player_index);
unit_hud_shield_meter_mapper_tick();
unit_hud_outline_mapper_tick();
if (player->local_player_index == render.local_player_index &&
player->unit_index != NONE)
{
struct unit_datum *unit = unit_get(player->unit_index);
struct unit_definition const *unit_definition =
unit_definition_get(unit->definition_index);
short local_player_index = player->local_player_index;
long player_index = local_player_get_player_index(local_player_index);
struct unit_hud_state *hud_state = get_hud_state(local_player_index);
long unit_indices[18] = { player->unit_index };
long unit_hud_indices[18] =
{
unit_definition_get_active_hud_index(
unit_definition,
local_player_count() > 1)
};
long unit_count = 1;
unsigned long auxilary_flags;
unsigned long aux_activated_when_disabled_flags;
real auxilary_values[1];
if (hud_state->last_unit_index == NONE)
initialize_hud_state(get_hud_state(player->local_player_index));
hud_state->last_unit_index = player->unit_index;
if (unit->object.parent_object_index != NONE &&
unit->unit.parent_seat_index != NONE)
{
long parent_unit_index = unit->object.parent_object_index;
struct unit_datum *parent_unit = unit_get(parent_unit_index);
struct unit_definition const *parent_unit_definition =
unit_definition_get(parent_unit->definition_index);
struct unit_seat const *seat = TAG_BLOCK_GET_ELEMENT(
&parent_unit_definition->unit.seats,
unit->unit.parent_seat_index,
struct unit_seat);
long parent_hud_index;
get_hud_state(local_player_index);
parent_hud_index = unit_definition_get_active_hud_index(
parent_unit_definition,
local_player_count() > 1);
if (TEST_FLAG(seat->flags, _unit_seat_driver_bit))
{
long child_unit_index;
if (parent_hud_index != NONE)
{
unit_indices[1] = parent_unit_index;
unit_hud_indices[1] = parent_hud_index;
unit_count = 2;
}
child_unit_index = parent_unit->object.first_child_object_index;
while (child_unit_index != NONE && unit_count < NUMBEROF(unit_indices))
{
struct object_datum *child_object = object_get(child_unit_index);
struct unit_datum *child_unit = unit_try_and_get(child_unit_index);
if (child_unit &&
child_unit->object.parent_object_index == parent_unit_index &&
child_unit->unit.parent_seat_index != NONE)
{
unit_indices[unit_count] = child_unit_index;
unit_hud_indices[unit_count] =
unit_definition_get_seat_active_hud_index(
parent_unit_definition,
child_unit->unit.parent_seat_index,
local_player_count() > 1);
unit_count++;
}
child_unit_index = child_object->object.next_object_index;
}
}
}
auxilary_flags = unit->unit.integrated_light_power == 1.0f;
aux_activated_when_disabled_flags =
!TEST_FLAG(unit->unit.flags, _unit_integrated_light_on_bit) &&
unit->unit.integrated_light_battery < 0.2f &&
TEST_FLAG(unit->unit.control_flags, _unit_control_integrated_light_bit);
auxilary_values[0] = unit->unit.integrated_light_battery;
while (unit_count)
{
struct unit_datum *hud_unit;
unit_count--;
hud_unit = unit_try_and_get(unit_indices[unit_count]);
if (hud_unit && unit_hud_indices[unit_count] != NONE)
{
struct unit_hud_interface_definition *hud_definition =
unit_hud_interface_definition_get(unit_hud_indices[unit_count]);
if (hud_definition->background.interface_bitmap.index != NONE)
{
short draw_flags = 0;
SET_FLAG(
draw_flags,
_hud_draw_disabled_bit,
TEST_FLAG(hud_unit->object.damage_flags, _object_dead_bit));
SET_FLAG(
draw_flags,
_hud_draw_in_multiplayer_bit,
local_player_count() > 1);
hud_draw_static_element(
local_player_index,
&hud_definition->absolute_placement,
&hud_definition->background,
draw_flags,
NONE);
}
if (game_engine_has_shield(player_index) &&
!TEST_FLAG(
unit_hud_globals->script_flags,
_hud_panel_shield_dont_show_bit))
{
short draw_flags =
hud_unit->object.shield_vitality < 0.25f ||
TEST_FLAG(
unit_hud_globals->script_flags,
_hud_panel_shield_blink_bit);
SET_FLAG(
draw_flags,
_hud_draw_disabled_bit,
TEST_FLAG(hud_unit->object.damage_flags, _object_dead_bit));
SET_FLAG(
draw_flags,
_hud_draw_in_multiplayer_bit,
local_player_count() > 1);
if (unit_count == 0)
{
if (TEST_FLAG(draw_flags, _hud_draw_flashing_bit))
{
if (hud_state->last_shield_flash_time == NONE)
hud_state->last_shield_flash_time = game_time_get();
}
else
{
hud_state->last_shield_flash_time = NONE;
}
}
if (hud_definition->shield_meter.meter.meter_bitmap.index != NONE)
{
real reference_shield_vitality;
short value_scale;
struct meter_hud_element_definition overcharge_meter;
game_engine_running();
if (unit_count == 0)
reference_shield_vitality = hud_state->last_shield_vitality;
else
reference_shield_vitality = hud_unit->object.shield_vitality;
value_scale = hud_definition->shield_meter.meter.value_scale ?
hud_definition->shield_meter.meter.value_scale :
UNSIGNED_CHAR_MAX;
overcharge_meter = hud_definition->shield_meter.meter;
{
pixel32 color[5] =
{
0,
0x00FF0000,
0x0000FF00,
0x00FFFF00,
0x007F00FF,
};
pixel32 *overcharge_color = color;
long overcharge_index;
for (overcharge_index = 0;
overcharge_index <= overcharge_count;
overcharge_color++, overcharge_index++)
{
boolean first_meter = overcharge_index == 0;
real shield_vitality = PIN(
hud_unit->object.shield_vitality - (real)overcharge_index,
0.0f,
1.0f);
real last_shield_vitality = PIN(
reference_shield_vitality - (real)overcharge_index,
0.0f,
1.0f);
boolean shield_fading = last_shield_vitality > shield_vitality;
real maximum_shield_vitality = shield_fading ?
last_shield_vitality :
shield_vitality;
real reference_time;
if (shield_vitality <= 0.0f &&
maximum_shield_vitality <= 0.0f)
{
break;
}
overcharge_meter.min_color = *overcharge_color;
overcharge_meter.max_color = *overcharge_color;
reference_time = shield_fading ? hud_state->fade_time : -1.0f;
hud_draw_meter(
local_player_index,
&hud_definition->absolute_placement,
first_meter ?
&hud_definition->shield_meter.meter :
&overcharge_meter,
(byte)PIN(
fast_ftol((real)value_scale * shield_vitality),
0,
UNSIGNED_CHAR_MAX),
(byte)PIN(
fast_ftol((real)value_scale * maximum_shield_vitality),
0,
UNSIGNED_CHAR_MAX),
draw_flags,
reference_time,
shield_vitality);
}
}
}
if (hud_definition->shield_meter.background.interface_bitmap.index != NONE)
{
hud_draw_static_element(
local_player_index,
&hud_definition->absolute_placement,
&hud_definition->shield_meter.background,
draw_flags,
hud_state->last_shield_flash_time);
}
}
if (!TEST_FLAG(
unit_hud_globals->script_flags,
_hud_panel_health_dont_show_bit))
{
short draw_flags =
TEST_FLAG(
hud_unit->object.damage_flags,
_object_shield_depleted_bit) ||
TEST_FLAG(
unit_hud_globals->script_flags,
_hud_panel_health_blink_bit);
SET_FLAG(
draw_flags,
_hud_draw_disabled_bit,
TEST_FLAG(hud_unit->object.damage_flags, _object_dead_bit));
SET_FLAG(
draw_flags,
_hud_draw_in_multiplayer_bit,
local_player_count() > 1);
if (unit_count == 0)
{
if (TEST_FLAG(draw_flags, _hud_draw_flashing_bit))
{
if (hud_state->last_health_flash_time == NONE)
hud_state->last_health_flash_time = game_time_get();
}
else
{
hud_state->last_health_flash_time = NONE;
}
}
if (hud_definition->health_meter.meter.meter_bitmap.index != NONE)
{
short value_scale = hud_definition->health_meter.meter.value_scale ?
hud_definition->health_meter.meter.value_scale :
8;
struct meter_hud_element_definition health_meter =
hud_definition->health_meter.meter;
if (hud_unit->object.body_vitality >=
hud_definition->health_meter.health_extras.max_cutoff)
{
health_meter.min_color = health_meter.max_color;
}
else if (hud_unit->object.body_vitality <=
hud_definition->health_meter.health_extras.min_cutoff)
{
health_meter.max_color = health_meter.min_color;
}
else
{
health_meter.max_color =
hud_definition->health_meter.health_extras.mid_color;
health_meter.min_color = health_meter.max_color;
}
hud_draw_meter(
local_player_index,
&hud_definition->absolute_placement,
&health_meter,
(byte)PIN(
fast_ftol_C(
(real)value_scale * hud_unit->object.body_vitality),
0,
UNSIGNED_CHAR_MAX),
(byte)PIN(
fast_ftol_C(
(real)value_scale * hud_unit->object.body_vitality),
0,
UNSIGNED_CHAR_MAX),
draw_flags,
-1.0f,
hud_unit->object.body_vitality);
}
if (hud_definition->health_meter.background.interface_bitmap.index != NONE)
{
hud_draw_static_element(
local_player_index,
&hud_definition->absolute_placement,
&hud_definition->health_meter.background,
draw_flags,
hud_state->last_health_flash_time);
}
hud_state->last_body_vitality = hud_unit->object.body_vitality;
}
if (unit_count == 0 &&
!TEST_FLAG(
unit_hud_globals->script_flags,
_hud_panel_motion_sensor_dont_show_bit) &&
game_engine_hud_draw_motion_sensor(player_index))
{
struct hud_absolute_placement_definition absolute_placement;
short draw_flags = 0;
point2d corner;
absolute_placement.corner = _hud_anchor_bottom_left;
SET_FLAG(
draw_flags,
_hud_draw_in_multiplayer_bit,
local_player_count() > 1);
SET_FLAG(
draw_flags,
_hud_draw_flashing_bit,
TEST_FLAG(
unit_hud_globals->script_flags,
_hud_panel_motion_sensor_blink_bit));
if (TEST_FLAG(draw_flags, _hud_draw_flashing_bit))
{
if (hud_state->last_motion_sensor_flash_time == NONE)
hud_state->last_motion_sensor_flash_time = game_time_get();
}
else
{
hud_state->last_motion_sensor_flash_time = NONE;
}
if (hud_definition->motion_sensor.background.interface_bitmap.index != NONE)
{
hud_draw_static_element(
local_player_index,
&absolute_placement,
&hud_definition->motion_sensor.background,
draw_flags,
NONE);
}
if (hud_definition->motion_sensor.foreground.interface_bitmap.index != NONE)
{
hud_draw_static_element(
local_player_index,
&absolute_placement,
&hud_definition->motion_sensor.foreground,
draw_flags,
NONE);
}
hud_calculate_point(
local_player_index,
&absolute_placement,
&hud_definition->blip_placement,
NULL,
local_player_count() > 1,
0.0f,
&corner);
motion_sensor_draw_screen(
local_player_index,
local_player_count() > 1,
&corner);
}
{
struct auxilary_panel_definition *auxilary_panel = &hud_definition->auxilary_panel;
word overlay_type_flags = game_engine_has_teams() != FALSE;
short draw_flags = 0;
short overlay_index;
SET_FLAG(
draw_flags,
_hud_draw_in_multiplayer_bit,
local_player_count() > 1);
for (overlay_index = 0;
overlay_index < auxilary_panel->auxilary_overlays.count;
overlay_index++)
{
struct auxilary_overlay_definition *overlay = TAG_BLOCK_GET_ELEMENT(
&auxilary_panel->auxilary_overlays,
overlay_index,
struct auxilary_overlay_definition);
if (TEST_FLAG(overlay_type_flags, overlay->type))
{
if (TEST_FLAG(
overlay->flags,
_auxilary_overlay_use_team_color_bit))
{
overlay->static_element.colors.color =
real_rgb_color_to_pixel32(
&hud_unit->object.base_change_colors[0]) |
0xFF000000;
}
hud_draw_static_element(
local_player_index,
&auxilary_panel->absolute_placement,
&overlay->static_element,
draw_flags,
NONE);
}
}
}
{
short meter_index;
for (meter_index = 0;
meter_index < hud_definition->auxilary_meters.count;
meter_index++)
{
struct auxilary_meter_definition *meter = TAG_BLOCK_GET_ELEMENT(
&hud_definition->auxilary_meters,
meter_index,
struct auxilary_meter_definition);
/* port: the type is the map's and indexes the flash times
and values (one type, the integrated light, which every
retail meter is): a meter of any other is not drawn, and
that is said once */
if (!VALID_INDEX(meter->type, (short)NUMBEROF(hud_state->auxilary_flash_time)))
{
static boolean bad_meter_type_reported = FALSE;
if (!bad_meter_type_reported)
{
bad_meter_type_reported = TRUE;
error(
_error_silent,
"unit hud auxilary meter of type %d (of %d) not drawn",
meter->type,
(short)NUMBEROF(hud_state->auxilary_flash_time));
}
continue;
}
if (TEST_FLAG(
hud_state->auxilary_active_type_flags,
meter->type) &&
!TEST_FLAG(auxilary_flags, meter->type))
{
hud_state->auxilary_flash_time[meter->type] = NONE;
}
if (TEST_FLAG(auxilary_flags, meter->type))
{
long background_bitmap_index = verify_tag_reference(
&meter->panel.background.interface_bitmap);
long meter_bitmap_index = verify_tag_reference(
&meter->panel.meter.meter_bitmap);
short draw_flags = 0;
SET_FLAG(
draw_flags,
_hud_draw_in_multiplayer_bit,
local_player_count() > 1);
SET_FLAG(
draw_flags,
_hud_draw_flashing_bit,
auxilary_values[meter->type] <=
meter->panel.aux_extras.min_cutoff);
hud_state->auxilary_flash_time[meter->type] += game_time_get_elapsed();
hud_state->auxilary_flash_time[meter->type] %= 2 * get_flash_duration(
&meter->panel.background.colors);
if (background_bitmap_index != NONE)
{
hud_draw_static_element(
local_player_index,
&hud_definition->absolute_placement,
&meter->panel.background,
draw_flags,
game_time_get() - hud_state->auxilary_flash_time[meter->type]);
}
if (meter_bitmap_index != NONE)
{
real value_scale = (real)meter->panel.meter.value_scale;
hud_draw_meter(
local_player_index,
&hud_definition->absolute_placement,
&meter->panel.meter,
(byte)PIN(
fast_ftol(value_scale * auxilary_values[meter->type]),
0,
UNSIGNED_CHAR_MAX),
(byte)PIN(
fast_ftol(value_scale * auxilary_values[meter->type]),
0,
UNSIGNED_CHAR_MAX),
draw_flags,
-1.0f,
auxilary_values[meter->type]);
}
}
else if (TEST_FLAG(
aux_activated_when_disabled_flags,
meter->type) ||
(hud_state->auxilary_flash_time[meter->type] != NONE &&
hud_state->auxilary_flash_time[meter->type] <
get_flash_duration(&meter->panel.background.colors)))
{
long background_bitmap_index = verify_tag_reference(
&meter->panel.background.interface_bitmap);
short draw_flags = 0;
SET_FLAG(
draw_flags,
_hud_draw_in_multiplayer_bit,
local_player_count() > 1);
SET_FLAG(
draw_flags,
_hud_draw_flashing_bit,
TRUE);
hud_state->auxilary_flash_time[meter->type] += game_time_get_elapsed();
if (background_bitmap_index != NONE)
{
hud_draw_static_element(
local_player_index,
&hud_definition->absolute_placement,
&meter->panel.background,
draw_flags,
game_time_get() - hud_state->auxilary_flash_time[meter->type]);
}
}
else
{
hud_state->auxilary_flash_time[meter->type] = NONE;
}
}
}
hud_state->auxilary_active_type_flags = (word)auxilary_flags;
}
}
}
match_assert_stack_frame("c:\\halo\\SOURCE\\interface\\hud_unit.c", 0x3C9);
return;
}