/******************************************************************************
Protocol snippet by KaVir. Released into the Public Domain in February 2011.
******************************************************************************/
/***************************************************************************
* File: protocol.h
*
* Update the MUD_NAME and descriptor_t for TBA.
***************************************************************************/
#define MUD_NAME "tbaMUD"
typedef struct descriptor_data descriptor_t;
/***************************************************************************
* File: protocol.c
*
* Update the Write(), ReportBug() and InfoMessage() functions for TBA.
***************************************************************************/
static void Write( descriptor_t *apDescriptor, const char *apData )
{
if ( apDescriptor != NULL && apDescriptor->has_prompt )
{
if ( apDescriptor->pProtocol->WriteOOB > 0 ||
*(apDescriptor->output) == '\0' )
{
apDescriptor->pProtocol->WriteOOB = 2;
}
}
write_to_output( apDescriptor, apData );
}
static void ReportBug( const char *apText )
{
log( apText );
}
static void InfoMessage( descriptor_t *apDescriptor, const char *apData )
{
Write( apDescriptor, "\t[F210][\toINFO\t[F210]]\tn " );
Write( apDescriptor, apData );
apDescriptor->pProtocol->WriteOOB = 0;
}
/***************************************************************************
* File: structs.h
*
* Add protocol.h to the top to get it working. Move it to the c files when
* you tidy up.
***************************************************************************/
#include "protocol.h"
/***************************************************************************
* File: structs.h
*
* Add the protocol pointer to the end of the descriptor_data structure.
***************************************************************************/
struct descriptor_data
{
socket_t descriptor; /**< file descriptor for socket */ ?c
char host[HOST_LENGTH+1]; /**< hostname */ r system
byte bad_pws; /**< number of bad pw attemps this login */
...
struct descriptor_data *snoop_by; /**< And who is snooping this char */
struct descriptor_data *next; /**< link to next descriptor */
struct oasis_olc_data *olc; /**< OLC info */
protocol_t *pProtocol; /* <--- Add this line */
};
/***************************************************************************
* File: comm.c
*
* Add msdp_update() to the list of local functions near the top of the file.
***************************************************************************/
/* Webster Dictionary Lookup functions */
static RETSIGTYPE websterlink(int sig);
static size_t proc_colors(char *txt, size_t maxlen, int parse);
static void handle_webster_file();
static void msdp_update(void); /* <--- Add this line */
/***************************************************************************
* File: comm.c
*
* Add the new msdp_update() function.
***************************************************************************/
static void msdp_update( void )
{
struct descriptor_data *d;
int PlayerCount = 0;
char buf[MAX_STRING_LENGTH];
extern const char *pc_class_types[];
for (d = descriptor_list; d; d = d->next)
{
struct char_data *ch = d->character;
if ( ch && !IS_NPC(ch) && d->connected == CON_PLAYING )
{
struct char_data *pOpponent = FIGHTING(ch);
++PlayerCount;
MSDPSetString( d, eMSDP_CHARACTER_NAME, GET_NAME(ch) );
MSDPSetNumber( d, eMSDP_ALIGNMENT, GET_ALIGNMENT(ch) );
MSDPSetNumber( d, eMSDP_EXPERIENCE, GET_EXP(ch) );
MSDPSetNumber( d, eMSDP_HEALTH, GET_HIT(ch) );
MSDPSetNumber( d, eMSDP_HEALTH_MAX, GET_MAX_HIT(ch) );
MSDPSetNumber( d, eMSDP_LEVEL, GET_LEVEL(ch) );
sprinttype( ch->player.chclass, pc_class_types, buf, sizeof(buf) );
MSDPSetString( d, eMSDP_CLASS, buf );
MSDPSetNumber( d, eMSDP_MANA, GET_MANA(ch) );
MSDPSetNumber( d, eMSDP_MANA_MAX, GET_MAX_MANA(ch) );
MSDPSetNumber( d, eMSDP_WIMPY, GET_WIMP_LEV(ch) );
MSDPSetNumber( d, eMSDP_MONEY, GET_GOLD(ch) );
MSDPSetNumber( d, eMSDP_MOVEMENT, GET_MOVE(ch) );
MSDPSetNumber( d, eMSDP_MOVEMENT_MAX, GET_MAX_MOVE(ch) );
MSDPSetNumber( d, eMSDP_AC, compute_armor_class(ch) );
/* This would be better moved elsewhere */
if ( pOpponent != NULL )
{
int hit_points = (GET_HIT(pOpponent) * 100) / GET_MAX_HIT(pOpponent);
MSDPSetNumber( d, eMSDP_OPPONENT_HEALTH, hit_points );
MSDPSetNumber( d, eMSDP_OPPONENT_HEALTH_MAX, 100 );
MSDPSetNumber( d, eMSDP_OPPONENT_LEVEL, GET_LEVEL(pOpponent) );
MSDPSetString( d, eMSDP_OPPONENT_NAME, PERS(pOpponent, ch) );
}
else /* Clear the values */
{
MSDPSetNumber( d, eMSDP_OPPONENT_HEALTH, 0 );
MSDPSetNumber( d, eMSDP_OPPONENT_LEVEL, 0 );
MSDPSetString( d, eMSDP_OPPONENT_NAME, "" );
}
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: comm.c
*
* Call msdp_update() from within the heartbeat() function.
*
* You can add a 1 second PULSE_MSDP to structs.h if you prefer.
***************************************************************************/
if (!(heart_pulse % PULSE_VIOLENCE))
perform_violence();
if (!(heart_pulse % PASSES_PER_SEC))
msdp_update();
/***************************************************************************
* File: comm.c
*
* Initialise the protocol data in the init_descriptor() function.
***************************************************************************/
CREATE(newd->history, char *, HISTORY_SIZE);
if (++last_desc == 1000)
last_desc = 1;
newd->desc_num = last_desc;
newd->pProtocol = ProtocolCreate(); /* <--- Add this line */
}
/***************************************************************************
* File: comm.c
*
* Perform the negotiation in the new_descriptor() function.
***************************************************************************/
/* initialize descriptor data */
init_descriptor(newd, desc);
/* prepend to list */
newd->next = descriptor_list;
descriptor_list = newd;
ProtocolNegotiate(newd); /* <--- Add this line */
/***************************************************************************
* File: comm.c
*
* Free the protocol data at the end of the close_socket() function.
***************************************************************************/
if (d->showstr_head)
free(d->showstr_head);
if (d->showstr_count)
free(d->showstr_vector);
ProtocolDestroy( d->pProtocol ); /* <--- Add this line */
/***************************************************************************
* File: comm.c
*
* Change process_input() to parse negotiation sequences.
***************************************************************************/
static int process_input(struct descriptor_data *t)
{
int buf_length, failed_subst;
ssize_t bytes_read;
size_t space_left;
char *ptr, *read_point, *write_point, *nl_pos = NULL;
char tmp[MAX_INPUT_LENGTH];
static char read_buf[MAX_PROTOCOL_BUFFER]; /* <--- Add this line */
read_buf[0] = '\0'; /* <--- Add this line */
Now divert the input by replacing this:
bytes_read = perform_socket_read(t->descriptor, read_point, space_left);
With this:
bytes_read = perform_socket_read(t->descriptor, read_buf, MAX_PROTOCOL_BUFFER);
if ( bytes_read >= 0 )
{
read_buf[bytes_read] = '\0';
ProtocolInput( t, read_buf, bytes_read, read_point );
bytes_read = strlen(read_point);
}
/***************************************************************************
* File: comm.c
*
* Change vwrite_to_output.
***************************************************************************/
Near the beginning of the function, add this:
wantsize = size = vsnprintf(txt, sizeof(txt), format, args);
strcpy(txt, ProtocolOutput( t, txt, (int*)&wantsize )); /* <--- Add this line */
size = wantsize; /* <--- Add this line */
if ( t->pProtocol->WriteOOB > 0 ) /* <--- Add this line */
--t->pProtocol->WriteOOB; /* <--- Add this line */
if (t->character)
wantsize = size = proc_colors(txt, sizeof(txt), COLOR_ON(t->character));
/***************************************************************************
* File: comm.c
*
* Change process_output() to avoid sending a prompt after sending OOB data.
***************************************************************************/
Add the following three WriteOOB checks:
/* add the extra CRLF if the person isn't in compact mode */
if (STATE(t) == CON_PLAYING && t->character && !IS_NPC(t->character) && !PRF_FLAGGED(t->character, PRF_COMPACT))
if ( !t->pProtocol->WriteOOB ) /* <--- Add this line */
strcat(osb, "\r\n"); /* strcpy: OK (osb:MAX_SOCK_BUF-2 reserves space) */
/* add a prompt */
if ( !t->pProtocol->WriteOOB ) /* <--- Add this line */
strcat(i, make_prompt(t)); /* strcpy: OK (i:MAX_SOCK_BUF reserves space) */
/* now, send the output. If this is an 'interruption', use the prepended
* CRLF, otherwise send the straight output sans CRLF. */
if (t->has_prompt && !t->pProtocol->WriteOOB) { /* <--- Update this line */
t->has_prompt = FALSE;
result = write_to_descriptor(t->descriptor, i);
if (result >= 2)
result -= 2;
} else
result = write_to_descriptor(t->descriptor, osb);
/***************************************************************************
* File: interpreter.c
*
* Send the <VERSION> tag at the end of the enter_player_game() function.
***************************************************************************/
MXPSendTag( d, "<VERSION>" ); /* <--- Add this line */
return load_result;
}
/***************************************************************************
* File: act_wizard.c
*
* Remove the tabs from the list_llog_entries() function.
***************************************************************************/
The \t are tabs, they need to be replaced with something else (like spaces):
while(!feof(fp)) {
send_to_char(ch, "%10s\t%d\t%s\t%s", llast.username, llast.punique,
last_array[llast.close_type], ctime(&llast.time));
i = fread(&llast, sizeof(struct last_entry), 1, fp);
}
For example:
while(!feof(fp)) {
send_to_char(ch, "%10s %d %s %s", llast.username, llast.punique,
last_array[llast.close_type], ctime(&llast.time));
i = fread(&llast, sizeof(struct last_entry), 1, fp);
}
/***************************************************************************
* File: utils.c
*
* Make sure string formatting properly handles MXP/colour/unicode.
***************************************************************************/
Add the following macro at the top of the utils.c file:
#define isspace_ignoretabs(c) ((c)!='\t' && isspace(c))
Then in the strfrmt() function, replace every instance of isspace() with
isspace_ignoretabs(). This will prevent tabs from being discarded.
Immediately after this section of code within strfrmt():
} else if (*sp=='`'||*sp=='$'||*sp=='#'||*sp=='@') {
if (sp[1] && (sp[1]==*sp))
wlen++; /* One printable char here */
if (*sp=='@' && (sp[1]!=*sp)) /* Color code, not @@ */
last_color = sp[1];
sp += 2; /* Eat the whole code regardless */
Add the following:
} else if (*sp=='\t'&&sp[1]) {
char MXPcode = sp[1]=='[' ? ']' : sp[1]=='<' ? '>' : '\0';
sp += 2; /* Eat the code */
if (MXPcode)
{
while (*sp!='\0'&&*sp!=MXPcode)
++sp; /* Eat the rest of the code */
}
/***************************************************************************
* File: comm.c and interpreter.c
*
* Use the new function for switching ECHO on and off.
***************************************************************************/
Replace all calls to the echo_off() function with the following:
ProtocolNoEcho( d, true );
Replace all calls to the echo_on() function with the following:
ProtocolNoEcho( d, false );
The old echo_off() and echo_on() functions in comm.c can be removed.