Skip to content

Conversation

@Loobinex
Copy link
Member

No description provided.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new library file patrols.lua that provides functionality for managing creature patrols. The library allows assigning heroes or parties to patrol between specified locations, with automatic succession when patrol members die.

Changes:

  • Added patrol management system with circular route navigation
  • Implemented death event handlers for leader and backup succession
  • Added RegisterPatrol public API for creating patrol routes

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +67 to +70
else

RemoveTrigger(triggerData.trigger)
end
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the leader dies and there is no backup, the old trigger for the dead leader is removed but the patrol remains in the Game.patrols table. The UpdatePatrol function will continue to be called for this patrol, but will do nothing since patrol.leader is nil. However, the patrol entry remains in memory indefinitely. Consider removing the patrol from the Game.patrols table when there are no more creatures to continue it, to prevent accumulation of dead patrol entries.

Copilot uses AI. Check for mistakes.
Comment on lines +84 to +87
if patrol.leader and patrol.leader.party[2] then
patrol.partybackup = patrol.leader.party[2]
local trigger2 = RegisterCreatureDeathEvent(BackupDeath, patrol.partybackup)
trigger2.triggerData.patrol_idx = triggerData.patrol_idx
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the old backup creature dies and a new backup is assigned from the leader's party, the old trigger for the deceased backup is not removed. This will cause the BackupDeath trigger to remain in the Game.triggers table even though the creature is dead, leading to a memory leak of unused triggers. The trigger should be removed before registering a new one, similar to how it's handled in the LeaderDeath function at line 69.

Copilot uses AI. Check for mistakes.
patrol.next_post = (patrol.next_post % #patrol.positions) + 1
target = patrol.positions[patrol.next_post]
end
if (patrol.leader.moveto_pos.stl_x ~= target.stl_x or patrol.leader.moveto_pos.stl_y ~= target.stl_y) then
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential nil access error. If the creature has not been given any movement orders yet, moveto_pos might be nil or uninitialized, causing this line to error when accessing moveto_pos.stl_x or moveto_pos.stl_y. Consider adding a nil check or initializing moveto_pos to a safe default value when first creating the patrol.

Suggested change
if (patrol.leader.moveto_pos.stl_x ~= target.stl_x or patrol.leader.moveto_pos.stl_y ~= target.stl_y) then
local moveto_pos = patrol.leader.moveto_pos
if (moveto_pos == nil
or moveto_pos.stl_x ~= target.stl_x
or moveto_pos.stl_y ~= target.stl_y) then

Copilot uses AI. Check for mistakes.
Comment on lines +117 to +118
if leader.party[2] ~= nil then
local partybackup = leader.party[2]
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential nil access when checking leader.party. If leader doesn't have a party field (or party is nil), accessing party[2] will cause an error. Although Creature.lua defines party as a field, it may not always be initialized for all creatures. Consider adding a check to ensure party exists before accessing party[2].

Copilot uses AI. Check for mistakes.
Comment on lines +52 to +55
patrol.leader = patrol.partybackup.party[1]
if patrol.leader == nil then
patrol.leader = patrol.partybackup
end
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The succession logic is confusing. According to Creature.lua line 9, party[1] is always the leader of the party. So patrol.partybackup.party[1] would be partybackup itself if partybackup is a party leader. The condition at line 53 will always be false if partybackup has a party (since party[1] == partybackup), making this check unnecessary. The intent appears to be to promote partybackup to the new leader, which should be done directly without the intermediate check.

Suggested change
patrol.leader = patrol.partybackup.party[1]
if patrol.leader == nil then
patrol.leader = patrol.partybackup
end
-- Promote the backup unit directly to be the new leader
patrol.leader = patrol.partybackup

Copilot uses AI. Check for mistakes.
Comment on lines +73 to +92
function BackupDeath(eventData,triggerData)
local patrol = Game.patrols[triggerData.patrol_idx]
if patrol == nil then
return
end

if triggerData.unit == patrol.leader then
-- Leader died, ignore backup death
return
end

if patrol.leader and patrol.leader.party[2] then
patrol.partybackup = patrol.leader.party[2]
local trigger2 = RegisterCreatureDeathEvent(BackupDeath, patrol.partybackup)
trigger2.triggerData.patrol_idx = triggerData.patrol_idx
else
patrol.partybackup = nil
end

end
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The BackupDeath trigger is never removed when the backup dies. Unlike LeaderDeath which removes the trigger at line 69 when there's no backup left, BackupDeath doesn't clean up its own trigger. This means when a backup creature dies, their death trigger remains in the Game.triggers table indefinitely, causing a memory leak. The trigger should be removed using RemoveTrigger(triggerData.trigger) before potentially registering a new one or when setting partybackup to nil.

Copilot uses AI. Check for mistakes.
Comment on lines +60 to +61
if patrol.leader.party[2] then
patrol.partybackup = patrol.leader.party[2]
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential nil access when checking patrol.leader.party. If patrol.leader exists but doesn't have a party field (or party is nil), accessing party[2] will cause an error. Although Creature.lua defines party as a field, it may not always be initialized for all creatures. Consider adding a check to ensure party exists before accessing party[2].

Copilot uses AI. Check for mistakes.
Comment on lines +84 to +85
if patrol.leader and patrol.leader.party[2] then
patrol.partybackup = patrol.leader.party[2]
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential nil access when checking patrol.leader.party. If patrol.leader exists but doesn't have a party field (or party is nil), accessing party[2] will cause an error. Although Creature.lua defines party as a field, it may not always be initialized for all creatures. Consider adding a check to ensure party exists before accessing party[2].

Copilot uses AI. Check for mistakes.
end
else

RemoveTrigger(triggerData.trigger)
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code attempts to remove the trigger using triggerData.trigger, but triggerData.trigger is never set anywhere in this file. The trigger system doesn't automatically populate triggerData with a reference to the trigger object. This means RemoveTrigger is being called with nil, which will fail to remove the trigger and cause a memory leak. The trigger reference needs to be stored in triggerData when it's created, or the trigger should be removed using a different mechanism.

Copilot uses AI. Check for mistakes.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants