feat: spell rotation plugin

This commit is contained in:
2024-11-02 04:23:07 +02:00
parent 3004c371a7
commit d40403b18e
5 changed files with 320 additions and 29 deletions

View File

@@ -10,3 +10,13 @@ install/spellbook:
watch/spellbook:
@echo "Watching for changes in Spellbook..."
@fswatch -o "./Spellbook/Spellbook.xml" | xargs -n1 -I{} make install/spellbook
.PHONY: install/spellrotation
install/spellrotation:
cp "./SpellRotation/SpellRotation.xml" "$(PLUGDIR)"
@echo "SpellRotation installed."
.PHONY: watch/spellrotation
watch/spellrotation:
@echo "Watching for changes in SpellRotation..."
@fswatch -o "./SpellRotation/SpellRotation.xml" | xargs -n1 -I{} make install/spellrotation

View File

@@ -7,4 +7,5 @@ See each plugin's README.md for details and usage.
## Plugins
- [Spellbook](./Spellbook) - Lists all spells in a sticky window for reference
- [SpellRotation](./SpellRotation) - Allows you to easily switch between spells for battle
efficiancy

48
SpellRotation/README.md Normal file
View File

@@ -0,0 +1,48 @@
# SpellRotation Aardwolf Plugin
This plugin lets you switch between various spells to use with SnD or your other aliases.
A typical rotation set might look like:
- `main` - The main spell
- `aoe` - An AOE spell
- `phys` - A physical spell for enemies resistent to elemental damage
## Installation
1. Download [SpellRotation.xml](SpellRotation.xml), place it somewhere it wouldn't move (e.g. the
plugins directory in your MUSHClient installation)
1. Open Plugin Manager (Ctrl+Shift+P)
1. Add `SpellRotation.xml` via the plugin manager
## Usage
1. To **set a rotation**, use `ks set <rotation name> <commands` e.g,
```
ks set main cast balefire`
ks set aoe cast 'fire breath';;cast 'balefire'
```
1. To **see a rotation command list**, use `ks get <rotation name>`
1. Attacking is done by using `kp` without a taregt, or `kp <target>`.
1. You can switch to a rotation by using `ks switch <rotation name>`. To switch mid-battle, you can
use `kp <rotation name>`, which will switch rotation and also attack the active target at the same
time. e.g. `kp aoe`
<!-- 1. `kkp` is a utility alias that will execute the main rotation on the current target set by SnD,
and fill the Command Input on the main window with the main attack command, so you can keep
pressing <kbd>Enter</kbd> to attack, without accidentally attacking a different target of the
same name if it dies while you spam the command. -->
### Aliases/Commands
Use `ks help` to see this list at any time in the game.
```
SpellRotation
--------------------------------------------------------------
kp [target] Execute current rotation
kp [name] Switch to rotation [name] and execute
ks get <name> Get rotation
ks <name> <cmds> Set rotation
ks switch <name> Switch to rotation
ks list List all rotations and their commands
```

View File

@@ -0,0 +1,234 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<!-- MuClient version 5.07-pre -->
<!-- Author: Chen Asraf <contact@casraf.dev> (KumoGami) -->
<!-- Source: https://github.com/chenasraf/aardwolf/tree/master/Spellbook -->
<!-- Plugin "SpellRotation" generated by Plugin Wizard -->
<muclient>
<plugin
name="SpellRotation"
author="KumoGami"
id="dc0917daa7ea3e68b4494d10"
language="Lua"
purpose="Allows you to switch between saved spells in custom categories, for easier attacking."
save_state="y"
date_written="2024-11-02 02:37:52"
requires="5.07"
version="1.0"
>
</plugin>
<script><![CDATA[
-- utils
require "serialize"
utils.unserialize = function (s)
local f = load("return " .. s)
if f then
return f()
end
end
utils.serialize = function (val)
return serialize.save_simple(val)
end
string.lpad = function(str, len, char)
if char == nil then char = ' ' end
return string.rep(char, len - #str) .. str
end
string.rpad = function(str, len, char)
if char == nil then char = ' ' end
return str .. string.rep(char, len - #str)
end
logger = {}
local function withColor(color)
return function (text)
ColourNote(color, "", text)
end
end
logger.Cyan = withColor("cyan")
logger.Yellow = withColor("yellow")
logger.Normal = withColor("white")
-- main
Rot = {
data = {},
type = "main",
snd = true,
}
function Rot:init()
self.data = utils.unserialize(GetVariable("rotData") or "{}")
self.type = GetVariable("rotType") or "main"
self.snd = GetVariable("rotSnd") == "true"
self:save()
end
function Rot:save()
SetVariable("rotData", utils.serialize(self.data or {}))
SetVariable("rotType", self.type)
SetVariable("rotSnd", tostring(self.snd))
end
function Rot:set(name, act)
self.data[name] = utils.split(act or "", ";")
self:save()
end
function Rot:get(name)
return self.data[name]
end
function Rot:switch(name)
self.type = name
if self.snd then
Execute("xset kk kp")
end
logger.Cyan("Switched to " .. name)
self:save()
end
function Rot:act(name, tgt)
tgt = tgt or ""
if tgt == "-" then
tgt = ""
end
if string.match(tgt, " ") then
tgt = "'" .. tgt .. "'"
end
local cmds = self:get(name)
if not cmds then
logger.Yellow("No cmds found for " .. name)
return
end
for _, cmd in ipairs(cmds) do
Send(cmd .. " " .. tgt)
end
end
function Rot:actDefault(tgt)
if self.data[tgt] then
self:switch(tgt)
tgt = "-"
end
self:act(self.type, tgt)
end
function Rot:parse(val)
local split = utils.split(val, " ")
local act = split[1]
local value = table.concat(split, " ", 2)
if act == "set" then
local split = utils.split(value, " ")
local name = split[1]
local cmds = table.concat(split, " ", 2)
self:set(name, cmds)
logger.Cyan("Set rotation '" .. name .. "' to: \"" .. table.concat(self:get(name), "; ") .. '"')
elseif act == "get" then
logger.Cyan("Rotation for '" .. value .. "': \"" .. table.concat(self:get(value), ", ") .. '"')
elseif act == "switch" then
self:switch(value)
elseif act == "list" then
self:list()
elseif act == "help" or act == "h" then
self:help()
else
self:actDefault(value)
end
end
function Rot:list()
logger.Cyan("Available rotations:")
local max = 0
for name, cmds in pairs(self.data) do
if #name > max then
max = #name
end
end
max = max + 2
for name, cmds in pairs(self.data) do
logger.Normal(string.rpad(name .. ": ", max + 2) .. table.concat(cmds, "; "))
end
end
function Rot:help()
logger.Cyan("SpellRotation")
logger.Cyan("--------------------------------------------------------------")
logger.Cyan("kp [target] Execute current rotation")
logger.Cyan("kp [name] Switch to rotation [name] and execute")
logger.Cyan("ks get <name> Get rotation")
logger.Cyan("ks <name> <cmds> Set rotation")
logger.Cyan("ks switch <name> Switch to rotation")
logger.Cyan("ks list List all rotations and their commands")
-- logger.Cyan("kkp Execute rotation on SnD target, and")
-- logger.Cyan(" fill Command input with main rotation")
end
function OnPluginInstall()
Rot:init()
logger.Cyan("SpellRotation initialized")
end
]]></script>
<!-- Aliases -->
<aliases>
<alias
match="kp *"
enabled="y"
group="atk"
send_to="12"
sequence="101"
>
<send>Rot:actDefault("%1")</send>
</alias>
<alias
match="ks (.+)"
enabled="y"
regexp="y"
group="cmd"
send_to="12"
sequence="100"
>
<send>Rot:parse("%1")</send>
</alias>
<alias
match="kkp"
enabled="n"
group="atk"
send_to="12"
sequence="100"
>
<send><![CDATA[
SetCommandSelection(0, 2)
PasteCommand("kp")
Execute("kk;kp")
]]></send>
</alias>
<alias
match="kp"
enabled="y"
group="atk"
send_to="10"
sequence="100"
>
<send>kp -</send>
</alias>
</aliases>
<!-- Variables -->
<variables>
<variable name="rotData">{ main = { "attack" } }</variable>
</variables>
</muclient>

View File

@@ -2,8 +2,8 @@
<!DOCTYPE muclient>
<!-- MuClient version 5.07-pre -->
<!-- Author: Chen Asraf <contact@casraf.dev> (KumoGami) -->
<!-- Plugin "Spellbook" generated by Plugin Wizard -->
<!-- Source: https://github.com/chenasraf/aardwolf/tree/master/Spellbook -->
<!-- Plugin "Spellbook" generated by Plugin Wizard -->
<muclient>
<plugin
@@ -15,7 +15,7 @@
save_state="y"
date_written="2024-10-08 00:56:30"
requires="5.07"
version="1.31"
version="1.32"
>
</plugin>
@@ -49,16 +49,14 @@ utils.serialize = function (t)
return s .. "}"
end
Log = {}
logger = {}
local function withColor(color)
return function (text)
ColourNote(color, "", text)
end
end
Log.Cyan = withColor("cyan")
Log.Yellow = withColor("yellow")
logger.Cyan = withColor("cyan")
logger.Yellow = withColor("yellow")
-- funcs
@@ -129,7 +127,7 @@ function Spw.GenerateSpellWindow()
end
end
Log.Yellow("Output captured to window.")
logger.Yellow("Output captured to window.")
EnableTriggerGroup("spellbook", false)
end
@@ -153,45 +151,45 @@ end
function Spw.SpwCommand(main, args)
local function showHelp()
Log.Cyan("Spellbook window commands")
Log.Cyan("----------------------------------------------------------------")
Log.Cyan("spw enable - Enable spellbook")
Log.Cyan("spw disable - Disable spellbook")
Log.Cyan("spw hide <spell id> - Hide spell from spellbook")
Log.Cyan("spw unhide <spell id> - Unhide spell from spellbook")
Log.Cyan("spw hidden - List hidden spells")
Log.Cyan("spw prac - Display practice % mode")
Log.Cyan("spw prac one - Practice spell % once per click")
Log.Cyan("spw prac full - Practice spell % to full on click")
logger.Cyan("Spellbook window commands")
logger.Cyan("----------------------------------------------------------------")
logger.Cyan("spw enable - Enable spellbook")
logger.Cyan("spw disable - Disable spellbook")
logger.Cyan("spw hide <spell id> - Hide spell from spellbook")
logger.Cyan("spw unhide <spell id> - Unhide spell from spellbook")
logger.Cyan("spw hidden - List hidden spells")
logger.Cyan("spw prac - Display practice % mode")
logger.Cyan("spw prac one - Practice spell % once per click")
logger.Cyan("spw prac full - Practice spell % to full on click")
end
if main == 'disable' or main == 'off' then
SpWin:hide()
EnableAliasGroup("spellbook", false)
EnableTriggerGroup("spellbook", false)
Log.Yellow("Spellbook disabled.")
logger.Yellow("Spellbook disabled.")
elseif main == 'enable' or main == 'on' then
EnableAliasGroup("spellbook", true)
EnableTriggerGroup("spellbook", true)
Log.Yellow("Spellbook enabled.")
logger.Yellow("Spellbook enabled.")
elseif main == 'hide' then
local sp = args[2]
if not sp then
Log.Yellow("Usage: spw hide <spell id>")
logger.Yellow("Usage: spw hide <spell id>")
return
end
SpWinIgnore[sp] = true
SetVariable("SpWinIgnore", utils.serialize(SpWinIgnore))
Log.Yellow("Spell " .. sp .. " hidden.")
logger.Yellow("Spell " .. sp .. " hidden.")
elseif main == 'unhide' then
local sp = args[2]
if not sp then
Log.Yellow("Usage: spw unhide <spell id>")
logger.Yellow("Usage: spw unhide <spell id>")
return
end
SpWinIgnore[sp] = nil
SetVariable("SpWinIgnore", utils.serialize(SpWinIgnore))
Log.Yellow("Spell " .. sp .. " unhidden.")
logger.Yellow("Spell " .. sp .. " unhidden.")
elseif main == 'hidden' then
local hidden = ""
for sp, _ in pairs(SpWinIgnore) do
@@ -202,17 +200,17 @@ function Spw.SpwCommand(main, args)
else
hidden = hidden:sub(1, -3)
end
Log.Yellow("Hidden spells: " .. hidden)
logger.Yellow("Hidden spells: " .. hidden)
elseif main == 'prac' then
local mode = args[2]
if mode == 'one' then
SetVariable("SpWinPrac", "one")
Log.Yellow("Spellbook practice mode set to 'one'.")
logger.Yellow("Spellbook practice mode set to 'one'.")
elseif mode == 'full' then
SetVariable("SpWinPrac", "full")
Log.Yellow("Spellbook practice mode set to 'full'.")
logger.Yellow("Spellbook practice mode set to 'full'.")
else
Log.Yellow("Spellbook practice mode is currently set to " .. GetVariable("SpWinPrac") .. ".")
logger.Yellow("Spellbook practice mode is currently set to " .. GetVariable("SpWinPrac") .. ".")
end
else
showHelp()