Making macros -- Accelerator(To)

Posted by Chico on Sat 24 Apr 2010 01:30 AM — 18 posts, 78,236 views.

USA #0
Hello there, having some issues with a script to make macros easily from command line.

I match on #macro {*} {*}, and it works fine using:

string.gsub("%2", "+", "_")
macro_key=%1
macro_value=%2
AddAlias(macro_key, macro_key, macro_value, alias_flag.Enabled + alias_flag.OmitFromLog + alias_flag.OmitFromOutput, "");
AcceleratorTo(macro_key, macro_value, 10)
ColourNote("red", "white", "".. macro_key .." now executes ".. macro_value ..".")


The only issue i get is when i want to include a variable in the macro, such as

#macro {alt+f} {c @heal}


Any help is appreciated ;)
Australia Forum Administrator #1
Add the alias_flag.ExpandVariables flag to the list of flags.
USA #2
Hmm, thought i tried that. I'll give it a shot real-quick.
USA #3
Ok, so i got it to work .. kind of.

I found out that no matter how i do it, even if i set up
the alias manually for the macro, it won't call the variable when i include @<variable_name>(bug?), but i managed to work around it. By just doing, for example:


#macro {alt+f} {/Send("c ".. GetVariable("heal")


And I'm fine with that. The new issue is how would i go about making a permanent list of the variables i set up doing this, in combination with the script i wrote to do #alias {foo} {bar}, in plugin form. I know that to update the variables i need to do:


function OnPluginClose()
 SetVariable("var1", var1)
 SetVariable("var2", var2)
 --etc..
end


I just need to know how I'd go about getting said variables.
I'm assuming i'd need to do something along the lines of


for i,v in ..--[[this is where the issue lies.
I have no idea how to work with lists in conjunction
with the for statement, or lists in general for that
matter.]]---


Would appreciate an example code snippet of how i would do this.

Thanks,
Chico
Amended on Wed 28 Apr 2010 01:56 AM by Chicomecoatl
Australia Forum Administrator #4
I'm not sure here if you are trying to shoe-horn the way things are done in tintin to MUSHclient. For a partial solution see:

Template:faq=39
Please read the MUSHclient FAQ - point 39.


Aliases really are intended to react to something you type (not to keystrokes per se).

Making an alias to add aliases seems to me to be a roundabout way of doing things, when you can just invoke the alias configuration and type in directly into the GUI what you want to have happen when you type something.

Aliases are automatically saved to the world file, once created. However the accelerator changes (keystrokes) are not. The FAQ item I pointed to above shows a simple way of making the accelerators load up every time.
USA #5
Right, i see how that is done. I was somewhat doing the same thing.

I like doing alot of my stuff from the command line, so i was looking how i would add macro's to that list. Short of opening the script each time i want to add a macro, saveing it, and them reloading the program, how would i make the list grow.

I'm a big fan of the #macro {foo} {bar} method, as i've used tintin for the better part of my mudding career. Essentially all i need is an alias to add the macros, but i don't comprehend how i would make it add the macro to the plugin listed in your previous post, so that the macro list will remain upon each loading of mushclient.

The only reason i need the macros to change and update is because i change macros frequently. And add them as i see fit.

In tintin i had 40+ macros rangeing from(this is in lua form):


#macro {alt+m} {/Execute("b "..GetVariable("roommob")}


to


#macro {alt+f} {/Execute("c "..GetVariable("heal")}
#macro {alt+.} {/Execute("mana")


And such. Most of my levelling is done by macros, one to heal, one for moves, one for mana, one to kill any mob with same keyword, one for area attacks, pk macros. I love the seperate windows of mush, i just prefer the macro style of tintin, so i was looking to combine the two to make a client that is the best of both worlds for me.
Amended on Wed 28 Apr 2010 05:11 PM by Chicomecoatl
USA #6
So far i have this, which is derived from the accelerator script that you posted above.

If you could show me how to add the accelerator to a list, where the comment is about adding to lists in the AddMacro function, that would solve my problems.


<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<muclient>
<plugin
   name="Accelerators"
   author="Nick Gammon"
   id="bcd4c85623b51c11ec643123"
   language="Lua"
   purpose="Add custom keystrokes"
   date_written="2007-04-17 16:16:25"
   requires="3.80"
   version="1.0"
   >
</plugin>
<aliases>
	<alias
	enabled="y"
	name="macro_adder"
	match="#macro {*} {*}"
	script="AddMacro"
	sequence="y"
	</alias>
</aliases>
<script>
<![CDATA[
function OnPluginInstall ()
	for i, v in ipairs (AcceleratorList ()) do
		Accelerator ("i", "v")
end -- function OnPluginInstall

function AddMacro(name, line, wildcards)
	Accelerator("wildcards[1]", wildcards[2])
	--Add accelerator to AcceleratorList
end -- function AddMacro
]]>
</script>
</muclient>
Amended on Wed 28 Apr 2010 05:20 PM by Chicomecoatl
Australia Forum Administrator #7
OK, I think this will work:

Template:saveplugin=Tintin_Macro_Adder
To save and install the Tintin_Macro_Adder plugin do this:
  1. Copy the code below (in the code box) to the Clipboard
  2. Open a text editor (such as Notepad) and paste the plugin code into it
  3. Save to disk on your PC, preferably in your plugins directory, as Tintin_Macro_Adder.xml
    • The "plugins" directory is usually under the "worlds" directory inside where you installed MUSHclient.
  4. Go to the MUSHclient File menu -> Plugins
  5. Click "Add"
  6. Choose the file Tintin_Macro_Adder.xml (which you just saved in step 3) as a plugin
  7. Click "Close"
  8. Save your world file, so that the plugin loads next time you open it.


[EDIT]: Amended to fix problem with FixVariables not being in the script space.


<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<!-- Saved on Thursday, April 29, 2010, 7:28 AM -->
<!-- MuClient version 4.51 -->

<!-- Plugin "Tintin_Macro_Adder" generated by Plugin Wizard -->

<muclient>
<plugin
   name="Tintin_Macro_Adder"
   author="Nick Gammon"
   id="3c626e5d9343e81ef69d9f93"
   language="Lua"
   purpose="Lets you add macro keys"
   save_state="y"
   date_written="2010-04-29 12:55"
   requires="4.50"
   version="1.1"
   >
<description trim="y">
<![CDATA[
Type: #macro {key} {action}

eg.  #macro {alt+f} {cast @heal}

Variables can be included in the actions and will be expanded when the key is hit.

Macros are saved for next time.

Type: '#macrolist' for a list of macros.

Type "Tintin_Macro_Adder:help" for this help.

]]>
</description>

</plugin>


<!--  Aliases  -->

<aliases>
  <alias
   match="#macro {*} {*}"
   enabled="y"
   sequence="100"
   script="AddMacro"
  >
  </alias>

  <alias
   script="MacroList"
   match="#macrolist"
   enabled="y"
   sequence="100"
  >
  </alias>
  
 <alias
   script="Execute_Macro"
   match="#execute_macro: *"
   enabled="y"
   send_to="12"
   omit_from_output="y"
   omit_from_command_history="y"
   sequence="100"
  >
  </alias>

</aliases>


<!--  Script  -->


<script>
<![CDATA[

require "serialize"

macros = {} -- in case none exist yet

function FixVariables (what)

 
  local errors =  {} -- no errors yet
  
  -- function to do the replacements for string.gsub
  
  local function replace_variables (s)
    s = string.sub (s, 2)  -- remove the @
    replacement = GetPluginVariable ("", s)    -- look up variable in global script space
    if not replacement then  -- not there, add to errors list
      table.insert (errors, s)
      return
    end -- not there
    return replacement  -- return variable
  end -- replace_variables 
  
  -- replace all variables starting with @
  
  command = string.gsub (what, "@%a[%w_]*", replace_variables)
  
  -- report any errors
  
  if table.getn (errors) > 0 then
    for k, v in ipairs (errors) do
      ColourNote ("white", "red", "Variable '" .. v .. "' does not exist")
    end -- for
    return
  end -- error in replacing

  Execute (command)

end -- function FixVariables

function AddMacro (name, line, wildcards)
  
  macro_key = wildcards [1]
  what_do_do = wildcards [2]
  Accelerator (macro_key , "#execute_macro: " .. what_do_do)
  
  ColourNote ("red", "white", macro_key  .." now executes: ".. what_do_do)

end -- function AddMacro

function OnPluginInstall ()
  assert (loadstring (GetVariable ("macros") or "")) ()

  -- add the accelerator keys back
  for _, k in ipairs (macros) do
    local key, action = string.match (k, "^(%w+%+%w+) = (.*)$")
    if key then
       Accelerator (key, action)
    end -- if
  
  end -- for loop
  
end -- OnPluginInstall

function OnPluginSaveState ()
  macros = AcceleratorList () or {}
  SetVariable ("macros", "macros = " .. serialize.save_simple (macros))
end -- function OnPluginSaveState

function MacroList (name, line, wildcards)
  macros = AcceleratorList () or {}

  table.sort (macros)
  
  for _, k in ipairs (macros) do
    local key, action = string.match (k, "^(%w+%+%w+) = (.*)$")
    if key then
       AcceleratorTo (key, action, sendto)
       action = string.match (action, '^#execute_macro: (.*)$')
       print (key, '=', action)
    end -- if
  
  end -- for loop

end -- function MacroList

function Execute_Macro (name, line, wildcards)
  FixVariables (wildcards [1])
end -- function Execute_Macro

]]>
</script>


<!--  Plugin help  -->

<aliases>
  <alias
   script="OnHelp"
   match="Tintin_Macro_Adder:help"
   enabled="y"
  >
  </alias>
</aliases>

<script>
<![CDATA[
function OnHelp ()
  world.Note (world.GetPluginInfo (world.GetPluginID (), 3))
end
]]>
</script> 

</muclient>


This skips the creation of aliases altogether.

For example:


#macro {ctrl+g} {kick @target}


It replies:


ctrl+g now executes: kick @target


Now if 'target' variable is not defined, and you type ctrl+g you see:


Variable 'target' does not exist


However if it *does* exist you see:


kick naga   (or whatever)


You can list your macros:


#macrolist

Alt+F = c @heal
Ctrl+G = kick @target
Ctrl+I = sigh


The existing macros are saved to the plugin state file, eg.


<variable name="macros">macros = {
  [1] = "Ctrl+G = #execute_macro: kick @target",
  [2] = "Ctrl+I = #execute_macro: sigh",
  [3] = "Alt+F = #execute_macro: c @heal",
  }</variable>


This is done in the OnPluginSaveState function, and they are loaded back in when the plugin is installed.

The macros are send an alias (#execute_macro) with the rest of the line after it. This alias calls the FixVariables function to replace the @variable sequence at the time you hit the accelerator.
Amended on Thu 29 Apr 2010 03:19 AM by Nick Gammon
USA #8
Perfect, thanks
USA #9
Woops, spoke too soon.


Run-time error
World: Aardwolf
Immediate execution
[string "Accelerator: Alt+F"]:1: attempt to call global 'FixVariables' (a nil value)
stack traceback:
        [string "Accelerator: Alt+F"]:1: in main chunk
Australia Forum Administrator #10
Oh, oops. I had that function in the main script space as well as the plugin when I was testing.

Hmmm, let me try a slightly different way of doing it - I'll get back to you soon.
Australia Forum Administrator #11
OK I fixed it up. I think it is OK now. I changed from sending to script to calling an alias (#execute_macro) which then switches back to the plugin script space. However that required another change as the GetVariable became GetPluginVariable, as I presume the variables to be substituted come from the main script space, not the plugin script space.
USA #12
I was under the impression that Accelerators were changed a while back to be executed within the context of the creating world/plugin, rather than always in the world. Is that not the case? Or is there another issue I've completely missed?
Amended on Thu 29 Apr 2010 03:17 AM by Twisol
Australia Forum Administrator #13
I can't find that in the release notes, and in any case if you do this:


/tprint (AcceleratorList ())


... it doesn't indicate any knowledge of what plugin the accelerator belongs to.
USA #14
I found what I was thinking of.

http://www.gammon.com.au/forum/bbshowpost.php?bbsubject_id=9757
Australia Forum Administrator #15
Ah. I see it was just a planned enhancement that somehow got lost in the recesses of my brain. ;)

I wonder if, if accelerators were to become bound to the plugin in which they were added, if that would cause backward compatibility problems?

I can see how it would fix the problem in this particular thread.
USA #16
It's possible, but I don't think it's likely. There's nothing desirable about executing plugin code within the world - especially dependent on user action - and it's also terribly confusing to see within the code.


If backwards compatibility is an issue - and it should be! - is there any chance we can start noting down these useful, desirable breaking changes, and start a new git branch for MUSHclient 5.0? After so many years of incremental, backwards-compatible development, I'm sure a lot of cruft builds up. I certainly wouldn't mind contributing.
Amended on Thu 29 Apr 2010 08:31 AM by Twisol
USA #17
Excellent Nick!

Thanks for the help, much appreciated!