UOSAGAS Scripting

Control Flow

Every block opens with a keyword and closes with a matching end…. There are no braces and no parentheses, which also means you cannot group conditions, so complex logic is expressed by nesting.

if / elseif / else

Runs a block when an expression is true. Close it with endif.

if hp < 30
    potion 'heal'
elseif hp < 60
    hotkey 'Bandage self'
else
    overhead 'healthy'
endif

Combine conditions with and / or, and negate with not:

if hp < 50 and mana >= 11
    cast 'greater heal'
endif
 
if not dead
    // main loop
endif

There are no parentheses. and and or are evaluated left to right, so you cannot write (a or b) and c. When you need that, nest two ifs. The outer one acts as the and.

while

Repeats a block for as long as the expression stays true. Close it with endwhile.

while mana < maxmana
    skill 'meditation'
    wait 11000
endwhile

for

Repeats a block a fixed number of times. Close it with endfor. The current pass is available as index, counting from 0.

for 5
    say 'shout {{index}}'
    wait 1000
endfor

foreach

Walks a list, putting each entry into a variable of your choosing. Also closed with endfor.

createlist 'ore'
pushlist 'ore' 0x19B9
pushlist 'ore' 0x19BA
 
foreach id in ore
    @dclicktype id backpack
    wait 500
endfor
 
removelist 'ore'

Combined with findtypelist, this is how you act on everything that matches, rather than on one random item:

loot-everything.razor
createlist 'loot'
findtypelist 'loot' 0x0EED ground 0 any 3   // gold within 3 tiles
 
foreach item in loot
    dclick item
    wait 600
endfor
 
removelist 'loot'

break & continue

break leaves the loop entirely; continue jumps back to the loop's condition and starts the next pass.

while 1 = 1
    if weight > maxweight
        break               // pack is full, stop looting
    endif
 
    if not findtype 0x0EED ground
        continue            // nothing here, look again
    endif
 
    dclicktype 0x0EED ground
endwhile

stop, replay & loop

stop ends the script immediately. loop jumps back to the very first line. That is the usual way to make a watcher script keep watching. replay is an older spelling of the same thing.

if dead
    overhead 'I am dead, stopping'
    stop
endif
 
// ... work ...
wait 250
loop

Waiting properly

Most scripts fail for one of two reasons: they do not wait for the server, or they do not wait at all.

  • After anything that opens a target cursor, use waitfortarget, never a fixed wait. The server's latency is not your business.
  • Same for gumps (waitforgump), menus (waitformenu) and prompts (waitforprompt).
  • In a loop, always wait at least a little, even when there is nothing to do.
cast 'greater heal'
waitfortarget           // right: waits exactly as long as needed
target 'self'
 
cast 'greater heal'
wait 2000               // wrong: too slow when fast, too fast when lagging
target 'self'