cotn/notes/
cotn/src/
/***************************************************************************
 *  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);
}