From 40baf41e22ab386b5b2a4ca88cc0260153a4d8e0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Nov 2025 00:14:40 +0000 Subject: [PATCH 1/6] Initial plan From 422166b0a8d34491039ba23cd3a3dc6a0995521e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Nov 2025 00:20:39 +0000 Subject: [PATCH 2/6] Remove debug logs and fix Arcane Echo/Auspicious cooldown logic - Removed all EchoFollowup debug logging statements (~40 statements) - Fixed cooldown logic: Target spell can now be cast if EITHER Echo OR Auspicious is on cooldown - Previous behavior: Prevented casting if EITHER was ready - New behavior: Only prevent casting if BOTH are ready Co-authored-by: Ewoog <72410352+Ewoog@users.noreply.github.com> --- HeroAI/combat.py | 126 ++++++++++------------------------------------- 1 file changed, 26 insertions(+), 100 deletions(-) diff --git a/HeroAI/combat.py b/HeroAI/combat.py index ece5379f6..6f74ea98d 100644 --- a/HeroAI/combat.py +++ b/HeroAI/combat.py @@ -1331,43 +1331,32 @@ def HandleCombat(self,ooc=False): skill_id = self.skills[slot].skill_id skill_name = GLOBAL_CACHE.Skill.GetName(skill_id) - Py4GW.Console.Log("EchoFollowup", f"Pending follow-up detected: slot={slot}, skill={skill_name} (ID:{skill_id})", Py4GW.Console.MessageType.Info) - # Check if we're still in aftercast from the previous spell (Echo/Auspicious) # If so, wait for it to complete before casting the follow-up if self.in_casting_routine: # Still in aftercast, return False to wait - elapsed = self.aftercast_timer.GetElapsedTime() - Py4GW.Console.Log("EchoFollowup", f"Waiting for aftercast to complete (elapsed: {elapsed}ms, target: {self.aftercast}ms)", Py4GW.Console.MessageType.Warning) return False # Not in aftercast anymore, attempt to cast the follow-up immediately # We skip most checks here because we already validated the skill was ready before casting Echo/Auspicious - Py4GW.Console.Log("EchoFollowup", "Aftercast complete, proceeding with follow-up cast checks", Py4GW.Console.MessageType.Info) - # Only do minimal validation: check if player can cast and target is valid if GLOBAL_CACHE.Agent.IsCasting(GLOBAL_CACHE.Player.GetAgentID()): # Player is casting, wait - Py4GW.Console.Log("EchoFollowup", "Player is currently casting, waiting...", Py4GW.Console.MessageType.Warning) return False if GLOBAL_CACHE.SkillBar.GetCasting() != 0: # Something is being cast, wait - casting_skill = GLOBAL_CACHE.SkillBar.GetCasting() - Py4GW.Console.Log("EchoFollowup", f"SkillBar shows casting in progress (skill: {casting_skill}), waiting...", Py4GW.Console.MessageType.Warning) return False # Get target for the follow-up skill target_agent_id = self.GetAppropiateTarget(slot) if target_agent_id == 0 or not GLOBAL_CACHE.Agent.IsLiving(target_agent_id): # Target not valid, clear pending and continue - Py4GW.Console.Log("EchoFollowup", f"Target not valid (ID: {target_agent_id}), clearing pending follow-up", Py4GW.Console.MessageType.Error) self.pending_followup_skill_slot = -1 return False # Cast the follow-up skill immediately - Py4GW.Console.Log("EchoFollowup", f"CASTING FOLLOW-UP: {skill_name} on target {target_agent_id}", Py4GW.Console.MessageType.Success) self.in_casting_routine = True if self.fast_casting_exists: @@ -1390,9 +1379,6 @@ def HandleCombat(self,ooc=False): # Check if the follow-up skill we just cast is Arcane Echo or Auspicious Incantation # If so, it also needs to set up its own follow-up skill if skill_id == self.arcane_echo or skill_id == self.auspicious_incantation: - echo_spell_name = GLOBAL_CACHE.Skill.GetName(skill_id) - Py4GW.Console.Log("EchoFollowup", f"Follow-up was {echo_spell_name}, setting up its follow-up...", Py4GW.Console.MessageType.Info) - from HeroAI.settings import Settings settings = Settings() @@ -1405,8 +1391,6 @@ def HandleCombat(self,ooc=False): nested_followup_skill_id = GLOBAL_CACHE.SkillBar.GetSkillIDBySlot(nested_followup_skillbar_slot + 1) if nested_followup_skill_id > 0 and nested_followup_skill_id != skill_id: - nested_followup_skill_name = GLOBAL_CACHE.Skill.GetName(nested_followup_skill_id) - # Find the prioritized slot index for this skill ID nested_followup_prioritized_slot = -1 for i in range(len(self.skills)): @@ -1415,62 +1399,45 @@ def HandleCombat(self,ooc=False): break if nested_followup_prioritized_slot >= 0: - Py4GW.Console.Log("EchoFollowup", f"Setting up nested follow-up: {nested_followup_skill_name} at prioritized slot {nested_followup_prioritized_slot}", Py4GW.Console.MessageType.Info) self.pending_followup_skill_slot = nested_followup_prioritized_slot self.followup_skill_timer.Reset() self.followup_skill_timer.Start() # Don't clear pending or reset pointer here - let the nested follow-up cast next - Py4GW.Console.Log("EchoFollowup", "Follow-up cast complete, nested follow-up pending", Py4GW.Console.MessageType.Success) return True # Clear the pending follow-up self.pending_followup_skill_slot = -1 self.ResetSkillPointer() - Py4GW.Console.Log("EchoFollowup", "Follow-up cast complete, pending cleared", Py4GW.Console.MessageType.Success) return True slot = self.skill_pointer skill_id = self.skills[slot].skill_id skill_name = GLOBAL_CACHE.Skill.GetName(skill_id) - # Debug logging for Auspicious Incantation - if skill_id == self.auspicious_incantation: - Py4GW.Console.Log("EchoFollowup", f"[DEBUG] Evaluating Auspicious Incantation at slot {slot}", Py4GW.Console.MessageType.Info) - is_skill_ready = self.IsSkillReady(slot) if not is_skill_ready: - if skill_id == self.auspicious_incantation: - Py4GW.Console.Log("EchoFollowup", f"[DEBUG] Auspicious failed IsSkillReady check", Py4GW.Console.MessageType.Warning) self.AdvanceSkillPointer() return False is_ooc_skill = self.IsOOCSkill(slot) if ooc and not is_ooc_skill: - if skill_id == self.auspicious_incantation: - Py4GW.Console.Log("EchoFollowup", f"[DEBUG] Auspicious failed OOC check (ooc={ooc}, is_ooc_skill={is_ooc_skill})", Py4GW.Console.MessageType.Warning) self.AdvanceSkillPointer() return False is_read_to_cast, target_agent_id = self.IsReadyToCast(slot) if not is_read_to_cast: - if skill_id == self.auspicious_incantation: - Py4GW.Console.Log("EchoFollowup", f"[DEBUG] Auspicious failed IsReadyToCast check", Py4GW.Console.MessageType.Warning) self.AdvanceSkillPointer() return False if target_agent_id == 0: - if skill_id == self.auspicious_incantation: - Py4GW.Console.Log("EchoFollowup", f"[DEBUG] Auspicious has no target (target_agent_id=0)", Py4GW.Console.MessageType.Warning) self.AdvanceSkillPointer() return False if not GLOBAL_CACHE.Agent.IsLiving(target_agent_id): - if skill_id == self.auspicious_incantation: - Py4GW.Console.Log("EchoFollowup", f"[DEBUG] Auspicious target not living (target_agent_id={target_agent_id})", Py4GW.Console.MessageType.Warning) return False # Special check for Arcane Echo: ensure target spell is ready @@ -1479,15 +1446,10 @@ def HandleCombat(self,ooc=False): settings = Settings() followup_skillbar_slot = settings.ArcaneEchoSkillSlot # This is the SKILLBAR slot (0-7), not prioritized index - Py4GW.Console.Log("EchoFollowup", f"Pre-cast check for Arcane Echo (configured skillbar slot={followup_skillbar_slot})", Py4GW.Console.MessageType.Info) - # Get the skill ID from the skillbar slot (1-based for GetSkillIDBySlot) followup_skill_id = GLOBAL_CACHE.SkillBar.GetSkillIDBySlot(followup_skillbar_slot + 1) if followup_skill_id > 0: - followup_skill_name = GLOBAL_CACHE.Skill.GetName(followup_skill_id) - Py4GW.Console.Log("EchoFollowup", f"Target skill in skillbar slot {followup_skillbar_slot}: {followup_skill_name} (ID: {followup_skill_id})", Py4GW.Console.MessageType.Info) - # Priority check: If Auspicious Incantation is configured to target Arcane Echo and is ready, # skip Arcane Echo to let Auspicious cast first # @@ -1507,22 +1469,15 @@ def HandleCombat(self,ooc=False): # Auspicious targets Arcane Echo slot is_auspicious_ready = Routines.Checks.Skills.IsSkillIDReady(self.auspicious_incantation) if is_auspicious_ready: - Py4GW.Console.Log("EchoFollowup", f"Auspicious Incantation is ready and targeting Arcane Echo - giving priority to Auspicious, skipping Arcane Echo", Py4GW.Console.MessageType.Info) self.ResetSkillPointer() # Reset to start so Auspicious gets a chance to cast return False # Check if the followup skill is ready (not on cooldown) is_ready = Routines.Checks.Skills.IsSkillIDReady(followup_skill_id) - Py4GW.Console.Log("EchoFollowup", f"Target spell {followup_skill_name} ready check: {is_ready}", Py4GW.Console.MessageType.Info) if not is_ready: - Py4GW.Console.Log("EchoFollowup", f"Target spell {followup_skill_name} NOT READY - skipping Arcane Echo cast", Py4GW.Console.MessageType.Warning) self.AdvanceSkillPointer() return False - else: - Py4GW.Console.Log("EchoFollowup", f"Target spell {followup_skill_name} is ready - proceeding with Arcane Echo cast", Py4GW.Console.MessageType.Success) - else: - Py4GW.Console.Log("EchoFollowup", f"No skill found in skillbar slot {followup_skillbar_slot}", Py4GW.Console.MessageType.Error) # Special check for Auspicious Incantation: ensure we have enough energy for both # Auspicious Incantation AND the target spell @@ -1531,19 +1486,13 @@ def HandleCombat(self,ooc=False): settings = Settings() followup_skillbar_slot = settings.AuspiciousIncantationSkillSlot # This is skillbar slot (0-7) - Py4GW.Console.Log("EchoFollowup", f"Pre-cast check for Auspicious Incantation (configured skillbar slot={followup_skillbar_slot})", Py4GW.Console.MessageType.Info) - # Get the skill ID from the skillbar slot (1-based for GetSkillIDBySlot) followup_skill_id = GLOBAL_CACHE.SkillBar.GetSkillIDBySlot(followup_skillbar_slot + 1) if followup_skill_id > 0: - followup_skill_name = GLOBAL_CACHE.Skill.GetName(followup_skill_id) - Py4GW.Console.Log("EchoFollowup", f"Target skill in skillbar slot {followup_skillbar_slot}: {followup_skill_name} (ID: {followup_skill_id})", Py4GW.Console.MessageType.Info) - # Check if the followup skill is ready (not on cooldown) is_ready = Routines.Checks.Skills.IsSkillIDReady(followup_skill_id) if not is_ready: - Py4GW.Console.Log("EchoFollowup", f"Target spell {followup_skill_name} NOT READY - skipping Auspicious Incantation cast", Py4GW.Console.MessageType.Warning) self.AdvanceSkillPointer() return False @@ -1562,55 +1511,48 @@ def HandleCombat(self,ooc=False): total_energy_needed = auspicious_cost + followup_cost - Py4GW.Console.Log("EchoFollowup", f"Energy check: Current={current_energy:.0f}, Needed={total_energy_needed:.0f} (Auspicious={auspicious_cost:.0f} + Target={followup_cost:.0f})", Py4GW.Console.MessageType.Info) - if current_energy < total_energy_needed: - Py4GW.Console.Log("EchoFollowup", f"Not enough energy - skipping Auspicious Incantation cast", Py4GW.Console.MessageType.Warning) self.AdvanceSkillPointer() return False - else: - Py4GW.Console.Log("EchoFollowup", f"Energy sufficient - proceeding with Auspicious Incantation cast", Py4GW.Console.MessageType.Success) - else: - Py4GW.Console.Log("EchoFollowup", f"No skill found in skillbar slot {followup_skillbar_slot}", Py4GW.Console.MessageType.Error) # Check if this is a target spell for Arcane Echo or Auspicious Incantation - # If so, and the Echo/Auspicious spell is available, skip this spell + # If so, and BOTH Echo AND Auspicious spells are available, skip this spell # Priority: Auspicious (highest) -> Arcane -> target spell + # Allow casting the target spell if at least one of Echo/Auspicious is on cooldown from HeroAI.settings import Settings settings = Settings() - # Check if current skill is the Auspicious target and Auspicious is ready - if (settings.AuspiciousIncantationSkillSlot < len(self.skills) and - skill_id == self.skills[settings.AuspiciousIncantationSkillSlot].skill_id and - skill_id != self.auspicious_incantation): - # Check if Auspicious Incantation is ready - if Routines.Checks.Skills.IsSkillIDReady(self.auspicious_incantation): - # Skip this spell, let Auspicious cast first + # Check if current skill is the target for Auspicious OR Arcane Echo + is_auspicious_target = (settings.AuspiciousIncantationSkillSlot < len(self.skills) and + skill_id == self.skills[settings.AuspiciousIncantationSkillSlot].skill_id and + skill_id != self.auspicious_incantation) + + is_arcane_target = (settings.ArcaneEchoSkillSlot < len(self.skills) and + skill_id == self.skills[settings.ArcaneEchoSkillSlot].skill_id and + skill_id != self.arcane_echo) + + # Only skip if BOTH are ready (meaning we want the chain to happen) + if is_auspicious_target or is_arcane_target: + auspicious_ready = Routines.Checks.Skills.IsSkillIDReady(self.auspicious_incantation) + arcane_ready = Routines.Checks.Skills.IsSkillIDReady(self.arcane_echo) + + # Skip only if both are configured as targets AND both are ready + if is_auspicious_target and is_arcane_target and auspicious_ready and arcane_ready: + # Both echo spells are ready, let them cast first self.AdvanceSkillPointer() return False - - # Check if current skill is the Arcane Echo target and Arcane Echo is ready - if (settings.ArcaneEchoSkillSlot < len(self.skills) and - skill_id == self.skills[settings.ArcaneEchoSkillSlot].skill_id and - skill_id != self.arcane_echo): - # Check if Arcane Echo is ready - if Routines.Checks.Skills.IsSkillIDReady(self.arcane_echo): - # Skip this spell, let Arcane Echo cast first + elif is_auspicious_target and auspicious_ready and not is_arcane_target: + # Only Auspicious target and it's ready, let it cast first + self.AdvanceSkillPointer() + return False + elif is_arcane_target and arcane_ready and not is_auspicious_target: + # Only Arcane target and it's ready, let it cast first self.AdvanceSkillPointer() return False + # Otherwise, at least one is on cooldown, so allow casting the target spell self.in_casting_routine = True - # Log when we're about to cast a skill (to detect if other skills are being cast when they shouldn't) - skill_name = GLOBAL_CACHE.Skill.GetName(skill_id) - if self.pending_followup_skill_slot >= 0: - # This should NEVER happen - if there's a pending follow-up, we should have handled it above - Py4GW.Console.Log("EchoFollowup", f"ERROR: Casting {skill_name} while pending_followup_skill_slot={self.pending_followup_skill_slot}! This is a bug!", Py4GW.Console.MessageType.Error) - - if skill_id == self.arcane_echo or skill_id == self.auspicious_incantation: - Py4GW.Console.Log("EchoFollowup", f"Casting {skill_name} (will set up follow-up after)", Py4GW.Console.MessageType.Info) - - if self.fast_casting_exists: activation, recharge = Routines.Checks.Skills.apply_fast_casting(skill_id, self.fast_casting_level) else: @@ -1633,9 +1575,6 @@ def HandleCombat(self,ooc=False): # Check if we just cast Arcane Echo or Auspicious Incantation # If so, schedule the configured follow-up skill to be cast next if skill_id == self.arcane_echo or skill_id == self.auspicious_incantation: - echo_spell_name = GLOBAL_CACHE.Skill.GetName(skill_id) - Py4GW.Console.Log("EchoFollowup", f"Just cast {echo_spell_name}, setting up follow-up...", Py4GW.Console.MessageType.Info) - from HeroAI.settings import Settings settings = Settings() @@ -1644,14 +1583,10 @@ def HandleCombat(self,ooc=False): else: # auspicious_incantation followup_skillbar_slot = settings.AuspiciousIncantationSkillSlot # This is skillbar slot (0-7) - Py4GW.Console.Log("EchoFollowup", f"Configured follow-up skillbar slot: {followup_skillbar_slot}", Py4GW.Console.MessageType.Info) - # Get the skill ID from the skillbar slot followup_skill_id = GLOBAL_CACHE.SkillBar.GetSkillIDBySlot(followup_skillbar_slot + 1) # +1 because GetSkillIDBySlot uses 1-based indexing if followup_skill_id > 0 and followup_skill_id != skill_id: - followup_skill_name = GLOBAL_CACHE.Skill.GetName(followup_skill_id) - # Find the prioritized slot index for this skill ID followup_prioritized_slot = -1 for i in range(len(self.skills)): @@ -1660,18 +1595,9 @@ def HandleCombat(self,ooc=False): break if followup_prioritized_slot >= 0: - Py4GW.Console.Log("EchoFollowup", f"Found {followup_skill_name} at prioritized slot {followup_prioritized_slot} (skillbar slot {followup_skillbar_slot})", Py4GW.Console.MessageType.Info) self.pending_followup_skill_slot = followup_prioritized_slot self.followup_skill_timer.Reset() self.followup_skill_timer.Start() - Py4GW.Console.Log("EchoFollowup", f"PENDING FOLLOW-UP SET: Will cast {followup_skill_name} next (aftercast: {self.aftercast}ms)", Py4GW.Console.MessageType.Success) - else: - Py4GW.Console.Log("EchoFollowup", f"Could not find {followup_skill_name} in prioritized skill list!", Py4GW.Console.MessageType.Error) - else: - if followup_skill_id == 0: - Py4GW.Console.Log("EchoFollowup", f"No skill in skillbar slot {followup_skillbar_slot}", Py4GW.Console.MessageType.Error) - elif followup_skill_id == skill_id: - Py4GW.Console.Log("EchoFollowup", f"Follow-up skill is same as Echo spell, not setting pending", Py4GW.Console.MessageType.Error) self.ResetSkillPointer() return True \ No newline at end of file From ee382a6f079f05032c3b2d9ccc4992f01ac6262c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Nov 2025 00:21:43 +0000 Subject: [PATCH 3/6] Address code review feedback - simplify logic and fix comments Co-authored-by: Ewoog <72410352+Ewoog@users.noreply.github.com> --- HeroAI/combat.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/HeroAI/combat.py b/HeroAI/combat.py index 6f74ea98d..ef3b6b364 100644 --- a/HeroAI/combat.py +++ b/HeroAI/combat.py @@ -1516,7 +1516,7 @@ def HandleCombat(self,ooc=False): return False # Check if this is a target spell for Arcane Echo or Auspicious Incantation - # If so, and BOTH Echo AND Auspicious spells are available, skip this spell + # If so, and BOTH Echo AND Auspicious are ready, skip this spell # Priority: Auspicious (highest) -> Arcane -> target spell # Allow casting the target spell if at least one of Echo/Auspicious is on cooldown from HeroAI.settings import Settings @@ -1531,7 +1531,7 @@ def HandleCombat(self,ooc=False): skill_id == self.skills[settings.ArcaneEchoSkillSlot].skill_id and skill_id != self.arcane_echo) - # Only skip if BOTH are ready (meaning we want the chain to happen) + # Only skip if the corresponding echo spell(s) are ready if is_auspicious_target or is_arcane_target: auspicious_ready = Routines.Checks.Skills.IsSkillIDReady(self.auspicious_incantation) arcane_ready = Routines.Checks.Skills.IsSkillIDReady(self.arcane_echo) @@ -1541,12 +1541,12 @@ def HandleCombat(self,ooc=False): # Both echo spells are ready, let them cast first self.AdvanceSkillPointer() return False - elif is_auspicious_target and auspicious_ready and not is_arcane_target: - # Only Auspicious target and it's ready, let it cast first + elif is_auspicious_target and auspicious_ready: + # Auspicious target and it's ready, let it cast first self.AdvanceSkillPointer() return False - elif is_arcane_target and arcane_ready and not is_auspicious_target: - # Only Arcane target and it's ready, let it cast first + elif is_arcane_target and arcane_ready: + # Arcane target and it's ready, let it cast first self.AdvanceSkillPointer() return False # Otherwise, at least one is on cooldown, so allow casting the target spell From cf6a5091b2adb83452c7fde8072b48ebcb3135af Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Nov 2025 00:23:06 +0000 Subject: [PATCH 4/6] Simplify cooldown logic - remove unreachable condition Co-authored-by: Ewoog <72410352+Ewoog@users.noreply.github.com> --- HeroAI/combat.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/HeroAI/combat.py b/HeroAI/combat.py index ef3b6b364..e37e9b7e5 100644 --- a/HeroAI/combat.py +++ b/HeroAI/combat.py @@ -1516,9 +1516,9 @@ def HandleCombat(self,ooc=False): return False # Check if this is a target spell for Arcane Echo or Auspicious Incantation - # If so, and BOTH Echo AND Auspicious are ready, skip this spell + # If so, and the corresponding echo spell is ready, skip this spell to let the echo spell cast first # Priority: Auspicious (highest) -> Arcane -> target spell - # Allow casting the target spell if at least one of Echo/Auspicious is on cooldown + # Allow casting the target spell if the echo spell is on cooldown from HeroAI.settings import Settings settings = Settings() @@ -1531,17 +1531,13 @@ def HandleCombat(self,ooc=False): skill_id == self.skills[settings.ArcaneEchoSkillSlot].skill_id and skill_id != self.arcane_echo) - # Only skip if the corresponding echo spell(s) are ready + # Skip if the corresponding echo spell is ready (let it cast first) if is_auspicious_target or is_arcane_target: auspicious_ready = Routines.Checks.Skills.IsSkillIDReady(self.auspicious_incantation) arcane_ready = Routines.Checks.Skills.IsSkillIDReady(self.arcane_echo) - # Skip only if both are configured as targets AND both are ready - if is_auspicious_target and is_arcane_target and auspicious_ready and arcane_ready: - # Both echo spells are ready, let them cast first - self.AdvanceSkillPointer() - return False - elif is_auspicious_target and auspicious_ready: + # Check Auspicious first (higher priority) + if is_auspicious_target and auspicious_ready: # Auspicious target and it's ready, let it cast first self.AdvanceSkillPointer() return False @@ -1549,7 +1545,7 @@ def HandleCombat(self,ooc=False): # Arcane target and it's ready, let it cast first self.AdvanceSkillPointer() return False - # Otherwise, at least one is on cooldown, so allow casting the target spell + # Otherwise, the echo spell is on cooldown, so allow casting the target spell self.in_casting_routine = True From a658c2a1cbf2a9ae962160b6809c0188d0d5c558 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Nov 2025 00:25:21 +0000 Subject: [PATCH 5/6] Optimize cooldown checks - only check relevant echo spell Co-authored-by: Ewoog <72410352+Ewoog@users.noreply.github.com> --- HeroAI/combat.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/HeroAI/combat.py b/HeroAI/combat.py index e37e9b7e5..3d8c00b55 100644 --- a/HeroAI/combat.py +++ b/HeroAI/combat.py @@ -1532,20 +1532,22 @@ def HandleCombat(self,ooc=False): skill_id != self.arcane_echo) # Skip if the corresponding echo spell is ready (let it cast first) - if is_auspicious_target or is_arcane_target: + # Check Auspicious first (higher priority) + if is_auspicious_target: auspicious_ready = Routines.Checks.Skills.IsSkillIDReady(self.auspicious_incantation) - arcane_ready = Routines.Checks.Skills.IsSkillIDReady(self.arcane_echo) - - # Check Auspicious first (higher priority) - if is_auspicious_target and auspicious_ready: + if auspicious_ready: # Auspicious target and it's ready, let it cast first self.AdvanceSkillPointer() return False - elif is_arcane_target and arcane_ready: + + if is_arcane_target: + arcane_ready = Routines.Checks.Skills.IsSkillIDReady(self.arcane_echo) + if arcane_ready: # Arcane target and it's ready, let it cast first self.AdvanceSkillPointer() return False - # Otherwise, the echo spell is on cooldown, so allow casting the target spell + + # Otherwise, the echo spell is on cooldown, so allow casting the target spell self.in_casting_routine = True From fd49acd4cf4f9e5560420e79358a2713dcccbb3f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 23 Nov 2025 02:20:51 +0000 Subject: [PATCH 6/6] Fix critical bug - use skillbar slot correctly to get target skill IDs The previous logic incorrectly used skillbar slot numbers to index into the prioritized skills array. This prevented any skills from being cast. Now correctly retrieves skill IDs from skillbar slots using GetSkillIDBySlot() API. Co-authored-by: Ewoog <72410352+Ewoog@users.noreply.github.com> --- HeroAI/combat.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/HeroAI/combat.py b/HeroAI/combat.py index 3d8c00b55..582142bad 100644 --- a/HeroAI/combat.py +++ b/HeroAI/combat.py @@ -1522,13 +1522,17 @@ def HandleCombat(self,ooc=False): from HeroAI.settings import Settings settings = Settings() + # Get the skill IDs from the configured skillbar slots + auspicious_target_skill_id = GLOBAL_CACHE.SkillBar.GetSkillIDBySlot(settings.AuspiciousIncantationSkillSlot + 1) + arcane_target_skill_id = GLOBAL_CACHE.SkillBar.GetSkillIDBySlot(settings.ArcaneEchoSkillSlot + 1) + # Check if current skill is the target for Auspicious OR Arcane Echo - is_auspicious_target = (settings.AuspiciousIncantationSkillSlot < len(self.skills) and - skill_id == self.skills[settings.AuspiciousIncantationSkillSlot].skill_id and + is_auspicious_target = (auspicious_target_skill_id > 0 and + skill_id == auspicious_target_skill_id and skill_id != self.auspicious_incantation) - is_arcane_target = (settings.ArcaneEchoSkillSlot < len(self.skills) and - skill_id == self.skills[settings.ArcaneEchoSkillSlot].skill_id and + is_arcane_target = (arcane_target_skill_id > 0 and + skill_id == arcane_target_skill_id and skill_id != self.arcane_echo) # Skip if the corresponding echo spell is ready (let it cast first)