mirror of
https://github.com/astromaddie/HaloCE-VR.git
synced 2026-10-22 20:00:15 +02:00
Lane B wave 1: six strict-exact functions (+2,727 meaningful / +2,784 padded)
New strict exact (unit :: function, padded bytes, relocations): game/aim_assist :: _local_player_aim_assist 368 12 game/game_engine_king :: _king_calculate_hill_state 448 32 units/unit_dialogue :: _unit_describe_speech 272 units/unit_dialogue :: _unit_make_damage_sound 784 units/biped_limp_noodle:: _biped_limp_noodle_relax_nodes_onto_environment 256 units/vehicles :: _create_ghost_effect 656 game_engine_king is now 29/29 on the function board (object NOT admitted: its .bss naming is owner-held and its .data is blocked, see below). Evidence per function: - _local_player_aim_assist: the later Win32 /Od build (halo_cache_symbols.exe fn 0x589420) and its RTC descriptor attest, independently of any compile, the result local initialised first with ONE return, the nested player_control_get_zoom_level argument, the real subtract_vectors3d call with RTC names velocity/target_velocity/magnetism_velocity, and two STORED pointer locals. /Od neither invents locals nor inlines. Closed on the first compile after the evidence; every element strip-tested alone -> residual. - _king_calculate_hill_state: the LAW Z negative-set member. January has ONE hill_controlled_count == HILL_CONTROL_TIME test at the bottom, not three; the team arm counts red/blue with the uncontrolled arm in the middle; each arm owns its data_iterator. That restores the two missing _king_globals references and January's pinned zero register with no zero-store steering. - _unit_describe_speech: the one board function whose loop differs by pure shape (January top-tested). A done-flag `while (!done)` loop, the Marathon idiom. - _unit_make_damage_sound: single-exit law (January 1 ret, ours had 2); the body is guarded by dialogue_index != NONE instead of an early return. - _biped_limp_noodle_relax_nodes_onto_environment: accessor-binding law - the object_get() result is bound to a local (non-destructive lea), as January does. - _create_ghost_effect: the marker count is TWO shorts summed in the loop test (hover_marker_count from the call, jet_marker_count = 0). First-party attestation: the later unoptimised debug build (halo_cache_symbols.exe fn 0x8f5530) stores the call result to one short, zero-initialises a SECOND short, then marker_index, and its loop test is movsx idx / movsx a / movsx b / add / cmp; the sibling create_pelican_effect (0x8f5c90) has the same three slots with the second one counting "jet thrusters". January's store order (`mov [ebp-4],0` then the call result) is exactly that. The zero-valued local is therefore an attested source variable, not a steering dummy; without it the body is the old residual. Flagged in the handoff for owner awareness. Zero-credit riders in the same files (no credit claimed): - vehicles.c _update_alien_fighter_physics_new: credible restructure with scoped blocks and real names; still residual [relocs 33!=32, sha]. The reviewer measured `real const` thrust locals as byte-neutral, so the plain literals land. - game_engine_king.c: adds the MISSING `struct game_engine king_engine` table (declared in the header, referenced from game_engine_list.c, defined nowhere). 136 bytes, 0 content bytes differ from January, 23/23 relocations identical. objdiff still scores the section <100%: January leaves the "king" literal undefined in this object and `$`-literal relocations match only by combined address (same cause as race_engine). Correct source, zero data credit. Config: config/parked.json - four entries REMOVED (now exact): _king_calculate_hill_state, _biped_limp_noodle_relax_nodes_onto_environment, _unit_describe_speech, _unit_make_damage_sound. Parks 184 -> 180, 0 stale, 0 invalid. No header, symbols.json, flag, tool or semantic-override change. Verification: full ninja all_source progress semantic_progress pass (Code 1443979 -> 1446706, 7291 -> 7297 functions). stable_verdicts vs the frozen baseline: gained 6 / 2784 bytes, regressions 0. Row diff of all 11,060 function and 1,706 section report rows: 0 rows lost 100%. Admission audit 19/0/8/0. _point_from_line3d guard, ownership (newly defined symbols vs January) and fake_match_scan: clean on every changed file. git diff --check clean. Reviewer: an independent adversarial agent re-gated every candidate from scratch and returned ACCEPT_EXACT for all six; orchestrator re-verified. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
7583df5d62
commit
01e16607f0
6 files changed
+310
-304
No files matched your search
@@ -1308,25 +1308,6 @@
|
||||
"objdiff_percent": 93.7518
|
||||
}
|
||||
},
|
||||
{
|
||||
"unit": "source/game/game_engine_king",
|
||||
"function": "_king_calculate_hill_state",
|
||||
"class": "unclassified",
|
||||
"evidence": "Fuzzy-parked under the current house rule after reconstructing the complete team and free-for-all hill-control state machine in ordinary typed C from January disassembly and independent HaloCEA behavior. The retained function iterates player_data through the normal data iterator, uses the authenticated king_hill_state and multiplayer-sound enums, preserves the previous-controller rule, and updates the control timer without optimizer-only carriers. Target and candidate share the 448-byte padded envelope; target has 32 relocations and the candidate 30, while objdiff reports 81.507355 percent similarity. Fable's bounded experiments covered count declaration scope, local state consolidation, early-return and shared-tail forms; none produced a lawful easy closure, and alignment-aware disassembly still shows broad control-flow and register-allocation differences. The fail-closed classifier returns UNKNOWN, so the honest class is unclassified. No volatile/register forcing, barrier, pragma, assembly, fake dependency, raw datum cast, invented address name, forced inline, or nonsensical branch is retained. Reopen only for authoritative January source/local records or a natural compatible-compiler donor that explains the two missing relocation sites and branch schedule.",
|
||||
"measurements": {
|
||||
"target": {
|
||||
"size": 448,
|
||||
"relocation_count": 32,
|
||||
"normalized_sha256": "9c852f781c6a691a41f7c445091bea59a0738ebd49fd6ec16add6961cedb8817"
|
||||
},
|
||||
"base": {
|
||||
"size": 448,
|
||||
"relocation_count": 30,
|
||||
"normalized_sha256": "e9d7a30d3245b8ffd0d72b1271a341f0dd5b20ddd94e9029876f4676c5ed9ae3"
|
||||
},
|
||||
"objdiff_percent": 81.507355
|
||||
}
|
||||
},
|
||||
{
|
||||
"unit": "source/game/game_engine_race",
|
||||
"function": "_race_engine_get_score",
|
||||
@@ -1479,25 +1460,6 @@
|
||||
"objdiff_percent": 87.124596
|
||||
}
|
||||
},
|
||||
{
|
||||
"unit": "source/units/biped_limp_noodle",
|
||||
"function": "_biped_limp_noodle_relax_nodes_onto_environment",
|
||||
"class": "unclassified",
|
||||
"evidence": "Fuzzy-parked after reconstructing the typed public relaxation wrapper from January disassembly and independent HCEA behavior. The retained ordinary C obtains the biped node-matrix block through the object-header API, snapshots every animation node position, invokes the reconstructed solver and exact orientation pass, saturates the iteration byte at CHAR_MAX, and returns whether relaxation was already complete. Target is 256 padded bytes and the candidate 240, with the same ordered nine-entry relocation target/type sequence although some relocation addresses drift; objdiff reports 89.82417 percent. At +0x1E January calls tag_get immediately, while VC7 first spills the biped pointer to [ebp-0x10], changing later register and loop allocation without changing the call topology. No register hint, volatile access, barrier, pragma, assembly, raw offset, false alias, fake dependency, forced inline, or nonsensical control flow is retained. Reopen only for authoritative January source/local records, a natural same-compiler donor explaining the pointer lifetime, or a source-authentic semantic correction.",
|
||||
"measurements": {
|
||||
"target": {
|
||||
"size": 256,
|
||||
"relocation_count": 9,
|
||||
"normalized_sha256": "19128c623c5575500437c95cdfd0363c69fcbfdbf57f7972bbdcf1d2dffaf84f"
|
||||
},
|
||||
"base": {
|
||||
"size": 240,
|
||||
"relocation_count": 9,
|
||||
"normalized_sha256": "d1b5db56b26dff8d5d6bafeeae5e1c0e202e19464ab0bf3dec48bea5e1e7ce18"
|
||||
},
|
||||
"objdiff_percent": 89.82417
|
||||
}
|
||||
},
|
||||
{
|
||||
"unit": "source/networking/network_connection",
|
||||
"function": "_network_connection_connect",
|
||||
@@ -2938,28 +2900,6 @@
|
||||
"objdiff_percent": 89.36364
|
||||
}
|
||||
},
|
||||
{
|
||||
"unit": "source/units/unit_dialogue",
|
||||
"function": "_unit_describe_speech",
|
||||
"class": "unclassified",
|
||||
"evidence": "Complete January-authoritative, HCEA-cross-checked speech-description reconstruction retained from the 2026-09-12 packet. Target and candidate share the 272-byte extent and all 15 relocation identities but remain normalized-code residuals. The natural typed body receives zero credit and no register or branch-layout steering is admitted. See docs/object_matching_logs/unit_dialogue_obj_unwritten_speech_packet_20260912.md.",
|
||||
"measurements": {
|
||||
"target": { "size": 272, "relocation_count": 15, "normalized_sha256": "7d9ee7e3b923460ae26a00c0612904b3106b6ed95c8c0491504d017841c1dc9c" },
|
||||
"base": { "size": 272, "relocation_count": 15, "normalized_sha256": "2b01a81debf36cda38bd965419e48997b2a2bbeac2dd4041f6752591f481edaf" },
|
||||
"objdiff_percent": 97.22727
|
||||
}
|
||||
},
|
||||
{
|
||||
"unit": "source/units/unit_dialogue",
|
||||
"function": "_unit_make_damage_sound",
|
||||
"class": "unclassified",
|
||||
"evidence": "Complete January-authoritative, HCEA-cross-checked damage/death vocalization reconstruction retained from the 2026-09-12 packet. Target and candidate share the 784-byte extent and all 18 relocation identities, including January-only wounded-sound suppression, but remain normalized-code residuals. The natural typed body receives zero credit and no codegen pressure is admitted. See docs/object_matching_logs/unit_dialogue_obj_unwritten_speech_packet_20260912.md.",
|
||||
"measurements": {
|
||||
"target": { "size": 784, "relocation_count": 18, "normalized_sha256": "87952366bca787dc5174221b78335b6a9e91770433b8d76266bdb21d1bf65975" },
|
||||
"base": { "size": 784, "relocation_count": 18, "normalized_sha256": "a72cd2b9285abc4fe3ed3a8f4de6c0606fe474c9e01a1049e16b3285f1497f01" },
|
||||
"objdiff_percent": 81.60833
|
||||
}
|
||||
},
|
||||
{
|
||||
"unit": "source/hs/hs_runtime",
|
||||
"function": "_render_debug_trigger_volumes",
|
||||
|
||||
+21
-15
@@ -559,6 +559,7 @@ long local_player_aim_assist(
|
||||
real_euler_angles2d *target_angular_position,
|
||||
real_euler_angles2d *target_angular_velocity)
|
||||
{
|
||||
long target_index= NONE;
|
||||
director_perspective perspective= director_get_perspective(local_player_index);
|
||||
|
||||
*autoaim_level= 0.f;
|
||||
@@ -570,39 +571,44 @@ long local_player_aim_assist(
|
||||
{
|
||||
struct player_datum *player= player_get(local_player_get_player_index(local_player_index));
|
||||
long aiming_unit_index= unit_get_aiming_unit_index(player->unit_index);
|
||||
short zoom_level= player_control_get_zoom_level(local_player_index);
|
||||
struct aim_assist_parameters parameters;
|
||||
|
||||
if (unit_get_aim_assist_parameters(aiming_unit_index, zoom_level, ¶meters))
|
||||
if (unit_get_aim_assist_parameters(aiming_unit_index, player_control_get_zoom_level(local_player_index), ¶meters))
|
||||
{
|
||||
struct observer_result const *camera= observer_get_camera(local_player_index);
|
||||
struct aim_assist_target target;
|
||||
|
||||
if (aim_assist(¶meters, &camera->position, &camera->forward, aiming_unit_index, player->team_index, &target))
|
||||
{
|
||||
real_vector3d aiming_velocity, target_velocity, relative_velocity;
|
||||
real horizontal_distance_squared, horizontal_distance;
|
||||
real_vector3d velocity, target_velocity, magnetism_velocity;
|
||||
|
||||
*autoaim_level= target.autoaim_level;
|
||||
*magnetism_level= target.magnetism_level;
|
||||
euler_angles2d_from_vector3d(target_angular_position, &target.vector);
|
||||
|
||||
object_get_velocities(player->unit_index, &aiming_velocity, NULL);
|
||||
object_get_velocities(player->unit_index, &velocity, NULL);
|
||||
object_get_velocities(target.object_index, &target_velocity, NULL);
|
||||
subtract_vectors3d(&target_velocity, &velocity, &magnetism_velocity);
|
||||
|
||||
subtract_vectors3d(&target_velocity, &aiming_velocity, &relative_velocity);
|
||||
horizontal_distance_squared= target.vector.i*target.vector.i + target.vector.j*target.vector.j;
|
||||
horizontal_distance= square_root(horizontal_distance_squared);
|
||||
target_angular_velocity->yaw= (target.vector.i*relative_velocity.j - target.vector.j*relative_velocity.i) /
|
||||
horizontal_distance_squared;
|
||||
target_angular_velocity->pitch= (relative_velocity.k*horizontal_distance -
|
||||
(target.vector.i*relative_velocity.i + target.vector.j*relative_velocity.j)/horizontal_distance*target.vector.k) /
|
||||
(target.vector.k*target.vector.k + horizontal_distance_squared);
|
||||
{
|
||||
real_vector3d const *relative_position= &target.vector;
|
||||
real_vector3d const *relative_velocity= &magnetism_velocity;
|
||||
real horizontal_distance_squared= relative_position->i*relative_position->i +
|
||||
relative_position->j*relative_position->j;
|
||||
real horizontal_distance= square_root(horizontal_distance_squared);
|
||||
|
||||
return target.object_index;
|
||||
target_angular_velocity->yaw= (relative_position->i*relative_velocity->j -
|
||||
relative_position->j*relative_velocity->i)/horizontal_distance_squared;
|
||||
target_angular_velocity->pitch= (horizontal_distance*relative_velocity->k -
|
||||
relative_position->k/horizontal_distance*(relative_position->i*relative_velocity->i +
|
||||
relative_position->j*relative_velocity->j))/(relative_position->k*relative_position->k +
|
||||
horizontal_distance_squared);
|
||||
}
|
||||
|
||||
target_index= target.object_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NONE;
|
||||
return target_index;
|
||||
}
|
||||
@@ -847,6 +847,46 @@ void king_engine_update(
|
||||
return;
|
||||
}
|
||||
|
||||
/* ---------- engine table */
|
||||
|
||||
struct game_engine king_engine =
|
||||
{
|
||||
"king",
|
||||
game_engine_king,
|
||||
king_engine_dispose,
|
||||
king_engine_initialize_for_new_map,
|
||||
king_engine_dispose_from_old_map,
|
||||
king_engine_player_added,
|
||||
king_engine_game_ending,
|
||||
king_engine_game_starting,
|
||||
king_engine_statistics_append,
|
||||
king_engine_handle_client_message,
|
||||
king_engine_handle_server_message,
|
||||
king_engine_pregame_post_rasterize,
|
||||
king_engine_post_rasterize,
|
||||
king_engine_player_update,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
king_engine_update,
|
||||
king_get_score,
|
||||
king_get_score_string,
|
||||
king_get_score_header_string,
|
||||
king_get_team_score_string,
|
||||
NULL,
|
||||
king_engine_player_damaged_player,
|
||||
king_engine_player_killed_player,
|
||||
king_engine_display_score,
|
||||
NULL,
|
||||
king_engine_prespawn_player_update,
|
||||
NULL,
|
||||
NULL,
|
||||
king_engine_goal_matches_player,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
/* ---------- private code */
|
||||
|
||||
static void hill_points_to_2d(
|
||||
@@ -982,31 +1022,31 @@ static boolean player_inside_hill(
|
||||
static void king_calculate_hill_state(
|
||||
void)
|
||||
{
|
||||
struct data_iterator iterator;
|
||||
struct player_datum *player;
|
||||
long player_count = 0;
|
||||
|
||||
if (game_engine_has_teams())
|
||||
{
|
||||
long enemy_count = 0;
|
||||
struct data_iterator player_iterator;
|
||||
long red_count = 0;
|
||||
long blue_count = 0;
|
||||
|
||||
data_iterator_new(&iterator, player_data);
|
||||
player = (struct player_datum *)data_iterator_next(&iterator);
|
||||
data_iterator_new(&player_iterator, player_data);
|
||||
player = (struct player_datum *)data_iterator_next(&player_iterator);
|
||||
while (player)
|
||||
{
|
||||
if (king_globals.on_the_hill[DATUM_INDEX_TO_ABSOLUTE_INDEX(iterator.datum_index)])
|
||||
if (king_globals.on_the_hill[DATUM_INDEX_TO_ABSOLUTE_INDEX(player_iterator.datum_index)])
|
||||
{
|
||||
if (player->team_index)
|
||||
enemy_count++;
|
||||
blue_count++;
|
||||
else
|
||||
player_count++;
|
||||
red_count++;
|
||||
}
|
||||
player = (struct player_datum *)data_iterator_next(&iterator);
|
||||
player = (struct player_datum *)data_iterator_next(&player_iterator);
|
||||
}
|
||||
|
||||
if (enemy_count)
|
||||
if (blue_count)
|
||||
{
|
||||
if (player_count)
|
||||
if (red_count)
|
||||
{
|
||||
king_globals.hill_state = king_hill_contested;
|
||||
if (king_globals.hill_controlled_count > HILL_CONTROL_TIME)
|
||||
@@ -1020,40 +1060,38 @@ static void king_calculate_hill_state(
|
||||
else
|
||||
king_globals.hill_controlled_count = 0;
|
||||
king_globals.hill_state = king_hill_controlled_blue;
|
||||
if (king_globals.hill_controlled_count == HILL_CONTROL_TIME)
|
||||
game_engine_play_multiplayer_sound(_multiplayer_sound_hill_controlled);
|
||||
}
|
||||
}
|
||||
else if (player_count)
|
||||
else if (!red_count)
|
||||
{
|
||||
king_globals.hill_state = king_hill_uncontrolled;
|
||||
king_globals.hill_controlled_count = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (king_globals.hill_state == king_hill_controlled_red)
|
||||
king_globals.hill_controlled_count++;
|
||||
else
|
||||
king_globals.hill_controlled_count = 0;
|
||||
king_globals.hill_state = king_hill_controlled_red;
|
||||
if (king_globals.hill_controlled_count == HILL_CONTROL_TIME)
|
||||
game_engine_play_multiplayer_sound(_multiplayer_sound_hill_controlled);
|
||||
}
|
||||
else
|
||||
{
|
||||
king_globals.hill_state = king_hill_uncontrolled;
|
||||
king_globals.hill_controlled_count = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
struct data_iterator player_iterator;
|
||||
long player_count = 0;
|
||||
long controller;
|
||||
|
||||
data_iterator_new(&iterator, player_data);
|
||||
player = (struct player_datum *)data_iterator_next(&iterator);
|
||||
data_iterator_new(&player_iterator, player_data);
|
||||
player = (struct player_datum *)data_iterator_next(&player_iterator);
|
||||
while (player)
|
||||
{
|
||||
if (king_globals.on_the_hill[DATUM_INDEX_TO_ABSOLUTE_INDEX(iterator.datum_index)])
|
||||
if (king_globals.on_the_hill[DATUM_INDEX_TO_ABSOLUTE_INDEX(player_iterator.datum_index)])
|
||||
{
|
||||
controller = iterator.datum_index;
|
||||
controller = player_iterator.datum_index;
|
||||
player_count++;
|
||||
}
|
||||
player = (struct player_datum *)data_iterator_next(&iterator);
|
||||
player = (struct player_datum *)data_iterator_next(&player_iterator);
|
||||
}
|
||||
|
||||
if (player_count > 1)
|
||||
@@ -1077,17 +1115,18 @@ static void king_calculate_hill_state(
|
||||
king_globals.hill_previous_controller = controller;
|
||||
}
|
||||
king_globals.hill_state = king_hill_controlled;
|
||||
if (king_globals.hill_controlled_count == HILL_CONTROL_TIME)
|
||||
game_engine_play_multiplayer_sound(_multiplayer_sound_hill_controlled);
|
||||
}
|
||||
else
|
||||
{
|
||||
king_globals.hill_previous_controller = NONE;
|
||||
king_globals.hill_state = king_hill_uncontrolled;
|
||||
king_globals.hill_controlled_count = 0;
|
||||
king_globals.hill_previous_controller = NONE;
|
||||
}
|
||||
}
|
||||
|
||||
if (king_globals.hill_controlled_count == HILL_CONTROL_TIME)
|
||||
game_engine_play_multiplayer_sound(_multiplayer_sound_hill_controlled);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -722,9 +722,10 @@ boolean biped_limp_noodle_relax_nodes_onto_environment(
|
||||
struct biped_definition *definition = biped_definition_get(biped->definition_index);
|
||||
struct animation_graph *animation_graph = animation_graph_definition_get(
|
||||
definition->object.animation_graph.index);
|
||||
struct object_datum *object = object_get(biped_index);
|
||||
real_matrix4x3 *node_matrices = (real_matrix4x3 *)object_header_block_get(
|
||||
biped_index,
|
||||
&object_get(biped_index)->object.node_matrices);
|
||||
&object->object.node_matrices);
|
||||
boolean relaxation_complete =
|
||||
biped->biped.limp_body_current_relaxation_iterations >=
|
||||
biped->biped.limp_body_max_relaxation_iterations;
|
||||
|
||||
+150
-135
@@ -488,18 +488,28 @@ char const *unit_describe_speech(
|
||||
|
||||
if (abbreviated)
|
||||
{
|
||||
boolean done = FALSE;
|
||||
|
||||
scan = sound_name;
|
||||
while (TRUE)
|
||||
while (!done)
|
||||
{
|
||||
if (!scan)
|
||||
break;
|
||||
|
||||
scan = strchr(scan, '\\');
|
||||
if (!scan)
|
||||
break;
|
||||
|
||||
scan++;
|
||||
sound_name = scan;
|
||||
if (scan)
|
||||
{
|
||||
scan = strchr(scan, '\\');
|
||||
if (scan)
|
||||
{
|
||||
scan++;
|
||||
sound_name = scan;
|
||||
}
|
||||
else
|
||||
{
|
||||
done = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
done = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -725,145 +735,150 @@ boolean unit_make_damage_sound(
|
||||
|
||||
(void)shield_damage;
|
||||
|
||||
if (unit->unit.dialogue_index == NONE)
|
||||
return spoke;
|
||||
|
||||
if (unit->unit.dialogue_index != NONE)
|
||||
{
|
||||
boolean took_body_damage = unit->object.recent_body_damage > 0.f;
|
||||
boolean took_major_body_damage = unit->object.recent_body_damage >= 0.6f;
|
||||
short vocalization_type = NONE;
|
||||
short damage_category = _unit_dialogue_damage_category_none;
|
||||
short unit_effect_type = NONE;
|
||||
short unit_effect_volume = 0;
|
||||
boolean involuntary_vocalization = FALSE;
|
||||
short vocalization_type = NONE;
|
||||
short damage_category = _unit_dialogue_damage_category_none;
|
||||
boolean took_body_damage = unit->object.recent_body_damage > 0.f;
|
||||
boolean took_major_body_damage = unit->object.recent_body_damage >= 0.6f;
|
||||
short unit_effect_type = NONE;
|
||||
short unit_effect_volume = 0;
|
||||
boolean involuntary_vocalization = FALSE;
|
||||
|
||||
if (damage_data && damage_data->definition_index != NONE)
|
||||
{
|
||||
damage_category = damage_effect_definition_get(
|
||||
damage_data->definition_index)->damage.category;
|
||||
}
|
||||
|
||||
if (died)
|
||||
{
|
||||
long actor_index = unit->unit.swarm_actor_index;
|
||||
boolean instantaneous = FALSE;
|
||||
boolean severe;
|
||||
|
||||
if (actor_index == NONE)
|
||||
actor_index = unit->unit.actor_index;
|
||||
|
||||
if (damage_data->definition_index != NONE)
|
||||
if (damage_data && damage_data->definition_index != NONE)
|
||||
{
|
||||
instantaneous = damage_effect_definition_get(
|
||||
damage_data->definition_index)->damage.instantaneous_acceleration >= 2.f;
|
||||
damage_category = damage_effect_definition_get(
|
||||
damage_data->definition_index)->damage.category;
|
||||
}
|
||||
|
||||
if (actor_index != NONE)
|
||||
if (died)
|
||||
{
|
||||
severe = actor_get(actor_index)->state.combat_status >=
|
||||
_unit_dialogue_actor_combat_status_definite;
|
||||
}
|
||||
else
|
||||
{
|
||||
severe = unit->object.recent_body_damage > body_damage + 0.2f;
|
||||
}
|
||||
long actor_index = unit->unit.swarm_actor_index != NONE ?
|
||||
unit->unit.swarm_actor_index :
|
||||
unit->unit.actor_index;
|
||||
boolean severe = FALSE;
|
||||
boolean instantaneous = FALSE;
|
||||
|
||||
if (damage_category == _unit_dialogue_damage_category_falling)
|
||||
vocalization_type = _vocalization_death_falling;
|
||||
else if (damage_category == _unit_dialogue_damage_category_flame)
|
||||
vocalization_type = _vocalization_death_agonizing;
|
||||
else if (instantaneous)
|
||||
vocalization_type = _vocalization_death_flying;
|
||||
else if (severe)
|
||||
{
|
||||
vocalization_type = died_instantly ?
|
||||
_vocalization_death_instant :
|
||||
_vocalization_death_violent;
|
||||
}
|
||||
else
|
||||
{
|
||||
vocalization_type = _vocalization_death_quiet;
|
||||
}
|
||||
|
||||
involuntary_vocalization = TRUE;
|
||||
if (vocalization_type != _vocalization_death_quiet)
|
||||
{
|
||||
unit_effect_type = _unit_dialogue_ai_unit_effect_death_scream;
|
||||
unit_effect_volume = vocalization_type == _vocalization_death_instant ? 4 : 1;
|
||||
}
|
||||
}
|
||||
else if (unit->unit.speech.damage_major_timer == 0)
|
||||
{
|
||||
if (damage_category == _unit_dialogue_damage_category_falling)
|
||||
{
|
||||
involuntary_vocalization = TRUE;
|
||||
vocalization_type = _vocalization_pain_falling;
|
||||
}
|
||||
else if (took_major_body_damage)
|
||||
{
|
||||
involuntary_vocalization = TRUE;
|
||||
vocalization_type = _vocalization_pain_body_major;
|
||||
}
|
||||
else if (unit->unit.speech.damage_minor_timer == 0 &&
|
||||
unit->unit.speech.damage_minor_sounds < 3 &&
|
||||
(unit->unit.speech.current.priority == _unit_speech_none ||
|
||||
real_seed_random(get_global_random_seed_address()) < 0.4f))
|
||||
{
|
||||
vocalization_type = took_body_damage ?
|
||||
_vocalization_pain_body :
|
||||
_vocalization_pain_shield;
|
||||
}
|
||||
}
|
||||
|
||||
if (vocalization_type != NONE)
|
||||
{
|
||||
long sound_definition_index = NONE;
|
||||
short priority = died ?
|
||||
_unit_speech_death :
|
||||
(involuntary_vocalization ? _unit_speech_involuntary : _unit_speech_pain);
|
||||
short play_type = unit_test_speech(
|
||||
unit_index,
|
||||
priority,
|
||||
TRUE,
|
||||
FALSE,
|
||||
NULL,
|
||||
&vocalization_type,
|
||||
&sound_definition_index);
|
||||
|
||||
if (!ai_debug.disable_wounded_sounds &&
|
||||
play_type > _unit_play_speech_none)
|
||||
{
|
||||
struct unit_speech_item speech_item;
|
||||
|
||||
csmemset(&speech_item, 0, sizeof(speech_item));
|
||||
speech_item.priority = priority;
|
||||
speech_item.vocalization_type = vocalization_type;
|
||||
speech_item.sound_definition_index = sound_definition_index;
|
||||
speech_item.pause_time = 7;
|
||||
ai_communication_packet_new(&speech_item.ai);
|
||||
unit_speak(unit_index, play_type, &speech_item);
|
||||
spoke = TRUE;
|
||||
|
||||
if (took_major_body_damage)
|
||||
if (damage_data->definition_index != NONE)
|
||||
{
|
||||
unit->unit.speech.damage_major_timer = 60;
|
||||
instantaneous = damage_effect_definition_get(
|
||||
damage_data->definition_index)->damage.instantaneous_acceleration >= 2.f;
|
||||
}
|
||||
|
||||
if (actor_index != NONE)
|
||||
{
|
||||
struct actor_datum *actor = actor_get(actor_index);
|
||||
|
||||
severe = actor->state.combat_status >=
|
||||
_unit_dialogue_actor_combat_status_definite;
|
||||
}
|
||||
else if (unit->object.recent_body_damage > body_damage + 0.2f)
|
||||
{
|
||||
severe = TRUE;
|
||||
}
|
||||
|
||||
if (damage_category == _unit_dialogue_damage_category_falling)
|
||||
{
|
||||
vocalization_type = _vocalization_death_falling;
|
||||
}
|
||||
else if (damage_category == _unit_dialogue_damage_category_flame)
|
||||
{
|
||||
vocalization_type = _vocalization_death_agonizing;
|
||||
}
|
||||
else if (instantaneous)
|
||||
{
|
||||
vocalization_type = _vocalization_death_flying;
|
||||
}
|
||||
else if (!severe)
|
||||
{
|
||||
vocalization_type = _vocalization_death_quiet;
|
||||
}
|
||||
else
|
||||
{
|
||||
unit->unit.speech.damage_minor_sounds++;
|
||||
unit->unit.speech.damage_minor_timer = 30;
|
||||
unit->unit.speech.damage_minor_decay_timer = 22;
|
||||
vocalization_type = died_instantly ?
|
||||
_vocalization_death_instant :
|
||||
_vocalization_death_violent;
|
||||
}
|
||||
|
||||
involuntary_vocalization = TRUE;
|
||||
if (vocalization_type != _vocalization_death_quiet)
|
||||
{
|
||||
unit_effect_type = _unit_dialogue_ai_unit_effect_death_scream;
|
||||
unit_effect_volume = vocalization_type == _vocalization_death_instant ? 4 : 1;
|
||||
}
|
||||
}
|
||||
else if (unit->unit.speech.damage_major_timer == 0)
|
||||
{
|
||||
if (damage_category == _unit_dialogue_damage_category_falling)
|
||||
{
|
||||
involuntary_vocalization = TRUE;
|
||||
vocalization_type = _vocalization_pain_falling;
|
||||
}
|
||||
else if (took_major_body_damage)
|
||||
{
|
||||
involuntary_vocalization = TRUE;
|
||||
vocalization_type = _vocalization_pain_body_major;
|
||||
}
|
||||
else if (unit->unit.speech.damage_minor_timer == 0 &&
|
||||
unit->unit.speech.damage_minor_sounds < 3 &&
|
||||
(unit->unit.speech.current.priority == _unit_speech_none ||
|
||||
real_seed_random(get_global_random_seed_address()) < 0.4f))
|
||||
{
|
||||
vocalization_type = took_body_damage ?
|
||||
_vocalization_pain_body :
|
||||
_vocalization_pain_shield;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (unit_effect_type != NONE)
|
||||
{
|
||||
ai_handle_unit_effect(
|
||||
unit_index,
|
||||
unit_effect_type,
|
||||
unit_effect_volume);
|
||||
}
|
||||
if (vocalization_type != NONE)
|
||||
{
|
||||
long sound_definition_index = NONE;
|
||||
short priority = died ?
|
||||
_unit_speech_death :
|
||||
(involuntary_vocalization ? _unit_speech_involuntary : _unit_speech_pain);
|
||||
short play_type = unit_test_speech(
|
||||
unit_index,
|
||||
priority,
|
||||
TRUE,
|
||||
FALSE,
|
||||
NULL,
|
||||
&vocalization_type,
|
||||
&sound_definition_index);
|
||||
|
||||
if (!ai_debug.disable_wounded_sounds &&
|
||||
play_type > _unit_play_speech_none)
|
||||
{
|
||||
struct unit_speech_item speech_item;
|
||||
|
||||
csmemset(&speech_item, 0, sizeof(speech_item));
|
||||
speech_item.priority = priority;
|
||||
speech_item.vocalization_type = vocalization_type;
|
||||
speech_item.sound_definition_index = sound_definition_index;
|
||||
speech_item.pause_time = 7;
|
||||
ai_communication_packet_new(&speech_item.ai);
|
||||
unit_speak(unit_index, play_type, &speech_item);
|
||||
spoke = TRUE;
|
||||
|
||||
if (took_major_body_damage)
|
||||
{
|
||||
unit->unit.speech.damage_major_timer = 60;
|
||||
}
|
||||
else
|
||||
{
|
||||
unit->unit.speech.damage_minor_sounds++;
|
||||
unit->unit.speech.damage_minor_timer = 30;
|
||||
unit->unit.speech.damage_minor_decay_timer = 22;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (unit_effect_type != NONE)
|
||||
{
|
||||
ai_handle_unit_effect(
|
||||
unit_index,
|
||||
unit_effect_type,
|
||||
unit_effect_volume);
|
||||
}
|
||||
}
|
||||
|
||||
return spoke;
|
||||
|
||||
+69
-64
@@ -964,95 +964,99 @@ static void update_alien_fighter_physics_new(
|
||||
|
||||
if (physics->powered_mass_points.count==2)
|
||||
{
|
||||
real_matrix3x3 actual, desired, difference;
|
||||
real_vector3d magic_force;
|
||||
real_vector3d magic_torque;
|
||||
real_vector3d axis;
|
||||
real_vector3d thrust;
|
||||
real_vector3d scaled;
|
||||
real_vector3d force;
|
||||
real_vector3d torque;
|
||||
real throttle, average, spin, maximum;
|
||||
|
||||
scale_vector3d(&vehicle->object.forward, vehicle->vehicle.speed, &torque);
|
||||
|
||||
if (vehicle->vehicle.speed>0.0f)
|
||||
throttle = vehicle->vehicle.speed/definition->unknown2f8;
|
||||
else
|
||||
throttle = -(vehicle->vehicle.speed/definition->unknown2fc);
|
||||
|
||||
compute_acceleration(&torque, &vehicle->object.translational_velocity, &axis,
|
||||
throttle*definition->unknown300, throttle*definition->unknown304);
|
||||
|
||||
scale_vector3d(&axis, physics->mass, &thrust);
|
||||
scale_vector3d(&thrust, vehicle->unit.seat_power[0], &force);
|
||||
|
||||
matrix3x3_from_forward_and_up(&actual, &vehicle->object.forward,
|
||||
&vehicle->object.up);
|
||||
|
||||
desired.forward = vehicle->unit.desired_facing_vector;
|
||||
|
||||
point_from_line3d(global_up3d, &desired.forward, -desired.forward.k, &desired.up);
|
||||
|
||||
if (normalize3d(&desired.up)==0.0f)
|
||||
desired.up = *global_forward3d;
|
||||
|
||||
if (!unit_driven_by_ai(vehicle_index))
|
||||
pitch_vectors(&desired.forward, &desired.up, sine(definition->unknown364),
|
||||
cosine(definition->unknown364));
|
||||
real_vector3d desired_angular_velocity;
|
||||
real_vector3d angular_acceleration;
|
||||
real spin;
|
||||
real thrust_delta;
|
||||
|
||||
{
|
||||
real_vector3d desired_velocity;
|
||||
real_vector3d acceleration;
|
||||
real throttle;
|
||||
|
||||
scale_vector3d(&vehicle->object.forward, vehicle->vehicle.speed, &desired_velocity);
|
||||
|
||||
if (vehicle->vehicle.speed>0.0f)
|
||||
throttle = vehicle->vehicle.speed/definition->unknown2f8;
|
||||
else
|
||||
throttle = -(vehicle->vehicle.speed/definition->unknown2fc);
|
||||
|
||||
compute_acceleration(&desired_velocity, &vehicle->object.translational_velocity, &acceleration,
|
||||
throttle*definition->unknown300, throttle*definition->unknown304);
|
||||
|
||||
scale_vector3d(&acceleration, physics->mass, &magic_force);
|
||||
scale_vector3d(&magic_force, vehicle->unit.seat_power[0], &magic_force);
|
||||
}
|
||||
|
||||
{
|
||||
real_matrix3x3 current_rotation, desired_rotation, rotation;
|
||||
real_quaternion rotation_quaternion;
|
||||
real yaw;
|
||||
real angle;
|
||||
|
||||
angle = (desired.forward.i*vehicle->object.translational_velocity.j-
|
||||
desired.forward.j*vehicle->object.translational_velocity.i)/
|
||||
matrix3x3_from_forward_and_up(¤t_rotation, &vehicle->object.forward,
|
||||
&vehicle->object.up);
|
||||
|
||||
desired_rotation.forward = vehicle->unit.desired_facing_vector;
|
||||
|
||||
point_from_line3d(global_up3d, &desired_rotation.forward, -desired_rotation.forward.k, &desired_rotation.up);
|
||||
|
||||
if (normalize3d(&desired_rotation.up)==0.0f)
|
||||
desired_rotation.up = *global_forward3d;
|
||||
|
||||
if (!unit_driven_by_ai(vehicle_index))
|
||||
pitch_vectors(&desired_rotation.forward, &desired_rotation.up, sine(definition->unknown364),
|
||||
cosine(definition->unknown364));
|
||||
|
||||
yaw = (desired_rotation.forward.i*vehicle->object.translational_velocity.j-
|
||||
desired_rotation.forward.j*vehicle->object.translational_velocity.i)/
|
||||
definition->unknown2f8*definition->unknown308;
|
||||
|
||||
yaw_vectors(&desired.up, &desired.forward, sine(angle), cosine(angle));
|
||||
yaw_vectors(&desired_rotation.up, &desired_rotation.forward, sine(yaw), cosine(yaw));
|
||||
|
||||
cross_product3d(&desired_rotation.up, &desired_rotation.forward, &desired_rotation.left);
|
||||
|
||||
matrix3x3_transpose(¤t_rotation, ¤t_rotation);
|
||||
matrix3x3_multiply(&desired_rotation, ¤t_rotation, &rotation);
|
||||
matrix3x3_rotation_to_quaternion(&rotation, &rotation_quaternion);
|
||||
quaternion_to_angle_and_vector(&rotation_quaternion, &angle, &axis);
|
||||
scale_vector3d(&axis, (-angle)*definition->unknown314*(1.0f/_pi), &desired_angular_velocity);
|
||||
}
|
||||
|
||||
cross_product3d(&desired.up, &desired.forward, &desired.left);
|
||||
subtract_vectors3d(&desired_angular_velocity, &vehicle->object.angular_velocity, &angular_acceleration);
|
||||
|
||||
matrix3x3_transpose(&actual, &actual);
|
||||
matrix3x3_multiply(&desired, &actual, &difference);
|
||||
{
|
||||
real_quaternion rotation;
|
||||
real angle;
|
||||
|
||||
matrix3x3_rotation_to_quaternion(&difference, &rotation);
|
||||
quaternion_to_angle_and_vector(&rotation, &angle, &desired.left);
|
||||
scale_vector3d(&desired.left, (-angle)*definition->unknown314*(1.0f/_pi), &thrust);
|
||||
}
|
||||
|
||||
subtract_vectors3d(&thrust, &vehicle->object.angular_velocity, &torque);
|
||||
|
||||
average = (physics->zz_moment+physics->yy_moment+physics->xx_moment)*(1.0f/3);
|
||||
|
||||
scale_vector3d(&torque, average, &torque);
|
||||
scale_vector3d(&torque, vehicle->unit.seat_power[0], &torque);
|
||||
scale_vector3d(&angular_acceleration,
|
||||
(physics->zz_moment+physics->yy_moment+physics->xx_moment)*(1.0f/3), &magic_torque);
|
||||
scale_vector3d(&magic_torque, vehicle->unit.seat_power[0], &magic_torque);
|
||||
|
||||
spin = magnitude3d(&vehicle->object.angular_velocity)/definition->unknown314;
|
||||
|
||||
if (spin>vehicle->vehicle.thrust)
|
||||
{
|
||||
maximum = PIN((1.0f-vehicle->vehicle.thrust)*
|
||||
(1.0f-vehicle->vehicle.thrust)*0.2f, 0.01f, 0.05f);
|
||||
|
||||
vehicle->vehicle.thrust += MIN(spin-vehicle->vehicle.thrust, maximum);
|
||||
thrust_delta = PIN((1.0f-vehicle->vehicle.thrust)*
|
||||
(1.0f-vehicle->vehicle.thrust)*0.2f,
|
||||
0.01f, 0.05f);
|
||||
thrust_delta = MIN(spin-vehicle->vehicle.thrust, thrust_delta);
|
||||
}
|
||||
else
|
||||
{
|
||||
maximum = -MAX(vehicle->vehicle.thrust*vehicle->vehicle.thrust*0.05f,
|
||||
thrust_delta = -MAX(vehicle->vehicle.thrust*vehicle->vehicle.thrust*0.05f,
|
||||
0.005f);
|
||||
|
||||
vehicle->vehicle.thrust += MAX(spin-vehicle->vehicle.thrust, maximum);
|
||||
thrust_delta = MAX(spin-vehicle->vehicle.thrust, thrust_delta);
|
||||
}
|
||||
|
||||
vehicle->vehicle.thrust += thrust_delta;
|
||||
|
||||
state[0].antigrav_fraction = vehicle->unit.seat_power[0];
|
||||
state[0].rotation = *global_identity_quaternion;
|
||||
|
||||
state[1].antigrav_fraction = vehicle->unit.seat_power[0];
|
||||
state[1].rotation = *global_identity_quaternion;
|
||||
|
||||
physics_update(vehicle_index, state, mass_points, &force, &torque);
|
||||
physics_update(vehicle_index, state, mass_points, &magic_force, &magic_torque);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1245,10 +1249,11 @@ static void create_ghost_effect(
|
||||
if (definition->effect.index!=NONE && vehicle->unit.seat_power[0]>0.0f)
|
||||
{
|
||||
struct object_marker markers[16];
|
||||
long marker_count = object_get_marker_by_name(vehicle_index, "hover thrusters", markers, 15);
|
||||
short hover_marker_count = object_get_marker_by_name(vehicle_index, "hover thrusters", markers, 15);
|
||||
short jet_marker_count = 0;
|
||||
short marker_index;
|
||||
|
||||
for (marker_index = 0; marker_index<marker_count; marker_index++)
|
||||
for (marker_index = 0; marker_index<hover_marker_count+jet_marker_count; marker_index++)
|
||||
{
|
||||
struct object_marker *marker = &markers[marker_index];
|
||||
struct collision_result collision;
|
||||
|
||||
Reference in new issue
Block a user