/***************************************************************************
* 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. *
* *
* 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. *
* *
* Dystopia Mud improvements copyright (C) 2000, 2001 by Brian Graversen *
* *
* 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. *
***************************************************************************/
/***************************************************************************
* _/ _/ *
* _/_/_/ _/_/ _/_/_/ _/ _/_/ _/ _/ _/_/_/ *
* _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ *
* _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ *
* _/ _/ _/ _/_/_/ _/ _/_/ _/_/_/ _/_/_/ *
***************************************************************************
* Mindcloud Copyright 2001-2003 by Jeff Boschee (Zarius), *
* Additional credits are in the help file CODECREDITS *
* All Rights Reserved. *
***************************************************************************/
/*
* The core of the automap system was taken from the snippet by Dingo
* which can be accessed at : http://www.vidler.clara.net/automap.html
*
* A few minor extensions to spiff it up was made by Jobo.
*/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include "merc.h"
/* The map itself */
//struct map_type map[MAPX + 1][MAPY + 1];
/* Take care of some repetitive code for later */
void get_exit_dir(int dir, int *x, int *y, int xorig, int yorig)
{
/*
* Get the next coord based on direction
*/
switch (dir)
{
case 0: /* North */
*x = xorig;
*y = yorig - 1;
break;
case 1: /* East */
*x = xorig + 1;
*y = yorig;
break;
case 2: /* South */
*x = xorig;
*y = yorig + 1;
break;
case 3: /* West */
*x = xorig - 1;
*y = yorig;
break;
default:
*x = -1;
*y = -1;
break;
}
}
/* Clear one map coord */
void clear_coord(int x, int y)
{
map[x][y].tegn = ' ';
map[x][y].vnum = 0;
map[x][y].depth = 0;
map[x][y].info = 0;
map[x][y].can_see = TRUE;
}
/* Clear all exits for one room */
void clear_room(int x, int y)
{
int dir, exitx, exity;
/*
* Cycle through the four directions
*/
for (dir = 0; dir < 4; dir++)
{
/*
* Find next coord in this direction
*/
get_exit_dir(dir, &exitx, &exity, x, y);
/*
* If coord is valid, clear it
*/
if (!BOUNDARY(exitx, exity))
clear_coord(exitx, exity);
}
}
/* This function is recursive, ie it calls itself */
void map_exits(CHAR_DATA * ch, ROOM_INDEX_DATA * pRoom, int x, int y,
int depth)
{
static char map_chars[4] = "|-|-";
int door;
int exitx = 0, exity = 0;
int roomx = 0, roomy = 0;
char buf[200]; // bugs
EXIT_DATA *pExit;
/*
* Setup this coord as a room
*/
switch (pRoom->sector_type)
{
case SECT_CITY:
case SECT_INSIDE:
case SECT_UNUSED:
map[x][y].tegn = 'O';
break;
case SECT_FIELD:
case SECT_FOREST:
case SECT_HILLS:
map[x][y].tegn = '*';
break;
case SECT_MOUNTAIN:
map[x][y].tegn = '@';
break;
case SECT_WATER_SWIM:
case SECT_WATER_NOSWIM:
map[x][y].tegn = '=';
break;
case SECT_AIR:
map[x][y].tegn = '~';
break;
case SECT_DESERT:
map[x][y].tegn = '+';
break;
default:
map[x][y].tegn = 'O';
xprintf(buf, "Map_exits: Bad sector type (%d) in room %d.",
pRoom->sector_type, pRoom->vnum);
bug(buf, 0);
break;
}
map[x][y].vnum = pRoom->vnum;
map[x][y].depth = depth;
map[x][y].info = pRoom->room_flags;
map[x][y].can_see = room_is_dark(pRoom);
/*
* Limit recursion
*/
if (depth > MAXDEPTH)
return;
/*
* This room is done, deal with it's exits
*/
for (door = 0; door < 4; door++)
{
/*
* Skip if there is no exit in this direction
*/
if ((pExit = pRoom->exit[door]) == NULL)
continue;
/*
* Get the coords for the next exit and room in this direction
*/
get_exit_dir(door, &exitx, &exity, x, y);
get_exit_dir(door, &roomx, &roomy, exitx, exity);
/*
* Skip if coords fall outside map
*/
if (BOUNDARY(exitx, exity) || BOUNDARY(roomx, roomy))
continue;
/*
* Skip if there is no room beyond this exit
*/
if (pExit->to_room == NULL)
continue;
/*
* Ensure there are no clashes with previously defined rooms
*/
if ((map[roomx][roomy].vnum != 0) &&
(map[roomx][roomy].vnum != pExit->to_room->vnum))
{
/*
* Use the new room if the depth is higher
*/
if (map[roomx][roomy].depth <= depth)
continue;
/*
* It is so clear the old room
*/
clear_room(roomx, roomy);
}
/*
* No exits at MAXDEPTH
*/
if (depth == MAXDEPTH)
continue;
/*
* No need for exits that are already mapped
*/
if (map[exitx][exity].depth > 0)
continue;
/*
* Fill in exit
*/
map[exitx][exity].depth = depth;
map[exitx][exity].vnum = pExit->to_room->vnum;
map[exitx][exity].info = pExit->exit_info;
map[exitx][exity].tegn = map_chars[door];
/*
* More to do? If so we recurse
*/
if ((depth < MAXDEPTH) &&
((map[roomx][roomy].vnum == pExit->to_room->vnum) ||
(map[roomx][roomy].vnum == 0)))
{
/*
* Depth increases by one each time
*/
map_exits(ch, pExit->to_room, roomx, roomy,
depth + 1);
}
}
}
/* Reformat room descriptions to exclude undesirable characters */
void reformat_desc(char *desc)
{
/*
* Index variables to keep track of array/pointer elements
*/
int i, j;
char buf[MAX_STRING_LENGTH], *p;
i = 0;
j = 0;
buf[0] = '\0';
if (!desc)
return;
/*
* Replace all "\n" and "\r" with spaces
*/
for (i = 0; i <= strlen(desc); i++)
{
if ((desc[i] == '\n') || (desc[i] == '\r'))
desc[i] = ' ';
}
/*
* Remove multiple spaces
*/
for (p = desc; *p != '\0'; p++)
{
buf[j] = *p;
j++;
/*
* Two or more consecutive spaces?
*/
if ((*p == ' ') && (*(p + 1) == ' '))
{
do
{
p++;
}
while (*(p + 1) == ' ');
}
}
buf[j] = '\0';
/*
* Copy to desc
*/
xprintf_2(desc, "%s", buf);
}
int get_line(char *desc, int max_len)
{
int i, j = 0, length;
length = strlen(desc);
/*
* Return if it's short enough for one line
*/
if (length <= max_len)
return 0;
/*
* Calculate end point in string without color
*/
for (i = 0; i <= length; i++)
{
/*
* Here you need to skip your color sequences
*/
j++;
if (j > max_len)
break;
}
/*
* End point is now in i, find the nearest space
*/
for (j = i; j > 0; j--)
{
if (desc[j] == ' ')
break;
}
/*
* There could be a problem if there are no spaces on the line
*/
return j + 1;
}
/* Display the map to the player */
void show_map(CHAR_DATA * ch, char *text)
{
char buf[MAX_STRING_LENGTH * 2];
int x, y, pos;
char *p;
bool alldesc = FALSE; /* Has desc been fully displayed? */
if (!text)
alldesc = TRUE;
pos = 0;
p = text;
buf[0] = '\0';
/*
* Top of map frame
*/
if (ch->level > 6)
xprintf(buf, "#0/----#BMAP#0----\\#n %s #0[#w%d#0]#n\n\r",
//xprintf( buf, "#0+-----------+#n %s #0[#w%d#0]#n\n\r",
ch->in_room->name, ch->in_room->vnum);
else
xprintf(buf, "#0/----#BMAP#0----\\#n %s\n\r",
ch->in_room->name);
/*
* Write out the main map area with text
*/
for (y = 0; y <= MAPY; y++)
{
strcat(buf, "#0<#n");
for (x = 0; x <= MAPX; x++)
{
switch (map[x][y].tegn)
{
case '-':
case '|':
xcatf(buf, "#y%c#n", map[x][y].tegn);
break;
case 'X':
xcatf(buf, "#R%c#n", map[x][y].tegn);
break;
case '*':
xcatf(buf, "#g%c#n", map[x][y].tegn);
break;
case '@':
xcatf(buf, "#y%c#n", map[x][y].tegn);
break;
case '=':
xcatf(buf, "#B%c#n", map[x][y].tegn);
break;
case '~':
xcatf(buf, "#C%c#n", map[x][y].tegn);
break;
case '+':
xcatf(buf, "#Y%c#n", map[x][y].tegn);
break;
default:
xcatf(buf, "%c", map[x][y].tegn);
}
}
xcatf_2(buf, "#0>#n ");
if (y == 0 && IS_SET(ch->act2, PLR_AUTOEXIT)) // the autoexits
{
xcatf(buf, "%s", get_exits(ch));
continue;
}
/*
* Add the text, if necessary
*/
if (!alldesc)
{
pos = get_line(p, 63);
if (pos > 0)
{
strncat(buf, p, pos);
p += pos;
}
else
{
strcat(buf, p);
alldesc = TRUE;
}
}
strcat(buf, "\n\r");
}
/*
* Finish off map area
*/
xcatf_2(buf, "#0\\___________/#n ");
//strcat( buf, "#0+-----------+#n " );
if (!alldesc)
{
pos = get_line(p, 63);
if (pos > 0)
{
strncat(buf, p, pos);
xcatf_2(buf, "\n\r");
p += pos;
}
else
{
strcat(buf, p);
alldesc = TRUE;
}
}
/*
* Deal with any leftover text
*/
if (!alldesc)
{
do
{
/*
* Note the number - no map to detract from width
*/
pos = get_line(p, 78);
if (pos > 0)
{
strncat(buf, p, pos);
xcatf_2(buf, "\n\r");
p += pos;
}
else
{
xcatf_2(buf, p);
alldesc = TRUE;
}
}
while (!alldesc);
}
xcatf_2(buf, "\n\r");
send_to_char(buf, ch);
if (IS_SET(ch->act2, PLR_AUTOWEATHER) && IS_OUTDOORS(ch))
{
show_weather(ch);
}
}
/* Clear, generate and display the map */
void draw_map(CHAR_DATA * ch, char *desc)
{
int x, y;
static char buf[MAX_STRING_LENGTH];
xprintf_2(buf, "%s", desc);
/*
* Remove undesirable characters
*/
reformat_desc(buf);
/*
* Clear map
*/
for (y = 0; y <= MAPY; y++)
{
for (x = 0; x <= MAPX; x++)
{
clear_coord(x, y);
}
}
/*
* Start with players pos at centre of map
*/
x = MAPX / 2;
y = MAPY / 2;
map[x][y].vnum = ch->in_room->vnum;
map[x][y].depth = 0;
/*
* Generate the map
*/
map_exits(ch, ch->in_room, x, y, 0);
/*
* Current position should be a "X"
*/
map[x][y].tegn = 'X';
/*
* Send the map
*/
show_map(ch, buf);
}