Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 42 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,50 @@
Simple windower command repeating tool for FFXI.
# Repeater

Commands
Simple command repeating tool for FFXI Windower.

//repeater Gives current settings for repeater.
## Commands

//repeater command Sets the line following as a windower command to be repeated.
- `//repeater` - Show current settings and status
- `//repeater help` - Display available commands
- `//repeater command <command>` - Set the command to repeat
- `//repeater delay <seconds>` - Set delay between repeats (default: 10)
- `//repeater count <number|forever>` - Set repeat count (default: forever)
- `//repeater repeat` - Toggle repeating on/off
- `//repeater on/start/go` - Start repeating
- `//repeater off/stop/quit` - Stop repeating

//repeater delay Sets the delay between repeat in seconds.
## Examples

//repeater on/start/go Starts repeating the command you set.

//repeater stop/quit/off Stops repeating the command.

//repeater repeat Starts or stops the command repeating.

//repeater count Determines how many times to repeat the action, default is forever.

Example uses:

Lastsynth: Can be used to repeat your last synth multiple times.
**Crafting:** Repeat last synthesis
```
//repeater command input /lastsynth
```

**Shouts:** Repeat a shout every 30 seconds
```
//repeater delay 30
//repeater command input /shout Selling items! <pos>
```

**Spells:** Cast spell repeatedly
```
//repeater command input /ma "Cure" <me>
```

**Job Abilities:** Use abilities (quotes auto-added for abilities with spaces)
```
//repeater command input /ja "Chakra" <me>
```

**Timers:** Set reminders
```
//repeater delay 300
//repeater count 1
//repeater command input /echo 5-minute timer expired!
```

Shouts: Can be used to shout something over and over again.
//repeater command input /shout Selling Alexandrite <pos>!

Spells: Can be used to cast a spell over and over.
//repeater command input /ma "Fire" <t>

Auctioneer: Can be used to repeatedly buy something while afk, specifically:
//repeater command buy Alexandrite 1 700000
## Notes

As a timer: Can use it to remind yourself of a pop time.
//repeater delay 300
//repeater command input /echo Guy with a 5 minute repop is popping now!
- Commands automatically stop when changing zones
- Job abilities with spaces are automatically quoted correctly
- Use `//repeater repeat` to quickly toggle on/off
206 changes: 119 additions & 87 deletions Repeater.lua
Original file line number Diff line number Diff line change
Expand Up @@ -25,111 +25,143 @@
--SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

_addon.name = 'Repeater'
_addon.version = '1.1'
_addon.version = '1.2 (Updated for current Windower by Palmer)'
_addon.author = 'Selindrile, thanks to: Balloon and Lorand and Mujihina'
_addon.commands = {'repeat','repeater'}

require('luau')
chat = require('chat')
chars = require('chat.chars')
packets = require('packets')
-- Updated requires for current Windower
require('strings')

repeatdelay = 10
line = 'input /echo Command to repeat has not been set.'
count = 'Forever'

-- Helper function to check if string is numeric
local function is_numeric(str)
return tonumber(str) ~= nil
end

-- Helper function to capitalize first letter (replaces :ucfirst())
local function capitalize_first(str)
return str:sub(1,1):upper() .. str:sub(2):lower()
end

-- Helper function to trim whitespace
local function trim(str)
return str:match("^%s*(.-)%s*$")
end

windower.register_event('addon command',function (...)
cmd = {...}
if cmd[1] ~= nil then
cmd[1] = cmd[1]:lower()
end
if cmd[1] == nil or cmd[1] == "status" then
if autorepeat == true then
windower.add_to_chat(7,'Repeating is ON.')
else
windower.add_to_chat(7,'Repeating is OFF.')
end
if cmd[1] ~= nil then
cmd[1] = cmd[1]:lower()
end
if cmd[1] == nil or cmd[1] == "status" then
if autorepeat == true then
windower.add_to_chat(7,'Repeating is ON.')
else
windower.add_to_chat(7,'Repeating is OFF.')
end

windower.add_to_chat(7,'Delay in seconds: '..repeatdelay..'')
windower.add_to_chat(7,'Command to repeat: '..line..'')
windower.add_to_chat(7,'Repeat count: '..count..'')
windower.add_to_chat(7,'Delay in seconds: '..repeatdelay..'')
windower.add_to_chat(7,'Command to repeat: '..line..'')
windower.add_to_chat(7,'Repeat count: '..count..'')
elseif cmd[1] == "help" then
windower.add_to_chat(7,'To start or stop repeating use //repeater repeat')
windower.add_to_chat(7,'To set command type the winder command you want to use after //repeater command')
windower.add_to_chat(7,'To set your repeat delay //repeater delay')
windower.add_to_chat(7,'To set your repeat count //repeater count')

elseif cmd[1] == "rollcall" then

if autorepeat == true and ((type(count) == 'string' and count == 'Forever') or (windower.regex.match(count, "^[0-9]+$") and count > 0)) then
windower.send_command(''..line..'')
windower.send_command('@wait '..repeatdelay..';repeater rollcall')
if count ~= 'Forever' then
count = count -1
windower.add_to_chat(7,'Repeats remaining: '..count..'')
end
end
elseif cmd[1] == "repeat" then
if autorepeat == false then
autorepeat = true
windower.add_to_chat(7,'Enabling Repeater.')
windower.send_command('repeater rollcall')
elseif autorepeat == true then
autorepeat = false
windower.add_to_chat(7,'Disabling Repeater.')
end
elseif cmd[1] == "on" or cmd[1] == "start" or cmd[1] == "begin" or cmd[1] == "go" or cmd[1] == "enable" or cmd[1] == "resume" or cmd[1] == "engage" then
if autorepeat == false then
autorepeat = true
windower.add_to_chat(7,'Enabling Repeater.')
windower.send_command('repeater rollcall')
else
windower.add_to_chat(7,'Repeater already enabled.')
end
elseif cmd[1] == "off" or cmd[1] == "stop" or cmd[1] == "end" or cmd[1] == "quit" or cmd[1] == "pause" or cmd[1] == "disable" or cmd[1] == "disengage" then
if autorepeat == true then
autorepeat = false
windower.add_to_chat(7,'Disabling Repeater.')
else
windower.add_to_chat(7,'Repeater already disabled.')
end
elseif cmd[1] == "command" or cmd[1] == "cmd" then
table.remove(cmd, 1)
line = table.concat(cmd, ' ')
windower.add_to_chat(122,'Your command to repeat has been set to: '..line..'.')

elseif cmd[1] == "reload" then
windower.send_command('lua reload repeater')

elseif cmd[1] == "unload" then
windower.send_command('lua unload repeater')
windower.add_to_chat(7,'To start or stop repeating use //repeater repeat')
windower.add_to_chat(7,'To set command type the windower command you want to use after //repeater command')
windower.add_to_chat(7,'To set your repeat delay //repeater delay <seconds>')
windower.add_to_chat(7,'To set your repeat count //repeater count <number|forever>')

elseif cmd[1] == "rollcall" then
if autorepeat == true and ((type(count) == 'string' and count == 'Forever') or (type(count) == 'number' and count > 0)) then
-- Execute the command - ensure it's sent properly
if line:sub(1,5) == 'input' then
windower.send_command(line)
else
windower.send_command('input '..line)
end
windower.send_command('@wait '..repeatdelay..';repeater rollcall')
if count ~= 'Forever' then
count = count - 1
windower.add_to_chat(7,'Repeats remaining: '..count..'')
end
end
elseif cmd[1] == "repeat" then
if autorepeat == false then
autorepeat = true
windower.add_to_chat(7,'Enabling Repeater.')
windower.send_command('repeater rollcall')
elseif autorepeat == true then
autorepeat = false
windower.add_to_chat(7,'Disabling Repeater.')
end
elseif cmd[1] == "on" or cmd[1] == "start" or cmd[1] == "begin" or cmd[1] == "go" or cmd[1] == "enable" or cmd[1] == "resume" or cmd[1] == "engage" then
if autorepeat == false then
autorepeat = true
windower.add_to_chat(7,'Enabling Repeater.')
windower.send_command('repeater rollcall')
else
windower.add_to_chat(7,'Repeater already enabled.')
end
elseif cmd[1] == "off" or cmd[1] == "stop" or cmd[1] == "end" or cmd[1] == "quit" or cmd[1] == "pause" or cmd[1] == "disable" or cmd[1] == "disengage" then
if autorepeat == true then
autorepeat = false
windower.add_to_chat(7,'Disabling Repeater.')
else
windower.add_to_chat(7,'Repeater already disabled.')
end
elseif cmd[1] == "command" or cmd[1] == "cmd" then
table.remove(cmd, 1)
line = table.concat(cmd, ' ')

-- Auto-fix common job ability formatting
if line:match('^/ja [^"]*%s.*<') then
-- Job ability with spaces but no quotes - add quotes around ability name
local ability = line:match('^/ja ([^<]*)')
if ability then
ability = trim(ability)
local target = line:match('(<.*>)')
if target then
line = '/ja "' .. ability .. '" ' .. target
end
end
end

windower.add_to_chat(122,'Your command to repeat has been set to: '..line..'.')

elseif cmd[1] == "reload" then
windower.send_command('lua reload repeater')

elseif cmd[1] == "unload" then
windower.send_command('lua unload repeater')

elseif cmd[1] == "delay" then
if windower.regex.match(cmd[2], "^[0-9]+$") then
repeatdelay = cmd[2]
windower.add_to_chat(122,'Your repeat delay has been set to: '..repeatdelay..'.')
else
windower.add_to_chat(122,'Delay must be input in numerals.')
end
elseif cmd[1] == "count" then
if cmd[2]:ucfirst() == 'Forever' then
count = 'Forever'
windower.add_to_chat(122,'Your repeat count has been set to: '..count..'.')
elseif windower.regex.match(cmd[2], "^[0-9]+$") then
count = tonumber(cmd[2])
windower.add_to_chat(122,'Your repeat count has been set to: '..count..'.')
else
windower.add_to_chat(122,'Delay must be input in numerals.')
end
elseif cmd[1] == "delay" then
if cmd[2] and is_numeric(cmd[2]) then
repeatdelay = tonumber(cmd[2])
windower.add_to_chat(122,'Your repeat delay has been set to: '..repeatdelay..' seconds.')
else
windower.add_to_chat(122,'Delay must be input in numerals.')
end
elseif cmd[1] == "count" then
if cmd[2] and capitalize_first(cmd[2]) == 'Forever' then
count = 'Forever'
windower.add_to_chat(122,'Your repeat count has been set to: '..count..'.')
elseif cmd[2] and is_numeric(cmd[2]) then
count = tonumber(cmd[2])
windower.add_to_chat(122,'Your repeat count has been set to: '..count..'.')
else
windower.add_to_chat(122,'Count must be input as a number or "Forever".')
end
end
end)

windower.register_event('load', function()
autorepeat = false
autorepeat = false
windower.add_to_chat(122,'Repeater addon loaded. Use //repeater help for commands.')
end)

windower.register_event('zone change', function()
autorepeat = false
autorepeat = false
end)