/****************************************************************************** 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 fields in the SendMSSP() function. /*************************************************************************** * File: Makefile * * Add protocol.o to the list of object files. ***************************************************************************/ /*************************************************************************** * File: merc.h * * Include protocol.h directly after the copyright notice/s. * * Or better yet put it in each c file that uses the protocol snippet. ***************************************************************************/ #include "protocol.h" /*************************************************************************** * File: merc.h * * Add the protocol pointer to the end of the descriptor_data structure. ***************************************************************************/ struct descriptor_data { DESCRIPTOR_DATA * next; DESCRIPTOR_DATA * snoop_by; CHAR_DATA * character; CHAR_DATA * original; bool valid; char * host; sh_int descriptor; sh_int connected; bool fcommand; char inbuf [4 * MAX_INPUT_LENGTH]; char incomm [MAX_INPUT_LENGTH]; char inlast [MAX_INPUT_LENGTH]; int repeat; char * outbuf; int outsize; int outtop; char * showstr_head; char * showstr_point; protocol_t * pProtocol; /* <--- Add this line */ }; /*************************************************************************** * File: update.c * * Add msdp_update() to the list of local functions near the top of the file. ***************************************************************************/ int hit_gain args( ( CHAR_DATA *ch ) ); int mana_gain args( ( CHAR_DATA *ch ) ); int move_gain args( ( CHAR_DATA *ch ) ); void mobile_update args( ( void ) ); void weather_update args( ( void ) ); void char_update args( ( void ) ); void obj_update args( ( void ) ); void aggr_update args( ( void ) ); void msdp_update args( ( void ) ); /* <--- Add this line */ /*************************************************************************** * File: update.c * * Add a new msdp_update() function. ***************************************************************************/ void msdp_update( void ) { DESCRIPTOR_DATA *d; int PlayerCount = 0; for ( d = descriptor_list; d != NULL; d = d->next ) { if ( d->character && d->connected == CON_PLAYING && !IS_NPC(d->character) ) { char buf[MAX_STRING_LENGTH]; CHAR_DATA *pOpponent = d->character->fighting; ROOM_INDEX_DATA *pRoom = d->character->in_room; AFFECT_DATA *paf; ++PlayerCount; MSDPSetString( d, eMSDP_CHARACTER_NAME, d->character->name ); MSDPSetNumber( d, eMSDP_ALIGNMENT, d->character->alignment ); MSDPSetNumber( d, eMSDP_EXPERIENCE, d->character->exp ); MSDPSetNumber( d, eMSDP_EXPERIENCE_MAX, exp_per_level(d->character, d->character->pcdata->points) ); MSDPSetNumber( d, eMSDP_EXPERIENCE_TNL, ((d->character->level + 1) * exp_per_level(d->character, d->character->pcdata->points) - d->character->exp ) ); MSDPSetNumber( d, eMSDP_HEALTH, d->character->hit ); MSDPSetNumber( d, eMSDP_HEALTH_MAX, d->character->max_hit ); MSDPSetNumber( d, eMSDP_LEVEL, d->character->level ); /* MSDPSetNumber( d, eMSDP_RACE, TBD ); MSDPSetNumber( d, eMSDP_CLASS, TBD ); */ MSDPSetNumber( d, eMSDP_MANA, d->character->mana ); MSDPSetNumber( d, eMSDP_MANA_MAX, d->character->max_mana ); MSDPSetNumber( d, eMSDP_WIMPY, d->character->wimpy ); MSDPSetNumber( d, eMSDP_PRACTICE, d->character->practice ); MSDPSetNumber( d, eMSDP_MONEY, d->character->gold ); MSDPSetNumber( d, eMSDP_MOVEMENT, d->character->move ); MSDPSetNumber( d, eMSDP_MOVEMENT_MAX, d->character->max_move ); MSDPSetNumber( d, eMSDP_HITROLL, GET_HITROLL(d->character) ); MSDPSetNumber( d, eMSDP_DAMROLL, GET_DAMROLL(d->character) ); MSDPSetNumber( d, eMSDP_AC, GET_AC(d->character) ); MSDPSetNumber( d, eMSDP_STR, get_curr_str(d->character) ); MSDPSetNumber( d, eMSDP_INT, get_curr_int(d->character) ); MSDPSetNumber( d, eMSDP_WIS, get_curr_wis(d->character) ); MSDPSetNumber( d, eMSDP_DEX, get_curr_dex(d->character) ); MSDPSetNumber( d, eMSDP_CON, get_curr_con(d->character) ); MSDPSetNumber( d, eMSDP_STR_PERM, d->character->pcdata->perm_str ); MSDPSetNumber( d, eMSDP_INT_PERM, d->character->pcdata->perm_int ); MSDPSetNumber( d, eMSDP_WIS_PERM, d->character->pcdata->perm_wis ); MSDPSetNumber( d, eMSDP_DEX_PERM, d->character->pcdata->perm_dex ); MSDPSetNumber( d, eMSDP_CON_PERM, d->character->pcdata->perm_con ); /* This would be better moved elsewhere */ if ( pOpponent != NULL ) { int hit_points = (pOpponent->hit * 100) / pOpponent->max_hit; MSDPSetNumber( d, eMSDP_OPPONENT_HEALTH, hit_points ); MSDPSetNumber( d, eMSDP_OPPONENT_HEALTH_MAX, 100 ); MSDPSetNumber( d, eMSDP_OPPONENT_LEVEL, pOpponent->level ); MSDPSetString( d, eMSDP_OPPONENT_NAME, pOpponent->name ); } else /* Clear the values */ { MSDPSetNumber( d, eMSDP_OPPONENT_HEALTH, 0 ); MSDPSetNumber( d, eMSDP_OPPONENT_LEVEL, 0 ); MSDPSetString( d, eMSDP_OPPONENT_NAME, "" ); } /* Only update room stuff if they've changed room */ if ( pRoom && pRoom->vnum != d->pProtocol->pVariables[eMSDP_ROOM_VNUM]->ValueInt ) { int i; /* Loop counter */ buf[0] = '\0'; for ( i = DIR_NORTH; i < MAX_DIR; ++i ) { if ( pRoom->exit[i] != NULL ) { const char MsdpVar[] = { (char)MSDP_VAR, '\0' }; const char MsdpVal[] = { (char)MSDP_VAL, '\0' }; extern char *const dir_name[]; strcat( buf, MsdpVar ); strcat( buf, dir_name[i] ); strcat( buf, MsdpVal ); if ( IS_SET(pRoom->exit[i]->exit_info, EX_CLOSED) ) strcat( buf, "C" ); else /* The exit is open */ strcat( buf, "O" ); } } if ( pRoom->area != NULL ) MSDPSetString( d, eMSDP_AREA_NAME, pRoom->area->name ); MSDPSetString( d, eMSDP_ROOM_NAME, pRoom->name ); MSDPSetTable( d, eMSDP_ROOM_EXITS, buf ); MSDPSetNumber( d, eMSDP_ROOM_VNUM, pRoom->vnum ); } /* MSDPSetNumber( d, eMSDP_WORLD_TIME, d->character-> ); */ buf[0] = '\0'; for ( paf = d->character->affected; paf; paf = paf->next ) { char skill_buf[MAX_STRING_LENGTH]; sprintf( skill_buf, "%c%s%c%d", (char)MSDP_VAR, skill_table[paf->type].name, (char)MSDP_VAL, paf->duration ); strcat( buf, skill_buf ); } MSDPSetTable( d, eMSDP_AFFECTS, buf ); MSDPUpdate( d ); } } /* 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 ); } /*************************************************************************** * File: update.c * * Call msdp_update() from within the update_handler. ***************************************************************************/ void update_handler( void ) { static int pulse_gain_exp; static int pulse_area; static int pulse_mobile; static int pulse_violence; static int pulse_point; static int pulse_msdp; /* <--- Add this line */ Then further down in the function, call msdp_update(): if ( --pulse_msdp <= 0 ) { pulse_msdp = PULSE_PER_SECOND; msdp_update(); } /*************************************************************************** * File: comm.c * * Add the protocol data to the descriptor in the init_descriptor() function. ***************************************************************************/ dnew = new_descriptor(); dnew->descriptor = desc; dnew->connected = CON_GET_NAME; dnew->showstr_head = NULL; dnew->showstr_point = NULL; dnew->outsize = 2000; dnew->outbuf = alloc_mem( dnew->outsize ); dnew->pProtocol = ProtocolCreate(); /* <--- Add this line */ And later in the same function: /* * Init descriptor data. */ dnew->next = descriptor_list; descriptor_list = dnew; ProtocolNegotiate(dnew); /* <--- Add this line */ /*************************************************************************** * File: comm.c * * Free the protocol data at the end of the close_socket() function. ***************************************************************************/ ProtocolDestroy( dclose->pProtocol ); /* <--- Add this line */ close( dclose->descriptor ); free_descriptor(dclose); #if defined(MSDOS) || defined(macintosh) exit(1); #endif return; } /*************************************************************************** * File: comm.c * * Change read_from_descriptor() to parse negotiation sequences. ***************************************************************************/ bool read_from_descriptor( DESCRIPTOR_DATA *d ) { int iStart; static char read_buf[MAX_PROTOCOL_BUFFER]; /* <--- Add this line */ read_buf[0] = '\0'; /* <--- Add this line */ Replace this: /* Check for overflow. */ iStart = strlen(d->inbuf); if ( iStart >= sizeof(d->inbuf) - 10 ) With this: /* Check for overflow. */ iStart = 0; if ( strlen(d->inbuf) >= sizeof(d->inbuf) - 10 ) Replace this: if ( c == '\r' ) putc( '\n', stdout ); d->inbuf[iStart++] = c; With this: if ( c == '\r' ) putc( '\n', stdout ); read_buf[iStart++] = c; Replace this: nRead = read( d->descriptor, d->inbuf + iStart, sizeof(d->inbuf) - 10 - iStart ); if ( nRead > 0 ) { iStart += nRead; if ( d->inbuf[iStart-1] == '\n' || d->inbuf[iStart-1] == '\r' ) break; } With this: nRead = read( d->descriptor, read_buf + iStart, sizeof(read_buf) - 10 - iStart ); if ( nRead > 0 ) { iStart += nRead; if ( read_buf[iStart-1] == '\n' || read_buf[iStart-1] == '\r' ) break; } Then at the end of the function replace this: d->inbuf[iStart] = '\0'; return TRUE; With this: read_buf[iStart] = '\0'; ProtocolInput( d, read_buf, iStart, d->inbuf ); return TRUE; /*************************************************************************** * File: comm.c * * Change write_to_buffer() to avoid sending blank lines. ***************************************************************************/ At the beginning of the function, add this: void write_to_buffer( DESCRIPTOR_DATA *d, const char *txt, int length ) { txt = ProtocolOutput( d, txt, &length ); /* <--- Add this line */ if ( d->pProtocol->WriteOOB > 0 ) /* <--- Add this line */ --d->pProtocol->WriteOOB; /* <--- Add this line */ Replace this: /* * Initial \n\r if needed. */ if ( d->outtop == 0 && !d->fcommand ) With this: /* * Initial \n\r if needed. */ if ( d->outtop == 0 && !d->fcommand && !d->pProtocol->WriteOOB ) /*************************************************************************** * File: comm.c * * In nanny(), send the <VERSION> tag right after the player enters the game. ***************************************************************************/ act( "$n has entered the game.", ch, NULL, NULL, TO_ROOM ); MXPSendTag( d, "<VERSION>" ); /* <--- Add this line */ You should also do the same in check_reconnect, after setting d->connected: d->connected = CON_PLAYING MXPSendTag( d, "<VERSION>" ); /* <--- Add this line */ /*************************************************************************** * File: comm.c * * Change process_output() to avoid sending a prompt after sending OOB data. ***************************************************************************/ bool process_output( DESCRIPTOR_DATA *d, bool fPrompt ) { extern bool merc_down; /* * Bust a prompt. */ if ( d->pProtocol->WriteOOB ) /* <-- Add this, and the ";" and "else" */ ; /* The last sent data was OOB, so do NOT draw the prompt */ else if (!merc_down && d->showstr_point) /*************************************************************************** * File: comm.c * * Whenever d->fcommand is set to TRUE, clear the write OOB ***************************************************************************/ d->fcommand = TRUE; if ( d->pProtocol != NULL ) d->pProtocol->WriteOOB = 0; /*************************************************************************** * File: comm.c * * Replace the echo_off_str and echo_on_str with the new ECHO function. ***************************************************************************/ Replace this line: write_to_buffer( d, echo_off_str, 0 ); With the following: ProtocolNoEcho( d, true ); And these lines: sprintf( buf, "New character.\n\rGive me a password for %s: %s", ch->name, echo_off_str ); With the following: ProtocolNoEcho( d, true ); sprintf( buf, "New character.\n\rGive me a password for %s: ", ch->name ); Then replace both instances of this line: write_to_buffer( d, echo_on_str, 0 ); With the following: ProtocolNoEcho( d, false );