MXP Sound problems.

Posted by Johnathan Allen on Mon 08 Sep 2003 09:36 AM — 28 posts, 93,005 views.

#0
Hello, I'm trying to get sounds to work with my client, I have the plugin installed, and the sounds installed, and the plugin pointing to the proper location, but I don't think that Mushclient is reading the tag properly. In the MXP debug window, I get:


A 20000: (  239) MXP element: <sound FName="mm_door_open.*" V=100 L=1 P=50 T="misc">
W  5012: (  239) MXP tag <sound> is not implemented
W  5015: (  239) Unused argument for <sound>: fname="mm_door_open.*"
W  5015: (  239) Unused argument for <sound>: v="100"
W  5015: (  239) Unused argument for <sound>: l="1"
W  5015: (  239) Unused argument for <sound>: p="50"
W  5015: (  239) Unused argument for <sound>: t="misc"


I'm not sure whats wrong, can you help me out?
#1
Is there a way to manually define mxp elements on the client side?
Australia Forum Administrator #2
Yes, you can do this. You need to add a script routine to your world script file, here is an example:


function OnMXPStartTag (name, args, mylist)

  dim i
  dim fn
  dim arg

'
'  only proces sound tags
'

  if name <> "sound" then 
    exit function
  end if

'
'  find the sound file name
'

  if not IsEmpty (mylist) then
    for i = lbound (mylist) to ubound (mylist)
      arg = split (mylist (i), "=")
      if arg (0) = "fname" then
        fn = arg (1)
      end if
    next
  End If

'
'  play sound
'

  if fn <> "" then
    fn = Replace (fn, "*", "wav")
    Sound "c:\mysounds" & fn
  end if

  ' suppress sound tags (handle them ourselves)	

  OnMXPStartTag = 1

end function



What you will then need to do is add "OnMXPStartTag" as the "Opening Tag" script file in the scripting configuration page (click the "MXP" button).

What is happening here is that when MUSHclient gets the MXP start tag "sound" it calls the script. The script gets passed all the sound arguments (FName="mm_door_open.*" V=100 L=1 P=50 T="misc") in an array.

It walks the array looking for the "FName" argument and then saves the filename.

Then it uses the "Sound" script command to play that sound.

In your example it cannot play the sound "mm_door_open.*" so I have replaced the "*" with "wav".

You may also need change the directory where it is looking for the sounds. I used "c:\mysounds".

Finally this line stops the line from being processed by MUSHclient and thus giving an error message:


OnMXPStartTag = 1
#3
Thanks Nick. :)
#4
Umm. I'm trying to wrap this all into a plugin, but the OnMXPStartTag isn't calling the plugin, it only works if I insert the code into my main script. Can you address the tag to a plugin?
Amended on Mon 15 Sep 2003 12:28 AM by Johnathan Allen
#5
Okay, let me elaborate on what I'm doing...

This is my plugin.

Quote:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE muclient>
<!-- Saved on Friday, September 12, 2003, 12:23 AM -->
<!-- MuClient version 3.24 -->

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

<muclient>
<plugin
name="MM_MSP_Emulation"
author="Nick Gammon with alterations by ****** for use with MateriaMagica IEN"
id="74c06c730af9e17ac98dc126"
language="VBscript"
purpose="Emulates MSP (MUD Sound Protocol) on MateriaMagica"
save_state="y"
date_written="2003-09-11 12:12:11"
requires="3.24"
version="1.0"
>
<description trim="y">
<![CDATA[
Type: "msp:help" to see this help.

See:

You will need to get the sound files manually (ie. from the
MUD) and install them before using this. The plugin is
configured to look for them in C:\Program Files\MUSHclient\msp,
but you can change that by typing:

set_msp_path new_path

eg.

set_msp_path C:\Program Files\MUSHclient\msp

This does require sound to be enabled, so type:

set sound on

Also, this requires you to manually set a few things.

Set MXP/Pueblo on, follow these steps:

1.) Press Ctrl+Alt+U, or use Game -> Configure -> MXP / Pueblo
2.) Set "Use MXP/Pueblo to "On Command"
3.) Uncheck all other options.

Now we need to add something to the scripting interface.
1.) Press Shift+Ctrl+6 or use Game -> Configure -> Scripting
2.) Press the MXP button
3.) In the Opening Tag box, insert "OnMXPStartTag", without the quotes.

And finally, you need to specify either .wav files, or .mp3 files,
type:

set_msp_type (file type)

eg.

set_msp_type wav
or
set_msp_type mp3

Any questions, feel free to contact ******* in game.

]]>
</description>

</plugin>


<!-- Get our standard constants -->

<include name="constants.vbs"/>

<!-- Aliases -->

<aliases>
<alias
script="On_set_MSP_path"
match="set_msp_path *"
enabled="y"
>
</alias>
<alias
script="On_set_MSP_type"
match="set_msp_type *"
enabled="y"
>
</alias>
</aliases>

<!-- Variables -->

<variables>
<variable name="msp_path">C:\Program Files\MUSHclient\msp</variable>
</variables>

<!-- Script -->


<script>
<![CDATA[
'
' Script to emulate MSP on MateriaMagica.
'

Sub On_set_MSP_type (strName, strLine, arrWildCards)

dim sType

sType = arrWildCards (1)

'
' ensure either "wav" or "mp3" was specified
'


Select Case sType
Case "wav"
world.setvariable "msp_type", sType
world.note "MSP will now use the .wav extension"
Case "mp3"
world.setvariable "msp_type", sType
world.note "MSP will now use the .mp3 extension"
Case Else
World.Note "You must specify either 'wav' or 'mp3' for sound file extension."
End Select

End Sub


sub On_set_MSP_path (strName, strLine, aryWildcards)

dim sPath

sPath = aryWildcards (1)

'
' ensure trailing backslash
'

if right (sPath, 1) <> "\" then
sPath = sPath & "\"
end if

world.setvariable "msp_path", sPath
world.note "MSP sound files will be obtained from " & _
sPath

end sub



Function OnMXPStartTag (name, args, mylist)

dim i
dim fn
dim arg

'
' only process sound tags
'

if name <> "sound" then
exit function
end if

'
' find the sound file name
'

if not IsEmpty (mylist) then
for i = lbound (mylist) to ubound (mylist)
arg = split (mylist (i), "=")
if arg (0) = "fname" then
fn = arg (1)
end if
next
End If

'
' play sound
'

if fn <> "" then
fn = Replace (fn, "*", world.getvariable ("msp_type"))
world.Sound msp_Path & fn
end if

' suppress sound tags (handle them ourselves)

OnMXPStartTag = 1

end function


]]>
</script>


<!-- Plugin help -->

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

<script>
<![CDATA[
Sub OnHelp (sName, sLine, wildcards)
World.Note World.GetPluginInfo (World.GetPluginID, 3)
End Sub
]]>
</script>

</muclient>


I'm trying to make a portable plugin for sounds with my mud. The only things that are hanging me up are the (on_mxp_open_tag="OnMXPStartTag" ), since I can't think of a way to automate that refrence to be installed into the world file (found under " <world " in the .mcl file, and the plugin doesn't work because theres no connection between "OnMXPStartTag" and the plugin. The script itself works fine if I add all the aliases and stuff to the regular world alias/trigger/script, but not as an independent standalone plugin.

I thought about adding a OnMXPStartTag sub and refrencing it to the plugin, but that kind of negates the portablility and automatic installation. Again, I'm shooting for ease of use and portablility, since this is going to be availible for download from the mud's web page. Is there an easy way to point OnMXPStartTag to the plugin?

USA #6
The problem here is basically the same as why there is a CallPlugin command, instead of a way to directly call a sub in a plugin script. I think it is a serious flaw and has made numerous plugin desigs impossible. I am not sure of the precise reason for it, but it mostly comes down to mushclient not knowing before hand what subs to expect in a script. Since the main script executes in a global namespace, the client can make direct calls too it, but plugins each exist in a seperate thread of something, in order to prevent conflicts with variables and things of that sort. MXP subs can't call using a plugin ID, so they have no way to know 'where' to look for the block of code that needs to be executed, even if they do have a name to look for.

There has got to be a better way imho. Being able to tell the world file the ID of a plugin to execute MXP stuff would help, with a blank ID defaulting to the main world, but calling plugins is still a pain. It would have been much better imho to do this:

set Handle = GetPluginHandle(BSTR Plugin ID)
Handle.SomeSubName(Arguement1, Arguement2, ...)

The method used now is inconvenient and requires complicated code to be added into one special sub, where everything has to be broken up and passed on to what you intended to call in the first place. This is not only unecessarily complicated, but confusing from the stand point of trying to call anything in a plugin. Especially since it doesn't even reflect the standard way that all other objects, commands and code is used for anything else in a script.

In theory.. If you get a world handle, so that you are executing global calls with it, instead of plugin calls, you might be able to set the names used for the scripts, then use ImportXML to 'import' the blocks of code containing those into the main world. They could either perform the actual commands or use CallPlugin to pass the needed information to your plugin and have that do the job. This is 'theory' though, I don't know if creating a handle to mushclient in the script will actually give you direct control over the main world, or if you would just be giving your script a roundabout way to talk to itself. lol

Hmm. Thinking on it, I am not sure it is even possible. Maybe if you used python and a Mushclient 'wrapper' to give the script information on the internals, but you would need to do something like this in VBScript:

a = getworldid(worldname)
dim b as object 'Create a generic object type.
'???? b = a ???? I have no idea what is needed here to have it work...,
'but you have to make the generic object 'become' your world some how.
b.inportXML("Your code here")

In Python, *with the wrapper*, it would be much easier, but it is still rediculous to have to do this sort of thing imho. Someone that understood COM better and had a lot more patience than me could probably make it work, but not me.

There is another alternative though. It would be reading the world file itself in to your script, checking to see if the code is there already and if not, then writing the entire file back in, including the code you needed to add. This is dangerous, nearly as complicated and still quite insane to have to do. :p
#7
It'd be nice if we can do custom distributions. I've sort of solved it by making a .mcl file and a vb script file for download. But a whole custom distribution would be pretty nice. It'd allow me to make all the appropriate settings availible for users.
USA #8
Well, hopefully Nick will find a way to use the plugins like objects, instead of the currect insane way. That would help some.

The second things is some means to import XML permanently into the world file and save it, or even a direct way to respond to MXP stuff in plugins, either one of which would solve your problem. It gets frustrating when such basic things require either a very unfriendly non-distributable solution or wrapping your mind around some convaluted and insane solution like the one I suggested, which would probably never work anyway....

Feels like traversing a bloody mazer without a flashlight sometimes. lol

So Nick.. Why is it exactly that plugins can't use the Object.Command method for calling plugins, aside from you not implimenting such? It seems to me to be far more consistent, considering what we try and would like to do with them. Even scripts calling other 'external' scripts would use this method, but not being able to use it 'in' a script running within Mushclient. :p
USA #9
Hmm.. Here is an idea though Johnathan. Under the file menu is an option for 'Import'. You may be able to create an mcl file that only has the options you specifically need and possibly some script code (or an 'include' directive that imports the needed scripts). It isn't elegant, but if the importer doesn't complain about things that are missing from the file (i.e. you left out to prevent it from overriding the settings), it 'may' work. It isn't A) safe or B) the best solution, but it may actually work.
#10
Nothing there for code... :(
Australia Forum Administrator #11
I can probably make without too much trouble it be possible to have MXP callbacks work in plugins. That would solve your problem I think.
#12
That would be awesome Nick. :)
Australia Forum Administrator #13
Well, I didn't know that. :) It seems I already have done it. The following pre-coded names are available as plugin callbacks:


OnPluginMXPstart
OnPluginMXPstop
OnPluginMXPopenTag
OnPluginMXPcloseTag
OnPluginMXPsetVariable
OnPluginMXPerror




OnPluginMXPopenTag

It seems that in the case of OnPluginMXPopenTag it the callback expects a single argument in the form:

name,arguments

In other words, you would get something like this:

sound,FName="mm_door_open.*" V=100 L=1 P=50 T="misc"

Thus you could use Split to break up the line into "sound" and the arguments, and then proceed much the same as before.


OnPluginMXPcloseTag

Just to complete the documentation, in the case of OnPluginMXPcloseTag you get the tag name followed by the text of the tag. eg.

<b>Hi there</b>

In this case the close tag for "b" would have as its argument:

b,Hi there


OnPluginMXPsetVariable

For OnPluginMXPsetVariable the argument is variable name=value, eg.

RoomName=Red Square


OnPluginMXPerror

For OnPluginMXPerror the argument is:

level,number,line_number,message

eg.

I,10008,417,MXP mode change from 'open' to 'permanently secure'




#14
Can you think of a way to insert the OnPluginMXPopenTag call with the OnPluginInstall function?
Australia Forum Administrator #15
You don't insert it, you just do it. That is, replace this:

Function OnMXPStartTag (name, args, mylist)

dim i
dim fn
dim arg


' ---- blah blah

End Function


with this:

Function OnPluginMXPopenTag (args)

dim i
dim fn
dim arg


' ---- blah blah

End Function



However the function will need to be rejigged slightly because all the information is in the single argument, as I described earlier.
#16
I don't need to put OnPluginMXPopenTag in the MXP script routines under the scripting configuration page?
#17
Apparently, I don't. This is awesome. Now to fiddle with the script. So far, I have this:


Function OnPluginMXPopenTag (strArgs)
 Dim fn
 Dim mylist 
 Dim arrType
dim i
dim arg

mylist = Cstr(strArgs)

arrType = Split(mylist, ",", -1, 1)


if arrType(0) <> "sound" then 
exit function
end if

mylist = arrType (1)


 arg = split (mylist, "=", -1)
   fn = arg (1)

fn = Replace(fn, "' v", "")
fn = Replace(fn, "'", "")

 
 msp_path = world.GetVariable ("msp_path")
 msp_type = world.GetVariable ("msp_type")
 

 
   if fn <> "" then
     fn = Replace (fn, "*", world.getvariable ("msp_type"))
     world.Sound msp_path & fn
  end if
 
 
OnPluginMXPopenTag = 1
 
End Function


It's pretty sloppy, but its 3 am here :P

I'd like to get rid of some variables. The first split is to get rid of the 'sound' precurser, the second split is to isolate the filename, but I kept getting something along the lines of:

'mm_sound1.*' v


..So, I had to do two replaces to get rid of the "'" and the "' v". I'm not sure of a better way to do that.

So, if you have a better suggestion, feel free. I'll be burning the midnight oil over here.
Australia Forum Administrator #18
Yes, you don't need anything in the scripting configuration window.

Now for the other problem. The arguments are:

FName="mm_door_open.*" V=100 L=1 P=50 T="misc"

So, the first split could be on a space, to get the individual arguments (eg. filename, V , L, P , T)

Then, after splitting that one you have "FName="mm_door_open.*"" which you can then split at the "=".
#19
Anything for plugins (or regular scripts) for mxp definitions?

From the MXP Debug screen:


I 20002: ( 3623) Got Definition: !en MaxHp  3495
I 20002: ( 3623) Got Definition: !en MaxSp  1992
I 20002: ( 3623) Got Definition: !en MaxSt  2138


What I'm trying to do is adapt the super health bar plugin to my mud, but again, things are being done differently. I'm trying to extract the variables and entities from my prompt, but its kinda funky:


.[6z...[1;34m<Mo   1b 5b 36 7a 0a 0d 1b 5b 31 3b 33 34 6d 3c 4d 6f
unt:.[0m .[0m249   75 6e 74 3a 1b 5b 30 6d 20 1b 5b 30 6d 32 34 39
3.[1;34mst>.[0m.   33 1b 5b 31 3b 33 34 6d 73 74 3e 1b 5b 30 6d 0a
..[1;37m[SAFE].[   0d 1b 5b 31 3b 33 37 6d 5b 53 41 46 45 5d 1b 5b
0m.[1;34m&lt;.[0   30 6d 1b 5b 31 3b 33 34 6d 26 6c 74 3b 1b 5b 30
m<V Hp>3495</V><   6d 3c 56 20 48 70 3e 33 34 39 35 3c 2f 56 3e 3c
!EN MaxHp 3495>.   21 45 4e 20 4d 61 78 48 70 20 33 34 39 35 3e 1b
[1;34mhp .[0m<V    5b 31 3b 33 34 6d 68 70 20 1b 5b 30 6d 3c 56 20
Sp>1992</V><!EN    53 70 3e 31 39 39 32 3c 2f 56 3e 3c 21 45 4e 20
MaxSp 1992>.[1;3   4d 61 78 53 70 20 31 39 39 32 3e 1b 5b 31 3b 33
4msp .[0m<V St>2   34 6d 73 70 20 1b 5b 30 6d 3c 56 20 53 74 3e 32
138</V><!EN MaxS   31 33 38 3c 2f 56 3e 3c 21 45 4e 20 4d 61 78 53
t 2138>.[1;34mst   74 20 32 31 33 38 3e 1b 5b 31 3b 33 34 6d 73 74
&gt;.[0m .[3z.[7   26 67 74 3b 1b 5b 30 6d 20 1b 5b 33 7a 1b 5b 37
z                  7a


And, it doesn't seem OnMXPvariable doesn't seem to be picking up the MaxHp/Sp/St and OnMXPEndTag isn't catching stuff between the 'V''s.

Sorry to be a pain Nick.
Amended on Sat 27 Sep 2003 06:18 AM by Johnathan Allen
Australia Forum Administrator #20
I tested it with the main script MXP closing tag, and it seemed to pick up the stuff between the Vs.

As for the !EN tags, you could detect them in the OnPluginMXPerror routine, as the !EN definition will be passed to that as an information message.
#21
I'm using the standard OnMXPEndTag sub that you published, and I'm getting nothing.
#22
I've got the !EN tags working okay, I used the OnMXPError function and split down the arguments to isolate the Hp/Sp/St and set them to variables (for testing purposes), but I still can't read the stuff between the <V> tags. Using the MXP start tag and end tag routines, I get nothing. As for debug, I get:

A 20000: ( 4994) MXP element: <V Hp>
E 1023: ( 4994) Unknown MXP element: <v>
A 20000: ( 4994) MXP element: </V>
W 5005: ( 4994) Closing MXP tag </v> does not have corresponding opening tag

That sort of signifies to me that its reading the start and end tags, but doing nothing with them. I'm guessing because the text actually resides between the opening and closing tags, and neither routine is designed to handle this. The mxp start tag is for arguments residing within the first tag, and mxp end tag is looking for a "<V Hp>" and a "</V Hp>", which isn't being used. I suppose I could do this with two sets of triggers, one for the !EN definitions, and another one just to read the prompt off the screen, but that introduces about a round of 'lag' between updates (i.e. the meter displays the last rounds statistics instead of the current one). I really don't know how to grab all the info I need in one fell swoop.

#23
I'm still puzzled... Basically its sending this for a prompt:

&lt;<V Hp>3595</V><!EN MaxHp 3595>hp <V Sp>1961</V><!EN MaxSp 1961>sp <V St>2138</V><!EN MaxSt 2138>st&gt;

But I'm still getting nothing with either mxp subroutine.
Australia Forum Administrator #24
Well, *why* is the server sending <V> tags if they aren't defined? Isn't that a server problem?
#25
I thought <V> tags didn't need to be defined, according to the MXP specs on zugg's website.

Quote:

<VAR> <V>
<VAR Name [DESC=description] [PRIVATE] [PUBLISH] [DELETE] [ADD] [REMOVE]>Value</VAR>

The <!ENTITY> tag allows the MUD server to set the value of a variable without displaying the value to the user. The <VAR> tag is just like the <!ENTITY> tag, except that the value of the variable is placed between the <VAR> and </VAR> tags, and this value is displayed to the user.
Hp: <VAR Hp>100</Var>
would display: "Hp: 100" to the user, and would set the entity hp to 100.
Amended on Thu 27 Nov 2003 05:02 AM by Johnathan Allen
Australia Forum Administrator #26
Grrrr, he has amended the spec since I did it. MUSHclient supports <var> not <v>.

For some reason Zugg has thrown in synonyms into the MXP specs, for instance <i> and <italic> are the same. When I did the MXP implementation there was only <var> but I see from your quote he has added <v> as well.

I'll add that into the next version.
#27
Thank you. And sorry for being a pain.