[Home] [Downloads] [Search] [Help/forum]


Register forum user name Search FAQ

Gammon Forum

[Folder]  Entire forum
-> [Folder]  MUSHclient
. -> [Folder]  Tips and tricks
. . -> [Subject]  New sound support in MUSHclient

New sound support in MUSHclient

It is now over 60 days since the last post. This thread is closed.     [Refresh] Refresh page


Posted by Nick Gammon   Australia  (22,975 posts)  [Biography] bio   Forum Administrator
Date Fri 20 Jun 2008 05:07 AM (UTC)

Amended on Sun 22 Jun 2008 09:41 PM (UTC) by Nick Gammon

Message
Version 4.28 of MUSHclient introduces somewhat better handling of playing sounds, in particular multiple simultaneous sounds.

This leverages off the DirectSound technology which is part of DirectX. This uses a couple of DirectX features to work, so it may not work if you don't have DirectX installed (most recent PCs do).
However as these are new script calls, the old sounds should still work.

The basic features are:


  • Up to 10 simultaneous sounds (channels), per world, can be played. Windows mixes them together to give an aggregate sound out of your speakers.

  • Each channel can play at a different volume level. (eg. quiet background ambient sounds)

  • Individual channels can loop if desired (eg. for background music, or ambient sounds).

  • Each channel can be "panned" so that the sound comes out of the left speaker, the right speaker, or both. This might be useful if you see something like "there is a market off to your left", so you could play ambient "market" sounds out of the left speaker.

  • Sounds can be reconfigured whilst playing, for example to make them softer or louder.

  • Sounds can be cancelled at any time.

  • You can query if a sound is still playing or not. You might set up a timer to check if the music channel has finished playing, and if so, play something else.


Buffers

The fundamental feature you need to know about to use this, is the concept of channels or buffers. Each sound is played from its own buffer (which is loaded up from a .wav file). You have 10 buffers to work with, numbered 1 to 10.

If designing sounds for use with a MUD you would need to assign various channels for various purposes. For example:


  1. Temporary battle sounds (like swords clashing)
  2. Ambient sound loops (like forest sounds, or town sounds)
  3. Background music loops


By assigning a buffer or channel to each type of sound like this, you can change the music by playing a new sound in channel 3, if that was the one you designated for music.

For example:


PlaySound (1, "swordhit.wav")
PlaySound (2, "forest.wav", true, -6)  -- loop forest sounds, -6 db  volume
PlaySound (3, "calm_music.wav", true, -4)  -- loop music, -4 db volume


Now if you got into a battle you could simply replace the music with battle music:


PlaySound (3, "battle_music.wav", true, -3)  -- loop music, -3 db volume


The other 2 channels will continue playing what they were before.

To make life easier, you can use channel 0, which means "take the first available channel". This is intended to let MUSHclient choose a free channel (one that is not currently playing a sound), rather than having to micro-manage channels for short-term effects like swords hitting, spells casting, and so on. The first available channel is chosen from channels 1 to 5, keeping channels 6 to 10 free for longer-term effects like ambient sounds and music.

For example:


PlaySound (0, "swordhit.wav")
PlaySound (0, "shield_block.wav")  
PlaySound (0, "fireball.wav")


The code above would let all 3 sounds play simultaneously. This would be useful where triggers might cause a sound to be played before another one had finished, and you didn't want the earlier sound to be cut off.

If MUSHclient can't find a free channel, the sound will replace whatever was in channel 1. Thus, you should keep channel 1 free for temporary sounds, and not use it to play music or ambient loops, otherwise they might get cut off during a busy battle.

In fact, you are advised to group your sounds as follows:


  • Buffers 1 to 5 - short-term sounds (like a sword-hit, spell cast, cry of pain, etc.)
  • Buffers 6 to 10 - longer-duration sounds or loops (like ambient sounds, music, crackling fire, etc.)


Full sound interface definition


result = PlaySound (Buffer, FileName, Loop, Volume, Pan)


Plays a sound, or adjusts the parameters of a sound that is currently playing. If a sound is currently playing in the selected buffer it is automatically stopped and its memory freed. Thus you do not need to stop sounds first before replacing them by something else.


  • Buffer: Which buffer to use (1 to 10) or 0 to take the first free buffer when playing a new sound. If there are no free buffers, buffer 1 is chosen.

  • FileName: The sound file to play. Can be the empty string in which case you are modifying the behaviour of a currently-playing sound in that buffer.

    If the file name is a fully-qualified path name (ie. it starts with a slash, or a drive letter, colon, slash like "C:\") then it is used "as is".
    Otherwise, MUSHclient prepends the MUSHclient execution directory + "sounds" subdirectory to the name

    For example, the file name "swordhit.wav" would be looked for at: C:\Program Files\MUSHclient\sounds\swordhit.wav

    You can use forward slashes in the file name (for convenience in typing strings in scripts), they are converted to backslashes.

    The only file type supported is a .wav file, as follows:


    • 16-bit
    • 22.05 KHz
    • PCM (ie. uncompressed)
    • Mono or Stereo


    Note that the entire file is read into memory, uncompressed. We do not attempt to "stream" the file. Thus large sound files will take a lot of memory. The sound functions are intended for sound effects and short loops of music or ambient sounds. They are not intended to play Beethoven's Fifth Symphony while you play.

    You can convert sound files which are in other formats (eg. MP3) into WAV files by using various programs. One very good free program is Audacity, which is available for Mac or Windows:


    http://audacity.sourceforge.net/


    In Audacity, open your file, and then choose: File Menu -> Export As WAV...


  • Loop: true or false (1 or 0). If true the sound loops, and thus repeats indefinitely until cancelled. A sound can be cancelled by calling the StopSound function for that buffer number, or simply playing a different sound in that buffer. Obviously it is preferable to not use buffer 0 if you are planning to loop, because you won't know which buffer actually got allocated.

    If omitted in Lua scripting this defaults to false (not looping).

  • Volume: -100 to 0. This is the number of db (decibels) to attenuate (reduce) the sound. Decibels are a logarithmic scale, every 3 db corresponds to half the perceived sound volume. Thus a volume of zero is "full volume". A volume of -3 is half-volume, -6 is quarter-volume, and so on. If you want to fade a sound away rather than just cut if off, you get quite a good effect by readjusting the sound every half second or so in a loop, reducing the volume by -2 each time, from 0 to -40. A sound at volume -40 is pretty quiet, after which you can just stop playing the sound. If you are going to write a "reduce the volume" loop you would need to use Lua coroutines, or some other timer mechanism, to turn the volume in that channel down periodically.

    If omitted in Lua scripting this defaults to 0 (full volume).

    If the volume is out of the range -100 to 0 then 0 (full volume) is used.

  • Pan: -100 to +100. This is the number of db (decibels) to attenuate the sound in one speaker, to create a stereo affect (that is, more from one speaker than the other).


    • Pan of -100 makes the sound come completely from the left speaker (the right speaker is cut off).
    • Pan of 0 makes the sound come from both speakers, and thus it sounds centered.
    • Pan of +100 makes the sound come completely from the right speaker (the left speaker is cut off).


    If omitted in Lua scripting this defaults to 0 (both speakers, or centered).

    If the pan value is out of the range -100 to +100 then 0 is used.



Examples:


-- play sound once only, full volume, centered, in buffer 1
PlaySound (1, "boing.wav", false, 0, 0)  

-- play sound once only, quarter volume, from the left speaker, in buffer 2
PlaySound (2, "ding.wav", false, -6, -100)  

-- play sound looping, eighth volume, from the right speaker, in buffer 3
PlaySound (3, "forest.wav", true, -9, 100) 

-- play sound once only, full volume, slightly to the left, in the first available buffer
PlaySound (0, "swordhit.wav", false, 0, -3)  


To adjust an existing sound, like the forest sound above:


PlaySound (3, "", false, -9, 100)  --> cancel looping for buffer 3, still play at -9 db
PlaySound (3, "", false, -12, 100)  --> cancel looping for buffer 3 and make softer


Possible return codes


  • eCannotPlaySound (30004):

    * DirectSound not initialized
    * An attempt made to change the volume, looping, or pan of a sound that is not playing
    * Sound file is not a .wav file
    * Cannot parse sound file
    * Sound file is not a PCM format file (wrong sound file format)
    * Cannot find sound data in sound file
    * Cannot create internal sound buffer (maybe all in use)
    * Cannot read sound data into memory
    * DirectSound refuses to play the sound

  • eBadParameter (30046):

    * An attempt made to change the volume, looping, or pan of a sound that is not in use
    * No sound file name given, and buffer 0 given
    * Buffer number outside range 0 to 10
    * File name > 127 characters long

  • eFileNotFound (30051):

    * Sound file not found

  • eOK (0):

    * Sound played OK (or volume/looping/pan adjusted OK)







result = StopSound (Buffer)


Stops one, or all, sound buffers from playing. It is not necessary to call this for non-looping sounds, which stop of their own accord anyway, however doing so would free up the memory used by the sound.


  • Buffer: Which buffer to stop (1 to 10) or 0 to stop all sound buffers playing.


Possible return codes



  • eBadParameter (30046):

    * Buffer number outside range 0 to 10

  • eOK (0):

    * Requested buffer(s) have been stopped.








result = GetSoundStatus (Buffer)


Gets the status of one of the sound buffers.

Basically if the returned number is > 0 then the sound is playing, and if it is <= 0 then it is not playing.

You might test this in a timer to see if a sound had stopped playing (eg. some music), and if so, play something else.


  • Buffer: Which buffer to query (1 to 10).


Possible return codes


  • -3: Sound system is not initialized (ie. DirectX not installed or too early version)
  • -2: That buffer is free (never played a sound, or the sound was stopped with StopSound)
  • -1: Requested buffer number out of range 1 to 10
  • 0: That buffer has reached the end and stopped playing
  • 1: That buffer is playing a sound, but not looping
  • 2: That buffer is playing a sound, which is a looping sound


A sensible test for a plugin might be to check if the sound system is available, eg.


if GetSoundStatus (1) == -3 then
  EnablePlugin ("982581e59ab42844527eec80", false) -- can't play sounds, disable plugin
end -- if





Notes

The MUSHclient Display menu -> Stop Sound Playing will cancel any sounds you have started via the PlaySound function. You might use that if sounds get out of hand a bit during testing.

There may be limitations on how many sounds can play simultaneously on your particular system. I haven't yet hit that limit, but it probably varies from one PC to the next, depending on Operating System verson, DirectX versions, type of sound card, sound card driver, and available system memory.

Apparently sounds can stop playing if you Alt+Tab to another application (or simply switch windows), and then switch back. Your scripts might want to periodically check whether music or ambient sounds they have started earlier are still playing (use GetSoundStatus), and if not, start them again.

Under the current configuration, the sounds stop playing if you make another application active, and then resume when MUSHclient is the foreground application again (or at least, it does for me).

You can still use the original Sound script function - that will play sounds "on top of" the sounds from PlaySound. Thus trigger (and other) sounds will continue to work.

I found that a judicious selection of sounds helped make playing a MUD somewhat more immersive. Having a stirring battle tune start up as you start a fight, and hearing each sword blow land, followed by the mob's death cry, made it quite a lot of fun.

Some versions of Windows may simply not support any DirectSound sound playing. If you can't get anything to work, try:


/print (GetSoundStatus (1))  


If that prints -3 then your version of Windows does not support DirectSound. You could try installing DirectX.

Otherwise, if you are having problems check the return code, for example:


require "check"
check (PlaySound (0, "cast/fireball.wav"))  --> Cannot open the specified file (misspelt maybe?)




- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nick Gammon   Australia  (22,975 posts)  [Biography] bio   Forum Administrator
Date Reply #1 on Fri 20 Jun 2008 05:07 AM (UTC)
Message
Where to find sounds

There are quite a few places you can obtain sounds from if you want to experiment with this stuff.


  • Some MUDs have pre-packaged sets of sounds (for use with MUD Sound Protocol) - you could download one of those. It would only take very minor modification to change the MSP plugin to use the new sound script calls.

  • Collections of sounds are available on CDROM, frequently very cheaply. Shops that sell computer software usually have some sort of sound collection available for around $10.

  • If you have some games installed, you can often get at the sounds that came with them. Whilst it would be a breach of copyright to distribute those, using them for personal use on the same PC you installed the game is hardly piracy. For example, Blizzard's games like Warcraft, Diablo, World of Warcraft, etc. have large quanties of quite suitable sounds (since these are games about fighting in fantasy worlds). In Blizzard's case the sounds are usually inside the MPQ files that come with the games. Google for "MPQ extractor" and you should find plenty of suitable utilities to get the sounds out of the MPQ files.

  • You can always make your own, armed with a microphone, some cutlery and saucepans. Use the Sound Recorder program that comes with Windows, or for somewhat more flexibility use, Audacity (or similar). See: http://audacity.sourceforge.net/

    It would be fun to record your own voice challenging the mobs as you go into battle "Take that you varlet!". You could also record your own ki-yap (battle shout). With a program like Audacity you could also alter the characteristic of the sound, for example playing it backwards to make a spooky sound, adding echo, or simply "normalizing" it so that all the sounds are at the same volume.

  • No doubt there are other sounds available over the Internet for downloading.

  • Some modern electronic keyboards (which play sound samples) have "foley" or "sound effects" voices. You could get some special effects from them.




- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nick Gammon   Australia  (22,975 posts)  [Biography] bio   Forum Administrator
Date Reply #2 on Sat 21 Jun 2008 06:07 AM (UTC)

Amended on Sat 21 Jun 2008 07:29 AM (UTC) by Nick Gammon

Message
My tests so far show that the DirectSound stuff works under Windows XP and Windows Vista, but not Windows NT 4.

And after installing Windows 98 in a Parallels virtual window, it worked under Windows 98 as well.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nick Gammon   Australia  (22,975 posts)  [Biography] bio   Forum Administrator
Date Reply #3 on Sat 21 Jun 2008 10:41 PM (UTC)
Message
After a bit of fooling around, I got an old copy of Windows 95 to install in a Parallels virtual window as well.

Initially I could not even run MUSHclient, because that relies on some of the slightly more up-to-date system DLLs. However installing Internet Explorer 5 fixed that.

Having got MUSHclient up, the DirectSound calls didn't work. However I then installed DirectX 7, after which everything worked.

DirectX 7 is fairly old, so anyone still running Windows 95 is likely to have it. If not, go to Microsoft's site and look for a copy. (I currently have DirectX 9 on Windows XP).

I haven't tested Windows ME, however since it came out after Windows 98, I think we can safely guess that anything that runs on Windows 98 (like DirectX) will also run on Windows ME.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nick Gammon   Australia  (22,975 posts)  [Biography] bio   Forum Administrator
Date Reply #4 on Tue 24 Jun 2008 05:50 AM (UTC)

Amended on Tue 24 Jun 2008 05:54 AM (UTC) by Nick Gammon

Message
Below is a suggested plugin for randomly choosing sounds from a group.

While testing sounds I found it was tedious to keep locating individual sound files (to make the sounds more interesting). The plugin below assumes you have groups of sounds (eg. battle music, sword hits, dagger hits, death cries). Just save from between the lines as Play_Random_Sound.xml and install that as a plugin.

Then, assuming you have a "dagger" sub-folder under your "sounds" folder, you can randomly choose a dagger sound like this:


-- play a single dagger sound in first free buffer at full volume
 check (CallPlugin ("461479af5d149307e69e305f", "PlayRandomSound", "0,dagger,n,0"))


And if you have some battle music in your battle folder, you can do this:


 -- loop a battle sound in buffer 9 at -6 db
 check (CallPlugin ("461479af5d149307e69e305f", "PlayRandomSound", "9,battle,y,-6"))


The plugin scans the folder, the first time it is called for each type of sound, locating all .wav files in it, and builds them into a table. Subsequently it chooses a sound at random from that table.



<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<!-- Saved on Tuesday, June 24, 2008, 3:20 PM -->
<!-- MuClient version 4.29 -->

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

<muclient>
<plugin
   name="Play_Random_Sound"
   author="Nick Gammon"
   id="461479af5d149307e69e305f"
   language="Lua"
   purpose="Plays a sound from a group of sounds"
   date_written="2008-06-24 15:08:41"
   requires="4.29"
   version="1.0"
   >
<description trim="y">
<![CDATA[
Implements an interface for other plugins, or triggers etc. to play a sound chosen at random.

Examples of use:

 -- loop a battle sound in buffer 9 at -6 db
 check (CallPlugin ("461479af5d149307e69e305f", "PlayRandomSound", "9,battle,y,-6"))
 
 -- play a single dagger sound in first free buffer at full volume
 check (CallPlugin ("461479af5d149307e69e305f", "PlayRandomSound", "0,dagger,n,0"))

]]>
</description>

</plugin>

<!--  Script  -->

<script>
<![CDATA[
sounds = {}

-- args are: buffer,folder,loop,level

function PlayRandomSound (args)
  
  local buffer, folder, loop, level = string.match (args,
        "(%d+),%s*(%w+),%s*([y|n]),%s*(%-?%d+)")
  
  if not buffer then
    error ("Arguments to PlayRandomSound are: buffer,folder,loop(y/n),level, you supplied: " .. args)
  end -- if

  -- if folder not read in yet, go grab it  
  if not sounds [folder] then
    sounds [folder]  = {}  -- table of sound file names
    local t = assert (utils.readdir (GetInfo (74) .. folder .. "/*wav"))
    
    -- copy from keys of the table of names, into a new table, dropping files starting with "."
    for k in pairs (t) do
      if k:sub (1, 1) ~= "." then
        table.insert (sounds [folder], k)
      end -- not temporary files
    end -- for adding each one
    
    -- check we got something
    assert (#sounds [folder] > 0, "No sounds in folder " .. folder)
    
    ColourNote ("white", "green", "Found " .. #sounds [folder] .. " sounds in " .. folder .. " folder.")
  end -- if not dagger sounds table yet
  
  -- choose one
  sound = folder .. "/" .. sounds [folder] [math.random (#sounds [folder])]

  -- play it  
  check (PlaySound (buffer, sound, loop == "y", level ))

end -- function PlayRandomSound 

math.randomseed (os.time ())

]]>
</script>


</muclient>

- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nick Gammon   Australia  (22,975 posts)  [Biography] bio   Forum Administrator
Date Reply #5 on Tue 24 Jun 2008 06:02 AM (UTC)

Amended on Tue 24 Jun 2008 06:35 AM (UTC) by Nick Gammon

Message
Below is the plugin I have been experimenting with to play "battle music". It requires the Play_Random_Sound plugin described above.

How it works is by detecting the battle prompt which will frequently appear during battle (you can usually customize your prompts on Diku-style MUDs). If the battle prompt doesn't work for you, change the first trigger to detect some message you normally see during battle.

It also needs to detect the non-battle prompt, or some other trigger that tells it the battle if over.

Based on this:


  • If we are in battle, it randomly chooses some battle music from the "battle" subdirectory by using the Play_Random_Sound plugin. It plays that looping, at -6 db (quarter volume).

  • If it is already playing the battle music, it simply bumps it back to -6 db volume, in case we had started fading it out.

  • If the battle is over it enters a coroutine using the "wait" module, and gradually fades the music out over about 4 seconds, so the music smoothly fades away, rather than abruptly stopping.

  • However if another battle starts (as detected by the "fighting" variable) then it stops fading the music out.



Save between the lines as Fighting_Sounds.xml and install as a plugin. Also install the plugin Play_Random_Sound described earlier.



<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE muclient>
<!-- Saved on Sunday, June 22, 2008, 1:50 PM -->
<!-- MuClient version 4.29 -->

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

<muclient>
<plugin
   name="Fighting_Sounds"
   author="Nick Gammon"
   id="2dcc6e67def105c71cf42e10"
   language="Lua"
   purpose="Play sounds during fights"
   date_written="2008-06-22 13:49:29"
   requires="4.29"
   version="1.0"
   >

</plugin>


<!--  Triggers  -->

<triggers>
  <trigger
   enabled="y"
   keep_evaluating="y"
   match="[Fighting: *"
   name="fighting_sound"
   send_to="12"
   sequence="100"
  >
  <send>
  
-- if not playing, choose a new one
if GetSoundStatus (9) &lt;= 0 then
  check (CallPlugin ("461479af5d149307e69e305f", "PlayRandomSound", "9,battle,y,-6"))
else
  check (PlaySound (9, "", true, -6))  -- put sound back to full volume
end -- not playing yet

-- note we are fighting, in case we are dropping the volume
fighting = true

</send>
  </trigger>
  
  
  <trigger
   enabled="y"
   keep_evaluating="y"
   match="^\[(\d+)\/(\d+)hp .*$"
   name="cancel_fighting_sound"
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>
  
-- Not fighting  now

require "wait"

-- fade sound out
if fighting and GetSoundStatus (9) &gt; 0 then
  wait.make (function ()

    fighting = false
    for i = 1, 20 do
      PlaySound (9, "", false, -6 -(i * 2) )
      wait.time (0.2)
      if fighting then
        return   -- stop if we got back into a fight
      end -- if
    end -- for loop
 
   check (StopSound (9))

  end)   -- end coroutine

end -- fading battle sound
</send>
  </trigger>
</triggers>

</muclient>


- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Nick Gammon   Australia  (22,975 posts)  [Biography] bio   Forum Administrator
Date Reply #6 on Tue 24 Jun 2008 06:05 AM (UTC)

Amended on Tue 24 Jun 2008 06:38 AM (UTC) by Nick Gammon

Message
Here is an example of a simple trigger that plays a sound when your weapon hits the opponent:


<triggers>
  <trigger
   enabled="y"
   keep_evaluating="y"
   match="^Your stab "
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>
check (CallPlugin ("461479af5d149307e69e305f", "PlayRandomSound", "0,dagger,n,0"))
</send>
  </trigger>
</triggers>


And here is an example of playing a particular sound when casting a spell:


<triggers>
  <trigger
   enabled="y"
   keep_evaluating="y"
   match="^Your burning hands "
   regexp="y"
   send_to="12"
   sequence="100"
  >
  <send>
check (PlaySound (0, "cast/fireball.wav"))
</send>
  </trigger>
</triggers>


- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Panaku   (34 posts)  [Biography] bio
Date Reply #7 on Wed 23 Oct 2013 05:53 AM (UTC)
Message
Trying to get PlaySound to work and maybe I just don't understand how to run them.. I'm currently trying to run them through a trigger (during certain boss fights, when in certain areas). But it's not working at all. Trigger sounds (single time) work no problem but the PlaySound function doesn't seem to work at all. How do I need to call this function?
[Go to top] top

Posted by Nick Gammon   Australia  (22,975 posts)  [Biography] bio   Forum Administrator
Date Reply #8 on Wed 23 Oct 2013 11:18 PM (UTC)
Message
First, make sure you have them in the right directory.

With scripting enabled, and "/" as the scripting prefix, type:


/print (GetInfo (74))


I got:


C:\Program Files\MUSHclient\sounds\


Second, some sound files do not work.

The only file type supported is a .wav file, as follows:


  • 16-bit
  • 22.05 KHz
  • PCM (ie. uncompressed)
  • Mono or Stereo


If necessary use a program like Audacity to convert your sound(s) to that format.


- Nick Gammon

www.gammon.com.au, www.mushclient.com
[Go to top] top

Posted by Panaku   (34 posts)  [Biography] bio
Date Reply #9 on Thu 24 Oct 2013 05:42 AM (UTC)
Message
That was the problem, I was putting files in the same folder as the world file. It's working great now, thanks so much.
[Go to top] top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


45,601 views.

It is now over 60 days since the last post. This thread is closed.     [Refresh] Refresh page

Go to topic:           Search the forum


[Go to top] top

Quick links: MUSHclient. MUSHclient help. Forum shortcuts. Posting templates. Lua modules. Lua documentation.

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.

[Home]


Written by Nick Gammon - 5K   profile for Nick Gammon on Stack Exchange, a network of free, community-driven Q&A sites   Marriage equality

Comments to: Gammon Software support
[RH click to get RSS URL] Forum RSS feed ( https://gammon.com.au/rss/forum.xml )

[Best viewed with any browser - 2K]    [Hosted at HostDash]