/*************************************************************************** * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik Strfeldt, 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. * * * * 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. * ***************************************************************************/ /*************************************************************************** * 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 * ****************************************************************************/ /*************************************************************************** * MapMaker originally created by * Wendigo of Oblivionmud.static.net port 9000 * If you use this code, enjoy it, have bug fixes or simply want to * chat, please feel free to email me at kcaffet@hotmail.com (msn as well) ****************************************************************************/ /* * Installation of this snippet should be rather easy. Simply put the file * in with the rest of your source code, edit your Makefile and add the * appropriate $.o file (where $ is the name of this file) * Declare a do_map in interp.h and add the command into interp.c * * This is a stand-alone file. However, it is recommended that you move * many of these functions into their appropriate files (All the recycle * info into recycle.c and wnatnot. */ /* Commands for do_map are as follows: * (Note: Commands do not need to be issued in any order) * * world: Area boundaries do not apply. It will go out as far as it * can into the world. Not specifying world leaves it at the * default of area only * * tight: Do not show room links(Not specifying will show links) * * # > 0: Ex: 4, 6, 30 Will show that many spaces away * from you, forming a box(not specifying will go until finished) * * # < 0: Ex: -1, -5, -20 Will limit the map to that depth (positive) * (not specifying will go until finished) * * doors: Will not go past closed doors.(Not Specified will go through * all doors) * * mob: Will highlight squares with mobs in them (colour coded) (Not * specified will not show mob colours) * * terrain: Will toggle terrain mode (rooms shown with terrain symbols) * (not specified will show regular area rooms) * * fog: Enables fog mode (Will not go past certain terrain types) * (Not specified will go through all terrain types) * * text: Enables room description text to be displayed to the right * of the map * * border: remove the pretty border around the map. * * Mulet: added this to spot players as well, of course only give it to imms * players: how players position and create an indexed color * * Ex: map tight 8 Will stay in the area, not show room links and only * go 8 spaces away from the user * * map 20 world Area boundaries ignored, shows room links, goes 20 * spaces away from the user * * map world tight mob terrain fog border doors * Yah.. Look at all the above options, apply them * * As a side note, colour code had to be reduced to a bare minimum due * to a resource limit on how much can be displayed at one time. * One line of 80 characters can take up a lot of space if every * spot is used and has an extra 4-8 colour code characters in it. * While the line "bobo likes pie" may seem small it gets quite large * when it's "{rb{ro{rb{ro{lw {lgl{lgi{lgk{lge{lgs{lw {rp{ri{re{lw" * * Mulet:this previous comment is mitigated as I rewrited the color management * * If you begin to experience disconnections when using the map at it's * maximum grid size, simply reduce the grid size. */ #include <sys/types.h> #include <string.h> #include <stdlib.h> #include <stdio.h> #include <time.h> #include <ctype.h> #include "an.h" #include "mapmakerv2.h" #include "interp.h" // External information, used by many things. MAP_QD *map_queue; MAP_VISIT *map_visit[MAX_MAP_HASH]; MAP_VISIT *map_visit_free; int map[MAX_MAP][MAX_MAP]; MAP_PARAM *mp = NULL; bool_t is_room_visited(CHAR_DATA *ch, ROOM_INDEX_DATA *pRoomIndex) { if ( !ch || !ch->pcdata || !pRoomIndex) return FALSE; if (IS_DEMI(ch)) return TRUE; return ch->pcdata->visitedroom[pRoomIndex->vnum / 8] & (1 << (pRoomIndex->vnum % 8)) ? TRUE : FALSE; } bool_t is_room_sn_visited(CHAR_DATA *ch, unsigned int vnum) { if ( !ch || !ch->pcdata) return FALSE; if (IS_DEMI(ch)) return TRUE; return ch->pcdata->visitedroom[vnum / 8] & (1 << (vnum % 8)) ? TRUE : FALSE; } void set_room_visited(CHAR_DATA *ch, ROOM_INDEX_DATA *pRoomIndex) { if ( !ch || !ch->pcdata || !pRoomIndex || IS_SET(pRoomIndex->room_flags, ROOM_NO_MAP)) return; ch->pcdata->visitedroom[pRoomIndex->vnum / 8] |= (1 << (pRoomIndex->vnum % 8)); } void set_room_sn_visited(CHAR_DATA *ch, unsigned int vnum) { ch->pcdata->visitedroom[vnum / 8] |= (1 << (vnum % 8)); } void unset_room_sn_visited(CHAR_DATA *ch, unsigned int vnum) { ch->pcdata->visitedroom[vnum / 8] &= ~(1 << (vnum % 8)); } static char previousColor[7]; char *mpcolourCH(CHAR_DATA *ch, char *arg, bool_t forcedColor) { static char colorch[7]; //to prevent bleeding background if ( !str_prefix_cs("{G", previousColor)) sprintf(colorch, "&%d", ch ? COLOR_TABLE[(ch->color[C_NRM])].number : C_NRM); else colorch[0] = '\0'; if ( !str_cmp(arg, "{nr")) //neutral color sprintf(colorch, "%s&%d", colorch, ch ? COLOR_TABLE[(ch->color[C_NRM])].number : C_NRM); else //magenta for border, only case I have to sort yet sprintf(colorch, "%s&%d", colorch, ch ? COLOR_TABLE[(ch->color[C_NRM])].number : C_NRM); if (str_cmp_cs(previousColor, arg) || forcedColor) { sprintf(previousColor, "%s", arg); return colorch; } return ""; } /* * ugly hack to make so colors are adapted to Arcane Nites code... (we use &1 to %23 colors) * adapt it to yours (G means background color, b bold, l low (dim normal whatever) * second letter is the color */ char *mpcolour(char *arg) { if (mp && !mp->color) return ""; if (!mp) previousColor[0] = '\0'; static char color[7]; //if previous color was a background one, and following is bold //they will overlap and give a bold color on previous background //so we insert a dummy light color to prevent it... //this code will only work here as the map do not send other combination if ( !str_prefix_cs("{G", previousColor) && !str_prefix_cs("{b", arg)) sprintf(color, "%s", "&1"); else color[0] = '\0'; if ( !str_prefix_cs("{GB", arg)) sprintf(color, "%s&%d", color, C_BG_BLUE); else if ( !str_prefix_cs("{GR", arg)) sprintf(color, "%s&%d", color, C_BG_RED); else if ( !str_prefix_cs("{GW", arg)) sprintf(color, "%s&%d", color, C_BG_WHITE); else if ( !str_prefix_cs("{GG", arg)) sprintf(color, "%s&%d", color, C_BG_GREEN); else if ( !str_prefix_cs("{GY", arg)) sprintf(color, "%s&%d", color, C_BG_YELLOW); else if ( !str_prefix_cs("{GC", arg)) sprintf(color, "%s&%d", color, C_BG_CYAN); else if ( !str_prefix_cs("{BM", arg)) sprintf(color, "%s&%d", color, C_BG_MAGENTA); else if ( !str_prefix_cs("{lw", arg)) sprintf(color, "%s&%d", color, C_WHT); else if ( !str_prefix_cs("{bW", arg)) sprintf(color, "%s&%d", color, C_B_WHT); else if ( !str_prefix_cs("{ly", arg)) sprintf(color, "%s&%d", color, C_YEL); else if ( !str_prefix_cs("{bY", arg)) sprintf(color, "%s&%d", color, C_B_YEL); else if ( !str_prefix_cs("{lg", arg)) sprintf(color, "%s&%d", color, C_GRN); else if ( !str_prefix_cs("{bG", arg)) sprintf(color, "%s&%d", color, C_B_GRN); else if ( !str_prefix_cs("{lb", arg)) sprintf(color, "%s&%d", color, C_BLU); else if ( !str_prefix_cs("{bB", arg)) sprintf(color, "%s&%d", color, C_B_BLU); else if ( !str_prefix_cs("{lc", arg)) sprintf(color, "%s&%d", color, C_CYN); else if ( !str_prefix_cs("{bC", arg)) sprintf(color, "%s&%d", color, C_B_CYN); else if ( !str_prefix_cs("{lr", arg)) sprintf(color, "%s&%d", color, C_RED); else if ( !str_prefix_cs("{bR", arg)) sprintf(color, "%s&%d", color, C_B_RED); else if ( !str_prefix_cs("{lm", arg)) sprintf(color, "%s&%d", color, C_MAG); else if ( !str_prefix_cs("{bM", arg)) sprintf(color, "%s&%d", color, C_B_MAG); if (strlen(arg) > 3) { if ( !str_suffix_cs("{lw", arg)) sprintf(color, "%s&%d", color, C_WHT); else if ( !str_suffix_cs("{bW", arg)) sprintf(color, "%s&%d", color, C_B_WHT); else if ( !str_suffix_cs("{bG", arg)) sprintf(color, "%s&%d", color, C_B_GRN); else if ( !str_suffix_cs("{lg", arg)) sprintf(color, "%s&%d", color, C_GRN); else if ( !str_suffix_cs("{ly", arg)) sprintf(color, "%s&%d", color, C_YEL); else if ( !str_suffix_cs("{bY", arg)) sprintf(color, "%s&%d", color, C_B_YEL); else if ( !str_suffix_cs("{bB", arg)) sprintf(color, "%s&%d", color, C_B_BLU); else if ( !str_suffix_cs("{lb", arg)) sprintf(color, "%s&%d", color, C_BLU); else if ( !str_suffix_cs("{bC", arg)) sprintf(color, "%s&%d", color, C_B_CYN); else if ( !str_suffix_cs("{bR", arg)) sprintf(color, "%s&%d", color, C_B_RED); else if ( !str_suffix_cs("{lm", arg)) sprintf(color, "%s&%d", color, C_MAG); else if ( !str_suffix_cs("{bM", arg)) sprintf(color, "%s&%d", color, C_B_MAG); } if (str_cmp(previousColor, arg)) { sprintf(previousColor, "%s", arg); return color; } return ""; } // Free's all visited rooms from the map_visit hash table void free_map_memory(void) { MAP_VISIT *mapv, *mapv_next; int hash; for (hash = 0;hash < MAX_MAP_HASH;hash ++) { for (mapv = map_visit[hash];mapv;mapv = mapv_next) { mapv_next = mapv->next; free(mapv); } map_visit[hash] = NULL; } MAP_QD *mapqd, *mapqd_next; // Lets add it at the end. It has to wait in line.. for (mapqd = map_queue;mapv;mapqd = mapqd_next) { mapqd_next = mapqd->next; free(mapqd); } unsigned short int x, y; for (x = 0;x < MAX_MAP;x ++) for (y = 0;y < MAX_MAP;y ++) map[x][y] = -1; } // Adds a room as visited void add_visited(unsigned int room) { int hash = room % MAX_MAP_HASH; MAP_VISIT *mv = malloc(sizeof( *mv)); mv->room = room; mv->next = map_visit[hash]; map_visit[hash] = mv; } // Returns T/F if room was visited bool_t has_visited(unsigned int room) { MAP_VISIT *map; unsigned int hash = room % MAX_MAP_HASH; for (map = map_visit[hash];map;map = map->next) if (map->room == room) return TRUE; return FALSE; } void init_mp(CHAR_DATA *ch, char* argument) { mp = malloc(sizeof( *mp)); mp->desc = calloc(4608, sizeof(char)); // max string mp->desc[0] = '\0'; short int size = -1; char arg[MSL]; mp->area = FALSE; mp->tight = FALSE; mp->fog = FALSE; mp->size = MAP_MID; mp->border = TRUE; mp->doors = TRUE; mp->depth = -1; mp->mobs = FALSE; mp->ter = FALSE; mp->text = FALSE; mp->players = FALSE; mp->doShare = FALSE; mp->doForget = FALSE; mp->mxp = FALSE; mp->share = NULL; mp->doStoreCoord = FALSE; mp->color = !ch ? FALSE : IS_SET(ch->comm, COMM_COLOR); for (argument = one_argument(argument, arg);arg[0] != '\0';) { // For every argument given.. if (is_number(arg)) { size = strtol(arg, NULL, 10); if (size >= MAP_MID) { mp->size = MAP_MID; chprintf(ch, "Maximum map size is:%d", MAP_MID); } else if (size > 0) mp->size = size; else if (size < 0) mp->depth = size * -1; } else if ( !str_prefix(arg, "share")) { mp->doShare = TRUE; break; } else if ( !str_prefix(arg, "forget")) { mp->doForget = TRUE; break; } else if ( !str_prefix(arg, "coord")) mp->doStoreCoord = TRUE; else if ( !str_prefix(arg, "world")) mp->area = TRUE; else if ( !str_prefix(arg, "tight")) mp->tight = TRUE; else if ( !str_prefix(arg, "fog")) mp->fog = TRUE; else if ( !str_prefix(arg, "border")) mp->border = FALSE; else if ( !str_prefix(arg, "doors")) mp->doors = FALSE; else if ( !str_prefix(arg, "mobs")) mp->mobs = TRUE; else if ( !str_prefix(arg, "terrain")) mp->ter = TRUE; else if ( !str_prefix(arg, "text")) mp->text = TRUE; else if ( !str_prefix(arg, "mxp")) mp->mxp = TRUE; else if ( !str_prefix(arg, "players") && IS_IMMORTAL(ch)) mp->players = TRUE; arg[0] = '\0'; argument = one_argument(argument, arg); } if (ch && ch->in_room) // Can call function with NULL (if used externally) sprintf(mp->desc, "%s%s", get_color_ch(ch, COL_NORM), ch->in_room->desc); if ( !mp->tight && mp->size > 0) // It's not a tight map, so we double it's size to make up for the extra links mp->size *= 2; if (mp->doShare) { char target[MAX_INPUT_LENGTH]; argument = one_argument(argument, target); one_argument(argument, mp->shareTarget); //get the player with which you want to share the map mp->share = get_char_room(ch, target); } if (mp->doForget) one_argument(argument, mp->shareTarget); } void free_mp() { if (!mp) return; free_string(&mp->desc); free(mp); mp = NULL; } // In a function incase I want to mod it later char *finish_map_text(void) { return mp->desc; } // Returns the colour of the link char *get_linkc(int link) { switch (link) { case NS_2WAYD: case NS_1WAYND: case NS_1WAYSD: case NS_HITD: case EW_2WAYD: case EW_1WAYED: case EW_1WAYWD: case EW_HITD: case NS_UNND: case NS_UNSD: case EW_UNED: case EW_UNWD: return mpcolour("{bG"); } // Something goofed return mpcolour("{lg"); } // Returns the character of the link char *get_link(int link) { switch (link) { case NS_2WAY: case NS_2WAYD: return "|"; case NS_1WAYN:case NS_1WAYND: return "^"; case NS_1WAYS:case NS_1WAYSD: return "v"; case NS_HIT: case NS_HITD: return "/"; case EW_2WAY: case EW_2WAYD: return "-"; case EW_1WAYE:case EW_1WAYED: return ">"; case EW_1WAYW:case EW_1WAYWD: return "<"; case EW_HIT: case EW_HITD: return "="; case NS_UNN: case NS_UNND: return ","; case NS_UNS: case NS_UNSD: return "`"; case EW_UNE: case EW_UNED: return ")"; case EW_UNW: case EW_UNWD: return "("; } return "?"; } char* add_mxp_path(unsigned int vnum, char *room) { if (!mp || !mp->mxp) return room; static char buf[MAX_INPUT_LENGTH]; sprintf(buf, "\t<send \"path %d\" hint=\"goto\">%s\t</send>", vnum, room); return buf; } /** * if ch param is used this will return the terrain character in wich the player is like it would * appear with map terrain param * do NOT use it without ch param unless you initialized map before or it will crash */ char *get_mroom(CHAR_DATA *ch, unsigned int room) { ROOM_INDEX_DATA *rm = ch ? ch->in_room : get_room_index(room); if (!rm) return " "; SHOP_DATA *shop = NULL; unsigned int vnum = rm->vnum; // Check for a shop. CHAR_DATA *keeper; for (keeper = rm->people;keeper;keeper = keeper->next_in_room) { if (IS_NPC(keeper) && (shop = keeper->pIndexData->pShop)) break; } if (ch || mp->ter) {// Terrain mode switch (rm->sectorType) { case SECT_INSIDE: return add_mxp_path(vnum, "+"); case SECT_CITY: return add_mxp_path(vnum, "#"); case SECT_FIELD: return add_mxp_path(vnum, "o"); case SECT_FOREST: return add_mxp_path(vnum, "T"); case SECT_HILLS: return add_mxp_path(vnum, "n"); case SECT_MOUNTAIN: return add_mxp_path(vnum, "M"); case SECT_WATER_SWIM: return add_mxp_path(vnum, "~"); case SECT_WATER_NOSWIM: return add_mxp_path(vnum, "~"); case SECT_AIR: return add_mxp_path(vnum, "^"); case SECT_DESERT: return add_mxp_path(vnum, "."); case SECT_FIRE: return add_mxp_path(vnum, "!"); case SECT_SUBZERO: return add_mxp_path(vnum, "!"); case SECT_TORNADO: return add_mxp_path(vnum, "@"); case SECT_QUICKSAND: return add_mxp_path(vnum, "s"); case SECT_ACID: return add_mxp_path(vnum, "!"); case SECT_UWATER: return add_mxp_path(vnum, "="); } return add_mxp_path(vnum, "*"); } // End Terrain mode if (IS_SET (rm->room_flags, ROOM_PET_SHOP)) // How about a pet shop? return add_mxp_path(vnum, "P"); if (shop) // Do we have a shop?? return add_mxp_path(vnum, "S"); // Default. return add_mxp_path(vnum, "*"); } char** playerInLine = NULL; char *get_terrain_color(ROOM_INDEX_DATA *rm) { if (!rm) return mpcolour("{lg"); switch (rm->sectorType) { case SECT_INSIDE: return mpcolour("{lw"); case SECT_CITY: return mpcolour("{bW"); case SECT_FIELD: return mpcolour("{ly"); case SECT_FOREST: return mpcolour("{bG"); case SECT_HILLS: return mpcolour("{lg"); case SECT_MOUNTAIN: return mpcolour("{bY"); case SECT_WATER_SWIM: return mpcolour("{bB"); case SECT_WATER_NOSWIM: return mpcolour("{lb"); case SECT_AIR: return mpcolour("{bC"); case SECT_DESERT: return mpcolour("{bR"); case SECT_FIRE: return mpcolour("{GR"); case SECT_SUBZERO: return mpcolour("{GW"); case SECT_TORNADO: return mpcolour("{GC"); case SECT_QUICKSAND: return mpcolour("{GY"); case SECT_ACID: return mpcolour("{BM"); case SECT_UWATER: return mpcolour("{GB"); default: return mpcolour("{lg"); } } /* Returns the colour code of the room */ char *get_mroomc(CHAR_DATA *ch, int room, short int line) { CHAR_DATA *mob; unsigned char mtype = 0; bool_t ptype = 0; ROOM_INDEX_DATA *rm = get_room_index(room); for (mob = rm->people;mob;mob = mob->next_in_room) { if (IS_NPC(mob)) {//only show mobs that are sentinel, it is a map, not a radar if (IS_SET(mob->act, ACT_SENTINEL)) { if (IS_SET(mob->act, ACT_AGGRESSIVE)) mtype = 2; mtype = UMAX(mtype, 1); } } else { ptype = TRUE; //add the char to the list to display on this line if (strlen(playerInLine[line]) + strlen(mob->short_descr) < 490) { if (strlen(playerInLine[line]) < 495) //because it is define to 500 sprintf(playerInLine[line], "%s %s ", playerInLine[line], "..."); } else sprintf(playerInLine[line], "%s %s ", playerInLine[line], mob->short_descr); } } /* Terrain mode colour, if needed. This will override exit and mob colours. Warning: May cause disconnect on * large display due to extra colour codes - hopefully the new colour control code has fixed that */ if (mp->ter) return get_terrain_color(rm); // Does it have an up and a down? Can they get there? if ((rm->exit[DIR_UP] && can_see_room(ch, rm->exit[DIR_UP]->u1.to_room)) && (rm->exit[DIR_DOWN] && can_see_room(ch, rm->exit[DIR_DOWN]->u1.to_room)) && (mp->doors || ( !IS_SET(rm->exit[DIR_UP]->exit_info, EX_CLOSED) || !IS_SET(rm->exit[DIR_DOWN]->exit_info, EX_CLOSED)))) { if (ptype) return mpcolour("{GY{bR"); if (mp->mobs && (mtype == 1 || mtype == 2)) return mtype == 1 ? mpcolour("{GB{bR") : mpcolour("{GR{bR"); return mpcolour("{bR"); } if (rm->exit[DIR_UP] && can_see_room(ch, rm->exit[DIR_UP]->u1.to_room) && (mp->doors || !IS_SET(rm->exit[DIR_UP]->exit_info, EX_CLOSED))) {// Going up? if (ptype) return mpcolour("{GY{bM"); if (mp->mobs && (mtype == 1 || mtype == 2)) return mtype == 1 ? mpcolour("{GB{bM") : mpcolour("{GR{bM"); return mpcolour("{bM"); } if (rm->exit[DIR_DOWN] && can_see_room(ch, rm->exit[DIR_DOWN]->u1.to_room) && (mp->doors || !IS_SET(rm->exit[DIR_DOWN]->exit_info, EX_CLOSED))) { if (ptype) return mpcolour("{GY{bB"); if (mp->mobs && (mtype == 1 || mtype == 2)) return mtype == 1 ? mpcolour("{GB{bB") : mpcolour("{GR{bB"); return mpcolour("{bB"); } // Default. if (ptype) return mpcolour("{GY{bG"); if (mp->mobs && (mtype == 1 || mtype == 2)) return mtype == 1 ? mpcolour("{GB{bG") : mpcolour("{GR{bG"); return mpcolour("{lg"); } // Finds out what type of link to put between rooms // returns the link number char put_link(ROOM_INDEX_DATA *room, int next, unsigned char dir) { ROOM_INDEX_DATA *other; EXIT_DATA *exit; // Get the reverse dir unsigned char dir2 = rev_dir[dir]; if (next > 0) {// Do we have a room there already? other = get_room_index(next); exit = other->exit[dir2]; } else { exit = room->exit[dir]->u1.to_room->exit[dir2]; other = room->exit[dir]->u1.to_room; } EXIT_DATA *org = room->exit[dir]; if (dir == DIR_NORTH) {// I'm going north if (!exit) {// 1 way? if (other && org->u1.to_room == other) // Is the link to that room? return IS_SET(org->exit_info, EX_ISDOOR) ? NS_1WAYND : NS_1WAYN; // Goes that way but not to that room return IS_SET(org->exit_info, EX_ISDOOR) ? NS_UNND : NS_UNN; } if (exit->u1.to_room == room) // 2 way? return (IS_SET(exit->exit_info, EX_ISDOOR) || IS_SET(org->exit_info, EX_ISDOOR)) ? NS_2WAYD : NS_2WAY; if (exit->u1.to_room != room) // 2 way collide? return (IS_SET(exit->exit_info, EX_ISDOOR) || IS_SET(org->exit_info, EX_ISDOOR)) ? NS_HITD : NS_HIT; return -1; } if (dir == DIR_SOUTH) {// I'm going south if (!exit) {// 1 way? if (org->u1.to_room == other) // Is the link to that room? return IS_SET(org->exit_info, EX_ISDOOR) ? NS_1WAYSD : NS_1WAYS; // Goes that way but not to that room return IS_SET(org->exit_info, EX_ISDOOR) ? NS_UNSD : NS_UNS; } if (exit->u1.to_room == room) // 2 way? return (IS_SET(exit->exit_info, EX_ISDOOR) || IS_SET(org->exit_info, EX_ISDOOR)) ? NS_2WAYD : NS_2WAY; if (exit->u1.to_room != room) // 2 way collide? return (IS_SET(exit->exit_info, EX_ISDOOR) || IS_SET(org->exit_info, EX_ISDOOR)) ? NS_HITD : NS_HIT; return -1; } if (dir == DIR_EAST) {// I'm going east if (!exit) {// 1 way? if (org->u1.to_room == other) // Is the link to that room? return IS_SET(org->exit_info, EX_ISDOOR) ? EW_1WAYED : EW_1WAYE; // Goes that way but no to that room return IS_SET(org->exit_info, EX_ISDOOR) ? EW_UNED : EW_UNE; } if (exit->u1.to_room == room) // 2 way? return (IS_SET(exit->exit_info, EX_ISDOOR) || IS_SET(org->exit_info, EX_ISDOOR)) ? EW_2WAYD : EW_2WAY; if (exit->u1.to_room != room) // 2 way collide? return (IS_SET(exit->exit_info, EX_ISDOOR) || IS_SET(org->exit_info, EX_ISDOOR)) ? EW_HITD : EW_HIT; return -1; } if (dir == DIR_WEST) {// I'm going west if (!exit) {// 1 way? if (org->u1.to_room == other) // Is the link to that room? return IS_SET(org->exit_info, EX_ISDOOR) ? EW_1WAYWD : EW_1WAYW; return IS_SET(org->exit_info, EX_ISDOOR) ? EW_UNWD : EW_UNW; } if (exit->u1.to_room == room) return (IS_SET(exit->exit_info, EX_ISDOOR) || IS_SET(org->exit_info, EX_ISDOOR)) ? EW_2WAYD : EW_2WAY; if (exit->u1.to_room != room) return (IS_SET(exit->exit_info, EX_ISDOOR) || IS_SET(org->exit_info, EX_ISDOOR)) ? EW_HITD : EW_HIT; return -1; } return -1; } // Returns a new map queue data MAP_QD *new_map_qd(void) { MAP_QD *map = malloc(sizeof( *map)); map->next = NULL; map->room = 0; map->x = 0; map->y = 0; return map; } // Add an MQD to the queue void add_map_qd(MAP_QD *mqd) { // Mark the room as visited add_visited(mqd->room); // Is there a mqd in the queue? If not lets start it off if (!map_queue) { map_queue = mqd; return; } MAP_QD *map; // Lets add it at the end. It has to wait in line.. for (map = map_queue;map;map = map->next) { if (map->next == NULL) { map->next = mqd; break; } } } // Returns the next queue waiting in line MAP_QD *next_map_qd(void) { if ( !map_queue) return NULL; MAP_QD *map = map_queue; map_queue = map_queue->next; return map; } unsigned char const mapdir[] = {DIR_NORTH, DIR_EAST, DIR_SOUTH, DIR_WEST}; // Uses a combination of a queue and recursion. Takes you, does all the rooms around you // After that, it does all those rooms, then the rooms those generated.. until it stops void add_to_map(CHAR_DATA *ch, ROOM_INDEX_DATA *room, unsigned char x, unsigned char y, short int depth) { EXIT_DATA *exit; MAP_QD *qd; bool_t setCoordinate = FALSE; unsigned char idir, dir, num; // Go in all 4 directions NESW, add the lines then add to map the next room for (idir = 0;idir < 4;idir ++) { dir = mapdir[idir]; exit = room->exit[dir]; if ( !exit || !exit->u1.to_room) continue; setCoordinate = FALSE; // Add your conditions for not mapping that room here. if ( (ch && !(is_room_visited(ch, exit->u1.to_room) || !can_see_room(ch, exit->u1.to_room))) || (mp->fog && exit->u1.to_room->sectorType == SECT_MOUNTAIN) // Is fog mod on? || ( !mp->doors && IS_SET(exit->exit_info, EX_CLOSED)) || (mp->depth >= 0 && depth == mp->depth)) continue; num = mp->tight ? 1 : 2; // Num is used to control if we do every second point as a room, or every point switch (dir) { case DIR_NORTH: // y - 1 if ( !mp->tight) {// Do we want our room links? if (y - 2 < 0) // Will we oversteap our bounds if we put try to put in this link? break; map[x][y - 1] = put_link(room, map[x][y - 2], dir); } // Cases where we WON'T add this room, and thereby search it if (y - num < 0 || map[x][y - num] != -1 || (room->area != exit->u1.to_room->area && !mp->area) || has_visited(exit->u1.to_room->vnum)) break; // It's passed the test, lets add it map[x][y - num] = exit->u1.to_room->vnum; qd = new_map_qd(); qd->x = x; qd->y = y - num; qd->room = exit->u1.to_room->vnum; qd->depth = depth + 1; add_map_qd(qd); setCoordinate = TRUE; break; case DIR_EAST: // x + 1 if ( !mp->tight) {// See all comments above. if (x + 2 > MAX_MAP - 1) break; map[x + 1][y] = put_link(room, map[x + 2][y], dir); } if (x + num > MAX_MAP - 1 || map[x + num][y] != -1 || (room->area != exit->u1.to_room->area && !mp->area) || has_visited(exit->u1.to_room->vnum)) break; map[x + num][y] = exit->u1.to_room->vnum; qd = new_map_qd(); qd->x = x + num; qd->y = y; qd->room = exit->u1.to_room->vnum; qd->depth = depth + 1; add_map_qd(qd); setCoordinate = TRUE; break; case DIR_SOUTH: // y + 1 if ( !mp->tight) { if (y + 2 > MAX_MAP - 1) break; map[x][y + 1] = put_link(room, map[x][y + 2], dir); } if (y + num > MAX_MAP - 1 || map[x][y + num] != -1 || (room->area != exit->u1.to_room->area && !mp->area) || has_visited(exit->u1.to_room->vnum)) break; map[x][y + num] = exit->u1.to_room->vnum; qd = new_map_qd(); qd->x = x; qd->y = y + num; qd->room = exit->u1.to_room->vnum; qd->depth = depth + 1; add_map_qd(qd); setCoordinate = TRUE; break; case DIR_WEST: // x - 1 if ( !mp->tight) { if (x - 2 < 0) break; map[x - 1][y] = put_link(room, map[x - 2][y], dir); } if (x - num < 0 || map[x - num][y] != -1 || (room->area != exit->u1.to_room->area && !mp->area) || has_visited(exit->u1.to_room->vnum)) break; map[x - num][y] = exit->u1.to_room->vnum; qd = new_map_qd(); qd->x = x - num; qd->y = y; qd->room = exit->u1.to_room->vnum; qd->depth = depth + 1; add_map_qd(qd); setCoordinate = TRUE; break; } // End of dir switch if (setCoordinate && mp->doStoreCoord) { ROOM_INDEX_DATA *room = get_room_index(qd->room ); room->coord.x = qd->x; room->coord.y = qd->y; } } // end of searching NESW from our point MAP_QD *next_qd = next_map_qd(); // But wait! Is there another room in the queue to search? if ( !next_qd) return; // Looks like it. Lets search this point just like we did when we first started this whole thing unsigned int qroom = next_qd->room; unsigned char qx = next_qd->x; unsigned char qy = next_qd->y; unsigned char qdepth = next_qd->depth; // This way I can free the qdata before the recursive call, meaning it's available right away instead of after all the recursion is done. free(next_qd); // Is it a valid room? Lets double check if (get_room_index(qroom)) add_to_map(ch, get_room_index(qroom), qx, qy, qdepth); } // make the map. Meat of the whole thing void make_map_no_char(ROOM_INDEX_DATA* roomStart, unsigned char x, unsigned char y) { if (!roomStart) return; // Lets start out with a fresh grid and hash table free_map_memory(); // Add your starting point map[x][y] = roomStart->vnum; if (mp->doStoreCoord) { roomStart->coord.x = x; roomStart->coord.y = y; } // Say you've visited your starting point add_visited(roomStart->vnum); // Use your starting point to begin the graphing process, with you in the middle add_to_map(NULL, roomStart, x, y, 0); } // make the map. Meat of the whole thing void make_map(CHAR_DATA *ch, unsigned char x, unsigned char y) { if (!ch) return; // Lets start out with a fresh grid and hash table free_map_memory(); // Add your starting point map[x][y] = ch->in_room->vnum; if (mp->doStoreCoord) { ch->in_room->coord.x = x; ch->in_room->coord.y = y; } // Say you've visited your starting point add_visited(ch->in_room->vnum); // Use your starting point to begin the graphing process, with you in the middle add_to_map(ch, ch->in_room, x, y, 0); } // get_?_start and get_?_to functions are used to trim the map down so only the smallet, visible map is displayed // returns their appropriate boundaries unsigned char get_x_start(void) { if (mp->size < MAP_MID) return MAP_MID - mp->size; unsigned char y, x; for (x = 0;x < MAX_MAP;x ++) for (y = 0;y < MAX_MAP;y ++) if (map[x][y] != -1) return x; return MAX_MAP - 1; } // See above unsigned char get_y_start(void) { if (mp->size < MAP_MID) return MAP_MID - mp->size; unsigned char y, x; for (y = 0;y < MAX_MAP;y ++) for (x = 0;x < MAX_MAP;x ++) if (map[x][y] != -1) return y; return MAX_MAP - 1; } // See above unsigned char get_x_to(void) { if (mp->size < MAP_MID) return MAX_MAP - MAP_MID + mp->size - 1; unsigned char y, x; for (x = MAX_MAP - 1;x != 0;x --) for (y = 0;y < MAX_MAP;y ++) if (map[x][y] != -1) return x; return 0; } // See above unsigned char get_y_to(void) { if (mp->size < MAP_MID) return MAX_MAP - MAP_MID + mp->size - 1; unsigned char y, x; for (y = MAX_MAP - 1;y != 0;y --) for (x = 0;x < MAX_MAP;x ++) if (map[x][y] != -1) return y; return 0; } char* get_map(CHAR_DATA *ch, unsigned char xx, unsigned char yy) { // Get our trimming thresholds unsigned char y_from = get_y_start(); unsigned char y_to = get_y_to(); unsigned char x_from = get_x_start(); unsigned char x_to = get_x_to(); playerInLine = malloc((y_to + 1) * sizeof(char*)); unsigned char i; for (i = 0;i <= y_to;i ++) { playerInLine[i] = malloc(500); playerInLine[i][0] = '\0'; } // Start out our buffer char buf[MSL]; static char totalbuf[MSL * 6]; //this entirely depends on how large your world is totalbuf[0] = '\0'; unsigned char x, y; if (mp->border) { //fanciful border sprintf(totalbuf, "%s(@", mpcolourCH(ch, "{lm", FALSE)); for (x = 0;x <= (x_to - x_from) / 2;x ++) strcat(totalbuf, "*@"); strcat(totalbuf,(x_to - x_from) % 2 == 1 ? "))\n\r" : ")\n\r"); } for (y = y_from;y <= y_to;y ++) { buf[0] = '\0'; for (x = x_from;x <= x_to;x ++) { if (map[x][y] != -1) {// Is there something here? if (map[x][y] < -1) // ? < -1 means a link type. Lets buffer it sprintf(buf, "%s%s%s", buf, get_linkc(map[x][y]), get_link(map[x][y])); else if (xx == x && yy == y) {// This is where we started. Make sure to mark it with a special character sprintf(buf, "%s%s@", buf, mpcolour("{bR")); ROOM_INDEX_DATA *rm = get_room_index(map[xx][yy]); CHAR_DATA *player; //for other rooms we already parse the char list in each of them for (player = rm->people;player;player = player->next_in_room) if (IS_PC(player)) sprintf(playerInLine[yy], "%s %s ", playerInLine[yy], player->short_descr); } else // Must be a room sprintf(buf, "%s%s%s", buf, get_mroomc(ch, map[x][y], y), get_mroom(NULL, map[x][y])); } else // Nothing's here.. Make a blank space sprintf(buf, "%s%s ", buf, mpcolourCH(ch, "{nr", FALSE)); } if (mp->border) sprintf(totalbuf, "%s%s((%s%s))%s\n\r", totalbuf, mpcolourCH(ch, "{lm", TRUE), buf, mpcolourCH(ch, "{lm", FALSE), mp->players && playerInLine[y] ? playerInLine[y] : ""); else sprintf(totalbuf, "%s%s%s%s\n\r", totalbuf, buf, mpcolourCH(ch, "{nr", TRUE), mp->players && playerInLine[y] ? playerInLine[y] : ""); } if (mp->border) { sprintf(totalbuf, "%s%s(@", totalbuf, mpcolourCH(ch, "{lm", TRUE)); for (x = 0;x <= (x_to - x_from) / 2;x ++) strcat(totalbuf, "*@"); if ((x_to - x_from) % 2 == 1) strcat(totalbuf, ")"); sprintf(totalbuf, "%s)%s\n\r", totalbuf, mpcolour("{lw")); } if (mp->text) sprintf(totalbuf, "%s%s%s", totalbuf, mpcolourCH(ch, "{nr", FALSE), finish_map_text()); sprintf(totalbuf, "%s%s", totalbuf, mpcolourCH(ch, "{nr", FALSE)); //log_param("map max size:%d currentsize:%d", MSL*12, strlen(totalbuf)); // We're done, so free the visits for (i = 0;i <= y_to;i ++) free(playerInLine[i]); free(playerInLine); free_map_memory(); free_mp(); return totalbuf; } // The map display function void show_map(CHAR_DATA *ch, unsigned char xx, unsigned char yy) { send_to_char(get_map(ch, xx, yy), ch); } // Command to start it all. bool_t do_map(CHAR_DATA *ch, char *argument) { if (!IS_PC(ch)) { send_to_char("Huh?\n\r", ch); return FALSE; } if (ch->fighting) { send_to_char("You are quite too busy for that right now, aren't you ?\n\r", ch); return FALSE; } if (IS_AFFECTED(ch,AFF_BLIND)) { send_to_char("You cannot see !\n\r", ch); return FALSE; } init_mp(ch, argument); if (mp->doShare) { CHAR_DATA *victim = mp->share; char shareTarget[MAX_INPUT_LENGTH]; sprintf(shareTarget, "%s", mp->shareTarget); free_mp(); if ( !victim) { send_to_char("Share your map with who?\n\r", ch); return FALSE; } if (victim == ch) { send_to_char("You swap your map from one pocket to another, happy?\n\r", ch); return FALSE; } if (victim->fighting) { chprintf(ch, "%s is too busy to copy your map right now!\n\r", victim->short_descr); return FALSE; } if (IS_NPC(victim)) { chprintf(ch, "%s has no use for it.\n\r", victim->short_descr); return FALSE; } if (shareTarget[0] == '\0') { send_to_char("Share all your map or only one area?\n\r", ch); return FALSE; } unsigned int sn; if ( !str_cmp(shareTarget, "all")) { //start to replicate the whole map for (sn = 0;sn <= top_vnum_room;sn ++) if (is_room_sn_visited(ch, sn)) set_room_sn_visited(victim, sn); chprintf(ch, "%s now knows everything you do.\n\r", victim->short_descr); chprintf(victim, "You now know everything %s did.\n\r", ch->short_descr); return TRUE; } AREA_DATA *pArea; for (pArea = area_first;pArea;pArea = pArea->next) { if ( !strstr(lower_str(pArea->name), shareTarget)) continue; for (sn = pArea->lvnum;sn <= pArea->uvnum;sn ++) if (is_room_sn_visited(ch, sn)) set_room_sn_visited(victim, sn); chprintf(ch, "%s now knows everything you do on %s.\n\r", victim->short_descr, pArea->name); chprintf(victim, "You now know everything %s did on %s.\n\r", ch->short_descr, pArea->name); return TRUE; } send_to_char("You know no area by that name.\n\r", ch); return FALSE; } if (mp->doForget) { char shareTarget[MAX_INPUT_LENGTH]; sprintf(shareTarget, "%s", mp->shareTarget); free_mp(); if (shareTarget[0] == '\0') { send_to_char("forget all your maps or only one specific area?\n\r", ch); return FALSE; } AREA_DATA *pArea; unsigned int sn; if ( !str_cmp(shareTarget, "all")) { //start to replicate the whole map for (sn = 0;sn <= top_vnum_room;sn ++) unset_room_sn_visited(ch, sn); send_to_char("You forgot everything about the realm.\n\r", ch); return TRUE; } for (pArea = area_first;pArea;pArea = pArea->next) { if ( !strstr(lower_str(pArea->name), shareTarget)) continue; for (sn = pArea->lvnum;sn <= pArea->uvnum;sn ++) unset_room_sn_visited(ch, sn); chprintf(ch, "You forgot everything about %s.\n\r", pArea->name); return TRUE; } send_to_char("You know no area by that name.\n\r", ch); return FALSE; } make_map(ch, MAP_MID, MAP_MID); // Create your map - most important part show_map(ch, MAP_MID, MAP_MID); // Use the show_map routine to display it - can create different routines to suit taste or need do_wait(ch, PULSE_VIOLENCE); return TRUE; }