Here is the promised ASCII map code version 1.0 This was made for CircleMUD 3.0bpl12 but may work in 11 or 13, maybe. I make no guarentees. This is fairly complicated and not your average size snippelet so you may want to read through it before you start applying it to your code. I would like to take this opportunity to thank the coders of Duris and now Basternaee for having such a great map system to be my inspiration. ==========================READ THIS FIRST========================== All the code and ideas contained herein are the intelectual property of Kyle Goodwin. By using any of the code or ideas contained within this document you agree to abide by the rules and conditions listed below: 1) You may not make any monney from the use of this code or the ideas contained within it. 2) You must notify me by email (vbmasta@earthlink.net) if you use this code or the ideas contained within it. 3) You must credit me on the screen displayed when a user first connects to whatever mud this code or te ideaas within it are used on. 4) You may not remove any of the original copyright notices from the code as long as any of it is used. 5) If you redistribute this document you must do so in its entirety including this agreement and all the copyright notices. 6) This code may not be redestributed without my express written consent and redistribution binds you to the same agreement as using the code or ideas. 7) If you are found in breach o this agreement you will be prosecuted the fullest extent f United States and International law. ======================================================================= !! DISCLACMER !! I am not liable for any damage this code or the ideas contained within may cause to your MUD, computer or any other property. You use this code at your own risk. Back things up before you use it so if you screw up or there is a probem with my code you can salvage your old code. I have added races on my mud so there may be a few things you have to take out to get it to compile without my races but that should be pretty simple. ======================================================================= comm.c ====== with the other #includes add #include "maputils.h" -------------------------------------------------------------- with the other external variable declarations at the top add: extern int mapnums[MAP_ROWS][MAP_COLS]; -------------------------------------------------------------- in init_game after #ifdef CIRCLE_UNIX log("Signal trapping."); signal_setup(); #endif add: log("Loading Surface Map. "); //Load the map vnums from a file into an array mapfile = fopen("c:\\surface.map", "r"); //fscanf(mapfile, "%d %d", &MAP_ROWS, &MAP_COLS); for (rowcounter = 0; rowcounter <= MAP_ROWS; rowcounter++) { for (colcounter = 0; colcounter <= MAP_COLS; colcounter++) { fscanf(mapfile, "%d", &vnum_read); mapnums[rowcounter][colcounter] = real_room(vnum_read); } } fclose(mapfile); --------------------------------------------------------------- acct.informative.c ================== with the other includes add: #include "maputils.h" --------------------------------------------------------------- in look_at_room after if (IS_DARK(ch->in_room) && !CAN_SEE_IN_DARK(ch)) { send_to_char("It is pitch black...\r\n", ch); return; } else if (IS_AFFECTED(ch, AFF_BLIND)) { send_to_char("You see nothing but infinite darkness...\r\n", ch); return; } add: /////////////MAP ROOMS//////////////// if (ROOM_FLAGGED(ch->in_room, ROOM_MAP)) { //show map thing printmap(ch->in_room, ch); } /////////////MAP ROOMS//////////////// --------------------------------------------------------------- new file: maputils.c ========== /***************************************************** * maputils.c --- implementation file for ascii maps * * * * Kyle Goodwin, (c) 1998 All Rights Reserved * * vbmasta@earthlink.net - Head Implemenor FirocMUD * *****************************************************/ #include "conf.h" #include "sysdep.h" #include "structs.h" #include "utils.h" #include "comm.h" #include "interpreter.h" #include "handler.h" #include "db.h" #include "spells.h" #include "screen.h" #include "maputils.h" extern struct room_data *world; int mapnums[MAP_ROWS][MAP_COLS]; char *map_chars[] = { " ", /* Inside, not used on map */ "&W&9^&0", /* City, used for entances to zones */ "&2.&0", /* Field */ "&b&2W&0", /* Forrest */ "&3^&0", /* Hills */ "&3M&0", /* Mountains */ "&B&b &0", /* Water */ "&B&b &0", /* Water */ "&B&b &0", /* Water */ " ", /* Flying, not used on map */ "&9&b+&0", /* Road */ "&bP&0", /* Player */ "&4&bM&0", /* NPC */ "\n" }; char *getmapchar(int rnum, struct char_data * ch) { char *mapchar; int roomtype; mapchar = malloc(8); if (world[rnum].people) { if (IS_NPC(world[rnum].people)) mapchar = map_chars[12]; else mapchar = map_chars[11]; } else { roomtype = world[rnum].sector_type; mapchar = map_chars[roomtype]; } return mapchar; } MapStruct findcoord ( int rnum ) { int x=0; int y=0; MapStruct coords; while (y <= MAP_ROWS) { while (x <= MAP_COLS) { if (mapnums[y][x] == rnum) { coords.y = y; coords.x = x; return coords; } x++; } y++; x = 0; } log("SYSERR: findcoord for non-map rnum"); return coords; } void printmap(int rnum, struct char_data * ch) { int x=0; int y=0; int sightradius; char buf[512]; MapStruct coord; coord = findcoord(rnum); strcpy(buf, "\r\n "); if (GET_LEVEL(ch) >= LVL_IMMORT) sightradius = 3; else if ((IS_DARK(rnum) && (ch->player.race >= RACE_EVIL)) || (IS_LIGHT(rnum) && (ch->player.race < RACE_EVIL))) sightradius = 3; else if (IS_LIGHT(rnum) && ((ch->player.race == RACE_DROW) || (ch->player.race == RACE_ILLITHID))) sightradius = 1; else sightradius = 2; for (y = coord.y-sightradius; y <= coord.y+sightradius; y++) { for (x = coord.x-sightradius; x <= coord.x+sightradius; x++) { if (x==coord.x && y==coord.y) strcat(buf, "&b@&0"); else if (x < 0 || y < 0 || y > MAP_ROWS || x > MAP_COLS) strcat(buf, "&B&b &0"); else strcat(buf, getmapchar(mapnums[y][x], ch)); } strcat(buf, "\r\n "); } strcat(buf, "\r\n"); send_to_char(buf, ch); } ------------------------------------------------------------------ new file: maputils.h ========== /***************************************************** * maputils.c --- implementation file for ascii maps * * * * Kyle Goodwin, (c) 1998 All Rights Reserved * * vbmasta@earthlink.net - Head Implemenor FirocMUD * *****************************************************/ #define MAP_ROWS 29 #define MAP_COLS 29 struct mapstruct { int x; int y; }; typedef struct mapstruct MapStruct; MapStruct findcoord(int rnum); char *getmapchar(int rnum, struct char_data * ch); void printmap(int rnum, struct char_data * ch); ------------------------------------------------------------------- structs.h ========= add the following #defines in their appropriate places: #define ROOM_MAP (1 << 16) /* Set to make a room a map room */ #define SECT_ROAD 10 /* For map rooms only */ ------------------------------------------------------------------- For this code tto function correctly you must create a file called c:\sirface.map (or whatever you changed the code to point to in comm.c). This file should contain a grid of the vnums of the map rooms like so: 10001 10002 10003 10004 10005 10006 10007 10008 and so on. You will also have to change the defines for map length and width to be one less than whatever your map is. For the actuall map zone you make a zone that connects correctly so the map makes sence and make eatch room a ROOM_MAP and also give it the correct sector number so when you call a room "The Large Road" it will show up as a "+" on the map. This code will also show mobs as Ms and players as Ps if they hapen to be in a map room you can see. I have written a program which will create these maps very easily and it is listed below. Note that this program is subject to the same agreement tat the acctual MUD code itself is. --------------------------------------------------------------------- #include #include #include #define MAX_MAPLINES 512 #define MAX_CODELINES 512 // function prototypes int GetLine( char *, FILE *, int ); int WriteRoom( FILE *, int, int, int, int, FILE * ); char *LookupCode( char , int, int * ); char *GetField( char *, int , int * ); // globals int countrooms = 1; int grid, world, zone; char *map[MAX_MAPLINES]; // to hold the map lines int maplines, maplinelength; char *codes[MAX_CODELINES]; // to hold the code lines int codelines; int main( int argc, char *argv[] ) { FILE *mapfile, *codefile; // open input files if ( argc == 3 ) { mapfile = fopen( argv[1], "r" ); // open file for input codefile = fopen( argv[2], "r" ); // open file for input } else { printf( "Usage: mapgen mapfile codefile\n" ); return 1; } if ( mapfile == NULL ) { printf(" unable to open file %s\n", argv[1] ); return 1; } if ( codefile == NULL) { printf(" unable to open file %s\n", argv[2] ); return 1; } /*******************/ /* read in the map */ /*******************/ printf( "Reading mapfile...\n" ); // read the grid size, world#, and zone# char temp[256]; GetLine( temp, mapfile, 256 ); if ( strncmp( temp, "GRID : ", 7 ) != 0 ) { printf( "Format error, line 1: Use GRID : gridsize\n" ); return 1; } else { grid = atoi( temp + 7 ); } GetLine( temp, mapfile, 256 ); if ( strncmp( temp, "WORLD NO : ", 11 ) != 0 ) { printf( "Format error, line 2: Use WORLD NO : worldnumber\n" ); return 1; } else { world = atoi( temp + 11 ); } GetLine( temp, mapfile, 256 ); if ( strncmp( temp, "ZONE NO : ", 10 ) != 0 ) { printf( "Format error, line 3: Use ZONE NO : zonenumber\n" ); return 1; } else { zone = atoi( temp + 10 ); } // read the map lines int linesread = 1; int rval; map[0] = new char [256]; maplinelength = GetLine( map[0], mapfile, 256 ); if ( maplinelength < 1 ) { printf( "Error, line 4: map width must be between 1 and 255 characters\n" ); return 1; } for ( int i = 1; i < MAX_MAPLINES; i++ ) { map[i] = new char [256]; rval = GetLine( map[i], mapfile, 256 ); if ( rval == -1 ) { // end of file printf( "%d map lines read\n", linesread ); break; } if ( rval != maplinelength ) { // map line wrong length printf( "Error, line %d: map line is inconsistent length\n", linesread + 4 ); return 1; } ++linesread; } if ( rval != -1 ) { printf( "Error: map is too long. %d map lines read.\n", linesread ); return 1; } maplines = linesread; // check map can be broken up into grid if ( (maplinelength%grid) || (maplines%grid) ) { printf( "Error: map size not divisible by grid size\n" ); printf( "map size %dx%d\n", maplinelength, maplines ); printf( "grid size %dx%d\n", grid, grid ); return 1; } fclose( mapfile ); // output the map file printf("GRID NO : %d\n", grid); printf("WORLD NO : %d\n", world); printf("ZONE NO : %d\n", zone); for ( i = 0; i < maplines; i++ ) { printf( "%s\n", map[i] ); } /*********************/ /* read in the codes */ /*********************/ printf( "\nReading codefile...\n" ); linesread = 0; for ( i = 0; i < MAX_CODELINES; i++ ) { codes[i] = new char [256]; rval = GetLine( codes[i], codefile, 256 ); if ( rval == -1 ) { // end of file printf( "%d code lines read\n", linesread ); break; } if ( rval == -2 ) { // code line too long printf( "Error, line %d: code line too long, must be < 256 chars\n", i + 1 ); return 1; } ++linesread; } if ( rval != -1 ) { printf( "Error: code file is too long, %d lines read\n", linesread ); return 1; } codelines = linesread; fclose( codefile ); // output the codes for ( i = 0; i < codelines; i++ ) { printf( "%s\n", codes[i] ); } /***********************/ /* make the .wld files */ /***********************/ int numwldfiles = (maplinelength/grid)*(maplines/grid); int numwldfilerooms = grid*grid; int xoffset, yoffset; int room, wld; xoffset = 0; // offset of current room relative to original map yoffset = 0; room = world; FILE *gridfile; gridfile = fopen( "vnums.map", "w" ); //open vnum file for ( int wldfile = 0; wldfile < numwldfiles; wldfile++ ) { // do each wild file FILE *outfile; char wldname[256]; wld = wldfile + zone; sprintf( wldname, "%d.wld", wld); outfile = fopen( wldname, "w" ); // open file for writing for ( int wldfileroom = 0; wldfileroom < numwldfilerooms; wldfileroom++ ) { // do each room WriteRoom( outfile, xoffset, yoffset, room, wldfileroom, gridfile ); ++room; } // write the terminating $ fprintf( outfile, "$\n$" ); fclose( outfile ); xoffset = (xoffset+grid)%maplinelength; if ( xoffset == 0 ) yoffset += grid; } fclose(gridfile); return 0; } int WriteRoom( FILE *outfile, int xoff, int yoff, int room, int roomoff, FILE *gridfile ) { long numvector; /* write the room number */ fprintf( gridfile, "%d ", room ); fprintf( outfile, "#%d\n", room ); // calculate location of current room, relative to little map int Xpos = roomoff%grid; int Ypos = roomoff/grid; if (countrooms == maplinelength) { fprintf( gridfile, "\n"); countrooms = 1; } else countrooms++; /* write the room name */ char *temp, description[256]; int length; char symbol = map[yoff + Ypos][xoff + Xpos]; temp = LookupCode( symbol, 1, &length ); strncpy( description, temp, length ); description[length] = '\0'; // add termination character fprintf( outfile, "%s~\n", description ); /* write the map */ /* char asciicode[256]; for (int y = 0; y < grid; y++) { // do a row for (int x = 0; x < grid; x++) { int length; if ((y == Ypos) && (x == Xpos)) fprintf( outfile, "&00&17&11@&00" ); else { symbol = map[yoff + y][xoff + x]; temp = LookupCode( symbol, 0, &length ); // debug - just print char //fprintf( outfile, "%c", symbol ); // write ascii code strncpy( asciicode, temp, length ); asciicode[length] = '\0'; // add termination character fprintf( outfile, "%s", asciicode ); } } fprintf( outfile, "\n"); } */ fprintf( outfile, " \n"); fprintf( outfile, "~\n" ); /* write the zone, bitvector and sector type */ fprintf( outfile, "%d", zone ); char bitvector[256]; temp = LookupCode( symbol, 2, &length ); strncpy( bitvector, temp, length ); bitvector[length] = '\0'; // add termination character numvector = atol(bitvector); numvector += 65536L; ltoa(numvector, bitvector, 10); fprintf( outfile, " %s", bitvector); char sectortype[256]; temp = LookupCode( symbol, 3, &length ); strncpy( sectortype, temp, length ); sectortype[length] = '\0'; // add termination character fprintf( outfile, " %s", sectortype ); fprintf( outfile, "\n" ); /* write the directions/exits out of room */ // North if ( (yoff + Ypos) > 0 ) { fprintf( outfile, "D0\n" ); symbol = map[yoff + Ypos - 1][xoff + Xpos]; temp = LookupCode( symbol, 1, &length ); // write description strncpy( description, temp, length ); description[length] = '\0'; // add termination character fprintf( outfile, "%s\n", description ); // separation chars fprintf( outfile, "~\n~\n" ); // calculate where it goes int nextroom; if ( Ypos > 0 ) nextroom = room - grid; else { //~~BUG Had to put in the + 400 to make map work properly! nextroom = room - (grid * grid) * (grid - 1) - grid + 400; } fprintf( outfile, "%d %d %d\n", 0, -1, nextroom ); } // East if ( (xoff + Xpos + 1) < maplinelength ) { fprintf( outfile, "D1\n" ); symbol = map[yoff + Ypos][xoff + Xpos + 1]; temp = LookupCode( symbol, 1, &length ); // write description strncpy( description, temp, length ); description[length] = '\0'; // add termination character fprintf( outfile, "%s\n", description ); // separation chars fprintf( outfile, "~\n~\n" ); // calculate where it goes int nextroom; if ( Xpos + 1 < grid ) nextroom = room + 1; else { nextroom = room + grid * (grid - 1) + 1; } fprintf( outfile, "%d %d %d\n", 0, -1, nextroom ); } // South if ( (yoff + Ypos) < maplines - 1 ) { fprintf( outfile, "D2\n" ); symbol = map[yoff + Ypos + 1][xoff + Xpos]; temp = LookupCode( symbol, 1, &length ); // write description strncpy( description, temp, length ); description[length] = '\0'; // add termination character fprintf( outfile, "%s\n", description ); // separation chars fprintf( outfile, "~\n~\n" ); // calculate where it goes int nextroom; if ( Ypos + 1 < grid ) nextroom = room + grid; else { //~~BUG Had to put in the - 400 to make map work properly! nextroom = room + (grid * grid) * (grid - 1) + grid - 400; } fprintf( outfile, "%d %d %d\n", 0, -1, nextroom ); } // West if ( (xoff + Xpos - 1) >= 0 ) { fprintf( outfile, "D3\n" ); symbol = map[yoff + Ypos][xoff + Xpos - 1]; temp = LookupCode( symbol, 1, &length ); // write description strncpy( description, temp, length ); description[length] = '\0'; // add termination character fprintf( outfile, "%s\n", description ); // separation chars fprintf( outfile, "~\n~\n" ); // calculate where it goes int nextroom; if ( Xpos > 0 ) nextroom = room - 1; else { nextroom = room - grid * (grid - 1) - 1; } fprintf( outfile, "%d %d %d\n", 0, -1, nextroom ); } // write room termination character fprintf( outfile, "S\n" ); return 0; } char *LookupCode( char code, int field, int *length ) { char *rval; rval = NULL; for ( int i = 0; i < codelines; i++ ) { if ( codes[i][0] == code ) { // found it rval = GetField( codes[i], field, length ); break; } } if ( rval == NULL ) { printf( "ERROR: LookupCode() - could not find code %c, field %d\n", code, field ); exit(1); } return rval; } char *GetField( char *string, int field, int *length ) { // each field consists of a string enclosed in ' // eg. 'string' // fields begin with field 0 char *ptr1, *ptr2; int i; // find start of field ptr1 = string; for ( i = 0; i < field; i++ ) { while ( (*ptr1 != '\'') && (*ptr1 != '\0') ) ++ptr1; if (*ptr1 == '\'') { // foung start of a field, move to end ++ptr1; while ( (*ptr1 != '\'') && (*ptr1 != '\0') ) ++ptr1; if ( *ptr1 == '\'' ) ++ptr1; // end of field } } // now pointing to just after end of field - 1 // move to start of field while ( (*ptr1 != '\'') && (*ptr1 != '\0') ) ++ptr1; if (*ptr1 != '\0') ++ptr1; // move past leading ' // find end of field if (*ptr1 != '\0') { ptr2 = ptr1; while ((*ptr2 != '\'') && (*ptr2 != '\0')) ++ptr2; //*ptr2 = '\0'; } // calc length of field *length = ptr2 - ptr1; if ( (*ptr1 == '\0') || (*ptr2 == '\0') ) { return NULL; // field not found } else return ptr1; } // globals //int grid, world, zone; //char *map[MAX_MAPLINES]; // to hold the map lines //int maplines, maplinelength; //char *codes[MAX_CODELINES]; // to hold the code lines //int codelines; /*******************************************************************/ /* file I/O */ /*******************************************************************/ int GetLine(char *line, FILE *stream, int linelength) { // read in a line, lines longer than linelength chars (includeing \n) are split int temp, i; i = 0; temp = fgetc(stream); while ((temp != '\n') && (temp != EOF) && (i < linelength)) { line[i++] = temp; temp = fgetc(stream); } line[i] = '\0'; if ((feof(stream) != 0) && (i == 0)) return -1; // end of file, no lines read else if (i > linelength) return -2; // line to long else return i; // return number of characters read } --------------------------------------------------------------------- For this program to work and generate both the zone and the surface,map file you must supply it with command line parameters for two files wich will be explained later. I use the following .bat file: del *.wld del vnums.map mapgen.exe map.txt codes.txt copy c:\mapgen\*.wld c:\circle~1\lib\world\wld copy c:\mapgen\vnums.map c:\surface.map --------------------------------------------------------------------- Here are the two files that make the map-generation program work: The first is the code file that specifies what symbols will stand for what in the seccond, map, file. Here is ann example: ~ : '&20 &00','The Open Ocean','0','7'; M : '&08&19M&00','The Western Mountains','0','5'; m : '&08&19M&00','The Eastern Mountains','0','5'; H : '&11&19^&00','The Golden Hills','0','4'; F : '&10&18f&00','The Forrest of Khor','0','3'; f : '&10&18f&00','The Forrest of Begoel','0','3'; . : '&08&18.&00','Endless Plains of Grass','0','2'; A : '&08&23^&00','City of New Thalos','0','1'; B : '&08&23^&00','Dwarven Stronghold','0','1'; C : '&08&23^&00','Elf Homes','0','1'; E : '&08&19M&00','The Western Mountains','0','5'; h : '&07&19^&00','Mountain Foothills','0','1'; W : '&07&19M&00','A Dark Forest','0','3'; s : '&08&18f&00','Hu-Man Green Lands','0','1'; q : '&02&22`&00','Swamp Lands','0','1'; + : '&07+&00','An Ancient Highway Made of Obsedian stone','0','10'; 1 : '&08&19.&00','Flood Planes','0','1'; 2 : '&14&20=&00','River of Kaldon','0','6'; 3 : '&20&06*&00','The Coral Reef of Qquadore','0','1'; b : '&11&19.&00','Sandy Beach','0','1'; ^ : ' ','The City of Midgaard','0','1'; Note that the symbols on the left are just the representations in the map file not the mud and that the seccond column is no longer needed and may be filled with ' ' if you desire. The next column is the name each room using this symbol will be given. The last two columns provide the room bitvectors and sector tags respectively. The final file is the map file with tells this generation program what to put where in the zone and sufae.map files. Here is an example: GRID : 30 WORLD NO : 9000 ZONE NO : 90 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~MMH........MMM............~~ ~~.MMH........MM.........WWW~~ ~~..MMH........MM...++++^.WW~~ ~~M.A+++++......MM..+..WWWW.~~ ~~MMMMH..+++.....MM.+...WWWW~~ ~~.HHHH....+.....MM.+....WWW~~ ~~..WWWWW..+++....M.+++++.WW~~ ~~.WWWWWWW...+......+MMM+...~~ ~~WWWWC++++++++++++++.MMBMMM~~ ~~.WWWWWWW.....+.......MMMMM~~ ~~..WWWWW......+............~~ ~~.............+............~~ ~~.............+............~~ ~~.............+............~~ ~~~~~~~~~~~2222+2222~~~~~~~~~~ ~~~~~~~~~~~2222+2222~~~~~~~~~~ ~~~~~~~~~~~2222+2222~~~~~~~~~~ ~~.............+....MMMMMM..~~ ~~.........++++++....MMMMMM.~~ ~~......++++WWWW+.....MMMMM.~~ ~~.........+WWWW++++++++.MM.~~ ~~.........+WWWW+.......MMM.~~ ~~..+++++++++++++.....MMM.M.~~ ~~M.....+.......+...HHHH....~~ ~~MM.................HH.....~~ ~~MMM...............HHH.....~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Note: Please don't use this exact map because it is the on I use in my mud. OK here's how this file works: First you specify how you want the map broken up into differant .wld files using the GRID: keyword. This number hould never be more than 30 because 30 * 30 = 900 and you don't want more than 999 rooms in any particular zone. The next field specifies the first number too be used as a vnum. After that you just tell it what zone this map will start at although it may use more thhann one if your grid isn't the same size as the map. The last thing you have to do is add the appropriate files to thier respective index files and get them all in the right directories. If I forgoot anything or you have any problems feel free to email me and I hope this will be of use to many people. Kyle Goodwin vbmasta@earthlink.net