Here is the script I use for bf4. It's not as simple as some of the others, but I love the fact it incorporates a first shot multiplier, a GUI, and tweakable guns that are assigned to hotkeys. I have it up and running through sandhawc
#UseHook
#SingleInstance force
#MaxThreadsPerHotkey 2
#NoEnv
SetBatchLines -1
CoordMode, Mouse, Screen
global voice := ComObjCreate("SAPI.SpVoice"), weap, HWND_GUI, HWND_GUNS
voice.rate := -1
OnMessage(0x03, "GuiMove")
weap := gunarray()
Menu, Tray, NoStandard
Menu, Tray, Add, Show Window, ShowWindow
Menu, Tray, Add
Menu, Tray, Add, Exit, Exit
Menu, Tray, Click, 1
Menu, Tray, Default, Show window
SetWorkingDir % A_Appdata "\BF4Tools"
global Settings := new Settings("settings.ini")
Settings.Read()
SetTimer, gamecheck, 500
Gui, Add, Button, x118 y4 h70 gSettings hwndHWND_SETTINGSBUTTON, >>
Gui, Add, Text, x10 y10, Game:
Gui, Add, Text, x45 y10 w70 vRunningText, Checking..
Gui, Add, Text, x10 y30 gToggleNoRecoil, NoRecoil:
Gui, Add, Text, % "x60 y30 w50 gToggleNoRecoil vNoRecoilText c" (Settings.NoRecoil ? "Green" : "Red"), % (Settings.NoRecoil ? "Enabled" : "Disabled")
Gui, Add, Button, % "x10 y50 vWeapon gDropDownList w100 gChooseWeapon", % Settings.Weapon
GuiControl, ChooseString, Weapon, % Settings.Weapon
Gui, Show, w150, BF4Tools
Gui, % "-0x20000 +hwnd" RandomString(10) " +Owner"
HWND_GUI := WinExist("BF4Tools")
GuiControl, focus, NoRecoil ; have "nothing" in focus
Hotkey, % "~*" Settings.NoRecoilHotkey, ToggleNoRecoil
Hotkey, ~*LButton, Fire
ShowWindow:
if !WinActive("ahk_id" HWND_GUI)
WinActivate % "ahk_id" HWND_GUI
return
ToggleNoRecoil:
Settings["NoRecoil"] := !Settings["NoRecoil"]
Settings.Write("NoRecoil", Settings["NoRecoil"])
if (!Settings["NoRecoil"]) {
SoundPlay, *16
Gui, Font, cRed
GuiControl, Font, NoRecoilText
GuiControl,, NoRecoilText, Disabled
} else {
SoundPlay, *48
Gui, Font, cGreen
GuiControl, Font, NoRecoilText
GuiControl,, NoRecoilText, Enabled
} Gui, Font
return
~F9::
~F10::
~F11::
~F12::
a := Settings["Gun" (RegExReplace(A_ThisHotkey, "[~F]", "") - 8)]
if !a
return
Settings.Write("Weapon", a)
GuiControl 1:, Weapon, % a
saygun(Settings.Weapon)
return
#IfWinActive SandhawC
~Right::
~Left::
Gui Submit, NoHide
RecoilMultiplier := (A_ThisHotkey = "~Right" ? (RecoilMultiplier + 1) : (RecoilMultiplier - 1))
GuiControl,, RecoilMultiplier, % RecoilMultiplier
GuiControl,, MultiplierText, % "x" Round(RecoilMultiplier / 100, 2)
Settings.Write("RecoilMultiplier", RecoilMultiplier)
voice.speak("", 2)
voice.speak((StrLen(RecoilMultiplier) > 2 ? (SubStr(RecoilMultiplier, 1, 1) "." SubStr(RecoilMultiplier, 2, 2)) : ("0." RecoilMultiplier)), 1)
return
CheckBox:
Gui Submit, NoHide
Settings.Write("HeavyBarrel", HeavyBarrel)
return
DropDownList:
Gui Submit, NoHide
Settings.Write("Weapon", Weapon)
return
Fire:
Critical
if !WinActive("SandhawC")
return
for x, b in weap
for a, y in b
if (a = Settings.Weapon)
typ := x, break
mult := weap[typ, Settings.Weapon, "FSM"]
rec_up := weap[typ, Settings.Weapon, "RU"]
rec_hor := weap[typ, Settings.Weapon, "RHA"]
rec_dir := (rec_hor = 0 ? 0 : (rec_hor > 0 ? -1 : 1))
rpm_ps := weap[typ, Settings.Weapon, "RPM"] / 60
sleep % Settings.Delay
s:=l:=time()
While (GetKeyState("LButton", "P"))&&(GetKeyState("NumPad8", "P") || Settings.Force)&&(Settings.NoRecoil)&&(running) {
if (rpm_ps*rec_up*(Settings.RecoilMultiplier/3)*((time()-l)/1000000)*((time()-s)/10000<rpm_ps?((Settings.HeavyBarrel?2:1)*mult):1) >= 1) {
i++
l:=time(),move(((Abs(i*rec_hor)>rec_up)?(rec_dir*(i:=1)):0),(Settings.Invert?-1:1))
}
}
return
gamecheck:
Process, exist, SandhawC.exe
if (Errorlevel > 0) {
running := true
Gui, Font, cGreen
GuiControl, Font, RunningText
GuiControl,, RunningText, Running!
Gui, Font
} else {
running := false
Gui, Font, cRed
GuiControl, Font, RunningText
GuiControl,, RunningText, Not running..
Gui, Font
} Gui, Submit, NoHide
return
GuiMove() {
global
WinGetPos, x, y, w,, % "ahk_id" HWND_GUI
if WinExist("ahk_id" HWND_SETTINGS)
Gui 2: Show, % "x" x+(w+10) " y" y " NoActivate"
if WinExist("ahk_id" HWND_GUNS)
Gui 3: Show, % "x" x-150 " y" y
}
Settings:
if WinExist("ahk_id" HWND_SETTINGS) {
gosub SettingsSave
return
} GuiControl,, >>, X
Hotkey, % "~*" Settings.NoRecoilHotkey, Off
Gui 2: Margin, 8, 6
Gui 2: Add, Text, x10, NoRecoil toggle:
Gui 2: Add, Hotkey, vNoRecoilHotkey hwndHWND_HOTKEY, % Settings.NoRecoilHotkey
AddToolTip(HWND_HOTKEY, "Button to toggle NoRecoil")
Gui 2: Add, Text, x10 y55, F9:
Gui 2: Add, Button, vGun1 gChooseGun1 yp-4 x35 w95, % Settings.Gun1
Gui 2: Add, Text, x10, F10:
Gui 2: Add, Button, vGun2 gChooseGun2 yp-4 x35 w95, % Settings.Gun2
Gui 2: Add, Text, x10, F11:
Gui 2: Add, Button, vGun3 gChooseGun3 yp-4 x35 w95, % Settings.Gun3
Gui 2: Add, Text, x10, F12:
Gui 2: Add, Button, vGun4 gChooseGun4 yp-4 x35 w95, % Settings.Gun4
Loop 4
GuiControl 2: ChooseString, Gun%A_Index%, % Settings["Gun" A_Index]
Gui 2: Add, CheckBox, % "vHeavyBarrel hwndHWND_BARREL x8 Checked" Settings.HeavyBarrel, Heavy barrel?
Gui 2: Add, CheckBox, % "vForce hwndHWND_FORCE x8 Checked" Settings.Force, Force NoRecoil
Gui 2: Add, CheckBox, % "vInvert hwndHWND_INVERT x8 Checked" Settings.Invert, Inverted look
AddToolTip(HWND_FORCE, "Enable if you use toggle aim, as opposed to hold to aim")
AddToolTip(HWND_INVERT, "Enable if you use inverted look ingame")
AddToolTip(HWND_BARREL, "Enable if your gun uses Heavy Barrel attachment")
Gui 2: Add, Text, x10, Recoil strength:
Gui 2: Add, Slider, x10 vRecoilMultiplier hwndHWND_SLIDER gSlider NoTicks Range10-800 AltSubmit Center w90, % Settings.RecoilMultiplier
Gui 2: Add, Text, vMultiplierText yp+5 x110, % "x" Round(Settings.RecoilMultiplier / 100, 2)
AddToolTip(HWND_SLIDER, "The sensitivity of the algorithm. Change until it matches your ingame sensitivity,")
Gui 2: Add, Text, x10, Initial delay:
Gui 2: Add, Slider, vDelay hwndHWND_DELAY Range10-150 ToolTip, % Settings.Delay
Gui 2: Font, s7, Arial
Gui 2: Add, Text,, Enjoy the Tool, Cubed2 <3
AddToolTip(HWND_DELAY, "The amount to wait until countering recoil after firing (default: 40)")
Gui 2: -0x20000 +Owner -Caption +Border +hwndHWND_SETTINGS
WinGetPos, x, y, w,, % "ahk_id" HWND_GUI
Gui 2: Show, % "x" x+(w+10) " y" y " hide", Settings
DllCall("AnimateWindow", "UInt", HWND_SETTINGS, "Int", 100, "UInt", "0x40001")
Gui 2: Show
GuiControl 2: focus, NoRecoilHotkey
GuiControl 2: focus, NoRecoil toggle:
return
SettingsSave:
Gui 2: Submit, NoHide
if !NoRecoilHotkey {
TrayTip,, All Hotkeys have to be filled/unique.
return
} Hotkey("~*" NoRecoilHotkey, "ToggleNoRecoil")
Hotkey("~*" NoRecoilHotkey, "On")
Settings.Write("HeavyBarrel", HeavyBarrel)
Settings.Write("NoRecoilHotkey", NoRecoilHotkey)
Settings.Write("Delay", Delay)
Settings.Write("Invert", Invert)
Settings.Write("Force", Force)
GuiControl,, X, >>
DllCall("AnimateWindow", "UInt", HWND_SETTINGS, "Int", 100, "UInt", "0x90000")
Gui 2: Destroy
WinActivate ahk_id%HWND_GUI%
TrayTip,, Settings saved.
return
Slider:
Gui Submit, NoHide
GuiControl 2:, MultiplierText, % "x" Round(RecoilMultiplier / 100, 2)
Settings.Write("RecoilMultiplier", RecoilMultiplier)
return
ChooseWeapon:
ChooseGun1:
ChooseGun2:
ChooseGun3:
ChooseGun4:
ChooseWeap(Settings[SubStr(A_ThisLabel, 7)], SubStr(A_ThisLabel, 7))
return
ChooseWeap(pre, butto) {
static
if WinExist("ahk_id" HWND_GUNS)
Gui 3: Destroy
Gui 3: Add, DropDownList, vGunType gTypeChange, % arraytoguilist(weap)
for x, b in weap
for a, y in b
if (a = pre)
typ := x, break
GuiControl 3: ChooseString, GunType, % typ
Gui 3: Add, ListBox, vGunWeap h200
GuiControl 3:, GunWeap, % arraytoguilist(weap[typ])
GuiControl 3: ChooseString, GunWeap, % pre
Gui 3: Add, Button, gSave w120, Save
Gui 3: Add, Edit,vbutton x0 y0 h0 w0 Hidden, % butto
Gui 3: -0x20000 +hwndHWND_GUNS -Caption +ToolWindow
WinGetPos x, y,,, % "ahk_id" HWND_GUI
Gui 3: Show, % "x" x-150 " y" y, Guns
return
Save:
Gui 3: Submit, NoHide
if !GunWeap
return
if (button = "Weapon") {
GuiControl 1:, Weapon, % GunWeap
Settings.Write("Weapon", GunWeap)
} else {
GuiControl 2:, % button, % GunWeap
Settings.Write("Gun" SubStr(button, 0), GunWeap)
} Gui 3: Destroy
return
TypeChange:
Gui 3: Submit, NoHide
GuiControl 3:, ListBox1, % "|" arraytoguilist(weap[GunType])
return
3GuiClose:
Gui 3: Destroy
return
}
arraytoguilist(arr) {
for a, b in arr
out .= a "|"
return out
}
saygun(string) {
a := RegExReplace(string, "-", "")
Loop, parse, a
if (RegExMatch(a, "[0-9][0-9]") = A_Index) && !RegExMatch(a, "[0-9][0-9][0-9]")
d .= A_LoopField
else
d .= A_LoopField . " "
voice.speak("", 2)
voice.speak(d, 1)
}
time() {
varsetcapacity(Count1, 8, 0)
DllCall("QueryPerformanceCounter", Uint, &Count1)
Count1:=Numget(Count1, 0)
return % Floor(count1 / 3.385)
}
GuiEscape:
GuiClose:
Gui Submit
ExitApp
return
Class Settings {
__New(file) {
this.file := file
this.defaults := {"NoRecoilHotkey": "F6"
, "RecoilMultiplier": 100
, "Weapon": "AK-12"
, "HeavyBarrel": false
, "NoRecoil": true
, "HoldRight": true
, "Delay": 40
, "Invert": false
, "Force": false
, "Gun1": "AK-12"
, "Gun2": "AEK-971"
, "Gun3": "FAMAS"
, "Gun4": "AUG A3"}
}
Defaults() {
for a, b in this.defaults
this.Write(a, b)
}
Read() {
for a, b in this.defaults
if ((this[a] := IniRead(this.file, "Settings", a)) = "")
this.Write(a, b)
}
Write(key, value) {
IniWrite(value, this.file, "Settings", key)
this[key] := value
}
}
IniRead(file, section, key) {
IniRead, tempf, % A_WorkingDir "\" file, % section, % key, % A_Space
return tempf
}
IniWrite(value, file, section, key) {
IniWrite, % value, % A_WorkingDir "\" file, % section, % key
}
move(x, y) {
DllCall("mouse_event", uint, 1, int, x, int, y, uint, 0, int, 0)
}
Equals(needle, haystack) {
Loop, parse, haystack, % "|"
if (A_LoopField = needle)
return true
return false
}
Hotkey(key, label := "", hwnd := "") {
if (hwnd)
Hotkey, IfWinActive, % "ahk_id" hwnd
else
Hotkey, IfWinActive
Hotkey, % key, % label, UseErrorLevel
}
Random(min, max) {
Random, out, % min, % max
return out
}
RandomString(length, special := false) {
Loop % length
str .= (r := Random(1, special ? 4 : 3)) = 1
? Random(0, 9) : r = 2
? Chr(Random(65, 90)) : r = 3
? Chr(Random(97, 122)) : SubStr("-_?!&:", r := Random(1, 6), 1)
return % str
}
Exit:
ExitApp
return
#if true
AddToolTip(CtrlHwnd,text,Modify=0) {
static TThwnd, GuiHwnd, Ptr
if (!TThwnd) {
Gui,+LastFound
GuiHwnd:=WinExist()
TThwnd:=DllCall("CreateWindowEx","Uint",0,"Str","TOOLTIPS_CLASS32","Uint",0,"Uint",2147483648 | 3,"Uint",-2147483648
,"Uint",-2147483648,"Uint",-2147483648,"Uint",-2147483648,"Uint",GuiHwnd,"Uint",0,"Uint",0,"Uint",0)
Ptr:=(A_PtrSize ? "Ptr" : "UInt"), DllCall("uxtheme\SetWindowTheme","Uint",TThwnd,Ptr,0,"UintP",0)
} Varsetcapacity(TInfo,44,0), Numput(44,TInfo), Numput(1|16,TInfo,4), Numput(GuiHwnd,TInfo,8), Numput(CtrlHwnd,TInfo,12), Numput(&text,TInfo,36)
!Modify ? (DllCall("SendMessage",Ptr,TThwnd,"Uint",1028,Ptr,0,Ptr,&TInfo,Ptr))
. (DllCall("SendMessage",Ptr,TThwnd,"Uint",1048,Ptr,0,Ptr,A_ScreenWidth))
DllCall("SendMessage",Ptr,TThwnd,"UInt",(A_IsUnicode ? 0x439 : 0x40c),Ptr,0,Ptr,&TInfo,Ptr)
}
gunarray() {
w1 := { "ACE 23": {"RPM": 770, "FSM": 2.25, "RU": 0.36, "RHA": 0.05} ; ASSAULT
, "AEK-971": {"RPM": 900, "FSM": 2.6, "RU": 0.42, "RHA": 0.1}
, "AK-12": {"RPM": 650, "FSM": 2.1, "RU": 0.3, "RHA": -0.025}
, "AR 160": {"RPM": 700, "FSM": 1.6, "RU": 0.23, "RHA": 0.0}
, "AUG A3": {"RPM": 700, "FSM": 1.95, "RU": 0.26, "RHA": -0.025}
, "AN-94": {"RPM": 600, "FSM": 265.0, "RU": 0.01, "RHA": 0.0}
, "CZ-805": {"RPM": 700, "FSM": 2.1, "RU": 0.29, "RHA": 0.055}
, "F2000": {"RPM": 850, "FSM": 2.4, "RU": 0.35, "RHA": -0.05}
, "FAMAS": {"RPM": 1000, "FSM": 2.5, "RU": 0.4, "RHA": 0.1}
, "L85A2X": {"RPM": 750, "FSM": 4.4, "RU": 0.35, "RHA": 0.0}
, "M16A4": {"RPM": 800, "FSM": 4.9, "RU": 0.28, "RHA": 0.055}
, "M416X": {"RPM": 750, "FSM": 3.25, "RU": 0.42, "RHA": 0.08}
, "QBZ-95-1": {"RPM": 650, "FSM": 2.0, "RU": 0.24, "RHA": -0.05}
, "SAR-21": {"RPM": 600, "FSM": 1.8, "RU": 0.14, "RHA": 0.0}
, "SCAR-HX": {"RPM": 620, "FSM": 4.0, "RU": 0.58, "RHA": 0.0}}
w2 := { "A-91": {"RPM": 800, "FSM": 2.0, "RU": 0.3, "RHA": 0.0} ; CARBINES
, "ACE 21 CQB": {"RPM": 770, "FSM": 2.25, "RU": 0.36, "RHA": 0.05}
, "ACE 52 CQB": {"RPM": 650, "FSM": 1.95, "RU": 0.56, "RHA": 0.0}
, "ACW-R": {"RPM": 880, "FSM": 2.5, "RU": 0.41, "RHA": -0.075}
, "AK 5CXH": {"RPM": 700, "FSM": 2.25, "RU": 0.49, "RHA": 0.0}
, "AKU-12": {"RPM": 680, "FSM": 2.1, "RU": 0.3, "RHA": -0.025}
, "G36C": {"RPM": 650, "FSM": 1.85, "RU": 0.3, "RHA": 0.0}
, "M4": {"RPM": 800, "FSM": 2.4, "RU": 0.28, "RHA": 0.055}
, "MTAR-21": {"RPM": 900, "FSM": 2.6, "RU": 0.34, "RHA": 0.0}
, "SG553": {"RPM": 830, "FSM": 2.3, "RU": 0.37, "RHA": 0.1}
, "TYPE-95B-1": {"RPM": 650, "FSM": 2.0, "RU": 0.24, "RHA": -0.05}}
w3 := { "ACE 53 SV": {"RPM": 260, "FSM": 1.1, "RU": 1.0, "RHA": 0.2} ; DMR
, "M39 EMR": {"RPM": 300, "FSM": 1.0, "RU": 1.2, "RHA": 0.0}
, "MK11 MOD 0": {"RPM": 260, "FSM": 1.0, "RU": 1.0, "RHA": 0.075}
, "QBU-88": {"RPM": 310, "FSM": 1.0, "RU": 0.8, "RHA": 0.2}
, "RFB": {"RPM": 260, "FSM": 1.0, "RU": 0.9, "RHA": 0.15}
, "SCAR-H SV": {"RPM": 260, "FSM": 1.0, "RU": 1.0, "RHA": 0.0}
, "SKS": {"RPM": 333, "FSM": 1.0, "RU": 0.7, "RHA": 0.05}
, "SVD-12": {"RPM": 260, "FSM": 1.0, "RU": 0.95, "RHA": -0.065}}
w4 := { "AS VAL": {"RPM": 900, "FSM": 2.55, "RU": 0.33, "RHA": 0.05} ; ENGINEER
, "CBJ-MSX": {"RPM": 700, "FSM": 3.0, "RU": 0.28, "RHA": 0.0}
, "CZ-3A1": {"RPM": 1000, "FSM": 3.0, "RU": 0.4, "RHA": 0.15}
, "JS2": {"RPM": 900, "FSM": 2.55, "RU": 0.38, "RHA": 0.1}
, "MP7": {"RPM": 950, "FSM": 2.15, "RU": 0.35, "RHA": 0.1}
, "MPX": {"RPM": 850, "FSM": 2.4, "RU": 0.36, "RHA": 0.0}
, "MX4": {"RPM": 830, "FSM": 2.3, "RU": 0.36, "RHA": -0.06}
, "P90": {"RPM": 900, "FSM": 2.0, "RU": 0.32, "RHA": 0.0}
, "PDW-R": {"RPM": 750, "FSM": 2.0, "RU": 0.26, "RHA": 0.07}
, "PP-2000": {"RPM": 650, "FSM": 1.65, "RU": 0.24, "RHA": -0.05}
, "SR-2": {"RPM": 900, "FSM": 2.3, "RU": 0.33, "RHA": 0.0}
, "UMP-45": {"RPM": 600, "FSM": 1.65, "RU": 0.38, "RHA": 0.0}
, "UMP-9": {"RPM": 700, "FSM": 1.8, "RU": 0.26, "RHA": 0.0}}
/*
w5 := { "44 MAGNUM": {"RPM": 150, "FSM": 1.0, "RU": 2.0, "RHA": 0.0} ; SECONDARY
, "93R": {"RPM": 900, "FSM": 2.0, "RU": 0.5, "RHA": 0.0}
, "COMPACT 45": {"RPM": 320, "FSM": 1.0, "RU": 0.7, "RHA": 0.0}
, "CZ-75": {"RPM": 360, "FSM": 1.0, "RU": 0.6, "RHA": 0.0}
, "DEAGLE 44": {"RPM": 220, "FSM": 1.0, "RU": 2.0, "RHA": 0.0}
, "FN57": {"RPM": 455, "FSM": 1.0, "RU": 0.7, "RHA": 0.0}
, "G18": {"RPM": 900, "FSM": 2.0, "RU": 0.56, "RHA": 0.0}
, "M1911": {"RPM": 310, "FSM": 1.0, "RU": 0.6, "RHA": 0.0}
, "M9": {"RPM": 400, "FSM": 1.0, "RU": 0.45, "RHA": 0.0}
, "MP412 REX": {"RPM": 180, "FSM": 1.0, "RU": 2.0, "RHA": 0.0}
, "MP443": {"RPM": 380, "FSM": 1.0, "RU": 0.7, "RHA": 0.0}
, "P226": {"RPM": 400, "FSM": 1.0, "RU": 0.4, "RHA": -0.1}
, "QSZ-92": {"RPM": 455, "FSM": 1.0, "RU": 0.4, "RHA": 0.0}}
*/
w6 := { "AWS": {"RPM": 780, "FSM": 2.2, "RU": 0.35, "RHA": 0.065} ; SUPPORT
, "LSAT": {"RPM": 650, "FSM": 1.75, "RU": 0.28, "RHA": 0.0}
, "M240B": {"RPM": 650, "FSM": 2.2, "RU": 0.48, "RHA": 0.0}
, "M249": {"RPM": 800, "FSM": 2.5, "RU": 0.325, "RHA": -0.05}
, "M60E4": {"RPM": 570, "FSM": 1.0, "RU": 0.4, "RHA": -0.05}
, "MG4": {"RPM": 800, "FSM": 3.55, "RU": 0.37, "RHA": 0.1}
, "PKP PECHENEG": {"RPM": 600, "FSM": 1.75, "RU": 0.43, "RHA": 0.0}
, "QBB-95-1": {"RPM": 650, "FSM": 3.55, "RU": 0.24, "RHA": -0.05}
, "RPK-12": {"RPM": 600, "FSM": 2.05, "RU": 0.27, "RHA": -0.03}
, "RPK-74M": {"RPM": 600, "FSM": 1.75, "RU": 0.36, "RHA": -0.05}
, "TYPE-88 LMG": {"RPM": 700, "FSM": 2.05, "RU": 0.28, "RHA": 0.0}
, "U-100 MK5": {"RPM": 590, "FSM": 2.5, "RU": 0.2, "RHA": 0.0}}
return {"ASSAULT": w1, "CARBINES": w2, "DMR": w3, "ENGINEER": w4, "SUPPORT": w6}
} ; download complete