/**************************************************************************
* 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-2004 by Markanth *
* http://www.firstmud.com/ <markanth@firstmud.com> *
* By using this code you have agreed to follow the term of *
* the 1stMud license in ../doc/1stMud/LICENSE *
***************************************************************************/
#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;
int depth;
RoomIndex *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].depth = 0;
map[x][y].pRoom = NULL;
}
struct sector_color_type
{
sector_t bit;
const char *display_color;
char display_symbol;
};
const struct sector_color_type sector_color_table[SECT_MAX] = {
{
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_ICE, "{C", 'O'},
{SECT_AIR, "{C", '~'},
{SECT_DESERT, "{y", '+'},
{SECT_ROAD, "{m", ':'},
{SECT_PATH, "{M", ':'},
{SECT_SWAMP, "{G", '&'},
{SECT_CAVE, "{w", '#'},
{SECT_NONE, "{w", '?'}
};
const char *get_sector_color(sector_t sector)
{
int looper;
for (looper = 0; looper < SECT_MAX; looper++)
if (sector_color_table[looper].bit == sector)
return (sector_color_table[looper].display_color);
return "";
}
char get_sector_symbol(sector_t sector)
{
int looper;
for (looper = 0; looper < SECT_MAX; looper++)
if (sector_color_table[looper].bit == sector)
return (sector_color_table[looper].display_symbol);
return '?';
}
void map_exits(CharData * ch, RoomIndex * pRoom, int x, int y)
{
int door;
int exitx = 0, exity = 0;
int roomx = 0, roomy = 0;
ExitData *pExit;
if (!can_see_room(ch, pRoom))
return;
map[x][y].symbol = get_sector_symbol(pRoom->sector_type);
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 (IsSet(pExit->exit_info, EX_CLOSED))
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 (depth == MAXDEPTH)
continue;
map[exitx][exity].depth = depth;
if (IsSet(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].pRoom == pExit->u1.to_room)
|| (map[roomx][roomy].pRoom == NULL)))
{
depth++;
map_exits(ch, pExit->u1.to_room, roomx, roomy);
depth--;
}
}
}
char *erase_new_lines(const char *desc)
{
unsigned int l, m, sz;
static char buf[MSL * 7];
char temp[MSL * 7];
if (NullStr(desc))
return "";
l = 0;
m = 0;
buf[0] = NUL;
temp[0] = NUL;
sz = strlen(desc);
for (m = 0; m <= sz; m++)
{
if (desc[m] == '\n' || desc[m] == '\r')
temp[m] = '\x20';
else
temp[m] = desc[m];
}
temp[m] = NUL;
for (m = 0; temp[m] != NUL; m++)
{
if (temp[m] == '\x20' && temp[m + 1] == '\x20')
{
buf[l++] = ' ';
do
{
m++;
}
while (temp[m] == '\x20');
}
buf[l++] = temp[m];
}
buf[l] = NUL;
return buf;
}
size_t get_line_len(const char *desc, size_t max_len)
{
size_t m, l, sz;
char buf[MSL];
if (NullStr(desc) || (sz = strlen(desc)) <= max_len)
return 0;
buf[0] = '\0';
l = 0;
for (m = 0; m <= sz; m++)
{
if (desc[m] == COLORCODE)
{
int k = ansi_skip(&desc[m]);
m += k;
if (k == 1)
lcolor = desc[m];
}
else if (desc[m] == CUSTOMSTART)
{
do
{
m++;
}
while (desc[m] != CUSTOMEND);
}
else if (desc[m] == MXP_BEGc)
{
do
{
m++;
}
while (desc[m] != MXP_ENDc);
}
if (++l > max_len)
break;
}
for (l = m; l > 0; l--)
if (desc[l] == ' ')
break;
return l + 1;
}
void show_map(CharData * ch, const char *text, bool fSmall)
{
char buf[MSL * 2];
size_t x, y, m, n, pos;
const char *p;
bool alldesc = false;
double rcnt = (double) (areacount(ch, ch->in_room->area));
double rooms = (double) (arearooms(ch->in_room->area));
int maxlen = get_scr_cols(ch);
int maplen = maxlen - 15;
if (fSmall)
{
m = 4;
n = 5;
}
else
{
m = 0;
n = 0;
}
pos = 0;
p = text;
buf[0] = '\0';
if (fSmall)
{
if (IsNPC(ch) || IsSet(ch->in_room->room_flags, ROOM_NOEXPLORE))
sprintf(buf, CTAG(_AUTOMAP) "+------------+{%c ", lcolor);
else
sprintf(buf,
CTAG(_AUTOMAP) "+-----[{x%3.0f%%" CTAG(_AUTOMAP) "]+{%c ",
Percent(rcnt, rooms), lcolor);
if (!alldesc)
{
pos = get_line_len(p, maplen);
if (pos > 0)
{
strncat(buf, p, pos);
p += pos;
}
else
{
strcat(buf, p);
alldesc = true;
}
}
strcat(buf, NEWLINE);
}
for (y = m; y <= (MAPY * 2) - m; y++)
{
if (fSmall)
strcat(buf, CTAG(_AUTOMAP) "|");
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)
&& !IsNPC(ch)
&& StrIsSet(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);
}
else
{
if (!fSmall)
strcat(buf, " {D.");
else
strcat(buf, " ");
}
}
if (!fSmall)
{
switch (y)
{
case 0:
strcat(buf, " {xX You are here");
break;
case 2:
strcat(buf, " {xo Normal Rooms");
break;
case 3:
strcat(buf, " {xU Room with exit up");
break;
case 4:
strcat(buf, " {xD Room with exit down");
break;
case 5:
strcat(buf, " {xB Room with exits up & down");
break;
case 6:
strcat(buf, " {x|- Exits");
break;
case 7:
strcat(buf, " {x>I< Closed Doors");
break;
case 8:
strcat(buf, " {x* Field/Forest");
break;
case 9:
strcat(buf, " {x! Hills");
break;
case 10:
strcat(buf, " {x@ Mountain");
break;
case 11:
strcat(buf, " {x= Water");
break;
case 12:
strcat(buf, " {x~ Air");
break;
case 13:
strcat(buf, " {x+ Desert");
break;
case 14:
strcat(buf, " {x: Road/Path");
break;
case 15:
strcat(buf, " {x& Swamp");
break;
case 16:
strcat(buf, " {x# Cave");
break;
case 17:
strcat(buf, " {x? Unknown");
break;
default:
strcat(buf, " {x");
break;
}
strcat(buf, NEWLINE);
}
else
{
sprintf(buf + strlen(buf), CTAG(_AUTOMAP) "| {%c", lcolor);
if (!alldesc)
{
pos = get_line_len(p, maplen);
if (pos > 0)
{
strncat(buf, p, pos);
p += pos;
}
else
{
strcat(buf, p);
alldesc = true;
}
}
strcat(buf, NEWLINE);
}
}
if (!fSmall)
chprintlnf(ch, "%s" NEWLINE "%s{x%s", draw_line(ch, NULL, 0), buf,
draw_line(ch, NULL, 0));
else
{
sprintf(buf + strlen(buf), CTAG(_AUTOMAP) "+-----------+{%c ",
lcolor);
if (!alldesc)
{
pos = get_line_len(p, maplen);
if (pos > 0)
{
strncat(buf, p, pos);
p += pos;
}
else
{
strcat(buf, p);
alldesc = true;
}
}
if (!alldesc)
{
do
{
pos = get_line_len(p, maxlen);
if (pos > 0)
{
strncat(buf, p, pos);
p += pos;
}
else
{
strcat(buf, p);
alldesc = true;
}
}
while (!alldesc);
}
strcat(buf, "{x");
chprint(ch, buf);
}
}
void draw_map(CharData * ch, const char *desc)
{
int x, y;
const char *buf;
bool fSmall;
lcolor = 'x';
if (NullStr(desc))
{
buf = desc;
fSmall = false;
}
else
{
buf = erase_new_lines(desc);
fSmall = true;
}
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_exits(ch, ch->in_room, x, y);
map[x][y].symbol = 'X';
show_map(ch, buf, fSmall);
}
Do_Fun(do_automap)
{
if (IsNPC(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.");
}
Do_Fun(do_map)
{
if (IsNPC(ch))
return;
if (!ch->in_room)
return;
if (!check_blind(ch))
return;
draw_map(ch, NULL);
return;
}