Code:
Dear Blizzard,
I am writing to you, on behalf of an online community of “World of Warcraft entrepreneurs” who are mainly focused on trading aspect of the game. As you are probably aware, a huge part of gold making relates to continuous and repetitive activities such as milling, prospecting and disenchanting. This leads us, to the main point of this inquiry – what is allowed to make those activities easier and what is considered as “crossing the line” or “botting”. I am aware that there have been multiple discussions on the matter, but most of the answers received were either vague or subject to interpretation.
Please note, that the only reason I’m asking for further confirmation on your behalf is because we, as a community greatly value fair play and are strictly against cheating, yet we always strive to achieve our goals in a more efficient and smart way. I believe we have the similar interests – we want to play the game that we love and have fun with it, without braking any rules; while you do not want to ban people that had no intention on cheating, but did so due to lack of information. So please, help us draw the line between “smart use of mechanics” and “botting”.
There are two points at which I’d like to approach to problem:
1. The practical one:
I have written an application in AHK_L that helps mill/prospect/disenchant easier. I have done my best to ensure, that this is not against your ToS. What it basically does is the following.
a. It can listen to your key presses and supplicate them to one or many minimized windows. It can either send the same key that was pressed, or remap it to another fixed or random one.
b. It can detect if your mouse has moved over a pre-defined period of time. For example: it waits 2-3 seconds and if over the said duration, the mouse cursor has changed its position on the screen, it will produce a key press – either a fixed or a random one.
c. It can detect if there has been any physical action by the user (including mouse movements, key presses, or other hardware such as joystick) over a pre-defined period of time. The functionality it similar to this in point 1.b.
I kindly ask, if you could provide a reply, point by point, on which of those is acceptable and which is not. I am fully aware of the general response that “in game actions, should be on a 1:1 relationships with in-game ones”, and I believe that none of the above is breaking this rule. Still I would greatly appreciate if I could get a more concrete answer.
Additionally I am enclosing the complete source code to the application.
2. The theoretical one:
What I am asking here, is for your assistance to get an understanding on the most detailed level possible, what is deemed acceptable on what not. Again I kindly as for your response point by point.
a. Key presses:
i. A key press, by an actual person, in an application, different than WoW, is sent to WoW as is. Example: pressing “K” in MS Word, sends “K” in WoW.
ii. A key press, by an actual person, in an application, different than WoW, is sent to WoW but is remapped beforehand. Example: pressing “K” in MS Word, sends “1” in WoW.
iii. A key press, by holding down a button, by an actual person, in any application, sends multiple key presses in WoW. Example: holding down the “Up” button, sends multiple “1”s while the “Up” button is being held down.
iv. A key press, by an actual person, translates into a mouse click in specific location in WoW. Example: pressing Enter produces a click on a predefined location on the screen.
v. A key press, by an actual person, in an application, different than WoW, is sent to WoW with a delay. Please note that this is still one to one relationship or many to one. Example: any key presses over the course of 1 minute, produce a single key press in WoW at the end of this minute, and then listen for another minute if any keys are pressed. At the end of the second minute, only input over this time would be considered valid.
vi. A key press, by an actual person, in an application, different than WoW, is sent to WoW but is remapped to more than one key, without delay in between. Example: pressing “K” in MS Word, sends “Ctrl + 1” in WoW.
b. Mouse movements.
i. Mouse movement, by an actual person, regardless of the focused window, produced a key press in WoW. Each movement of the mouse would produce a key press, with the only limitation being how fast, the computer can calculate the movement and send the keys.
ii. Mouse movement, by an actual person, regardless of the focused window, produced a key press in WoW after a predefined delay. For example: the application reads the mouse coordinates initially, then after a pre-defined period 2-3 seconds, checks if the mouse coordinates have changed. If the position has changed – send the keys.
iii. Mouse movement, by an actual person, regardless of the focused window, produced a key press in WoW depending on the distance traveled by the mouse. Example: moving the mouse form coordinates 200,200 on the screen, to coordinates 200,400, produces 200 clicks due to mouse travelling the same distance. The keys are sent without delay.
iv. Same as above, but the keys are sent with delay.
v. Mouse scroll, by an actual person, regardless of the focused window, produced a key press in WoW depending on the scroll amount. Example: scrolling the mouse “200” units, produces 200 key presses without delay.
vi. Same as above, but the keys are sent with delay.
c. General questions:
Those somewhat overlap the questions above, but I would still like to get your general stance on the following topics:
i. Delays – I understand those are frowned upon, but what should be done in case of detection of mouse movement? Should keys just be spammed in order to avoid delay? Is there any acceptable amount of delay?
ii. Mouse movements – do you consider mouse movements a valid user input (gesture recognition comes to mind), and accept mouse movements being translated to clicks / key presses?
iii. Holding down a key – what is your general stance on holding down a key being able to produce multiple key presses?
iv. Random keys – what is your stance on pressing a key, and this producing another random key press?
v. Keys sequences – much like the /castsequence macro command. Pressing a key repeatedly produces a different key each time, following a pre-defined sequence?
Thank you, in advance, for taking your time to answer those questions.
Kind Regards,
Hristo Piyankov a.k.a Pliaksi @ World of Warcraft and http://consortium.stormspire.net/forum.php
On behalf of the community @ The Consortium
4.1.1. Listen to mouse - the application will be tracking if the mouse has changed it's position on the screen over a said period with artificial delay (more on this later).
4.1.2. Listen to keyboard - the application will be listening for all your key presses. There is no artificial delay here - a single key press triggers a single action.
4.1.3. Listen to input - the application will be tracking if there has been any sort of physical user input over a said period with artificial delay.
4.3.1. Mimic input - this is only relevant if the Listen to keyboard option is selected. If this is enabled, rather than sending the Keys to send, the application will try to mimic your input on a 1:1 relationship (e.g. if you press N it tries to send the exact same key).
4.3.2. Random events - generates additional random events on top of Random interval X - Y sec. What it specifically does is that, on a random interval between 1 and 20 key sending "events", it generates an additional event for a single send that modifies the Random interval X - Y sec. by multiplying both the top and the bottom by a random number from the following array [0.1, 0.5, 0.7, 2, 3, 4, 5]. Some of you might be wondering, why is this option even present : while as previously stated, this application is legal, because all it does is generate an event based on your actual RL actions, I believe it is better to be on the safe side and not give Blizzard/Warden a reason to doubt you. Consider this really a pre-pre-precaution measure.
4.3.3. Refresh button - forces an immediate refresh of the list of currently open windows.
4.3.4. Pause button - pauses all actions taken by the application. This is also bound to the Windows Key + P short cut.
4.3.5. Help button - displays the help article.
4.6.1. The application does not play very well with some of the more sophisticated text editors, when it comes to sending input. It would take a really lot of writing to explain all the perks, so I guess you would have to try if it works for your needs.
4.6.2. The application has a really hard time sending {Backspace} command with the Mimic mode. This is currently under investigation.
4.6.3. If you pick a number for the time intervals, that is already present in the drop down menu, this number will get duplicated in the drop down next time you start the application. This has absolutely NO impact on functionality, it's just
Code:
#SingleInstance force
#NoEnv
#InstallKeybdHook
#InstallMouseHook
FileInstall, CCS.jpg,CCS.jpg, 1
Gui, Add, Picture, Section w600 h-1 gConsLogo, CCS.jpg
Gui, Add, Button, Section w450 x75 gConsLink, Visit: The Consortium Gold Forums - Best Resources for Gold Making tips, tricks and guides
Gui, Add, Checkbox, Section x10 gMouseListen vMouseEnabled, Listen to mouse
Gui, Add, Checkbox, xs gKbdListen vKbdEnabled, Listen to keyboard
Gui, Add, Checkbox, xs gPhsListen vPhsEnabled, Listen to user input
Gui, Add, Checkbox, ys vMimic Section, Mimic input
Gui, Add, Checkbox, xs vRandEnabled, Random events
Gui, Add, Checkbox, xs vSequenceEnabled, Sequence send
Gui, add, Button, Section gRefreshList ys w60, Refresh
Gui, add, Button, gHelpListen xs w60, Help
Gui, add, Text, xs, Pause button
Gui, add, Button, Section gPauseListen ys w60 vPauseButton Default, Pause
Gui, add, Button, gCoordsListen xs w60, CoordSpy
Gui, add, edit, xs vPauseKey gEditChange w50
Gui, Add, Checkbox, ys gAutoRef vAutoEnabled Section, AutoRefresh each
Gui, add, ComboBox, ys vSecToRef w50, 1|2|3|4|5|6|7|8|9|10||
Gui, add, Text, ys, sec
Gui, add, Text, xs Section, Random interval
Gui, add, ComboBox, ys vRandStart w50, 0.5|1|1.5|2||2.5|3|3.5|4|4.5|5
Gui, add, Text, ys, -
Gui, add, ComboBox, ys vRandEnd w50, 0.5|1|1.5|2|2.5|3||3.5|4|4.5|5
Gui, add, Text, ys, sec
Gui, add, Text, xs Section, Keys to send
Gui, add, edit, ys vKeys w150
Gui, add, ListView, vMyList gMyList w600 h300 Checked SortDesc xm, Name|Class|ID
CoordMode, Mouse, Screen
if A_IsCompiled
Menu, Tray, Icon, %A_ScriptFullPath%, -159
IniRead, SecToRefTemp, %A_WorkingDir%\CKSSettings.ini, 1, SecToRef
IniRead, RandStartTemp, %A_WorkingDir%\CKSSettings.ini, 1, RandStart
IniRead, RandEndTemp, %A_WorkingDir%\CKSSettings.ini, 1, RandEnd
IniRead, KeysTemp, %A_WorkingDir%\CKSSettings.ini, 1, Keys
IniRead, PauseKeyTemp, %A_WorkingDir%\CKSSettings.ini , 1, PauseKey
if (PauseKeyTemp = "ERROR" or PauseKeyTemp = "") {
PauseKeyTemp := "#p"
}
if (SecToRefTemp = "ERROR") {
MsgBox,, Attention !, This seems to be the first time that you are using the Consortium Key Sender. Please read the help first !
gosub, HelpListen
} else {
GuiControl,, SecToRef, %SecToRefTemp%||
GuiControl,, RandStart, %RandStartTemp%||
GuiControl,, RandEnd, %RandEndTemp%||
GuiControl,, Keys, %KeysTemp%
GuiControl,, PauseKey, %PauseKeyTemp%
}
idList := object()
refresh(idList)
OldPause := PauseKeyTemp
Hotkey, %PauseKeyTemp%, PauseListen
Seq := 0
Timer := 0
Gui, show,, Consortium Key Sender
return
EditChange:
Gui submit, NoHide
if (OldPause = PauseKey)
return
if (OldPause != "") {
Hotkey, %OldPause%, Off
}
if (PauseKey = "" )
return
Hotkey, %PauseKey%, PauseListen
OldPause := PauseKey
return
CoordsListen:
if (Timer) {
Settimer WatchCursor, off
Tooltip
Timer:=0
} else {
Settimer WatchCursor, 50
Timer:=1
}
return
WatchCursor:
MouseGetPos , mouseX, mouseY
ToolTip, %mouseX% %mouseY%
return
ConsLogo:
ConsLink:
Run, http://consortium.stormspire.net/content/
return
KbdListen:
Gui submit, NoHide
while (KbdEnabled)
{
Input, SingleKey, L1, {LControl}{RControl}{LAlt}{RAlt}{LShift}{RShift}{LWin}{RWin}{AppsKey}{F1}{F2}{F3}{F4}{F5}{F6}{F7}{F8}{F9}{F10}{F11}{F12}{Left}{Right}{Up}{Down}{Home}{End}{PgUp}{PgDn}{Del}{Ins}{Backspace}{Capslock}{Numlock}{PrintScreen}{Pause}
Send % SingleKey
Gui submit, NoHide
if (Mimic)
sendkeys(SingleKey, Seq++, SequenceEnabled)
else
sendKeys(Keys, Seq++, SequenceEnabled)
}
return
PhsListen:
Gui submit, NoHide
lastInput := 100
while (PhsEnabled)
{
if (A_TimeIdlePhysical < lastInput)
sendKeys(Keys, Seq++, SequenceEnabled)
lastInput := sleepSpecial(RandStart, RandEnd, RandEnabled)
Gui submit, NoHide
}
return
PauseListen:
if IsPaused
{
Pause off
IsPaused := false
GuiControl,, PauseButton, Pause
}
else
SetTimer, Pause, 10
return
Pause:
SetTimer, Pause, off
IsPaused := true
GuiControl,, PauseButton, Unpause
Pause, on
return
HelpListen:
txtVar =
(
Welcome to the Consortium Key Sender application. Please read the following lines, as they are important.
1. Basic use: This application gives you the possibility to redirect input to your PC to multiple applications (rather than just the active one). You could, for instance, be browsing the internet, while in the background, your World of Warcraft character is prospecting/milling/etc.
2. Important notice: It is highly recommended that you should be using this application only if you got it from the consortium.stormspire.net forums. This is for your own safety, as technically the application listens to your key presses. This means that with modifications, this could be turned into a key logger. The only way to ensure that this won't happen to you is if you download this from the official forum thread at the aforementioned site.
3. Is this legal to use with games: the best way to ensure this is to consult with the game's ToS/EULA and/or game representatives. In the case of World of Warcraft, it has been stated multiple times that as long as there is physical input from the user (and this application cannot work without this) - you should be fine. Still, please use this application at your own risk.
4. Basic setup:
1. Open all windows/programs you want to send input to.
2. Run the "Consortium Key Sender"
3. Check within the application all windows you want to send input to.
4. Select the send method.
5. Select what keys you want to send.
6. You are done!
5. Send method descriptions:
1. Listen to mouse - Checks if the mouse location has changed over the "Random interval" specified.
2. Listen to keyboard - Listens for any key press on the keyboard. Note: this does not play well with some text editors, especially if they are not the active (input receiving) window.
3. Listen to user input - Checks if over the "Random interval" specified there has been any user physical input.
Note: You can select all methods if you wish to, but there is generally no reason to do so. The main difference between the methods (apart from what they respond to) is that "mouse" and "user" inputs enforce an artificial delay (you wouldn't want to spam keys for every single pixel that your mouse moves through, would you), while "keyboard" acts on one-to-one basis with your key presses on the keyboard.
6. Additional options:
1. Mimic input - attempts to mimic your input from the active window, to the windows selected (rather than sending pre-defined key-strokes).
2. Random events - apart from using the "Random interval", generates additional random events (stretches on shrinks the specified interval).
3. Sequence send - sends the list of keys in a sequance, rather than random.
4. Pause - pauses the script. It is also hot keyed to the Windows key + P shortcut.
5. Refresh - checks if there are any newly opened windows.
6. CoordSpy - helps you determine your mouse coordinates in case you want to simulate a click. Press second time to remove the tracking.
6. Pause button - specifies what will be your pause button. Modifier keys are applicable, so for instance #p = Windows Key + p; !p = Alt +p; ^p = Ctrl + p. The pause key needs to be a single key or a modifier + key. If you try to input anything different, you will get an error message.
7. Auto refreshes each X seconds - sends a "Refresh" command each X seconds. You are not limited to the values in the combo box! Feel free to input your own, including floating numbers (e.g. 11.353).
8. Random interval - defines the random interval for mouse events and user input events. Impute options are same as above.
9. Keys to send - sends the specified keys. This can be one key or a list of keys or semicolon-separated list of case. In case of the latter, a random entity of the ones listed is send. Furthermore, you can send more complex commands such as "{Shift Down}34{Shift Up}" which will hold down the Shift key, press 34 and then release the Shift key, or you could send mouse clicks by using the following syntax "mclick x300 y300" - this would reproduce a click at the respective coordinates, rative to your screen. For a complete list of possible commands please refer to http://www.autohotkey.com/docs/commands/Send.htm.
7. Additional notes:
1. If no options are input a default value is used. For Auto refresh - 10 sec, for Random Interval - 2:3 sec, for Keys to send - 1, for Pause button - #p.
8. Currently known issues:
1. Keyboard input does not recognize Backspace.
2. If the remembered user preference was an already default value, it gets duplicated in the combo boxes.
)
msgbox ,,Help, %txtVar%
return
AutoRef:
Gui submit, NoHide
while (AutoEnabled)
{
refresh(idList)
if (secToRef="") {
SecToRef := 10000
GuiControl,,SecToRef,10||
} else {
secToRef*=1000
}
sleep, SecToRef
Gui submit, NoHide
}
return
MouseListen:
MouseGetPos , xPos , yPos
Gui submit, NoHide
while (MouseEnabled)
{
MouseGetPos , xPosNew , yPosNew
if (xPos <> xPosNew or yPos <> yPosNew)
{
sendKeys(Keys, Seq++, SequenceEnabled)
xPos := xPosNew
yPos := yPosNew
}
sleepSpecial(RandStart, RandEnd, RandEnabled)
Gui submit, NoHide
}
return
RefreshList:
refresh(idList)
return
MyList:
GuiContextMenu:
return
close:
guiClose:
Gui submit, NoHide
IniWrite,%SecToRef%, %A_WorkingDir%\CKSSettings.ini , 1, SecToRef
IniWrite,%RandStart%, %A_WorkingDir%\CKSSettings.ini , 1, RandStart
IniWrite,%RandEnd%, %A_WorkingDir%\CKSSettings.ini , 1, RandEnd
IniWrite,%Keys%, %A_WorkingDir%\CKSSettings.ini , 1, Keys
IniWrite,%PauseKey%, %A_WorkingDir%\CKSSettings.ini , 1, PauseKey
ExitApp
refresh(idList) {
WinGet, id, list,,, Program Manager
Loop, %id%
{
this_id := id%A_Index%
if (idList[this_id] = 1)
continue
WinGetClass, this_class, ahk_id %this_id%
WinGetTitle, this_title, ahk_id %this_id%
if (this_title = "" or this_title = "Start")
continue
LV_Add("",this_title,this_class,this_id)
idList[this_id] := 1
}
Loop % LV_GetCount()
{
LV_GetText(win_id, A_Index,3)
IfWinNotExist, ahk_id%win_id%
{
LV_Delete(a_index)
insertList.Remove(win_id)
}
}
LV_ModifyCol(1,"Auto")
LV_ModifyCol(2,"Auto")
LV_ModifyCol(3,"Auto")
}
sleepSpecial(RandStart, RandEnd, RandEnabled)
{
If (RandEnd < RandStart or RandEnd ="" or RandStart="") {
RandStart := 2000
RandEnd := 3000
GuiControl,,RandStart,2||
GuiControl,,RandEnd,3||
} else {
RandStart *=1000
RandEnd *=1000
}
if (RandEnabled) {
Random, spec, 1, 10
if (spec = 1) {
randEventArr := [0.1, 0.5, 0.7, 2, 3, 4, 5]
Random, modif, 1 ,7
RandStart *= randEventArr[modif]
RandEnd *= randEventArr[modif]
}
}
Random, rand, RandStart, RandEnd
sleep , rand
return rand
}
sendKeys(Keys, Sequence, SEnabled)
{
if (Keys = "")
Keys := 1
RowNumber = 0
Loop
{
RowNumber := LV_GetNext(RowNumber,"Checked")
if not RowNumber
break
StringSplit, keyArr, Keys, `;
if (SEnabled) {
rand := Mod(Sequence, KeyArr0) + 1
} else {
Random, rand, 1 , keyArr0
}
LV_GetText(win_id, RowNumber,3)
keyToSend := keyArr%rand%
IfInString, keyToSend, mclick
{
Stringmid, keyToSend, keyToSend, 8
ControlClick, %keytoSend%, ahk_id%win_id%
} else
ControlSend,, %keytoSend%, ahk_id%win_id%
}
}