This is my collection of scripts to simplify buying multiples of items such a scrolls or ammo from vendors easier. the python scripts are currently my main focus as the AHK scripts have been finished to a good standard as far as I'm concerned. I will be posting them here but I am also maintaining Github repositories for them:
https://github.com/DrowArrow/NWNHotkeys (AHK)
https://github.com/DrowArrow/NWNHotkeys-V2 (Python)
feedback is welcome should you have any.
Use of the AHK scripts will require you to have AutoHotkey V2 installed on your system. and if you're a windows user I'd probably recommend using the AHK version for the sake of simplicity.
AHK Scripts
Script 1:
This is the first version that i successfully got working.
Code: Select all
#Requires AutoHotkey v2.0-rc.2
#Hotif WinActive("AHK_exe nwmain.exe")
Global DragDistance := 300
; Use Ctrl + F to quickly buy 10 of the item you are hovering the cursor over.
^f:: {
MouseGetPos &StartX, &StartY
Loop(10) { ; change the loop count to however many times you want it to make the purchase before stopping
Click "Down Right"
Sleep 220
MouseMove StartX + DragDistance, StartY
Click "Up Right"
Sleep 220
MouseMove StartX, StartY
}
}
Version 2 of my quick buy script, functionally works just the same but I approached it in a more compact manner.
Code: Select all
#Requires AutoHotkey v2.0-rc.2
#Hotif WinActive("AHK_exe nwmain.exe")
Global DragDistance := 300
; Use Ctrl + F to quickly buy 10 of the item you are hovering the cursor over.
^f:: {
MouseGetPos &StartX, &StartY
Loop(10) { ; change the loop count to however many times you want it to make the purchase before stopping
MouseClickDrag "right", StartX, StartY, StartX + DragDistance, StartY, 100
Sleep 230
MouseMove StartX, StartY
}
}
decided to add a GUI so the end user can easily change the hotkey used as well as the amount of times it will buy the item.
Code: Select all
#Requires Autohotkey v2
#SingleInstance Force
#NoTrayIcon
HotIfWinActive("ahk_exe nwmain.exe")
; INI file configuration
if FileExist("NWNHotkeys.ini"){
QBHotkey := IniRead("NWNHotkeys.ini", "Hotkeys", "QBHotkey", "^f")
QBLoop := IniRead("NWNHotkeys.ini", "Loops", "QBLoop")
OpLevel := IniRead("NWNHotkeys.ini", "Options", "Opacity")
AOTCheck := IniRead("NWNHotkeys.ini", "Options", "AlwaysOnTop", 0)
}
else {
IniWrite "^f", "NWNHotkeys.ini", "Hotkeys", "QBHotkey"
IniWrite 10, "NWNHotkeys.ini", "Loops", "QBLoop"
IniWrite 255, "NWNHotkeys.ini", "Options", "Opacity"
IniWrite 0, "NWNHotkeys.ini", "Options", "AlwaysOnTop"
QBHotkey := IniRead("NWNHotkeys.ini", "Hotkeys", "QBHotkey", "^f")
QBLoop := IniRead("NWNHotkeys.ini", "Loops", "QBLoop", 10)
OpLevel := IniRead("NWNHotkeys.ini", "Options", "Opacity", 255)
AOTCheck := IniRead("NWNHotkeys.ini", "Options", "AlwaysOnTop", 0)
}
{
myGui := Constructor()
myGui.Show("w300 h200")
}
Constructor()
{
Global QBHotkey
myGui := Gui()
Tab := myGui.Add("Tab3", "x0 y0 w303 h210", ["Neverwinter Nights", "Options"])
Tab.UseTab(1)
myGui.AddHotkey("vQuickBuy Limit1 x8 y32 w120 h21", QBHotkey) ; "vQuickBuy": used to assign a variable name for the hotkey which can be called later on with gui.submit | "QBHotkey": A variable that holds the key combination for the hotkey which is defined as a Global variable at the top of the script
myGui.Add("Text", "x136 y32 w120 h23 +0x200", "Quick Buy")
UpdBtn1 := myGui.Add("Button", "x200 y32 w80 h21", "Update")
myGui.AddEdit("vQBEdit Number x8 y64 w120 h21", QBLoop)
myGui.Add("Text", "x136 y64 w120 h23 +0x200", "Buy Count")
UpdBtn2 := myGui.Add("Button", "x200 y64 w80 h21", "Update")
Tab.UseTab(2)
AOT := myGui.AddCheckbox("vcb_aot x200 y180 Checked" AOTCheck, "Always on top?")
Opacity := myGui.AddSlider("AltSubmit Center NoTicks ToolTipTop range100-255 x8 y55 w120 h21", OpLevel)
myGui.Add("Text", "x30 y32 w120 h23 +0x200", "Transparency")
Tab.UseTab()
UpdBtn1.OnEvent("Click", UpdateHotkey) ; Calls the UpdateHotkey function when the update button is clicked.
UpdBtn2.OnEvent("Click", UpdateLoop)
AOT.OnEvent("Click", AlwaysOnTop)
Opacity.OnEvent("Change", Op_Adjust)
myGui.OnEvent('Close', ExitProcedure)
myGui.Title := "NWNHotkeys"
return myGui
}
;Startup Variables Read
WinWait("NWNHotkeys")
WinSetTransparent(OpLevel)
AOT_Startup := myGui.Submit(0).cb_aot
if (AOT_Startup = 1)
WinSetAlwaysOnTop 1
else
WinSetAlwaysOnTop 0
;Hotkey Update Function
UpdateHotkey(*) {
Global QBHotkey
QBHK := myGui.Submit(0).Quickbuy ; Grabs the updated hotkey from the hotkey gui box
; assigns the updated Hotkey value from the gui to the QBHK variable
ChangeHotkey(QBHK) {
Hotkey(QBHotkey, QB, 'Off') ; Disables Hotkey
QBHotkey := QBHK ; Updates the QBHotkey variable with the Hotkey value from the QBHK variable
Hotkey(QBHotkey, QB) ; Enables hotkey with the newly assigned Hotkey combination
IniWrite QBHotkey, "NWNHotkeys.ini", "Hotkeys", "QBHotkey"
}
if (QBHK != "") {
ChangeHotkey(QBHK)
ToolTip("Hotkey changed!")
Sleep 1000
ToolTip() ; Clear the tooltip
}
}
;Buy Count Update Function
UpdateLoop(*) {
Global QBLoop
LoopCount := myGui.Submit(0).QBEdit ;grabs the value from the Buy Count GUI box and assigned it to the LoopCount variable
;assigns the updated buy count from the gui to the new loop variable
ChangeLoop(LoopCount){
QBLoop := LoopCount ; assigns the updated buy count to the QBLoop variable
IniWrite QBLoop, "NWNHotkeys.ini", "Loops", "QBLoop" ;writes the new value of the QBLoop variable to the configuration file
}
if (LoopCount !=""){
ChangeLoop(LoopCount)
ToolTip("Buy Count Changed!")
sleep 1000
ToolTip()
}
}
;Function for "ALways on Top?"" Checkbox
AlwaysOnTop(AOT, info){
if (aot.Value = 1)
WinSetAlwaysOnTop 1, "A"
else
WinSetAlwaysOnTop 0, "A"
}
Op_Adjust(Opacity, *){
WinSetTransparent(Opacity.value)
IniWrite(Opacity.value, "NWNHotkeys.ini", "Options", "Opacity")
}
Global DragDistance := 300
;Hotkeys
Hotkey(QBHotkey, QB)
; Quickbuy Function
QB(*) {
MouseGetPos &StartX, &StartY
Loop(QBLoop) { ; change the loop count to however many times you want it to make the purchase before stopping
MouseClickDrag "right", StartX, StartY, StartX + DragDistance, StartY
sleep 285 ; Edit the sleep time (milliseconds) to change how quick it makes each purchase
}
MouseMove StartX, StartY
}
ExitProcedure(AOTCheck){
AOTCheck := mygui.Submit(0).cb_aot
IniWrite(AOTCheck, "NWNHotkeys.ini", "Options", "AlwaysOnTop")
ExitApp()
}
HotIf
Python Scripts
Script 1:
this is the first iteration of the python script I'm working on that i feel is worth sharing. it will buy 10 of what ever item you're hovering your cursor over by pressing ctrl+f on your keyboard. this can be changed in the script pretty easily should you wish to do so. it also only works while the game is in focus if you have another window as your main focus the hotkey will do nothing unless the window itself has a use for that key combination.
Code: Select all
import keyboard
import mouse
import time
import pygetwindow as gw
# version 0.0.1
QBHK = 'ctrl + f'
TARGET_WINDOW = 'Neverwinter Nights'
def QB():
active_window = gw.getActiveWindow()
MousePos = mouse.get_position()
if TARGET_WINDOW in active_window.title:
for _ in range(10):
mouse.hold("right")
mouse.move(300, 0, False, 0.15)
mouse.release("right")
mouse.move(*MousePos, True, 0.15)
keyboard.add_hotkey(QBHK, QB)
while True:
try:
time.sleep(1)
except KeyboardInterrupt:
break
This version of the script creates a configuration file in the scripts directory which stores the amount of times it will buy the item as well as the hotkey combination
Code: Select all
import keyboard
import mouse
import time
import pygetwindow as gw
import configparser as cp
import os
# version 0.1.0
TARGET_WINDOW = 'Neverwinter Nights'
def create_config():
config = cp.ConfigParser()
config["General"] = {"QBHK": "ctrl + f", "LOOPS": "10"}
# config["Options"] = {"Opacity": "100", "AlwaysOnTop": "1"}
with open('config.ini', 'w') as configfile:
config.write(configfile)
if __name__ == "__main__": # if the script was launched directly and therefore the __name__ of the script is the __main__ module or parent as it was launched directly then check if config file exists and if it does not, create it.
config_file_path = "config.ini"
if not os.path.exists(config_file_path):
create_config()
print("No configuration found\nConfiguration file has been created")
def read_config():
config = cp.ConfigParser()
config.read("config.ini")
LOOP = config.getint("General", "LOOPS")
QBHK = config.get("General", "QBHK")
config_values = {
"LOOP": LOOP,
"QBHK": QBHK
}
return config_values # returns the config values as a dictionary(dict) to be referenced by the rest of the code when looking for values assigned to variables in the config
if __name__ == "__main__":
config_data = read_config() # reads the values in the dict created and returns the requested settings value such as config_data["LOOP"] which would return the value assigned to the loop key in the config file which in this case is 10 by default.
def QB():
config_data = read_config()
active_window = gw.getActiveWindow()
MousePos = mouse.get_position()
loop_count = config_data["LOOP"]
if TARGET_WINDOW in active_window.title:
for _ in range(loop_count):
mouse.hold("right")
mouse.move(300, 0, False, 0.15)
mouse.release("right")
mouse.move(*MousePos, True, 0.15)
keyboard.add_hotkey(config_data["QBHK"], QB)
while True:
try:
time.sleep(1)
except KeyboardInterrupt:
break
- Put your cursor on the item you want to buy multiple of.
- Hold Ctrl and press the F key (Ctrl + F)
- None
- Figure out how to allow the GUI version to remember hotkey and loop changes between instances
(This may take a while, especially if it means rewriting large parts of the script) was easier than I thought.