/*************************************************************************** * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * * * Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * * * Ack 2.2 improvements copyright (C) 1994 by Stephen Dooley * * * * In order to use any part of this Merc Diku Mud, you must comply with * * both the original Diku license in 'license.doc' as well the Merc * * license in 'license.txt'. In particular, you may not remove either of * * these copyright notices. * * * * _/ _/_/_/ _/ _/ _/ ACK! MUD is modified * * _/_/ _/ _/ _/ _/ Merc2.0/2.1/2.2 code * * _/ _/ _/ _/_/ _/ (c)Stephen Zepp 1998 * * _/_/_/_/ _/ _/ _/ Version #: 4.3 * * _/ _/ _/_/_/ _/ _/ _/ * * * * http://ackmud.nuc.net/ * * zenithar@ackmud.nuc.net * * Much time and thought has gone into this software and you are * * benefitting. We hope that you share your changes too. What goes * * around, comes around. * ***************************************************************************/ /* This code inspired by a snippet from : */ /************************************************************************/ /* mlkesl@stthomas.edu =====> Ascii Automapper utility */ /* Let me know if you use this. Give a newbie some _credit_, */ /* at least I'm not asking how to add classes... */ /* Also, if you fix something could ya send me mail about, thanks */ /* PLEASE mail me if you use this or like it, that way I will keep it up*/ /************************************************************************/ /* * Ported to DOTDII MUD (http://www.dotd.com) by Garil 6-15-99 */ #include <ctype.h> /* for isalpha */ #include <string.h> #include <stdlib.h> #include <stdio.h> #include <time.h> #include "ackmapper.h" #define safe_strcat(len, dest, src) strncat((dest), (src), (len)-strlen(dest)) int door_marks[4][2] ={ {-1, 0},{ 0, 1},{ 1, 0},{ 0,-1} }; int offsets[4][2] ={ {-2, 0},{ 0, 2},{ 2, 0},{ 0,-2} }; #define SECT_HERE SECT_MAX #define SECT_UNSEEN ( SECT_MAX + 1 ) #define SECT_BLOCKED ( SECT_UNSEEN + 1 ) #define SECT_TOP ( SECT_BLOCKED + 1 ) const struct map_info_type door_info[] = { { DOOR_LOCKED, "&r" , "#&w", "", "Locked door" }, { DOOR_OPEN, "&W" , " &w", "", "Open door" }, { DOOR_CLOSED, "&R" , "#&w", "", "Closed Door" }, { DOOR_NS, "&W" , "|&w", "", "N/S Exit" }, { DOOR_EW, "&W" , "-&w", "", "E/W Exit" }, { DOOR_NULL, "&w", "#&w", "", "Invalid" } }; const struct map_info_type map_info[] = { { SECT_INSIDE, "&P", "o", "", "inside" }, { SECT_CITY, "&w", "o", "", "city" }, { SECT_FIELD, "&G", "o", "", "field" }, { SECT_FOREST, "&g", "o", "&W", "forest" }, { SECT_HILLS, "&Y", "^", "&W", "hills" }, { SECT_MOUNTAIN, "&O", "^", "", "mountain" }, { SECT_WATER_SWIM, "&B", "o", "", "shallow water" }, { SECT_WATER_NOSWIM, "&b", "o", "", "deep running water" }, { SECT_UNDERWATER, "&B", "^", "", "underwater" }, { SECT_AIR, "&w", "a", "", "air" }, { SECT_DESERT, "&O", "o", "", "desert" }, { SECT_DUNNO, "&w", "?", "", "dunno" }, { SECT_OCEANFLOOR, "&B", "~", "", "ocean floor" }, { SECT_UNDERGROUND, "&w", "u", "", "underground" }, { SECT_LAVA, "&r", "o", "", "lava" }, { SECT_SWAMP, "&G", "^", "", "swamp" }, { SECT_BLOCKED, "&w", "~", "", "blocked" }, { SECT_UNSEEN, "&w", " ", "", "unknown" }, { SECT_HERE, "&r", "@", "", "you!" }, { SECT_TOP, "&Y", "~", "", "bad sector type" } }; char * get_sector_display( int sector ) { sh_int looper; for ( looper = 0; ; looper++ ) if ( ( map_info[looper].sector_type == sector ) || ( map_info[looper].sector_type == SECT_TOP ) ) break; return ( map_info[looper].display_code ); } char * get_sector_color( int sector ) { sh_int looper; for ( looper = 0; ; looper++ ) if ( ( map_info[looper].sector_type == sector ) || ( map_info[looper].sector_type == SECT_TOP ) ) break; return ( map_info[looper].display_color ); } char * get_invert_color( int sector ) { sh_int looper; for ( looper = 0; ; looper++ ) if ( ( map_info[looper].sector_type == sector ) || ( map_info[looper].sector_type == SECT_TOP ) ) break; return ( map_info[looper].invert_color ); } char * get_door_display( int door ) { sh_int looper; for ( looper = 0; ; looper++ ) if ( ( door_info[looper].sector_type == door ) || ( door_info[looper].sector_type == DOOR_NULL ) ) break; return ( door_info[looper].display_code ); } char * get_door_color( int door ) { sh_int looper; for ( looper = 0; ; looper++ ) if ( ( door_info[looper].sector_type == door ) || ( door_info[looper].sector_type == DOOR_NULL ) ) break; return ( door_info[looper].display_color ); } char * get_sector_name( int sector ) { sh_int looper; for ( looper = 0; ; looper++ ) if ( ( map_info[looper].sector_type == sector ) || ( map_info[looper].sector_type == SECT_TOP ) ) break; return ( map_info[looper].desc ); } /* * This code written by Altrag for Ack!Mud */ #define iseol(c) ((c)=='\n' || (c)=='\r') /* Like one_argument but saves case, and if len isnt NULL, fills it in * with the length. Also accounts for color. Does NOT account for * quoted text. */ char *break_arg(char *str, char *first_arg, int bufsize, int max, int *buflen, int *len) { int slen=0; char *arg; while (isspace(*str)) ++str; if (*str=='\\' && str[1]=='b' && str[2]=='r') { strcpy(first_arg, "\n\r"); if (buflen) *buflen=0; if (len) *len=0; str+=3; while (isspace(*str)) ++str; return str; } arg=first_arg; while (*str && arg-first_arg<bufsize && slen<max) { if (isspace(*str)) { ++str; break; } else if (*str=='@' && str[1]=='@' && str[2]!='\0') { if (arg-first_arg>=max-3) break; *arg++=*str++; *arg++=*str++; *arg++=*str++; } else if (*str=='\\' && str[1]=='b' && str[2]=='r') break; else { *arg++=*str++; ++slen; } } *arg='\0'; if (len) *len=slen; if (buflen) *buflen=arg-first_arg; while (isspace(*str)) ++str; return str; } char *string_justify(char *str, int len, int width, int numwords, int *rlen) { static char buf[MAX_STRING_LENGTH]; char arg[MAX_INPUT_LENGTH]; int minspaces = numwords-1; int spaces_needed; float space_ratio, space_between; int i, j = 0, alen; char *bp = buf; spaces_needed = minspaces+(width-(len+1)); if (spaces_needed<=minspaces || minspaces<=0) { sprintf(buf, "%s\n\r", str); return buf; } space_ratio = (float)spaces_needed/(float)minspaces; space_between = space_ratio; for (i = 0; i < minspaces; ++i) { str = break_arg(str, arg, sizeof(arg), width, &alen, NULL); strcpy(bp, arg); bp += alen; for (; j < (int)(space_between+0.5); ++j) *bp++ = ' '; space_between += space_ratio; } str = break_arg(str, arg, sizeof(arg), width, &alen, NULL); strcpy(bp, arg); bp += alen; /* bp += sprintf(bp, "\n\r%d:%d:%d", len, width, numwords); bp += sprintf(bp, "\n\r%d:%d:%f", minspaces, spaces_needed, space_ratio);*/ *bp++ = '\n'; *bp++ = '\r'; *bp = '\0'; if (rlen) *rlen = bp-buf; return buf; } char last_color(char *str) { char *end; for (end=str+strlen(str)-2; end > str; --end) if (*end == '@' && end[-1]=='@') return end[1]; return '\0'; } char *string_format(char *str, int *numlines, int width, int height, bool unjust) { static char ret[MAX_STRING_LENGTH]; char buf[MAX_STRING_LENGTH]; char arg[MAX_INPUT_LENGTH]; int alen; int blen=0; char *pbuf=buf, *pret=ret; int len; int currline = 0; int last; char *sp; char c; int numwords = 0; int jlen; --height; --width; *pret='\0'; for (sp = break_arg(str, arg, sizeof(arg), width, &len, &alen); *arg; sp = break_arg(sp, arg, sizeof(arg), width, &len, &alen)) { blen += alen; if (blen+1>=width || iseol(*arg)) { *pbuf++='\n'; *pbuf++='\r'; *pbuf='\0'; c = last_color(buf); if (unjust || iseol(*arg)) { strcpy(pret, buf); pret += pbuf-buf; } else { strcpy(pret, string_justify(buf, blen-alen, width, numwords, &jlen)); pret += jlen; } pbuf=buf; if (++currline>height) break; if (c) { *pbuf++='@'; *pbuf++='@'; *pbuf++=c; } blen=alen; if (iseol(*arg)) *arg='\0'; numwords = 0; } else if (pbuf>buf) { if (pbuf-buf>2 && pbuf[-2]=='@' && pbuf[-3]=='@') { if (pbuf-buf==3) last=0; else last=-4; } else last=-1; if (last) { if (unjust && pbuf[last]=='.') *pbuf++=' ', ++blen; // if (!iseol(pbuf[last])) *pbuf++=' ', ++blen; } } strcpy(pbuf, arg); pbuf+=len; ++numwords; } if (pbuf>buf) { if (pbuf-buf>2 && pbuf[-2]=='@' && pbuf[-3]=='@') { if (pbuf-buf==3) last=0; else last=-4; } else last=-1; if (last && pbuf[last]!='\n' && pbuf[last]!='\r') { *pbuf++='\n'; *pbuf++='\r'; ++currline; } } *pbuf='\0'; strcpy(pret, buf); if (numlines) *numlines=currline; return ret; } char *map_format(char *str, int start, char map[MAP_Y][MAX_STRING_LENGTH], int *numlines, int term_width, int height, bool unjust) { static char ret[MAX_STRING_LENGTH]; char buf[MAX_STRING_LENGTH]; char arg[MAX_INPUT_LENGTH]; int width = (start<MAP_Y ? term_width-15 : term_width-1); int alen; int blen=0; char *pbuf=buf, *pret=ret; int len; int currline = start; int last; char *sp; char c; int numwords = 0; int jlen; --height; *pret='\0'; for (sp = break_arg(str, arg, sizeof(arg), width, &len, &alen); *arg; sp = break_arg(sp, arg, sizeof(arg), width, &len, &alen)) { blen += alen; if (blen+1>=width || iseol(*arg)) { *pbuf++='\n'; *pbuf++='\r'; *pbuf='\0'; c = last_color(buf); if (currline<MAP_Y) pret += sprintf(pret, "%s ", map[currline]); else if (currline==MAP_Y) strcpy(pret, " "), pret+=14; if (unjust || iseol(*arg)) { strcpy(pret, buf); pret += pbuf-buf; } else { strcpy(pret, string_justify(buf, blen-alen, width, numwords, &jlen)); pret += jlen; } if (currline==MAP_Y) width=term_width-1; pbuf=buf; if (++currline>height) break; if (c) { *pbuf++='@'; *pbuf++='@'; *pbuf++=c; } blen=alen; if (iseol(*arg)) *arg='\0'; numwords = 0; } else if (pbuf>buf) { if (pbuf-buf>2 && pbuf[-2]=='@' && pbuf[-3]=='@') { if (pbuf-buf==3) last=0; else last=-4; } else last=-1; if (last) { if (unjust && pbuf[last]=='.') *pbuf++=' ', ++blen; // if (!iseol(pbuf[last])) *pbuf++=' ', ++blen; } } strcpy(pbuf, arg); pbuf+=len; ++numwords; } /* sprintf(bug_buf, "%d:%d", width, blen); monitor_chan(bug_buf, MONITOR_DEBUG);*/ if (pbuf>buf) { if (pbuf-buf>2 && pbuf[-2]=='@' && pbuf[-3]=='@') { if (pbuf-buf==3) last=0; else last=-4; } else last=-1; if (last && pbuf[last]!='\n' && pbuf[last]!='\r') { *pbuf++='\n'; *pbuf++='\r'; if (currline<MAP_Y) pret += sprintf(pret, "%s ", map[currline]); else if (currline==MAP_Y || (currline==MAP_Y+1 && blen<=term_width-15)) strcpy(pret, " "), pret+=14; ++currline; } } *pbuf='\0'; strcpy(pret, buf); if (numlines) *numlines=currline; return ret; } char *exit_string( CHAR_DATA * ch, ROOM_INDEX_DATA *r) { EXIT_DATA *e; static char buf[128]; strcpy(buf, "["); for (e = r->first_exit; e; e=e->next) if (e->to_room && !str_cmp( "", e->keyword) ) { if ( IS_SET( e->exit_info, EX_CLOSED ) ) { if ( IS_SET( e->exit_info, EX_HIDDEN ) ) { continue; } else //if (( IS_NPC( ch ) ? 50 : ch->pcdata->learned[gsn_find_doors] ) > number_percent() ) { sprintf(buf+strlen(buf), " (%s)", dir_name[e->vdir] ); } } else { sprintf(buf+strlen(buf), " %s", dir_name[e->vdir]); } } strcat(buf, " ]"); return buf; } void show_char_to_char( CHAR_DATA *list, CHAR_DATA *ch ); void disp_map(char *border, char *map, CHAR_DATA *ch) { int cols=80; int rows=9999; char bufs[MAP_Y][MAX_STRING_LENGTH]; char disp[MAX_STRING_LENGTH]; int y, ty=MAP_Y-1; char *x, *ox; strcpy(bufs[0], border); strcpy(bufs[ty], border); x = map; for (y = 1; y < ty && *x; ++y) { while (*x=='\n' || *x=='\r') ++x; ox = x; while (*x!='\n' && *x!='\r' && *x!='\0') ++x; sprintf(bufs[y], "%.*s", (x-ox), ox); } strcpy(disp, map_format("", 0, bufs, &y, cols, rows, TRUE)); strcat(disp, map_format(ch->in_room->description, y, bufs, &y, cols, rows, TRUE)); /* remarked out this line of code so i could display the exits in a different spot strcat(disp, map_format(exit_string(ch, ch->in_room), y, bufs, &y, cols, rows, TRUE)); */ if (y<MAP_Y) { x = disp+strlen(disp); while (y<MAP_Y) x += sprintf(x, "%s\n\r", bufs[y]), ++y; } send_to_char(disp, ch); /*added these 3 lines to displeay the edits different and to also show the mobs and objects in the room Tommi*/ do_exits( ch, "auto" ); show_list_to_char( ch->in_room->first_content, ch, FALSE, FALSE ); show_char_to_char( ch->in_room->first_person, ch ); return; } int map[MAX_MAP][MAX_MAP]; void MapArea(ROOM_INDEX_DATA *room, CHAR_DATA *ch, int x, int y, int min, int max, int line_of_sight ) { // CHAR_DATA * victim; // int looper; EXIT_DATA *door; sh_int door_type = 0; if ( map[x][y] < 0 ) return; /* it's a door, not a room in the map */ /* marks the room as visited */ map[x][y]=room->sector_type; /* displays seen mobs nearby as numbers for ( looper = 0, victim = room->first_person; victim; victim = victim->next_in_room ) if ( can_see( ch, victim, FALSE ) && !is_same_group( ch, victim ) ) looper++; if ( looper > 0 ) sprintf( contents[x][y].string, "&B%i&x", UMIN( looper, 9 ) ); else contents[x][y].string[0] = '\0';*/ for ( door = room->first_exit; door; door=door->next ) { if (door->vdir == DIR_NORTHEAST || door->vdir == DIR_NORTHWEST || door->vdir == DIR_SOUTHEAST || door->vdir == DIR_SOUTHWEST || door->vdir == DIR_UP || door->vdir == DIR_DOWN) continue; if (x<min || y<min || x>max || y>max) return; if ( !get_exit_to(door->to_room, rev_dir[door->vdir], room->vnum) ) { map[x][y]=SECT_BLOCKED; /* one way into area OR maze */ return; } /* selects door symbol */ door_type = 0; if ( !IS_SET(door->exit_info, EX_ISDOOR) ) { if ( door->vdir == DIR_NORTH || door->vdir == DIR_SOUTH ) door_type = DOOR_NS; else door_type = DOOR_EW; } else if ( IS_SET( door->exit_info, EX_LOCKED ) ) { door_type = DOOR_LOCKED; } else if ( IS_SET( door->exit_info, EX_CLOSED ) ) { door_type = DOOR_CLOSED; } else door_type = DOOR_OPEN; if ( !IS_NPC( ch ) && !str_cmp( door->keyword, "" ) && ( door_type <= DOOR_OPEN || !IS_SET(door->exit_info, EX_ISDOOR) || ( IS_SET( door->exit_info, EX_CLOSED ) && !IS_SET( door->exit_info, EX_HIDDEN ) && !str_cmp( door->keyword, "" ) ) ) ) // ch->pcdata->learned[gsn_find_doors] > number_percent() && { map[x+door_marks[door->vdir][0]][y+door_marks[door->vdir][1]]=door_type; if ( door_type < DOOR_CLOSED && ( line_of_sight == LOS_INITIAL || door->vdir == line_of_sight ) && map[x+offsets[door->vdir][0]][y+offsets[door->vdir][1]]==SECT_UNSEEN ) { MapArea(door->to_room, ch, x+offsets[door->vdir][0], y+offsets[door->vdir][1], min, max, line_of_sight==LOS_INITIAL?door->vdir:line_of_sight ); } } } return; } void ShowRoom( CHAR_DATA *ch, int min, int max, int size, int center ) { // void disp_map(char *border, char *map, CHAR_DATA *ch); int x,y, looper; char outbuf[MAX_STRING_LENGTH]; char catbuf[MAX_STRING_LENGTH]; char borderbuf[MAX_STRING_LENGTH]; char colorbuf[MAX_STRING_LENGTH]; char displaybuf[MAX_STRING_LENGTH]; outbuf[0] = '\0'; sprintf( outbuf, "%s", "\n\r" ); sprintf( borderbuf, "%s", "+" ); for ( looper = 0; looper <= size+1; looper++ ) { sprintf( catbuf, "%s", "-" ); safe_strcat( MAX_STRING_LENGTH, borderbuf, catbuf ); } safe_strcat( MAX_STRING_LENGTH, borderbuf, "+" ); for (x = min; x <= max; ++x) { /* every row */ safe_strcat( MAX_STRING_LENGTH, outbuf, "| " ); for (y = min; y <= max; ++y) { /* every column */ if ( (y==min) || (map[x][y-1]!=map[x][y]) ) { sprintf( colorbuf, "%s%s", ( map[x][y]< 0 ? get_door_color( map[x][y] ) : get_sector_color( map[x][y] ) ), ( ( contents[x][y].string[0] == '\0' ) ? "" : get_invert_color( map[x][y] ) ) ); sprintf( displaybuf, "%s", ( map[x][y]< 0 ? get_door_display( map[x][y] ) : ( contents[x][y].string[0] == '\0' ? get_sector_display(map[x][y] ) : contents[x][y].string ) ) ); sprintf( catbuf, "%s%s", colorbuf, displaybuf ); safe_strcat( MAX_STRING_LENGTH, outbuf, catbuf ); } else { sprintf( catbuf, "%s", (map[x][y]<0) ? get_door_display( map[x][y] ) : get_sector_display(map[x][y]) ); safe_strcat( MAX_STRING_LENGTH, outbuf, catbuf ); } } safe_strcat( MAX_STRING_LENGTH, outbuf, " |\n\r" ); } disp_map(borderbuf, outbuf, ch); /* NOTE: with your imp, probably put the three together into one string? */ return; } /* mlk :: shows a map, specified by size */ void ShowMap( CHAR_DATA *ch, int min, int max, int size, int center ) { int x, y, looper; char outbuf[MAX_STRING_LENGTH]; char catbuf[MAX_STRING_LENGTH]; char borderbuf[MAX_STRING_LENGTH]; char colorbuf[MAX_STRING_LENGTH]; char displaybuf[MAX_STRING_LENGTH]; sprintf( outbuf, "%s", "\n\r" ); sprintf( borderbuf, "%s", "+" ); for ( looper = 0; looper <= size+1; looper++ ) { sprintf( catbuf, "%s", "-" ); safe_strcat( MAX_STRING_LENGTH, borderbuf, catbuf ); } safe_strcat( MAX_STRING_LENGTH, borderbuf, "+" ); for (x = min; x <= max; ++x) { safe_strcat( MAX_STRING_LENGTH, outbuf, "| " ); for (y = min; y <= max; ++y) { if ( (y==min) || (map[x][y-1]!=map[x][y]) ) { sprintf( colorbuf, "%s%s", ( map[x][y] < 0 ? get_door_color( map[x][y] ) : get_sector_color( map[x][y] ) ), ( contents[x][y].string[0] == '\0' ? "" : get_invert_color( map[x][y] ) ) ); sprintf( displaybuf, "%s", ( map[x][y]< 0 ? get_door_display( map[x][y] ) : ( contents[x][y].string[0] == '\0' ? get_sector_display(map[x][y] ) : contents[x][y].string ) ) ); sprintf( catbuf, "%s%s{x&w", colorbuf, displaybuf ); safe_strcat( MAX_STRING_LENGTH, outbuf, catbuf ); } else { sprintf( catbuf, "%s{x&w", (map[x][y]<0) ? get_door_display( map[x][y] ) : get_sector_display(map[x][y]) ); safe_strcat( MAX_STRING_LENGTH, outbuf, catbuf ); } } safe_strcat( MAX_STRING_LENGTH, outbuf, " |\n\r" ); } send_to_char( "\n\r", ch ); /* this is the top line of the map itself, currently not part of the mapstring */ send_to_char( borderbuf, ch ); /* this is the contents of the map */ send_to_char( outbuf, ch ); /* this is the bottom line of the map */ send_to_char( borderbuf, ch ); send_to_char( "\n\r", ch ); send_to_char( "Also try mapper legend.\n\r", ch ); return; } void do_mapper( CHAR_DATA *ch, char *argument ) { int size,center,x,y,min,max,looper; char arg1[MAX_STRING_LENGTH]; char catbuf[MAX_STRING_LENGTH]; char outbuf[MAX_STRING_LENGTH]; one_argument( argument, arg1 ); if ( is_name( arg1, "legend key help" ) ) { sprintf( outbuf, "Map Legend:\n\r" ); for ( looper = 0; looper < SECT_TOP; looper++ ) { sprintf( catbuf, "%s%s{x&w : %s\n\r" , map_info[looper].display_color, map_info[looper].display_code, map_info[looper].desc ); safe_strcat( MAX_STRING_LENGTH, outbuf, catbuf ); } for ( looper = 0; looper < 5; looper++ ) { sprintf( catbuf, "%s%s{x&w : %s\n\r" , door_info[looper].display_color, door_info[looper].display_code, door_info[looper].desc ); safe_strcat( MAX_STRING_LENGTH, outbuf, catbuf ); } send_to_char( outbuf, ch ); return; } size = ( is_number( arg1 ) ) ? atoi (arg1) : 21; if ( size != 7 ) { size = IS_IMMORTAL( ch ) ? size : get_curr_int( ch )/2 + ( ( !IS_NPC( ch ) ) ? ch->pcdata->learned[gsn_peek]/25 : 0 ); if ( size % 2 == 0 ) size +=1; size = URANGE( 9, size, MAX_MAP ); } size=URANGE(3,size,MAX_MAP); center=MAX_MAP/2; min = MAX_MAP/2-size/2; max = MAX_MAP/2+size/2; for (x = 0; x < MAX_MAP; ++x) for (y = 0; y < MAX_MAP; ++y) { map[x][y]=SECT_UNSEEN; contents[x][y].string[0] = '\0'; } /* starts the mapping with the center room */ MapArea(ch->in_room, ch, center, center, min-1, max, LOS_INITIAL); /* marks the center, where ch is */ sprintf( contents[center][center].string, "%s", "&R@&x" ); if ( size == 7 ) ShowRoom( ch, min, max, size, center ); else ShowMap( ch, min, max, size, center ); return; }