Upstream AutoMark v2.5.3 (Shui Yu, Nexus #736) baseline

This commit is contained in:
2026-10-03 06:04:57 -04:00
commit 41a999f7d7
17 changed files with 5255 additions and 0 deletions
+683
View File
@@ -0,0 +1,683 @@
---@class AutoMarkMod:DMFMod
local mod = get_mod("AutoMark")
local breeds = require("scripts/settings/breed/breeds")
local Breed = require("scripts/utilities/breed")
-- Global Cache
local CLASS = CLASS
local ScriptUnit_extension = ScriptUnit.extension
local table_clear = table.clear
-- Smart Tag Names
---@class AutoMarkTagNames
local TAG_NAMES = {
ENEMY_TAG = "enemy_over_here",
VETERAN_TAG = "enemy_over_here_veteran",
COMPANION_TAG = "enemy_companion_target",
SERVO_SKULL_TAG = "servo_skull_enemy_companion_target",
}
mod.TAG_NAMES = TAG_NAMES
-- Mod Settings
---@class AutoMarkModSettings
local mod_settings = {
toggle_mod = mod:get("toggle_mod") or false,
toggle_mod_keybind = mod:get("toggle_mod_keybind") or {},
toggle_mod_notify = mod:get("toggle_mod_notify") or false,
debug_mode = mod:get("debug_mode") or false,
companion_mark_keybind = mod:get("companion_mark_keybind") or {},
companion_mark_ignore_unaggroed = mod:get("companion_mark_ignore_unaggroed") or false,
companion_range_limitation = mod:get("companion_range_limitation") or 0,
companion_mark_max_distance = mod:get("companion_mark_max_distance") or 0,
companion_mark_threat_priority = mod:get("companion_mark_threat_priority") or false,
execution_order_priority = mod:get("execution_order_priority") or false,
execution_order_force_mark = mod:get("execution_order_force_mark") or false,
companion_mark_tagged_always_visible = mod:get("companion_mark_tagged_always_visible") or false,
companion_mark_sticky_targeting = mod:get("companion_mark_sticky_targeting") or false,
companion_mark_sticky_targeting_elite = mod:get("companion_mark_sticky_targeting_elite") or false,
companion_mark_sticky_targeting_special = mod:get("companion_mark_sticky_targeting_special") or false,
companion_mark_sticky_targeting_boss = mod:get("companion_mark_sticky_targeting_boss") or false,
companion_cancel_mark = mod:get("companion_cancel_mark") or false,
companion_cancel_mark_human = mod:get("companion_cancel_mark_human") or false,
companion_cancel_mark_non_human = mod:get("companion_cancel_mark_non_human") or false,
companion_health_threshold = (mod:get("companion_health_threshold") or 0) / 100,
companion_time_threshold = mod:get("companion_time_threshold") or 0,
companion_distance_threshold = mod:get("companion_distance_threshold") or 0,
servo_skull_mark_keybind = mod:get("servo_skull_mark_keybind") or {},
servo_skull_mark_ignore_unaggroed = mod:get("servo_skull_mark_ignore_unaggroed") or false,
servo_skull_range_limitation = mod:get("servo_skull_range_limitation") or 0,
servo_skull_mark_threat_priority = mod:get("servo_skull_mark_threat_priority") or false,
hack_mark_keybind = mod:get("hack_mark_keybind") or {},
auto_hack = mod:get("auto_hack") or false,
disable_auto_hack_for_noospheric_command = mod:get("disable_auto_hack_for_noospheric_command") or false,
noospheric_command_boost = mod:get("noospheric_command_boost") or false,
noospheric_command_boost_elite = mod:get("noospheric_command_boost_elite") or false,
noospheric_command_boost_special = mod:get("noospheric_command_boost_special") or false,
noospheric_command_boost_boss = mod:get("noospheric_command_boost_boss") or false,
capacitance_retention = mod:get("capacitance_retention") or false,
capacitance_retention_elite_threshold = (mod:get("capacitance_retention_elite_threshold") or 0) / 100,
capacitance_retention_special_threshold = (mod:get("capacitance_retention_special_threshold") or 0) / 100,
capacitance_retention_boss_threshold = (mod:get("capacitance_retention_boss_threshold") or 0) / 100,
servo_skull_mark_sticky_targeting = mod:get("servo_skull_mark_sticky_targeting") or false,
servo_skull_mark_sticky_targeting_elite = mod:get("servo_skull_mark_sticky_targeting_elite") or false,
servo_skull_mark_sticky_targeting_special = mod:get("servo_skull_mark_sticky_targeting_special") or false,
servo_skull_mark_sticky_targeting_boss = mod:get("servo_skull_mark_sticky_targeting_boss") or false,
servo_skull_cancel_mark = mod:get("servo_skull_cancel_mark") or false,
servo_skull_cancel_mark_time_threshold = mod:get("servo_skull_cancel_mark_time_threshold") or 0,
servo_skull_cancel_mark_health_threshold = (mod:get("servo_skull_cancel_mark_health_threshold") or 0) / 100,
focus_target_overwrite = mod:get("focus_target_overwrite") or false,
focus_target_overwrite_delta = mod:get("focus_target_overwrite_delta") or 5,
focus_target_ignore_unaggroed = mod:get("focus_target_ignore_unaggroed") or false,
focus_target_switch = mod:get("focus_target_switch") or false,
focus_target_switch_override_manual = mod:get("focus_target_switch_override_manual") or false,
focus_target_switch_melee = mod:get("focus_target_switch_melee") or false,
focus_target_switch_range = mod:get("focus_target_switch_range") or false,
}
mod.settings = mod_settings
if mod:get("capacitance_retention_elite_threshold_negative_zero") then
mod_settings.capacitance_retention_elite_threshold = -0
mod:set("capacitance_retention_elite_threshold", -0, false)
end
if mod:get("capacitance_retention_special_threshold_negative_zero") then
mod_settings.capacitance_retention_special_threshold = -0
mod:set("capacitance_retention_special_threshold", -0, false)
end
if mod:get("capacitance_retention_boss_threshold_negative_zero") then
mod_settings.capacitance_retention_boss_threshold = -0
mod:set("capacitance_retention_boss_threshold", -0, false)
end
local noospheric_command_breed_settings = mod:get("noospheric_command_breed_settings") or {}
mod.noospheric_command_breed_settings = noospheric_command_breed_settings
for _, breed_settings in pairs(noospheric_command_breed_settings) do
if breed_settings.threshold_negative_zero then
breed_settings.threshold = -0
end
end
local companion_cancel_mark_breed_settings = mod:get("companion_cancel_mark_breed_settings") or {}
mod.companion_cancel_mark_breed_settings = companion_cancel_mark_breed_settings
-- Default Class Settings
---@class AutoMarkDefaultClassSettings
local DEFAULT_CLASS_SETTINGS = {
toggle_class = true,
cooldown = 25,
reset_cooldown = true,
interval = 1,
mark_limit = true,
min_range = 0,
max_range = 100,
override_manual = false,
priority_switch = false,
toggle_elite = true,
toggle_special = true,
toggle_boss = true,
toggle_other = true,
breed_priorities = {},
}
for breed_name, breed_data in pairs(breeds) do
if Breed.is_minion(breed_data) and breed_data.unit_template_name == "minion" and breed_data.smart_tag_target_type == "breed" and breed_data.faction_name ~= "imperium" then
if breed_data.tags.elite then
DEFAULT_CLASS_SETTINGS.breed_priorities[breed_name] = 0
elseif breed_data.tags.special then
DEFAULT_CLASS_SETTINGS.breed_priorities[breed_name] = 1
elseif breed_data.is_boss then
DEFAULT_CLASS_SETTINGS.breed_priorities[breed_name] = 1
if breed_data.tags.witch then
DEFAULT_CLASS_SETTINGS.breed_priorities[breed_name .. "_passive"] = 1
end
else
DEFAULT_CLASS_SETTINGS.breed_priorities[breed_name] = 1
end
end
end
mod.DEFAULT_CLASS_SETTINGS = DEFAULT_CLASS_SETTINGS
-- Context
---@class AutoMarkContext
local context = {
mod_enabled = false,
game_mode_valid = false,
player = nil,
class_name = nil,
talent_resource_component = nil,
disabled_character_state_component = nil,
locomotion_component = nil,
has_companion = false,
has_execution_order = false,
has_focus_target = false,
focus_target_max_stacks = 0,
has_servo_skull = false,
has_noospheric_command = false,
smart_targeting_extension = nil,
companion_spawner_extension = nil,
player_ability_extension = nil,
smart_tag_system = nil,
outline_system = nil,
smoke_fog_system = nil,
force_field_system = nil,
broadphase_system = nil,
side_system = nil,
hud_element_smart_tagging = nil,
companion_command_tap = "double"
}
mod.context = context
-- Auto Mark Settings
local auto_mark_settings = mod:get("auto_mark_settings") or {}
mod.auto_mark_settings = auto_mark_settings
-- Mark States
---@class AutoMarkMarkContext
local mark_context = {
auto_mark_interval = 0,
execution_order_units = setmetatable({}, { __mode = "k" }),
[TAG_NAMES.ENEMY_TAG] = {
tag = nil,
cooldown = 0,
priority_switch_cooldown = 0,
delay = 0,
delay_times = 0,
interval = 0,
manual_unit = nil,
manual_unit_expired_time = nil,
is_manual = false,
},
[TAG_NAMES.VETERAN_TAG] = {
tag = nil,
cooldown = 0,
priority_switch_cooldown = 0,
delay = 0,
delay_times = 0,
interval = 0,
manual_unit = nil,
manual_unit_expired_time = nil,
is_manual = false,
switch_melee_unit = nil,
switch_range_unit = nil,
switch_unit_expired_time = nil,
is_switch_melee = false,
is_switch_range = false,
removed_units = setmetatable({}, { __mode = "k" }),
},
[TAG_NAMES.COMPANION_TAG] = {
tag = nil,
cooldown = 0,
priority_switch_cooldown = 0,
delay = 0,
delay_times = 0,
interval = 0,
manual_unit = nil,
manual_unit_expired_time = nil,
is_manual = false,
pounce_start_time = nil,
is_cancelable = false,
canceled_units = setmetatable({}, { __mode = "k" }),
removed_units = setmetatable({}, { __mode = "k" }),
},
[TAG_NAMES.SERVO_SKULL_TAG] = {
tag = nil,
cooldown = 0,
priority_switch_cooldown = 0,
delay = 0,
delay_times = 0,
interval = 0,
manual_unit = nil,
manual_unit_expired_time = nil,
is_manual = false,
shoot_start_time = nil,
noospheric_command_next_time = math.huge,
servo_skull_lose_sight_time = nil,
canceled_units = setmetatable({}, { __mode = "k" }),
removed_units = setmetatable({}, { __mode = "k" }),
},
}
mod.mark_context = mark_context
-- Enemy Visbility Check
local visibility_cache = setmetatable({}, { __mode = "k" })
local visibility_check_frame = setmetatable({}, { __mode = "k" })
mod.visibility_cache = visibility_cache
mod.visibility_check_frame = visibility_check_frame
local servo_skull_visibility_cache = setmetatable({}, { __mode = "k" })
local servo_skull_visibility_check_frame = setmetatable({}, { __mode = "k" })
mod.servo_skull_visibility_cache = servo_skull_visibility_cache
mod.servo_skull_visibility_check_frame = servo_skull_visibility_check_frame
mod.num_visibility_checks_this_frame = 0
---@class AutoMarkDisablingTypes
local DISABLING_TYPES = {
-- netted = true,
pounced = true,
warp_grabbed = true,
mutant_charged = true,
consumed = true,
grabbed = true,
}
mod.DISABLING_TYPES = DISABLING_TYPES
-- Reset all params
local function reset_context()
-- Reset Mark Params
mark_context.auto_mark_interval = 0
table_clear(mark_context.execution_order_units)
table_clear(visibility_cache)
table_clear(visibility_check_frame)
table_clear(servo_skull_visibility_cache)
table_clear(servo_skull_visibility_check_frame)
for _, tag_name in pairs(TAG_NAMES) do
local tag_context = mark_context[tag_name]
tag_context.tag = nil
tag_context.cooldown = 0
tag_context.priority_switch_cooldown = 0
tag_context.delay = 0
tag_context.delay_times = 0
tag_context.interval = 0
tag_context.manual_unit = nil
tag_context.manual_unit_expired_time = nil
tag_context.is_manual = false
end
local veteran_tag_context = mark_context[TAG_NAMES.VETERAN_TAG]
veteran_tag_context.switch_melee_unit = nil
veteran_tag_context.switch_range_unit = nil
veteran_tag_context.switch_unit_expired_time = nil
veteran_tag_context.is_switch_melee = false
veteran_tag_context.is_switch_range = false
table_clear(veteran_tag_context.removed_units)
local companion_tag_context = mark_context[TAG_NAMES.COMPANION_TAG]
companion_tag_context.pounce_start_time = nil
companion_tag_context.is_cancelable = false
table_clear(companion_tag_context.canceled_units)
table_clear(companion_tag_context.removed_units)
local servo_skull_tag_context = mark_context[TAG_NAMES.SERVO_SKULL_TAG]
servo_skull_tag_context.shoot_start_time = nil
servo_skull_tag_context.noospheric_command_next_time = math.huge
servo_skull_tag_context.servo_skull_lose_sight_time = nil
table_clear(servo_skull_tag_context.canceled_units)
table_clear(servo_skull_tag_context.removed_units)
end
local function destroy_references()
context.player = nil
context.talent_resource_component = nil
context.disabled_character_state_component = nil
context.locomotion_component = nil
context.smart_targeting_extension = nil
context.companion_spawner_extension = nil
context.player_ability_extension = nil
context.smart_tag_system = nil
context.outline_system = nil
context.smoke_fog_system = nil
context.force_field_system = nil
context.broadphase_system = nil
context.side_system = nil
context.hud_element_smart_tagging = nil
mod:destroy_visibility_raycast_objects()
end
-- Load Other Files
mod:io_dofile("AutoMark/scripts/mods/AutoMark/utils/utils")
mod:io_dofile("AutoMark/scripts/mods/AutoMark/context/context")
mod:io_dofile("AutoMark/scripts/mods/AutoMark/setting/class_setting")
mod:io_dofile("AutoMark/scripts/mods/AutoMark/setting/cyber_mastiff_setting")
mod:io_dofile("AutoMark/scripts/mods/AutoMark/setting/servo_skull_setting")
mod:io_dofile("AutoMark/scripts/mods/AutoMark/targeting/targeting")
mod:io_dofile("AutoMark/scripts/mods/AutoMark/targeting/custom_targeting")
mod:io_dofile("AutoMark/scripts/mods/AutoMark/mark/base_mark")
mod:io_dofile("AutoMark/scripts/mods/AutoMark/mark/companion_mark")
mod:io_dofile("AutoMark/scripts/mods/AutoMark/mark/focus_target_mark")
mod:io_dofile("AutoMark/scripts/mods/AutoMark/mark/servo_skull_mark")
-- Mod Enabled
mod.on_enabled = function(initial_call)
context.mod_enabled = true
mod:check_game_mode()
mod:init_auto_mark_settings()
-- init cache after mod enabled since all hooks were disabled
mod:init_context()
mod:init_execution_order_units()
mod:init_visibility_raycast_objects()
mod:set_menu_class_settings(mod:get_menu_class_name())
mod:set_menu_servo_skull_breed_settings(mod:get("noospheric_command_boost_breed_name"))
mod:set_menu_cyber_mastiff_breed_settings(mod:get("companion_cancel_mark_breed_name"))
end
-- Mod Disabled
mod.on_disabled = function(initial_call)
context.mod_enabled = false
-- mark info rest
reset_context()
destroy_references()
end
-- Enter/Exit GameplayStateRun
mod.on_game_state_changed = function(status, state_name)
if state_name == "GameplayStateRun" then
if status == "enter" then
mod:check_game_mode()
-- game settings cache
mod:init_game_settings()
-- display
mod:set_menu_class_settings(mod:get_menu_class_name())
elseif status == "exit" then
context.game_mode_valid = false
-- menu mark info rest
reset_context()
end
end
end
-- Mod Setting Change
mod.on_setting_changed = function(setting_id)
local result = mod:get(setting_id)
local class_name = mod:get("class_selection")
-- Normal Mod Settings
if mod_settings[setting_id] ~= nil then
if setting_id == "companion_health_threshold" or setting_id == "servo_skull_cancel_mark_health_threshold" then
result = result / 100
elseif setting_id == "capacitance_retention_elite_threshold" or setting_id == "capacitance_retention_special_threshold" or setting_id == "capacitance_retention_boss_threshold" then
result = result / 100
if result == -0 and 1 / result < 0 then
mod:set(setting_id .. "_negative_zero", true, false)
else
mod:set(setting_id .. "_negative_zero", false, false)
end
end
mod_settings[setting_id] = result
-- Apply Class Settings to Other Classes
elseif setting_id == "apply_button" then
if result == "apply_to_all" then
mod:apply_to_all_classes(class_name)
elseif result == "apply_to_normal" then
mod:apply_to_normal_tag(class_name)
end
mod:set("apply_button", "blank", false)
-- Reset Class Settings
elseif setting_id == "reset_button" then
if result == "reset_all" then
mod:reset_auto_mark_settings()
elseif result == "reset_current" then
mod:reset_class_settings(class_name)
end
mod:set_menu_class_settings(class_name)
mod:set("reset_button", "blank", false)
-- Select Noospheric Command Breed Name
elseif setting_id == "noospheric_command_boost_breed_name" then
mod:set_menu_servo_skull_breed_settings(result)
-- Set Noospheric Command Breed Settings
elseif mod:is_servo_skull_breed_setting_id(setting_id) then
local breed_name = mod:get("noospheric_command_boost_breed_name")
mod:set_servo_skull_breed_setting(breed_name, setting_id, result)
-- Select Companion Cancel Mark Breed Name
elseif setting_id == "companion_cancel_mark_breed_name" then
mod:set_menu_cyber_mastiff_breed_settings(result)
-- Set Companion Cancel Mark Breed Settings
elseif mod:is_cyber_mastiff_breed_setting_id(setting_id) then
local breed_name = mod:get("companion_cancel_mark_breed_name")
mod:set_cyber_mastiff_breed_setting(breed_name, setting_id, result)
-- Set Class Name
elseif setting_id == "class_selection" then
mod:set_menu_class_settings(result)
-- Set Class Settings
else
local class_settings = auto_mark_settings[class_name]
if DEFAULT_CLASS_SETTINGS[setting_id] ~= nil then
class_settings[setting_id] = result
elseif DEFAULT_CLASS_SETTINGS.breed_priorities[setting_id] ~= nil then
if (class_name == "adamant_companion" or class_name == "cryptic_servo_skull") and setting_id == "chaos_poxwalker_bomber" then
class_settings.breed_priorities[setting_id] = 0
mod:set_menu_class_settings(class_name)
else
class_settings.breed_priorities[setting_id] = result
end
end
mod:set("auto_mark_settings", auto_mark_settings, false)
end
end
-- Toggle Mod Enabled/Disabled
mod.toggle_mod = function()
if mod_settings.toggle_mod_notify then
mod:notify("Auto Mark " .. (not mod_settings.toggle_mod and "Enabled" or "Disabled"))
end
mod:set("toggle_mod", not mod_settings.toggle_mod, true)
end
local talent_settings = require("scripts/settings/talent/talent_settings")
local cryptic_talent_settings = talent_settings.cryptic
local function can_noospheric_command_boost()
local player_ability_extension = context.player_ability_extension
if not player_ability_extension then
return false
end
return player_ability_extension:has_enough_ability_charge_percentage("combat_ability", cryptic_talent_settings.servo_skull_shooting_tagging.minimum_capacitance)
end
local function is_player_in_platform()
local locomotion_component = context.locomotion_component
local locomotion_parent_unit = locomotion_component and locomotion_component.parent_unit
return locomotion_parent_unit and ScriptUnit_extension(locomotion_parent_unit, "moveable_platform_system")
end
-- Check if Tag is Valid for Current Class
local function is_tag_valid(tag_name)
if tag_name == TAG_NAMES.COMPANION_TAG then
return context.class_name == "adamant" and context.has_companion and not is_player_in_platform()
elseif tag_name == TAG_NAMES.VETERAN_TAG then
return context.class_name == "veteran" and context.has_focus_target
elseif tag_name == TAG_NAMES.ENEMY_TAG then
return context.class_name ~= "veteran" or not context.has_focus_target
elseif tag_name == TAG_NAMES.SERVO_SKULL_TAG then
return context.class_name == "cryptic" and context.has_servo_skull and not mod:is_servo_skull_hacking()
end
return false
end
-- Auto-Mark Target Unit with the Tag
local function auto_mark_by_tag(tag_name, t, fixed_frame)
if not is_tag_valid(tag_name) then
return false
end
local tag_context = mark_context[tag_name]
if tag_context.interval > 0 then
return false
end
local marked_tag = tag_context.tag
local marked_tag_is_manual = tag_context.is_manual
local disabled_character_state_component = context.disabled_character_state_component
local is_character_disabled = disabled_character_state_component and disabled_character_state_component.is_disabled and DISABLING_TYPES[disabled_character_state_component.disabling_type]
local target_unit, target_tag, target_is_dormant_daemonhost
if is_character_disabled and (tag_name == TAG_NAMES.COMPANION_TAG or tag_name == TAG_NAMES.SERVO_SKULL_TAG) then
local disabling_unit = disabled_character_state_component and disabled_character_state_component.disabling_unit
if disabling_unit and (not marked_tag or marked_tag._target_unit ~= disabling_unit) then
mod:print_debug("Auto Mark Disabling Unit")
target_unit = disabling_unit
end
else
local class_settings = mod:get_class_settings(tag_name)
-- mark when cooldown is zero
local is_cooldown_ready = tag_context.cooldown <= 0 and (not class_settings.mark_limit or not marked_tag)
-- mark when priority switch is on
local is_priority_switch = tag_context.priority_switch_cooldown <= 0 and class_settings.priority_switch and marked_tag
if class_settings.toggle_class and (class_settings.override_manual or not marked_tag_is_manual) then
if is_cooldown_ready then
target_unit, target_tag, target_is_dormant_daemonhost = mod:find_auto_mark_target_unit(class_settings.min_range, class_settings.max_range, tag_name, tag_context, class_settings)
elseif is_priority_switch then
target_unit, target_tag, target_is_dormant_daemonhost = mod:find_auto_mark_target_unit(class_settings.min_range, class_settings.max_range, tag_name, tag_context, class_settings, marked_tag)
end
end
end
if target_unit then
if tag_name == TAG_NAMES.VETERAN_TAG and target_is_dormant_daemonhost then
mod:set_auto_mark(TAG_NAMES.ENEMY_TAG, target_unit, target_tag)
else
mod:set_auto_mark(tag_name, target_unit, target_tag)
end
return true
end
if tag_name == TAG_NAMES.VETERAN_TAG then
if mod_settings.focus_target_overwrite and marked_tag then
local marked_unit = marked_tag._target_unit
if not mod:is_dormant_daemonhost(marked_unit) and mod:can_focus_target_overwrite(marked_unit, marked_tag) and mod:is_target_pingable(marked_unit) then
mod:print_debug("Focus Target Overwrite")
if tag_context.is_switch_melee then
tag_context.switch_melee_unit = marked_unit
elseif tag_context.is_switch_range then
tag_context.switch_range_unit = marked_unit
end
if marked_tag_is_manual then
mod:on_manual_mark(tag_context, marked_unit)
end
mod:set_auto_mark(tag_name, marked_unit, target_tag)
return true
end
end
elseif tag_name == TAG_NAMES.SERVO_SKULL_TAG then
if mod_settings.noospheric_command_boost and context.has_noospheric_command and marked_tag and t >= tag_context.noospheric_command_next_time and can_noospheric_command_boost() then
local marked_unit = marked_tag._target_unit
if is_character_disabled
or not mod:is_dormant_daemonhost(marked_unit)
and mod:is_noospheric_command_boost_breed_valid(marked_unit)
and mod:has_enough_capacitance(marked_unit)
and mod:is_servo_skull_target_visible(marked_unit, fixed_frame, true)
and mod:is_target_pingable(marked_unit)
then
mod:print_debug("Noospheric Command Boost")
if marked_tag_is_manual then
mod:on_manual_mark(tag_context, marked_unit)
end
mod:set_auto_mark(tag_name, marked_unit, target_tag)
return true
end
end
end
return false
end
-- Auto-Mark
local function auto_mark(dt, t, fixed_frame)
-- calculate interval
if mark_context.auto_mark_interval > 0 then
mark_context.auto_mark_interval = mark_context.auto_mark_interval - dt
end
-- calculate cooldown and delay for all tags
local skip = false
for _, tag_name in pairs(TAG_NAMES) do
local tag_context = mark_context[tag_name]
if tag_context.delay > 0 then
tag_context.delay = tag_context.delay - dt
if tag_context.delay <= 0 then
tag_context.delay = 0
tag_context.delay_times = 0
else
skip = true
end
end
if tag_context.interval > 0 then
tag_context.interval = tag_context.interval - dt
end
if tag_context.cooldown > 0 then
tag_context.cooldown = tag_context.cooldown - dt
end
if tag_context.priority_switch_cooldown > 0 then
tag_context.priority_switch_cooldown = tag_context.priority_switch_cooldown - dt
end
end
-- pause auto mark for a period of time after it is executed.
if mark_context.auto_mark_interval > 0 or skip then
return
end
-- all kinds of tag to mark
if auto_mark_by_tag(TAG_NAMES.COMPANION_TAG, t, fixed_frame) then
return
end
if auto_mark_by_tag(TAG_NAMES.SERVO_SKULL_TAG, t, fixed_frame) then
return
end
if auto_mark_by_tag(TAG_NAMES.VETERAN_TAG, t, fixed_frame) then
return
end
if auto_mark_by_tag(TAG_NAMES.ENEMY_TAG, t, fixed_frame) then
return
end
end
local function clean_visibility_cache(fixed_frame)
if fixed_frame % 20 == 0 then
local frame_threshold = fixed_frame - 5
for cached_unit, check_frame in pairs(visibility_check_frame) do
if check_frame < frame_threshold then
visibility_cache[cached_unit] = nil
visibility_check_frame[cached_unit] = nil
end
end
for cached_unit, check_frame in pairs(servo_skull_visibility_check_frame) do
if check_frame < frame_threshold then
servo_skull_visibility_cache[cached_unit] = nil
servo_skull_visibility_check_frame[cached_unit] = nil
end
end
end
end
local function clean_expired_units(t)
for _, tag_name in pairs(TAG_NAMES) do
local tag_context = mark_context[tag_name]
if tag_context.manual_unit_expired_time and t >= tag_context.manual_unit_expired_time then
tag_context.manual_unit = nil
tag_context.manual_unit_expired_time = nil
end
if tag_context.switch_unit_expired_time and t >= tag_context.switch_unit_expired_time then
tag_context.switch_melee_unit = nil
tag_context.switch_range_unit = nil
tag_context.switch_unit_expired_time = nil
end
local canceled_units = tag_context.canceled_units
if canceled_units then
for unit, expired_time in pairs(canceled_units) do
if t >= expired_time then
canceled_units[unit] = nil
end
end
end
local removed_units = tag_context.removed_units
if removed_units then
for unit, expired_time in pairs(removed_units) do
if t >= expired_time then
removed_units[unit] = nil
end
end
end
end
end
-- Main Entry For Auto Mark
mod:hook_safe(CLASS.PlayerUnitSmartTargetingExtension, "fixed_update",
function(self, unit, dt, t, fixed_frame)
if self._player.viewport_name ~= "player1" then
return
end
if mod_settings.toggle_mod and context.game_mode_valid then
mod.num_visibility_checks_this_frame = 0
clean_expired_units(t)
clean_visibility_cache(fixed_frame)
mod:auto_cancel_companion_mark(dt, t)
mod:auto_cancel_servo_skull_mark(dt, t, fixed_frame)
mod:auto_hack(dt, t, fixed_frame)
auto_mark(dt, t, fixed_frame)
end
end)
@@ -0,0 +1,812 @@
local mod = get_mod("AutoMark")
local Breed = require("scripts/utilities/breed")
local Breeds = require("scripts/settings/breed/breeds")
local Archetypes = require("scripts/settings/archetype/archetypes")
local elite_widget = {
setting_id = "toggle_elite",
type = "checkbox",
default_value = true,
sub_widgets = {},
}
local special_widget = {
setting_id = "toggle_special",
type = "checkbox",
default_value = true,
sub_widgets = {},
}
local boss_widget = {
setting_id = "toggle_boss",
type = "checkbox",
default_value = true,
sub_widgets = {},
}
local other_widget = {
setting_id = "toggle_other",
type = "checkbox",
default_value = true,
sub_widgets = {},
}
local function create_breed_priority_dropdown(breed_name, default_value)
local breed_priority_setting = {
setting_id = breed_name,
type = "numeric",
default_value = breed_name == "chaos_poxwalker_bomber" and 0 or default_value,
range = { 0, 30 },
tooltip = "tooltip_breed_priority",
}
return breed_priority_setting
end
local elite_priority_dropdown = {}
local special_priority_dropdown = {}
local boss_priority_dropdown = {}
local other_priority_dropdown = {}
for breed_name, breed_data in pairs(Breeds) do
if Breed.is_minion(breed_data) and breed_data.unit_template_name == "minion" and breed_data.smart_tag_target_type == "breed" and breed_data.faction_name ~= "imperium" then
if breed_data.tags.elite then
elite_priority_dropdown[#elite_priority_dropdown + 1] = create_breed_priority_dropdown(breed_name, 0)
elseif breed_data.tags.special then
special_priority_dropdown[#special_priority_dropdown + 1] = create_breed_priority_dropdown(breed_name, 1)
elseif breed_data.is_boss then
boss_priority_dropdown[#boss_priority_dropdown + 1] = create_breed_priority_dropdown(breed_name, 1)
if breed_data.tags.witch then
boss_priority_dropdown[#boss_priority_dropdown + 1] = create_breed_priority_dropdown(breed_name .. "_passive", 1)
end
else
other_priority_dropdown[#other_priority_dropdown + 1] = create_breed_priority_dropdown(breed_name, 1)
end
end
end
local get_breed_sort = function(breed_name)
return mod:localize(breed_name)
end
local compare_breed_name = function(a, b)
return get_breed_sort(a.setting_id) < get_breed_sort(b.setting_id)
end
table.sort(elite_priority_dropdown, compare_breed_name)
table.sort(special_priority_dropdown, compare_breed_name)
table.sort(boss_priority_dropdown, compare_breed_name)
table.sort(other_priority_dropdown, compare_breed_name)
elite_widget.sub_widgets = elite_priority_dropdown
special_widget.sub_widgets = special_priority_dropdown
boss_widget.sub_widgets = boss_priority_dropdown
other_widget.sub_widgets = other_priority_dropdown
local class_options = {
{ text = "adamant_companion", value = "adamant_companion" },
{ text = "veteran_focus_target", value = "veteran_focus_target" },
{ text = "cryptic_servo_skull", value = "cryptic_servo_skull" },
}
for class_name, _ in pairs(Archetypes) do
class_options[#class_options + 1] = { text = class_name, value = class_name }
end
table.sort(class_options, function(a, b) return a.text < b.text end)
local breed_name_options = {}
local elite_breed_names = {}
local special_breed_names = {}
local boss_breed_names = {}
local captain_breed_names = {}
local other_breed_names = {}
for breed_name, breed_data in pairs(Breeds) do
if Breed.is_minion(breed_data) and breed_data.unit_template_name == "minion" and breed_data.smart_tag_target_type == "breed" and breed_data.faction_name ~= "imperium" then
if breed_data.tags.elite then
elite_breed_names[#elite_breed_names + 1] = breed_name
elseif breed_data.tags.special then
special_breed_names[#special_breed_names + 1] = breed_name
elseif breed_data.is_boss then
if breed_data.tags.captain or breed_data.tags.cultist_captain then
captain_breed_names[#captain_breed_names + 1] = breed_name
else
boss_breed_names[#boss_breed_names + 1] = breed_name
end
else
other_breed_names[#other_breed_names + 1] = breed_name
end
end
end
table.sort(elite_breed_names, function(a, b) return get_breed_sort(a) < get_breed_sort(b) end)
table.sort(special_breed_names, function(a, b) return get_breed_sort(a) < get_breed_sort(b) end)
table.sort(boss_breed_names, function(a, b) return get_breed_sort(a) < get_breed_sort(b) end)
table.sort(captain_breed_names, function(a, b) return get_breed_sort(a) < get_breed_sort(b) end)
table.sort(other_breed_names, function(a, b) return get_breed_sort(a) < get_breed_sort(b) end)
for _, breed_name in ipairs(elite_breed_names) do
breed_name_options[#breed_name_options + 1] = { text = breed_name, value = breed_name }
end
for _, breed_name in ipairs(special_breed_names) do
breed_name_options[#breed_name_options + 1] = { text = breed_name, value = breed_name }
end
for _, breed_name in ipairs(boss_breed_names) do
breed_name_options[#breed_name_options + 1] = { text = breed_name, value = breed_name }
end
for _, breed_name in ipairs(captain_breed_names) do
breed_name_options[#breed_name_options + 1] = { text = breed_name, value = breed_name }
end
for _, breed_name in ipairs(other_breed_names) do
breed_name_options[#breed_name_options + 1] = { text = breed_name, value = breed_name }
end
-- Manual settings
local widgets = {
{
setting_id = "mod_settings",
type = "group",
sub_widgets = {
{
setting_id = "toggle_mod",
type = "checkbox",
default_value = true,
},
{
setting_id = "toggle_mod_keybind",
type = "keybind",
default_value = {},
keybind_global = false,
keybind_trigger = "pressed",
keybind_type = "function_call",
function_name = "toggle_mod",
},
{
setting_id = "toggle_mod_notify",
type = "checkbox",
default_value = true,
},
{
setting_id = "debug_mode",
type = "checkbox",
default_value = false
},
}
},
{
setting_id = "adamant_settings",
type = "group",
sub_widgets = {
{
setting_id = "companion_mark_keybind",
type = "keybind",
default_value = {},
keybind_global = false,
keybind_trigger = "pressed",
keybind_type = "function_call",
function_name = "companion_mark",
},
{
setting_id = "companion_mark_ignore_unaggroed",
title = "ignore_unaggroed",
type = "checkbox",
default_value = false,
},
{
setting_id = "companion_range_limitation",
type = "numeric",
title = "companion_range_limitation",
tooltip = "companion_range_limitation_tooltip",
default_value = 0,
range = { 0, 100 },
unit_text = "meter",
decimals_number = 0
},
{
setting_id = "companion_mark_max_distance",
type = "numeric",
title = "companion_mark_max_distance",
tooltip = "companion_mark_max_distance_tooltip",
default_value = 0,
range = { 0, 100 },
unit_text = "meter",
decimals_number = 0
},
{
setting_id = "companion_mark_tagged_always_visible",
type = "checkbox",
default_value = false,
},
{
setting_id = "companion_mark_threat_priority",
title = "threat_priority",
tooltip = "threat_priority_tooltip",
type = "checkbox",
default_value = false,
},
{
setting_id = "execution_order_priority",
type = "checkbox",
default_value = false,
},
{
setting_id = "execution_order_force_mark",
type = "checkbox",
default_value = false,
},
{
setting_id = "companion_mark_sticky_targeting",
type = "checkbox",
title = "sticky_targeting",
tooltip = "sticky_targeting_tooltip",
default_value = false,
sub_widgets = {
{
setting_id = "companion_mark_sticky_targeting_elite",
type = "checkbox",
title = "elite",
tooltip = "elite_tooltip",
default_value = false,
},
{
setting_id = "companion_mark_sticky_targeting_special",
type = "checkbox",
title = "special",
tooltip = "special_tooltip",
default_value = false,
},
{
setting_id = "companion_mark_sticky_targeting_boss",
type = "checkbox",
title = "boss",
tooltip = "boss_tooltip",
default_value = false,
},
}
},
{
setting_id = "companion_cancel_mark",
type = "checkbox",
default_value = false,
sub_widgets = {
{
setting_id = "companion_cancel_mark_human",
type = "checkbox",
default_value = false,
},
{
setting_id = "companion_cancel_mark_non_human",
type = "checkbox",
default_value = false,
},
{
setting_id = "companion_health_threshold",
type = "numeric",
title = "health_threshold",
tooltip = "companion_health_threshold_tooltip",
default_value = 0,
unit_text = "percent",
range = { 0, 100 },
decimals_number = 0
},
{
setting_id = "companion_time_threshold",
type = "numeric",
title = "time_threshold",
tooltip = "companion_time_threshold_tooltip",
default_value = 0,
unit_text = "second",
range = { 0, 25 },
decimals_number = 1
},
{
setting_id = "companion_distance_threshold",
type = "numeric",
title = "distance_threshold",
tooltip = "companion_distance_threshold_tooltip",
default_value = 0,
unit_text = "meter",
range = { 0, 100 },
decimals_number = 0
},
}
},
{
setting_id = "companion_cancel_mark_breed_name",
type = "dropdown",
title = "enemy_settings",
tooltip = "enemy_settings_tooltip",
default_value = breed_name_options[1].value,
options = table.clone(breed_name_options),
sub_widgets = {
{
setting_id = "reset_all_cyber_mastiff_breed_settings",
type = "button",
title = "enemy_settings_reset",
tooltip = "enemy_settings_reset_tooltip",
button_text = "hold_to_reset",
button_trigger = "held",
button_hold_duration = 1.5,
function_name = "reset_all_cyber_mastiff_breed_settings",
},
{
setting_id = "companion_cancel_mark_breed_override",
type = "checkbox",
title = "enemy_settings_override",
tooltip = "enemy_settings_override_tooltip",
default_value = false,
sub_widgets = {
{
setting_id = "companion_range_limitation_breed",
type = "numeric",
title = "companion_range_limitation",
tooltip = "companion_range_limitation_tooltip",
default_value = 0,
range = { 0, 100 },
unit_text = "meter",
decimals_number = 0
},
{
setting_id = "companion_mark_max_distance_breed",
type = "numeric",
title = "companion_mark_max_distance",
tooltip = "companion_mark_max_distance_tooltip",
default_value = 0,
range = { 0, 100 },
unit_text = "meter",
decimals_number = 0
},
{
setting_id = "companion_mark_sticky_targeting_breed",
type = "checkbox",
title = "sticky_targeting",
tooltip = "sticky_targeting_tooltip",
default_value = false,
},
{
setting_id = "companion_cancel_mark_breed_health_threshold",
type = "numeric",
title = "health_threshold",
tooltip = "companion_health_threshold_tooltip",
default_value = 0,
range = { 0, 100 },
unit_text = "percent",
decimals_number = 0
},
{
setting_id = "companion_cancel_mark_breed_time_threshold",
type = "numeric",
title = "time_threshold",
tooltip = "companion_time_threshold_tooltip",
default_value = 0,
range = { 0, 25 },
unit_text = "second",
decimals_number = 1
},
{
setting_id = "companion_cancel_mark_breed_distance_threshold",
type = "numeric",
title = "distance_threshold",
tooltip = "companion_distance_threshold_tooltip",
default_value = 0,
range = { 0, 100 },
unit_text = "meter",
decimals_number = 0
},
}
},
}
},
}
},
{
setting_id = "cryptic_settings",
type = "group",
sub_widgets = {
{
setting_id = "servo_skull_mark_keybind",
type = "keybind",
default_value = {},
keybind_global = false,
keybind_trigger = "pressed",
keybind_type = "function_call",
function_name = "servo_skull_mark",
},
{
setting_id = "servo_skull_mark_ignore_unaggroed",
type = "checkbox",
title = "ignore_unaggroed",
default_value = false,
},
{
setting_id = "servo_skull_range_limitation",
type = "numeric",
title = "companion_range_limitation",
tooltip = "companion_range_limitation_tooltip",
default_value = 0,
range = { 0, 100 },
unit_text = "meter",
decimals_number = 0
},
{
setting_id = "servo_skull_mark_threat_priority",
type = "checkbox",
title = "threat_priority",
tooltip = "threat_priority_tooltip",
default_value = false,
},
{
setting_id = "hack_mark_keybind",
type = "keybind",
default_value = {},
keybind_global = false,
keybind_trigger = "pressed",
keybind_type = "function_call",
function_name = "hack_mark",
},
{
setting_id = "auto_hack",
type = "checkbox",
default_value = false,
sub_widgets = {
{
setting_id = "disable_auto_hack_for_noospheric_command",
type = "checkbox",
default_value = false,
},
}
},
{
setting_id = "noospheric_command_boost",
type = "checkbox",
default_value = false,
sub_widgets = {
{
setting_id = "noospheric_command_boost_elite",
type = "checkbox",
title = "elite",
default_value = false,
},
{
setting_id = "noospheric_command_boost_special",
type = "checkbox",
title = "special",
default_value = false,
},
{
setting_id = "noospheric_command_boost_boss",
type = "checkbox",
title = "boss",
default_value = false,
},
}
},
{
setting_id = "capacitance_retention",
type = "checkbox",
default_value = false,
sub_widgets = {
{
setting_id = "capacitance_retention_elite_threshold",
type = "numeric",
title = "elite",
default_value = 0,
range = { -1000, 1000 },
unit_text = "percent",
decimals_number = 0,
},
{
setting_id = "capacitance_retention_special_threshold",
type = "numeric",
title = "special",
default_value = 0,
range = { -1000, 1000 },
unit_text = "percent",
decimals_number = 0,
},
{
setting_id = "capacitance_retention_boss_threshold",
type = "numeric",
title = "boss",
default_value = 0,
range = { -1000, 1000 },
unit_text = "percent",
decimals_number = 0,
},
}
},
{
setting_id = "servo_skull_mark_sticky_targeting",
type = "checkbox",
title = "sticky_targeting",
tooltip = "sticky_targeting_tooltip",
default_value = false,
sub_widgets = {
{
setting_id = "servo_skull_mark_sticky_targeting_elite",
type = "checkbox",
title = "elite",
tooltip = "elite_tooltip",
default_value = false,
},
{
setting_id = "servo_skull_mark_sticky_targeting_special",
type = "checkbox",
title = "special",
tooltip = "special_tooltip",
default_value = false,
},
{
setting_id = "servo_skull_mark_sticky_targeting_boss",
type = "checkbox",
title = "boss",
tooltip = "boss_tooltip",
default_value = false,
},
}
},
{
setting_id = "servo_skull_cancel_mark",
type = "checkbox",
default_value = false,
sub_widgets = {
{
setting_id = "servo_skull_cancel_mark_time_threshold",
type = "numeric",
title = "servo_skull_lose_sight_tolerance",
tooltip = "servo_skull_lose_sight_tolerance_tooltip",
default_value = 0,
range = { 0, 25 },
unit_text = "second",
decimals_number = 1
},
{
setting_id = "servo_skull_cancel_mark_health_threshold",
type = "numeric",
title = "health_threshold",
tooltip = "servo_skull_health_threshold_tooltip",
default_value = 0,
range = { 0, 100 },
unit_text = "percent",
decimals_number = 0
},
}
},
{
setting_id = "noospheric_command_boost_breed_name",
type = "dropdown",
title = "enemy_settings",
tooltip = "enemy_settings_tooltip",
default_value = breed_name_options[1].value,
options = table.clone(breed_name_options),
sub_widgets = {
{
setting_id = "reset_all_servo_skull_breed_settings",
type = "button",
title = "enemy_settings_reset",
tooltip = "enemy_settings_reset_tooltip",
button_text = "hold_to_reset",
button_trigger = "held",
button_hold_duration = 1.5,
function_name = "reset_all_servo_skull_breed_settings",
},
{
setting_id = "noospheric_command_boost_breed_override",
type = "checkbox",
title = "enemy_settings_override",
tooltip = "enemy_settings_override_tooltip",
default_value = false,
sub_widgets = {
{
setting_id = "servo_skull_range_limitation_breed",
type = "numeric",
title = "companion_range_limitation",
tooltip = "companion_range_limitation_tooltip",
default_value = 0,
range = { 0, 100 },
unit_text = "meter",
decimals_number = 0
},
{
setting_id = "noospheric_command_boost_breed_toggle",
type = "checkbox",
default_value = false,
},
{
setting_id = "capacitance_retention_breed_threshold",
type = "numeric",
default_value = 0,
range = { -1000, 1000 },
unit_text = "percent",
decimals_number = 0,
},
{
setting_id = "servo_skull_mark_sticky_targeting_breed",
type = "checkbox",
title = "sticky_targeting",
tooltip = "sticky_targeting_tooltip",
default_value = false,
},
{
setting_id = "servo_skull_cancel_mark_breed_time_threshold",
type = "numeric",
title = "servo_skull_lose_sight_tolerance",
tooltip = "servo_skull_lose_sight_tolerance_tooltip",
default_value = 0,
range = { 0, 25 },
unit_text = "second",
decimals_number = 1
},
{
setting_id = "servo_skull_cancel_mark_breed_health_threshold",
type = "numeric",
title = "health_threshold",
tooltip = "servo_skull_health_threshold_tooltip",
default_value = 0,
range = { 0, 100 },
unit_text = "percent",
decimals_number = 0
},
}
},
}
},
}
},
{
setting_id = "veteran_settings",
type = "group",
sub_widgets = {
{
setting_id = "focus_target_ignore_unaggroed",
type = "checkbox",
title = "ignore_unaggroed",
default_value = false,
},
{
setting_id = "focus_target_overwrite",
type = "checkbox",
default_value = false,
sub_widgets = {
{
setting_id = "focus_target_overwrite_delta",
type = "numeric",
default_value = 5,
range = { 1, 10 },
unit_text = "stack",
},
}
},
{
setting_id = "focus_target_switch",
type = "checkbox",
default_value = false,
sub_widgets = {
{
setting_id = "focus_target_switch_override_manual",
type = "checkbox",
default_value = false,
},
{
setting_id = "focus_target_switch_melee",
type = "checkbox",
default_value = false,
},
{
setting_id = "focus_target_switch_range",
type = "checkbox",
default_value = false,
},
}
}
}
},
{
setting_id = "auto_mark_settings",
type = "group",
sub_widgets = {
{
setting_id = "class_selection",
type = "dropdown",
default_value = "adamant",
options = class_options,
},
{
setting_id = "apply_button",
type = "dropdown",
default_value = "blank",
options = {
{ text = "apply_to_normal", value = "apply_to_normal" },
{ text = "apply_to_all", value = "apply_to_all" },
{ text = "blank", value = "blank" },
}
},
{
setting_id = "reset_button",
type = "dropdown",
default_value = "blank",
options = {
{ text = "reset_current", value = "reset_current" },
{ text = "reset_all", value = "reset_all" },
{ text = "blank", value = "blank" },
}
},
{
setting_id = "toggle_class",
type = "checkbox",
default_value = true,
},
{
setting_id = "interval",
type = "numeric",
default_value = 1,
range = { 0, 50 },
unit_text = "second",
decimals_number = 1
},
{
setting_id = "cooldown",
type = "numeric",
default_value = 25,
range = { 10, 50 },
unit_text = "second",
decimals_number = 1
},
{
setting_id = "reset_cooldown",
type = "checkbox",
default_value = true
},
{
setting_id = "mark_limit",
type = "checkbox",
default_value = true
},
{
setting_id = "min_range",
type = "numeric",
default_value = 0,
range = { 0, 100 },
unit_text = "meter",
decimals_number = 0
},
{
setting_id = "max_range",
type = "numeric",
default_value = 100,
range = { 1, 100 },
unit_text = "meter",
decimals_number = 0
},
-- {
-- setting_id = "max_angle",
-- type = "numeric",
-- default_value = 0,
-- range = { 0, 180 },
-- unit_text = "degree",
-- decimals_number = 0
-- },
{
setting_id = "override_manual",
type = "checkbox",
default_value = false
},
{
setting_id = "priority_switch",
type = "checkbox",
default_value = false
},
elite_widget,
special_widget,
boss_widget,
other_widget,
}
},
}
return {
name = mod:localize("mod_name"),
description = mod:localize("mod_description"),
is_togglable = true,
options = {
widgets = widgets
}
}
@@ -0,0 +1,915 @@
local Breed = require("scripts/utilities/breed")
local Breeds = require("scripts/settings/breed/breeds")
local Archetypes = require("scripts/settings/archetype/archetypes")
local InputUtils = require("scripts/managers/input/input_utils")
local function color_text(text, color_name)
local color = Color[color_name](255, true)
return InputUtils.apply_color_to_input_text(text, color)
end
local function highlight(text)
return color_text(text, "terminal_text_warning_light")
end
-- ###############################################################################################################
-- zh-tw Localization maintenance note:
-- For zh-tw updates, use the latest translation glossary as the source of truth:
-- https://github.com/SyuanTsai/Warhammer-40-000-DARKTIDE-Mods/blob/main/Referneces/Translation.md
-- Preserve existing context-specific translations when the glossary contains multiple valid terms.
-- ###############################################################################################################
local localization = {
-- mod_name
mod_name = {
en = "Auto Mark",
["zh-cn"] = "智能标记",
["zh-tw"] = "智慧標記",
},
mod_description = {
en = "Enhance your marking experience",
["zh-cn"] = "增强你的标记体验",
["zh-tw"] = "增強你的標記體驗",
},
-- mod_settings
mod_settings = {
en = "Mod Settings",
["zh-cn"] = "模组设置",
["zh-tw"] = "模組設定",
},
toggle_mod = {
en = "Toggle Mod",
["zh-cn"] = "模组开关",
["zh-tw"] = "模組開關",
},
toggle_mod_keybind = {
en = "Toggle Keybind",
["zh-cn"] = "模组开关按键",
["zh-tw"] = "模組開關按鍵",
},
toggle_mod_notify = {
en = "Toggle Notification",
["zh-cn"] = "模组开关通知",
["zh-tw"] = "模組開關通知",
},
debug_mode = {
en = "Debug Mode",
["zh-cn"] = "调试模式",
["zh-tw"] = "除錯模式",
},
-- arbites settings
adamant_settings = {
en = "Arbites Settings",
["zh-cn"] = "法务官设置",
["zh-tw"] = "法務官設定",
},
companion_mark_keybind = {
en = "Cyber-Mastiff Mark Keybind",
["zh-cn"] = "智能獒犬标记按键",
["zh-tw"] = "電子獒犬標記按鍵",
},
companion_mark_keybind_description = {
en = "Dedicated key for Cyber-Mastiff Mark. As Arbites, you can now use both normal enemy mark and Cyber-Mastiff mark at the same time.\n\n" ..
"When " .. highlight("Companion Target Tag") ..
" is set to " .. highlight("Press Once") ..
", this function becomes a normal enemy mark.",
["zh-cn"] = "智能獒犬标记专用按键,现在你可以作为法务官,同时使用普通敌人标记和智能獒犬标记了。\n\n" ..
"当" .. highlight("伙伴目标标记") ..
"设置为" .. highlight("按一次") ..
"时,此功能变为普通敌人标记。",
["zh-tw"] = "電子獒犬標記專用按鍵,身為法務官,你現在可同時使用一般敵人標記與電子獒犬標記。\n\n" ..
"當" .. highlight("同伴目標標記方式") ..
"設為" .. highlight("按一次") ..
"時,此功能會變為一般敵人標記。",
},
ignore_unaggroed = {
en = "Ignore Unalerted Enemies",
["zh-cn"] = "忽略未警觉的敌人",
["zh-tw"] = "忽略未觸發警戒的敵人",
},
companion_mark_ignore_unaggroed_description = {
en = "When enabled, Cyber-Mastiff Auto-Mark will not mark enemies that are not alerted.",
["zh-cn"] = "当启用时,智能獒犬自动标记将不会标记未警觉的敌人。",
["zh-tw"] = "當啟用時,電子獒犬自動標記將不會標記未觸發警戒的敵人。",
},
companion_mark_tagged_always_visible = {
en = "Hunt Them Down",
["zh-cn"] = "追踪到底",
["zh-tw"] = "追蹤到底",
},
companion_mark_tagged_always_visible_description = {
en = "When enabled, targets marked by any mark or chosen by Execution Order are always treated as visible by Cyber-Mastiff AUTO-MARK.",
["zh-cn"] = "开启后,被任意标记或处决指令选中的目标,智能獒犬自动标记将始终视其为可见。",
["zh-tw"] = "開啟後,被任意標記或處決指令選中的目標,智慧獒犬自動標記將始終視其為可見。",
},
threat_priority = {
en = "Threat Priority",
["zh-cn"] = "威胁优先",
["zh-tw"] = "威脅優先",
},
threat_priority_tooltip = {
en = "When enabled, Companion Auto-Mark prioritizes enemies targeting the player.",
["zh-cn"] = "开启后,伙伴自动标记将优先标记以玩家为攻击目标的敌人。",
["zh-tw"] = "開啟後,同伴自動標記將優先標記以玩家為攻擊目標的敵人。",
},
execution_order_priority = {
en = "Execution Order Priority",
["zh-cn"] = "遵从处决指令",
["zh-tw"] = "遵從處決指令",
},
execution_order_priority_description = {
en = "Arbites Cyber-Mastiff Auto-Mark prioritizes enemies chosen by Execution Order.",
["zh-cn"] = "遵从处决指令的选择,法务官智能獒犬自动标记将优先标记已被处决指令选中的敌人。",
["zh-tw"] = "遵從處決指令的選擇,法務官電子獒犬自動標記將優先標記已被處決指令選中的敵人。",
},
execution_order_force_mark = {
en = "Execution Order Force Mark",
["zh-cn"] = "处决指令强制标记",
["zh-tw"] = "處決指令強制標記",
},
execution_order_force_mark_description = {
en = "When enabled, targets chosen by Execution Order can be auto marked by Cyber-Mastiff even if their enemy type is set to ignored in priority settings.",
["zh-cn"] = "开启后,处决指令选中的目标,即便其敌人类型在优先级设置中被设为忽略,仍可被智能獒犬自动标记。",
["zh-tw"] = "開啟後,處決指令選中的目標,即便其敵人類型在優先度設定中被設為忽略,仍可被電子獒犬自動標記。",
},
companion_range_limitation = {
en = "Companion Range Limitation",
["zh-cn"] = "伙伴范围限制",
["zh-tw"] = "伙伴範圍限制",
},
companion_range_limitation_tooltip = {
en = "Restrict the maximum distance between your " .. highlight("companion") .. " and a target that can be marked by the Companion Auto-Mark.\n\n" ..
"Set to " .. highlight("0") .. " to disable.",
["zh-cn"] = "限制伙伴自动标记系统可标记的目标与你的" .. highlight("伙伴") .. "之间的最大距离。\n\n" ..
"设置为" .. highlight("0") .. "以禁用。",
["zh-tw"] = "限制同伴自動標記系統可標記的目標與你的" .. highlight("同伴") .. "之間的最大距離。\n\n" ..
"設為" .. highlight("0") .. "可停用",
},
companion_cancel_mark = {
en = "Auto Cancel Cyber-Mastiff Mark",
["zh-cn"] = "自动取消智能獒犬标记",
["zh-tw"] = "自動取消電子獒犬標記",
},
companion_cancel_mark_human = {
en = "Human",
["zh-cn"] = "人类",
["zh-tw"] = "人類",
},
companion_cancel_mark_human_description = {
en = "Enable for human-sized enemies that can be pounced by your Cyber-Mastiff.",
["zh-cn"] = "在人类体型的敌人上启用,这些敌人可以被你的智能獒犬扑倒。",
["zh-tw"] = "對可被你的電子獒犬撲倒的人型敵人啟用。",
},
companion_cancel_mark_non_human = {
en = "Non-Human",
["zh-cn"] = "非人类",
["zh-tw"] = "非人類",
},
companion_cancel_mark_non_human_description = {
en = "Enable for non-human-sized enemies that cannot be pounced by your Cyber-Mastiff.",
["zh-cn"] = "在非人类体型的敌人上启用,这些敌人不能被你的智能獒犬扑倒。",
["zh-tw"] = "對無法被你的電子獒犬撲倒的非人型敵人啟用。",
},
health_threshold = {
en = "Health Threshold",
["zh-cn"] = "生命阈值",
["zh-tw"] = "生命值門檻",
},
companion_health_threshold_tooltip = {
en = "Cancel the Cyber-Mastiff mark when the health of your Cyber-Mastiff's current attack target falls below your selected health percentage.\n\n" ..
"Set to " .. highlight("0") .. " to disable.\n" ..
"Does not affect " .. highlight("manual") .. " marks.",
["zh-cn"] = "当你的智能獒犬的攻击目标的血量低于所选百分比时,取消该目标的智能獒犬标记。\n\n" ..
"设置为" .. highlight("0") .. "以禁用。\n" ..
"对" .. highlight("手动") .. "标记无效。",
["zh-tw"] = "當你的電子獒犬目前攻擊目標的生命值低於設定百分比時,取消該目標的電子獒犬標記。\n\n" ..
"設為" .. highlight("0") .. "可停用。\n" ..
"不影響" .. highlight("手動") .. "標記。",
},
time_threshold = {
en = "Time Threshold",
["zh-cn"] = "时间阈值",
["zh-tw"] = "時間門檻",
},
companion_time_threshold_tooltip = {
en = "Cancel the Cyber-Mastiff mark when your Cyber-Mastiff has been attacking its current target for longer than your selected duration (in seconds).\n\n" ..
"Set to " .. highlight("0") .. " to disable.\n" ..
"Does not affect " .. highlight("manual") .. " marks.",
["zh-cn"] = "当你的智能獒犬攻击当前目标的持续时间超过所选时长(单位:秒)时,取消该目标的智能獒犬标记。\n\n" ..
"设置为" .. highlight("0") .. "以禁用。\n" ..
"对" .. highlight("手动") .. "标记无效。",
["zh-tw"] = "當你的電子獒犬攻擊目前目標超過設定秒數時,取消該目標的電子獒犬標記。\n\n" ..
"設為" .. highlight("0") .. "可停用。\n" ..
"不影響" .. highlight("手動") .. "標記。",
},
distance_threshold = {
en = "Distance Threshold",
["zh-cn"] = "距离阈值",
["zh-tw"] = "距離門檻",
},
companion_distance_threshold_tooltip = {
en = "Cancel the Cyber-Mastiff mark when the distance between you and your Cyber-Mastiff exceeds your selected distance (in meters).\n\n" ..
"Set to " .. highlight("0") .. " to disable.\n" ..
"Does not affect " .. highlight("manual") .. " marks.",
["zh-cn"] = "当你与你的智能獒犬之间的距离超过所选距离(单位:米)时,取消智能獒犬标记。\n\n" ..
"设置为" .. highlight("0") .. "以禁用。\n" ..
"对" .. highlight("手动") .. "标记无效。",
["zh-tw"] = "當你與你的電子獒犬之間的距離超過設定公尺時,取消電子獒犬標記。\n\n" ..
"設為" .. highlight("0") .. "可停用。\n" ..
"不影響" .. highlight("手動") .. "標記。",
},
enemy_settings = {
en = "Enemy Settings Override",
["zh-cn"] = "敌人设置覆盖",
["zh-tw"] = "敵人設定覆蓋",
},
enemy_settings_tooltip = {
en = "Select an enemy to configure its individual settings, which override the settings above, except for the master toggles.",
["zh-cn"] = "选择一种敌人,为其配置其独立的设置,这些设置将覆盖上方的设置,除了总开关。",
["zh-tw"] = "選擇一種敵人以設定其個別設定。除了總開關外,個別設定會覆蓋上方的一般設定。",
},
enemy_settings_reset = {
en = "Reset to Defaults",
["zh-cn"] = "重置为默认值",
["zh-tw"] = "重設為預設值",
},
enemy_settings_reset_tooltip = {
en = "Reset all per-enemy individual settings to their default values.",
["zh-cn"] = "重置所有敌人的设置为默认值。",
["zh-tw"] = "將所有敵人的個別設定重設為預設值。",
},
enemy_settings_override = {
en = "Override",
["zh-cn"] = "启用覆盖",
["zh-tw"] = "啟用覆蓋",
},
enemy_settings_override_tooltip = {
en = "Apply dedicated settings for this enemy, which take priority over the general settings above, except for the master toggles.",
["zh-cn"] = "为这种敌人应用专用设置,这些设置将优先于上方的设置,除了总开关。",
["zh-tw"] = "為此敵人套用專用設定。除了總開關外,專用設定優先於上方的一般設定。",
},
companion_cancel_mark_breed_health_threshold_description = {
en = "Set Auto Cancel Cyber-Mastiff Mark Health Threshold for this enemy.\n\n" ..
"Set to " .. highlight("0") .. " to disable.\n" ..
"Does not affect " .. highlight("manual") .. " marks.",
["zh-cn"] = "为所选敌人设置自动取消智能獒犬标记生命阈值。\n\n" ..
"设置为" .. highlight("0") .. "以禁用。\n" ..
"对" .. highlight("手动") .. "标记无效。",
["zh-tw"] = "設定此敵人的自動取消電子獒犬標記生命值門檻。\n\n" ..
"設為" .. highlight("0") .. "可停用。\n" ..
"不影響" .. highlight("手動") .. "標記。",
},
companion_cancel_mark_breed_time_threshold_description = {
en = "Set Auto Cancel Cyber-Mastiff Mark Time Threshold for this enemy.\n\n" ..
"Set to " .. highlight("0") .. " to disable.\n" ..
"Does not affect " .. highlight("manual") .. " marks.",
["zh-cn"] = "为所选敌人设置自动取消智能獒犬标记时间阈值。\n\n" ..
"设置为" .. highlight("0") .. "以禁用。\n" ..
"对" .. highlight("手动") .. "标记无效。",
["zh-tw"] = "設定此敵人的自動取消電子獒犬標記時間門檻。\n\n" ..
"設為" .. highlight("0") .. "可停用。\n" ..
"不影響" .. highlight("手動") .. "標記。",
},
companion_cancel_mark_breed_distance_threshold_description = {
en = "Set Auto Cancel Cyber-Mastiff Mark Distance Threshold for this enemy.\n\n" ..
"Set to " .. highlight("0") .. " to disable.\n" ..
"Does not affect " .. highlight("manual") .. " marks.",
["zh-cn"] = "为所选敌人设置自动取消智能獒犬标记距离阈值。\n\n" ..
"设置为" .. highlight("0") .. "以禁用。\n" ..
"对" .. highlight("手动") .. "标记无效。",
["zh-tw"] = "設定此敵人的自動取消電子獒犬標記距離門檻。\n\n" ..
"設為" .. highlight("0") .. "可停用。\n" ..
"不影響" .. highlight("手動") .. "標記。",
},
companion_mark_max_distance = {
en = "Player Max Distance",
["zh-cn"] = "玩家最大距离",
["zh-tw"] = "玩家最大距離",
},
companion_mark_max_distance_tooltip = {
en = "Restrict the maximum distance between " .. highlight("player") .. " and a target that can be marked by the Companion Auto-Mark.\n\n" ..
"Set to " .. highlight("0") .. " to disable.",
["zh-cn"] = "限制伙伴自动标记系统可标记的目标与" .. highlight("玩家") .. "之间的最大距离。\n\n" ..
"设置为" .. highlight("0") .. "以禁用。",
["zh-tw"] = "限制同伴自動標記系統可標記的目標與" .. highlight("玩家") .. "之間的最大距離。\n\n" ..
"設為" .. highlight("0") .. "可停用",
},
-- cryptic settings
cryptic_settings = {
en = "Skitarii Settings",
["zh-cn"] = "护教军设置",
["zh-tw"] = "護教軍設定",
},
servo_skull_mark_keybind = {
en = "Servo-Skull Mark Keybind",
["zh-cn"] = "伺服颅骨标记按键",
["zh-tw"] = "伺服顱骨標記按鍵",
},
servo_skull_mark_keybind_description = {
en = "Dedicated key for Servo-Skull Mark. As Skitarii, you can now use both normal enemy mark and Servo-Skull mark at the same time.\n\n" ..
"When " .. highlight("Companion Target Tag") .. " is set to " .. highlight("Press Once") .. ", this function becomes a normal enemy mark.",
["zh-cn"] = "伺服颅骨标记专用按键,现在你可以作为护教军,同时使用普通敌人标记和伺服颅骨标记了。\n\n" ..
"当" .. highlight("伙伴目标标记") .. "设置为" .. highlight("按一次") .. "时,此功能变为普通敌人标记。",
["zh-tw"] = "伺服顱骨標記專用按鍵。身為護教軍,你現在可同時使用一般敵人標記與伺服顱骨標記。\n\n" ..
"當" .. highlight("同伴目標標記方式") .. "設為" .. highlight("按一次") .. "時,此功能會變為一般敵人標記。",
},
servo_skull_mark_ignore_unaggroed_description = {
en = "When enabled, Servo-Skull Auto-Mark will not mark enemies that are not alerted.",
["zh-cn"] = "当启用时,伺服颅骨自动标记将不会标记未警觉的敌人。",
["zh-tw"] = "當啟用時,伺服顱骨自動標記將不會標記未觸發警戒的敵人。",
},
servo_skull_lose_sight_tolerance = {
en = "Out of Sight Tolerance",
["zh-cn"] = "视野丢失容忍时间",
["zh-tw"] = "視野丟失容忍時間",
},
servo_skull_lose_sight_tolerance_tooltip = {
en = "Cancel Servo-Skull marks when your Servo-Skull loses sight of the target for longer than your selected time (in seconds).\n\n" ..
"Set to " .. highlight("0") .. " to disable.\n" ..
"Does not affect " .. highlight("manual") .. " marks.",
["zh-cn"] = "当你的伺服颅骨失去目标视野超过所选时间(单位:秒)时,取消伺服颅骨标记。\n\n" ..
"设置为" .. highlight("0") .. "以禁用。\n" ..
"对" .. highlight("手动") .. "标记无效。",
["zh-tw"] = "當你的伺服顱骨失去目標視野超過設定秒數時,取消伺服顱骨標記。\n\n" ..
"設為" .. highlight("0") .. "可停用。\n" ..
"不影響" .. highlight("手動") .. "標記。",
},
hack_mark_keybind = {
en = "Data Interrogation Keybind",
["zh-cn"] = "数据查询按键",
["zh-tw"] = "資料查詢按鍵",
},
hack_mark_keybind_description = {
en = "Dedicated key for Sending the Servo-Skull to hack the minigame.",
["zh-cn"] = "用于指派伺服颅骨黑入数据查询小游戏的专用按键。",
["zh-tw"] = "用於指派伺服顱骨黑入資料查詢小遊戲的專用按鍵。",
},
auto_hack = {
en = "Auto Data Interrogation",
["zh-cn"] = "自动数据查询",
["zh-tw"] = "自動資料查詢",
},
auto_hack_description = {
en = "Automatically sends your Servo-Skull to hack the minigame when you aim at a hackable objective",
["zh-cn"] = "当你瞄准一个数据查询小游戏时,自动派遣伺服颅骨前去黑入。",
["zh-tw"] = "當你瞄準一個資料查詢小遊戲時,自動派遣伺服顱骨前去黑入。",
},
disable_auto_hack_for_noospheric_command = {
en = "Disable Auto Data Interrogation When Noospheric Command Talent is Equiped",
["zh-cn"] = "当装备星语指令时禁用自动数据查询",
["zh-tw"] = "當裝備心智網指令時停用自動資料查詢",
},
capacitance_retention = {
en = "Capacitance Retention",
["zh-cn"] = "电容保留",
["zh-tw"] = "電容量保留",
},
capacitance_retention_description = {
en = "While the Noospheric Command talent is active, all Servo-Skull Auto-Mark features (including Noospheric Command Boost) are disabled when remaining capacitance drops below the configured threshold.\n\n" ..
"This threshold supports negative values (including -0):\n" ..
"Non-negative values are checked directly against remaining capacitance.\n" ..
"For negative values, the actual threshold equals maximum ability charges plus the configured value.\n\n" ..
"Remaining capacitance is calculated as ability charge count plus current capacitance percentage.",
["zh-cn"] = "当装备星语指令天赋时,若剩余电容低于所选阈值,将禁用所有伺服颅骨自动标记功能,包括星语指令增强。\n\n" ..
"本阈值支持设置为负值(含-0):\n" ..
"阈值为非负数时,直接以剩余电容数值判定。\n" ..
"阈值为负数时,实际阈值等于技能最大充能次数加上设定值。\n\n" ..
"剩余电容等于技能充能次数加上当前电容百分比。",
["zh-tw"] = "當啟用心智網指令時,若剩餘電容量低於所選門檻,將停用所有伺服顱骨自動標記功能,包含心智網指令強化。\n\n" ..
"本門檻支援設定為負值(含-0):\n" ..
"門檻為非負數時,直接以剩餘電容量數值判定。\n" ..
"門檻為負數時,實際門檻等於技能最大充能次數加上設定值。\n\n" ..
"剩餘電容量等於技能充能次數加上當前電容量百分比。",
},
capacitance_retention_elite_threshold_description = {
en = "Set Capacitance Retention Threshold for elites.",
["zh-cn"] = "为精英敌人设置电容保留阈值。",
["zh-tw"] = "設定精英敵人的電容保留門檻。",
},
capacitance_retention_special_threshold_description = {
en = "Set Capacitance Retention Threshold for specialists.",
["zh-cn"] = "为专家敌人设置电容保留阈值。",
["zh-tw"] = "針對專家敵人的電容量,設定保留門檻。",
},
capacitance_retention_boss_threshold_description = {
en = "Set Capacitance Retention Threshold for bosses.",
["zh-cn"] = "为Boss设置电容保留阈值。",
["zh-tw"] = "針對Boss的電容量,設定保留門檻。",
},
capacitance_retention_breed_threshold = {
en = "Capacitance Retention",
["zh-cn"] = "电容保留",
["zh-tw"] = "電容量門檻",
},
capacitance_retention_breed_threshold_description = {
en = "Set Capacitance Retention Threshold for this enemy.",
["zh-cn"] = "为所选敌人设置电容保留阈值。",
["zh-tw"] = "設定此敵人的電容保留門檻。",
},
noospheric_command_boost = {
en = "Noospheric Command Boost",
["zh-cn"] = "星语指令增强",
["zh-tw"] = "心智網指令強化",
},
noospheric_command_boost_description = {
en = "Automatically re-marks marked targets to extend the Noospheric Command effect.\n\n" ..
"Re-marking occurs at intervals equal to the effect's duration, and only triggers when the target is within the Servo-Skull's line of sight.",
["zh-cn"] = "自动对已标记目标进行重复标记,以延长星语指令的效果。\n\n" ..
"重复标记间隔为星语指令的持续时间,只有当目标在伺服颅骨视野内时才会进行标记。",
["zh-tw"] = "自動重新標記已標記目標,以延長心智網指令效果。\n\n" ..
"重新標記間隔等同於效果持續時間,且僅在目標位於伺服顱骨視線內時觸發。",
},
noospheric_command_boost_elite_description = {
en = "Enable Noospheric Command Boost for elites.",
["zh-cn"] = "为精英敌人启用星语指令增强",
["zh-tw"] = "為精英敵人啟用心智網指令強化。",
},
noospheric_command_boost_special_description = {
en = "Enable Noospheric Command Boost for specialists.",
["zh-cn"] = "为专家敌人启用星语指令增强",
["zh-tw"] = "為專家敵人啟用心智網指令強化。",
},
noospheric_command_boost_boss_description = {
en = "Enable Noospheric Command Boost for bosses.",
["zh-cn"] = "为Boss启用星语指令增强",
["zh-tw"] = "為Boss啟用心智網指令強化。",
},
noospheric_command_boost_breed_toggle = {
en = "Noospheric Command",
["zh-cn"] = "星语指令",
["zh-tw"] = "心智網指令",
},
noospheric_command_boost_breed_toggle_description = {
en = "Enable/Disable Noospheric Command Boost for this enemy.",
["zh-cn"] = "为所选敌人启用/禁用星语指令增强。",
["zh-tw"] = "為所選敵人啟用/停用心智網指令強化。",
},
-- veteran settings
veteran_settings = {
en = "Veteran Settings",
["zh-cn"] = "老兵设置",
["zh-tw"] = "老兵設定",
},
focus_target_overwrite = {
en = "Focus Target Overwrite",
["zh-cn"] = "聚焦目标覆盖",
["zh-tw"] = "專注目標覆蓋",
},
focus_target_overwrite_description = {
en = highlight("Off") .. ": Enemie marked by Focus Target will not be re-marked.\n" ..
highlight("On") .. ": If the player's Focus Target stacks exceed those applied to the enemy, and the stack difference is greater than or equal to the option 'Focus Target Overwrite Delta' or the stacks are at max, the Focus Target mark will be reapplied.",
["zh-cn"] = highlight("关闭") .. ":已被聚焦目标标记的敌人,不会再次被标记。\n" ..
highlight("开启") .. ":当玩家自身聚焦目标层数高于敌人已被施加的层数,且层数差大于等于下方选项「聚焦目标覆盖最小层数差」或自身层数已满时,将重新施加聚焦目标标记。",
["zh-tw"] = highlight("關閉") .. ":已被專注目標標記的敵人,不會再次被標記。\n" ..
highlight("開啟") .. ":當玩家自身專注目標層數高於敵人已被施加的層數,且層數差大於等於下方選項「專注目標覆蓋最小層數差」或自身層數已滿時,將重新施加專注目標標記。",
},
focus_target_overwrite_delta = {
en = "Focus Target Overwrite Delta",
["zh-cn"] = "聚焦目标覆盖最小层数差",
["zh-tw"] = "專注目標覆蓋最小層數差",
},
focus_target_ignore_unaggroed_description = {
en = "When enabled, Focus Target will not mark enemies that are not alerted.",
["zh-cn"] = "当启用时,聚焦目标将不会标记未警觉的敌人。",
["zh-tw"] = "當啟用時,專注目標將不會標記未觸發警戒的敵人。",
},
focus_target_switch = {
en = "Switch Target on Attack",
["zh-cn"] = "攻击时切换目标",
["zh-tw"] = "攻擊時切換目標",
},
focus_target_switch_description = {
en = "When the player is attacking, the focus target mark will switch to the aimed target.",
["zh-cn"] = "当进行攻击时,聚焦目标将标记当前瞄准的敌人。",
["zh-tw"] = "進行攻擊時,專注目標將標記當前瞄準的敵人。",
},
focus_target_switch_override_manual = {
en = "Override Manual",
["zh-cn"] = "覆盖手动标记",
["zh-tw"] = "覆蓋手動標記",
},
focus_target_switch_override_manual_description = {
en = highlight("Off") .. ": Switch-Target stops when a manual mark is present.\n" ..
highlight("On") .. ": Switch-Target continues to find new targets even when a manual mark is present.",
["zh-cn"] = highlight("关闭") .. ":手动标记存在时,切换目标将停止。\n" ..
highlight("开启") .. ":即使当前标记为手动标记,切换目标也会继续寻找新的目标。",
["zh-tw"] = highlight("關閉") .. ":當存在手動標記時,切換目標會停止。\n" ..
highlight("開啟") .. ":即使目前有手動標記,切換目標仍會持續尋找新目標。",
},
focus_target_switch_melee = {
en = "Melee Weapon",
["zh-cn"] = "近战武器",
["zh-tw"] = "近戰武器",
},
focus_target_switch_range = {
en = "Ranged Weapon",
["zh-cn"] = "远程武器",
["zh-tw"] = "遠程武器",
},
-- class settings
auto_mark_settings = {
en = "Auto Mark Settings",
["zh-cn"] = "自动标记设置",
["zh-tw"] = "自動標記設定",
},
class_selection = {
en = "Class",
["zh-cn"] = "职业",
["zh-tw"] = "職業",
},
class_selection_description = {
en = "Normal enemy marks for all classes, plus special marks for certain classes (Cyber-Mastiff, Servo-Skull, Focus Target).",
["zh-cn"] = "所有职业的普通敌人标记,以及某些职业的特殊标记(智能獒犬、伺服颅骨、聚焦目标)。",
["zh-tw"] = "所有職業的一般敵人標記,以及特定職業的特殊標記(電子獒犬、伺服顱骨、專注目標)。",
},
toggle_class = {
en = "Toggle",
["zh-cn"] = "开关",
["zh-tw"] = "開關",
},
toggle_class_description = {
en = "Toggle Auto-Mark for the selected mark type.",
["zh-cn"] = "开启/关闭所选标记类型的自动标记功能。",
["zh-tw"] = "啟用或停用所選標記類型的自動標記功能。",
},
interval = {
en = "Interval",
["zh-cn"] = "间隔时间",
["zh-tw"] = "間隔時間",
},
interval_description = {
en = "Minimum interval after a mark expires before Auto-Mark marks the next target.\n\nUnit: seconds.",
["zh-cn"] = "设置标记消失后,执行下一次标记的最短时间间隔。\n\n单位:秒。",
["zh-tw"] = "設定標記消失後,執行下一次標記的最短時間間隔。\n\n單位:秒。",
},
cooldown = {
en = "Cooldown",
["zh-cn"] = "冷却时间",
["zh-tw"] = "冷卻時間",
},
cooldown_description = {
en = "Cooldown after a mark is applied before Auto-Mark marks the next target.\n\nUnit: seconds.",
["zh-cn"] = "设置标记生成后,自动标记下一个目标前的冷却时间。\n\n单位:秒。",
["zh-tw"] = "設定標記生成後,自動標記下一個目標前的冷卻時間。\n\n單位:秒。",
},
reset_cooldown = {
en = "Reset Cooldown",
["zh-cn"] = "刷新冷却",
["zh-tw"] = "重置冷卻",
},
reset_cooldown_description = {
en = "Resets Auto-Mark cooldown when the last mark disappears.",
["zh-cn"] = "当上个标记消失时,刷新自动标记冷却时间。",
["zh-tw"] = "當上個標記消失時,重置自動標記冷卻時間。",
},
mark_limit = {
en = "Mark Limit",
["zh-cn"] = "标记限制",
["zh-tw"] = "標記限制",
},
mark_limit_description = {
en = "Stops Auto-Mark when the last mark is present.",
["zh-cn"] = "当上个标记存在时,停止自动标记。",
["zh-tw"] = "當上個標記存在時,停止自動標記。",
},
min_range = {
en = "Min Range",
["zh-cn"] = "最小范围",
["zh-tw"] = "最小範圍",
},
min_range_description = {
en = "Unit: Meters",
["zh-cn"] = "单位:米",
["zh-tw"] = "單位:公尺",
},
max_range = {
en = "Max Range",
["zh-cn"] = "最大范围",
["zh-tw"] = "最大範圍",
},
max_range_description = {
en = "Unit: Meters",
["zh-cn"] = "单位:米",
["zh-tw"] = "單位:公尺",
},
max_angle = {
en = "Max Angle",
["zh-cn"] = "最大角度",
["zh-tw"] = "最大角度",
},
max_angle_description = {
en = "Maximum angle in degrees between your crosshair and markable enemies. \n\nSet to " .. highlight("0") .. " to use vanilla raycast detection.",
["zh-cn"] = "可标记敌人与准星间的最大角度。\n\n设置为" .. highlight("0") .. "时将使用游戏原版射线检测。",
["zh-tw"] = "可標記敵人與準星間的最大角度。\n\n設為" .. highlight("0") .. "時將使用遊戲原版射線偵測。",
},
override_manual = {
en = "Override Manual",
["zh-cn"] = "覆盖手动标记",
["zh-tw"] = "覆蓋手動標記",
},
override_manual_description = {
en = highlight("Off") .. ": Auto-mark stops when a manual mark is present.\n" ..
highlight("On") .. ": Auto-mark continues to find new targets even when a manual mark is present.",
["zh-cn"] = highlight("关闭") .. ":手动标记存在时,自动标记将停止。\n" ..
highlight("开启") .. ":即使当前标记为手动标记,自动标记也会继续寻找新的目标。",
["zh-tw"] = highlight("關閉") .. ":當存在手動標記時,自動標記會停止。\n" ..
highlight("開啟") .. ":即使目前有手動標記,自動標記仍會持續尋找新目標。",
},
priority_switch = {
en = "Priority Switch",
["zh-cn"] = "优先级切换",
["zh-tw"] = "優先順序切換",
},
priority_switch_description = {
en = "Switches to the aimed target if it has higher priority than the current marked target.",
["zh-cn"] = "当正在瞄准的目标优先级高于已被标记的目标时,切换至瞄准的目标。",
["zh-tw"] = "當正在瞄準的目標優先順序高於已標記的目標時,切換至瞄準的目標。",
},
toggle_elite = {
en = "Toggle Elite",
["zh-cn"] = "精英开关",
["zh-tw"] = "精英開關",
},
toggle_elite_description = {
en = "Enable/Disable Auto-Mark for elites.",
["zh-cn"] = "为精英敌人启用/禁用自动标记功能。",
["zh-tw"] = "啟用或停用精英敵人的自動標記功能。",
},
toggle_special = {
en = "Toggle Specialist",
["zh-cn"] = "专家开关",
["zh-tw"] = "專家開關",
},
toggle_special_description = {
en = "Enable/Disable Auto-Mark for specialists.",
["zh-cn"] = "为专家敌人启用/禁用自动标记功能。",
["zh-tw"] = "啟用或停用專家敵人的自動標記功能。",
},
toggle_boss = {
en = "Toggle Boss",
["zh-cn"] = "Boss开关",
["zh-tw"] = "Boss開關",
},
toggle_boss_description = {
en = "Enable/Disable Auto-Mark for bosses.",
["zh-cn"] = "为Boss启用/禁用自动标记功能。",
["zh-tw"] = "為Boss啟用或停用自動標記功能。",
},
toggle_other = {
en = "Toggle Other",
["zh-cn"] = "其他开关",
["zh-tw"] = "其他開關",
},
toggle_other_description = {
en = "Enable/Disable Auto-Mark for other enemies.",
["zh-cn"] = "为其他敌人启用/禁用自动标记功能。",
["zh-tw"] = "啟用或停用其他敵人的自動標記功能。",
},
priority_off = {
en = "Off",
["zh-cn"] = "关闭",
["zh-tw"] = "關閉",
},
priority_lowest = {
en = "Priority Lowest",
["zh-cn"] = "最低优先级",
["zh-tw"] = "最低優先",
},
priority_low = {
en = "Priority Low",
["zh-cn"] = "低优先级",
["zh-tw"] = "低優先",
},
priority_medium = {
en = "Priority Medium",
["zh-cn"] = "中优先级",
["zh-tw"] = "中優先",
},
priority_high = {
en = "Priority High",
["zh-cn"] = "高优先级",
["zh-tw"] = "高優先",
},
priority_highest = {
en = "Priority Highest",
["zh-cn"] = "最高优先级",
["zh-tw"] = "最高優先",
},
adamant_companion = {
en = "Arbitrator Cyber-Mastiff",
["zh-cn"] = "法务官 智能獒犬",
["zh-tw"] = "法務官 電子獒犬",
},
veteran_focus_target = {
en = "Veteran Focus Target",
["zh-cn"] = "老兵聚焦目标",
["zh-tw"] = "老兵專注目標",
},
cryptic_servo_skull = {
en = "Skitarius Servo-Skull",
["zh-cn"] = "护教军士兵 伺服颅骨",
["zh-tw"] = "護教軍 伺服顱骨",
},
apply_to_all_classes = {
en = "Apply to All Classes",
["zh-cn"] = "应用于所有职业",
["zh-tw"] = "套用至所有職業",
},
apply_button = {
en = "Apply to All",
["zh-cn"] = "应用于所有职业",
["zh-tw"] = "套用至全部",
},
apply_button_description = {
en =
"Apply settings from the selected mark type to either all mark types or only normal enemy marks across all classes.",
["zh-cn"] = "将所选标记类型的设置应用于所有标记类型或者只应用于所有职业的普通敌人标记。",
["zh-tw"] = "將所選標記類型的設定套用到所有標記類型,或僅套用到所有職業的一般敵人標記。",
},
reset_auto_mark_settings = {
en = "Reset Auto Mark Settings",
["zh-cn"] = "重置自动标记设置",
["zh-tw"] = "重置自動標記設定",
},
reset_button = {
en = "Reset to Defaults",
["zh-cn"] = "重置为默认值",
["zh-tw"] = "重設為預設值",
},
reset_button_description = {
en = "Reset mark settings to defaults for all mark types or the selected mark type.",
["zh-cn"] = "将所有标记类型或所选标记类型的设置重置为默认值。",
["zh-tw"] = "將所有標記類型或所選標記類型的設定重設為預設值。",
},
blank = {
en = " ",
["zh-cn"] = " ",
["zh-tw"] = " ",
},
reset = {
en = "Reset",
["zh-cn"] = "重置",
["zh-tw"] = "重設",
},
apply_to_normal = {
en = "Apply to Normal Enemy Marks",
["zh-cn"] = "应用于普通敌人标记",
["zh-tw"] = "套用到一般敵人標記",
},
apply_to_all = {
en = "Apply to All Mark Types",
["zh-cn"] = "应用于所有标记类型",
["zh-tw"] = "套用到所有標記類型",
},
reset_current = {
en = "Reset Selected Mark Settings",
["zh-cn"] = "重置所选标记设置",
["zh-tw"] = "重設所選標記設定",
},
reset_all = {
en = "Reset All Mark Settings",
["zh-cn"] = "重置所有标记设置",
["zh-tw"] = "重設所有標記設定",
},
tooltip_breed_priority = {
en = "Set the marking priority for this enemy type. Auto-Mark prioritizes targets with higher priority values.\n\n" ..
"Set to " .. highlight("0") .. " to ignore this enemy type.",
["zh-cn"] = "设置该类敌人的标记优先级。自动标记将优先标记优先级更高的目标。\n\n" ..
"设置为" .. highlight("0") .. "以忽略此类敌人。",
["zh-tw"] = "設定該類敵人的標記優先度。自動標記將優先標記優先度較高的目標。\n\n" ..
"設為" .. highlight("0") .. "可忽略此類敵人。",
},
elite = {
en = "Elite",
["zh-cn"] = "精英",
["zh-tw"] = "精英",
},
elite_tooltip = {
en = "Enable for elites.",
["zh-cn"] = "为精英敌人启用。",
["zh-tw"] = "為精英敵人啟用。",
},
special = {
en = "Specialist",
["zh-cn"] = "专家",
["zh-tw"] = "專家",
},
special_tooltip = {
en = "Enable for specialists.",
["zh-cn"] = "为专家敌人启用。",
["zh-tw"] = "為專家敵人啟用。",
},
boss = {
en = "Boss",
["zh-cn"] = "Boss",
["zh-tw"] = "Boss",
},
boss_tooltip = {
en = "Enable for bosses.",
["zh-cn"] = "为Boss敌人启用。",
["zh-tw"] = "為Boss敵人啟用。",
},
sticky_targeting = {
en = "Mark Stickiness",
["zh-cn"] = "标记粘滞",
["zh-tw"] = "標記黏滯",
},
sticky_targeting_tooltip = {
en = "Enable for the selected enemy type. If a marked enemy has Mark Stickiness enabled, AUTO-MARK will pause target switching caused by priority switch.",
["zh-cn"] = "为所选敌人类型启用标记粘滞。如果被标记的敌人开启了标记粘滞功能,自动标记会暂停因优先级切换导致的切换目标行为。",
["zh-tw"] = "為所選敵人類型啟用標記黏滯。如果被標記的敵人開啟了標記黏滯功能,自動標記會暫停因優先順序切換導致的切換目標行為。",
},
servo_skull_cancel_mark = {
en = "Auto Cancel Servo-Skull Mark",
["zh-cn"] = "自动取消伺服颅骨标记",
["zh-tw"] = "自動取消伺服顱骨標記",
},
servo_skull_health_threshold_tooltip = {
en = "Cancel the Servo-Skull mark when the health of your Servo-Skull's current attack target falls below your selected health percentage.\n\n" ..
"Set to " .. highlight("0") .. " to disable.\n" ..
"Does not affect " .. highlight("manual") .. " marks.",
["zh-cn"] = "当你的伺服颅骨的攻击目标的血量低于所选百分比时,取消该目标的伺服颅骨标记。\n\n" ..
"设置为" .. highlight("0") .. "以禁用。\n" ..
"对" .. highlight("手动") .. "标记无效。",
["zh-tw"] = "當你的伺服顱骨目前攻擊目標的生命值低於設定百分比時,取消該目標的伺服顱骨標記。\n\n" ..
"設為" .. highlight("0") .. "可停用。\n" ..
"不影響" .. highlight("手動") .. "標記。",
},
meter = {
en = "m",
["zh-cn"] = "米",
["zh-tw"] = "公尺",
},
percent = {
en = "%%",
},
degree = {
en = "°",
},
stack = {
en = "stack",
["zh-cn"] = "层",
["zh-tw"] = "层",
},
second = {
en = "s",
["zh-cn"] = "秒",
["zh-tw"] = "秒",
},
hold_to_reset = {
en = "to Reset",
["zh-cn"] = "重置",
["zh-tw"] = "重設",
},
}
local function is_localization_valid(text)
return not string.find(text, "unlocalized")
end
local function add_breed_localization(breed_name, breed_data, is_passive)
local text = Localize(breed_data.is_boss and type(breed_data.boss_display_name) == "string" and breed_data.boss_display_name or breed_data.display_name)
if is_localization_valid(text) then
if is_passive then
localization[breed_name .. "_passive"] = {
en = text .. " (Dormant)",
["zh-cn"] = text .. "(休眠)",
["zh-tw"] = text .. "(休眠)",
}
elseif breed_name == "chaos_mutator_ritualist" then
localization[breed_name] = {
en = "Hexbound " .. text,
["zh-cn"] = "咒缚" .. text,
["zh-tw"] = "魔縛" .. text,
}
elseif breed_name ~= "chaos_mutator_daemonhost" and string.find(breed_name, "mutator") then
localization[breed_name] = {
en = text .. " (Mutator)",
["zh-cn"] = text .. "(变异体)",
["zh-tw"] = text .. "(變異體)",
}
else
localization[breed_name] = { en = text }
end
else
localization[breed_name] = { en = breed_name }
end
end
for breed_name, breed_data in pairs(Breeds) do
if Breed.is_minion(breed_data) and breed_data.unit_template_name == "minion" and breed_data.smart_tag_target_type == "breed" and breed_data.faction_name ~= "imperium" then
add_breed_localization(breed_name, breed_data)
if breed_data.tags.witch then
add_breed_localization(breed_name, breed_data, true)
end
end
end
for class_name, archetype in pairs(Archetypes) do
local text = Localize(archetype.archetype_name)
localization[class_name] = {
en = text
}
end
return localization
@@ -0,0 +1,410 @@
---@class AutoMarkMod:DMFMod
local mod = get_mod("AutoMark")
local context = mod.context
-- Global Cache
local CLASS = CLASS
local ScriptUnit = ScriptUnit
local Managers = Managers
-- Get Extensions
local function get_player_talent_extension()
local player = Managers.player:local_player_safe(1)
return player and ScriptUnit.extension(player.player_unit, "talent_system")
end
local function get_player_data_extension()
local player = Managers.player:local_player_safe(1)
return player and ScriptUnit.extension(player.player_unit, "unit_data_system")
end
local function get_smart_targeting_extension()
local player = Managers.player:local_player_safe(1)
return player and ScriptUnit.extension(player.player_unit, "smart_targeting_system")
end
local function get_companion_spawner_extension()
local player = Managers.player:local_player_safe(1)
return player and ScriptUnit.extension(player.player_unit, "companion_spawner_system")
end
local function get_player_ability_extension()
local player = Managers.player:local_player_safe(1)
return player and ScriptUnit.extension(player.player_unit, "ability_system")
end
-- Track Player
local function init_player()
local player = Managers.player:local_player_safe(1)
if player then
context.player = player
end
local class_name = player and player:archetype_name()
if class_name then
context.class_name = class_name
end
end
-- Track Player Components
local function init_player_components(player_data_extension)
player_data_extension = player_data_extension or get_player_data_extension()
if not player_data_extension then
return
end
context.talent_resource_component = player_data_extension:read_component("talent_resource")
context.disabled_character_state_component = player_data_extension:read_component("disabled_character_state")
context.locomotion_component = player_data_extension:read_component("locomotion")
mod:print_debug("Init talent_resource_component")
end
local function destroy_player_components()
context.talent_resource_component = nil
context.disabled_character_state_component = nil
context.locomotion_component = nil
end
-- Track Player Extensions
local function init_player_extensions()
local smart_targeting_extension = get_smart_targeting_extension()
if smart_targeting_extension then
context.smart_targeting_extension = smart_targeting_extension
end
local companion_spawner_extension = get_companion_spawner_extension()
if companion_spawner_extension then
context.companion_spawner_extension = companion_spawner_extension
end
local player_ability_extension = get_player_ability_extension()
if player_ability_extension then
context.player_ability_extension = player_ability_extension
end
end
local function init_hud_elements()
local hud = Managers.ui:get_hud()
local hud_element_smart_tagging = hud and hud:element("HudElementSmartTagging")
if hud_element_smart_tagging then
context.hud_element_smart_tagging = hud_element_smart_tagging
end
end
-- Talent Names
local TALENT_NAMES = {
LONE_WOLF = "adamant_disable_companion",
EXECUTION_ORDER = "adamant_execution_order",
FOCUS_TARGET = "veteran_improved_tag",
FOCUSED_FIRE = "veteran_improved_tag_more_damage",
FORCE_FIELD = "cryptic_grenade_ability_force_field",
ARC_GRENADE = "cryptic_grenade_ability_arc_grenade",
NOOSPHERIC_COMMAND = "cryptic_servo_skull_improved_tagging",
}
-- Talent Settings
local talent_settings = require("scripts/settings/talent/talent_settings")
local veteran_talent_settings = talent_settings.veteran
local veteran_tag_max_stacks = veteran_talent_settings.veteran_tag.max_stacks
local veteran_tag_max_stacks_talent = veteran_talent_settings.veteran_tag.max_stacks_talent
-- Track Player Talent Status
local function init_player_talent_status(player_talent_extension)
player_talent_extension = player_talent_extension or get_player_talent_extension()
if not player_talent_extension then
return
end
local talents = player_talent_extension._talents
-- has companion
context.has_companion = context.class_name == "adamant" and not talents[TALENT_NAMES.LONE_WOLF]
-- has execution order
context.has_execution_order = context.class_name == "adamant" and not not talents[TALENT_NAMES.EXECUTION_ORDER]
-- has focus target
context.has_focus_target = context.class_name == "veteran" and not not talents[TALENT_NAMES.FOCUS_TARGET]
-- has focused fire
local has_focused_fire = not not talents[TALENT_NAMES.FOCUSED_FIRE]
-- focus target max stacks
context.focus_target_max_stacks = context.class_name == "veteran" and context.has_focus_target and (has_focused_fire and veteran_tag_max_stacks_talent or veteran_tag_max_stacks) or 0
context.has_servo_skull = context.class_name == "cryptic" and not talents[TALENT_NAMES.FORCE_FIELD] and not talents[TALENT_NAMES.ARC_GRENADE]
context.has_noospheric_command = context.class_name == "cryptic" and not not talents[TALENT_NAMES.NOOSPHERIC_COMMAND]
mod:print_debug("has companion", context.has_companion)
mod:print_debug("has execution order", context.has_execution_order)
mod:print_debug("has focus target", context.has_focus_target)
mod:print_debug("focus target max stacks", context.focus_target_max_stacks)
mod:print_debug("has servo skull", context.has_servo_skull)
mod:print_debug("has noospheric command", context.has_noospheric_command)
end
-- Track Systems
local function init_systems()
local smart_tag_system = Managers.state.extension and Managers.state.extension:system("smart_tag_system")
if smart_tag_system then
context.smart_tag_system = smart_tag_system
end
local outline_system = Managers.state.extension and Managers.state.extension:system("outline_system")
if outline_system then
context.outline_system = outline_system
end
local smoke_fog_system = Managers.state.extension and Managers.state.extension:system("smoke_fog_system")
if smoke_fog_system then
context.smoke_fog_system = smoke_fog_system
end
local force_field_system = Managers.state.extension and Managers.state.extension:system("force_field_system")
if force_field_system then
context.force_field_system = force_field_system
end
local broadphase_system = Managers.state.extension and Managers.state.extension:system("broadphase_system")
if broadphase_system then
context.broadphase_system = broadphase_system
end
local side_system = Managers.state.extension and Managers.state.extension:system("side_system")
if side_system then
context.side_system = side_system
end
end
-- Track Game Settings
local function init_game_settings()
context.companion_command_tap = Managers.save:account_data().input_settings.companion_command_tap
end
function mod:init_game_settings()
init_game_settings()
end
local INVALID_MODE_NAMES = {
training_grounds = true,
hub = true,
prologue_hub = true,
}
-- Check if player is in hub
function mod:check_game_mode()
local game_mode_manager = Managers.state.game_mode
local game_mode_name = game_mode_manager and game_mode_manager:game_mode_name()
if game_mode_name and not INVALID_MODE_NAMES[game_mode_name] then
context.game_mode_valid = true
end
mod:print_debug("Game mode:", game_mode_name, context.game_mode_valid and "valid" or "invalid")
end
-- Init all params
function mod:init_context()
-- Init Player
init_player()
-- Init Player Components
init_player_components()
-- Init Extensions
init_player_extensions()
-- Init HUD Elements
init_hud_elements()
-- Init Talents Status
init_player_talent_status()
-- Init Systems
init_systems()
-- Init Game Settings
init_game_settings()
end
-- Cache Player
mod:hook_safe(CLASS.HumanPlayer, "init",
function(self)
if self.viewport_name == "player1" then
mod:print_debug("Init HumanPlayer")
context.player = self
end
end)
mod:hook_safe(CLASS.HumanPlayer, "destroy",
function(self)
if self.viewport_name == "player1" then
mod:print_debug("Destroy HumanPlayer")
context.player = nil
end
end)
-- Get Archetype Name When Player Set Profile
mod:hook_safe(CLASS.HumanPlayer, "set_profile",
function(self)
if self.viewport_name == "player1" then
context.class_name = self:archetype_name()
mod:print_debug("Class name", context.class_name)
end
end)
-- Player Unit Data Hook for Components
mod:hook_safe(CLASS.PlayerUnitDataExtension, "init",
function(self)
if self._player.viewport_name == "player1" then
mod:print_debug("Init PlayerUnitDataExtension")
init_player_components(self)
end
end)
mod:hook_safe(CLASS.PlayerUnitDataExtension, "destroy",
function(self)
if self._player.viewport_name == "player1" then
mod:print_debug("Destroy PlayerUnitDataExtension")
destroy_player_components()
end
end)
-- Hook Extensions for Cache
mod:hook_safe(CLASS.PlayerUnitSmartTargetingExtension, "init",
function(self)
if self._player.viewport_name == "player1" then
mod:print_debug("Init PlayerUnitSmartTargetingExtension")
context.smart_targeting_extension = self
end
end)
mod:hook_safe(CLASS.PlayerUnitSmartTargetingExtension, "delete",
function(self)
if self._player.viewport_name == "player1" then
mod:print_debug("Delete PlayerUnitSmartTargetingExtension")
context.smart_targeting_extension = nil
end
end)
mod:hook_safe(CLASS.CompanionSpawnerExtension, "init",
function(self)
if self._owner_player.viewport_name == "player1" then
mod:print_debug("Init CompanionSpawnerExtension")
context.companion_spawner_extension = self
end
end)
mod:hook_safe(CLASS.CompanionSpawnerExtension, "destroy",
function(self)
if self._owner_player.viewport_name == "player1" then
mod:print_debug("Destroy CompanionSpawnerExtension")
context.companion_spawner_extension = nil
end
end)
mod:hook_safe(CLASS.PlayerUnitAbilityExtension, "init",
function(self)
if self._player.viewport_name == "player1" then
mod:print_debug("Init PlayerUnitAbilityExtension")
context.player_ability_extension = self
end
end)
mod:hook_safe(CLASS.PlayerUnitAbilityExtension, "delete",
function(self)
if self._player.viewport_name == "player1" then
mod:print_debug("Delete PlayerUnitAbilityExtension")
context.player_ability_extension = nil
end
end)
-- Cache HUD Elements
mod:hook_safe(CLASS.HudElementSmartTagging, "init",
function(self, parent, draw_layer, start_scale)
if self._parent._player_viewport_name == "player1" then
mod:print_debug("Init HudElementSmartTagging")
context.hud_element_smart_tagging = self
end
end)
mod:hook_safe(CLASS.HudElementSmartTagging, "destroy",
function(self, ui_renderer)
if self._parent._player_viewport_name == "player1" then
mod:print_debug("Destroy HudElementSmartTagging")
context.hud_element_smart_tagging = nil
end
end)
-- Update Talent Status
mod:hook_safe(CLASS.PlayerUnitTalentExtension, "_apply_talents",
function(self)
if self._player.viewport_name == "player1" then
init_player_talent_status(self)
end
end)
mod:hook_safe(CLASS.PlayerHuskTalentExtension, "_update_talents",
function(self)
if self._player.viewport_name == "player1" then
init_player_talent_status(self)
end
end)
-- System Cache Hook
mod:hook_safe(CLASS.SmartTagSystem, "init",
function(self)
mod:print_debug("Init SmartTagSystem")
context.smart_tag_system = self
end)
mod:hook_safe(CLASS.SmartTagSystem, "destroy",
function()
mod:print_debug("Destroy SmartTagSystem")
context.smart_tag_system = nil
end)
mod:hook_safe(CLASS.OutlineSystem, "init",
function(self)
mod:print_debug("Init OutlineSystem")
context.outline_system = self
end)
mod:hook_safe(CLASS.OutlineSystem, "destroy",
function()
mod:print_debug("Destroy OutlineSystem")
context.outline_system = nil
end)
mod:hook_safe(CLASS.SmokeFogSystem, "init",
function(self)
mod:print_debug("Init SmokeFogSystem")
context.smoke_fog_system = self
end)
mod:hook_safe(CLASS.SmokeFogSystem, "destroy",
function()
mod:print_debug("Destroy SmokeFogSystem")
context.smoke_fog_system = nil
end)
mod:hook_safe(CLASS.ForceFieldSystem, "init",
function(self)
mod:print_debug("Init ForceFieldSystem")
context.force_field_system = self
end)
mod:hook_safe(CLASS.ForceFieldSystem, "destroy",
function()
mod:print_debug("Destroy ForceFieldSystem")
context.force_field_system = nil
end)
mod:hook_safe(CLASS.BroadphaseSystem, "init",
function(self)
mod:print_debug("Init BroadphaseSystem")
context.broadphase_system = self
end)
mod:hook_safe(CLASS.BroadphaseSystem, "destroy",
function()
mod:print_debug("Destroy BroadphaseSystem")
context.broadphase_system = nil
end)
mod:hook_safe(CLASS.SideSystem, "init",
function(self)
mod:print_debug("Init SideSystem")
context.side_system = self
end)
mod:hook_safe(CLASS.SideSystem, "destroy",
function()
mod:print_debug("Destroy SideSystem")
context.side_system = nil
end)
-- Update settings when input settings changed
mod:hook_safe(CLASS.EventManager, "trigger", function(self, event_name)
if event_name == "event_on_input_settings_changed" then
mod:print_debug("input settings changed")
init_game_settings()
end
end)
@@ -0,0 +1,319 @@
---@class AutoMarkMod:DMFMod
local mod = get_mod("AutoMark")
local context = mod.context
local mark_context = mod.mark_context
local TAG_NAMES = mod.TAG_NAMES
local mod_settings = mod.settings
local companion_cancel_mark_breed_settings = mod.companion_cancel_mark_breed_settings
-- Imports
local TalentSettings = require("scripts/settings/talent/talent_settings")
local NetworkLookup = require("scripts/network_lookup/network_lookup")
local cryptic_talent_settings = TalentSettings.cryptic
local noospheric_command_duration = cryptic_talent_settings.servo_skull_shooting_tagging.duration
-- Global Cache
local CLASS = CLASS
local ScriptUnit = ScriptUnit
local Managers = Managers
-- Delay for Server Latency, Interval for Auto Mark
local AUTO_MARK_DELAY = 0.5
local AUTO_MARK_INTERVAL = 0.2
local ENEMY_TAG_DELAY = 3
local PRIORITY_SWITCH_COOLDOWN = 0.3
local FOCUS_TARGET_DELAY = 1.5
-- set delay and interval for auto mark
local function on_set_tag(tag_context)
-- mark_context.auto_mark_interval = AUTO_MARK_INTERVAL
tag_context.delay = AUTO_MARK_DELAY
tag_context.delay_times = tag_context.delay_times + 1
end
-- record manual marked unit
function mod:on_manual_mark(tag_context, target_unit)
mod:print_debug("manual mark unit:", target_unit)
tag_context.manual_unit = target_unit
tag_context.manual_unit_expired_time = mod:get_latest_fixed_time() + 1
end
-- cancel mark by tag id
function mod:cancel_mark(tag_id)
local smart_tag_system = context.smart_tag_system
if not smart_tag_system then
return
end
local player = context.player
local player_unit = player and player.player_unit
if not player_unit then
return
end
smart_tag_system:cancel_tag(tag_id, player_unit)
end
-- mark target unit with tag
function mod:set_auto_mark(tag_name, target_unit, target_tag)
local player = context.player
local player_unit = player and player.player_unit
local tag_context = mark_context[tag_name]
local smart_tag_system = context.smart_tag_system
if not player_unit or not target_unit or not tag_context or not smart_tag_system
then
return
end
local player_unit_id = Managers.state.unit_spawner:game_object_id(player_unit)
if not player_unit_id then
return
end
local target_unit_id = Managers.state.unit_spawner:game_object_id(target_unit)
if not target_unit_id then
return
end
if target_tag then
if tag_name == TAG_NAMES.COMPANION_TAG or tag_name == TAG_NAMES.VETERAN_TAG or tag_name == TAG_NAMES.SERVO_SKULL_TAG then
local template = target_tag._template
local is_enemy_mark = template and template.name == TAG_NAMES.ENEMY_TAG
if is_enemy_mark then
local tagger_player = target_tag._tagger_player
local tagger_player_unit = tagger_player and tagger_player.player_unit
if tagger_player_unit then
smart_tag_system:cancel_tag(target_tag._id, tagger_player_unit, true)
end
end
end
end
mod:print_debug("Auto Mark", tag_name, target_unit)
on_set_tag(tag_context)
local template_name_id = NetworkLookup.smart_tag_templates[tag_name]
if smart_tag_system._is_server then
local tag_id = smart_tag_system:_generate_tag_id()
local tag = smart_tag_system:_create_tag_locally(tag_id, tag_name, player_unit, target_unit)
smart_tag_system:_server_check_tag_group_limit(player_unit, tag:group())
Managers.state.game_session:send_rpc_clients("rpc_set_smart_tag", tag_id, template_name_id, player_unit_id, target_unit_id)
else
Managers.state.game_session:send_rpc_server("rpc_request_set_smart_tag", template_name_id, player_unit_id, target_unit_id)
end
end
function mod:set_manual_mark(tag_name, target_unit, target_tag)
local player = context.player
local player_unit = player and player.player_unit
local smart_tag_system = context.smart_tag_system
if not player_unit or not target_unit or not smart_tag_system then
return
end
if target_tag then
if tag_name == TAG_NAMES.COMPANION_TAG or tag_name == TAG_NAMES.VETERAN_TAG or tag_name == TAG_NAMES.SERVO_SKULL_TAG then
local template = target_tag._template
local is_enemy_mark = template and template.name == TAG_NAMES.ENEMY_TAG
if is_enemy_mark then
local tagger_player = target_tag._tagger_player
local tagger_player_unit = tagger_player and tagger_player.player_unit
if tagger_player_unit then
smart_tag_system:cancel_tag(target_tag._id, tagger_player_unit, true)
end
end
end
end
smart_tag_system:set_tag(tag_name, player_unit, target_unit)
end
mod:hook(CLASS.SmartTagSystem, "set_tag",
function(func, self, template_name, tagger_unit, target_unit, ...)
local player = context.player
if player and tagger_unit == player.player_unit then
local tag_context = mark_context[template_name]
if tag_context then
-- the unit is marked manually
mod:on_manual_mark(tag_context, target_unit)
-- set delay and interval for auto mark
on_set_tag(tag_context)
end
end
return func(self, template_name, tagger_unit, target_unit, ...)
end)
local function delay_normal_tag()
local tag_context = mark_context[TAG_NAMES.ENEMY_TAG]
if tag_context.cooldown < ENEMY_TAG_DELAY then
tag_context.cooldown = ENEMY_TAG_DELAY
end
if tag_context.priority_switch_cooldown < ENEMY_TAG_DELAY then
tag_context.priority_switch_cooldown = ENEMY_TAG_DELAY
end
end
-- Smart Tag Hook
mod:hook_safe(CLASS.SmartTag, "init",
function(self, tag_id, template, tagger_unit, target_unit, target_location, replies, is_server)
local tagger_player = self._tagger_player
if not tagger_player or tagger_player.viewport_name ~= "player1" then
return
end
local tag_name = template.name
local tag_context = mark_context[tag_name]
if not tag_context then
return
end
mod:print_debug("init smart tag", tag_name)
mark_context.auto_mark_interval = AUTO_MARK_INTERVAL
-- refresh delay and set cooldown
tag_context.tag = self
tag_context.interval = 0
tag_context.cooldown = mod:get_class_settings(tag_name).cooldown
tag_context.priority_switch_cooldown = PRIORITY_SWITCH_COOLDOWN
-- reset delay
tag_context.delay_times = tag_context.delay_times - 1
if tag_context.delay_times <= 0 then
tag_context.delay = 0
tag_context.delay_times = 0
end
-- check if the tag is manual
tag_context.is_manual = tag_context.manual_unit == target_unit
tag_context.manual_unit = nil
if tag_name == TAG_NAMES.COMPANION_TAG then
tag_context.pounce_start_time = nil
local target_data_extension = ScriptUnit.extension(target_unit, "unit_data_system")
local target_breed_data = target_data_extension and target_data_extension._breed
local breed_name = target_breed_data and target_breed_data.name
local breed_settings = companion_cancel_mark_breed_settings[breed_name]
if breed_settings and breed_settings.override then
tag_context.is_cancelable = true
else
local pounce_setting = target_breed_data and target_breed_data.companion_pounce_setting
local pounce_action = pounce_setting and pounce_setting.companion_pounce_action
if pounce_action == "human" then
tag_context.is_cancelable = mod_settings.companion_cancel_mark_human
else
tag_context.is_cancelable = mod_settings.companion_cancel_mark_non_human
end
end
delay_normal_tag()
elseif tag_name == TAG_NAMES.SERVO_SKULL_TAG then
tag_context.shoot_start_time = nil
if context.has_noospheric_command then
tag_context.noospheric_command_next_time = mod:get_latest_fixed_time() + noospheric_command_duration
else
tag_context.noospheric_command_next_time = math.huge
end
delay_normal_tag()
elseif tag_name == TAG_NAMES.VETERAN_TAG then
if tag_context.switch_melee_unit == target_unit then
tag_context.is_switch_melee = true
tag_context.is_switch_range = false
elseif tag_context.switch_range_unit == target_unit then
tag_context.is_switch_melee = false
tag_context.is_switch_range = true
else
tag_context.is_switch_melee = false
tag_context.is_switch_range = false
end
tag_context.switch_melee_unit = nil
tag_context.switch_range_unit = nil
elseif tag_name == TAG_NAMES.ENEMY_TAG then
if context.class_name == "veteran" and context.has_focus_target then
local veteran_tag_context = mark_context[TAG_NAMES.VETERAN_TAG]
veteran_tag_context.tag = self
veteran_tag_context.interval = 0
veteran_tag_context.cooldown = mod:get_class_settings(TAG_NAMES.VETERAN_TAG).cooldown
veteran_tag_context.priority_switch_cooldown = PRIORITY_SWITCH_COOLDOWN
veteran_tag_context.is_manual = tag_context.is_manual
end
end
end)
mod:hook(CLASS.SmartTag, "destroy",
function(func, self, ...)
local tag_name = self._template.name
local tag_context = mark_context[tag_name]
if not tag_context then
return func(self, ...)
end
if tag_context.tag == self then
mod:print_debug("destroy smart tag", tag_name)
tag_context.tag = nil
tag_context.is_manual = false
local class_settings = mod:get_class_settings(tag_name)
tag_context.interval = class_settings.interval
if class_settings.reset_cooldown then
tag_context.cooldown = 0
end
if tag_name == TAG_NAMES.COMPANION_TAG then
tag_context.removed_units[self._target_unit] = mod:get_latest_fixed_time() + 1.5
tag_context.pounce_start_time = nil
tag_context.is_cancelable = false
delay_normal_tag()
elseif tag_name == TAG_NAMES.SERVO_SKULL_TAG then
tag_context.removed_units[self._target_unit] = mod:get_latest_fixed_time() + 1.5
tag_context.shoot_start_time = nil
tag_context.noospheric_command_next_time = math.huge
delay_normal_tag()
elseif tag_name == TAG_NAMES.VETERAN_TAG then
tag_context.removed_units[self._target_unit] = mod:get_latest_fixed_time() + 1.5
if tag_context.is_switch_melee and tag_context.cooldown < FOCUS_TARGET_DELAY then
tag_context.cooldown = FOCUS_TARGET_DELAY
end
tag_context.is_switch_melee = false
tag_context.is_switch_range = false
elseif tag_name == TAG_NAMES.ENEMY_TAG then
if context.class_name == "veteran" and context.has_focus_target then
local veteran_tag_context = mark_context[TAG_NAMES.VETERAN_TAG]
if veteran_tag_context.tag == self then
veteran_tag_context.tag = nil
veteran_tag_context.is_manual = false
local veteran_class_settings = mod:get_class_settings(TAG_NAMES.VETERAN_TAG)
veteran_tag_context.interval = veteran_class_settings.interval
if veteran_class_settings.reset_cooldown then
veteran_tag_context.cooldown = 0
end
end
end
end
end
return func(self, ...)
end)
local SERVO_SKULL_DAMAGE_PROFILE_NAMES = {
default_companion_servo_skull_lasgun_killshot = true,
improved_companion_servo_skull_lasgun_killshot = true,
}
-- Hook for Companion Dog Attack Info
mod:hook_safe(CLASS.AttackReportManager, "add_attack_result",
function(self, damage_profile, attacked_unit, attacking_unit, attack_direction, hit_world_position, hit_weakspot, damage, attack_result, attack_type, damage_efficiency, is_critical_strike)
local player = context.player
local player_unit = player and player.player_unit
if not player_unit or attacking_unit ~= player_unit then
return
end
if attack_type == "companion_dog" then
local tag_context = mark_context[TAG_NAMES.COMPANION_TAG]
local marked_tag = tag_context.tag
if marked_tag and marked_tag._target_unit == attacked_unit and not tag_context.pounce_start_time then
tag_context.pounce_start_time = mod:get_latest_fixed_time()
mod:print_debug("pounce start time:", tag_context.pounce_start_time)
end
elseif SERVO_SKULL_DAMAGE_PROFILE_NAMES[damage_profile.name] then
local tag_context = mark_context[TAG_NAMES.SERVO_SKULL_TAG]
local marked_tag = tag_context.tag
if marked_tag and marked_tag._target_unit == attacked_unit and not tag_context.shoot_start_time then
tag_context.shoot_start_time = mod:get_latest_fixed_time()
mod:print_debug("shoot start time:", tag_context.shoot_start_time)
end
end
end)
@@ -0,0 +1,247 @@
---@class AutoMarkMod:DMFMod
local mod = get_mod("AutoMark")
local context = mod.context
local mod_settings = mod.settings
local mark_context = mod.mark_context
local TAG_NAMES = mod.TAG_NAMES
local companion_cancel_mark_breed_settings = mod.companion_cancel_mark_breed_settings
local DISABLING_TYPES = mod.DISABLING_TYPES
-- Imports
local Health = require("scripts/utilities/health")
-- Global Cache
local CLASS = CLASS
local HEALTH_ALIVE = HEALTH_ALIVE
local Managers = Managers
local callback = callback
local Unit_world_position = Unit.world_position
local Vector3_distance_squared = Vector3.distance_squared
local ScriptUnit_extension = ScriptUnit.extension
-- Outline Name For Execution Order Detection
local EXECUTION_ORDER_OUTLINE_NAME = "adamant_mark_target"
local CANCEL_INTERVAL = 0.5
-- Callback Function for Companion Mark
local function companion_mark_callback()
local smart_tag_system = context.smart_tag_system
if not smart_tag_system then
return
end
local target_unit = mod:find_target_unit()
if not target_unit then
return
end
local target_tag = smart_tag_system:unit_tag(target_unit)
local tag_name = TAG_NAMES.COMPANION_TAG
mod:set_manual_mark(tag_name, target_unit, target_tag)
end
-- Callback Function for Enemy Mark
local function enemy_mark_callback()
local smart_tag_system = context.smart_tag_system
if not smart_tag_system then
return
end
local target_unit = mod:find_target_unit()
if not target_unit then
return
end
local target_tag = smart_tag_system:unit_tag(target_unit)
if target_tag then
return
end
local tag_name = TAG_NAMES.ENEMY_TAG
mod:set_manual_mark(tag_name, target_unit, target_tag)
end
-- Companion Mark Keybind Function
mod.companion_mark = function()
if not context.mod_enabled or not context.game_mode_valid or context.class_name ~= "adamant" or not context.has_companion then
return
end
local companion_command_tap = context.companion_command_tap
if companion_command_tap == "double" then
local cb = callback(companion_mark_callback)
Managers.state.game_mode:register_physics_safe_callback(cb)
elseif companion_command_tap == "single" then
local cb = callback(enemy_mark_callback)
Managers.state.game_mode:register_physics_safe_callback(cb)
end
end
-- Check If Target Unit Is Marked by Execution Order
local function is_marked_by_execution_order(unit)
local outline_system = context.outline_system
local extension = outline_system and outline_system._unit_extension_data[unit]
local outlines = extension and extension.outlines
if not outlines then
return false
end
for i = 1, #outlines do
if outlines[i].name == EXECUTION_ORDER_OUTLINE_NAME then
return true
end
end
return false
end
-- Cache All Units Marked by Execution Order
function mod:init_execution_order_units()
if not context.has_execution_order then
return
end
local smart_tag_system = context.smart_tag_system
if not smart_tag_system then
return
end
local unit_extension_data = smart_tag_system._unit_extension_data
if not unit_extension_data then
return
end
local execution_order_units = mark_context.execution_order_units
for unit, smart_tag_extension in pairs(unit_extension_data) do
if HEALTH_ALIVE[unit]
and smart_tag_extension._target_type == "breed"
and is_marked_by_execution_order(unit)
then
execution_order_units[unit] = true
end
end
end
local cancel_interval = 0
function mod:auto_cancel_companion_mark(dt, t)
if not mod_settings.companion_cancel_mark or context.class_name ~= "adamant" or not context.has_companion then
return
end
if cancel_interval > 0 then
cancel_interval = cancel_interval - dt
return
end
local disabled_character_state_component = context.disabled_character_state_component
if disabled_character_state_component and disabled_character_state_component.is_disabled and DISABLING_TYPES[disabled_character_state_component.disabling_type] then
return
end
local tag_context = mark_context[TAG_NAMES.COMPANION_TAG]
local marked_tag = tag_context.tag
local marked_unit = marked_tag and marked_tag._target_unit
if not marked_tag or not marked_unit then
return
end
if tag_context.is_manual or not tag_context.is_cancelable then
return
end
if not tag_context.pounce_start_time then
return
end
local unit_data_extension = ScriptUnit_extension(marked_unit, "unit_data_system")
local breed_data = unit_data_extension and unit_data_extension._breed
local breed_name = breed_data and breed_data.name
local breed_settings = companion_cancel_mark_breed_settings[breed_name]
local health_threshold, time_threshold, distance_threshold
if breed_settings and breed_settings.override then
health_threshold = breed_settings.health_threshold or 0
time_threshold = breed_settings.time_threshold or 0
distance_threshold = breed_settings.distance_threshold or 0
else
health_threshold = mod_settings.companion_health_threshold
time_threshold = mod_settings.companion_time_threshold
distance_threshold = mod_settings.companion_distance_threshold
end
if health_threshold > 0 then
local health_percent = Health.current_health_percent(marked_unit)
if health_percent < health_threshold then
mod:print_debug("cancel companion mark due to health threshold, health_percent:", health_percent)
tag_context.canceled_units[marked_unit] = t + 3
cancel_interval = CANCEL_INTERVAL
mod:cancel_mark(marked_tag._id)
return
end
end
if time_threshold > 0 then
local elapsed_time = t - tag_context.pounce_start_time
if elapsed_time > time_threshold then
mod:print_debug("cancel companion mark due to time threshold, elapsed_time:", elapsed_time)
tag_context.canceled_units[marked_unit] = t + 3
cancel_interval = CANCEL_INTERVAL
mod:cancel_mark(marked_tag._id)
return
end
end
if distance_threshold > 0 then
local companion_spawner_extension = context.companion_spawner_extension
local companion_units = companion_spawner_extension and companion_spawner_extension:companion_units()
local companion_unit = companion_units and companion_units[1]
if not companion_unit then
goto exit
end
local player = context.player
local player_unit = player and player.player_unit
if not player_unit then
goto exit
end
local POSITION_LOOKUP = POSITION_LOOKUP
local companion_position = POSITION_LOOKUP[companion_unit] or Unit_world_position(companion_unit, 1)
local player_position = POSITION_LOOKUP[player_unit] or Unit_world_position(player_unit, 1)
if not companion_position or not player_position then
goto exit
end
local distance_squared = Vector3_distance_squared(companion_position, player_position)
if distance_squared > distance_threshold * distance_threshold then
mod:print_debug("cancel companion mark due to distance threshold, distance squared:", distance_squared)
tag_context.canceled_units[marked_unit] = t + 3
cancel_interval = CANCEL_INTERVAL
mod:cancel_mark(marked_tag._id)
return
end
::exit::
end
end
-- Cache Unit Marked by Execution Order
mod:hook_safe(CLASS.OutlineSystem, "add_outline",
function(self, unit, outline_name)
if outline_name == EXECUTION_ORDER_OUTLINE_NAME then
mark_context.execution_order_units[unit] = true
end
end)
-- Uncache Unit Unmarked by Execution Order
mod:hook_safe(CLASS.OutlineSystem, "remove_outline",
function(self, unit, outline_name)
if outline_name == EXECUTION_ORDER_OUTLINE_NAME then
mark_context.execution_order_units[unit] = nil
end
end)
-- Uncache Unit Dead
mod:hook_safe(CLASS.OutlineSystem, "on_remove_extension",
function(self, unit, extension_name)
mark_context.execution_order_units[unit] = nil
end)
@@ -0,0 +1,84 @@
---@class AutoMarkMod:DMFMod
local mod = get_mod("AutoMark")
local context = mod.context
local mod_settings = mod.settings
local mark_context = mod.mark_context
local TAG_NAMES = mod.TAG_NAMES
-- Global Cache
local CLASS = CLASS
-- Constants
local MELEE_RANGE = 5
local function focus_target_switch(is_melee)
if not context.mod_enabled or not context.game_mode_valid or context.class_name ~= "veteran" or not context.has_focus_target then
return
end
local tag_name = TAG_NAMES.VETERAN_TAG
local tag_context = mark_context[tag_name]
if mark_context.auto_mark_interval > 0 or tag_context.delay > 0 then
return
end
if not mod_settings.focus_target_switch_override_manual and tag_context.is_manual and not tag_context.is_switch_melee and not tag_context.is_switch_range then
return
end
local smart_tag_system = context.smart_tag_system
if not smart_tag_system then
return
end
local target_unit, target_tag
if is_melee then
target_unit, target_tag = mod:find_focus_target_switch_melee_target_unit(MELEE_RANGE)
else
target_unit = mod:find_target_unit(true)
end
target_tag = target_tag or smart_tag_system:unit_tag(target_unit)
if not target_unit or not mod:can_focus_target_overwrite(target_unit, target_tag) then
return
end
if is_melee then
tag_context.switch_melee_unit = target_unit
else
tag_context.switch_range_unit = target_unit
end
tag_context.switch_unit_expired_time = mod:get_latest_fixed_time() + 1
mod:print_debug("Focus Target Switch", target_unit)
mod:on_manual_mark(tag_context, target_unit)
mod:set_auto_mark(tag_name, target_unit, target_tag)
end
local MELEE_ACTION_KINDS = {
-- windup = true,
sweep = true,
}
local RANGED_ACTION_KINDS = {
shoot_hit_scan = true,
shoot_pellets = true,
-- overload_charge = true,
-- charge_ammo = true,
}
mod:hook_safe(CLASS.ActionHandler, "start_action",
function(self, id, action_objects, action_name, action_params, action_settings, used_input, t, transition_type, condition_func_params, automatic_input, reset_combo_override)
if self._unit_data_extension._player.viewport_name ~= 'player1' then
return
end
if id == "weapon_action" then
if mod_settings.toggle_mod and mod_settings.focus_target_switch then
local action_kind = action_settings.kind
if mod_settings.focus_target_switch_melee and MELEE_ACTION_KINDS[action_kind] then
focus_target_switch(true)
elseif mod_settings.focus_target_switch_range and RANGED_ACTION_KINDS[action_kind] then
focus_target_switch(false)
end
end
end
end)
@@ -0,0 +1,324 @@
---@class AutoMarkMod:DMFMod
local mod = get_mod("AutoMark")
local context = mod.context
local mark_context = mod.mark_context
local TAG_NAMES = mod.TAG_NAMES
local mod_settings = mod.settings
local noospheric_command_breed_settings = mod.noospheric_command_breed_settings
local DISABLING_TYPES = mod.DISABLING_TYPES
-- Imports
local SpecialRulesSettings = require("scripts/settings/ability/special_rules_settings")
local CompanionServoSkullSettings = require("scripts/settings/companion/companion_servo_skull_settings")
local Hud = require("scripts/utilities/ui/hud")
local Health = require("scripts/utilities/health")
local special_rules = SpecialRulesSettings.special_rules
local servo_skull_states = CompanionServoSkullSettings.STATES
-- Global Cache
local RESOLUTION_LOOKUP = RESOLUTION_LOOKUP
local Managers = Managers
local callback = callback
local get_game_object_field = GameSession.game_object_field
local ScriptUnit_extension = ScriptUnit.extension
local HACK_TAG_NAME = "hacking_over_here_companion"
local CANCEL_INTERVAL = 0.5
local function servo_skull_mark_callback()
local smart_tag_system = context.smart_tag_system
if not smart_tag_system then
return
end
local target_unit = mod:find_target_unit()
if not target_unit then
return
end
local target_tag = smart_tag_system:unit_tag(target_unit)
local tag_name = TAG_NAMES.SERVO_SKULL_TAG
mod:set_manual_mark(tag_name, target_unit, target_tag)
end
local function enemy_mark_callback()
local smart_tag_system = context.smart_tag_system
if not smart_tag_system then
return
end
local target_unit = mod:find_target_unit()
if not target_unit then
return
end
local target_tag = smart_tag_system:unit_tag(target_unit)
if target_tag then
return
end
local tag_name = TAG_NAMES.ENEMY_TAG
mod:set_manual_mark(tag_name, target_unit, target_tag)
end
mod.servo_skull_mark = function()
if not context.mod_enabled or not context.game_mode_valid or context.class_name ~= "cryptic" or not context.has_servo_skull then
return
end
local companion_command_tap = context.companion_command_tap
if companion_command_tap == "double" then
local cb = callback(servo_skull_mark_callback)
Managers.state.game_mode:register_physics_safe_callback(cb)
elseif companion_command_tap == "single" then
local cb = callback(enemy_mark_callback)
Managers.state.game_mode:register_physics_safe_callback(cb)
end
end
local function hack_mark_callback()
local smart_tag_system = context.smart_tag_system
if not smart_tag_system then
return
end
local hud_element_smart_tagging = context.hud_element_smart_tagging
if not hud_element_smart_tagging then
return
end
local player = context.player
local player_unit = player and player.player_unit
if not player_unit then
return
end
local target_marker, _ = hud_element_smart_tagging:_find_world_marker_target()
local target_unit = target_marker and target_marker.unit
if not target_unit then
return
end
local target_extension = smart_tag_system._unit_extension_data[target_unit]
local template_name = target_extension and target_extension:_contextual_tag_template_name(player_unit, "companion_order")
if template_name ~= HACK_TAG_NAME then
return
end
local target_tag = smart_tag_system:unit_tag(target_unit)
local tagger_player = target_tag and target_tag._tagger_player
local tagger_player_unit = tagger_player and tagger_player.player_unit
if tagger_player_unit then
smart_tag_system:cancel_tag(target_tag._id, tagger_player_unit, true)
end
smart_tag_system:set_tag(HACK_TAG_NAME, player_unit, target_unit)
end
mod.hack_mark = function()
if not context.mod_enabled or not context.game_mode_valid or context.class_name ~= "cryptic" or not context.has_servo_skull then
return
end
local cb = callback(hack_mark_callback)
Managers.state.game_mode:register_physics_safe_callback(cb)
end
function mod:is_servo_skull_hacking()
local companion_spawner_extension = context.companion_spawner_extension
local companion_unit = companion_spawner_extension and companion_spawner_extension:spawned_unit_lookup(special_rules.cryptic_servo_skull_hack)
if not companion_unit then
return false
end
local game_session = Managers.state.game_session:game_session()
local game_object_id = Managers.state.unit_spawner:game_object_id(companion_unit)
local state = get_game_object_field(game_session, game_object_id, "state")
return state == servo_skull_states.hacking
end
function mod:is_noospheric_command_boost_breed_valid(target_unit)
local unit_data_extension = ScriptUnit_extension(target_unit, "unit_data_system")
local breed_data = unit_data_extension and unit_data_extension._breed
if not breed_data then
return false
end
local breed_name = breed_data.name
local breed_settings = noospheric_command_breed_settings[breed_name]
if breed_settings and breed_settings.override then
return breed_settings.toggle
end
if breed_data.is_boss then
return mod_settings.noospheric_command_boost_boss
elseif breed_data.tags.special then
return mod_settings.noospheric_command_boost_special
else
return mod_settings.noospheric_command_boost_elite
end
end
local find_hackable_target_unit = function()
local hud_element_smart_tagging = context.hud_element_smart_tagging
if not hud_element_smart_tagging then
return
end
local smart_tag_system = context.smart_tag_system
if not smart_tag_system then
return
end
Managers.event:trigger("request_world_markers_list", callback(hud_element_smart_tagging, "_cb_world_markers_list_request"))
local world_markers_list = hud_element_smart_tagging._world_markers_list
local hud_scale = Hud.hud_scale()
local selected_marker_distance = math.huge
local selected_marker_unit
local parent = hud_element_smart_tagging._parent
local player = parent:player()
local player_unit = player.player_unit
local resolution_width, resolution_height = RESOLUTION_LOOKUP.width, RESOLUTION_LOOKUP.height
local center_x, center_y = 0.5 * resolution_width, 0.5 * resolution_height
local radius = resolution_height / 8 * 3
local radius_squared = radius * radius
for i = 1, #world_markers_list do
local marker = world_markers_list[i]
local widget = marker.widget
if widget then
local distance = widget.content.distance
if hud_element_smart_tagging:_is_marker_valid_for_tagging(player_unit, marker, distance) then
local offset = widget.offset
local x = offset[1] * hud_scale
local y = offset[2] * hud_scale
local dx = x - center_x
local dy = y - center_y
if dx * dx + dy * dy <= radius_squared and distance < selected_marker_distance then
local marker_unit = marker.unit
local target_extension = smart_tag_system._unit_extension_data[marker_unit]
local template_name = target_extension and target_extension:_contextual_tag_template_name(player_unit, "companion_order")
if template_name == HACK_TAG_NAME then
selected_marker_unit = marker_unit
selected_marker_distance = distance
end
end
end
end
end
return selected_marker_unit, selected_marker_distance
end
local hack_interval = 0
function mod:auto_hack(dt, t, fixed_frame)
if not mod_settings.auto_hack or (mod_settings.disable_auto_hack_for_noospheric_command and context.has_noospheric_command) or context.class_name ~= "cryptic" or not context.has_servo_skull then
return
end
if hack_interval > 0 then
hack_interval = hack_interval - dt
return
end
if mod:is_servo_skull_hacking() then
return
end
local smart_tag_system = context.smart_tag_system
if not smart_tag_system then
return
end
local player = context.player
local player_unit = player and player.player_unit
if not player_unit then
return
end
local target_unit, _ = find_hackable_target_unit()
if not target_unit then
return
end
local target_tag = smart_tag_system:unit_tag(target_unit)
local tagger_player = target_tag and target_tag._tagger_player
local tagger_player_unit = tagger_player and tagger_player.player_unit
if tagger_player_unit then
smart_tag_system:cancel_tag(target_tag._id, tagger_player_unit, true)
end
hack_interval = 1
smart_tag_system:set_tag(HACK_TAG_NAME, player_unit, target_unit)
end
local cancel_interval = 0
function mod:auto_cancel_servo_skull_mark(dt, t, fixed_frame)
if not mod_settings.servo_skull_cancel_mark or context.class_name ~= "cryptic" or not context.has_servo_skull then
return
end
if cancel_interval > 0 then
cancel_interval = cancel_interval - dt
return
end
local disabled_character_state_component = context.disabled_character_state_component
if disabled_character_state_component and disabled_character_state_component.is_disabled and DISABLING_TYPES[disabled_character_state_component.disabling_type] then
return
end
local tag_context = mark_context[TAG_NAMES.SERVO_SKULL_TAG]
local marked_tag = tag_context.tag
local marked_unit = marked_tag and marked_tag._target_unit
if not marked_tag or not marked_unit then
return
end
if tag_context.is_manual then
return
end
local unit_data_extension = ScriptUnit_extension(marked_unit, "unit_data_system")
local breed_data = unit_data_extension and unit_data_extension._breed
local breed_name = breed_data and breed_data.name
local breed_settings = noospheric_command_breed_settings[breed_name]
local time_threshold, health_threshold
if breed_settings and breed_settings.override then
health_threshold = breed_settings.health_threshold or 0
time_threshold = breed_settings.time_threshold or 0
else
time_threshold = mod_settings.servo_skull_cancel_mark_time_threshold
health_threshold = mod_settings.servo_skull_cancel_mark_health_threshold
end
if time_threshold > 0 then
if mod:is_servo_skull_target_visible(marked_unit, fixed_frame, true) then
tag_context.servo_skull_lose_sight_time = nil
elseif not tag_context.servo_skull_lose_sight_time then
tag_context.servo_skull_lose_sight_time = t
end
if tag_context.servo_skull_lose_sight_time and t - tag_context.servo_skull_lose_sight_time > time_threshold then
mod:print_debug("cancel servo skull mark due to time threshold")
tag_context.canceled_units[marked_unit] = t + 0.3
cancel_interval = CANCEL_INTERVAL
mod:cancel_mark(marked_tag._id)
end
end
if health_threshold > 0 and tag_context.shoot_start_time then
local health_percent = Health.current_health_percent(marked_unit)
if health_percent < health_threshold then
mod:print_debug("cancel servo skull mark due to health threshold, health_percent:", health_percent)
tag_context.canceled_units[marked_unit] = t + 3
cancel_interval = CANCEL_INTERVAL
mod:cancel_mark(marked_tag._id)
return
end
end
end
@@ -0,0 +1,199 @@
---@class AutoMarkMod:DMFMod
local mod = get_mod("AutoMark")
local auto_mark_settings = mod.auto_mark_settings
local context = mod.context
local DEFAULT_CLASS_SETTINGS = mod.DEFAULT_CLASS_SETTINGS
local TAG_NAMES = mod.TAG_NAMES
-- Imports
local Archetypes = require("scripts/settings/archetype/archetypes")
-- Global Cache
local table_clone = table.clone
-- Constants
local BASE_CLASSES = {}
for class_name, _ in pairs(Archetypes) do
BASE_CLASSES[class_name] = true
end
-- Additional Class Name for Arbites and Veteran
local ADAMANT_COMPANION = "adamant_companion"
local CRYPTIC_SERVO_SKULL = "cryptic_servo_skull"
local VETERAN_FOCUS_TARGET = "veteran_focus_target"
-- Valid Class Names
local VALID_CLASSES = {
[ADAMANT_COMPANION] = true,
[CRYPTIC_SERVO_SKULL] = true,
[VETERAN_FOCUS_TARGET] = true,
}
for class_name, _ in pairs(Archetypes) do
VALID_CLASSES[class_name] = true
end
local ADAMANT_COMPANION_DEFAULT_CLASS_SETTINGS = table_clone(DEFAULT_CLASS_SETTINGS)
ADAMANT_COMPANION_DEFAULT_CLASS_SETTINGS.interval = 0
local adamant_companion_breed_priorities = ADAMANT_COMPANION_DEFAULT_CLASS_SETTINGS.breed_priorities
adamant_companion_breed_priorities["chaos_daemonhost_passive"] = 0
adamant_companion_breed_priorities["chaos_mutator_daemonhost_passive"] = 0
adamant_companion_breed_priorities["chaos_daemonhost_torment_passive"] = 0
adamant_companion_breed_priorities["chaos_ogryn_houndmaster"] = 0
adamant_companion_breed_priorities["chaos_poxwalker_bomber"] = 0
local CRYPTIC_SERVO_SKULL_DEFAULT_CLASS_SETTINGS = table_clone(DEFAULT_CLASS_SETTINGS)
CRYPTIC_SERVO_SKULL_DEFAULT_CLASS_SETTINGS.interval = 0
local cryptic_servo_skull_breed_priorities = CRYPTIC_SERVO_SKULL_DEFAULT_CLASS_SETTINGS.breed_priorities
cryptic_servo_skull_breed_priorities["chaos_daemonhost_passive"] = 0
cryptic_servo_skull_breed_priorities["chaos_mutator_daemonhost_passive"] = 0
cryptic_servo_skull_breed_priorities["chaos_daemonhost_torment_passive"] = 0
cryptic_servo_skull_breed_priorities["chaos_poxwalker_bomber"] = 0
local VETERAN_FOCUS_TARGET_DEFAULT_CLASS_SETTINGS = table_clone(DEFAULT_CLASS_SETTINGS)
VETERAN_FOCUS_TARGET_DEFAULT_CLASS_SETTINGS.interval = 0
local veteran_focus_target_breed_priorities = VETERAN_FOCUS_TARGET_DEFAULT_CLASS_SETTINGS.breed_priorities
-- veteran_focus_target_breed_priorities["chaos_daemonhost_passive"] = 0
veteran_focus_target_breed_priorities["chaos_mutator_daemonhost_passive"] = 0
local function get_default_class_settings(class_name)
if class_name == ADAMANT_COMPANION then
return ADAMANT_COMPANION_DEFAULT_CLASS_SETTINGS
elseif class_name == CRYPTIC_SERVO_SKULL then
return CRYPTIC_SERVO_SKULL_DEFAULT_CLASS_SETTINGS
elseif class_name == VETERAN_FOCUS_TARGET then
return VETERAN_FOCUS_TARGET_DEFAULT_CLASS_SETTINGS
end
return DEFAULT_CLASS_SETTINGS
end
local function init_table(dest, source)
for key, value in pairs(source) do
if type(value) == "table" then
if type(dest[key]) == "table" then
dest[key] = init_table(dest[key], value)
else
dest[key] = table_clone(value)
end
else
if dest[key] == nil or type(dest[key]) ~= type(value) then
dest[key] = value
end
end
end
for key, _ in pairs(dest) do
if source[key] == nil then
dest[key] = nil
end
end
return dest
end
-- Init Auto Mark Settings
function mod:init_auto_mark_settings()
for class_name, _ in pairs(VALID_CLASSES) do
if auto_mark_settings[class_name] == nil then
auto_mark_settings[class_name] = {}
end
local class_settings = auto_mark_settings[class_name]
init_table(class_settings, get_default_class_settings(class_name))
end
local cyber_mastiff_settings = auto_mark_settings[ADAMANT_COMPANION]
local cyber_mastiff_breed_priorities = cyber_mastiff_settings.breed_priorities
cyber_mastiff_breed_priorities["chaos_poxwalker_bomber"] = 0
local servo_skull_settings = auto_mark_settings[CRYPTIC_SERVO_SKULL]
local servo_skull_breed_priorities = servo_skull_settings.breed_priorities
servo_skull_breed_priorities["chaos_poxwalker_bomber"] = 0
for class_name, _ in pairs(auto_mark_settings) do
if not VALID_CLASSES[class_name] then
auto_mark_settings[class_name] = nil
end
end
mod:set("auto_mark_settings", auto_mark_settings, false)
end
-- Reset Auto Mark Settings to Default
function mod:reset_auto_mark_settings()
for class_name, _ in pairs(VALID_CLASSES) do
auto_mark_settings[class_name] = table_clone(get_default_class_settings(class_name))
end
mod:set("auto_mark_settings", auto_mark_settings, false)
end
function mod:reset_class_settings(class_name)
if not VALID_CLASSES[class_name] then
return
end
auto_mark_settings[class_name] = table_clone(get_default_class_settings(class_name))
mod:set("auto_mark_settings", auto_mark_settings, false)
end
-- Apply Settings to All Classes
function mod:apply_to_all_classes(class_name)
for other_class_name, _ in pairs(VALID_CLASSES) do
if other_class_name ~= class_name then
auto_mark_settings[other_class_name] = table_clone(auto_mark_settings[class_name])
end
end
mod:set("auto_mark_settings", auto_mark_settings, false)
end
-- Apply Settings to Normal Tag
function mod:apply_to_normal_tag(class_name)
for other_class_name, _ in pairs(BASE_CLASSES) do
if other_class_name ~= class_name then
auto_mark_settings[other_class_name] = table_clone(auto_mark_settings[class_name])
end
end
mod:set("auto_mark_settings", auto_mark_settings, false)
end
-- Set Menu for Display
function mod:set_menu_class_settings(class_name)
if not VALID_CLASSES[class_name] then
return
end
mod:set("class_selection", class_name, false)
local class_settings = auto_mark_settings[class_name]
for setting_name, default_setting in pairs(get_default_class_settings(class_name)) do
if type(default_setting) == "table" then
local breed_priorities = class_settings[setting_name]
for breed_name, _ in pairs(default_setting) do
mod:set(breed_name, breed_priorities[breed_name], false)
end
else
mod:set(setting_name, class_settings[setting_name], false)
end
end
end
-- Get Class Settings by Tag Name
function mod:get_class_settings(tag_name)
if tag_name == TAG_NAMES.ENEMY_TAG then
return auto_mark_settings[context.class_name]
elseif tag_name == TAG_NAMES.VETERAN_TAG then
return auto_mark_settings[VETERAN_FOCUS_TARGET]
elseif tag_name == TAG_NAMES.COMPANION_TAG then
return auto_mark_settings[ADAMANT_COMPANION]
elseif tag_name == TAG_NAMES.SERVO_SKULL_TAG then
return auto_mark_settings[CRYPTIC_SERVO_SKULL]
end
end
-- Get Class Name
function mod:get_menu_class_name()
if context.class_name == "adamant" and context.has_companion then
return ADAMANT_COMPANION
elseif context.class_name == "veteran" and context.has_focus_target then
return VETERAN_FOCUS_TARGET
elseif context.class_name == "cryptic" and context.has_servo_skull then
return CRYPTIC_SERVO_SKULL
else
return context.class_name or "adamant"
end
end
@@ -0,0 +1,56 @@
---@class AutoMarkMod:DMFMod
local mod = get_mod("AutoMark")
local companion_cancel_mark_breed_settings = mod.companion_cancel_mark_breed_settings
local CYBER_MASTIFF_BREED_SETTING_IDS = {
companion_cancel_mark_breed_override = true,
companion_range_limitation_breed = true,
companion_mark_max_distance_breed = true,
companion_mark_sticky_targeting_breed = true,
companion_cancel_mark_breed_health_threshold = true,
companion_cancel_mark_breed_time_threshold = true,
companion_cancel_mark_breed_distance_threshold = true,
}
function mod:is_cyber_mastiff_breed_setting_id(setting_id)
return CYBER_MASTIFF_BREED_SETTING_IDS[setting_id]
end
function mod:set_menu_cyber_mastiff_breed_settings(breed_name)
local breed_settings = companion_cancel_mark_breed_settings[breed_name]
mod:set("companion_cancel_mark_breed_override", breed_settings and breed_settings.override or false, false)
mod:set("companion_range_limitation_breed", breed_settings and breed_settings.range_limitation or 0, false)
mod:set("companion_mark_max_distance_breed", breed_settings and breed_settings.max_distance or 0, false)
mod:set("companion_mark_sticky_targeting_breed", breed_settings and breed_settings.sticky_targeting or false, false)
mod:set("companion_cancel_mark_breed_health_threshold", (breed_settings and breed_settings.health_threshold or 0) * 100, false)
mod:set("companion_cancel_mark_breed_time_threshold", breed_settings and breed_settings.time_threshold or 0, false)
mod:set("companion_cancel_mark_breed_distance_threshold", breed_settings and breed_settings.distance_threshold or 0, false)
end
function mod:set_cyber_mastiff_breed_setting(breed_name, setting_id, value)
if companion_cancel_mark_breed_settings[breed_name] == nil then
companion_cancel_mark_breed_settings[breed_name] = { override = false, range_limitation = 0, max_distance = 0, sticky_targeting = false, health_threshold = 0, time_threshold = 0, distance_threshold = 0 }
end
if setting_id == "companion_cancel_mark_breed_override" then
companion_cancel_mark_breed_settings[breed_name].override = value
elseif setting_id == "companion_range_limitation_breed" then
companion_cancel_mark_breed_settings[breed_name].range_limitation = value
elseif setting_id == "companion_mark_max_distance_breed" then
companion_cancel_mark_breed_settings[breed_name].max_distance = value
elseif setting_id == "companion_mark_sticky_targeting_breed" then
companion_cancel_mark_breed_settings[breed_name].sticky_targeting = value
elseif setting_id == "companion_cancel_mark_breed_health_threshold" then
companion_cancel_mark_breed_settings[breed_name].health_threshold = value / 100
elseif setting_id == "companion_cancel_mark_breed_time_threshold" then
companion_cancel_mark_breed_settings[breed_name].time_threshold = value
elseif setting_id == "companion_cancel_mark_breed_distance_threshold" then
companion_cancel_mark_breed_settings[breed_name].distance_threshold = value
end
mod:set("companion_cancel_mark_breed_settings", companion_cancel_mark_breed_settings, false)
end
mod.reset_all_cyber_mastiff_breed_settings = function()
table.clear(companion_cancel_mark_breed_settings)
mod:set("companion_cancel_mark_breed_settings", companion_cancel_mark_breed_settings, false)
mod:set("companion_cancel_mark_breed_name", mod:get("companion_cancel_mark_breed_name"), true)
end
@@ -0,0 +1,61 @@
---@class AutoMarkMod:DMFMod
local mod = get_mod("AutoMark")
local noospheric_command_breed_settings = mod.noospheric_command_breed_settings
local SERVO_SKULL_BREED_SETTING_IDS = {
noospheric_command_boost_breed_override = true,
servo_skull_range_limitation_breed = true,
noospheric_command_boost_breed_toggle = true,
capacitance_retention_breed_threshold = true,
servo_skull_mark_sticky_targeting_breed = true,
servo_skull_cancel_mark_breed_time_threshold = true,
servo_skull_cancel_mark_breed_health_threshold = true,
}
function mod:is_servo_skull_breed_setting_id(setting_id)
return SERVO_SKULL_BREED_SETTING_IDS[setting_id]
end
function mod:set_menu_servo_skull_breed_settings(breed_name)
local breed_settings = noospheric_command_breed_settings[breed_name]
mod:set("noospheric_command_boost_breed_override", breed_settings and breed_settings.override or false, false)
mod:set("servo_skull_range_limitation_breed", breed_settings and breed_settings.range_limitation or 0, false)
mod:set("noospheric_command_boost_breed_toggle", breed_settings and breed_settings.toggle or false, false)
mod:set("capacitance_retention_breed_threshold", (breed_settings and breed_settings.threshold or 0) * 100, false)
mod:set("servo_skull_mark_sticky_targeting_breed", breed_settings and breed_settings.sticky_targeting or false, false)
mod:set("servo_skull_cancel_mark_breed_time_threshold", breed_settings and breed_settings.time_threshold or 0, false)
mod:set("servo_skull_cancel_mark_breed_health_threshold", (breed_settings and breed_settings.health_threshold or 0) * 100, false)
end
function mod:set_servo_skull_breed_setting(breed_name, setting_id, value)
if noospheric_command_breed_settings[breed_name] == nil then
noospheric_command_breed_settings[breed_name] = { override = false, range_limitation = 0, toggle = false, threshold = 0, threshold_negative_zero = false, sticky_targeting = false, time_threshold = 0, health_threshold = 0 }
end
if setting_id == "noospheric_command_boost_breed_override" then
noospheric_command_breed_settings[breed_name].override = value
elseif setting_id == "servo_skull_range_limitation_breed" then
noospheric_command_breed_settings[breed_name].range_limitation = value
elseif setting_id == "noospheric_command_boost_breed_toggle" then
noospheric_command_breed_settings[breed_name].toggle = value
elseif setting_id == "capacitance_retention_breed_threshold" then
noospheric_command_breed_settings[breed_name].threshold = value / 100
if value == -0 and 1 / value < 0 then
noospheric_command_breed_settings[breed_name].threshold_negative_zero = true
else
noospheric_command_breed_settings[breed_name].threshold_negative_zero = false
end
elseif setting_id == "servo_skull_mark_sticky_targeting_breed" then
noospheric_command_breed_settings[breed_name].sticky_targeting = value
elseif setting_id == "servo_skull_cancel_mark_breed_time_threshold" then
noospheric_command_breed_settings[breed_name].time_threshold = value
elseif setting_id == "servo_skull_cancel_mark_breed_health_threshold" then
noospheric_command_breed_settings[breed_name].health_threshold = value / 100
end
mod:set("noospheric_command_breed_settings", noospheric_command_breed_settings, false)
end
mod.reset_all_servo_skull_breed_settings = function()
table.clear(noospheric_command_breed_settings)
mod:set("noospheric_command_breed_settings", noospheric_command_breed_settings, false)
mod:set("noospheric_command_boost_breed_name", mod:get("noospheric_command_boost_breed_name"), true)
end
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,45 @@
---@class AutoMarkMod:DMFMod
local mod = get_mod("AutoMark")
local context = mod.context
-- Global Cache
local HEALTH_ALIVE = HEALTH_ALIVE
local SMART_TARGETING_TEMPLATE = {
precision_target = {
max_range = 100,
min_range = 1,
smart_tagging = true,
},
}
local SMART_TARGETING_PRECISION_TEMPLATE = {
only_direct_hit = true,
precision_target = {
max_range = 100,
min_range = 1,
smart_tagging = true,
},
}
-- Find Target Unit For Mark System
function mod:find_target_unit(only_direct_hit)
local smart_targeting_extension = context.smart_targeting_extension
if not smart_targeting_extension then
return nil
end
local ray_origin, forward, right, up = smart_targeting_extension:_targeting_parameters()
smart_targeting_extension._precision_target_aim_assist:update_precision_target(
smart_targeting_extension._unit,
only_direct_hit and SMART_TARGETING_PRECISION_TEMPLATE or SMART_TARGETING_TEMPLATE,
ray_origin, forward, right, up,
smart_targeting_extension._smart_tag_targeting_data,
smart_targeting_extension._latest_fixed_frame,
smart_targeting_extension._visibility_cache,
smart_targeting_extension._visibility_check_frame
)
local targeting_data = smart_targeting_extension:smart_tag_targeting_data()
local target_unit = targeting_data and targeting_data.unit
return HEALTH_ALIVE[target_unit] and target_unit
end
@@ -0,0 +1,36 @@
---@class AutoMarkMod:DMFMod
local mod = get_mod("AutoMark")
local mod_settings = mod.settings
local FixedFrame = require("scripts/utilities/fixed_frame")
-- Global Cache
local Managers = Managers
-- Debug Print
function mod:print_debug(...)
if mod_settings.debug_mode then
local n = select("#", ...)
if n == 0 then
return
end
local result = tostring(select(1, ...))
for i = 2, n do
local value = select(i, ...)
result = result .. " " .. tostring(value)
end
mod:echo(result)
end
end
-- Time for Now
function mod:get_main_time()
return Managers.time:time("main")
end
function mod:get_gameplay_time()
return Managers.time:time("gameplay")
end
function mod:get_latest_fixed_time()
return FixedFrame.get_latest_fixed_time()
end