add lockandkey portal bot: summon portals on tell, stipend collection, partial bella (jaw only)
All checks were successful
/ test (push) Successful in 25s

This commit is contained in:
Erik 2026-04-14 21:15:43 +02:00
parent de5ea084db
commit 6780b985cb
2 changed files with 3364 additions and 0 deletions

448
af/lockandkey.af Normal file
View file

@ -0,0 +1,448 @@
~~
~~ lockandkey.af - Portal Bot with Stipend & Partial Bella Services
~~
~~ A portal summoning bot that:
~~ - Listens for tells containing "primary" or "secondary" to summon portals
~~ - Collects stipend on timer (with backoff)
~~ - Runs partial bella (jaw turn-in only, no kill bella)
~~ - Returns home via ah_recall after services
~~
~~ Portal Spells:
~~ Summon Primary Portal I = spell 157
~~ Summon Secondary Portal I = spell 2648
~~
~~ {
~~ FOR AUTO-COMPLETION ASSISTANCE: testvar getvar setvar touchvar clearallvars clearvar getcharintprop getchardoubleprop getcharquadprop getcharboolprop getcharstringprop getisspellknown getcancastspell_hunt getcancastspell_buff getcharvital_base getcharvital_current getcharvital_buffedmax getcharskill_traininglevel getcharskill_base getcharskill_buffed getplayerlandcell getplayercoordinates coordinategetns coordinategetwe coordinategetz coordinatetostring coordinateparse coordinatedistancewithz coordinatedistanceflat wobjectgetphysicscoordinates wobjectgetname wobjectgetobjectclass wobjectgettemplatetype wobjectgetisdooropen wobjectfindnearestmonster wobjectfindnearestdoor wobjectfindnearestbyobjectclass wobjectfindininventorybytemplatetype wobjectfindininventorybyname wobjectfindininventorybynamerx wobjectgetselection wobjectgetplayer wobjectfindnearestbynameandobjectclass actiontryselect actiontryuseitem actiontryapplyitem actiontrygiveitem actiontryequipanywand actiontrycastbyid actiontrycastbyidontarget chatbox chatboxpaste statushud statushudcolored uigetcontrol uisetlabel isfalse istrue iif randint cstr strlen getobjectinternaltype cstrf stopwatchcreate stopwatchstart stopwatchstop stopwatchelapsedseconds cnumber floor ceiling round abs getworldname getitemcountininventorybyname getheading getitemcountininventorybynamerx getheadingto actiontrygiveprofile vitae getfellowshipstatus getfellowshipname getfellowshipisopen getfellowshipisleader getfellowshipleaderid getfellowshipcanrecruit getfellowid getfellowshipcount getfellowshiplocked getfellowname getfellowshipisfull sin cos tan sqrt asin acos atan atan2 sinh cosh tanh vtsetmetastate getregexmatch echo chr ord wobjectgetid wobjectgethealth wobjectfindbyid wobjectgetintprop wobjectfindnearestbytemplatetype wobjectgetopencontainer testquestflag getquestktprogress isrefreshingquests getquestktrequired getqueststatus getisday getgamehour getgamehourname getisnight getgameday getgameticks getminutesuntilday getgamemonth getplayerlandblock wobjectisvalid getitemcountbytemplatetype ifthen
~~ }
STATE: {Default}
~~ Init variables then transition to service check
IF: Not Expr {testvar[bellaStartAttempts]}
DO: DoExpr {setvar[bellaStartAttempts, 0]}
IF: Not Expr {testvar[bellaMpPrimaryAttempts]}
DO: DoExpr {setvar[bellaMpPrimaryAttempts, 0]}
IF: Not Expr {testvar[bellaTurnInAttempts]}
DO: DoExpr {setvar[bellaTurnInAttempts, 0]}
IF: Not Expr {testvar[bellaJawRunRecoverAttempts]}
DO: DoExpr {setvar[bellaJawRunRecoverAttempts, 0]}
IF: Not Expr {testvar[bellaBackoffSeconds]}
DO: DoExpr {setvar[bellaBackoffSeconds, 86400]}
IF: Not Expr {testvar[stipendBackoffSeconds]}
DO: DoExpr {setvar[stipendBackoffSeconds, 86400]}
IF: Not Expr {testvar[disableBellaServices]}
DO: DoExpr {setvar[disableBellaServices, 0]}
IF: Not Expr {testvar[serviceCheckInterval]}
DO: DoExpr {setvar[serviceCheckInterval, 43200]}
IF: Not Expr {testvar[serviceClock]}
DO: DoAll
DoExpr {setvar[serviceClock,stopwatchcreate[]]}
DoExpr {stopwatchstart[getvar[serviceClock]]}
IF: Always
DO: DoAll
Chat {/ub opt set VTank.PatchExpressionEngine true}
Chat {/vt opt set enablecombat false}
Chat {/vt opt set enablelooting false}
Chat {/vt opt set enablenav false}
Chat {/vt opt set enablebuffing true}
SetState {service_quest_refresh}
~~ }
STATE: {idle}
~~ Main loop: listen for portal tells, check service timer, handle buffs
IF: Death
DO: SetState {death}
IF: NeedToBuff
DO: SetState {buffing}
~~ Listen for tells containing "primary"
IF: ChatCapture {(^(\[[A-z]+?\] |)You|.*\<Tell:IIDString:.+:(?<who>[^\<]*)\>.+\<\\Tell\>) .*, ".*primary.*"$} {}
DO: SetState {summon_primary}
~~ Listen for tells containing "secondary"
IF: ChatCapture {(^(\[[A-z]+?\] |)You|.*\<Tell:IIDString:.+:(?<who>[^\<]*)\>.+\<\\Tell\>) .*, ".*secondary.*"$} {}
DO: SetState {summon_secondary}
~~ Periodic service check
IF: All
Expr {testvar[serviceClock]}
Expr {stopwatchelapsedseconds[getvar[serviceClock]]>=getvar[serviceCheckInterval]}
DO: SetState {service_quest_refresh}
IF: Always
DO: None
STATE: {summon_primary}
~~ Face 180, equip wand, cast Summon Primary Portal I (157) with retries
IF: Death
DO: SetState {death}
IF: Always
DO: DoAll
Chat {/vt opt set enablecombat false}
Chat {/ub face 180}
DoExpr {actiontryequipanywand[]}
IF: SecsInStateGE 4
DO: DoExpr {actiontrycastbyid[157]}
IF: SecsInStateGE 7
DO: DoExpr {actiontrycastbyid[157]}
IF: SecsInStateGE 10
DO: DoExpr {actiontrycastbyid[157]}
IF: SecsInStateGE 17
DO: SetState {idle}
STATE: {summon_secondary}
~~ Face 90, equip wand, cast Summon Secondary Portal I (2648) with retries
IF: Death
DO: SetState {death}
IF: Always
DO: DoAll
Chat {/vt opt set enablecombat false}
Chat {/ub face 90}
DoExpr {actiontryequipanywand[]}
IF: SecsInStateGE 4
DO: DoExpr {actiontrycastbyid[2648]}
IF: SecsInStateGE 7
DO: DoExpr {actiontrycastbyid[2648]}
IF: SecsInStateGE 10
DO: DoExpr {actiontrycastbyid[2648]}
IF: SecsInStateGE 17
DO: SetState {idle}
STATE: {buffing}
~~ Wait for buffs to complete, then return to idle
IF: Death
DO: SetState {death}
IF: Not NeedToBuff
DO: SetState {idle}
IF: SecsInStateGE 120
DO: SetState {idle}
STATE: {service_quest_refresh}
~~ Request quest status refresh, wait for completion
IF: Death
DO: SetState {death}
IF: Always
DO: DoAll
Chat {/myquests}
DoExpr {touchvar[questsRequested]}
IF: All
Expr {testvar[questsRequested]}
Expr {isrefreshingquests[]==0}
SecsInStateGE 2
DO: SetState {service_pending_eval}
IF: SecsInStateGE 8
DO: SetState {service_pending_eval}
STATE: {service_pending_eval}
~~ Check if bella jaw quest is ready (no augment application for portal bot)
IF: Always
DO: SetState {service_decide}
STATE: {service_decide}
~~ Decide which services to run: stipend, partial bella, or return to idle
~~ Reset bella backoff if timer expired
IF: All
Expr {getvar[disableBellaServices]==1}
Expr {testvar[bellaBackoffClock]}
Expr {stopwatchelapsedseconds[getvar[bellaBackoffClock]]>=getvar[bellaBackoffSeconds]}
DO: DoAll
DoExpr {setvar[disableBellaServices, 0]}
DoExpr {setvar[bellaStartAttempts, 0]}
DoExpr {setvar[bellaMpPrimaryAttempts, 0]}
DoExpr {setvar[bellaTurnInAttempts, 0]}
DoExpr {setvar[bellaJawRunRecoverAttempts, 0]}
DoExpr {clearvar[bellaBackoffClock]}
~~ Stipend: first run (no backoff clock)
IF: All
Expr {getqueststatus[`stipendtimer_0812`]==1}
Not Expr {testvar[stipendBackoffClock]}
DO: SetState {service_stipend}
~~ Stipend: backoff expired
IF: All
Expr {getqueststatus[`stipendtimer_0812`]==1}
Expr {testvar[stipendBackoffClock]}
Expr {stopwatchelapsedseconds[getvar[stipendBackoffClock]]>=getvar[stipendBackoffSeconds]}
DO: DoAll
DoExpr {clearvar[stipendBackoffClock]}
SetState {service_stipend}
~~ Partial bella: jaw quest ready + services not disabled
IF: All
Expr {getvar[disableBellaServices]!=1}
Expr {getqueststatus[`insatiableeaterjaw`]==1}
DO: SetState {service_bella_start}
~~ Nothing to do, return to idle
IF: Always
DO: DoAll
DoExpr {setvar[serviceClock,stopwatchcreate[]]}
DoExpr {stopwatchstart[getvar[serviceClock]]}
SetState {idle}
STATE: {service_stipend}
~~ Run stipend collection nav, start backoff clock
IF: Death
DO: SetState {death}
IF: Always
DO: SetWatchdog 3 600 {service_reset_main}
IF: Always
DO: DoAll
Chat {/vt opt set enablecombat false}
Chat {/vt opt set enablelooting false}
Chat {/vt opt set enablenav true}
DoExpr {setvar[stipendBackoffClock, stopwatchcreate[]]}
DoExpr {stopwatchstart[getvar[stipendBackoffClock]]}
DoExpr {touchvar[stipendNavLoaded]}
EmbedNav nav0__stipend_nav {stipend.nav}
IF: All
Expr {testvar[stipendNavLoaded]}
NavEmpty
SecsInStateGE 2
DO: SetState {service_reset_main}
STATE: {service_bella_start}
~~ Enter marketplace for bella jaw run
IF: Death
DO: SetState {death}
IF: Always
DO: DoExpr {setvar[bellaStartAttempts,getvar[bellaStartAttempts]+1]}
IF: Expr {getvar[bellaStartAttempts]>=3}
DO: SetState {service_bella_backoff}
IF: Always
DO: DoAll
Chat {/vt opt set enablecombat false}
Chat {/vt opt set enablelooting false}
Chat {/vt opt set enablenav false}
Chat {/vt opt set enablebuffing true}
IF: SecsInStateGE 2
DO: DoAll
Chat {/a [bella] starting marketplace entry}
Chat {/vt opt set enablenav false}
Chat {/mp}
IF: ExitPortal
DO: DoAll
DoExpr {setvar[bellaStartAttempts, 0]}
SetState {service_bella_mp_primary}
IF: SecsInStateGE 120
DO: SetState {service_bella_start}
STATE: {service_bella_mp_primary}
~~ Navigate through marketplace primary path to jaw dungeon portal
IF: Death
DO: SetState {death}
IF: Always
DO: DoExpr {setvar[bellaMpPrimaryAttempts,getvar[bellaMpPrimaryAttempts]+1]}
IF: Expr {getvar[bellaMpPrimaryAttempts]>=3}
DO: SetState {service_bella_backoff}
IF: Always
DO: DoAll
Chat {/vt opt set enablebuffing true}
Chat {/vt opt set enablenav true}
Chat {/vt opt set enablecombat false}
Chat {/vt opt set enablelooting false}
Chat {/vt opt set NavPriorityBoost false}
Chat {/vt opt set navclosestoprange 0.008}
IF: Expr {getplayerlandblock[]==23855104}
DO: Chat {/vt nav load mp_primary}
IF: All
Expr {getplayerlandblock[]!=23855104}
SecsInStateGE 30
DO: DoAll
Chat {/a [bella] wrong mp_primary landblock, restarting marketplace entry}
SetState {service_bella_start}
IF: ExitPortal
DO: DoAll
Chat {/vt opt set enablenav false}
DoExpr {setvar[bellaMpPrimaryAttempts, 0]}
SetState {service_bella_jaw_run}
IF: SecsInStateGE 60
DO: DoAll
Chat {/a [bella] mp_primary timed out, restarting marketplace entry}
SetState {service_bella_start}
STATE: {service_bella_jaw_run}
~~ Run jaw dungeon nav
IF: Death
DO: SetState {death}
IF: Expr {getplayerlandblock[]==9830400}
DO: DoAll
Chat {/vt opt set enablenav true}
Chat {/vt nav load jaw_1}
IF: All
Expr {getplayerlandblock[]!=9830400}
SecsInStateGE 30
DO: DoAll
Chat {/a [bella] wrong jaw_run landblock, restarting marketplace entry}
SetState {service_bella_start}
IF: All
Expr {getplayerlandblock[]==9830400}
SecsInStateGE 30
NavEmpty
DO: DoAll
DoExpr {setvar[bellaStartAttempts, 0]}
DoExpr {setvar[bellaJawRunRecoverAttempts, 0]}
Chat {/vt nav load jaw_1_hunt}
Chat {/vt opt set enablecombat true}
Chat {/vt opt set enablelooting true}
Chat {/vt opt set lootonlyrarecorpses false}
SetState {service_bella_jaw_hunt}
IF: All
SecsInStateGE 300
Expr {getvar[bellaJawRunRecoverAttempts]<3}
DO: DoAll
DoExpr {chatbox[`/a [bella] jaw_run stuck, recall retry `+cstr[getvar[bellaJawRunRecoverAttempts]+1]+`/3`]}
DoExpr {setvar[bellaJawRunRecoverAttempts,getvar[bellaJawRunRecoverAttempts]+1]}
Chat {/vt nav load nav_portal_recall}
SetState {service_bella_jaw_run_recover}
IF: All
SecsInStateGE 300
Expr {getvar[bellaJawRunRecoverAttempts]>=3}
DO: SetState {service_bella_backoff}
STATE: {service_bella_jaw_run_recover}
~~ Recovery wait for jaw run stuck
IF: Death
DO: SetState {death}
IF: SecsInStateGE 20
DO: SetState {service_bella_jaw_run}
STATE: {service_bella_jaw_hunt}
~~ Hunt for jaw drop
IF: Death
DO: SetState {death}
IF: ExitPortal
DO: DoAll
Chat {/vt opt set enablenav true}
SetState {service_bella_turn_in_jaw}
IF: ItemCountGE 1 {Insatiable Eater Jaw}
DO: DoAll
Chat {/vt opt set enablecombat false}
Chat {/vt nav load to_fiun}
IF: SecsInStateGE 1200
DO: SetState {service_bella_start}
STATE: {service_bella_turn_in_jaw}
~~ Turn in jaw to Fiun NPC, then return home (partial bella - no mp_trans/secondary/kill)
IF: Death
DO: SetState {death}
~~ Jaw accepted: return home instead of continuing to mp_secondary
IF: ChatMatch {^.*One who obtains such as this is truly worthy of that which we would teach\. The highest peak of the deadliest isle contains that which you seek.*$}
DO: DoAll
Chat {/a [bella] jaw turned in, returning home (partial bella)}
DoExpr {setvar[bellaTurnInAttempts, 0]}
SetState {service_reset_main}
IF: All
SecsInStateGE 300
ItemCountGE 1 {Insatiable Eater Jaw}
Expr {getvar[bellaTurnInAttempts]<3}
DO: DoAll
DoExpr {chatbox[`/a [bella] jaw turn-in timed out, retry `+cstr[getvar[bellaTurnInAttempts]+1]+`/3`]}
DoExpr {setvar[bellaTurnInAttempts,getvar[bellaTurnInAttempts]+1]}
Chat {/vt nav load to_fiun}
SetState {service_bella_turn_in_jaw}
IF: All
SecsInStateGE 300
ItemCountGE 1 {Insatiable Eater Jaw}
Expr {getvar[bellaTurnInAttempts]>=3}
DO: SetState {service_bella_backoff}
~~ Jaw already gone (consumed by NPC), just go home
IF: SecsInStateGE 300
DO: DoAll
DoExpr {setvar[bellaTurnInAttempts, 0]}
SetState {service_reset_main}
STATE: {service_bella_backoff}
~~ Disable bella services for 24h, return home
IF: Always
DO: DoAll
Chat {/a [bella] backoff tripped, disabling bella services for 24h}
Chat {/vt opt set enablecombat false}
Chat {/vt opt set enablenav true}
DoExpr {setvar[disableBellaServices, 1]}
DoExpr {setvar[bellaStartAttempts, 0]}
DoExpr {setvar[bellaMpPrimaryAttempts, 0]}
DoExpr {setvar[bellaTurnInAttempts, 0]}
DoExpr {setvar[bellaJawRunRecoverAttempts, 0]}
DoExpr {setvar[bellaBackoffClock,stopwatchcreate[]]}
DoExpr {stopwatchstart[getvar[bellaBackoffClock]]}
SetState {service_reset_main}
STATE: {service_reset_main}
~~ Clear service vars, load ah_recall to return home, then go to idle
IF: Death
DO: SetState {death}
IF: Always
DO: SetWatchdog 3 600 {service_reset_main_stuck}
IF: Always
DO: DoAll
DoExpr {clearvar[questsRequested]}
DoExpr {clearvar[stipendNavLoaded]}
Chat {/vt opt set enablecombat false}
Chat {/vt opt set enablelooting false}
Chat {/vt opt set enablenav true}
Chat {/vt opt set enablebuffing true}
DoExpr {setvar[serviceClock,stopwatchcreate[]]}
DoExpr {stopwatchstart[getvar[serviceClock]]}
DoExpr {touchvar[resetNavLoaded]}
Chat {/vt nav load ah_recall}
IF: All
Expr {testvar[resetNavLoaded]}
NavEmpty
SecsInStateGE 2
DO: DoAll
DoExpr {clearvar[resetNavLoaded]}
ClearWatchdog
Chat {/vt opt set enablenav false}
SetState {idle}
STATE: {service_reset_main_stuck}
~~ Fallback if ah_recall nav gets stuck
IF: Always
DO: DoAll
Chat {/ah}
SetState {service_reset_main_wait}
STATE: {service_reset_main_wait}
~~ Wait for /ah recall, then retry reset
IF: Death
DO: SetState {death}
IF: ExitPortal
DO: SetState {service_reset_main}
IF: SecsInStateGE 30
DO: SetState {service_reset_main}
STATE: {death}
~~ Death recovery: wait for portal exit, recall home
IF: Always
DO: DoAll
Chat {/vt opt set enablecombat false}
Chat {/vt opt set enablelooting false}
IF: ExitPortal
DO: DoAll
Chat {/ah}
SetState {death_wait_recall}
IF: SecsInStateGE 30
DO: DoAll
Chat {/ah}
SetState {death_wait_recall}
STATE: {death_wait_recall}
~~ Wait for /ah recall portal exit, then return to idle
IF: Death
DO: SetState {death}
IF: ExitPortal
DO: SetState {idle}
IF: SecsInStateGE 60
DO: SetState {idle}
~~========================= ONLY NAVS APPEAR BELOW THIS LINE =========================~~
NAV: nav0__stipend_nav once
pau 47.1262349446615 26.1864453474681 0.225020837783813 2000
cht -101.597905190786 -96.6216093699137 2.08333134651184E-05 {/ah}
pau 47.1262349446615 26.1864453474681 0.225020837783813 15000
pnt 59.3590666453044 -28.7057823816935 0.0500208298365275
ptl -101.597905190786 -96.6216093699137 2.08333134651184E-05 59.3936458587647 -28.7256083488464 0.0508250035345554 14 {Portal to Town Network}
pnt -101.615851815542 -96.6388638178507 2.08333134651184E-05
pnt -101.657751337687 -96.5832635879517 2.08333134651184E-05
pnt -101.658352184296 -96.5325949986776 2.08333134651184E-05
ptl -101.597905190786 -96.6216093699137 2.08333134651184E-05 -101.588099161784 -96.5166525046031 -0.000262499845121056 14 {Portal to Arwic}
pnt 56.6498762130737 33.416518386205 0.175020837783813
pnt 56.655900033315 33.5368880271912 0.175020837783813
pnt 56.7470087051392 33.5495386441549 0.175020837783813
pnt 56.7795230229696 33.6337207794189 0.175020837783813
tlk -101.597905190786 -96.6216093699137 2.08333134651184E-05 56.7816291809082 33.6455291748047 0.175020843744278 37 {Monroe}