feat: 360-degree omni marking option
- omni_mark: full-sphere sweep (linear_sphere_sweep capsule covering max_range around the player) replaces the forward-only ping raycast, so enemies behind you / off-screen become mark candidates - omni_mark_ignore_los: optional sub-toggle, skips line-of-sight checks entirely - prefer nearest unit on score ties (sweep hit order is arbitrary) - bypass FOV dot gate in is_target_pingable when omni_mark is on - LOS check budget 10 -> 16 per frame
This commit is contained in:
@@ -53,13 +53,14 @@ local INDEX_NORMAL = 3
|
||||
local INDEX_ACTOR = 4
|
||||
local COLLISION_FILTER = "filter_player_ping_target_selection"
|
||||
local EMPTY_TABLE = {}
|
||||
local MAX_VISIBILITY_CHECKS_PER_FRAME = 10
|
||||
local MAX_VISIBILITY_CHECKS_PER_FRAME = 16
|
||||
local VIEW_CHECK_MIN_DISTANCE = 3
|
||||
local VIEW_CHECK_MIN_DOT = 0.75
|
||||
local AIM_CHECK_FILTER = "filter_player_ping_target_selection"
|
||||
local AIM_CHECK_MAX_HITS = 64
|
||||
local AIM_CHECK_MIN_RADIUS = 1
|
||||
local AIM_CHECK_RADIUS_PER_METER = 0.052
|
||||
local OMNI_MAX_HITS = 128
|
||||
|
||||
-- Params
|
||||
local visibility_raycast_object = nil
|
||||
@@ -524,7 +525,7 @@ function mod:is_target_pingable(target_unit)
|
||||
local forward = Vector3_flat(Quaternion_forward(first_person_component.rotation))
|
||||
local dot = Vector3_dot(Vector3_normalize(forward), Vector3_normalize(to_target))
|
||||
if dot < VIEW_CHECK_MIN_DOT then
|
||||
return false
|
||||
return mod_settings.omni_mark == true
|
||||
end
|
||||
|
||||
local first_person_extension = ScriptUnit_extension(player_unit, "first_person_system")
|
||||
@@ -578,9 +579,16 @@ function mod:find_auto_mark_target_unit(min_range, max_range, tag_name, tag_cont
|
||||
return
|
||||
end
|
||||
|
||||
-- raycast for hit unit list
|
||||
-- hit unit list: forward raycast, or full-sphere sweep when omni mark is enabled
|
||||
local omni_mark = mod_settings.omni_mark
|
||||
local ray_origin, forward, right, up = smart_targeting_extension:_targeting_parameters()
|
||||
local hits, num_hits = PhysicsWorld_raycast(smart_targeting_extension._physics_world, ray_origin, forward, max_range, "all", "collision_filter", COLLISION_FILTER)
|
||||
local hits, num_hits, hits_use_actor
|
||||
if omni_mark then
|
||||
hits, num_hits = PhysicsWorld_linear_sphere_sweep(smart_targeting_extension._physics_world, ray_origin, ray_origin + forward * max_range, max_range, OMNI_MAX_HITS, "types", "both", "collision_filter", COLLISION_FILTER, "report_initial_overlap", true)
|
||||
hits_use_actor = true
|
||||
else
|
||||
hits, num_hits = PhysicsWorld_raycast(smart_targeting_extension._physics_world, ray_origin, forward, max_range, "all", "collision_filter", COLLISION_FILTER)
|
||||
end
|
||||
|
||||
if not hits or num_hits <= 0 then
|
||||
return
|
||||
@@ -624,9 +632,11 @@ function mod:find_auto_mark_target_unit(min_range, max_range, tag_name, tag_cont
|
||||
local best_unit_is_dormant_daemonhost = false
|
||||
local best_unit_marked_by_execution_order = false
|
||||
local best_unit_is_sticky_targeting = false
|
||||
local best_unit_distance = math.huge
|
||||
local marked_unit = marked_tag and marked_tag._target_unit
|
||||
if marked_unit then
|
||||
best_unit = marked_unit
|
||||
best_unit_distance = Vector3_length(Unit_world_position(best_unit, 1) - ray_origin)
|
||||
local best_unit_data_extension = ScriptUnit_extension(best_unit, "unit_data_system")
|
||||
local best_unit_breed_data = best_unit_data_extension and best_unit_data_extension._breed
|
||||
best_unit_breed_name = best_unit_breed_data and best_unit_breed_data.name
|
||||
@@ -640,7 +650,7 @@ function mod:find_auto_mark_target_unit(min_range, max_range, tag_name, tag_cont
|
||||
|
||||
for i = 1, num_hits do
|
||||
local hit = hits[i]
|
||||
local hit_actor = hit[INDEX_ACTOR]
|
||||
local hit_actor = hits_use_actor and hit.actor or hit[INDEX_ACTOR]
|
||||
if not hit_actor then
|
||||
goto continue
|
||||
end
|
||||
@@ -695,7 +705,7 @@ function mod:find_auto_mark_target_unit(min_range, max_range, tag_name, tag_cont
|
||||
best_unit_score = best_unit_score + (best_unit_is_attacking_player and 100 or 0)
|
||||
end
|
||||
|
||||
if hit_unit_score <= best_unit_score then
|
||||
if hit_unit_score < best_unit_score then
|
||||
goto continue
|
||||
end
|
||||
|
||||
@@ -707,6 +717,11 @@ function mod:find_auto_mark_target_unit(min_range, max_range, tag_name, tag_cont
|
||||
goto continue
|
||||
end
|
||||
|
||||
-- prefer the closer unit on score ties (hit order is arbitrary for the omni sweep)
|
||||
if hit_unit_score == best_unit_score and distance >= best_unit_distance then
|
||||
goto continue
|
||||
end
|
||||
|
||||
local hit_unit_tag = smart_tag_system:unit_tag(hit_unit)
|
||||
if tag_name == TAG_NAMES.ENEMY_TAG then
|
||||
if hit_unit_tag then
|
||||
@@ -733,7 +748,9 @@ function mod:find_auto_mark_target_unit(min_range, max_range, tag_name, tag_cont
|
||||
end
|
||||
|
||||
local visible
|
||||
if tag_name == TAG_NAMES.SERVO_SKULL_TAG then
|
||||
if omni_mark and mod_settings.omni_mark_ignore_los then
|
||||
visible = true
|
||||
elseif tag_name == TAG_NAMES.SERVO_SKULL_TAG then
|
||||
visible = is_servo_skull_target_visible(companion_position, hit_unit, fixed_frame)
|
||||
elseif tag_name == TAG_NAMES.COMPANION_TAG then
|
||||
local half_height = Breed_height(hit_unit, hit_unit_breed_data) * 0.5
|
||||
@@ -755,6 +772,7 @@ function mod:find_auto_mark_target_unit(min_range, max_range, tag_name, tag_cont
|
||||
best_unit_is_dormant_daemonhost = hit_unit_is_dormant_daemonhost
|
||||
best_unit_marked_by_execution_order = hit_unit_marked_by_execution_order
|
||||
best_unit_is_sticky_targeting = false
|
||||
best_unit_distance = distance
|
||||
|
||||
::continue::
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user