/**************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* *
* 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. *
* *
* Much time and thought has gone into this software and you are *
* benefiting. We hope that you share your changes too. What goes *
* around, comes around. *
***************************************************************************
* ROM 2.4 is copyright 1993-1998 Russ Taylor *
* ROM has been brought to you by the ROM consortium *
* Russ Taylor (rtaylor@hypercube.org) *
* Gabrielle Taylor (gtaylor@hypercube.org) *
* Brian Moore (zump@rom.org) *
* By using this code, you have agreed to follow the terms of the *
* ROM license, in the file Rom24/doc/rom.license *
***************************************************************************
* 1stMUD ROM Derivative (c) 2001-2002 by Ryan Jennings *
* http://1stmud.dlmud.com/ <r-jenn@shaw.ca> *
***************************************************************************/
#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "merc.h"
char map_chars[5] = "|-|-";
char map_chars_closed[5] = "I>I<";
char lcolor = 'x';
int depth = 0;
#define MAXDEPTH 4
#define MAPX 10
#define MAPY 8
#define BOUNDARY(x, y) (((x) < 0) || ((y) < 0) || \
((x) > (MAPX * 2)) || ((y) > (MAPY * 2))) \
struct map_type
{
char symbol;
vnum_t vnum;
int depth;
ROOM_INDEX_DATA *pRoom;
};
typedef struct map_type MAP_DATA;
MAP_DATA map[(MAPX * 2) + 1][(MAPY * 2) + 1];
void get_exit_dir(int dir, int *x, int *y, int xorig, int yorig)
{
switch (dir)
{
case 0:
*x = xorig;
*y = yorig - 1;
break;
case 1:
*x = xorig + 1;
*y = yorig;
break;
case 2:
*x = xorig;
*y = yorig + 1;
break;
case 3:
*x = xorig - 1;
*y = yorig;
break;
default:
*x = -1;
*y = -1;
break;
}
}
void clear_coord(int x, int y)
{
map[x][y].symbol = '.';
map[x][y].vnum = 0;
map[x][y].depth = 0;
map[x][y].pRoom = NULL;
}
void clear_room(int x, int y)
{
int dir, exitx, exity;
for (dir = DIR_NORTH; dir <= DIR_WEST; dir++)
{
get_exit_dir(dir, &exitx, &exity, x, y);
if (!BOUNDARY(exitx, exity))
clear_coord(exitx, exity);
}
}
struct sector_color_type
{
int bit;
const char *display_color;
char display_symbol;
};
const struct sector_color_type sector_color_table[] = {
{SECT_INSIDE, "{w", 'o'},
{SECT_CITY, "{w", 'o'},
{SECT_FIELD, "{G", '*'},
{SECT_FOREST, "{g", '*'},
{SECT_HILLS, "{y", '*'},
{SECT_MOUNTAIN, "{W", '@'},
{SECT_WATER_SWIM, "{B", '='},
{SECT_WATER_NOSWIM, "{b", '='},
{SECT_UNUSED, "{w", 'o'},
{SECT_AIR, "{C", '~'},
{SECT_DESERT, "{y", '+'},
{SECT_MAX, "{w", 'o'}
};
const char *get_sector_color(int sector)
{
int looper;
for (looper = 0;; looper++)
if ((sector_color_table[looper].bit == sector)
|| (sector_color_table[looper].bit == SECT_MAX))
break;
return (sector_color_table[looper].display_color);
}
char get_sector_symbol(int sector)
{
int looper;
for (looper = 0;; looper++)
if ((sector_color_table[looper].bit == sector)
|| (sector_color_table[looper].bit == SECT_MAX))
break;
return (sector_color_table[looper].display_symbol);
}
void map_exits(CHAR_DATA * ch, ROOM_INDEX_DATA * pRoom, int x, int y)
{
int door;
int exitx = 0, exity = 0;
int roomx = 0, roomy = 0;
EXIT_DATA *pExit;
if (!can_see_room(ch, pRoom))
return;
map[x][y].symbol = get_sector_symbol(pRoom->sector_type);
map[x][y].vnum = pRoom->vnum;
map[x][y].depth = depth;
map[x][y].pRoom = pRoom;
if (depth >= MAXDEPTH)
return;
for (door = DIR_NORTH; door <= DIR_DOWN; door++)
{
if ((pExit = pRoom->exit[door]) == NULL)
continue;
if (pExit->u1.to_room == NULL)
continue;
if (!can_see_room(ch, pExit->u1.to_room))
continue;
get_exit_dir(door, &exitx, &exity, x, y);
get_exit_dir(door, &roomx, &roomy, exitx, exity);
if (BOUNDARY(exitx, exity) || BOUNDARY(roomx, roomy))
continue;
if ((map[roomx][roomy].vnum != 0)
&& (map[roomx][roomy].vnum != pExit->u1.to_room->vnum)
/* only clear exits and rooms of higher depth */
&& map[roomx][roomy].depth > depth && depth < MAXDEPTH)
{
clear_room(roomx, roomy);
}
if (depth == MAXDEPTH)
continue;
map[exitx][exity].depth = depth;
map[exitx][exity].vnum = pExit->u1.to_room->vnum;
if (IS_SET(pExit->exit_info, EX_CLOSED))
map[exitx][exity].symbol = map_chars_closed[door];
else
map[exitx][exity].symbol = map_chars[door];
map[exitx][exity].pRoom = pExit->u1.to_room;
if ((depth < MAXDEPTH)
&& ((map[roomx][roomy].vnum == pExit->u1.to_room->vnum)
|| (map[roomx][roomy].vnum == 0)))
{
depth++;
map_exits(ch, pExit->u1.to_room, roomx, roomy);
depth--;
}
}
}
void reformat_desc(char *desc)
{
char *p;
unsigned int l, m;
char buf[MSL * 2];
l = 0;
m = 0;
buf[0] = '\0';
if (desc[0] == '\0')
return;
/* remove all \n & \r */
for (m = 0; m <= strlen(desc); m++)
if (desc[m] == '\n' || desc[m] == '\r')
desc[m] = ' ';
/* remove multiple spaces */
for (p = desc; *p != '\0'; p++)
{
if (*p == ' ' && *(p + 1) == ' ')
{
buf[l] = *p;
l++;
do
{
p++;
}
while (*p == ' ');
}
buf[l] = *p;
l++;
}
buf[l] = '\0';
sprintf(desc, buf);
return;
}
unsigned int get_line(char *desc, unsigned int max_len)
{
unsigned int m;
unsigned int l;
char buf[MSL];
if (strlen(desc) <= max_len)
return 0;
buf[0] = '\0';
l = 0;
for (m = 0; m <= strlen(desc); m++)
{
if (desc[m] == ANSI_KEY)
{
m++;
lcolor = desc[m];
m++;
}
else if (desc[m] == ANSI_CUSTOM)
{
while (desc[m] != ANSI_END)
m++;
m++;
}
l++;
if (l > max_len)
break;
}
for (l = m; l > 0; l--)
if (desc[l] == ' ')
break;
return l + 1;
}
void show_map(CHAR_DATA * ch, char *text, bool fSmall)
{
char buf[MSL * 2];
int x, y, m, n, pos;
char *p;
bool alldesc = FALSE;
int rcnt = areacount(ch, ch->in_room->area);
double rooms = (double) (arearooms(ch->in_room->area));
double percent = UMIN((double) rcnt / (rooms / 100), 100);
int maxlen = (ch->desc
&& ch->desc->scr_width > 0) ? ch->desc->scr_width - 2 : 78;
int maplen = maxlen - 15;
if (fSmall)
{
m = 4;
n = 5;
}
else
{
m = 0;
n = 0;
}
pos = 0;
p = text;
buf[0] = '\0';
lcolor = 'x';
if (fSmall)
{
if (IS_NPC(ch) || IS_SET(ch->in_room->room_flags, ROOM_NOEXPLORE))
sprintf(buf, "{R+------------+{%c ", lcolor);
else
sprintf(buf, "{R+-----[{x%3.0f%%{R]+{%c ", percent, lcolor);
if (!alldesc)
{
pos = get_line(p, maplen);
if (pos > 0)
{
strncat(buf, p, pos);
p += pos;
}
else
{
strcat(buf, p);
alldesc = TRUE;
}
}
strcat(buf, "\n\r");
}
for (y = m; y <= (MAPY * 2) - m; y++)
{
if (fSmall)
strcat(buf, "{R|{x");
else
strcat(buf, "{D");
for (x = n; x <= (MAPX * 2) - n; x++)
{
if (map[x][y].pRoom)
{
if (map[x][y].symbol ==
get_sector_symbol(map[x][y].pRoom->sector_type)
&& !IS_NPC(ch)
&& STR_IS_SET(ch->pcdata->explored, map[x][y].pRoom->vnum))
{
if (map[x][y].pRoom->exit[DIR_UP]
&& map[x][y].pRoom->exit[DIR_DOWN])
map[x][y].symbol = 'B';
else if (!map[x][y].pRoom->exit[DIR_UP]
&& map[x][y].pRoom->exit[DIR_DOWN])
map[x][y].symbol = 'D';
else if (map[x][y].pRoom->exit[DIR_UP]
&& !map[x][y].pRoom->exit[DIR_DOWN])
map[x][y].symbol = 'U';
}
if (!fSmall)
sprintf(buf + strlen(buf), " %s%c{D",
get_sector_color(map[x][y].pRoom->sector_type),
map[x][y].symbol);
else
sprintf(buf + strlen(buf), "%s%c",
get_sector_color(map[x][y].pRoom->sector_type),
map[x][y].symbol != '.' ? map[x][y].symbol : ' ');
}
else
{
if (!fSmall)
{
strcat(buf, " ");
strcat(buf, &map[x][y].symbol);
}
else
strcat(buf,
map[x][y].symbol != '.' ? &map[x][y].symbol : " ");
}
}
if (!fSmall)
{
switch (y)
{
case 0:
strcat(buf, " {xX You are here\n\r");
break;
case 2:
strcat(buf, " {xo Normal Rooms\n\r");
break;
case 3:
strcat(buf, " {xU Room with exit up\n\r");
break;
case 4:
strcat(buf, " {xD Room with exit down\n\r");
break;
case 5:
strcat(buf, " {xB Room with exits up & down\n\r");
break;
case 6:
strcat(buf, " {x|- Exits\n\r");
break;
case 7:
strcat(buf, " {x>I< Closed Doors\n\r");
break;
case 8:
strcat(buf, " {x* Field/Forest/Hills\n\r");
break;
case 9:
strcat(buf, " {x@ Mountain\n\r");
break;
case 10:
strcat(buf, " {x= Water\n\r");
break;
case 11:
strcat(buf, " {x~ Air\n\r");
break;
case 12:
strcat(buf, " {x+ Desert\n\r");
break;
default:
strcat(buf, " {x\n\r");
break;
}
}
else
{
strcat(buf, "{R| {");
strcat(buf, &lcolor);
if (!alldesc)
{
pos = get_line(p, maplen);
if (pos > 0)
{
strncat(buf, p, pos);
p += pos;
}
else
{
strcat(buf, p);
alldesc = TRUE;
}
}
strcat(buf, "\n\r");
}
}
if (!fSmall)
chprintlnf(ch, "%s\n\r%s%s", draw_line(ch, NULL, 0), buf,
draw_line(ch, NULL, 0));
else
{
strcat(buf, "{R+-----------+{");
strcat(buf, &lcolor);
strcat(buf, " ");
if (!alldesc)
{
pos = get_line(p, maplen);
if (pos > 0)
{
strncat(buf, p, pos);
p += pos;
}
else
{
strcat(buf, p);
alldesc = TRUE;
}
}
if (!alldesc)
{
do
{
pos = get_line(p, maxlen);
if (pos > 0)
{
strncat(buf, p, pos);
p += pos;
}
else
{
strcat(buf, p);
alldesc = TRUE;
}
}
while (!alldesc);
}
strcat(buf, "{x");
chprintln(ch, buf);
}
}
void draw_map(CHAR_DATA * ch, const char *desc)
{
int x, y;
static char buf[MSL];
bool fSmall;
if (IS_NULLSTR(desc))
fSmall = FALSE;
else
{
fSmall = TRUE;
sprintf(buf, desc);
reformat_desc(buf);
}
for (y = 0; y <= MAPY * 2; y++)
{
for (x = 0; x <= MAPX * 2; x++)
{
clear_coord(x, y);
}
}
x = MAPX;
y = MAPY;
depth = (fSmall) ? 2 : 0;
map[x][y].vnum = ch->in_room->vnum;
map[x][y].depth = depth;
map_exits(ch, ch->in_room, x, y);
map[x][y].symbol = 'X';
show_map(ch, buf, fSmall);
}
CH_CMD(do_automap)
{
if (IS_NPC(ch))
return;
set_on_off(ch, &ch->act, PLR_AUTOMAP,
"You now see an automap in room descriptions.",
"You no longer see automap room descriptions.");
}
bool check_blind args((CHAR_DATA * ch));
CH_CMD(do_map)
{
if (IS_NPC(ch))
return;
if (!ch->in_room)
return;
if (!check_blind(ch))
return;
draw_map(ch, NULL);
return;
}