Fixes bundle 3 + new things#4212
Open
Henrybk wants to merge 3 commits into
Open
Conversation
Henrybk
referenced
this pull request
May 19, 2026
* Added missing keys to config * bundle * Update config.txt * Update Misc.pm * pot * Update config.txt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR is a follow-up bundle that fixes and extends several systems touched by the previous routing/attack/config updates.
It focuses on:
portals.txt;Task::Route;This PR is smaller than the previous bundle, but it improves several practical edge cases that appear during normal bot operation.
Highlights
portalUpdatePosition.replacePortalLUTto update or canonicalizeportals.txt.notWhileBeingCastedwhileBeingCastedwhenNoNearPartyMemberCastingwhenNearPartyMemberCastingtarget_notWhileBeingCastedtarget_whileBeingCastedactorIsBeingCastedOnnearPartyMemberIsCastingCastConditionsTest.pm.attackChangeTargetso it can switch from an aggressive target to a higher-priority aggressive target.getBestTarget.ZENYandTICKETroute weight defaults.Task::CalcMapRoute::getRouteString.isPortalRouteroute metadata.job_changedhook for self job changes.allto defaultpriority.txt.Motivation
This PR addresses several edge cases found after the previous routing and automation changes.
Why portal updates are needed
Portal recording previously tended to append new portal records when the known coordinates were slightly wrong. This can create duplicate or near-duplicate portal lines such as:
In practice, this may happen when:
This PR adds a safer update path that can replace the old canonical portal line instead of appending duplicate data.
Why cast conditions are needed
Many automation blocks need to know whether a skill is already being cast.
Examples:
Assumptioon a party member if someone is already castingAssumptioon them.Decrease Agilityon a monster if another party member is already casting it.Magnificatbefore using a follow-up behavior.The existing
whileCasting/notWhileCastingchecks only describe the character’s own casting state. They do not answer:This PR adds those condition checks.
Why attack target switching needed refinement
The previous
attackChangeTargetbehavior could switch away from a passive current target to an aggressive one, but it did not handle a second important case:This PR allows
attackChangeTargetto switch to a higher-priority aggressive monster when appropriate.This makes
priority.txtmore meaningful during combat, especially when the bot is already engaged but a more dangerous or more important monster appears.Config changes
1. New
portalUpdatePositionNew config key:
When enabled, OpenKore tries to update known portal coordinates after a map change if it detects that the real observed portal source/destination differs from the existing
portals.txtrecord.This works together with:
Example default area:
Behavior
When a route uses a known simple portal and the map changes, OpenKore stores a candidate describing the expected old portal line:
After the map change finishes,
processPortalRecordingcompares:If the portal is the same logical portal but the coordinates changed, OpenKore updates the existing
portals.txtline instead of appending a duplicate.2. New cast condition keys in
config.txtNew shared self-condition keys:
New player target condition keys:
New monster target condition keys:
These are documented in the shared condition templates in
control/config.txt.3. New route weight defaults
control/routeweights.txtnow includes:These make the route cost model explicit for:
This is important because the route calculator now tracks real zeny and ticket usage in addition to walk cost.
4. Default
priority.txtcatch-allcontrol/priority.txtnow includes:This gives a catch-all priority entry by default.
This matters because the attack target-switching update now uses monster priority to decide whether to switch from one aggressive target to another higher-priority aggressive target.
Portal update system
1.
processPortalRecordingnow supports update-only modePreviously:
Now:
This allows portal position updates to run even when the user wants to update known portal coordinates rather than only record unknown portals.
2. Portal update candidate tracking
Task::MapRoute::mapChangednow stores an update candidate when:portalUpdatePositionis enabled;%portals_lut.Example stored state:
This lets
processPortalRecordingknow whichportals.txtline the route expected to use.3. Updating known portal positions
New helper:
It checks whether the observed portal transition corresponds to the previously expected portal route.
If the source/destination maps match but the coordinates changed, it calls:
and logs:
Then it recompiles portals.
4. Updating nearby sibling portal records
New helper:
This handles the case where no exact old candidate exists, but a nearby portal record likely refers to the same logical portal.
It uses:
with drift thresholds:
Meaning:
If a nearby sibling is found, it replaces that line in
portals.txt.Example log:
5. Portal recompilation helper
New helper:
It performs:
This centralizes portal reload/recompile behavior after recording or updating.
replacePortalLUTsrc/FileParsers.pmadds:This function replaces or canonicalizes portal records in
portals.txt.Behavior
It can:
Return values:
updatePortalLUTandupdatePortalLUT2now usereplacePortalLUTBefore, both functions appended directly:
Now they call:
This prevents duplicate entries and gives callers a meaningful result.
Example
Old file:
# Prontera portal prontera 100 100 izlude 50 50Observed transition:
With
portalUpdatePosition 1, OpenKore can replace the old line:# Prontera portal prontera 101 100 izlude 51 50instead of appending:
# Prontera portal prontera 100 100 izlude 50 50 prontera 101 100 izlude 51 50Cast-aware condition system
1. New helper:
actorIsBeingCastedOnChecks whether any visible caster is currently casting one of the listed skills on the target actor.
It scans:
It checks each caster’s:
and compares:
The skill list is comma-separated.
Example skill list:
2. New helper:
nearPartyMemberIsCastingnearPartyMemberIsCasting($skills)Checks whether a visible party member is currently casting one of the listed skills.
It only considers actors that:
playersList;$char->{party}{users};castingstructure;This is useful for avoiding duplicate party support skill casts.
3. Self-condition cast checks
New
checkSelfConditionkeys:notWhileBeingCastedFails if one of the listed skills is currently being cast on self.
Example:
useSelf_skill Blessing { lvl 10 notWhileBeingCasted Blessing # [checkSelfCondition] }Meaning:
Blessingif someone is already castingBlessingon me.whileBeingCastedPasses only if one of the listed skills is currently being cast on self.
Example:
useSelf_skill Emergency Skill { whileBeingCasted HP_ASSUMPTIO # [checkSelfCondition] }Meaning:
HP_ASSUMPTIOis being cast on me.whenNoNearPartyMemberCastingFails if a visible party member is casting one of the listed skills.
Example:
useSelf_skill Magnificat { lvl 5 whenNoNearPartyMemberCasting PR_MAGNIFICAT # [checkSelfCondition] }Meaning:
Magnificatif a party member is already castingPR_MAGNIFICAT.whenNearPartyMemberCastingPasses only if a visible party member is casting one of the listed skills.
Example:
useSelf_skill Follow Up Skill { whenNearPartyMemberCasting PR_MAGNIFICAT # [checkSelfCondition] }Meaning:
PR_MAGNIFICAT.4. Player target cast checks
New
checkPlayerConditionkeys:target_notWhileBeingCastedFails if the player target is already receiving one of the listed casts.
Example:
partySkill Assumptio { lvl 5 target target_notWhileBeingCasted HP_ASSUMPTIO # [checkSelfCondition] # [checkPlayerCondition] }Meaning:
Assumptioif another actor is already castingHP_ASSUMPTIOon that party target.target_whileBeingCastedPasses only if the player target is receiving one of the listed casts.
Example:
partySkill Support Chain { target target_whileBeingCasted HP_ASSUMPTIO # [checkPlayerCondition] }5. Monster target cast checks
New
checkMonsterConditionkeys:target_notWhileBeingCastedFails if the monster target is already receiving one of the listed casts.
Example:
attackSkillSlot Decrease Agility { lvl 10 target_notWhileBeingCasted MER_DECAGI # [checkSelfCondition] # [checkMonsterCondition] }Meaning:
Decrease Agilityif someone is already casting it on that monster.target_whileBeingCastedPasses only if the monster is receiving one of the listed casts.
Example:
attackSkillSlot Follow Up { lvl 10 target_whileBeingCasted MER_DECAGI # [checkMonsterCondition] }Cast condition examples
Prevent duplicate Assumptio on party targets
partySkill Assumptio { lvl 5 target target_hp < 95% target_notWhileBeingCasted HP_ASSUMPTIO # [checkSelfCondition] # [checkPlayerCondition] }Prevent duplicate Magnificat casts in party
useSelf_skill Magnificat { lvl 5 sp > 40% whenNoNearPartyMemberCasting PR_MAGNIFICAT # [checkSelfCondition] }Do not debuff a monster while another actor is already casting the same debuff
attackSkillSlot Decrease Agility { lvl 10 target_notWhileBeingCasted MER_DECAGI # [checkSelfCondition] # [checkMonsterCondition] }Only run a block while a party member is casting a specific skill
useSelf_skill Prepare Followup { whenNearPartyMemberCasting PR_MAGNIFICAT # [checkSelfCondition] }Only run a block while self is being targeted by a skill cast
useSelf_skill Emergency Response { whileBeingCasted Blessing,HP_ASSUMPTIO # [checkSelfCondition] }Attack logic updates
1.
attackChangeTargetcan now switch to higher-priority aggressive targetsPreviously, target switching mainly handled:
Now it also handles:
New logic compares:
It can switch when:
$switch_to_aggressiveor:
$switch_to_higher_priorityExample log when switching to a higher-priority aggressive target:
Example log when switching from passive to aggressive:
2. Why this matters
With
priority.txtnow including:and user-specific priorities, the bot can make better choices in crowded combat.
Example:
If the bot is attacking a normal aggressive monster and a higher-priority aggressive monster appears,
attackChangeTargetcan switch to the more important target.3. Recent failed targets are filtered inside
getBestTargetNew helper:
It checks:
using:
getBestTargetnow skips recently failed targets.This centralizes failed-target filtering instead of scattering it in
processAutoAttack.4.
getBestTargetnow respectsattackRouteMaxPathDistanceTarget selection now skips monsters whose direct block distance exceeds:
It also skips pathfinding candidates whose route solution length exceeds the same limit.
This prevents target selection from choosing monsters that are technically visible or known but too far to route to under the configured attack path limits.
5. Removed old failed-target filtering from
processAutoAttackThe old logic in
processAutoAttackdirectly skipped monsters using:That filtering was removed from the loop because it is now handled in
getBestTarget.This keeps target filtering more consistent across different callers.
Attack code documentation cleanup
src/AI/Attack.pmnow includes many clarifying comments around the attack loop.This does not only document the code; it makes future review of the attack state machine easier by explaining the purpose of each stage.
Documented areas include:
attack_auto == 3;This is especially useful because
AI::Attackcontains complex interactions between movement prediction, skill selection, kiting, route resets, and target switching.Route calculation updates
1.
getRouteStringnow includes coordinates and walk costOld route string example:
New format:
This is much more useful for debugging:
searchshop;2.
searchStepdebug improvementsTask::CalcMapRoute::searchStepnow tracks:and logs:
This gives better visibility into route expansion behavior.
3. Route expansion cleanup
searchStepwas restructured to:This improves readability and reduces nested control flow.
4.
canAddOpenListEntryTODOA TODO was added around duplicate route states:
This documents a known route-cost/heap duplicate-state issue for future work.
5. Dynamic portal debug noise reduction
The verbose debug message inside
isPortalDestinationEnabledForRoutewhen a dynamic portal group is blocked was removed.The actual blocking behavior remains, but the route calculation becomes less noisy.
MapRoute and Route changes
1. Portal route metadata
Task::MapRoutenow passes:when creating route subtasks for portal movement.
Task::Routenow allows:as a valid constructor argument.
This makes it possible to distinguish normal routes from portal-entry routes.
2. Missing portal proximity tolerance
The missing portal check changed from:
to:
This is more forgiving when the actor ends up adjacent to the expected portal cell rather than exactly on it.
This helps with real in-game movement where the client/server may stop the character one cell away from the portal trigger cell.
3. Occupied destination stopping logic
Task::Routenow stops one cell away from an occupied destination when:Previously it depended on
stepsleft == 2and not being a meeting subroute.The new condition is more general and uses actual distance to destination.
This helps when the destination cell is occupied by another actor, portal object, or obstacle and the route is already close enough.
Network/packet handling changes
1. Skill delay statuses now use stable skill handles
skill_post_delayandskill_post_delaylistnow set status using skill handles:instead of localized display names plus
" Delay".Before:
After:
Example:
This is more stable for config/status checks because it avoids localized skill names.
2. Self job-change hook
sprite_changenow distinguishes self job changes from other player job changes.For self:
It also logs:
For other players, behavior remains a normal message:
This gives plugins a clean way to react to the player’s own job changes.
3. Sell result handling fix
sell_resultnow counts sold items using:and only prints item count if greater than zero:
It also now finds the
sellAutoaction by index:and sets:
This is safer than assuming the current AI action is
sellAuto.4. Casting packets now store
targetIDskill_castnow stores:inside:
This is required by the new
actorIsBeingCastedOnhelper.It lets cast conditions reliably identify the target actor even when the target object reference is missing or stale.
Autosell fix
Inside
processAutoSell, the sell list now uses the global@sellListdirectly instead of a local@sellItems.Before:
After:
This matches the later
sell_resultlogic, which checks@sellList.This fixes mismatches where the sell result handler could not accurately report or track the items that were sent for selling.
Tests
New test file:
Registered in:
Cast condition tests cover
The new tests cover:
Example tested scenarios
Self being casted on
Config:
Expected:
Party member casting nearby
Config:
Expected:
Player target already receiving Assumptio
Config:
Expected:
Monster target already receiving Decrease Agility
Config:
Expected:
Example configurations
Prevent duplicate party Assumptio casts
partySkill Assumptio { lvl 5 target target_hp < 95% target_notWhileBeingCasted HP_ASSUMPTIO # [checkSelfCondition] # [checkPlayerCondition] }Prevent duplicate Magnificat in party
useSelf_skill Magnificat { lvl 5 sp > 40% whenNoNearPartyMemberCasting PR_MAGNIFICAT # [checkSelfCondition] }Only cast when a party member is casting Magnificat
useSelf_skill Follow Up { whenNearPartyMemberCasting PR_MAGNIFICAT # [checkSelfCondition] }Do not debuff a monster while the same debuff is already being cast
attackSkillSlot Decrease Agility { lvl 10 target_notWhileBeingCasted MER_DECAGI # [checkSelfCondition] # [checkMonsterCondition] }Only run a monster skill while a target is being casted on
attackSkillSlot Follow Up Skill { lvl 10 target_whileBeingCasted MER_DECAGI # [checkSelfCondition] # [checkMonsterCondition] }Attack target switching with priority
Example
priority.txt:If currently attacking a lower-priority aggressive monster and a higher-priority aggressive monster appears, OpenKore can switch targets.
Portal update behavior
Expected behavior:
portals.txt;Manual test plan
Portal update system
portalUpdatePosition 1.portals.txtupdates the old line instead of appending a duplicate.portals.txtare preserved.portalRecord_recompileAfter 1reloads/recompiles portals.Cast conditions
notWhileBeingCastedon self.whileBeingCastedon self.whenNoNearPartyMemberCasting.whenNearPartyMemberCasting.target_notWhileBeingCastedforpartySkill.target_whileBeingCastedforpartySkill.target_notWhileBeingCastedforattackSkillSlot.target_whileBeingCastedforattackSkillSlot.Attack target switching
attackChangeTarget.attackRouteMaxPathDistanceare skipped.Autosell
sellAuto.@sellListis populated.sell_resultreports the correct item count.recv_sell_packetis set on the queuedsellAutoaction, not necessarily the current action.Skill delay statuses
<SKILL_HANDLE>_DELAY.Job change hook
job_changedhook is called with old/new job IDs.Route behavior
isPortalRoute.<= 1.Unit tests
Suggested command:
New test registration:
New files
Modified files
Compatibility notes
portalUpdatePositiondefaults to1, so portal recording can now update known portal coordinates.updatePortalLUTandupdatePortalLUT2now go throughreplacePortalLUTinstead of direct append._DELAY, not localized names plusDelay.HP_ASSUMPTIOPR_MAGNIFICATMER_DECAGIpriority.txtnow includesall, which can affect target priority behavior whenattackChangeTargetis enabled.getBestTargetnow skips recently failed targets and targets exceedingattackRouteMaxPathDistance.Task::Routenow acceptsisPortalRouteas route metadata.Review focus
Please review carefully:
replacePortalLUTbehavior with comments, blank lines, existing duplicates, and stepped portal lines.processPortalRecording.Task::MapRoute::mapChanged.2;6.portalUpdatePosition 1should be default-enabled.actorIsBeingCastedOnscanning all actor lists.nearPartyMemberIsCastingonly considering visible party members.getBestTargetfiltering recently failed targets.attackRouteMaxPathDistancefiltering in direct and pathfinding branches.@sellItemsto global@sellList.job_changedhook naming and payload.Short changelog
portalUpdatePosition.replacePortalLUT.updatePortalLUTandupdatePortalLUT2to avoid duplicate appends.actorIsBeingCastedOn.nearPartyMemberIsCasting.CastConditionsTest.ZENYandTICKETroute weight defaults.alltopriority.txt.attackChangeTargetto switch to higher-priority aggressive monsters.getBestTarget.attackRouteMaxPathDistancefiltering to target selection.Task::CalcMapRoute::getRouteString.isPortalRouteroute metadata.Task::Route._DELAYstatuses.job_changedhook for self job changes.targetIDto skill casting state.