Skip to content

Commit

Permalink
sh catchup
Browse files Browse the repository at this point in the history
Co-Authored-By: Sebastian Gabl (aka Hoppip) <[email protected]>
  • Loading branch information
nikitawastaken and segabl committed Jul 20, 2024
1 parent 1d32ab0 commit 2fe4ec1
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 48 deletions.
9 changes: 4 additions & 5 deletions lua/copdamage.lua
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,10 @@ function CopDamage:_sync_dismember(attacker_unit, ...)
end
end

-- Don't set suppression to maximum on hit, increase by a static value instead
local build_suppression_original = CopDamage.build_suppression
function CopDamage:build_suppression(amount, ...)
return build_suppression_original(self, amount == "max" and 2 or amount, ...)
end
-- Additional suppression on hit
Hooks:PreHook(CopDamage, "_on_damage_received", "sh__on_damage_received", function (self, damage_info)
self:build_suppression(4 * damage_info.damage / self._HEALTH_INIT, nil)
end)

-- Give flamethrowers a damage multiplier against dozers
Hooks:PreHook(CopDamage, "damage_fire", "eclipse_damage_fire", function(self, attack_data)
Expand Down
100 changes: 64 additions & 36 deletions lua/coplogictravel.lua
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,12 @@ function CopLogicTravel._begin_coarse_pathing(data, my_data, ...)
my_data.coarse_path = {
{
data.unit:movement():nav_tracker():nav_segment(),
mvector3.copy(data.m_pos),
mvector3.copy(data.m_pos)
},
{
nav_seg,
pos,
},
pos
}
}
end

Expand All @@ -68,7 +68,7 @@ function CopLogicTravel._get_allowed_travel_nav_segs(data, ...)
end

-- Fix need for another queued task to update pathing after expired cover leave time
Hooks:PreHook(CopLogicTravel, "upd_advance", "sh_upd_advance", function(data)
Hooks:PreHook(CopLogicTravel, "upd_advance", "sh_upd_advance", function (data)
local unit = data.unit
local my_data = data.internal_data
local t = TimerManager:game():time()
Expand Down Expand Up @@ -137,16 +137,14 @@ function CopLogicTravel._get_exact_move_pos(data, nav_index, ...)
local nav_seg_pos = nav_manager._nav_segments[nav_seg_id].pos

-- Pick cover positions that are close to nav segment doors
local doors = nav_manager:find_segment_doors(nav_seg_id, function(seg_id)
return seg_id == next_nav_seg_id
end)
local doors = nav_manager:find_segment_doors(nav_seg_id, function (seg_id) return seg_id == next_nav_seg_id end)
local door = table.random(doors)
local to_pos = door and door.center or coarse_path[nav_index][2] or nav_seg_pos

local cover = nav_manager:find_cover_in_nav_seg_2(nav_seg_id, to_pos)
if cover then
nav_manager:reserve_cover(cover, data.pos_rsrv_id)
my_data.moving_to_cover = { cover }
my_data.moving_to_cover = { cover }
to_pos = cover[1]
else
mvector3.step(tmp_vec1, to_pos, nav_seg_pos, 200)
Expand All @@ -159,7 +157,7 @@ function CopLogicTravel._get_exact_move_pos(data, nav_index, ...)
pos_from = nav_seg_pos,
pos_to = tmp_vec1,
allow_entry = true,
trace = true,
trace = true
}
nav_manager:raycast(ray_params)
to_pos = ray_params.trace[1]
Expand All @@ -170,30 +168,59 @@ end

local _determine_destination_occupation_original = CopLogicTravel._determine_destination_occupation
function CopLogicTravel._determine_destination_occupation(data, objective, ...)
if objective.type ~= "defend_area" or objective.cover or objective.pos or data.kpr_keep_position then
if objective.cover or objective.pos or data.kpr_keep_position then
return _determine_destination_occupation_original(data, objective, ...)
end

local near_pos = objective.follow_unit and objective.follow_unit:movement():nav_tracker():field_position()
local cover = CopLogicTravel._find_cover(data, objective.nav_seg, near_pos)
if cover then
return {
type = "defend",
seg = objective.nav_seg,
cover = {
cover,
},
radius = objective.radius,
}
else
near_pos = CopLogicTravel._get_pos_on_wall(managers.navigation:find_random_position_in_segment(objective.nav_seg), 500)
return {
type = "defend",
seg = objective.nav_seg,
pos = near_pos,
radius = objective.radius,
}
if alive(objective.follow_unit) then
local follow_tracker = objective.follow_unit:movement():nav_tracker()
local follow_nav_seg = follow_tracker:nav_segment()
local follow_pos = follow_tracker:field_position()

local cover
if data.attention_obj and data.attention_obj.nav_tracker and data.attention_obj.reaction >= AIAttentionObject.REACT_COMBAT then
cover = managers.navigation:find_cover_in_nav_seg_3(follow_nav_seg, nil, follow_pos, threat_pos)
end

if not cover and data.team.foes.criminal1 then
cover = CopLogicTravel._find_cover(data, objective.nav_seg or follow_nav_seg, follow_pos)
end

if cover then
return {
type = "defend",
cover = {
cover
}
}
else
return {
type = "defend",
pos = CopLogicTravel._get_pos_on_wall(follow_pos, objective.called and 600)
}
end
elseif objective.type == "defend_area" then
local cover = CopLogicTravel._find_cover(data, objective.nav_seg)
if cover then
return {
type = "defend",
seg = objective.nav_seg,
cover = {
cover
},
radius = objective.radius
}
else
return {
type = "defend",
seg = objective.nav_seg,
pos = CopLogicTravel._get_pos_on_wall(managers.navigation:find_random_position_in_segment(objective.nav_seg), 500),
radius = objective.radius
}
end
end

return _determine_destination_occupation_original(data, objective, ...)
end

function CopLogicTravel._get_pos_behind_unit(data, unit, min_dis, max_dis)
Expand All @@ -217,10 +244,10 @@ function CopLogicTravel._get_pos_behind_unit(data, unit, min_dis, max_dis)
local ray_params = {
trace = true,
pos_from = unit_pos,
pos_to = pos,
pos_to = pos
}
local rsrv_desc = {
radius = 40,
radius = 40
}

repeat
Expand Down Expand Up @@ -250,7 +277,7 @@ function CopLogicTravel._get_pos_behind_unit(data, unit, min_dis, max_dis)
end

-- Fix cover wait time being set to 0 if players aren't literally next to enemy
Hooks:PostHook(CopLogicTravel, "action_complete_clbk", "sh_action_complete_clbk", function(data, action)
Hooks:PostHook(CopLogicTravel, "action_complete_clbk", "sh_action_complete_clbk", function (data, action)
if action:type() ~= "walk" then
return
end
Expand All @@ -269,11 +296,11 @@ end)

-- Stop existing advancing action on exit to a new travel logic
-- This allows enemies to start their new path immediately instead of having to finish the old one
Hooks:PreHook(CopLogicTravel, "exit", "sh_exit", function(data, new_logic_name)
Hooks:PreHook(CopLogicTravel, "exit", "sh_exit", function (data, new_logic_name)
if new_logic_name == "travel" and data.internal_data.advancing and not data.unit:movement():chk_action_forbidden("idle") then
data.brain:action_request({
body_part = 2,
type = "idle",
type = "idle"
})
end
end)
Expand All @@ -298,9 +325,10 @@ function CopLogicTravel._on_destination_reached(data, ...)
return _on_destination_reached_original(data, ...)
end


-- Play generic radio report chatter during travel while unalerted
Hooks:PostHook(CopLogicTravel, "queued_update", "sh_queued_update", function(data)
Hooks:PostHook(CopLogicTravel, "queued_update", "sh_queued_update", function (data)
if data.cool and data.char_tweak.chatter and data.char_tweak.chatter.report then
managers.groupai:state():chk_say_enemy_chatter(data.unit, data.m_pos, "report")
end
end)
end)
128 changes: 121 additions & 7 deletions lua/groupaistatebesiege.lua
Original file line number Diff line number Diff line change
Expand Up @@ -973,14 +973,128 @@ function GroupAIStateBesiege:_choose_best_group(best_groups, total_weight)
return best_grp, best_grp_type
end

-- Save spawn group element in group description for debugging stuck groups
local _spawn_in_group_original = GroupAIStateBesiege._spawn_in_group
function GroupAIStateBesiege:_spawn_in_group(spawn_group, ...)
local group = _spawn_in_group_original(self, spawn_group, ...)
if group then
group.spawn_group_element = spawn_group.mission_element
return group
-- Fix amount_min not being enforced when possible and save spawn group element in group description for debugging stuck groups
function GroupAIStateBesiege:_spawn_in_group(spawn_group, spawn_group_type, grp_objective, ai_task)
local spawn_group_desc = tweak_data.group_ai.enemy_spawn_groups[spawn_group_type]

local wanted_nr_units
if type(spawn_group_desc.amount) == "number" then
wanted_nr_units = spawn_group_desc.amount
else
wanted_nr_units = math.random(spawn_group_desc.amount[1], spawn_group_desc.amount[2])
end

local valid_unit_types = {}
self._extract_group_desc_structure(spawn_group_desc.spawn, valid_unit_types)

local total_weight = 0
local unit_categories = tweak_data.group_ai.unit_categories
for _, spawn_entry in ipairs(valid_unit_types) do
local cat_data = unit_categories[spawn_entry.unit]
if not cat_data then
StreamHeist:error("Unit category %s in spawn group type %s doesn't exist", spawn_entry.unit, spawn_group_type)
return
end

local special_type = not cat_data.is_captain and cat_data.special_type
if special_type and managers.job:current_spawn_limit(special_type) < self:_get_special_unit_type_count(special_type) + (spawn_entry.amount_min or 0) then
spawn_group.delay_t = self._t + 10
return
end

total_weight = total_weight + spawn_entry.freq
end

for _, sp_data in ipairs(spawn_group.spawn_pts) do
sp_data.delay_t = self._t + math.rand(0.5)
end

local group_size = 0
local spawn_task = {
objective = not grp_objective.element and self._create_objective_from_group_objective(grp_objective),
units_remaining = {},
spawn_group = spawn_group,
spawn_group_type = spawn_group_type,
ai_task = ai_task
}

table.insert(self._spawning_groups, spawn_task)

local function _add_unit_type_to_spawn_task(i, spawn_entry)
local add_amount = 1
if spawn_entry.amount_min then
add_amount = math.max(spawn_entry.amount_min, add_amount)
spawn_entry.amount_min = nil
end

if wanted_nr_units < add_amount then
add_amount = wanted_nr_units
StreamHeist:warn("Can not satisfy amount_min for unit category %s in spawn group type %s", spawn_entry.unit, spawn_group_type)
end

spawn_task.units_remaining[spawn_entry.unit] = spawn_task.units_remaining[spawn_entry.unit] or {
amount = 0,
spawn_entry = spawn_entry
}
spawn_task.units_remaining[spawn_entry.unit].amount = spawn_task.units_remaining[spawn_entry.unit].amount + add_amount

group_size = group_size + add_amount
wanted_nr_units = wanted_nr_units - add_amount

if spawn_entry.amount_max then
if add_amount >= spawn_entry.amount_max then
table.remove(valid_unit_types, i)
total_weight = total_weight - spawn_entry.freq
return true
else
spawn_entry.amount_max = spawn_entry.amount_max - add_amount
end
end
end

local i = 1
while wanted_nr_units > 0 and i <= #valid_unit_types do
local spawn_entry = valid_unit_types[i]
local entry_removed = spawn_entry.amount_min and _add_unit_type_to_spawn_task(i, spawn_entry)
if not entry_removed then
i = i + 1
end
end

while wanted_nr_units > 0 and #valid_unit_types > 0 do
local roll = math.random() * total_weight
local rand_entry

i = 1
repeat
rand_entry = valid_unit_types[i]
roll = roll - rand_entry.freq
i = i + 1
until roll <= 0

local cat_data = unit_categories[rand_entry.unit]
local special_type = not cat_data.is_captain and cat_data.special_type
if special_type and managers.job:current_spawn_limit(special_type) <= self:_get_special_unit_type_count(special_type) then
table.remove(valid_unit_types, i - 1)
total_weight = total_weight - rand_entry.freq
else
_add_unit_type_to_spawn_task(i - 1, rand_entry)
end
end

local group = self:_create_group({
size = group_size,
type = spawn_group_type
})

group.objective = grp_objective
group.objective.moving_out = true
group.team = self._teams[spawn_group.team_id or tweak_data.levels:get_default_team_ID("combatant")]
group.spawn_group_element = spawn_group.mission_element

spawn_task.group = group

return group
end

-- Make a generic group voice function instead of individual ones and make retiring groups play retreat lines
Expand Down
24 changes: 24 additions & 0 deletions lua/teamailogicidle.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
local tmp_vec = Vector3()

-- Improve following in big nav segments
function TeamAILogicIdle._check_should_relocate(data, my_data, objective)
local follow_movement = objective.follow_unit:movement()

local max_allowed_dis_xy = 500
local max_allowed_dis_z = 250

if follow_movement:nav_tracker():nav_segment() == data.unit:movement():nav_tracker():nav_segment() then
max_allowed_dis_xy = max_allowed_dis_xy * 3
max_allowed_dis_z = max_allowed_dis_z * 2
end

mvector3.set(tmp_vec, follow_movement:m_newest_pos())
mvector3.subtract(tmp_vec, data.m_pos)

if math.abs(tmp_vec.z) > max_allowed_dis_z then
return true
end

mvector3.set_z(tmp_vec, 0)
return mvector3.length(tmp_vec) > max_allowed_dis_xy
end
1 change: 1 addition & 0 deletions supermod.xml
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@
<post :hook_id="interactions/interactionext"/>

<group :hook_id="player_team/">
<post :hook_id="logics/teamailogicidle"/>
<post :hook_id="actions/lower_body/criminalactionwalk"/>
<post :hook_id="teamaidamage"/>
<post :hook_id="teamaimovement"/>
Expand Down

0 comments on commit 2fe4ec1

Please sign in to comment.