With the untimely demise of Mojo on June 2, 2021, many DAoC players have been left without a reliable way to launch their characters, manage their in-game macros, and multibox multiple clients at the same time. There are several efforts underway to replace this functionality by other third-party tools, but none of them are ready at this time. On this website, I intend to provide some resources for how to use AutoHotKey to achieve this.
AutoHotKey (AHK) is an automation scripting language for Windows. It is not specifically designed for gaming (reportedly, gaming questions are strictly forbidden in the AHK Discord), but it can certainly be used for automating and macroing in games such as DAoC. On this website, I have three separate efforts for AHK scripts (described in detail below):
AHK library supporting basic macroing;
AHK library for launching DAoC; and
AHK library for multiboxing DAoC.
To get started with AutoHotKey, go to the AHK website (https://www.autohotkey.com/), download the software, and install it. This will bind all files with the suffix .ahk to AutoHotKey. To start an AHK script, I recommend that you right-click and then choose "Run as Administrator" to ensure that the script works seamlessly inside the DAoC client.
The AHK help documentation is extensive, but can be quite technical. Furthermore, AHK itself is, frankly speaking, not the most elegant scripting language. Hence this guide.
AHK scripts are pure text files. Accordingly, to edit an AHK script, you need to use a text editor, like Notepad. Don't attempt to edit .ahk files using a word processor such as Microsoft Word, as that may change the file format.
AHK scripts are a form of computer programming in that they consist of lines of code. Each line is an instruction that tells the computer what to do. These lines are of the form Send, {f} (which sends the key "f" to the current window) or SetKeyDelay 20, 20 (which sets the delay between keys as well as the key press duration to 20 milliseconds).
AHK scripts are generally case-insensitive, meaning that Send, {f} and send, {f} are the same thing. The exception is strings, which use double quotes such as "this example string", as well as the hotkeys themselves, where "{f}" and "{F}" are the same key with and without shift pressed.
All AHK scripts consist of two parts: the "auto-execute" part, and the rest. The auto-execute part is the first lines of the script until the first Return statement; as the name implies, AHK will execute this part from top to bottom until this return statement is encountered. After that, other parts of the script can only be invoked when a hotkey is pressed or a function is called.
Finally, to use the below three AHK "libraries" (loosely termed, as this is still very early work), you will need to use the #include directive. I show example usage below, but basically, #Include will "paste" the contents of an existing file into the current script file. This allow your individual scripts to be relatively simple and clean, leaving most of the heavy lifting to the "library". Here is an example:
#Include %A_ScriptDir%\Launchelot.ahk
To the best of my knowledge, macroing as described in this document is explicitly permitted in DAoC by BroadSword itself (multiboxing is allowed outside of RvR zones). Having said that, please use any of this information and AHK scripts at your own risk.
I am in no way an AHK expert! I am merely trying to fill the vacuum left behind by Mojo. If you find problems with what I have written here or have suggestions on improvements, I am happy to hear you out and update this information. Please get in touch with me as BelomarFleetfoot#0319 on Discord (Madgrim in the Official DAoC Discord).
This website as well as the AHK code are synthesized from information I have received from a bunch of people. In particular, Mplode (Mplode#7776) gave guidance on how to launch DAoC from the command line, and Teehehe (Teehehe#9239 on Discord) provided much of the original SendMessage code for multiboxing as well as information on killing mutexes.
AHK scripts are essentially lists of hotkeys (as well hotstrings, which we need not worry about here) followed by little snippets of code of what will happen when that hotkey is pressed. Hotkeys are specified using the key combinations as well as modifiers, such as Ctrl (specified using ^), Alt (!), and Shift (+).
Here is an example of the bodyguard/guard macro for my armsman, which will use a bunch of protective abilities when I press Shift + W:
; --> Guard and Bodyguard
$+w::
Send, !{1} ; bodyguard
Send, !{2} ; guard
Send, !{3} ; intercept
Send, !{4} ; protect
Return
The very first line (after the semi-colon which is used as a comment label) shows the hotkey: Shift and w. Note the '$' at the beginning of the line. This tells AHK to ignore the use of the key itself in the following script. This is not a problem here, but if you ever want to, say, use the hotkey 3 to yield the key sequence 1, 2, 3, not having the $ would yield an infinite loop (sending 3 inside the script would cause the 3 hotkey to be called again).
What follows after the double colons (::) is the actual script of what happens when the hotkey is pressed. If your code is a single instruction, you can actually write it on a single line, like so:
$3::Send, 3
Most of the time, you will be writing more complex macros, in which case you will write each instruction on a line, and close the end of the script for the hotkey with the Return statement (if you forget, your code will "fall" down to the next hotkey).
The instructions in this case are simple; just a bunch of Send calls, which emits a particular hotkey to the current window. You may also need the Sleep command to wait a defined number of milliseconds between keystrokes; for example, Sleep, 200 sleeps for 200 milliseconds (0.2 seconds). These commands are likely enough for most basic DAoC macro applications.
AHK scripts tend to include a bunch of code at the beginning which is more or less boiler plate. My DAoC preamble eliminates most of this, but it can be useful to know what each line does. Here is a snippet (with some descriptive comments):
#SingleInstance, Force ; Force a single instance of the script
#NoEnv ; For performance and compatibility with future AHK releases.
#Warn ; Enable warnings to assist with detecting common errors.
SendMode Event ; To make this work with DAoC. ("Input" does not seem to work well.)
SetTitleMatchMode, 2 ; Match parts of the window title.
SetKeyDelay 20, 20 ; Control timing between consecutive key presses.
You can safely keep this boilerplate in place without changing it (or use my library below).
I have written a simple AHK library for basic macroing for DAoC. It has the following functionality:
Visual indication of the script, including your toon's name;
Button for easily closing down your script;
Hotkey for enabling/disabling the script (Print Screen); and
Hotkey for reloading the script (Ctrl + Alt + R).
Download the library and then create a specialized AHK script file for your toon in the same folder. The toon script should #include the preamble. Here is an example of how this script could look, again using the armsman as an example:
; -- Variables
global CharName := "Madderick"
; -- Include the standard preamble
#Include %A_ScriptDir%\preamble.ahk
; -- Only let these hotkeys affect DAoC
#IfWinActive Dark Age of Camelot
; --> Sword/shield
$+1::
Send, +{1}
Send, ^{q}
return
; --> Polearm
$+2::
Send, +{2}
Send, ^{w}
return
; --> Guard and Bodyguard
$+w::
Send, !{1}
Send, !{2}
Send, !{3}
Send, !{4}
return
I have heard some reports of the above preamble causing slowdowns with mouse move events and similar. Your mileage may vary and you have been warned.
In addition to the macroing, you want may to be able to launch DAoC inside your AHK scripts. I have created an AHK utility called Launchelot for this as well. Launchelot can both be used in standalone format, as well as called from another script. Here is an example of how the latter is achieved:
; -- Variables
global CharName := "Madderick"
; -- Include the standard preamble
#Include %A_ScriptDir%\preamble.ahk
#Include %A_ScriptDir%\Launchelot.ahk
; -- Only let these hotkeys affect DAoC
#IfWinActive Dark Age of Camelot
[...] ; Add your hotkey code here
; --> Launch DAoC using Ctrl+Alt+O
#IfWinActive
$^!o::LaunchToon(CharName)
The library relies on a toon database called launchelot.ini that resides in the same folder as the script itself. Please use Launchelot to add and delete toons and accounts to this file; you can't edit it manually because passwords are encoded and not in clear text.
Even if AHK was not specifically written for multiboxing, it can be used for this purpose (with some effort). The big challenge is sending events, such as keypresses and mouse clicks, to a background window. The way to achieve this is using the SendMessage command; thanks to Teehehe for the pointers on how to do this. Unfortunately, it is a rather involved process, so I have created an AHK library called Multiverse that encapsulates most of the technical difficulty.
The first challenge is launching multiple toons from a single script. The problem is that DAoC is hardwired to only allow up to two clients to be run at any point in time. To get around this, the library uses Robert Sack's "kill_mutex_64.exe" utility from the now-defunct Mojo. Please download this (my copy is only for courtesy; I am not the creator of this utility) and place it in the same folder as the AHK script itself. Then you will be able to launch a team using the hotkey Ctrl+Alt+O as follows:
$^!o::LaunchTeam([ "toon1", "toon2", "toon3", "toon4" ])
This will look up each of the four toons (toon1 through 4) in toons.txt and then launch them with a 500 ms interval. It will also kill the mutex that is created every time a DAoC client is launched.
The next challenge is to distribute a hotkey to all of the active DAoC clients. I provide a simple function called Hotkey that achieves this; it will send the same hotkey (or hotkey combination) to all of the active clients.
$1::Hotkey("32")
The above will send the key combination 3 and then 2 to all of the open clients. To use a modifier, do the following:
$!1::Hotkey("12", "alt")
$!2::Hotkey("3", "ctrl alt")
Sometimes you will want to send different keys to different clients. The multibox script provides a minimalistic GUI where each of the open clients can be categorized into "archetypes" such as caster, melee, PBAE, and healer (all customizable). This means that you can do different things for different archetypes with a single command:
$3::HotkeyByArchetype({ PBAE: "f3", Caster: "f2", "Melee": "32", "Healer": "4" })
This could cause a PBAE to cast their PBAE, a caster to single-target nuke, a melee to style (with a backup), and a healer to cast their group heals. All in a single line of code; pretty nifty, huh?
Finally, to send a slash command, you can do the following:
$x::Slash("/sit")
To make it possible to access the names you assign the different toons (controlled by clicking the "..." button next to each client), use the %current% wildcard. Here is an example of an assist command:
$e::Slash("/assist %current%")
I also provide a utility function called PortTeam which asks for a string to say and then distributes it to all clients:
f3::PortTeam()
Here is a full code example:
; -- Variables
global archetypes := "Passive||Caster|PBAE|Melee|Healer"
; -- Include Multiverse and Launchelot
#Include %A_ScriptDir%\Multiverse.ahk
#Include %A_ScriptDir%\Launchelot.ahk
; -- Only let the below affect DAoC
#IfWinActive Dark Age of Camelot
; -- Face
$f::Hotkey("f")
$1::Hotkey("1")
; -- Basic attack
$2::HotkeyByArchetype({ PBAE: "f2", Caster: "f2", "Melee": "32" })
; -- PBAE or attack
$3::HotkeyByArchetype({ PBAE: "f3", Caster: "f2", "Healer": "f4" })
; -- Shields
$!1::
KeyWait, Alt
Hotkey("12", "alt")
Sleep, 2000
Hotkey("3", "alt")
Return
; -- Port the team
f3::PortTeam()
; -- Select the current leader
$^w::
KeyWait Control
Slash("/target %current%")
Sleep, 100
Hotkey("f", "Ctrl")
Return
; -- Assist
$e::Slash("/assist %current%")
; -- All sit
$x::Slash("/sit")
; --> Launch DAoC using Ctrl+Alt+O
#IfWinActive
$^!o::LaunchTeam([ "toon1", "toon2", "toon3", "toon4" ])
See the Launchelot page for more details on the GUI launcher.