Fatal Dimensions - MavEtJu's rom coding part

Fixes

Keep in mind that these are my fixes and might or might not be implemented in the standard RoM-distribution.

Autologoff

Problem

When a player gets auto-logged off other playerfiles can get corrupted.

Cause

The for-loop in char_update doesn’t keep track of the possibility of pets. If a player is auto-logged off and his pet is the next ch_next, player-characters in the freed-characterslist might be saved with invalid strings in their playerfiles.

Patch

In update.c/update_char(), add the following

/*
   * Autosave and autoquit.
   * Check that these chars still exist.
   */
  for ( ch = char_list; ch != NULL; ch = ch_next ) {
+     if (!IS_VALID(ch)) {
+         bug('update_char: Trying to work with an invalidated character.\n'); 
+         break;
+     }

      ch_next = ch->next;

To be sure it never happens again, add this to save.c/save_char_obj():

  if ( IS_NPC(ch) )
      return;

+ //
+ // Don't save if the character is invalidated.
+ // This might happen during the auto-logoff of players.
+ // (or other places not yet found out)
+ //
+ if ( !IS_VALID(ch)) {
+     bug("save_char_obj: Trying to save an invalidated character.\n");
+     return;
+ }
 
  if ( ch->desc != NULL && ch->desc->original != NULL )
      ch = ch->desc->original;

force

Problem

Entering force all quit can corrupt playerfiles.

Cause

The for-loop in the do_force() command doesn’t keep track of the possibility of pets. If a player is forced to quit and his pet is the next vch_next, all player-characters in the freed-characterslist will be saved with invalid strings in their playerfiles.

Patch

Replace in act_wiz.c/do_force():

if ( !str_cmp( arg, "all" ) )
{
    CHAR_DATA *vch;
    CHAR_DATA *vch_next;

    if (get_trust(ch) < MAX_LEVEL - 3) {
	send_to_char("Not at your level!\n\r",ch);
	return;
    }

    for ( vch = char_list; vch != NULL; vch = vch_next ) {
	vch_next = vch->next;

	if ( !IS_NPC(vch) && get_trust( vch ) < get_trust( ch ) ) {
	    act( buf, ch, NULL, vch, TO_VICT );
	    interpret( vch, argument );
	}
    }
}

with

if ( !str_cmp( arg, "all" ) )
{
    DESCRIPTOR_DATA *desc,*desc_next;

    if (get_trust(ch) < MAX_LEVEL - 3) {
	send_to_char("Not at your level!\n\r",ch);
	return;
    }

    for ( desc = descriptor_list; desc != NULL; desc = desc_next ) {
	desc_next = desc->next;

	if (desc->connected==CON_PLAYING &&
	    get_trust( desc->character ) < get_trust( ch ) ) {
	    act( buf, ch, NULL, desc->character, TO_VICT );
	    interpret( desc->character, argument );
	}
    }
}

Same thing should be done for the players-force and the gods-force.


$p

Problem

Entering delete $p crashes the mud.

Cause

When a $p is printed on wiznet, it’s expanded in act_new while it the information required by this expansing isn’t available or valid. This can cause the mud to crash (it will most of the time).

Checking

Login in your mud, make sure you have wiznet on, login with another character, type delete $p. If your mud doesn’t crash you’re not vulnerable.

Patch

In interp.c/interpret(), replace

if ( ( !IS_NPC(ch) && IS_SET(ch->act, PLR_LOG) )
||   fLogAll
||   cmd_table[cmd].log == LOG_ALWAYS )
{
    sprintf( log_buf, "Log %s: %s", ch->name, logline );
    wiznet(log_buf,ch,NULL,WIZ_SECURE,0,get_trust(ch));
    log_string( log_buf );
}

with

if ( ( !IS_NPC(ch) && IS_SET(ch->act, PLR_LOG) )
||   fLogAll
||   cmd_table[cmd].log == LOG_ALWAYS )
{
    char    s[2*MAX_INPUT_LENGTH],*ps;
    int     i;
 
    ps=s; 
    sprintf( log_buf, "Log %s: %s", ch->name, logline );
    /* Make sure that was is displayed is what is typed */
    for (i=0;log_buf[i];i++) { 
	*ps++=log_buf[i];  
	if (log_buf[i]=='$')
	    *ps++='$';
	if (log_buf[i]=='{')
	    *ps++='{';
    }
    *ps=0;
    wiznet(s,ch,NULL,WIZ_LOGS,0,get_trust(ch));
    log_string( log_buf );
}

More $

Problem

It seemed that the $-problem in the previous paragraph gave also problems in the act_new()-function, when you get a string with a $ dollar in it. Perhaps the previous fix was not enough on it’s on, with this is it.

Cause

In act_new(), it’s assumed that all pointers are valid.

Checking

Take a mortal character, let him say “cast ‘bless’ $p” for about 40 times and make sure you have the wiznet-spam option on. If your mud crashes you have to apply the following patch.

Patch

Check the pointers before using them:

   case 't': i = (char *) arg1;                            break;
   case 'T': i = (char *) arg2;                            break;
   case 'n': i = PERS( ch,  to  );                         break;
   case 'N': i = PERS( vch, to  );                         break;
   case 'e': i = he_she  [URANGE(0, ch  ->sex, 2)];        break;
   etc...

should become

   case 't': if (arg1) i=(char *)arg1;
             else bug("Act: bad code $t for 'arg1'",0);
             break;
   case 'T': if (arg2) i=(char *)arg2;
             else bug("Act: bad code $T for 'arg2'",0);
             break;
   case 'n': if (ch&&to) i=PERS(ch,to);
             else bug("Act: bad code $n for 'ch' or 'to'",0);
             break;
   case 'N': if (vch&&to) i=PERS(vch,to);
             else bug("Act: bad code $N for 'ch' or 'to'",0);
             break;
   case 'e': if (ch) i=he_she[URANGE(0,ch->sex,2)];
             else bug("Act: bad code $e for 'ch'",0);
             break;
   etc...
             break;
             break;
             break; // BREAK IT! :-)

Thanks

Thanks to the guy from primenet for telling me the problem (although it was already fixed in our code :-)


Alias

Problem

When assigning alias x to goto 3001 and executing the command x it comes back with a No such location.

Cause

When expanding an alias substitute_alias() always adds a space and the arguments to the command. do_goto() then checks if “goto 3001 “ is an valid location (which it isn’t).

Checking

Login to your mud, alias x to goto 3001, execute x. If you get No such location, you have to apply the patch.

Patch

In alias.c/substitute_alias(), replace

buf[0] = '\0';
strcat(buf,ch->pcdata->alias_sub[alias]);
strcat(buf," ");
strcat(buf,point);</pre>

with

buf[0] = '\0';
strcat(buf,ch->pcdata->alias_sub[alias]);
if (point[0]) {
    strcat(buf," ");
    strcat(buf,point);
}

More alias’s

Problem

When entering an alias with a ‘ (tick) in it, it will screw up the player-file.

Checking

Create an alias with a ‘ in it, for example ’ ‘hi. Quit the character and enter the mud again. If you type alias, it will display a lot of skill/inventory information also in the alias-list.

Patch

In alias.c/do_alias(), add the following lines:

    if (!str_prefix("una",arg) || !str_cmp("alias",arg)) {                   
	send_to_char("Sorry, that word is reserved.\n\r",ch);
	return;  
    }

+   if (strchr(arg,' ')||strchr(arg,'"')||strchr(arg,'\'')) {      
+	send_to_char("The word to be aliased should not contain a space, "
+	    "a tick or a double-quote.\n\r",ch);
+	return;
+   }   

    if (argument[0] == '\0')
    {

Notes

Problem

When continueing with a note which is too long the mud crashes.

Cause

The function string.c/string_addline() checked for the length of the variable buf which while this should have been *ch->desc->pString.

Checking

Make a note. A long note. A very long note. Wait until it’s long enough to get the message String too long, last line skipped.. Type note edit. Add a line. If the mud now crashes you have to apply the patch.

Patch

In string.c/string_addline(), replace

/*
* Truncate strings to MAX_STRING_LENGTH.
* --------------------------------------
*/
if ( strlen( buf ) + strlen( argument ) >= ( MAX_STRING_LENGTH - 4 ) )
{   
    send_to_char( "String too long, last line skipped.\n\r", ch );

with

/*
* Truncate strings to MAX_STRING_LENGTH.
* --------------------------------------
*/
if ( strlen( *ch->desc->pString ) + strlen( argument ) >= ( MAX_STRING_LENGTH - 4 ) )
{   
    send_to_char( "String too long, last line skipped.\n\r", ch );

Double newbies

Problem

If a person opens two telnet sessions and enters twice the same newbie-name, two players with that name are created on the mud.

Cause

It’s a race-problem: as long as the player-file isn’t saved to disc newbies with this name are accepted.

Checking

Open two telnet-sessions to your mud, in both fill in the same name. Complete the creation procedure for both. Check with who who is online.

Patch

I’ve patched it by adding a new check to comm.c/check_parse_name() function:

    /*
     * check names of people playing. Yes, this is necessary for multiple
     * newbies with the same name (thanks Saro)
     */
    if (descriptor_list) {
        count=0;
        for (d = descriptor_list; d != NULL; d = dnext) {
            dnext=d->next;
            if (d->connected!=CON_PLAYING&&d->character&&d->character->name
                && d->character->name[0] && !str_cmp(d->character->name,name)) {
                count++;
                close_socket(d);
            }
        }
        if (count) {
            sprintf(log_buf,"Double newbie alert (%s)",name);
            wiznet(log_buf,NULL,NULL,WIZ_LOGINS,0,0);

            return FALSE;
        }
    }

Ghost-pets

Problem

Sometimes a player seems to have two or more pets in his group. These pets are not locatable via mwhere.

Cause

It is not sure in how much this is the only cause, but it’s related to getting linkdead, disappearing into void and reconnecting.

Checking

Extend do_mwhere() with the following code:

    /* all the mobs without a room */
    if (!str_cmp(argument,"nowhere")) {
        buffer = new_buf();
        found=FALSE;
        count=0;
        for ( victim = char_list; victim != NULL; victim = victim->next ) {
            if (victim->in_room==NULL) {
                found = TRUE;
                count++;
                sprintf( buf, "%3d) [%5d] %-28s %lx\n\r", count,
                    IS_NPC(victim) ? victim->pIndexData->vnum : 0,
                    IS_NPC(victim) ? victim->short_descr : victim->name,
                    (unsigned long)victim);
                add_buf(buffer,buf);
            }
        }
        if (found) 
            page_to_char(buf_string(buffer),ch);
        else
            send_to_char("No mobs without rooms found.\n\r",ch);
        free_buf(buffer);
        return;
    }

This will display, when you enter mwhere nowhere, all the mobs who aren’t in a room.

Now login with a test-puppet, let him buy a pet, make him link-dead, let him disappear into void and reconnect. Then do the *mwhere nowhere command, you’ll see that one mob is in there (perhaps try it more than once, also reconnecting without making linkdead gives often the same effect).

Patch

In comm.c, add this code to check_reconnect():

            else {
+               if (d->character->pet) {
+                   CHAR_DATA *pet=d->character->pet;
+
+                   char_to_room(pet,get_room_index( ROOM_VNUM_LIMBO));
+                   stop_follower(pet);
+                   extract_char(pet,TRUE);
+               }
                free_char( d->character );
                d->character = ch;
                ch->desc     = d;</pre>

Cause

It seemed that if you enter the game but type the wrong password, there also will popup a ghost-pet.

Patch

In comm.c/nanny, add this code to the CON_GET_OLD_PASSWORD case:

        if ( strcmp( crypt( argument, ch->pcdata->pwd ), ch->pcdata->pwd ))
        {       
            sprintf( log_buf, "Denying access to %s@%s (bad password).",
                ch->name, d->host );
            log_string( log_buf ); 
            wiznet(log_buf,NULL,NULL,WIZ_LOGINS,0,get_trust(ch));
            write_to_buffer( d, "Wrong password.\n\r", 0 );

+           if (d->character->pet) {
+               CHAR_DATA *pet=d->character->pet;
+
+               char_to_room(pet,get_room_index( ROOM_VNUM_LIMBO));
+               stop_follower(pet);
+               extract_char(pet,TRUE);
+           }   
            close_socket( d );
            return; 
        }

Prefix

Problem

When having a prefix and the command entered is too long, the mud will crash.

Cause

The length of the prefix and the length of the command are incorrectly checked against the length of the string they have to form.

Checking

Set your prefix to : and enter a command too long. First a function in comm.c will complain, then your mud will crash.

Patch

In alias.c/substitute_alias(), fix the next lines:

/* check for prefix */
if (ch->prefix[0] != '\0' && str_prefix("prefix",argument)) {
-   if (strlen(ch->prefix) + strlen(argument) > MAX_INPUT_LENGTH)
+   if (strlen(ch->prefix) + strlen(argument) > MAX_INPUT_LENGTH-2)
	send_to_char("Line to long, prefix not processed.\r\n",ch);
    else {   
	sprintf(prefix,"%s %s",ch->prefix,argument);
	argument = prefix;
    }
}