This the code to make the trailto command, an idea I got from a coffeemud command but this code was written from scratch using the track code. What it does is take a start and and end point, and return a string of directions between them. You can specify either a room vnum or a character/mob for either of the arguments. This can be a handy command for immortals trying to give directions to a lost newbie, or can even be used to compile a list of walking directions to popular places etc. Example output: Path: 3w, 2n, u, 5n, e. Installation: In Track.cpp: Find the function find_first_step and change the function header from int find_first_step (CRoomIndexData *src, CRoomIndexData *target, int maxdist) to int find_first_step (CRoomIndexData *src, CRoomIndexData *target, int maxdist, BOOL bBetweenAreas = FALSE) This adds another argument to find_first_step that defaults to FALSE, but if you call it with the argument set to TRUE the function will work between areas. You won't have to make any changes to do_track this way because it'll default to FALSE for the calls from that function. You could easily make it so that do_track will work between areas as well though, or make a more advanced tracking skill even... down in the function itself change if (src->GetArea () != target->GetArea ()) return BFS_NO_PATH; to if (!bBetweenAreas && src->GetArea () != target->GetArea ()) return BFS_NO_PATH; //Add this to mud.h/smaug.h by the dir_name definition extern char* const short_dir_name []; Add this to act_move.cpp or wherever dir_name is defined : //Make sure these are kept in sync with dir_name above, used to construct //whole path strings and make them a lot shorter character-wise - Kurgan char * const short_dir_name [] = { "n", "e", "s", "w", "u", "d", "ne", "nw", "se", "sw", "somewhere" }; Add the following two functions to track.cpp: //Function will return a string containing the full path from start to dest // (providing the way to get there isn't a mptransfer or somesuch) - Kurgan char *get_path_string(CRoomIndexData *start, CRoomIndexData *dest) { static char buf[MAX_STRING_LENGTH*2]; char temp [MAX_STRING_LENGTH]; int last_dir = -1; int dircount = 0; //used to count how many times we move in the same direction CRoomIndexData *curr_room = NULL; //room we're currently checking from CExitData *pExit = NULL; //used to get curr_room int dir = -1; //What direction we're moving next buf[0] = '\0'; //Couple of checks if (!start) { bug ("Function get_path_string: NULL start room."); return NULL; } if (!dest) { bug ("Function get_path_string: NULL dest room."); return NULL; } curr_room = start; BOOL done = FALSE; //Start our big loop here while (!done) { //If there's ever a problem with finding a path to a place //that can be walked to on the mud, can increase the distance //here I suppose dir = find_first_step (curr_room, dest, 1000000, TRUE); switch (dir) { case BFS_ERROR: bug ("Function get_path_string: Error finding path."); return NULL; case BFS_ALREADY_THERE: done = TRUE; break; case BFS_NO_PATH: return NULL; default: break; } if (!done) { pExit = get_exit (curr_room, dir); curr_room = pExit->GetToRoom (); //Keep track of how many times we go the same direction so we can do output //like 3E, 2SE, N, NE, 5E etc. if (last_dir == -1) { dircount = 1; last_dir = dir; } else { if (dir != last_dir) { if (dircount > 1) sprintf (temp, "%d%s, ", dircount, short_dir_name[last_dir]); else sprintf (temp, "%s, ", short_dir_name[last_dir]); strcat (buf, temp); last_dir = dir; dircount = 1; } else ++dircount; } if (curr_room->vnum == dest->vnum) { if (dircount > 1) sprintf (temp, "%d%s.", dircount, short_dir_name[dir]); else sprintf (temp, "%s.", short_dir_name[dir]); strcat (buf, temp); } } } return buf; } //Function to find and return a string of directions to and from: // 1) character calling to specified character // 2) character specified to another character specified. // 3) character calling to a specified vnum // 4) specified vnum to another specified vnum // or any combination of the above: eg. specified vnum to character specified void do_trailto (CCharacter *ch, char *argument) { char arg1[MAX_INPUT_LENGTH]; char arg2[MAX_INPUT_LENGTH]; CRoomIndexData *start = NULL; CRoomIndexData *dest = NULL; CCharacter *start_ch = NULL; CCharacter *dest_ch = NULL; int svnum = 0; int dvnum = 0; char *buf = NULL; argument = one_argument (argument, arg1); argument = one_argument (argument, arg2); //Can't just trailto nothing.... if (arg1[0] == '\0') { ch->SendText ("Usage: trailto [character/roomvnum]\n\r"); return; } //Now we need to get which arguments are which and get out starting //and destination points. if (arg2[0] == '\0') { //If only one argument specified we make the starting point //the calling character's room if ((start = ch->GetInRoom ()) == NULL) { bug ("Function do_trailto: NULL ch->GetinRoom ()"); return; } //Now see if the argument given is in the form of a vnum or a //character/mob name if (is_number (arg1)) { dvnum = atoi(arg1); if (dvnum < 1 || dvnum > 2097152000) { bug ("Function do_trailto: destination vnum out of range."); return; } if ((dest = RoomTable.GetRoom (dvnum)) == NULL) { bug ("Function do_trailto: NULL destination room (%d).", dvnum); return; } } else { if ((dest_ch = get_char_world (ch, arg1)) == NULL) { ch->SendText ("Target character/mob not found.\n\r"); return; } if ((dest = dest_ch->GetInRoom ()) == NULL) { bug ("Function do_trailto: NULL dest_ch->GetInRoom ()."); return; } } } //Two arguments specified so let's see what we got else { //see if the arg1 is in the form of a vnum or a //character/mob name if (is_number (arg1)) { svnum = atoi(arg1); if (svnum < 1 || svnum > 2097152000) { bug ("Function do_trailto: start vnum out of range."); return; } if ((start = RoomTable.GetRoom (svnum)) == NULL) { bug ("Function do_trailto: NULL start room (%d).", dvnum); return; } } else { if ((start_ch = get_char_world (ch, arg1)) == NULL) { ch->SendText ("Start character/mob not found.\n\r"); return; } if ((start = start_ch->GetInRoom ()) == NULL) { bug ("Function do_trailto: NULL start_ch->GetInRoom ()."); return; } } //see if the arg2 is in the form of a vnum or a //character/mob name if (is_number (arg2)) { dvnum = atoi(arg2); if (dvnum < 1 || dvnum > 2097152000) { bug ("Function do_trailto: destination vnum out of range."); return; } if ((dest = RoomTable.GetRoom (dvnum)) == NULL) { bug ("Function do_trailto: NULL destination room (%d).", dvnum); return; } } else { if ((dest_ch = get_char_world (ch, arg2)) == NULL) { ch->SendText ("Destination character/mob not found.\n\r"); return; } if ((dest = dest_ch->GetInRoom ()) == NULL) { bug ("Function do_trailto: NULL dest_ch->GetInRoom ()."); return; } } } //Okay, at this point we presumably have our start and dest rooms. if (start->vnum == dest->vnum) { ch->SendText ("No need to find a path...they're already in the same spot...\n\r"); return; } //This next little bit is actually the guts of the thing... if ((buf = get_path_string (start, dest)) == NULL) { ch->SendText ("Unable to find a path for some reason...\n\r"); return; } set_char_color (AT_GREEN, ch); ch->SendTextf ("Path: %s\n\r", buf); return; } Add table entries in Skills.cpp for do_trailto like any other command. Also add a DO_FUN entry in smaug.h with the rest of the commands. Clean and compile, and make the trailto command online with cedit. cedit trailto create do_trailto This command is meant to be for immortals so the level should be set to 51 or higher. Note: My code compiles without having to pre-declare local functions headers so if you have a problem you might need to add the function prototype for get_path_string near the beginning of track.cpp And that's all there is to it. This code was developed on a highly modified SmaugWiz 2.02 codebase, but it should work fine with the stock code (I hadn't made any changes to the tracking code prior to writing this). Use it, abuse it. Change it to be better if you like. Enjoy. I've ported over -lots- of smaug code to SmaugWiz, so I don't think it would be very hard to port this over to regular smaug code, but that's up to anyone who wants to do it.