First of all, thanks for sharing the script/idea, I have had a fun time playing with it and learning some stuff because of it.
Moreover, during this, I found that BattleList keeps quite a messy table of dynamic indices and caches some creatures which are way out of range in a given moment, and also could grab some creatures from floors above me.
I downloaded the newest version of the battle list script from github, which seems to have dealt with the issue somewhat, but that entire module seems like it's doing so many unnecessary things.
I don't know for you, but upon testing it on the newest battle list, I once again ran into some issues with the script where it would attempt to target a nil entry in the table every time I finish a full rotation, thus always having 1 key press do nothing when rotating between several creatures.
Just curious, why didn't you detect creatures via getSpectator instead of battle list? And have you considered giving player access to choose which key they want to bind instead of space?
I have remade the script to do it like that, and it seems to be performing much more efficiently, not to mention the customization possibilities:
I think letting the player select the range at which it detects is also important, because some players may be playing a melee class that would like to prioritize creatures closer/closest to him instead of rotating through others that may be far away. (Yes, I know there is Sorting mechanism for battle list, but that's also another icky thing)
I'm curious to hear.
Thanks again, and if anyone wants to check/use my edits, you will find links below. I will just post parts that are relevant. (I didn't bother to change various function names so stuff might look weird)
Lua:
autoAttackButton = nil
alreadyAttacked = {}
function init()
end
function terminate()
unbindSpacebar()
end
-------------------------------------------------
--Scripts----------------------------------------
-------------------------------------------------
local battleListCounter = 1
local function getDistanceBetween(p1, p2)
return math.max(math.abs(p1.x - p2.x), math.abs(p1.y - p2.y))
end
function chooseAimFromBattleList()
local DetectDistance = modules.client_options.getOption('quicktargetrange')
local spectators = g_map.getSpectators(g_game.getLocalPlayer():getPosition(), false)
for k,v in pairs(spectators) do
if getDistanceBetween(g_game.getLocalPlayer():getPosition(), v:getPosition()) <= DetectDistance then
if isViableTarget(v) then
if alreadyAttacked[v:getId()] then
if alreadyAttacked[v:getId()] ~= 1 then
g_game.attack(v)
break
end
else
alreadyAttacked[v:getId()] = 1
g_game.attack(v)
break
end
end
end
if k == #spectators and alreadyAttacked ~= nil and next(alreadyAttacked) ~= nil then
alreadyAttacked = nil
alreadyAttacked = {}
chooseAimFromBattleList()
end
end
end
function isViableTarget(creatureData)
if creatureData:isMonster() then
if creatureData:isInvisible() == false then
return true
end
elseif creatureData:isPlayer() then
--[[ Return False for now - when PVP is implemented, we will make a check whether the player wants to attack players or not via Options
if g_game.isSafeFight() then
return false
else
return true
end ]]--
return false
elseif creatureData:isNpc() then
return false
else
return false
end
end
function bindSpacebar()
g_keyboard.bindKeyPress(g_settings.getString("quicktargettingkey"), chooseAimFromBattleList)
end
function unbindSpacebar()
g_keyboard.unbindKeyPress(g_settings.getString("quicktargettingkey"), chooseAimFromBattleList)
end
function toggleSpacebarBind()
if g_settings.getBoolean("quicktargetting") == true then
unbindSpacebar()
bindSpacebar()
else
unbindSpacebar()
end
end
-------------------------------------------------
--Scripts END------------------------------------
-------------------------------------------------
In options lua, we add some new options:
Lua:
quicktargetting = false,
quicktargettingkey = "",
quicktargetrange = 5
Below it, in locals:
Code:
local addQuickTargetButton = nil
In setup function:
Lua:
addQuickTargetButton = generalPanel:getChildById("extraOptions"):getChildById("addHotkeyButton")
local hotkeyButtonLabel = generalPanel:getChildById("extraOptions"):getChildById("hotkeyButtonLabel")
local optvalue1 = g_settings.getString("quicktargettingkey")
if optvalue1 == '' then optvalue1 = 'none' end
hotkeyButtonLabel:setText('Currently: ' ..optvalue1)
In setoption function insert this in any appropriate place:
Lua:
elseif key == 'quicktargetrange' then
generalPanel:getChildById('extraOptions'):getChildById('quickTargetRangeLabel'):setText(tr('Detect range: %d sqm', value))
elseif key == 'quicktargetting' then
addQuickTargetButton = generalPanel:getChildById("extraOptions"):getChildById("addHotkeyButton")
if generalPanel:getChildById("extraOptions"):getChildById("quicktargetting"):isChecked() then
addQuickTargetButton:setEnabled(true)
g_settings.set("quicktargetting", true)
else
addQuickTargetButton:setEnabled(false)
g_settings.set("quicktargetting", false)
end
modules.game_autoattack.toggleSpacebarBind()
New functions for options.lua which will be things that are triggered when new buttons are pressed:
Lua:
function addHotkey()
local assignWindow = g_ui.createWidget('HotkeyAssignWindow', rootWidget)
assignWindow:grabKeyboard()
local comboLabel = assignWindow:getChildById('comboPreview')
comboLabel.keyCombo = ''
assignWindow.onKeyDown = hotkeyCapture
end
function hotkeyCapture(assignWindow, keyCode, keyboardModifiers)
local keyCombo = determineKeyComboDesc(keyCode, keyboardModifiers)
local comboPreview = assignWindow:getChildById('comboPreview')
comboPreview:setText('Current key to add: ' ..keyCombo)
comboPreview.keyCombo = keyCombo
comboPreview:resizeToText()
assignWindow:getChildById('addButton'):enable()
assignWindow:getChildById('addButton').onClick = function() hotkeyCaptureOk(assignWindow, assignWindow:getChildById('comboPreview').keyCombo) end
return true
end
function hotkeyCaptureOk(assignWindow, keyCombo)
if g_settings.getBoolean("quicktargetting") == true then
modules.game_autoattack.unbindSpacebar()
generalPanel:getChildById("extraOptions"):getChildById("hotkeyButtonLabel"):setText('Currently: ' ..keyCombo)
g_settings.set("quicktargettingkey", keyCombo)
modules.game_autoattack.bindSpacebar()
end
assignWindow:destroy()
end
In OTUI you will need to have some new elements set up for it, i have some like:
Code:
OptionCheckBox
id: quicktargetting
!text: tr('Enable Quick Targetting (Experimental)')
!tooltip: tr('Upon pressing the set key, targets the next monster within the set detection range\nstarting with the ones closest to you.')
font: verdana-11px-rounded
anchors.left: parent.left
margin-left: 5
anchors.top: horizontalseparator1.bottom
margin-top: 5
Button
id: addHotkeyButton
!text: tr('Bind Key')
width: 64
anchors.left: parent.left
anchors.top: prev.bottom
margin-top: 5
margin-left: 3
@onClick: modules.client_options.addHotkey()
Label
id: hotkeyButtonLabel
!text: tr('Currently: %s', 'none')
anchors.left: prev.right
anchors.top: prev.top
font: verdana-11px-rounded
margin-left: 5
margin-top: 5
text-auto-resize: true
Label
id: quickTargetRangeLabel
color: #849a52
font: verdana-11px-rounded
anchors.left: parent.left
anchors.top: addHotkeyButton.bottom
margin-top: 5
margin-left: 5
text-auto-resize: true
@onSetup: |
local value = modules.client_options.getOption('quicktargetrange')
self:setText(tr('Detect range: %d', value))
OptionScrollbar
id: quicktargetrange
anchors.left: parent.left
anchors.right: parent.right
anchors.top: prev.bottom
margin-left: 5
margin-top: 5
minimum: 1
maximum: 10
The code above will not work if inserted raw like this, mostly because there are names and references to things that might be called differently in your folders/scripts, so go over that yourself and fix the inconsistencies + make sure that the OTUI references refer to the proper parent/child relations, based on how you insert the OTUI code. The code I posted are children of a panel called extraOptions, you might do your option window differently, idk.