/**************************************************************************** * * Random Dungeon Mapper, from Netherworld Dreamscape * * Written by Morpheus Nosferatu/Jeff Standish * morpheus@sage.cc.purdue.edu * standish@mentor.cc.purdue.edu * * Initial version, March 1993 * * This program copyright by Jeff Standish, 1993. All rights reserved. You * are free to copy and modify this program, so long as this header remains * intact and appropriate attribution is given to the author. This program * may not be sold for profit without the author's consent. * * Compile this program with you favorite C compiler and run it with the * -help or -h option, which will give usage information for the command * line options. * * This program generates random dungeon maps, printing out LaTeX [default] * or PostScript files. For each level of the dungeon, a different file is * generated by taking the base file name and appending the level of the * dungeon and the appropriate format suffix [.tex or .ps]. Files can then * be displayed on a graphics terminal viewer or sent to a laser printer * capable of graphics (in the case of LaTeX files, after the .tex files * have been converted to appropriate printable format by a "latex" program). * * The size of dungeon can be scaled, preferably in the range of 100 to 500. * This scale is the maximum width of the dungeon in feet. Since this program * treates graphical coordinates in points (1 point = 1/72 inch), the maximum * good resolution of a dungeon will be with a width of 500. If the size is * set larger than this, the lines will overlap and make the map difficult to * read (even a map of size 500 is somewhat difficult to read due to how small * it is). * * The entrance to the dungeon is either a doorway or a stairway. The doorway * will be placed in the middle of the wall such that the door faces in a * given direction (a door facing north is in the south wall of the dungeon). * If the entrance is a stairway, it is placed in the middle of the first * level of the dungeon. * ****************************************************************************/ #include #define MAX(a,b) ((a > b) ? (a) : (b)) #define MIN(a,b) ((a < b) ? (a) : (b)) #define EXITSTACK 0 #define ROOM 1 #define CHAMBER 2 #define PASSAGE 3 #define JUNCTION 4 #define STAIRWAY 5 #define DOORWAY 10 #define ARCHWAY 11 #define OPENING 12 #define NORTH 20 #define SOUTH 21 #define EAST 22 #define WEST 23 #define UP 24 #define DOWN 25 #define XSIZE 500 #define YSIZE 700 #define PRINTLATEX 1 #define PRINTPS 2 struct queuestruct { struct exitstruct *exit; struct queuestruct *queuenext; }; struct exitstruct { int orientation, x1, y1, x2, y2, exittype, locationtype, level; struct locationstruct *parent; struct exitstruct *next; }; struct linestruct { int x1, y1, x2, y2; struct linestruct *next; }; struct locationstruct { int xmin, xmax, ymin, ymax, locationtype, locationdata, level, number; struct linestruct *firstline; struct locationstruct *next, *previous; }; typedef struct queuestruct QUEUE; typedef struct exitstruct EXITS; typedef struct linestruct LINES; typedef struct locationstruct LOCAT; static int stairwaydownlines5[4][11][4] = { { { 0, 20, 5, 20 }, { 0, 0, 0, 20 }, { 5, 0, 5, 20 }, { 0, 4, 5, 4 }, { 0, 6, 5, 6 }, { 1, 8, 4, 8 }, { 1, 10, 4, 10 }, { 1, 12, 4, 12 }, { 2, 14, 3, 14 }, { 2, 16, 3, 16 }, { 2, 18, 3, 18 } }, { { 0,-20, -5,-20 }, { 0, 0, 0,-20 }, { -5, 0, -5,-20 }, { 0, -4, -5, -4 }, { 0, -6, -5, -6 }, { -1, -8, -4, -8 }, { -1,-10, -4,-10 }, { -1,-12, -4,-12 }, { -2,-14, -3,-14 }, { -2,-16, -3,-16 }, { -2,-18, -3,-18 } }, { { 20, 0, 20, -5 }, { 0, 0, 20, 0 }, { 0, -5, 20, -5 }, { 4, 0, 4, -5 }, { 6, 0, 6, -5 }, { 8, -1, 8, -4 }, { 10, -1, 10, -4 }, { 12, -1, 12, -4 }, { 14, -2, 14, -3 }, { 16, -2, 16, -3 }, { 18, -2, 18, -3 } }, { {-20, 0,-20, 5 }, { 0, 0,-20, 0 }, { 0, 5,-20, 5 }, { -4, 0, -4, 5 }, { -6, 0, -6, 5 }, { -8, 1, -8, 4 }, {-10, 1,-10, 4 }, {-12, 1,-12, 4 }, {-14, 2,-14, 3 }, {-16, 2,-16, 3 }, {-18, 2,-18, 3 } } }; static int stairwayuplines5[4][11][4] = { { { 0, 20, 5, 20 }, { 0, 0, 0, 20 }, { 5, 0, 5, 20 }, { 0, 18, 5, 18 }, { 0, 16, 5, 16 }, { 1, 14, 4, 14 }, { 1, 12, 4, 12 }, { 1, 10, 4, 10 }, { 2, 8, 3, 8 }, { 2, 6, 3, 6 }, { 2, 4, 3, 4 } }, { { 0,-20, -5,-20 }, { 0, 0, 0,-20 }, { -5, 0, -5,-20 }, { 0,-18, -5,-18 }, { 0,-16, -5,-16 }, { -1,-14, -4,-14 }, { -1,-12, -4,-12 }, { -1,-10, -4,-10 }, { -2, -8, -3, -8 }, { -2, -6, -3, -6 }, { -2, -4, -3, -4 } }, { { 20, 0, 20, -5 }, { 0, 0, 20, 0 }, { 0, -5, 20, -5 }, { 18, 0, 18, -5 }, { 16, 0, 16, -5 }, { 14, -1, 14, -4 }, { 12, -1, 12, -4 }, { 10, -1, 10, -4 }, { 8, -2, 8, -3 }, { 6, -2, 6, -3 }, { 4, -2, 4, -3 } }, { {-20, 0,-20, 5 }, { 0, 0,-20, 0 }, { 0, 5,-20, 5 }, {-18, 0,-18, 5 }, {-16, 0,-16, 5 }, {-14, 1,-14, 4 }, {-12, 1,-12, 4 }, {-10, 1,-10, 4 }, { -8, 2, -8, 3 }, { -6, 2, -6, 3 }, { -4, 2, -4, 3 } } }; static int stairwaydownlines10[4][11][4] = { { { 0, 20, 10, 20 }, { 0, 0, 0, 20 }, { 10, 0, 10, 20 }, { 1, 4, 9, 4 }, { 1, 6, 9, 6 }, { 2, 8, 8, 8 }, { 2, 10, 8, 10 }, { 3, 12, 7, 12 }, { 3, 14, 7, 14 }, { 4, 16, 6, 16 }, { 4, 18, 6, 18 } }, { { 0,-20,-10,-20 }, { 0, 0, 0,-20 }, {-10, 0,-10,-20 }, { -1, -4, -9, -4 }, { -1, -6, -9, -6 }, { -2, -8, -8, -8 }, { -2,-10, -8,-10 }, { -3,-12, -7,-12 }, { -3,-14, -7,-14 }, { -4,-16, -6,-16 }, { -4,-18, -6,-18 } }, { { 20, 0, 20,-10 }, { 0, 0, 20, 0 }, { 0,-10, 20,-10 }, { 4, -1, 4, -9 }, { 6, -1, 6, -9 }, { 8, -2, 8, -8 }, { 10, -2, 10, -8 }, { 12, -3, 12, -7 }, { 14, -3, 14, -7 }, { 16, -4, 16, -6 }, { 18, -4, 18, -6 } }, { {-20, 0,-20, 10 }, { 0, 0,-20, 0 }, { 0, 10,-20, 10 }, { -4, 1, -4, 9 }, { -6, 1, -6, 9 }, { -8, 2, -8, 8 }, {-10, 2,-10, 8 }, {-12, 3,-12, 7 }, {-14, 3,-14, 7 }, {-16, 4,-16, 6 }, {-18, 4,-18, 6 } } }; static int stairwayuplines10[4][11][4] = { { { 0, 20, 10, 20 }, { 0, 0, 0, 20 }, { 10, 0, 10, 20 }, { 1, 18, 9, 18 }, { 1, 16, 9, 16 }, { 2, 14, 8, 14 }, { 2, 12, 8, 12 }, { 3, 10, 7, 10 }, { 3, 8, 7, 8 }, { 4, 6, 6, 6 }, { 4, 4, 6, 4 } }, { { 0,-20,-10,-20 }, { 0, 0, 0,-20 }, {-10, 0,-10,-20 }, { -1,-18, -9,-18 }, { -1,-16, -9,-16 }, { -2,-14, -8,-14 }, { -2,-12, -8,-12 }, { -3,-10, -7,-10 }, { -3, -8, -7, -8 }, { -4, -6, -6, -6 }, { -4, -4, -6, -4 } }, { { 20, 0, 20,-10 }, { 0, 0, 20, 0 }, { 0,-10, 20,-10 }, { 18, -1, 18, -9 }, { 16, -1, 16, -9 }, { 14, -2, 14, -8 }, { 12, -2, 12, -8 }, { 10, -3, 10, -7 }, { 8, -3, 8, -7 }, { 6, -4, 6, -6 }, { 4, -4, 4, -6 } }, { {-20, 0,-20, 10 }, { 0, 0,-20, 0 }, { 0, 10,-20, 10 }, {-18, 1,-18, 9 }, {-16, 1,-16, 9 }, {-14, 2,-14, 8 }, {-12, 2,-12, 8 }, {-10, 3,-10, 7 }, { -8, 3, -8, 7 }, { -6, 4, -6, 6 }, { -4, 4, -4, 6 } } }; static int stairwaydownlines15[4][11][4] = { { { 0, 20, 15, 20 }, { 0, 0, 0, 20 }, { 15, 0, 15, 20 }, { 0, 4, 15, 4 }, { 1, 6, 14, 6 }, { 2, 8, 13, 8 }, { 3, 10, 12, 10 }, { 4, 12, 11, 12 }, { 5, 14, 10, 14 }, { 6, 16, 9, 16 }, { 7, 18, 8, 18 } }, { { 0,-20,-15,-20 }, { 0, 0, 0,-20 }, {-15, 0,-15,-20 }, { 0, -4,-15, -4 }, { -1, -6,-14, -6 }, { -2, -8,-13, -8 }, { -3,-10,-12,-10 }, { -4,-12,-11,-12 }, { -5,-14,-10,-14 }, { -6,-16, -9,-16 }, { -7,-18, -8,-18 } }, { { 20, 0, 20,-15 }, { 0, 0, 20, 0 }, { 0,-15, 20,-15 }, { 4, 0, 4,-15 }, { 6, -1, 6,-14 }, { 8, -2, 8,-13 }, { 10, -3, 10,-12 }, { 12, -4, 12,-11 }, { 14, -5, 14,-10 }, { 16, -6, 16, -9 }, { 18, -7, 18, -8 } }, { {-20, 0,-20, 15 }, { 0, 0,-20, 0 }, { 0, 15,-20, 15 }, { -4, 0, -4, 15 }, { -6, 1, -6, 14 }, { -8, 2, -8, 13 }, {-10, 3,-10, 12 }, {-12, 4,-12, 11 }, {-14, 5,-14, 10 }, {-16, 6,-16, 9 }, {-18, 7,-18, 8 } } }; static int stairwayuplines15[4][11][4] = { { { 0, 20, 15, 20 }, { 0, 0, 0, 20 }, { 15, 0, 15, 20 }, { 0, 18, 15, 18 }, { 1, 16, 14, 16 }, { 2, 14, 13, 14 }, { 3, 12, 12, 12 }, { 4, 10, 11, 10 }, { 5, 8, 10, 8 }, { 6, 6, 9, 6 }, { 7, 4, 8, 4 } }, { { 0,-20,-15,-20 }, { 0, 0, 0,-20 }, {-15, 0,-15,-20 }, { 0,-18,-15,-18 }, { -1,-16,-14,-16 }, { -2,-14,-13,-14 }, { -3,-12,-12,-12 }, { -4,-10,-11,-10 }, { -5, -8,-10, -8 }, { -6, -6, -9, -6 }, { -7, -4, -8, -4 } }, { { 20, 0, 20,-15 }, { 0, 0, 20, 0 }, { 0,-15, 20,-15 }, { 18, 0, 18,-15 }, { 16, -1, 16,-14 }, { 14, -2, 14,-13 }, { 12, -3, 12,-12 }, { 10, -4, 10,-11 }, { 8, -5, 8,-10 }, { 6, -6, 6, -9 }, { 4, -7, 4, -8 } }, { {-20, 0,-20, 15 }, { 0, 0,-20, 0 }, { 0, 15,-20, 15 }, {-18, 0,-18, 15 }, {-16, 1,-16, 14 }, {-14, 2,-14, 13 }, {-12, 3,-12, 12 }, {-10, 4,-10, 11 }, { -8, 5, -8, 10 }, { -6, 6, -6, 9 }, { -4, 7, -4, 8 } } }; static int doorwaylines5[4][11][4] = { { { 0, 0, 1, 0 }, { 0, 1, 1, 1 }, { 4, 0, 5, 0 }, { 4, 1, 5, 1 }, { 1, -1, 4, -1 }, { 1, 2, 4, 2 }, { 1, -1, 1, 2 }, { 4, -1, 4, 2 } }, { { 0, 0, -1, 0 }, { 0, -1, -1, -1 }, { -4, 0, -5, 0 }, { -4, -1, -5, -1 }, { -1, 1, -4, 1 }, { -1, -2, -4, -2 }, { -1, 1, -1, -2 }, { -4, 1, -4, -2 } }, { { 0, 0, 0, -1 }, { 1, 0, 1, -1 }, { 0, -4, 0, -5 }, { 1, -4, 1, -5 }, { -1, -1, -1, -4 }, { 2, -1, 2, -4 }, { -1, -1, 2, -1 }, { -1, -4, 2, -4 } }, { { 0, 0, 0, 1 }, { -1, 0, -1, 1 }, { 0, 4, 0, 5 }, { -1, 4, -1, 5 }, { 1, 1, 1, 4 }, { -2, 1, -2, 4 }, { 1, 1, -2, 1 }, { 1, 4, -2, 4 } } }; static int doorwaylines10[4][8][4] = { { { 0, 0, 2, 0 }, { 0, 1, 2, 1 }, { 8, 0, 10, 0 }, { 8, 1, 10, 1 }, { 2, -1, 8, -1 }, { 2, 2, 8, 2 }, { 2, -1, 2, 2 }, { 8, -1, 8, 2 } }, { { 0, 0, -2, 0 }, { 0, -1, -2, -1 }, { -8, 0,-10, 0 }, { -8, -1,-10, -1 }, { -2, 1, -8, 1 }, { -2, -2, -8, -2 }, { -2, 1, -2, -2 }, { -8, 1, -8, -2 } }, { { 0, 0, 0, -2 }, { 1, 0, 1, -2 }, { 0, -8, 0,-10 }, { 1, -8, 1,-10 }, { -1, -2, -1, -8 }, { 2, -2, 2, -8 }, { -1, -2, 2, -2 }, { -1, -8, 2, -8 } }, { { 0, 0, 0, 2 }, { -1, 0, -1, 2 }, { 0, 8, 0, 10 }, { -1, 8, -1, 10 }, { 1, 2, 1, 8 }, { -2, 2, -2, 8 }, { 1, 2, -2, 2 }, { 1, 8, -2, 8 } } }; static int doorwaylines15[4][9][4] = { { { 0, 0, 3, 0 }, { 0, 1, 3, 1 }, { 12, 0, 15, 0 }, { 12, 1, 15, 1 }, { 3, -1, 12, -1 }, { 3, 2, 12, 2 }, { 3, -1, 3, 2 }, { 7, -1, 7, 2 }, { 12, -1, 12, 2 } }, { { 0, 0, -3, 0 }, { 0, -1, -3, -1 }, {-12, 0,-15, 0 }, {-12, -1,-15, -1 }, { -3, 1,-12, 1 }, { -3, -2,-12, -2 }, { -3, 1, -3, -2 }, { -7, 1, -7, -2 }, {-12, 1,-12, -2 } }, { { 0, 0, 0, -3 }, { 1, 0, 1, -3 }, { 0,-12, 0,-15 }, { 1,-12, 1,-15 }, { -1, -3, -1,-12 }, { 2, -3, 2,-12 }, { -1, -3, 2, -3 }, { -1, -7, 2, -7 }, { -1,-12, 2,-12 } }, { { 0, 0, 0, 3 }, { -1, 0, -1, 3 }, { 0, 12, 0, 15 }, { -1, 12, -1, 15 }, { 1, 3, 1, 12 }, { -2, 3, -2, 12 }, { 1, 3, -2, 3 }, { 1, 7, -2, 7 }, { 1, 12, -2, 12 } } }; #define LATEXHEADERLEN 10 static char *latexheader[LATEXHEADERLEN] = { "\\documentstyle{report}", "\\pagestyle{empty}", "\\addtolength{\\textwidth}{3in}", "\\addtolength{\\oddsidemargin}{-1.5in}", "\\addtolength{\\topmargin}{-1.5in}", "\\addtolength{\\textheight}{3in}", "", "\\begin{document}", "\\begin{picture}(500,730)", "" }; #define HELPLEN 18 static char *helpmessage[HELPLEN] = { " -help\t\t - this help message", " -entrancedirection [direction] - select the direction that", "\t\t\t\t the entrance to the first level is facing,", "\t\t\t\t select from \"north\", \"south\", \"east\",", "\t\t\t\t or \"west\", defaults to \"north\"", " -entrancetype [type] - select form of entrance to first level,", "\t\t\t\t select from \"doorway\" or \"stairway\"", "\t\t\t\t defaults to \"stairway\"", " -output [format]\t - set the map file format as either \"latex\"", "\t\t\t\t or \"postscript\", defaults to \"latex\"", " -maxlevel [level]\t - maximum level of the dungeon,", "\t\t\t\t defaults to level = 1", " -mapwidth [size]\t - maximum width of the dungeon, height = width * 1.4", "\t\t\t\t defaults to size = 250", "\t\t\t\t warning: strange maps may result if size > 500", " -number\t\t - number the rooms on the map", " -dubug\t\t - turn on debugging messages", " filename\t\t - the base name of output file" }; char filename[100]; int mapwidth = 250, mapheight = 350; int entrancetype = STAIRWAY, entrancedirection = NORTH; int startlevel = 1, maxlevel = 1; int gc = 0, gcnum = 0, printout = PRINTLATEX, numberoutput = 0; int debugging = 0; EXITS *exitfreestack = NULL; LOCAT *firstlocation = NULL, *lastlocation = NULL; QUEUE *queuehead = NULL, *queuetail = NULL, *queuefreestack = NULL; EXITS *new_exit_node(); EXITS *dequeue_exit(); LINES *new_line_node(); LOCAT *new_location_node(); LOCAT *box_empty(); QUEUE *new_queue_node(); /**************************************************************************** * * main() - read in command line arguments and call the functions for * generating and drawing the maps * ****************************************************************************/ int main(argc, argv) int argc; char **argv; { int ac; strcpy(filename, "map"); if (argc == 1) { print_usage(argv[0]); exit(0); } /* read in the various options */ ac = 1; while (ac < argc) { if (!strcmp(argv[ac], "-entrancetype")) { ++ac; if (ac < argc) { if (!strcmp(argv[ac], "stairway")) entrancetype = STAIRWAY; else if (!strcmp(argv[ac], "doorway")) entrancetype = DOORWAY; else fatal_error("unknown entrance type \"%s\"", argv[ac]); } else fatal_error("entrance type not given in command line"); } else if (!strcmp(argv[ac], "-entrancedirection")) { ++ac; if (ac < argc) { if (!strcmp(argv[ac], "north")) entrancedirection = NORTH; else if (!strcmp(argv[ac], "south")) entrancedirection = SOUTH; else if (!strcmp(argv[ac], "east")) entrancedirection = EAST; else if (!strcmp(argv[ac], "west")) entrancedirection = WEST; else fatal_error("invalid entrance direction \"%s\"", argv[ac]); } else fatal_error("entrance direction not given in command line"); } else if (!strcmp(argv[ac], "-maxlevel")) { ++ac; if (ac < argc) { maxlevel = atoi(argv[ac]); if (maxlevel < 1) fatal_error("invalid maximum level: %s", argv[ac]); } else fatal_error("maximum level value not given"); } else if (!strcmp(argv[ac], "-mapwidth")) { ++ac; if (ac < argc) { mapwidth = atoi(argv[ac]); mapheight = mapwidth * 1.4; } else fatal_error("maximum map size not given"); } else if (!strcmp(argv[ac], "-output")) { ++ac; if (ac < argc) { if (!strcmp(argv[ac], "latex")) printout = PRINTLATEX; else if (!strcmp(argv[ac], "postscript")) printout = PRINTPS; else fatal_error("unknown output format \"%s\"", argv[ac]); } else fatal_error("output form not given"); } else if (!strcmp(argv[ac], "-number")) { numberoutput = 1; } else if (!strcmp(argv[ac], "-debug")) { debugging = 1; } else if ((!strcmp(argv[ac], "-help")) || (!strcmp(argv[ac], "-h"))) { print_usage(argv[0]); exit(0); } else break; ++ac; } /* get the root name for the output files */ if (ac < argc) { if (argv[ac][0] == '-') { printf("invalid option \"%s\"\n\n", argv[ac]); print_usage(argv[0]); exit(1); } else if (argc > (ac + 1)) { printf("extra information after filename\n\n"); print_usage(argv[0]); exit(1); } else strcpy(filename, argv[ac]); } else { printf("filename not given\n\n"); print_usage(argv[0]); exit(1); } srand(time(0)); create_entrance(); process_exit_queue(); printf("\n\n"); stock_dungeon(); if (printout == PRINTPS) print_postscript_file(); else print_latex_file(); return 0; } /**************************************************************************** * * print_usage() - print a short usage message and information on arguments * ****************************************************************************/ print_usage(name) char name[]; { int i; printf("Usage: %s [argument list] filename\n", name); for (i = 0; i < HELPLEN; ++i) printf("%s\n", helpmessage[i]); } /**************************************************************************** * * stock_dungeon() - presently, this function merely scans through the dungeon * and numbers the rooms and determines the maximum level * that was generated * ****************************************************************************/ stock_dungeon() { int lvl, count, roomnum; LOCAT *room; roomnum = 1; for (lvl = 1; lvl <= maxlevel; ++lvl) { count = 1; room = firstlocation; while (room != NULL) { if (room->level == lvl) { if (((digits_in_number(count) * 4) <= (scale_x(room->xmax) - scale_x(room->xmin))) && ((room->locationtype == ROOM) || (room->locationtype == CHAMBER))) { room->number = roomnum++; } ++count; } room = room->next; } if (count == 1) { maxlevel = lvl - 1; break; } } } /**************************************************************************** * * digits_in_number() - given an integer, return the number of digits in it * ****************************************************************************/ int digits_in_number(foo) int foo; { int i = 1; while (foo > 9) { foo /= 10; ++i; } return i; } /**************************************************************************** * * create_entrance() - generate the entrance of the dungeon, either a stairway * positioned in the middle of the first level, or a * doorway in one of the walls (with the assumption * that the first level is above ground) * ****************************************************************************/ create_entrance() { int xpos, ypos; LOCAT *room; EXITS *exit; room = new_location_node(); add_location_to_queue(room); room->level = startlevel; room->locationtype = STAIRWAY; exit = new_exit_node(); add_exit_to_queue(exit); exit->level = startlevel; exit->orientation = entrancedirection; exit->locationtype = ROOM; exit->parent = room; if (entrancetype == DOORWAY) { exit->exittype = DOORWAY; switch (entrancedirection) { case NORTH: exit->x1 = (mapwidth / 2) - 5; exit->x2 = (mapwidth / 2) + 5; exit->y1 = 1; exit->y2 = 1; add_line_to_location(room, (mapwidth / 2) - 5, 1, (mapwidth / 2) - 5, 0); add_line_to_location(room, (mapwidth / 2) + 5, 1, (mapwidth / 2) + 5, 0); add_line_to_location(room, 0, 0, (mapwidth / 2) - 5, 0); add_line_to_location(room, mapwidth, 0, (mapwidth / 2) + 5, 0); break; case SOUTH: exit->x1 = (mapwidth / 2) - 5; exit->x2 = (mapwidth / 2) + 5; exit->y1 = mapheight - 1; exit->y2 = mapheight - 1; add_line_to_location(room, (mapwidth / 2) - 5, mapheight - 1, (mapwidth / 2) - 5, mapheight); add_line_to_location(room, (mapwidth / 2) + 5, mapheight - 1, (mapwidth / 2) + 5, mapheight); add_line_to_location(room, 0, mapheight, (mapwidth / 2) - 5, mapheight); add_line_to_location(room, mapwidth, mapheight, (mapwidth / 2) + 5, mapheight); break; case EAST: exit->x1 = 1; exit->x2 = 1; exit->y1 = (mapheight / 2) - 5; exit->y2 = (mapheight / 2) + 5; add_line_to_location(room, 1, (mapheight / 2) - 5, 0, (mapheight / 2) - 5); add_line_to_location(room, 1, (mapheight / 2) + 5, 0, (mapheight / 2) + 5); add_line_to_location(room, 0, 0, 0, (mapheight / 2) - 5); add_line_to_location(room, 0, mapheight, 0, (mapheight/2)+5); break; case WEST: exit->x1 = mapwidth - 1; exit->x2 = mapwidth - 1; exit->y1 = (mapheight / 2) - 5; exit->y2 = (mapheight / 2) + 5; add_line_to_location(room, mapwidth - 1, (mapheight / 2) - 5, mapwidth, (mapheight / 2) - 5); add_line_to_location(room, mapwidth - 1, (mapheight / 2) + 5, mapwidth, (mapheight / 2) + 5); add_line_to_location(room, mapwidth, 0, mapwidth, (mapheight / 2) - 5); add_line_to_location(room, mapwidth, mapheight, mapwidth, (mapheight/2)+5); break; default: fatal_error("create_entrance(): unknown entrance direction"); } if (entrancedirection != NORTH) add_line_to_location(room, 0, 0, mapwidth, 0); if (entrancedirection != SOUTH) add_line_to_location(room, 0, mapheight, mapwidth, mapheight); if (entrancedirection != EAST) add_line_to_location(room, 0, 0, 0, mapheight); if (entrancedirection != WEST) add_line_to_location(room, mapwidth, 0, mapwidth, mapheight); } else if (entrancetype == STAIRWAY) { xpos = mapwidth / 2; ypos = mapheight / 2; exit->x1 = xpos; exit->y1 = ypos; exit->x2 = xpos; exit->y2 = ypos; exit->exittype = OPENING; switch (entrancedirection) { case NORTH: exit->x2 -= 10; draw_stairs_up(room, SOUTH, 10, xpos, ypos); break; case SOUTH: exit->x2 += 10; draw_stairs_up(room, NORTH, 10, xpos, ypos); break; case EAST: exit->y2 += 10; draw_stairs_up(room, WEST, 10, xpos, ypos); break; case WEST: exit->y2 -= 10; draw_stairs_up(room, EAST, 10, xpos, ypos); break; default: fatal_error("create_entrance(): unknown entrance direction"); } compress_allocated_space(room); } else fatal_error("create_entrance(): unknown entrance type"); } /**************************************************************************** * * process_exit_queue() - maintain a queue of all unfinished exits in the * dungeon, when new exits are created, add them to * the end of the queue, when ready to create a new * location, grab an exit from the front of the queue, * check if sufficient space can be allocated for the * location, and if possible create the location * (possibly with one or more exits), and removed the * now-finished exit from the queue * ****************************************************************************/ process_exit_queue() { int delta, width, xpos, ypos, flag; EXITS *exit; LOCAT *room; /* loop until all exits are finished */ while (queuehead != NULL) { exit = dequeue_exit(); /* if the exit is null, ignore it (it was probably nullified by being merged with another exit to form a new location */ if (exit == NULL) continue; /* if the exit has no parent location, something is very wrong */ if (exit->parent == NULL) fatal_error("process_exit_queue(): found exit with no parent"); /* try to join two exits together to prevent cases where locations on the map spread ever outward and never join up, which would result it annoying, unrealistic maps */ if (join_exits(exit)) { free_exit_node(exit); continue; } /* allocate a new location for the exit */ room = new_location_node(); room->xmin = MIN(exit->x1, exit->x2); room->xmax = MAX(exit->x1, exit->x2); room->ymin = MIN(exit->y1, exit->y2); room->ymax = MAX(exit->y1, exit->y2); room->locationtype = exit->locationtype; room->level = exit->level; /* shift the entrance to the room so that it does not overlap the previous room */ switch(exit->orientation) { case NORTH: room->ymin += 1; room->ymax += 1; break; case SOUTH: room->ymin -= 1; room->ymax -= 1; break; case EAST: room->xmin += 1; room->xmax += 1; break; case WEST: room->xmin -= 1; room->xmax -= 1; break; } /* determine the key position of the exit */ find_exit_position(exit, &width, &xpos, &ypos); /* expand the allocated space of the location depending upon what type of location it is */ if (exit->locationtype == JUNCTION) delta = expand_allocated_space(room, exit->orientation, width); else if (exit->locationtype == STAIRWAY) delta = expand_allocated_space(room, exit->orientation, 20); else if (exit->locationtype == PASSAGE) delta = expand_allocated_space(room, exit->orientation, ((rand() % 8) * 5) + 25); else delta = expand_allocated_space(room, exit->orientation, ((rand() % 10) * 5) + 10); /* if insufficient space is allocated, then scrap the location and seal off the exit as if never existed */ if (delta < width) { seal_exit(exit); free_exit_node(exit); continue; } flag = 0; /* create the type of location requested by the exit */ switch (exit->locationtype) { case ROOM: case CHAMBER: flag = draw_room(room, exit); break; case PASSAGE: flag = draw_passage(room, exit, delta); break; case JUNCTION: flag = draw_junction(room, exit, delta, width); break; case STAIRWAY: flag = draw_stairway(room, exit, delta, width, xpos, ypos); break; default: fatal_error("process_exit_queue(): unknown location type"); } /* if an error occurred in location creation, scrap the exit */ if (flag) { seal_exit(exit); free_exit_node(exit); continue; } /* otherwise draw the exit */ draw_exit(exit); /* do not add locationf to queue until last so will not interfer with checking of allocated space */ compress_allocated_space(room); add_location_to_queue(room); free_exit_node(exit); } } /**************************************************************************** * * join_exits() - try to join the given exit with a currently exiting exit * so can have multiple paths to the same location, otherwise * will end up with only one possible path connected two * locations which looks strange and unrealistic * ****************************************************************************/ int join_exits(exit) EXITS *exit; { int mergeflag; int sl, sr, nl, nr, et, eb, wt, wb; int sflag, nflag, eflag, wflag; int delta; EXITS *otherexit; LOCAT *newroom; QUEUE *que; /* do not join all exits that possibly can, only do some of them */ if (rand() % 2) return 0; /* do not mess with exits for stairways */ if (exit->locationtype == STAIRWAY) return 0; /* search for an exit to merge with */ mergeflag = 0; nflag = sflag = eflag = wflag = 0; que = queuehead; while (que != NULL) { if ((que->exit != NULL) && (que->exit->level == exit->level) && (que->exit->locationtype != STAIRWAY)) { otherexit = que->exit; if (otherexit->parent == NULL) fatal_error("join_exits(): second exit has no parent\n"); if (exit->orientation == NORTH) { sl = MIN(exit->x1, exit->x2); sr = MAX(exit->x1, exit->x2); sflag = 1; if (otherexit->orientation == EAST) { wt = MAX(otherexit->y1, otherexit->y2); wb = MIN(otherexit->y1, otherexit->y2); if ((otherexit->x1 < sl) && (exit->y1 < wb) && ((wt - exit->y1) <= 61) && ((sr - otherexit->x1) <= 61) && ((newroom = box_empty(wt, exit->y1+1, otherexit->x1+1, sr, exit->level)) != NULL)) { wflag = 1; mergeflag = SOUTH; break; } } else if (otherexit->orientation == SOUTH) { nl = MIN(otherexit->x1, otherexit->x2); nr = MAX(otherexit->x1, otherexit->x2); if (((otherexit->y1 - 1) > (exit->y1 + 1)) && ((otherexit->y1 - exit->y1) <= 62) && ((otherexit->y1 - exit->y1) > 11) && (abs(nl - sl) < 60) && ((newroom = box_empty(otherexit->y1 - 1, exit->y1 + 1, MIN(nl, sl), MAX(nr, sr), exit->level)) != NULL)) { nflag = 1; mergeflag = SOUTH; break; } } else if (otherexit->orientation == WEST) { et = MAX(otherexit->y1, otherexit->y2); eb = MIN(otherexit->y1, otherexit->y2); if ((otherexit->x1 > sr) && (exit->y1 < eb) && ((et - exit->y1) <= 61) && ((otherexit->x1 - sl) <= 61) && ((newroom = box_empty(et, exit->y1 + 1, sl, otherexit->x1 - 1, exit->level)) != NULL)) { eflag = 1; mergeflag = SOUTH; break; } } } else if (exit->orientation == SOUTH) { nl = MIN(exit->x1, exit->x2); nr = MAX(exit->x1, exit->x2); nflag = 1; if (otherexit->orientation == EAST) { wt = MAX(otherexit->y1, otherexit->y2); wb = MIN(otherexit->y1, otherexit->y2); if ((otherexit->x1 < nl) && (exit->y1 > wt) && ((exit->y1 - wb) <= 61) && ((nr - otherexit->x1) <= 61) && ((newroom = box_empty(exit->y1-1, wb, otherexit->x1+1, nr, exit->level)) != NULL)) { wflag = 1; mergeflag = NORTH; break; } } else if (otherexit->orientation == NORTH) { sl = MIN(otherexit->x1, otherexit->x2); sr = MAX(otherexit->x1, otherexit->x2); if (((otherexit->y1 + 1) < (exit->y1 - 1)) && ((exit->y1 - otherexit->y1) <= 62) && ((exit->y1 - otherexit->y1) > 11) && (abs(nl - sl) <= 60) && ((newroom = box_empty(exit->y1 - 1, otherexit->y1 + 1, MIN(nl,sl), MAX(nr,sr), exit->level)) != NULL)) { sflag = 1; mergeflag = NORTH; break; } } else if (otherexit->orientation == WEST) { et = MAX(otherexit->y1, otherexit->y2); eb = MIN(otherexit->y1, otherexit->y2); if ((otherexit->x1 > nr) && (exit->y1 > et) && ((exit->y1 - eb) <= 61) && ((otherexit->x1 - nl) <= 61) && ((newroom = box_empty(exit->y1 - 1, eb, nl, otherexit->x1 - 1, exit->level)) != NULL)) { eflag = 1; mergeflag = NORTH; break; } } } else if (exit->orientation == EAST) { wt = MAX(exit->y1, exit->y2); wb = MIN(exit->y1, exit->y2); wflag = 1; if (otherexit->orientation == NORTH) { sl = MIN(otherexit->x1, otherexit->x2); sr = MAX(otherexit->x1, otherexit->x2); if ((exit->x1 < sl) && (otherexit->y1 < wb) && ((sr - exit->x1) <= 61) && ((wt - otherexit->y1) <= 61) && ((newroom = box_empty(wt, otherexit->y1 + 1, exit->x1 + 1, sr, exit->level)) != NULL)) { sflag = 1; mergeflag = WEST; break; } } else if (otherexit->orientation == SOUTH) { nl = MIN(otherexit->x1, otherexit->x2); nr = MAX(otherexit->x1, otherexit->x2); if ((exit->x1 < nl) && (wt < otherexit->y1) && ((nr - exit->x1) <= 61) && ((otherexit->y1 - wb) <= 61) && ((newroom = box_empty(otherexit->y1 - 1, wb, exit->x1 + 1, nr, exit->level)) != NULL)) { nflag = 1; mergeflag = WEST; break; } } else if (otherexit->orientation == WEST) { et = MAX(otherexit->y1, otherexit->y2); eb = MIN(otherexit->y1, otherexit->y2); if (((exit->x1 + 1) < (otherexit->x1 - 1)) && ((otherexit->x1 - exit->x1) <= 62) && ((otherexit->x1 - exit->x1) > 11) && (abs(et - wt) < 60) && ((newroom = box_empty(MAX(et, wt), MIN(eb, wb), exit->x1 + 1, otherexit->x1 - 1, exit->level)) != NULL)) { eflag = 1; mergeflag = WEST; break; } } } else if (exit->orientation == WEST) { et = MAX(exit->y1, exit->y2); eb = MIN(exit->y1, exit->y2); eflag = 1; if (otherexit->orientation == NORTH) { sl = MIN(otherexit->x1, otherexit->x2); sr = MAX(otherexit->x1, otherexit->x2); if ((otherexit->y1 < eb) && (sr < exit->x1) && ((exit->x1 - sl) <= 61) && ((et - otherexit->y1) <= 61) && ((newroom = box_empty(et, otherexit->y1 + 1, sl, exit->x1 - 1, exit->level)) != NULL)) { sflag = 1; mergeflag = EAST; break; } } else if (otherexit->orientation == SOUTH) { nl = MIN(otherexit->x1, otherexit->x2); nr = MAX(otherexit->x1, otherexit->x2); if ((nr < exit->x1) && (et < otherexit->y1) && ((exit->x1 - nl) <= 61) && ((otherexit->y1 - eb) <= 61) && ((newroom = box_empty(otherexit->y1 - 1, eb, nl, exit->x1 - 1, exit->level)) != NULL)) { nflag = 1; mergeflag = EAST; break; } } else if (otherexit->orientation == EAST) { wt = MAX(otherexit->y1, otherexit->y2); wb = MIN(otherexit->y1, otherexit->y2); if (((otherexit->x1 + 1) < (exit->x1 - 1)) && ((exit->x1 - otherexit->x1) <= 62) && ((exit->x1 - otherexit->x1) > 11) && (abs(et - wt) <= 61) && ((newroom = box_empty(MAX(et, wt), MIN(eb, wb), otherexit->x1 + 1, exit->x1 - 1, exit->level)) != NULL)) { wflag = 1; mergeflag = EAST; break; } } } } que = que->queuenext; } if (!mergeflag) return (0); /* if reach this point, then have successfully found an exit to merge with */ if (debugging) printf("successful merging of two exits\n"); /* decide upon a type for the location, make small locations into junctions to try and avoid having room numbers fall in the middle of what appear to be hallways */ if (MIN(newroom->xmax - newroom->xmin, newroom->ymax - newroom->ymin) <=15) newroom->locationtype = JUNCTION; else newroom->locationtype = ROOM; newroom->level = exit->level; add_location_to_queue(newroom); /* draw the exits into this location, and try to add a few new ones */ if (nflag) { if (mergeflag == NORTH) draw_exit(exit); else { draw_exit(otherexit); que->exit = NULL; free_exit_node(otherexit); } } else { delta = expand_allocated_space(newroom, NORTH, (rand() % 3) * 5); if (rand() % 2) { nflag = 1; create_exit(newroom, NORTH, &nr, &nl); } } if (sflag) { if (mergeflag == SOUTH) draw_exit(exit); else { draw_exit(otherexit); que->exit = NULL; free_exit_node(otherexit); } } else { delta = expand_allocated_space(newroom, SOUTH, (rand() % 3) * 5); if (rand() % 2) { sflag = 1; create_exit(newroom, SOUTH, &sr, &sl); } } if (eflag) { if (mergeflag == EAST) draw_exit(exit); else { draw_exit(otherexit); que->exit = NULL; free_exit_node(otherexit); } } else { delta = expand_allocated_space(newroom, EAST, (rand() % 3) * 5); if (rand() % 2) { eflag = 1; create_exit(newroom, EAST, &et, &eb); } } if (wflag) { if (mergeflag == WEST) draw_exit(exit); else { draw_exit(otherexit); que->exit = NULL; free_exit_node(otherexit); } } else { delta = expand_allocated_space(newroom, WEST, (rand() % 3) * 5); if (rand() % 2) { wflag = 1; create_exit(newroom, WEST, &wt, &wb); } } /* draw the outline of the location */ if (nflag) { add_line_to_location(newroom, newroom->xmin, newroom->ymax, nl, newroom->ymax); add_line_to_location(newroom, nr, newroom->ymax, newroom->xmax, newroom->ymax); } else add_line_to_location(newroom, newroom->xmin, newroom->ymax, newroom->xmax, newroom->ymax); if (sflag) { add_line_to_location(newroom, newroom->xmin, newroom->ymin, sl, newroom->ymin); add_line_to_location(newroom, sr, newroom->ymin, newroom->xmax, newroom->ymin); } else add_line_to_location(newroom, newroom->xmin, newroom->ymin, newroom->xmax, newroom->ymin); if (eflag) { add_line_to_location(newroom, newroom->xmax, newroom->ymax, newroom->xmax, et); add_line_to_location(newroom, newroom->xmax, eb, newroom->xmax, newroom->ymin); } else add_line_to_location(newroom, newroom->xmax, newroom->ymax, newroom->xmax, newroom->ymin); if (wflag) { add_line_to_location(newroom, newroom->xmin, newroom->ymax, newroom->xmin, wt); add_line_to_location(newroom, newroom->xmin, wb, newroom->xmin, newroom->ymin); } else add_line_to_location(newroom, newroom->xmin, newroom->ymax, newroom->xmin, newroom->ymin); return 1; } /**************************************************************************** * * box_empty() - given a box on a certain level of the dungeon, see if there * are any locations that fall within that box, if not then * allocate a location to fill that box and return the pointer * to that location (return NULL if unable to create location) * ****************************************************************************/ LOCAT *box_empty(top, bottom, left, right, level) int top, bottom, left, right, level; { LOCAT *room, *newroom; room = firstlocation; while (room != NULL) { if ((room->level == level) && ((room->xmax >= left) && (room->xmin <= right)) && ((room->ymax >= bottom) && (room->ymin <= top))) return (NULL); room = room->next; } /* if reach here, then the location is vacant, allocate it and return a pointer to it */ newroom = new_location_node(); newroom->xmax = right; newroom->xmin = left; newroom->ymax = top; newroom->ymin = bottom; return (newroom); } /**************************************************************************** * * location_beyond_opening() - decide upon what type of a location should be * found on the other side of an opening * ****************************************************************************/ int location_beyond_opening() { int i, rtn; i = rand() % 14; if (i < 3) rtn = CHAMBER; else if (i < 5) rtn = PASSAGE; else if (i < 13) rtn = JUNCTION; else rtn = STAIRWAY; return (rtn); } /**************************************************************************** * * location_beyond_doorway() - decide what kind of location should be found * on the other side of a doorway * ****************************************************************************/ int location_beyond_doorway() { int i, rtn; i = rand() % 18; if (i < 8) rtn = ROOM; else if (i < 10) rtn = CHAMBER; else if (i < 14) rtn = PASSAGE; else rtn = JUNCTION; return (rtn); } /**************************************************************************** * * find_exit_postion() - given an exit, determine its key location and width, * exits facing different directions with the same key * position appear to revolve around that position * ****************************************************************************/ find_exit_position(exit, width, xpos, ypos) EXITS *exit; int *width, *xpos, *ypos; { switch (exit->orientation) { case NORTH: *width = MAX(exit->x1, exit->x2) - MIN(exit->x1, exit->x2); *xpos = MIN(exit->x1, exit->x2); *ypos = exit->y1; break; case SOUTH: *width = MAX(exit->x1, exit->x2) - MIN(exit->x1, exit->x2); *xpos = MAX(exit->x1, exit->x2); *ypos = exit->y1; break; case EAST: *width = MAX(exit->y1, exit->y2) - MIN(exit->y1, exit->y2); *xpos = exit->x1; *ypos = MAX(exit->y1, exit->y2); break; case WEST: *width = MAX(exit->y1, exit->y2) - MIN(exit->y1, exit->y2); *xpos = exit->x1; *ypos = MIN(exit->y1, exit->y2); break; } } /**************************************************************************** * * draw_room() - expand the space for a room, create some exits for it, and * draw all of the lines for that room/chamber * ****************************************************************************/ int draw_room(room, exit) LOCAT *room; EXITS *exit; { int xne, yne, xse, yse, xsw, ysw, xnw, ynw; int nflag, sflag, eflag, wflag; int sl, sr, nl, nr, et, eb, wt, wb; int delta2, delta3; if (debugging) printf("drawing a room\n"); /* expand space to either side of exit so that it does not look like a passage */ delta2 = expand_allocated_space(room, left_direction(exit->orientation), (rand() % 5) * 5); delta3 = expand_allocated_space(room, right_direction(exit->orientation), (rand() % 5) * 5); /* get the four corners of the room */ xne = xse = room->xmax; xnw = xsw = room->xmin; yne = ynw = room->ymax; yse = ysw = room->ymin; /* make certain that the room measures at least ten feet on a side */ if (MIN((room->xmax - room->xmin), (room->ymax - room->ymin)) < 10) return 1; nflag = sflag = eflag = wflag = 0; /* if the entrance to the room faces a certain direction, get either side of it, otherwise randomly place an exit in that wall */ if (exit->orientation == NORTH) { sl = MIN(exit->x1, exit->x2); sr = MAX(exit->x1, exit->x2); sflag = 1; } else { if (rand() % 2) { sflag = 1; create_exit(room, SOUTH, &sr, &sl); } } if (exit->orientation == SOUTH) { nl = MIN(exit->x1, exit->x2); nr = MAX(exit->x1, exit->x2); nflag = 1; } else { if (rand() % 2) { nflag = 1; create_exit(room, NORTH, &nr, &nl); } } if (exit->orientation == EAST) { wt = MAX(exit->y1, exit->y2); wb = MIN(exit->y1, exit->y2); wflag = 1; } else { if (rand() % 2) { wflag = 1; create_exit(room, WEST, &wt, &wb); } } if (exit->orientation == WEST) { et = MAX(exit->y1, exit->y2); eb = MIN(exit->y1, exit->y2); eflag = 1; } else { if (rand() % 2) { eflag = 1; create_exit(room, EAST, &et, &eb); } } /* draw the four walls of the room, leaving openings for exits */ if (nflag) { add_line_to_location(room, xnw, ynw, nl, yne); add_line_to_location(room, nr, ynw, xne, yne); } else add_line_to_location(room, xnw, ynw, xne, yne); if (sflag) { add_line_to_location(room, xsw, ysw, sl, yse); add_line_to_location(room, sr, ysw, xse, yse); } else add_line_to_location(room, xsw, ysw, xse, yse); if (eflag) { add_line_to_location(room, xne, yne, xne, et); add_line_to_location(room, xse, eb, xse, yse); } else add_line_to_location(room, xne, yne, xse, yse); if (wflag) { add_line_to_location(room, xnw, ynw, xnw, wt); add_line_to_location(room, xsw, wb, xsw, ysw); } else add_line_to_location(room, xnw, ynw, xsw, ysw); return 0; } /**************************************************************************** * * create_exit() - create an exit facing a certain direction * ****************************************************************************/ create_exit(room, orient, high, low) LOCAT *room; int orient, *high, *low; { int i, length, over, exitwidth; EXITS *newexit; /* get length of wall exit is in */ if ((orient == NORTH) || (orient == SOUTH)) length = room->xmax - room->xmin; else length = room->ymax - room->ymin; i = rand() % 10; /* decide upon a size for the exit */ if ((i < 2) && (length >= 15)) exitwidth = 15; else if ((i < 8) && (length >= 10)) exitwidth = 10; else exitwidth = 5; /* decide upon where to place the exit in the wall */ if ((length - exitwidth) > 1) over = rand() % (length - exitwidth); else over = 0; /* create the exit and add it to the queue */ newexit = new_exit_node(); add_exit_to_queue(newexit); newexit->parent = room; newexit->level = room->level; newexit->orientation = orient; /* set the location of the exit */ if ((orient == NORTH) || (orient == SOUTH)) { newexit->x1 = *high = room->xmax - over; newexit->x2 = *low = room->xmax - over - exitwidth; if (orient == NORTH) newexit->y1 = newexit->y2 = room->ymax; else newexit->y1 = newexit->y2 = room->ymin; } else { newexit->y1 = *high = room->ymax - over; newexit->y2 = *low = room->ymax - over - exitwidth; if (orient == EAST) newexit->x1 = newexit->x2 = room->xmax; else newexit->x1 = newexit->x2 = room->xmin; } /* determine what type of location lies on the other side of the exit */ if (room->locationtype == ROOM) { newexit->exittype = DOORWAY; newexit->locationtype = location_beyond_doorway(); } else { newexit->exittype = OPENING; newexit->locationtype = location_beyond_opening(); } } /**************************************************************************** * * draw_passage() - draw a passage from an exit: basically extend a hallway * in the direction the exit is facing and place a new exit * in the far end of the hallway * ****************************************************************************/ int draw_passage(room, exit, delta) LOCAT *room; EXITS *exit; int delta; { EXITS *newexit; if (debugging) printf("drawing a passage\n"); /* create the exit in the far end of the hallway */ newexit = new_exit_node(); add_exit_to_queue(newexit); newexit->orientation = exit->orientation; newexit->parent = room; newexit->level = room->level; newexit->exittype = ((rand() % 4) ? OPENING : DOORWAY); /* set the type of location beyond the exit */ if (newexit->exittype == DOORWAY) newexit->locationtype = location_beyond_doorway(); else newexit->locationtype = location_beyond_opening(); /* draw the walls of the passage and set the position of new exit */ switch (exit->orientation) { case NORTH: case SOUTH: if (exit->orientation == NORTH) { newexit->y1 = exit->y1 + delta + 1; newexit->y2 = exit->y2 + delta + 1; } else { newexit->y1 = exit->y1 - delta - 1; newexit->y2 = exit->y2 - delta - 1; } newexit->x1 = exit->x1; newexit->x2 = exit->x2; add_line_to_location(room, room->xmin, room->ymin, room->xmin, room->ymax); add_line_to_location(room, room->xmax, room->ymin, room->xmax, room->ymax); break; case EAST: case WEST: if (exit->orientation == EAST) { newexit->x1 = exit->x1 + delta + 1; newexit->x2 = exit->x2 + delta + 1; } else { newexit->x1 = exit->x1 - delta - 1; newexit->x2 = exit->x2 - delta - 1; } newexit->y1 = exit->y1; newexit->y2 = exit->y2; add_line_to_location(room, room->xmin, room->ymin, room->xmax, room->ymin); add_line_to_location(room, room->xmin, room->ymax, room->xmax, room->ymax); break; } return 0; } /**************************************************************************** * * draw_junction() - draw a passage junction, which is basically a location * with an exit that takes the entire length of a wall * but each wall is only the width of a passage * ****************************************************************************/ int draw_junction(room, exit, delta, width) LOCAT *room; EXITS *exit; int delta, width; { int xnw, ynw, xne, yne, xse, yse, xsw, ysw, count; EXITS *newexit; if (debugging) printf("drawing a junction\n"); count = 0; /* make sure a square area was allocated for the junction */ if (delta < width) seal_exit(exit); else { switch (exit->orientation) { case NORTH: xnw = xsw = MIN(exit->x1, exit->x2); xne = xse = MAX(exit->x1, exit->x2); ynw = yne = exit->y1 + 1 + width; ysw = yse = exit->y1 + 1; break; case SOUTH: xnw = xsw = MIN(exit->x1, exit->x2); xne = xse = MAX(exit->x1, exit->x2); ynw = yne = exit->y1 - 1; ysw = yse = exit->y1 - 1 - width; break; case EAST: xne = xse = exit->x1 + 1 + width; xnw = xsw = exit->x1 + 1; ynw = yne = MAX(exit->y1, exit->y2); ysw = yse = MIN(exit->y1, exit->y2); break; case WEST: xne = xse = exit->x1 - 1; xnw = xsw = exit->x1 - 1 - width; ynw = yne = MAX(exit->y1, exit->y2); ysw = yse = MIN(exit->y1, exit->y2); break; } /* add zero-length lines at each corner to assure that the necessary allocated space is not compressed */ add_line_to_location(room, xnw, ynw, xnw, ynw); add_line_to_location(room, xne, yne, xne, yne); add_line_to_location(room, xse, yse, xse, yse); add_line_to_location(room, xsw, ysw, xsw, ysw); /* if there is no exit in the north wall (facing south), then plane an exit in the north wall with .666 probability */ if (exit->orientation != SOUTH) { if (rand() % 3) { ++count; newexit = new_exit_node(); add_exit_to_queue(newexit); newexit->orientation = NORTH; newexit->parent = room; newexit->level = room->level; newexit->exittype = ((rand() % 4) ? OPENING : DOORWAY); newexit->x1 = xnw; newexit->y1 = ynw; newexit->x2 = xne; newexit->y2 = yne; if (newexit->exittype == DOORWAY) newexit->locationtype = location_beyond_doorway(); else newexit->locationtype = location_beyond_opening(); } else add_line_to_location(room, xnw, ynw, xne, yne); } if (exit->orientation != NORTH) { if (rand() % 3) { ++count; newexit = new_exit_node(); add_exit_to_queue(newexit); newexit->orientation = SOUTH; newexit->parent = room; newexit->level = room->level; newexit->exittype = ((rand() % 4) ? OPENING : DOORWAY); newexit->x1 = xse; newexit->y1 = yse; newexit->x2 = xsw; newexit->y2 = ysw; if (newexit->exittype == DOORWAY) newexit->locationtype = location_beyond_doorway(); else newexit->locationtype = location_beyond_opening(); } else add_line_to_location(room, xsw, ysw, xse, yse); } if (exit->orientation != WEST) { if (rand() % 3) { ++count; newexit = new_exit_node(); add_exit_to_queue(newexit); newexit->orientation = EAST; newexit->parent = room; newexit->level = room->level; newexit->exittype = ((rand() % 4) ? OPENING : DOORWAY); newexit->x1 = xne; newexit->y1 = yne; newexit->x2 = xse; newexit->y2 = yse; if (newexit->exittype == DOORWAY) newexit->locationtype = location_beyond_doorway(); else newexit->locationtype = location_beyond_opening(); } else add_line_to_location(room, xne, yne, xse, yse); } if (exit->orientation != EAST) { if (rand() % 3) { ++count; newexit = new_exit_node(); add_exit_to_queue(newexit); newexit->orientation = WEST; newexit->parent = room; newexit->level = room->level; newexit->exittype = ((rand() % 4) ? OPENING : DOORWAY); newexit->x1 = xsw; newexit->y1 = ysw; newexit->x2 = xnw; newexit->y2 = ynw; if (newexit->exittype == DOORWAY) newexit->locationtype = location_beyond_doorway(); else newexit->locationtype = location_beyond_opening(); } else add_line_to_location(room, xnw, ynw, xsw, ysw); } } /* return true if no exits were added to the junction, so that the junction will be junked */ return (!count); } /**************************************************************************** * * draw_stairway() - draw a stairway randomly going up or down, but abort if * go above the first level or below the maximum level * ****************************************************************************/ int draw_stairway(room, exit, delta, width, xpos, ypos) LOCAT *room; EXITS *exit; int delta, width, xpos, ypos; { LOCAT *newroom; EXITS *newexit; if (debugging) printf("drawing a stairway\n"); /* space must be 20 feet long for the stairway */ if (delta < 20) return 1; /* set the location of the stairway on the next level */ newroom = new_location_node(); newroom->xmin = MIN(exit->x1, exit->x2); newroom->xmax = MAX(exit->x1, exit->x2); newroom->ymin = MIN(exit->y1, exit->y2); newroom->ymax = MAX(exit->y1, exit->y2); newroom->locationtype = STAIRWAY; /* give an exit for the stairway on the new level */ newexit = new_exit_node(); newexit->x1 = exit->x1; newexit->y1 = exit->y1; newexit->x2 = exit->x2; newexit->y2 = exit->y2; newexit->orientation = exit->orientation; newexit->locationtype = location_beyond_opening(); newexit->exittype = OPENING; newexit->parent = newroom; /* determine the postion of the exit at the top/bottom of the stairs */ switch (exit->orientation) { case NORTH: newexit->y1 += 20; newexit->y2 += 20; break; case SOUTH: newexit->y1 -= 20; newexit->y2 -= 20; break; case EAST: newexit->x1 += 20; newexit->x2 += 20; break; case WEST: newexit->x1 -= 20; newexit->x2 -= 20; break; } /* stairs go up or down with random probability */ if (rand() % 2) { if (room->level <= startlevel) return 1; /* set the stairway to go up (decreasing level number) */ room->locationdata = UP; newroom->locationdata = DOWN; newroom->level = room->level - 1; delta = expand_allocated_space(newroom, exit->orientation, 20); if (delta < 20) return 1; draw_stairs_up(room, exit->orientation, width, xpos, ypos); switch (exit->orientation) { case NORTH: draw_stairs_down(newroom, SOUTH, width, xpos+width, ypos+20); break; case SOUTH: draw_stairs_down(newroom, NORTH, width, xpos-width, ypos-20); break; case EAST: draw_stairs_down(newroom, WEST, width, xpos+20, ypos-width); break; case WEST: draw_stairs_down(newroom, EAST, width, xpos-20, ypos+width); break; } } else { if (room->level >= maxlevel) return 1; /* set the stairway going down (increasing level number) */ room->locationdata = DOWN; newroom->locationdata = UP; newroom->level = room->level + 1; delta = expand_allocated_space(newroom, exit->orientation, 20); if (delta < 20) return 1; draw_stairs_down(room, exit->orientation, width, xpos, ypos); switch (exit->orientation) { case NORTH: draw_stairs_up(newroom, SOUTH, width, xpos+width, ypos+20); break; case SOUTH: draw_stairs_up(newroom, NORTH, width, xpos-width, ypos-20); break; case EAST: draw_stairs_up(newroom, WEST, width, xpos+20, ypos-width); break; case WEST: draw_stairs_up(newroom, EAST, width, xpos-20, ypos+width); break; } } newexit->level = newroom->level; add_location_to_queue(newroom); add_exit_to_queue(newexit); /* always return with no error condition */ return 0; } /**************************************************************************** * * draw_stairs_down() - draw the lines for a stairway going down * ****************************************************************************/ draw_stairs_down(room, orient, width, xpos, ypos) LOCAT *room; int orient, width, xpos, ypos; { int i; for (i = 0; i < 11; ++i) { switch (width) { case 5: add_line_to_location(room, xpos + stairwaydownlines5[orient-NORTH][i][0], ypos + stairwaydownlines5[orient-NORTH][i][1], xpos + stairwaydownlines5[orient-NORTH][i][2], ypos + stairwaydownlines5[orient-NORTH][i][3]); break; case 10: add_line_to_location(room, xpos + stairwaydownlines10[orient-NORTH][i][0], ypos + stairwaydownlines10[orient-NORTH][i][1], xpos + stairwaydownlines10[orient-NORTH][i][2], ypos + stairwaydownlines10[orient-NORTH][i][3]); break; case 15: add_line_to_location(room, xpos + stairwaydownlines15[orient-NORTH][i][0], ypos + stairwaydownlines15[orient-NORTH][i][1], xpos + stairwaydownlines15[orient-NORTH][i][2], ypos + stairwaydownlines15[orient-NORTH][i][3]); break; default: printf("width: %d\n", width); fatal_error("draw_stairs_down(): bad width of stairway"); } } } /**************************************************************************** * * draw_stairs_up() - draw the lines for a stairway going up * ****************************************************************************/ draw_stairs_up(room, orient, width, xpos, ypos) LOCAT *room; int orient, width, xpos, ypos; { int i; for (i = 0; i < 11; ++i) { switch (width) { case 5: add_line_to_location(room, xpos + stairwayuplines5[orient-NORTH][i][0], ypos + stairwayuplines5[orient-NORTH][i][1], xpos + stairwayuplines5[orient-NORTH][i][2], ypos + stairwayuplines5[orient-NORTH][i][3]); break; case 10: add_line_to_location(room, xpos + stairwayuplines10[orient-NORTH][i][0], ypos + stairwayuplines10[orient-NORTH][i][1], xpos + stairwayuplines10[orient-NORTH][i][2], ypos + stairwayuplines10[orient-NORTH][i][3]); break; case 15: add_line_to_location(room, xpos + stairwayuplines15[orient-NORTH][i][0], ypos + stairwayuplines15[orient-NORTH][i][1], xpos + stairwayuplines15[orient-NORTH][i][2], ypos + stairwayuplines15[orient-NORTH][i][3]); break; default: printf("width: %d\n", width); fatal_error("draw_stairs_up(): bad width of stairway"); } } } /**************************************************************************** * * draw_exit() - given an exit, draw the actual lines that form it, the lines * which form an exit are placed with the parent of the exit * ****************************************************************************/ draw_exit(exit) EXITS *exit; { int width, xpos, ypos; find_exit_position(exit, &width, &xpos, &ypos); if (exit->parent == NULL) fatal_error("draw_exit(): exit has no parent pointer"); if (exit->exittype == DOORWAY) draw_doorway(exit->parent, exit->orientation, width, xpos, ypos); else if (exit->exittype == OPENING) draw_opening(exit->parent, exit->orientation, width, xpos, ypos); else fatal_error("process_exit_queue(): unknown exit type"); } /**************************************************************************** * * draw_doorway() - draw the lines for a doorway * ****************************************************************************/ draw_doorway(room, orient, width, xpos, ypos) LOCAT *room; int orient, width, xpos, ypos; { int i; if (debugging) printf("drawing a doorway\n"); switch (width) { case 5: for (i = 0; i < 8; ++i) add_line_to_location(room, xpos + doorwaylines5[orient-NORTH][i][0], ypos + doorwaylines5[orient-NORTH][i][1], xpos + doorwaylines5[orient-NORTH][i][2], ypos + doorwaylines5[orient-NORTH][i][3]); break; case 10: for (i = 0; i < 8; ++i) add_line_to_location(room, xpos + doorwaylines10[orient-NORTH][i][0], ypos + doorwaylines10[orient-NORTH][i][1], xpos + doorwaylines10[orient-NORTH][i][2], ypos + doorwaylines10[orient-NORTH][i][3]); break; case 15: for (i = 0; i < 9; ++i) add_line_to_location(room, xpos + doorwaylines15[orient-NORTH][i][0], ypos + doorwaylines15[orient-NORTH][i][1], xpos + doorwaylines15[orient-NORTH][i][2], ypos + doorwaylines15[orient-NORTH][i][3]); break; default: printf("width given as %d\n", width); fatal_error("draw_doorway(): bad width of doorway"); } } /**************************************************************************** * * draw_opening() - draw the lines for an opening in the wall * ****************************************************************************/ draw_opening(room, orient, width, xpos, ypos) LOCAT *room; int orient, width, xpos, ypos; { if (debugging) printf("drawing an opening\n"); switch (orient) { case NORTH: add_line_to_location(room, xpos, ypos, xpos, ypos+1); add_line_to_location(room, xpos+width, ypos, xpos+width, ypos+1); break; case SOUTH: add_line_to_location(room, xpos, ypos, xpos, ypos-1); add_line_to_location(room, xpos-width, ypos, xpos-width, ypos-1); break; case EAST: add_line_to_location(room, xpos, ypos, xpos+1, ypos); add_line_to_location(room, xpos, ypos-width, xpos+1, ypos-width); break; case WEST: add_line_to_location(room, xpos, ypos, xpos-1, ypos); add_line_to_location(room, xpos, ypos+width, xpos-1, ypos+width); break; } } /**************************************************************************** * * seal_exit() - seal off an exit by drawing a line across the space in the * wall where it should have gone * ****************************************************************************/ seal_exit(exit) EXITS *exit; { if (debugging) printf("sealing an exit\n"); add_line_to_location(exit->parent, exit->x1, exit->y1, exit->x2, exit->y2); } /**************************************************************************** * * add_line_to_location() - given the endpoints of a line, place the line in * the list of lines for the room * ****************************************************************************/ add_line_to_location(room, x1, y1, x2, y2) LOCAT *room; int x1, y1, x2, y2; { LINES *line; line = new_line_node(); line->next = room->firstline; room->firstline = line; line->x1 = x1; line->y1 = y1; line->x2 = x2; line->y2 = y2; } /**************************************************************************** * * compress_allocated_space() - find the minimum amount of space occupied by * a location, to make sure the location is not * accidentally allocated more than it needs * ****************************************************************************/ compress_allocated_space(room) LOCAT *room; { int minx = mapwidth, miny = mapheight, maxx = 0, maxy = 0; LINES *line; line = room->firstline; /* do nothing if here are no lines */ if (line == NULL) return; while (line != NULL) { minx = MIN(minx, line->x1); minx = MIN(minx, line->x2); maxx = MAX(maxx, line->x1); maxx = MAX(maxx, line->x2); miny = MIN(miny, line->y1); miny = MIN(miny, line->y2); maxy = MAX(maxy, line->y1); maxy = MAX(maxy, line->y2); line = line->next; } room->xmin = minx; room->xmax = maxx; room->ymin = miny; room->ymax = maxy; } /**************************************************************************** * * expand_allocated_space() - expand the space allocated to a location in * a given direction for a given distance, * and return the amount actually expanded * ****************************************************************************/ int expand_allocated_space(location, direction, maxdelta) LOCAT *location; int direction, maxdelta; { int delta, lvl; LOCAT *room; /* just return zero if amount to expand is less than one */ if (maxdelta < 1) return (0); lvl = location->level; switch (direction) { case NORTH: /* try to expand the allocated space as far as possible to the north */ delta = mapheight; room = firstlocation; while (room != NULL) { if ((room->level == lvl) && (room->xmax >= location->xmin) && (room->xmin <= location->xmax) && (room->ymax >= location->ymin)) delta = MIN(delta, room->ymin); room = room->next; } /* get the amount of change and decrement it, so allocated space does not overlap another location */ delta = delta - location->ymax - 1; /* make sure do not expand it more than requested */ if (delta > maxdelta) delta = maxdelta; /* if actually allocated some space, increase the amount of space allocated */ if (delta > 0) location->ymax += delta; break; case SOUTH: delta = 0; room = firstlocation; while (room != NULL) { if ((room->level == lvl) && (room->xmax >= location->xmin) && (room->xmin <= location->xmax) && (room->ymin <= location->ymax)) delta = MAX(delta, room->ymax); room = room->next; } delta = location->ymin - delta - 1; if (delta > maxdelta) delta = maxdelta; if (delta > 0) location->ymin -= delta; break; case EAST: delta = mapwidth; room = firstlocation; while (room != NULL) { if ((room->level == lvl) && (room->ymax >= location->ymin) && (room->ymin <= location->ymax) && (room->xmax >= location->xmin)) delta = MIN(delta, room->xmin); room = room->next; } delta = delta - location->xmax - 1; if (delta > maxdelta) delta = maxdelta; if (delta > 0) location->xmax += delta; break; case WEST: delta = 0; room = firstlocation; while (room != NULL) { if ((room->level == lvl) && (room->ymax >= location->ymin) && (room->ymin <= location->ymax) && (room->xmin <= location->xmax)) delta = MAX(delta, room->xmax); room = room->next; } delta = location->xmin - delta - 1; if (delta > maxdelta) delta = maxdelta; if (delta > 0) location->xmin -= delta; break; default: fatal_error("expand_allocated_space(): unknown direction"); } /* return the amount that the allocated space was expanded */ return (delta); } /**************************************************************************** * * opposite_direction() - return the direction opposite to that given * ****************************************************************************/ int opposite_direction(dir) int dir; { int i; switch (dir) { case NORTH: i = SOUTH; break; case SOUTH: i = NORTH; break; case EAST: i = WEST; break; case WEST: i = EAST; break; case UP: i = DOWN; break; case DOWN: i = UP; break; default: fatal_error("opposite_direction(): unknown direction"); } return (i); } /**************************************************************************** * * left_direction() - return the direction to the left of that given * ****************************************************************************/ int left_direction(dir) int dir; { int i; switch (dir) { case NORTH: i = WEST; break; case SOUTH: i = EAST; break; case EAST: i = NORTH; break; case WEST: i = SOUTH; break; default: fatal_error("left_direction(): unknown direction"); } return (i); } /**************************************************************************** * * right_direction() - return the direction to the right of that given * ****************************************************************************/ int right_direction(dir) int dir; { int i; switch (dir) { case NORTH: i = EAST; break; case SOUTH: i = WEST; break; case EAST: i = SOUTH; break; case WEST: i = NORTH; break; default: fatal_error("right_direction(): unknown direction"); } return (i); } /**************************************************************************** * * print_postscript_file() - print out the dungeon in PostScript format * ****************************************************************************/ print_postscript_file() { char fname[100]; int lvl; FILE *fopen(), *outfile; LOCAT *room; LINES *line; /* print out a separate file for each level, since they can get big */ for (lvl = startlevel; lvl <= maxlevel; ++lvl) { /* get the name of the file */ sprintf(fname, "%s%d.ps", filename, lvl); printf("Drawing dungeon level %d to file \"%s\".\n", lvl, fname); if ((outfile = fopen(fname, "w")) == NULL) fatal_error("unable to open file \"%s\" for output", fname); /* print out the postscript header */ fprintf(outfile, "%%!PS-Adobe-1.0\n\n"); fprintf(outfile, "/Times-Roman findfont 12 scalefont\nsetfont\n\n"); fprintf(outfile, "newpath\n 50 750 moveto\n(Level %d) show\n\n", lvl); fprintf(outfile, "/Times-Roman findfont 6 scalefont\nsetfont\n\n"); /* print out a boarder for the level if not built into the level due to having a doorway entrance to the level */ if ((lvl != startlevel) || (entrancetype != DOORWAY)) { fprintf(outfile, "newpath\n 50 30 moveto\n 50 %4d lineto\n", YSIZE + 30); fprintf(outfile, " 50 30 moveto\n %4d 30 lineto\n", XSIZE + 50); fprintf(outfile, " %4d 30 moveto\n %4d %4d lineto\n", XSIZE + 50, XSIZE + 50, YSIZE + 30); fprintf(outfile, " 50 %4d moveto\n %4d %4d lineto\nstroke\n\n", YSIZE + 30, XSIZE + 50, YSIZE + 30); } /* loop through all locations and print out the ones on the current level */ room = firstlocation; while (room != NULL) { if (room->level == lvl) { line = room->firstline; /* print the room number if it is a numbered location and the user has requested numbering be turned on */ if (numberoutput && (room->number != 0)) fprintf(outfile, "newpath\n %d %d moveto\n(%d) show\n\n", scale_x(room->xmin + 2) + 50, scale_y(room->ymin + 2) + 30, room->number); /* print out all lines associated with this location (provided the lines have a non-zero length */ fprintf(outfile, "newpath\n"); while (line != NULL) { if ((line->x1 != line->x2) || (line->y1 != line->y2)) fprintf(outfile, " %d %d moveto\n %d %d lineto\n", scale_x(line->x1) + 50, scale_y(line->y1) +30, scale_x(line->x2) + 50, scale_y(line->y2) +30); line = line->next; } fprintf(outfile, "stroke\n\n"); } room = room->next; } /* close the file for the current level */ fprintf(outfile, "showpage\n"); fclose(outfile); } } /**************************************************************************** ****************************************************************************/ print_latex_file() { char fname[100]; int i, dx, dy, length, lvl; FILE *fopen(), *outfile; LOCAT *room; LINES *line; /* print out a separate file for each level, since they can get big */ for (lvl = startlevel; lvl <= maxlevel; ++lvl) { /* get the name of the file */ sprintf(fname, "%s%d.tex", filename, lvl); printf("Drawing dungeon level %d to file \"%s\".\n", lvl, fname); if ((outfile = fopen(fname, "w")) == NULL) fatal_error("unable to open file \"%s\" for output", fname); /* print out the latex header */ for (i = 0; i < LATEXHEADERLEN; ++i) fprintf(outfile, "%s\n", latexheader[i]); fprintf(outfile, "\n\\put(10,720){\\shortstack{Level %d}}\n\n", lvl); /* print out a boarder for the level if not built into the level due to having a doorway entrance to the level */ if ((lvl != startlevel) || (entrancetype != DOORWAY)) { fprintf(outfile, "\\put(0,0){\\line(0,1){%d}}\n", YSIZE); fprintf(outfile, "\\put(0,0){\\line(1,0){%d}}\n", XSIZE); fprintf(outfile, "\\put(0,%d){\\line(1,0){%d}}\n", YSIZE, XSIZE); fprintf(outfile, "\\put(%d,0){\\line(0,1){%d}}\n", XSIZE, YSIZE); } /* loop through all locations and print out the ones on the current level */ room = firstlocation; while (room != NULL) { if (room->level == lvl) { /* print the room number if it is a numbered location and the user has requested numbering be turned on */ if (numberoutput && (room->number != 0)) fprintf(outfile,"\\put(%d,%d){\\shortstack{\\small{%d}}}\n", scale_x(room->xmin + 2), scale_x(room->ymin + 2), room->number); /* print out all lines associated with this location (provided the lines have a non-zero length */ line = room->firstline; while (line != NULL) { dx = 0; dy = 0; if (line->x1 != line->x2) { dx = ((line->x1 < line->x2) ? (1) : (-1)); length = abs(scale_x(line->x1) - scale_x(line->x2)); } else if (line->y1 != line->y2) { dy = ((line->y1 < line->y2) ? (1) : (-1)); length = abs(scale_y(line->y1) - scale_y(line->y2)); } else { line = line->next; continue; } fprintf(outfile, "\\put(%d,%d){\\line(%d,%d){%d}}\n", scale_x(line->x1), scale_y(line->y1), dx, dy, length); line = line->next; } } room = room->next; } /* close the file for the current level */ fprintf(outfile, "\n\\end{picture}\n\\end{document}\n"); fclose(outfile); } } /**************************************************************************** * * scale_x() - scale the position of a point to the map's scale * ****************************************************************************/ int scale_x(foo) int foo; { foo = ((float)XSIZE / (float)mapwidth) * (float)foo; return (foo); } /**************************************************************************** * * scale_y() - scale a point's position so it fits the size of the map * ****************************************************************************/ int scale_y(foo) int foo; { foo = ((float)YSIZE / (float)mapheight) * (float)foo; return (foo); } /**************************************************************************** * * new_exit_node() - return a pointer to a new (or reused) exit node * ****************************************************************************/ EXITS *new_exit_node() { EXITS *ext; if (exitfreestack != NULL) { ext = exitfreestack; exitfreestack = exitfreestack->next; } else if ((ext = (EXITS*)malloc(sizeof(EXITS))) == NULL) fatal_error("new_Exit_node(): malloc memory failed"); ext->orientation = 0; ext->x1 = 0; ext->y1 = 0; ext->x2 = 0; ext->y2 = 0; ext->exittype = 0; ext->locationtype = ROOM; ext->parent = NULL; ext->next = NULL; ext->level = 0; return (ext); } /**************************************************************************** * * free_exit_node() - free up the memory used by an exit node * ****************************************************************************/ free_exit_node(ext) EXITS *ext; { ext->parent = NULL; ext->next = exitfreestack; exitfreestack = ext; } /**************************************************************************** * * new_line_node() - return a pointer to a new line node * ****************************************************************************/ LINES *new_line_node() { LINES *lin; if ((lin = (LINES*)malloc(sizeof(LINES))) == NULL) fatal_error("new_line_node(): malloc memory failed"); lin->x1 = 0; lin->y1 = 0; lin->x2 = 0; lin->y2 = 0; lin->next = NULL; return (lin); } /**************************************************************************** * * new_location_node() - return a pointer to a new location node * ****************************************************************************/ LOCAT *new_location_node() { LOCAT *loc; if ((loc = (LOCAT*)malloc(sizeof(LOCAT))) == NULL) fatal_error("new_location_node(): malloc memory failed"); loc->xmin = 0; loc->xmax = 0; loc->ymin = 0; loc->ymax = 0; loc->locationtype = ROOM; loc->locationdata = -666; loc->level = 0; loc->number = 0; loc->firstline = NULL; loc->next = NULL; loc->previous = NULL; return (loc); } /**************************************************************************** * * new_queue_node() - return a pointer to a new (or reused) exit queue node * ****************************************************************************/ QUEUE *new_queue_node() { QUEUE *que; if (queuefreestack != NULL) { que = queuefreestack; queuefreestack = queuefreestack->queuenext; } else if ((que = (QUEUE*)malloc(sizeof(QUEUE))) == NULL) fatal_error("new_queue_node(): malloc memory failed"); que->exit = NULL; que->queuenext = NULL; return (que); } /**************************************************************************** * * free_queue_node() - free up the memory used by an exit queue node * ****************************************************************************/ free_queue_node(que) QUEUE *que; { que->queuenext = queuefreestack; queuefreestack = que; que->exit = NULL; } /**************************************************************************** * * add_exit_to_queue() - and an exit to the queue of exit nodes * ****************************************************************************/ add_exit_to_queue(exit) EXITS *exit; { QUEUE *que; ++gc; if (debugging) printf("adding exit to queue, newsize: %d\n", gc); else { printf("%4d", gc); ++gcnum; if (gcnum > 15) { gcnum = 0; printf("\n"); } } que = new_queue_node(); que->exit = exit; if (queuehead == NULL) queuehead = queuetail = que; else { /* decude whether to place new exit at front or end of queue */ if (EXITSTACK) { /* do as stack */ que->queuenext = queuehead; queuehead = que; } else { /* do as queue */ queuetail->queuenext = que; queuetail = que; } } } /**************************************************************************** * * dequeue_exit() - remove an exit from the queue of exit nodes, note that * the pointer which is returned may still be NULL, which * typically results from joining two exits and NULLing * the pointer to a node in the middle of the queue, which * is easier than trying to completely yank the node from * the middle of the queue * ****************************************************************************/ EXITS *dequeue_exit() { EXITS *ext; QUEUE *que; --gc; if (!debugging) { printf("%4d", gc); ++gcnum; if (gcnum > 15) { gcnum = 0; printf("\n"); } } /* make sure there is an exit queue node */ if (queuehead == NULL) fatal_error("dequeue_exit(): attempt to dequeue from empty queue"); ext = queuehead->exit; que = queuehead; if (queuehead->queuenext == NULL) queuehead = queuetail = NULL; else queuehead = queuehead->queuenext; free_queue_node(que); return (ext); } /**************************************************************************** * * add_location_to_queue() - add a location to the list of locations * ****************************************************************************/ add_location_to_queue(ptr) LOCAT *ptr; { if (firstlocation == NULL) firstlocation = lastlocation = ptr; else { ptr->next = NULL; ptr->previous = lastlocation; lastlocation->next = ptr; lastlocation = ptr; } } /**************************************************************************** * * fatal_error() - print out a fatal error message and abort execution * ****************************************************************************/ fatal_error(strg, arg) char strg[], arg[]; { printf("Error: "); printf(strg, arg); printf("\n\n"); exit(1); }