Jump to content
wolfie

AHK And Multiboxing

Recommended Posts

I know this may be a touchy subject but AFAIK Net-7 doesn't disallow multiboxing.  But they don't support it either.  So, with that I tiptoe into the minefield.

 

The past few days I have done quite a bit of work on some AutoHotKey scripts to launch and run EnB with the aid of my G13 keypad and G15 keyboard.  And I got to thinking maybe others could use what I have learned and accomplished with their setups.  The scripts are not dependent on those specific keyboards since they listen for keystrokes.  They could operate with any keyboard, macro or not.  And they are not race/class dependent nor require specific items on your game hotbar.

 

Here is what the scripts do.

Loader:

  1. Accepts a parameter that you set via a desktop (or anywhere else) shortcut to load the specified number of alt windows.
  2. Detects number of monitors
  3. Detects primary monitor
  4. Detects monitor resolutions
  5. Handles setting window sizes in the registry so each E&B window loads at the needed size.
  6. Places the main toon window on the main monitor
  7. Places 1 to 5 alts on a second monitor (adjacent to the main if you have >2 monitors)
  8. If only 1 alt, the second consumes the monitor fully.  If more than one alt, then it tiles them in a 2x2 grid (with #5 half down and overlapping the two left column).
  9. Runs the client unlocker app
  10. Runs the necessary required copies of Net-7 and answers all the dialogs (click and forget until time to log in)
  11. Is smart enough so that if one instance of EnB crashes, you can re-run the script and it will only replace the missing window leaving all others.

 

Play Script:

  1. Automatically adapts to the number of alts, 1 to whatever you can run.
  2. Keys/mouse actions sent to all alts automatically as needed.
  3. Automatically scales mouse positions to loaded window sizes
  4. All mouse clicks for alts return the mouse to the main window
  5. Handles group leader target acquisition (alts select group leader's target)
  6. Handles loot and close for alts on each pull to release the carcass to other group members
  7. Mass accept/reject wormhole with single keystroke
  8. Mass Action/Alt Action on selected target (ie dock is Action, Register is Alt Action and also works for gating and following and talking)
  9. Group Formation and alts join.
  10. Has full panel sell (still flaky due to EnB's bot detection but mostly works) in the selected alt/main window to sell the 12 visible items to a vendor
  11. Quick Buy of 12 of the current item in the selected alt/main window (ie buying tradegoods, one keystroke buys 12 or a full panel at once).

 

There is a helper script for loading and handles the actual running of EnB so that one script is the only one you need to worry about to edit directory paths.

The loader script process:

  1. Checks monitor count, monitor sizes and calculates appropriate window sizes for the various E&B instances to load.
  2. Checks to see if the client unlocker is running, if not, runs it.
  3. Launches Net-7 and presses its play button once loaded
  4. Waits for the TOS from E&B and dismisses it.
  5. Waits for the main E&B window and positions it based on whether its the main or one of the alts.
  6. Each new E&B window is given a unique title that is used internally and you can see it in the title bar of each window.
  7. Fires the Play Script when windows have been loaded so you are ready to log in and play

 

Because I have separated the process into 3 scripts, Loader, Loader Helper and Play, Each can be run independently.  This allows you to edit and debug them separately if needed.

 

The loader script is launched using a shortcut which you edit to supply a number of alts you want it to load.  If not specified, it assumes 1 alt.  One script will run 1 to 5 alts.  So you make copies of the shortcut and supply the number of alts you wish to run.  Lets say you start with 2 alts but decide you need all 5.  Simply run the 5 shortcut and it will add the missing 3 to what you had and relaunch the play script.  This also allows you to re-run it if one client crashes or you closed it by accident so you don't have to start all over loading every window again.  Its smart, it won't try to load main/alts already running.  I have also placed a config section at the top of the loader helper script that you can set additional padding around each alt window so you can click between them to access windows behind without alt-tabbing or going to the taskbar.  Or if you just want extra space just because :)

 

The play script would probably need to be tweaked by each person based on their habits, keymapping and needs but should provide the necessary starter framework.  Its not dependent on any E&B class or how you set up your (or your alts) hot bars.  It assumes the stock FPS control config in E&B and thats about it.

 

AutoHotKey is a free and open source app.  Download it here: https://autohotkey.com/

 

So, is there any interest in me taking the time to package the scripts up and write some install directions?

 

  • Upvote 1

Share this post


Link to post
Share on other sites

This is of course open for you to put out if people were to desire it, but our stance to be clear is simple. Nothing completely unattended, as in if you're doing some action and someone happens to think you are unresponsive they might report you to a GM if one happens to be available who may check on you. If they do, and you don't respond it is a problem and there will likely be some sort of disciplinary action as a result.

As long as you can answer, macro happily away all you want. To me, takes the fun out of playing though. :)

Share this post


Link to post
Share on other sites

The only unattended part here is loading the copies of EnB.  The rest is responding to your keyboard inputs to control multiple alt windows.  I understand the difference between macros and botting.  Thank you for stating the position clearly.  Much appreciated.

 

Share this post


Link to post
Share on other sites

I'd really like to see those scripts. Launching E&B drives me crazy because due my bad ISP connection I crash almost every second gate.

Share this post


Link to post
Share on other sites

The paths set up in these scripts are mine and not the default install location of EnB.

 

Here is my EnB shortcut fence:

enbshortcuts.jpg.bd933d9594ff421c825f648341e0b36e.jpg

The only things I really need there are the 5 launcher shortcuts.  They launch EnB main window with 1 to 5 alts.

Here is an example shortcut property:

EnBProperties.jpg.60705f631e8710f7fc78f9c8148cbe03.jpg

The number 3 after the filename is all it needs to know.

 

Here is my 2 monitor set up after running the #2 script. Main plus 2 alts:

EnBM2.thumb.jpg.4d098f7fb6a62591d16219a92629d216.jpg

 

If I now want to add 2 more, I simply click the #4 script and it ADDs 2 more leaving the others:

EnBM4.thumb.jpg.99c0c28b0f86e391a97f4502d7d49048.jpg

 

Next post will begin the actual scripts.

 

  • Upvote 1

Share this post


Link to post
Share on other sites

Ok, now for the scripts.  You don't have to put them where I did, but, hey, I like to keep all game assets in one place.  So Net-7, the Starship creator, and these scripts are all inside my main EnB folder.

 

In the case of the scripts, I created an AHK folder.

 

First script: LaunchEnB.ahk

; ==============================================================================================
;
; This script runs an instance of Earth and Beyond
;
;  It runs Net-7, hits the Play, Dismisses the Terms Window and sets the title to "EnBLoad"
; ==============================================================================================

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
#singleinstance force  ;  Allow only one to run at a time

Progress, w200,, Please do not disturb the process. , Loading EnB Instance

Progress, 10
Gosub, LoadMultiUnlocker

Progress, 20
Run , *RunAs D:\Programs\Games\Earth & Beyond\Net-7\bin\LaunchNet7.exe, D:\Programs\Games\Earth & Beyond\Net-7\bin\


; Handle the Net-7 Launcher
WinWaitActive, LaunchNet7
Sleep 5000
WinSetTitle, Net7
Sleep 2000
SendInput {Return}
Progress, 40
BlockInput, On

; When the terms notice comes up alter the title and dismiss
WinWaitActive, Earth & Beyond
Progress, 50
Sleep 1000
WinSetTitle, Loader
Sleep 1000
SendInput {Enter}
Sleep 1000
Progress, 75

; Wait until the main window initializes and rename it
WinWaitActive, Earth & Beyond
Progress, 90
WinSetTitle, EnBLoad

BlockInput, Off
Progress, 100
Progress, Off
Exit

LoadMultiUnlocker:
	IfWinNotExist , Net7 multi client unlocker
	{
		Run , *RunAs D:\Wolfie\Downloads\_Downloads\Other Games\ENB\Net7MultiClientUnlocker\Net7MultiClientUnlocker.exe, D:\Wolfie\Downloads\_Downloads\Other Games\ENB\Net7MultiClientUnlocker
		Sleep 2000
		WinWaitActive, Net7 multi client unlocker
		WinMinimize
	}
	Return

 

The LaunchEnB script is what actually loads the programs such as MultiUnlocker and Net-7 proxy app.  You will need to edit the 2 paths within this file.

 

While this file isn't intended to run alone it can.  It will launch Enb and leave the window titled "EnBLoad".  This is normal as its whats expected by the next script.

 

Second Script: EnbLaunchClients.ahk

; ==============================================================================================
;
; This script launches the main EnB window and 1 to 6 alt windows as provided by a single number
; on the commandline.
;
;  Call with no parameters and it will default to the main window and a single alt
;  Call with 1 parameter and it will create that many alt windows and tile them.
;  Example:
;	EnbLaunchClients.ahk 4
;  	Launches main window and 4 alts (total of 5)
;
; This secript will detect the number and window size of monitors.  The main EnB instance will
; load on your primary monitor.  
;
; If only one alt is requested, it will consume the next monitor.
;
; If more than one alt was requested the second monitor will be divided into a 2 x 2 grid that
; will support up to 4 alts not being overlapped.
;
; If more than 4 alts are requested, it will permit up to 5 but #5 and #6 will be centered
; vertically on the second monitor and they will overlap the other alt windows.
;
; For some reason if I try 6 or more clients, I get the "Already Running" dialog.  So, this
; script caps at 5.
; ==============================================================================================

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

; ==============================================================================================
; Config Section
; ==============================================================================================
; Use PrintScn and drop a copy of an EnB window into paint.  Then pixel peep to get the settings.
; These are default for my Windows 10 setup
;
WindowsTitleBarHeight = 27	; Uppwer title bar area
WindowsBorder = 2		; The side and bottom borders

EBMainWindowExtraPaddingW = 5 	; Makes its width 5px smaller(in case you want to get to your desktop)
EBMainWindowExtraPaddingH = 5 	; Makes its height 5px smaller(in case you want to get to your desktop)

EBAltWindowExtraPaddingW = 5 	; Makes its width 5px smaller(in case you want to get to your desktop)
EBAltWindowExtraPaddingH = 5 	; Makes its height 5px smaller(in case you want to get to your desktop)
; ==============================================================================================

; ==============================================================================================
; Global Vars Section
; ==============================================================================================
EBMainMonitor = 1
EBMainMonitorTop = -1
EBMainMonitorLeft = -1
EBMainMonitorW = -1
EBMainMonitorH = -1
EBMainWindowW = -1
EBMainWindowH = -1

EBAltMonitor = 1
EBAltMonitorTop = -1
EBAltMonitorLeft = -1
EBAltMonitorW = -1
EBAltMonitorH = -1
EBAltWindowW = -1
EBAltWindowH = -1

EBAltCount = 1
; ==============================================================================================

;Grab the command line count
if 0 = 1 
	EBAltCount = %1%

;Limit to 5 alts
if EBAltCount > 5
	EBAltCount := 5


DetectMonitors()

;MsgBox, Main Monitor %EBMainMonitor% at %EBMainMonitorTop% x %EBMainMonitorLeft% is  %EBMainMonitorW%w x %EBMainMonitorH%h Game is %EBMainWindowW%w x %EBMainWindowH%h
;MsgBox, Alt Monitor %EBAltMonitor% at %EBAltMonitorTop% x %EBAltMonitorLeft% is  %EBAltMonitorW%w x %EBAltMonitorH%h Game is EBAlt %EBAltWindowW%w x %EBAltWindowH%h 


LoadMainEBWindow()



Loop %EBAltCount% {
	LoadAltEBWindow( a_index )
}

;BlockInput, Off

CoordMode, Mouse, Client 
Run, EnBPlay.ahk
ExitApp


LoadMainEBWindow()
{
	global
	SplashTextOn, 400, 200, Loading, Loading Main Window
	WinMove, Loading, , EBMainMonitorLeft,EBMainMonitorTop
	IfWinNotExist , EnBMain
	{
		SetWindowSize( EBMainWindowW, EBMainWindowH )
		Run LaunchEnB.ahk
		WinWaitActive, EnBLoad
		WinSetTitle, EnBMain
		;WinMove,,,%EBMainMonitorLeft%,%EBMainMonitorTop%
	}
	SplashTextOff
}

LoadAltEBWindow(TheAltNumber)
{
	global
	;BlockInput, On
	local TheAlt = "EnBAlt" + TheAltNumber
	local GridAlt := TheAltNumber -1
	local Grid0 := (GridAlt & 1) = 1
	local Grid2 := (GridAlt & 2) = 2
	local Grid4 := (GridAlt & 4) = 4

	local AltWindowT := EBAltMonitorTop
	local AltWindowL := EBAltMonitorLeft

	;msgbox %Grid0% %Grid2% %Grid4%

	AltWindowL := Round( AltWindowL + ( Grid0 * ( EBAltWindowW + ( WindowsBorder * 2 ) + EBAltWindowExtraPaddingW ) ) )
	AltWindowT := Round( AltWindowT + ( Grid2 * ( EBAltWindowH + WindowsTitleBarHeight + WindowsBorder + EBAltWindowExtraPaddingH ) ) )
	AltWindowT := Round( AltWindowT + ( Grid4 * ( EBAltWindowH / 2 ) ) )

	;msgbox %AltWindowL% %AltWindowT%

	SplashTextOn, 300, 100, Loading, `nLoading Alt %TheAltNumber% of %EBAltCount% `n`nPlacing window at %AltWindowL% x %AltWindowT%
	WinMove, Loading, , AltWindowL,AltWindowT

	IfWinNotExist , %TheAlt%
		{
			SetWindowSize( EBAltWindowW, EBAltWindowH )
			Run LaunchEnB.ahk
			WinWaitActive, EnBLoad
			WinSetTitle, %TheAlt%
			WinMove,,,AltWindowL,AltWindowT
		}
	Sleep 1000
	SplashTextOff

}



DetectMonitors()
{
	global

	local AltFrameH = 0
	local AltFrameW = 0

	SysGet, MonitorCount, MonitorCount
	SysGet, MonitorPrimary, MonitorPrimary
	

	If MonitorCount >= 2
	{
		EBMainMonitor = %MonitorPrimary%
		If EBMainMonitor = 1 
			EBAltMonitor := EBMainMonitor + 1
		If EBMainMonitor > 1
			EBAltMonitor := EBMainMonitor - 1
	}
	Loop, %MonitorCount%
	{
		SysGet, MonitorName, MonitorName, %A_Index%
		SysGet, Monitor, Monitor, %A_Index%
		SysGet, MonitorWorkArea, MonitorWorkArea, %A_Index%
		If (A_Index = EBMainMonitor)
		{
			EBMainMonitorTop = %MonitorTop%
			EBMainMonitorLeft = %MonitorLeft%
			EBMainMonitorW := MonitorWorkAreaRight - MonitorWorkAreaLeft
			EBMainMonitorH := MonitorWorkAreaBottom - MonitorWorkAreaTop
		}
		If (A_Index = EBAltMonitor)
		{
			EBAltMonitor = %A_Index%
			EBAltMonitorTop = %MonitorTop%
			EBAltMonitorLeft = %MonitorLeft%
			EBAltMonitorW := MonitorWorkAreaRight - MonitorWorkAreaLeft
			EBAltMonitorH := MonitorWorkAreaBottom - MonitorWorkAreaTop
		}
	}



	; Set EB Window Sizes
	EBMainWindowW := Round( ( EBMainMonitorW - (10 + ( WindowsBorder * 2) ) ) - EBMainWindowExtraPaddingW )
	EBMainWindowH := Round( ( EBMainMonitorH - (10 + ( WindowsTitleBarHeight + WindowsBorder) ) )- EBMainWindowExtraPaddingH )

	AltFrameH := ( WindowsTitleBarHeight + WindowsBorder)
	AltFrameW := ( WindowsBorder * 2)

	; Assumed settings for only 1 alt
	EBAltWindowW := Round( EBAltMonitorW - ( AltFrameW + EBAltWindowExtraPaddingW ) )
	EBAltWindowH := Round( EBAltMonitorH - ( AltFrameH + EBAltWindowExtraPaddingH ) )

	;If the alt count is more than 1 assume a 2x2 grid
	if EBAltCount > 1
	{
		EBAltWindowW := Round( ( EBAltMonitorW - ( ( AltFrameW + EBAltWindowExtraPaddingW ) * 2) ) / 2 )
		EBAltWindowH := Round( ( EBAltMonitorH - ( ( AltFrameH + EBAltWindowExtraPaddingH ) * 2) ) / 2 )
	}
}

SetWindowSize( WindowWidth, WindowHeight )
{
	If WindowWidth > 100 && WindowWidth < 10000 && WindowHeight > 100 && WindowWidth > 100 && WindowWidth < 10000
	{
		;MsgBox, Applying Registry: %WindowWidth% x %WindowHeight%
		RegWrite, REG_DWORD, HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Westwood Studios\Earth and Beyond\Render, RenderDeviceWidth, %WindowWidth%
		RegWrite, REG_DWORD, HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Westwood Studios\Earth and Beyond\Render, RenderDeviceHeight, %WindowHeight%
		;MsgBox, Set: %WindowWidth% x %WindowHeight%
	}
}

 

This script takes care of loading the main window, the alts as well as calculating their proper window sizes.  There is a config section at the top of this file.  If your windows theme has odd sizes for the titlebars and borders, you may wish to screenshot a EnB window and throw it into paint to verify your border sizes and title bar height.

 

Also in the config section are 4 variables for controlling extra padding around the windows.  I like to have a bit of squeeze between the windows so I can click between them.  This helps a lot if you are running 5 alts (6 total) as the 5th one will overlap two on the second monitor.  And you can then click between the windows to access it if you need to.  Set the padding to 0 if you don't like it.  Easy.

 

This script grabs the monitor details from windows.  It selects the main display for the main EnB window.  It selects your other monitor for the alts.  If you have more than 2 monitors it will choose the monitor next to the main.  If your main is #1 it will choose monitor #2 for the alts.  If your main monitor is #2 it will choose monitor #1 for the alts.  If you have only one monitor, it obviously will load them all on the one.

 

If you do not like how the script picks monitors, check this section:

	If MonitorCount >= 2
	{
		EBMainMonitor = %MonitorPrimary%
		If EBMainMonitor = 1 
			EBAltMonitor := EBMainMonitor + 1
		If EBMainMonitor > 1
			EBAltMonitor := EBMainMonitor - 1
	}

Replace it with:

EBMainMonitor := 1
EBAltMonitor := 2

And edit the numbers after the "=" to be whatever monitor number you want to force the windows to.

 

The rest is automatic.  It grabs the display sizes and handles the math for window sizes minus the padding you specified and minus the standard boards and titlebar.  Then pokes that into the registry prior to launching the first script.

 

Once the LaunchEnB.ahk loads a copy of EnB, its left with a window titled "EnBLoad".  This script then takes that window and renames it to "EnBMain" or "EnBAlt1" or whatever the sequence is.  It moves that window to the calculated display position.  It then calls the launch script again and repeats the process until the required number of copies are run.

 

Last Script: EnBPlay.ahk

; ==============================================================================================
;
; This script is the play time script and handles feeding commands to the alts as well as the
; main window.
;
; ==============================================================================================

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.
#singleinstance force
; ==============================================================================================
; Global Vars Section
; ==============================================================================================

MainMouseX:=0
MainMouseY:=0


; ==============================================================================================

; ==============================================================================================
; Main Startup Section
; ==============================================================================================
CoordMode, Mouse, Client

GetWindowSizeByTitle("EnBMain",w,h)
EBMain := new ObjectXY(w,h)
EBMainLocations:= New EnBWindowLocations(EBMain.x,EBMain.y)

GetWindowSizeByTitle("EnBAlt1",w,h)
EBAlt := new ObjectXY(w,h)
EBAltLocations:= New EnBWindowLocations(EBAlt.x,EBAlt.y)


MsgBox EnB Play Script Initialized.`nReady to play.

WinActivate, EnBMain
SaveMainMouse()
; ==============================================================================================

#IfWinActive EnBMain
;~~~~~~~~~~~~~~~~~~~~~ [ Main Window Only Macros ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

;===========================================================
; Formations
;===========================================================
Numpad1::
	KeyWait Control
	Gosub, FormationPipe
	Return
Numpad2::
	KeyWait Control
	Gosub, FormationBlock
	Return
Numpad3::
	KeyWait Control
	Gosub, FormationSlot
	Return
Numpad4::
	KeyWait Control
	Gosub, FormationAlt
	Return
;===========================================================

;===========================================================
; Alt Targeting and Firing
;===========================================================
Numpad5::
	Gosub, AltSelectMainTarget
	Return

Numpad6::
	SendToAlts(" ")
	ActivateMain()
	Return
;===========================================================

;===========================================================
; Looting
;===========================================================
!Numpad5::
	AltSelectMainTarget("EnBAlt1")
	AltLoot("EnBAlt1")
	Return
!Numpad6::

	AltSelectMainTarget("EnBAlt2")
	AltLoot("EnBAlt2")
	Return
!Numpad7::
	AltSelectMainTarget("EnBAlt3")
	AltLoot("EnBAlt3")
	Return
!Numpad8::
	AltSelectMainTarget("EnBAlt4")
	AltLoot("EnBAlt4")
	Return
!Numpad9::
	KeyWait Alt
	IfWinExist , EnBMain
	{
		FromMainXY( "SelectedObjectAction",LootButtonX,LootButtonY)
		FromMainXY( "LootTopSlot",LootSlotX,LootSlotY)
		WinActivate, EnBMain
		SendInput {Click, %LootButtonX% ,  %LootButtonY% }
		Sleep 1000
		SendInput {Click, %LootSlotX%, %LootSlotY% }
		Sleep 000
		SendInput {Click, %LootButtonX% , %LootButtonY% }
	}
	Return
;===========================================================

;===========================================================
; Gateing and Registration
;===========================================================
!NumpadAdd::
	KeyWait Alt
	Gosub, ItemActionAllAlts ; Operates Main Action on selected thing (gate, dock, etc)
	Return
!NumpadSub::
	KeyWait Alt
	Gosub, ItemSecondActionAllAlts ; Operates Secondary Action on selected thing (register for example)
	Return
NumpadAdd::
	Gosub, ItemActionMain ; Operates Main Action on selected thing (gate, dock, etc)
	Return
NumpadSub::
	Gosub, ItemSecondActionMain ; Operates Secondary Action on selected thing (register for example)
	Return
^NumpadAdd::
	KeyWait Control
	Gosub, AltsAcceptWormhole ; Accepts Wormhole on all alts
	Return
^NumpadSub::
	KeyWait Control
	Gosub, AltsRejectWormhole ; Rejects Wormhole on all alts
	Return
;===========================================================

;===========================================================
; Inventory Sales
;===========================================================
^SC029::
	KeyWait Control
	MainSellWholePanel()
	Return

!SC029::
	KeyWait Alt
	loop 12 {
		Send, {Ctrl Down}{Click}{Ctrl up}
		Sleep 100
	}
	return

;===========================================================

;~~~~~~~~~~~~~~~~~~~~~ [ Main Window Only Macros ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#IfWinActive


#IfWinActive EnBAlt
;~~~~~~~~~~~~~~~~~~~~~ [ Alt Window Only Macros ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

;===========================================================
; Inventory Sales
;===========================================================
^SC029::
	KeyWait Control
	AltSellWholePanel()
	Return

!SC029::
	KeyWait Alt
	loop 12 {
		Send, {Ctrl Down}{Click}{Ctrl up}
		Sleep 100
	}
	return

;===========================================================

;~~~~~~~~~~~~~~~~~~~~~ [ Alt Window Only Macros ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#IfWinActive

;===========================================================
; Utilities
;===========================================================

FormationPipe:

	FromMainXY( "Formation", FormX, FormY)
	FromMainXY( "FormationPipe", OptX, OptY)
	ActivateMain()
	Click, %FormX%,%FormY%
	Sleep 1500
	Click, %OptX%,%OptY%
	Sleep 1000
	Gosub, FormationAlt
	ActivateMain()
	Return 

FormationBlock:
	FromMainXY( "Formation", FormX, FormY)
	FromMainXY( "FormationBlock", OptX, OptY)

	ActivateMain()
	Click, %FormX%,%FormY%
	Sleep 1500
	Click, %OptX%,%OptY%
	Sleep 1000
	Gosub, FormationAlt
	ActivateMain()
	Return 

FormationSlot:
	FromMainXY( "Formation", FormX, FormY)
	FromMainXY( "FormationSlot", OptX, OptY)

	ActivateMain()
	Click, %FormX%,%FormY%
	Sleep 1500
	Click, %OptX%,%OptY%
	Sleep 1000
	Gosub, FormationAlt
	ActivateMain()
	Return 

FormationAlt:
	;SendToWindow("EnBAlt1", "`,")
	SendToAlts("`,")
	Return 

AltSelectMainTarget:
	SaveMainMouse()
	WinGet, winList, List, EnBAlt
	Loop % winList
	{
	_hWin := winList%A_Index%
	WinGetTitle, title, ahk_id %_hWin%
	AltSelectMainTarget(title)
	}
	RestoreMainMouse()
	Return 

ItemActionAllAlts:
	FromAltXY( "SelectedObjectAction", OptX, OptY)
	WinGet, winList, List, EnBAlt
	Loop % winList
	{
	_hWin := winList%A_Index%
	WinGetTitle, title, ahk_id %_hWin%
	ClickOnWindow(title,OptX,OptY)
	}
	RestoreMainMouse()
	Return

ItemSecondActionAllAlts:
	FromAltXY( "SelectedObjectSecondaryAction", OptX, OptY)
	WinGet, winList, List, EnBAlt
	Loop % winList
	{
	_hWin := winList%A_Index%
	WinGetTitle, title, ahk_id %_hWin%
	ClickOnWindow(title,OptX,OptY)
	}
	RestoreMainMouse()
	Return

ItemActionMain:
	FromMainXY( "SelectedObjectAction", OptX, OptY)
	ClickOnWindow("EnBMain",OptX,OptY)
	Return

ItemSecondActionMain:
	FromMainXY( "SelectedObjectSecondaryAction", OptX, OptY)
	ClickOnWindow("EnBMain",OptX,OptY)
	Return

AltsAcceptWormhole:
	FromAltXY( "WormHoleAccept", OptX, OptY)
	WinGet, winList, List, EnBAlt
	Loop % winList
	{
	_hWin := winList%A_Index%
	WinGetTitle, title, ahk_id %_hWin%
	ClickOnWindow(title,OptX,OptY)
	}
	RestoreMainMouse()
	Return

AltsRejectWormhole:
	FromAltXY( "WormHoleReject", OptX, OptY)
	WinGet, winList, List, EnBAlt
	Loop % winList
	{
	_hWin := winList%A_Index%
	WinGetTitle, title, ahk_id %_hWin%
	ClickOnWindow(title,OptX,OptY)
	}
	RestoreMainMouse()
	Return


AltLoot(TheAlt)
{
	local lX,lY
	IfWinExist , %TheAlt%
	{
		FromAltXY( "SelectedObjectAction",LootButtonX,LootButtonY)
		FromAltXY( "LootTopSlot",LootSlotX,LootSlotY)
		FromAltXY( "SelectedObject",ObjectX,ObjectY)
		;msgbox %LootButtonX% %LootButtonY%
		CoordMode, Mouse, Client 
		MouseGetPos, lX,lY
		WinActivate, %TheAlt%
		SendInput {Click, %LootButtonX%,%LootButtonY%}
		Sleep 1000
		SendInput {Click, %LootSlotX%,%LootSlotY%}
		Sleep 500
		SendInput {Click right %ObjectX%, %ObjectY%}
		Sleep 500
		WinActivate, EnBMain
		MouseMove, lX, lY
	}
}

AltSelectMainTarget(TheAlt)
{
	IfWinExist , %TheAlt%
	{
		FromAltXY( "GroupLeaderTarget",tgtX,tgtY)
		;msgbox %tgtX% %tgtY%
		WinActivate, %TheAlt%
		SendInput {Click, %tgtX%, %tgtY%}
		Sleep 500
	}
	

}

AltSellWholePanel()
{
	local ClickDelay := 200
	local MouseLow := 0
	local MouseHigh := 20
	local r := 0
	local c := 0
	local s := ""

	loop 4 { ; Row Loop
		r := a_index
		Loop 3 { ; Col Loop
			c := a_index
			s := "InventoryC" . c . "R" . r
			SetMouseDelay, Rand(MouseLow,MouseHigh)
			FromAltXY( s,tgtX,tgtY)
			MouseMove %tgtX%,%tgtY%
			Sleep 100+Rand(ClickDelay)
			SendEvent  +{Click}
		}
	} ; Row Loop

}
MainSellWholePanel()
{
	local ClickDelay := 200
	local MouseLow := 0
	local MouseHigh := 20
	local r := 0
	local c := 0
	local s := ""

	loop 4 { ; Row Loop
		r := a_index
		Loop 3 { ; Col Loop
			c := a_index
			s := "InventoryC" . c . "R" . r
			SetMouseDelay, Rand(MouseLow,MouseHigh)
			FromMainXY( s,tgtX,tgtY)
			MouseMove %tgtX%,%tgtY%
			Sleep 100+Rand(ClickDelay)
			SendEvent  +{Click}
		}
	} ; Row Loop

}

;===========================================================
; Core Utilities
;===========================================================

ActivateMain()
{
	WinActivate, EnBMain
	Sleep 250
}

SendToAlts(SendToAll)
{
	SendIt := SendToAll
	WinGet, winList, List, EnBAlt
	Loop % winList
	{
	_hWin := winList%A_Index%
	WinGetTitle, title, ahk_id %_hWin%
	SendToWindow(title,SendIt)
	}

}
ClickOnWindow(TheWindow,X,Y)
{
	IfWinExist , %TheWindow%
	{
		SetMouseDelay 100
		WinActivate, %TheWindow%
		SendInput {Click, %X%,%Y%}
		Sleep 100
	}
}

SendToWindow(TheWindow,TextToSend)
{
	IfWinExist , %TheWindow%
	{
		WinActivate  %TheWindow%
		Send %TextToSend%
		Sleep 150
	}
}

SaveMainMouse()
{
	global
	WinActivate, EnBMain
	local lX,lY
	MouseGetPos, lX,lY
	MainMouseX := lX
	MainMouseY := lY
}

RestoreMainMouse()
{
	global
;	SplashTextOn, 400, 300, Mouse, Mouse Stored: %MainMouseX% x %MainMouseY%
;	Sleep 5000
;	SplashTextOff
	WinActivate, EnBMain
	MouseMove, MainMouseX, MainMouseY
}

Rand( a=0.0, b=1 ) {
   IfEqual,a,,Random,,% r := b = 1 ? Rand(0,0xFFFFFFFF) : b
   Else Random,r,a,b
   Return r
}

GetWindowSizeByTitle(WindowTitle, ByRef WinWidth := "", ByRef WinHeight := "", WinMode := 1) {
	local TheWindowID
	WinGet, TheWindowID, ID, %WindowTitle%
	fnWinGetPos(TheWindowID, , , WinWidth, WinHeight, WinMode)
}

fnWinGetPos(hWnd, ByRef x := "", ByRef y := "", ByRef Width := "", ByRef Height := "", Mode := 0) {
	VarSetCapacity(WRECT, 8 * 2, 0), i := {}
	, h := DllCall("User32.dll\GetWindowRect", "Ptr", hWnd, "Ptr", &WRECT)
	if (Mode=1||Mode=3)
		VarSetCapacity(CRECT, 8 * 2, 0)
		, h := DllCall("User32.dll\GetClientRect", "Ptr", hWnd, "Ptr", &CRECT)
	if (Mode=2||Mode=3)
		DllCall("User32.dll\ClientToScreen", "Ptr", hWnd, "Ptr", &WRECT)
		, DllCall("User32.dll\ClientToScreen", "Ptr", hWnd, "Ptr", &CRECT)
	i.x := x := NumGet(WRECT, 0, "Int"), i.y := y := NumGet(WRECT, 4, "Int")
	, i.h := i.Height := Height := NumGet(Mode=1||Mode=3?CRECT:WRECT, 12, "Int") - (Mode=1||Mode=3?0:y)
	, i.w := i.Width := Width := NumGet(Mode=1||Mode=3?CRECT:WRECT,  8, "Int") - (Mode=1||Mode=3?0:x)
	return i, ErrorLevel := !h
}


Class EnBWindowLocations{
	; These were the dimesnions on which all the points were measured
	Static BaseClientWidth = 1901 ; Don't Change these!
	Static BaseClientHeight = 1038 ; Don't Change these!

	Static WindowWidth := This.BaseClientWidth
	Static WindowHeight := This.BaseClientHeight

	Static ScaleWidth := 1
	Static ScaleHeight := 1

	Static Coords := {}

	Static TempScale = New ObjectXY()

	__New( WinWidth, WinHeight ) {

		This.Coords["SelectedObject"] := New ObjectXY(1700,870)
		This.Coords["SelectedObjectAction"] := New ObjectXY(1835,697)
		This.Coords["SelectedObjectSecondaryAction"] := New ObjectXY(1762,697)

		This.Coords["GroupLeaderTarget"] := New ObjectXY(1818,626)

		This.Coords["Formation"] := New ObjectXY(1755,360)
		This.Coords["FormationPipe"] := New ObjectXY(1677,300)
		This.Coords["FormationBlock"] := New ObjectXY(1752,300)
		This.Coords["FormationSlot"] := New ObjectXY(1832,300)

		This.Coords["LootTopSlot"] := New ObjectXY(1696,316)

		This.Coords["WormHoleAccept"] := New ObjectXY(760,555)
		This.Coords["WormHoleReject"] := New ObjectXY(1150,555)

		This.Coords["InventoryC1R1"] := New ObjectXY(90,414)
		This.Coords["InventoryC1R2"] := New ObjectXY(90,495)
		This.Coords["InventoryC1R3"] := New ObjectXY(90,578)
		This.Coords["InventoryC1R4"] := New ObjectXY(90,658)

		This.Coords["InventoryC2R1"] := New ObjectXY(202,414)
		This.Coords["InventoryC2R2"] := New ObjectXY(202,495)
		This.Coords["InventoryC2R3"] := New ObjectXY(202,578)
		This.Coords["InventoryC2R4"] := New ObjectXY(202,658)

		This.Coords["InventoryC3R1"] := New ObjectXY(318,414)
		This.Coords["InventoryC3R2"] := New ObjectXY(318,495)
		This.Coords["InventoryC3R3"] := New ObjectXY(318,578)
		This.Coords["InventoryC3R4"] := New ObjectXY(318,658)

		; Set up the scaling
		This.WindowWidth := WinWidth
		This.WindowHeight := WinHeight
		This.ScaleWidth := This.WindowWidth / This.BaseClientWidth
		This.ScaleHeight := This.WindowHeight / This.BaseClientHeight

	}
	Set(name, X, Y)
	{
		return This.Coords[name] := New ObjectXY(X,Y)
	}
	Get(name)
	{
		local tmp = New ObjectXY()
		This.TempScale := This.Coords[name]
		tmp.x := This.TempScale.x
		tmp.y := This.TempScale.y
		return tmp
	}
	GetScaled(name)
	{
		local tmp = New ObjectXY()
		This.TempScale := This.Coords[name]
		tmp.x := This.TempScale.x
		tmp.y := This.TempScale.y
		tmp.x := Round( tmp.x * This.ScaleWidth )
		tmp.y := Round( tmp.y * This.ScaleHeight )
		return tmp
	}}

Class ObjectXY {
	x := 0
	y := 0
	__New(xIn,yIn){
		This.x := xIn
		This.y := yIn
	}
}

FromXY_old(obj, ByRef X, ByRef Y){
	x := obj.x
	y := obj.y
}
FromMainXY(Setting, ByRef X, ByRef Y){
	global
	local obj := EBMainLocations.GetScaled(Setting)
	local x1 := obj.x
	local y1 := obj.y
	X := obj.x
	Y := obj.y
}
FromAltXY(Setting, ByRef X, ByRef Y){
	global
	local obj := EBAltLocations.GetScaled(Setting)
	X := obj.x
	Y := obj.y
}

This script gets launched at the end of the EnbLaunchClients.ahk script.  Once this script initializes, you will see the "EnB Play Script Initialized." dialog box appear (see previous screenshots).  This indicates that the play script is ready for action.

 

This play script listens for the various keboard shortcuts that I programmed into it and then takes care of sending keystrokes to the main or alt windows or clicking the mouse on various areas of the windows.  The class at the end of the script "Class EnBWindowLocations" contains the mouse X/Y positions on MY default window size of 1901x1038.  It performs scaling FROM those settings TO whatever size YOUR windows are.  Don't edit those positions!  It calculates them so they are right for whatever your monitor size is and whatever size the windows loaded as.  So if you change the padding or have a bigger or smaller desktop than I do, the numbers will scale automatically by the program.

 

I tried to label the main groups of hotkeys so its easy to tweak them as you want or add your own.  As I said, these are NOT meant for a human to type.  You probably don't want to hit Alt-NumPad5 for an alt to loot.  Or Ctl-NumPadPlus to accept a wormhole.  These were made quirky to stay out of the way of EnB's standard FPS key settings.  And I use them in my G13 and G15:

EnBG13_1.thumb.jpg.4988f1490c92b215a102fb646db938d2.jpg

EnBG13_2.thumb.jpg.2661b8e16a1a10f5277f1ed9431c8489.jpg

 

Except for chatting, I never touch the normal QUERTY keys while playing.  One hand on the G13, one on the mouse.  I ran out of keys on blue (non-combat) so I programmed G13 and G16 (lower left corner of the G15 keyboard) to refuse and accept wormholes as these aren't used much and its quick to hit them using my left hand thats normally on the G13 pad.

 

The exception to that is the quick sales and quick buys.  Ctl-Tilde will attempt to sell a 12 slot inventory panel, whats visible.  Due to EnB's bot detection (at least I think thats what it is) it misses some.  I have randomized the click times, randomized the waits and I simply can't get it to sell 100% of the time.

 

The other key combo is Alt-Tilde.  It buys 12 of whatever you have selected from the vendor.  Very rapidly.  Extremely handy for fillin up your hold with trade goods quickly so you can get on the road.  I set it to 12 just so it didn't run me broke if I accidentally hit it.  If you wish to change the number of buys, search the play script for "!SC029::".  Right after that is a "loop 12".  Change the 12 to however many you want to buy when hitting this key combo.  The "!" means ALT.  The "SC029" is the scancode for the Tilde key (top left corner on standard keyboards next to "1".

 

 

Again, you can change the key combos to whatever you desire in the play script.  And then program your keyboard or arrange them to suit a normal keyboard play style.

 

 

 

 

 

Edited by wolfie
  • Upvote 2

Share this post


Link to post
Share on other sites

Lets say in the normal course of play that Alt1 crashes or you close it and you had been running 4 alts.  Simply hit your shortcut for 4 again and it will smartly check to see if the main and each alt is running.  If it finds one missing it will re-load it.  And at the end, re-launch the play script.  No need to kill the play script.  Its marked so that only ONE copy will run at a time.  So the next launch of it automatically kills the first.

 

That single instance property is also handy for you to edit the script.  Simply open in your text editor and save (leave it open).  Then double click the script in explorer and it will relaunch it for you to try the new settings and you don't have to close all your EnB instances to do that either.

 

So, there you go.  You have the staring pieces to build your own system from.  Link to AHK is in the OP.  You will need that installed.

 

Oh!  Almost forgot.  Once you install AHK.  Go to its install folder and change the properties on all the EXEs in there (compatibility tab) to run as Admin.  If you don't it can't send keys and such to the Net-7 or EnB windows as they are run as Admin too and would be at a higher protection level.  Once you set the AHK exes to run on the same permissions level as EnB and Net-7 it all should rock.

 

  • Upvote 1

Share this post


Link to post
Share on other sites

I'll have to check this out. Most of my macro code is in AC Tools, and it is really sensitive to screen/windows positions. So I either run it with E&B full screen or windowed in the default top-left starting position.  But using something like this to get repeatable accurate locations of windows could fix much of that.

 

 

Share this post


Link to post
Share on other sites

The way my code works is this.  I created a EnBWindowLocations class that holds a collection of screen points, the original window dimensions and the current window dimensions.  The points I made by opening a screenshot of the game and clipping off the borders and title bar.  Then used the x/y from the paint program (PSP if you want to know) within the class.

 

When the class initializes it calls the __New() function which populates the collection by adding a series of new entries like:
 

This.Coords["GroupLeaderTarget"] := New ObjectXY(1818,626)

That adds a new x/y object to the collection under the key "GroupLeaderTarget".  The 1818,626 values are from the paint program.

 

The class also has static values of BaseClientWidth and BaseClientHeight which are defined as what the dimensions were in the paint program and are the base reference for the coordinates.

 

At the end of the init routine the class calculates the scaling factors (height/width) ScaleWidth and ScaleHeight based on the CURRENT window size as a scale from the size from my paint program.

 

So, my original screen shot was 1901 wide.  Lets say the alt window loads to 600 wide.  So after the init, the ScaleWidth variable will hold 0.31562335612835349815886375591794.

 

Within the main portion of the script it makes a call to the GetScaled() function of the class to retrieve a X/Y pair.  In the case of the GroupLeaderTarget, the class will take 1818 and multiply that by the ScaleWidth which will result in an X position of 573.8 so it will round to 574 as an integer.  So that position on a 600w window should click the group leader's target.  So the class takes care of all the scaling and value lookups.  You simply call it with the name of the key from the collection and it will return a scaled X/Y position for that key.


The main portion of the script creates two instances of this class:

GetWindowSizeByTitle("EnBMain",w,h)
EBMain := new ObjectXY(w,h)
EBMainLocations:= New EnBWindowLocations(EBMain.x,EBMain.y)

GetWindowSizeByTitle("EnBAlt1",w,h)
EBAlt := new ObjectXY(w,h)
EBAltLocations:= New EnBWindowLocations(EBAlt.x,EBAlt.y)

First it gets the window size, builds an XY object from that and then instances the class based on that window size.  So EBMainLocations object will return a different X/Y setting for GroupLeaderTarget than EBAltLocations will assuming the main window and alts are two different sizes.

 

All this makes the main portion of the script independent from the window size thats actually being referenced.  No size or mouse locations are stored there, all are in the class.  If you take a look at the AltSelectMainTarget() in the main script area, you will see its fairly readable by humans and able to understand whats happening.

This  gets the XY position of the GroupLeaderTarget location into tgtX & tgtY variables:
 

FromAltXY( "GroupLeaderTarget",tgtX,tgtY)

This clicks on the window:
 

SendInput {Click, %tgtX%, %tgtY%}

Notice no hard work here.  No math.  No looking up raw values.

Guess what this does:
 

FromAltXY( "SelectedObjectAction",LootButtonX,LootButtonY)
FromAltXY( "LootTopSlot",LootSlotX,LootSlotY)
FromAltXY( "SelectedObject",ObjectX,ObjectY)
SendInput {Click, %LootButtonX%,%LootButtonY%}
SendInput {Click, %LootSlotX%,%LootSlotY%}
SendInput {Click right %ObjectX%, %ObjectY%}


Clicks the loot button, clicks the top loot slot, right clicks on the object panel to de-select the mob carcass (or asteroid for mining) to release it to another alt for looting.  Thats from the AltLoot() function.  Again, automatically scales.  No need for bulk editing mouse locations.  And it doesn't matter where the window is.  All taken care of by the class.

 

One note here on the SelectedObjectAction and SelectedObjectSecondaryAction location keys.  These are mostly universal positions of the two commonly used action and alt action of whatever you have selected (yea, I know some things have a 3rd one but I can't remember the last time I needed it).  If you have a station selected, the main action is dock, the secondary action is register.  If you are on a quest, a mob action might be talk.  If you are hunting and have a mob selected, action is follow.  If you are a miner and have a roid selected, prospect is the action.  All occur at the same window location in EnB.  So while the location may all be the same, the action EnB takes widely varies.  So thats why these two are rather nondescript in their titles.  You could duplicate the keys and call them "Speak", "Dock", etc.  I saw no need.  I am ok with these being fairly generic.  Just means the same code can be used to loot a mob carcass after a kill or to mine the top mineral in a roid by an explorer.  As you can tell, I like reusable code :)

 

My goal was to separate Game instancing and loading from play time functionality.  Take care of the positions in the EnBWindowLocations class.  Take care of control, activation and timing in the main script.  Make main script fairly readable.  Make both expandable.  And have it all adapt to different monitor sizes/locations.

 

I will say up front, I only started using AHK a few days ago so maybe there are better ways to do things.  I saw it as very similar to what I do as a programmer, it was fairly easy to grasp and run with.

 

Share this post


Link to post
Share on other sites

Only limited by your computer.

And don't leave them unattended.

Share this post


Link to post
Share on other sites
On 5/12/2017 at 2:36 AM, dramaking said:

since multiboxing is allowed is there a limit to the number;

 

I have only managed to get 6 running at once before the "Already Running" prevents any more.  Even with the unlocker.  No matter what I do, 6.  Thats it.  So thats basically what these scripts support.  1 main and 5 alts.

 

And, the scripts are not bots.  They spread commands to alts from a main window or monitor keystrokes to send commands.  They, in no way, facilitate botting or leaving them alone to do something without a human.  Its not like they are gonna auto-mine roids while you go take a pee and get another dew.  So they fall within any reasonable interpretation of TOS and any fair play ethics.  A human has to press a button to get them to do anything.

Share this post


Link to post
Share on other sites

awsome write up wolfie...yea i had a problem with ac tools also..your post also helped alot of "6 pack multi-toon" players so thx for this post :)

 

Share this post


Link to post
Share on other sites

Just stumbled over this post looking how to multi box after many years of absence from the game. (it's so useful to have a packmule accompanying you on mixed mining trips)

Still haven't tried out yet, as I still need to find a working download for the Net7MultiClientUnlocker, but the whole AHK and Logitech hotkey setup looks really, really sweet and elegant. And this is coming from somebody who worked in software test automation :) 

I have the Logitech MMO mouse and was already quite happy after setting up a macro to enter the client password for me, because damn am I tired of Megan telling me "I'm sorry, your log-in information wasn't accepted..."

Thank you for sharing this and sharing it so clearly and well documented!

Share this post


Link to post
Share on other sites

Wow, I Have not even made any toons on the server yet, but I can say that this script and keystroke mapping you've done here is far too much work for my taste. its a game enjoy it, dont work it.

 

Tho I am amazed at the things some people do, in order to do less work.

 

+1

Share this post


Link to post
Share on other sites
On 5/3/2017 at 11:24 PM, wolfie said:

Oh!  Almost forgot.  Once you install AHK.  Go to its install folder and change the properties on all the EXEs in there (compatibility tab) to run as Admin.  If you don't it can't send keys and such to the Net-7 or EnB windows as they are run as Admin too and would be at a higher protection level.  Once you set the AHK exes to run on the same permissions level as EnB and Net-7 it all should rock.

 

 

That was an important bit.

So it almost works for me now, just one issue I have is that selecting&thus logging in the character is not really possible, I can't seem to get through the character selection screen since the game won't accept any Mouseclicks into the alt-windows (And I don't think there is a keymapping to select the character itself aside from clicking on it). Any help with that?

 

Edit: It looks like the click event somehow does not "stick" in the client... when either I manually click on the name button it only flickers for a few miliseconds. Same if I tell AHK to do something like this:

 

AltClick(TheAlt)
{
	local lX,lY
	IfWinExist , %TheAlt%
	{
		CoordMode, Mouse, Client 
		MouseGetPos, lX,lY
		WinActivate, %TheAlt%
		ClickOnWindow(%TheAlt%,473,225) ; Manually added the X/Y for char slot 4 here for now.
		Sleep 500
		WinActivate, EnBMain
		MouseMove, lX, lY
	}
}

Ill see the cursor in my Alt1 window move to the right spot, see the button of Char4 flicker and even get to hear the MouseUp sound. Tho no camera move and selection of the character. :-/

IDK if that has to do with how the second client is started, since no mouseclicks are recieved by it, even if I kill the AHK script and the Main client. If I manually start two clients with the same Net7MultiClientUnlocker.exe (running net7config in between both clients to set the right res & have them on the right monitors) and without the AHK scripts - no issues with clicks on either client.

Edited by akeean

Share this post


Link to post
Share on other sites

thanks Wolfie,

 

this stuff is pure magic to the untrained eye!

 

at the moment i just use the script to start the alts on the 2nd monitor in a nice 2x2 grid.

 

was somehow hoping i could get the alts to fire weapons somehow on keystroke?

 

Quote

; Alt Targeting and Firing
;===========================================================
Numpad5::
	Gosub, AltSelectMainTarget
	Return

Numpad6::
	SendToAlts(" ")
	ActivateMain()
	Return

 

 

the numpad5 key works as intended,

 

numpad6 breaks all the alts out of formation and makes them thrust towards the target and then stop & do nothing.

 

must be something on my end i guess.

 

happy with what it can do right now regardless.

 

Share this post


Link to post
Share on other sites

Do you have your key bindings set for the FPS default?  If so, space should fire weapons.  Thats what Numpad6 is programmed to do.

On 6/26/2017 at 2:56 AM, Tiga65 said:

Wow, I Have not even made any toons on the server yet, but I can say that this script and keystroke mapping you've done here is far too much work for my taste. its a game enjoy it, dont work it.

 

Tho I am amazed at the things some people do, in order to do less work.

 

+1

I am a programmer.  This was fun.  And it was a challenge to see IF it could be done.

Share this post


Link to post
Share on other sites
On 6/27/2017 at 8:01 AM, akeean said:

 

That was an important bit.

So it almost works for me now, just one issue I have is that selecting&thus logging in the character is not really possible, I can't seem to get through the character selection screen since the game won't accept any Mouseclicks into the alt-windows (And I don't think there is a keymapping to select the character itself aside from clicking on it). Any help with that?

 

Edit: It looks like the click event somehow does not "stick" in the client... when either I manually click on the name button it only flickers for a few miliseconds. Same if I tell AHK to do something like this:

 

 


AltClick(TheAlt)
{
	local lX,lY
	IfWinExist , %TheAlt%
	{
		CoordMode, Mouse, Client 
		MouseGetPos, lX,lY
		WinActivate, %TheAlt%
		ClickOnWindow(%TheAlt%,473,225) ; Manually added the X/Y for char slot 4 here for now.
		Sleep 500
		WinActivate, EnBMain
		MouseMove, lX, lY
	}
}

Ill see the cursor in my Alt1 window move to the right spot, see the button of Char4 flicker and even get to hear the MouseUp sound. Tho no camera move and selection of the character. :-/

IDK if that has to do with how the second client is started, since no mouseclicks are recieved by it, even if I kill the AHK script and the Main client. If I manually start two clients with the same Net7MultiClientUnlocker.exe (running net7config in between both clients to set the right res & have them on the right monitors) and without the AHK scripts - no issues with clicks on either client.

 

I am not clear on where you put that function.  Second where and how are you calling it?  I purposely didn't put in any login functions in the scripts since I have different teams I play  Its just as easy to simply click on the toon I want in each window.

 

Note that user input is locked during the load process to prevent the user from accidentally typing something or moving the mouse which would interrupt the programmed sequence of events.  Not sure if that is what you are interpreting as "mouseclicks are recieved".

 

Its possible that something is going on with the EnB Client too.  I had a hell of a time getting the auto sell to work to sell trade goods.  The normal click on window function didn't work.  I had to use mouse delay, move and click independently with randomization to foil what I presume EnB has as bot automation detection in that interface:

SetMouseDelay, Rand(MouseLow,MouseHigh)
MouseMove %tgtX%,%tgtY%
Sleep 100+Rand(ClickDelay)
SendEvent  +{Click}

 

 

In your case its possible you might want to convert the call to my internal function to use these functions.  Try:
 

SetMouseDelay 200 ; Will need to tinker on delay amount, this controls the time that the mouse is simulated to be pressed down.
MouseMove 473,225 ; Your coords.  But I recommend using the class I gave you to scale properly.
Sleep 200; Again play with value
SendEvent  {Click}
SetMouseDelay 10 ; Return back to reasonable delay.

 

16 minutes ago, TempestNWK said:

thanks Wolfie,

 

this stuff is pure magic to the untrained eye!

 

at the moment i just use the script to start the alts on the 2nd monitor in a nice 2x2 grid.

 

was somehow hoping i could get the alts to fire weapons somehow on keystroke?

 

 

the numpad5 key works as intended,

 

numpad6 breaks all the alts out of formation and makes them thrust towards the target and then stop & do nothing.

 

must be something on my end i guess.

 

happy with what it can do right now regardless.

 

 

Make sure you are running the clients with "Default FPS" key bindings.  If thats the case, space should fire all weapons.  You will, obviously, have to check the "AutoFire" option on each weapon so it will recycle automatically.

 

Share this post


Link to post
Share on other sites
2 hours ago, wolfie said:

In your case its possible you might want to convert the call to my internal function to use these functions.  Try:
 


SetMouseDelay 200 ; Will need to tinker on delay amount, this controls the time that the mouse is simulated to be pressed down.
MouseMove 473,225 ; Your coords.  But I recommend using the class I gave you to scale properly.
Sleep 200; Again play with value
SendEvent  {Click}
SetMouseDelay 10 ; Return back to reasonable delay.

 

 

 

Thanks, I'll try your the alternative, tho I really doubt that would be the issue. Because it seems you can click in the login screens of your alts fine, while I can't.

 

Something is intercepting my clicks. (I've also tried different variants of left mouse down followed by sending a left mouse up, none of the mouse down events are received by the client, while mouse up plays a sound effect on ui elements and causes them to flicker for a couple of milliseconds)
 

I've screen capped the character selection screen of EnBAlt* window with OBS. This is me first trying to click on "Edison" twice via the button using my mouse, then on the character itself, then back to the button tapping left on my mousepad. The EndMain window works without issue. I've not interfered at all with the startup, basically not touching my mouse&keyboard till the "script done" window popped up.
 

 

Tho I think that it might be some issue with AHK itself. Just to check.. what flavor of AHK are you using? Cause there seem to be three different flavors that might not be all that compatible to each other. Maybe I'm just trying to run your script with the wrong version...?

I've tried it with AHK 1.1.2600 (Unicode-64bit install option) on win10x64.

 

PS: AHK 1.0 & 2.0a both throw different errors when trying to run the scripts with it so I guess ahk 1.1 was correct.

Edited by akeean

Share this post


Link to post
Share on other sites

I don't remember the version.  I can check when I get home from work.  However, I don't have those mouse problems at all  I can click on the windows just fine after launching.

 

Also, other than size and positions, the alt windows are launched in the same way as the main window is.  You do have your E&B set for windowed in the graphics setup right?

 

And thanks for mentioning OBS.  I have been trying to find a decent screen recorder.  You made me google it.  Looks nice.  I will have to grab a copy and give it a go.

 

My version is 1.1.25.1

 

Here is my startup and you can see no issues with mouse clicks.

https://www.youtube.com/embed/CHoiE6JFUq0

Edited by wolfie
  • Upvote 1

Share this post


Link to post
Share on other sites
9 hours ago, wolfie said:

Also, other than size and positions, the alt windows are launched in the same way as the main window is.  You do have your E&B set for windowed in the graphics setup right?

 

And thanks for mentioning OBS.  I have been trying to find a decent screen recorder.  You made me google it.  Looks nice.  I will have to grab a copy and give it a go.

 

So after trying out the different versions of AHK & reinstalling 1.1, messing around in the files I've got it to work. Still have to confirm it also works when the second screen is connected (when I got it to work I was away from the 2nd screen with my laptop). If it works I'll diff my files and see what made it break for me.

 

About OBS: Its more for streaming than just recording. If you intend to stream, get the OBS-FTL variant so you can do low-latency streaming to Mixer (it has miliseconds of stream delay over the ~10 seconds that Twitch has) (https://watchbeam.zendesk.com/hc/en-us/articles/115000638643-Streaming-With-OBS-FTL)
 

Alternatively if you just want to upload to Youtube and have an Intel i5 or i7 CPU that's 3rd gen core-i or newer, use QuickSync H.264 as Encoder (unless you are using the FTL settings for lowest latency). This will give you better quality/size than Nvidia Shadowplay combined with low CPU & hard disk usage. Plus it saves you time as you don't need to re-encode if you were saving it with a lower, fast compression. Tweak ICQ Quality till you are happy with the details quality.
 

obs-settings.png

 

 

Just for capturing, I think using MSI Afterburner is much easier. Ingame just hit the record keybind, press again to stop. No setting up scenes, capture modes in OBS etc. MSI Afterburner also supports QuickSync via "configure external Plugin" then picking QSV.dll on the list. /OT

Edited by akeean

Share this post


Link to post
Share on other sites

Thanks.  Will take a look at it.  Normally I don't record both monitors so I effed up the settings and it recorded two 1080 monitors side by side at 1125 so that video looked like crap but it was sufficient to get the point across that I haven't had those mouse issues.  So instead of being 2k wide, it was 1k wide.  KNow the quality sux.  Meh, it was a one off recording anyway so no crisis.  Needed to bang it out and get the version to you before I met up with friends in ESO.

 

Now that you mention your laptop and 2nd monitor.  Wondering if that could be a odd combo for AHK.  Mine is a desktop and the 2nd monitor is always there.  No idea if that matters.  Its just not a scenario I have ever tried.

 

Curious, though, how the heck did you embed the video in your post?  I don't see any video embed option in this editor.

Share this post


Link to post
Share on other sites
3 hours ago, wolfie said:

Curious, though, how the heck did you embed the video in your post?  I don't see any video embed option in this editor.

 

Just copied the URL from the youtube address bar (i.e. youtube .com/watch?v=xyz) , it then auto.transforms it into an embed after a second (using Opera/Chrome). Only issue is that if you already have text after the link, it might get removed by the embed.

 

Didn't test on the 2nd screen yet, will do once I have time again.

Edited by akeean

Share this post


Link to post
Share on other sites

Any other useful AHK scripts that have been developed to help with more tedious tasks like trade goods purchasing / selling, etc.?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×