Here is the new version of mapsnip patch, now it fits correctly to CircleMUD 3.0bpl21 I would like to take this opportunity to thank Kyle Goodwin (vbmasta@earthlink.net) who wrote the first version of this code for CircleMUD 3.0bpl12, and the coders of Duris and now Basternae for having such a great map system to be his inspiration. ==========================READ THIS FIRST========================== All the code and ideas contained herein are the intelectual property of Kyle Goodwin and Paolo Libardi. 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 us by email (vbmasta@earthlink.net) if you use this code or the ideas contained within it. For the new version code you have to notify to pinkpallin@libero.it 3) You must credit us 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 our 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 !! We are 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 our code you can salvage your old code. ======================================================================= 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 */ ------------------------------------------------------------------- new file: maputils.h ========== /***************************************************** * maputils.h --- implementation file for ascii maps * * * * Kyle Goodwin, (c) 1998 All Rights Reserved * * vbmasta@earthlink.net - Head Implemenor FirocMUD * * * * Paolo Libardi - pinkpallin@libero.it * *****************************************************/ #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); ------------------------------------------------------------------- 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+1][MAP_COLS+1]; -------------------------------------------------------------- in init_game with the other variables add FILE *mapfile; int rowcounter, colcounter; int vnum_read; 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("../lib/surface.map", "r"); 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); --------------------------------------------------------------- act.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)) printmap(ch->in_room, ch); //show map thing /////////////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 * * * * Paolo Libardi - pinkpallin@libero.it * *****************************************************/ #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+1][MAP_COLS+1]; char *map_chars[] = { " ", /* Inside, not used on map */ "^", /* City, used for entances to zones */ ".", /* Field */ "F", /* Forrest */ "C", /* Hills */ "M", /* Mountains */ "~", /* Water */ "\\", /* Water */ "-", /* Water */ " ", /* Flying, not used on map */ "+", /* Road */ "P", /* Player */ "#", /* 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_LIGHT(rnum)) sightradius = 2; else sightradius = 1; 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, "@"); else if (x < 0 || y < 0 || y > MAP_ROWS || x > MAP_COLS) strcat(buf, " "); else strcat(buf, getmapchar(mapnums[y][x], ch)); } strcat(buf, "\r\n "); } strcat(buf, "\r\n"); send_to_char(ch, buf); } ------------------------------------------------------------------- You have also to add maputils files to your Makefile * add maputils.o to the list of OBJFILES * add maputils.c to the list of CXREX_FILES * add maputils.h to the list of act.informative.o file dependencies * add maputils.h to the list of comm.o file dependencies * append next lines to the end of the file maputils.o: maputils.c conf.h sysdep.h structs.h utils.h comm.h interpreter.h \ handler.h db.h spells.h screen.h $(CC) -c $(CFLAGS) maputils.c ------------------------------------------------------------------- For this code to function correctly you must create a file called lib/surface.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 (in maputils.h) to be one less than whatever your map is. For the actual map zone you make a zone that connects correctly so the map makes sence and make each 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. Kyle Goodwine wrote (and Paolo Libardi modified) a program which creates these maps very easily and it is listed below. Note that this program is subject to the same agreement that the actual MUD code itself is. new file: mapgen.cpp ========== #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 ( int i = 0; i < maplines; i++ ) { printf( "%s\n", map[i] ); } */ /*********************/ /* read in the codes */ /*********************/ printf( "\nReading codefile...\n" ); linesread = 0; for ( int 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 ( int 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 ); 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; sprintf(bitvector, "%ld", numvector); 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 */ if ( (yoff + Ypos) > 0 ) { // North 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 ); } if ( (xoff + Xpos + 1) < maplinelength ) { // East 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 ); } if ( (yoff + Ypos) < maplines - 1 ) { // South 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 ); } if ( (xoff + Xpos - 1) >= 0 ) { // West 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 == '\'') { // found 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; } // calc length of field *length = ptr2 - ptr1; if ( (*ptr1 == '\0') || (*ptr2 == '\0') ) return NULL; // field not found else return ptr1; } /*******************************************************************/ /* 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. 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 second, map, file. Here is an 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 different .wld files using the GRID: keyword. This number should 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 than 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 their respective index files and get them all in the right directories. For this example copy 90.wld to lib/world/wld directory and add 90.wld name to the index file in that directory, also add 90.zon to the index file in lib/world/zon directory and copy the file 90.zon in this directory. If I forgot anything or you have any problems feel free to email me and I hope this will be of use to many people. Paolo Libardi pinkpallin@libero.it