/******************************************************************************
 Protocol snippet by KaVir.  Released into the Public Domain in February 2011.
 ******************************************************************************/

In protocol.h:

   Update MUD_NAME and descriptor_t for your mud.

In protocol.c:

   Update the Write(), ReportBug() and InfoMessage() functions.

   Update the fields in the SendMSSP() function.

In your makefile:

   Add protocol.o to the list of object files.

Don't forget:

   #include protocol.h in each file that uses the snippet.

/***************************************************************************
 * Add the protocol pointer to the end of the data structure that contains 
 * each players' descriptor and other connection information.
 ***************************************************************************/

struct descriptor_t
{
   ...other variables are listed here...

   protocol_t *pProtocol;
};

/***************************************************************************
 * Create an update function, it should be called at least once per second.
 * 
 * Alternatively, call MSDPSetString() and MSDPSetNumber() at the specific 
 * places in the code where those values change.  For example, if you're 
 * using C++ and the values are changed through Set and Get methods, you 
 * could set the MSDP variables there.
 ***************************************************************************/

void msdp_update( void )
{
   int PlayerCount = 0;

   loop through every fully connected player descriptor
   {
      ++PlayerCount;

      MSDPSetString( descriptor, eMSDP_CHARACTER_NAME, name );
      MSDPSetNumber( descriptor, eMSDP_HEALTH, current hit points );
      MSDPSetNumber( descriptor, eMSDP_HEALTH_MAX, maximum hit points );
      MSDPSetNumber( descriptor, eMSDP_MANA, current mana );
      MSDPSetNumber( descriptor, eMSDP_MANA_MAX, maximum mana );
      MSDPSetNumber( descriptor, eMSDP_MOVEMENT, current movement points );
      MSDPSetNumber( descriptor, eMSDP_MOVEMENT_MAX, maximum movement points );

      ...continue setting all your variables here...

      MSDPUpdate( descriptor ); /* Flush all the dirty variables */
   }

   /* Ideally this should be called once at startup, and again whenever 
    * someone leaves or joins the mud.  But this works, and it keeps the 
    * snippet simple.  Optimise as you see fit.
    */
   MSSPSetPlayers( PlayerCount );
}


/***************************************************************************
 * Initialise the protocol data when a new descriptor structure is allocated.
 ***************************************************************************/

   new_descriptor = new/malloc/etc space for one descriptor_t
   new_descriptor->blah = ...
   new_descriptor->blah = ...
   new_descriptor->blah = ...

   ...and so on, until we reach the end...

   new_descriptor->pProtocol = ProtocolCreate();

Once the descriptor has been fully created and added to any lists, it's time 
to negotiate:

   ProtocolNegotiate(new_descriptor);

/***************************************************************************
 * Free the protocol data when a socket is closed.
 ***************************************************************************/

   ProtocolDestroy( dclose->pProtocol );

/***************************************************************************
 * When data is read in from a descriptor, read it into a temporary buffer 
 * first, and send that to ProtocolInput to parse.
 ***************************************************************************/

   static char temporary_buffer[MAX_PROTOCOL_BUFFER];
   temporary_buffer[0] = '\0';

   ...copy everything into the temporary_buffer...

   ProtocolInput( d, read_buf, iStart, descriptor->input_buffer );

   ...the rest of the mud can now use descriptor->input_buffer as normal...

/***************************************************************************
 * When data is written out to a descriptor, send it to ProtocolOutput first 
 * to parse any special variables for colour, MXP, UTF-8, etc.
 ***************************************************************************/

   ...where "string_to_send" is passed into the function...

   string_to_send = ProtocolOutput( descriptor, string_to_send, NULL );
   if ( descriptor->pProtocol->WriteOOB > 0 )
      --descriptor->pProtocol->WriteOOB;

   Only send a newline if descriptor->pProtocol->WriteOOB > 0

/***************************************************************************
 * Send the MXP <VERSION> tag immediately after a player enters the game or 
 * reconnects to an existing character.
 ***************************************************************************/

   ...the user is sent a "you enter the game" or "you reconnect" message...

   MXPSendTag( descriptor, "<VERSION>" );

/***************************************************************************
 * Don't send a new prompt to the user if they've only received OOB data 
 * since the last time they received a prompt.
 ***************************************************************************/

   if ( d->pProtocol->WriteOOB )
      ; /* The last sent data was OOB, so do NOT draw the prompt */
   else
      ...normal prompt drawing code follow...

/***************************************************************************
 * Whenever the user sends a command, clear the WriteOOB counter.
 ***************************************************************************/

   descriptor->entered_command = true;

   if ( descriptor->pProtocol != NULL )
      descriptor->pProtocol->WriteOOB = 0;