Sample plugin

Posted by Nick Gammon on Wed 05 Jun 2002 04:43 AM — 1 posts, 5,625 views.

Australia Forum Administrator #0
For the interest of people who have been following the "plugins" debate, here is a sample plugin, which I have been using to test the plugins idea. It is a variation of the "random socials" script.

It illustrates a few useful points:

  • Triggers
  • Aliases
  • Timers
  • Help text (plugin description)
  • Customisation (by using entities near the start)
  • Interaction between the plugin and the user - in this case, by allowing them to remove socials from the list.
  • Scripts
  • Saving state


The scripts in this example are done in pieces, one for each trigger/alias/timer. MUSHclient will concatenate them all together to make one script file internally, but putting each script sub under its appropriate trigger (etc.) seems to me to make the layout easier to follow.

"Saving state" refers to the fact that the plugin will automatically save its variables to disk when the world is closed, so that next time the same list of socials will be available. You could use a similar idea to keep track of potions, spells etc.




<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE muclient [
  <!ENTITY socials_command "socials" > 
  <!ENTITY end_socials_regexp "&lt;" > 
  <!ENTITY timer_interval "10" > 
]>


<!--

Customising (change above entities) ...

Change "socials_command" to whatever sends a list of socials.
  Default: socials
  
Change "end_socials_regexp" to whatever will *not* be in a socials line.
  Default: <
 
Change "timer_interval" to be the number of seconds between checking for socials.
	Default: 10 seconds
	
(Note - every "timer_interval" seconds there is a 20% chance that the social will be sent.)
  
-->

<muclient>
<plugin name="Random_Socials"
  author="Nick Gammon"
  language="vbscript"
  id = "982581e59ab42844527eec80"
  purpose = "Displays a random social from time to time"
  save_state = "y"
  >
<description trim="y">
<![CDATA[

This plugin checks to see if it has a list of socials (in the "socials" variable).

If not, it sends "socials" to the MUD to build a list.

Then, every 10 seconds it has a 20% chance of displaying one picked at random.

Commands
--------

socials:help       - shows this description in the output window
socials:remove:all - removes all socials (ie. reloads the list)
socials:remove X   - removes social X from the list (eg. social:remove burp)
]]>            
</description>
</plugin>

<!--  =============================================

Sub "SocialsList" - collects a list of socials.

 =============================================  -->

<script>
<![CDATA[
dim SocialsList  ' store list of socials

Randomize  ' Initialize random-number generator.

sub GetSocials
  world.setvariable "socials", ""
  world.enabletrigger "Collect_Socials", 1
  '
  '  cancel CDATA so we can use the entity (from DOCTYPE header)
  '
]]>            
  world.send "&socials_command;"
<![CDATA[
  world.note "Collecting list of socials ..."
end sub

]]>            
 </script>
 
<!--  =============================================

Timer:   RandomSocial
Script:  DoRandomSocial
Purpose: Chooses a social at random, builds the list if necessary

 =============================================  -->
 
<timers>
  <timer name="RandomSocial" script="DoRandomSocial" enabled="y" second="&timer_interval;" >
  </timer>
</timers>
<script>
<![CDATA[
Sub DoRandomSocial (strTimerName)

'
'  Wait a minute after connecting to let them put in the character name and password
' 

  If DateDiff ("n", World.GetInfo (301), Now) < 1 Then
    Exit Sub
  End If
  
'
' If collecting socials, list, just wait for it to finish
'

   If World.GetTriggerInfo ("Collect_Socials", 8) then
      Exit Sub
   End If

'
' If no socials list, get one
'

  If IsEmpty (SocialsList) Then
     If world.getvariable ("socials") = "" Then
       Call GetSocials
     Else  
       SocialsList = split (world.getvariable ("socials"))
     End If
     Exit Sub
  End If

'
'  Do a random social
'

   If Rnd < 0.2 Then
      World.Send SocialsList ( Rnd * Ubound (SocialsList))
   End If

End Sub
]]>            
 </script>

<!--  =============================================

Trigger:  Collect_Socials
Script:   Do_Collect_Socials
Purpose:  Matches a line of socials

 =============================================  -->
 
<triggers>
  <trigger
   custom_colour="2"
   match="^[A-Za-z ]+$"
   name="Collect_Socials"
   regexp="y"
   script="Do_Collect_Socials"
   sequence="100"
  >
  </trigger>
</triggers>

<script>
<![CDATA[
sub Do_Collect_Socials (sName, sLine, wildcards)
  world.enabletrigger "End_Socials", 1
  sLine = Trim (sLine)
  while Instr (sLine, "  ") > 0
    sLine = world.Replace (sLine, "  ", " ", 1)
  wend
  world.setvariable "socials", _
    world.getvariable ("socials") & " " & sLine
end sub

]]>            
 </script>

<!--  =============================================

Trigger:  End_Socials
Script:   Do_End_Socials
Purpose:  Detects end of socials list - in this case we look for the < at the
          start of a MUD prompt, but you could look for anything that wouldn't be
          a social line.

 =============================================  -->

<triggers>
  <trigger
   custom_colour="1"
   match="&end_socials_regexp;"
   name="End_Socials"
   regexp="y"
   script="Do_End_Socials"
   sequence="100"
  >
  </trigger>
</triggers>
<script>
<![CDATA[

sub Do_End_Socials (sName, sLine, wildcards)
  world.note "End of socials list"
  world.enabletrigger "Collect_Socials", 0
  world.enabletrigger "End_Socials", 0

  SocialsList = split (world.getvariable ("socials"))

end sub

]]>            
 </script>

<!--  =============================================

Trigger:  Remove_Social
Script:   Do_Remove_Social
Purpose:  Removes a social from the list (eg. it might be inappropriate)

 =============================================  -->

<aliases>
  <alias
   name="Remove_Social"
   script="Do_Remove_Social"
   match="^socials\:remove ([A-Za-z]+)$"
   enabled="y"
   regexp="y"
  >
  </alias>
</aliases>

<script>
<![CDATA[

sub Do_Remove_Social (sName, sLine, wildcards)

If not Instr (world.GetVariable ("socials") & " ",  wildcards (1) & " ") > 0 then
  world.note "Social " & wildcards (1) & " was not in the list."
  Exit Sub
End If

'
'  Remove the specified social from the list
'
 world.SetVariable "socials", _
   Trim (world.Replace (world.GetVariable ("socials") & " ", _
                  wildcards (1) & " ", "", 1))
 
world.note "Removed social " & wildcards (1) & " from the list."
                  
'
'  Regenerate the list
'                  

  SocialsList = split (world.getvariable ("socials"))

end sub

]]>            
 </script>
 
<!--  =============================================

Trigger:  Remove_All_Socials"
Script:   Do_Remove_All_Socials
Purpose:  Removes all socials (ie. forces list to be regenerated)

 =============================================  -->

<aliases>
  <alias
   name="Remove_All_Socials"
   script="Do_Remove_All_Socials"
   match="socials:remove:all"
   enabled="y"
  >
  </alias>
</aliases>

<script>
<![CDATA[

sub Do_Remove_All_Socials (sName, sLine, wildcards)

  World.SetVariable "socials", ""
  SocialsList = Empty
  World.Note "All socials removed from list."
  
end sub

]]>            
 </script> 


<!--  =============================================

Alias:   socials:help
Script:  OnHelp
Purpose: Shows plugin help

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

<script>
<![CDATA[
 sub OnHelp (sName, sLine, wildcards)
   world.note world.getplugininfo (world.getpluginid, 3)
 end sub
]]>            
 </script> 
 
 </muclient>




The sequence <![CDATA[ ... ]]> is used a bit in this plugin. This is a standard XML construct that allows you to imbed "literal" data into an XML file without having to worry about representing "<" as "&lt;", "&" as "&amp;" and so on. The only restriction is that the exact sequence "]]>" may not occur inside the sequence (obviously), however it would be a rare piece of code that needed that, and in any case, you could always work around it by adding a space here and there (eg. "] ] >")