[MUD-Dev] Re: MapMaker

Matthew R. Sheahan chaos at crystal.palace.net
Sat Jul 11 17:56:50 CEST 1998


oliver at jowett.manawatu.planet.co.nz propagated a meme to the effect of:
> 3d is more flexible than 2d. However 3d is considerably
> more complex than 2d. So..

enclosed are some meat and bones from the 3d map generation mechanism i
created for Lost Souls.  it is not intended to be featureful, but rather
adequate to its task without being terribly expensive.  in fact, i have
to constantly fight off people who want to make it featureful in ways
like handling exits beyond NSEWUD without thinking the matter through.
it derives its configuration from files which basically contain painting
directives.  the existing painting directives are entirely 2d in nature
because this is computationally cheap and because i don't know anything
about 3d graphics programming.

this is LPC code for the Amylaar LPMud driver.

the files included are in this order:

map.conf: a sample map configuration file
rooms.conf: a sample map room configuration file
overlays.conf: a sample map overlay configuration file
map.c: the map generation daemon inheritable
map_room.c: the specialized room file used for maps

								chiaroscuro

----------------------------- begin map.conf ---------------------------------

// Map configuration file by Chaos, Mon Dec  4 15:19:49 CST 1995

<X> 40			// Number of points + and - from origin on X
<Y> 40			// Number of points + and - from origin on Y
<Z> 5			// Number of points + and - from origin on Z

<Population> 150	// Maximum number of inhabitants to maintain

<FillerType> Earth Earth Earth Earth Earth Plains Air Air Air Air Air
			// Use this room type for default; this must be set!
			// FillerType must occur after X, Y, Z, and Population
			// Regions must occur after FillerType
			// FillerType can either be a single room type which
			// will be used for all rooms, or one room type for
			// each map plane (a total of (Z * 2) + 1), in order
			// from bottom to top

<Region Cloud>
  <Point> 2, 20/20
</Region>

// The Caelidh Meadows

<Region CaelidhMeadows>
  <Circle> 0, 20/22, 4
</Region>

// The Blackwood

<Region BlackwoodLower>
  <Circle> 0, 20/20, 2
</Region>

<Region BlackwoodUpper>
  <Circle> 1, 20/20, 2
</Region>

<Region BlackwoodOuter>
  <SurroundRoom> 0, BlackwoodLower
</Region>

// The Dune Sea

<Region DuneSea>
  <Rectangle> 0, -15/15, 25/-15
</Region>

// The Great Rift

<Region Rift>
  <Line> 0, 14/-4, 21/-3
  <Line> -1, 14/-4, 21/-3
  <Line> -2, 14/-4, 21/-3
  <Line> -3, 14/-4, 21/-3
  <Line> -4, 14/-4, 21/-3
</Region>

<Region RiftEdge>
  <Line> 0, 14/-3, 21/-2
  <Line> 0, 14/-5, 21/-4
</Region>

<Region RiftWall>
  <Line> -1, 14/-3, 21/-2
  <Line> -1, 14/-5, 21/-4
  <Line> -2, 14/-3, 21/-2
  <Line> -2, 14/-5, 21/-4
  <Line> -3, 14/-3, 21/-2
  <Line> -3, 14/-5, 21/-4
  <Line> -4, 14/-3, 21/-2
  <Line> -4, 14/-5, 21/-4
</Region>

<Region RiftBottom>
  <BroadLine> -5, -2, 14/-3, 21/-2
</Region>

// The Worldspine

<Region WorldspineBase>
  <Line> 0, -35/36, 30/36
  <Point> 0, -36/37
  <Point> 0, -36/38
  <Point> 0, -37/39
  <Point> 0, -37/40
  <Point> 0, 31/37
  <Point> 0, 31/38
  <Point> 0, 32/39
  <Point> 0, 32/40
</Region>

<Region WorldspineSlope>
  <Line> 1, -35/36, 30/36
  <Line> 1, -36/37, 31/37
  <Line> 1, -36/38, 31/38
  <Line> 1, -37/39, 32/39
  <Line> 1, -37/40, 32/40
  <BroadLine> 4, -2, -19/39, -17/39
  <BroadLine> 3, -4, -20/39, -16/39
  <BroadLine> 2, -4, -20/40, -16/40
  <BroadLine> 4, -2, 19/39, 21/39
  <BroadLine> 3, -4, 18/39, 22/39
  <BroadLine> 2, -4, 18/40, 22/40
  <BroadLine> 4, -2, 6/39, 8/39
  <BroadLine> 3, -4, 5/39, 9/39
  <BroadLine> 2, -4, 5/40, 9/40
  <BroadLine> 4, -2, -2/39, 0/39
  <BroadLine> 3, -4, -3/39, 1/39
  <BroadLine> 2, -4, -3/40, 1/40
  <BroadLine> 4, -2, -11/39, -9/39
  <BroadLine> 3, -4, -12/39, -8/39
  <BroadLine> 2, -4, -12/40, -8/40
  <BroadLine> 4, -2, -25/39, -23/39
  <BroadLine> 3, -4, -26/39, -22/39
  <BroadLine> 2, -4, -26/40, -22/40
  <BroadLine> 4, -2, -32/39, -30/39
  <BroadLine> 3, -4, -33/39, -29/39
  <BroadLine> 2, -4, -33/40, -29/40
  <BroadLine> 4, -2, 27/39, 29/39
  <BroadLine> 3, -4, 26/39, 30/39
  <BroadLine> 2, -4, 26/40, 30/40
</Region>

<Region WorldspinePeak>
  <Point> 5, -18/38
  <Point> 5, 20/38
  <Point> 5, 7/38
  <Point> 5, -1/38
  <Point> 5, -10/38
  <Point> 5, -24/38
  <Point> 5, -31/38
  <Point> 5, 28/38
</Region>

<Region WorldspineInterior>
  <Line> 0, -35/37, 30/37
  <Line> 0, -35/38, 30/38
  <Line> 0, -36/39, 31/39
  <Line> 0, -36/40, 31/40
  <Point> 3, -18/38
  <BroadLine> 2, -2, -19/39, -17/39
  <BroadLine> 1, -2, -19/39, -17/39
  <Point> 3, 20/38
  <BroadLine> 2, -2, 19/39, 21/39
  <BroadLine> 1, -2, 19/39, 21/39
  <Point> 3, 7/38
  <BroadLine> 2, -2, 6/39, 8/39
  <BroadLine> 1, -2, 6/39, 8/39
  <Point> 3, -1/38
  <BroadLine> 2, -2, -2/39, 0/39
  <BroadLine> 1, -2, -2/39, 0/39
  <Point> 3, -10/38
  <BroadLine> 2, -2, -11/39, -9/39
  <BroadLine> 1, -2, -11/39, -9/39
  <Point> 3, -24/38
  <BroadLine> 2, -2, -25/39, -23/39
  <BroadLine> 1, -2, -25/39, -23/39
  <Point> 3, -31/38
  <BroadLine> 2, -2, -32/39, -30/39
  <BroadLine> 1, -2, -32/39, -30/39
  <Point> 3, 28/38
  <BroadLine> 2, -2, 27/39, 29/39
  <BroadLine> 1, -2, 27/39, 29/39
</Region>

<Region WorldspineFoothills>
  <Line> 0, -36/35, 31/35
  <Line> 0, -35/34, 30/34
  <Point> 0, -37/36
  <Point> 0, -37/38
  <Point> 0, -38/39
  <Point> 0, -38/40
  <Point> 0, 32/37
  <Point> 0, 32/38
  <Point> 0, 33/39
  <Point> 0, 33/40
</Region>

// The Atalantic Ocean

<Region AtalanticSurface>
  <Rectangle> 0, -40/40, -33/27
  <Circle> 0, -30/30, 10
</Region>

<Region AtalanticShore>
  <SurroundRoom> 0, AtalanticSurface
</Region>

<Region AtalanticBottomShallow>
  <Circle> -3, -30/30, 10
</Region>

<Region AtalanticShallow>
  <Rectangle> -1, -40/40, -33/27
  <Circle> -1, -30/30, 10
  <Rectangle> -2, -40/40, -33/27
  <Circle> -2, -30/30, 10
  <Rectangle> -3, -40/40, -33/27
</Region>

<Region AtalanticDeep>
  <Rectangle> -4, -40/40, -33/27
</Region>

<Region AtalanticBottomDeep>
  <Rectangle> -5, -40/40, -33/27
</Region>

// Roads

<Overlay AltrianRoad>
  <Line> 0, 10/20, 30/20
  <Line> 0, 20/30, 20/10
</Overlay>

------------------------------- end map.conf ---------------------------------

----------------------------- begin rooms.conf -------------------------------

// Map room types configuration file by Chaos, Mon Dec  4 15:54:28 CST 1995
//
// Notes:
//   The RoomType BASE is a special type which sets the defaults for
//   other RoomTypes.
//
//   The BASE room class only applies to classes which come after it.
//   You can take advantage of this using multiple BASE class definitions.
//
//   The maximum number of definable RoomTypes is 255, not counting any BASE
//   classes.

<RoomType BASE>		// BASE class sets defaults for all other types
  <Realms> Almeria	// Realms to set
  <Light> 1		// Light level to set
  <Outdoors> 4		// Outdoors level to set
  <Access> walk		// How one can get into it
</RoomType>

// Non-specific terrains

<RoomType Plains>
  <ShortDesc> a rolling plain
  <LongDesc> This is a region of gently rolling plains, with tall grasses growing everywhere.
  <AdjacentDesc> %t are rolling plains.
  <Terrain> plains
  <Inhabited> 10
  <Inhabitants> bison wolf
</RoomType>

<RoomType Air>
  <Outdoors> 0
  <ShortDesc> the air
  <LongDesc> This is the empty air above the surface of the world.
  <Items> empty air,,air::There is little to remark upon about thin air.
  <Terrain> air
  <Access> fly
  <Altitude> 1
</RoomType>

<RoomType Cloud>
  <ShortDesc> a cloud
  <LongDesc> This is the midst of a cloud, its gray vapor permeating and obscuring the otherwise empty air.
  <Items> empty air,,air::Its only feature is the cloud vapor within it.;;cloud,,vapor,,cloud vapor::A haze of cold moisture hanging in the air.
  <Terrain> cloud
  <AdjacentDesc> There is a cloud %t.
  <Access> fly
  <Altitude> 1
</RoomType>

<RoomType Earth>
  <ShortDesc> the depths of the earth
  <Terrain> underground
  <Access> tunnel
  <Light> 0
  <Outdoors> 0
  <Altitude> -1
</RoomType>

// Caelidh Meadows rooms

<RoomType CaelidhMeadows>
  <ShortDesc> the Caelidh Meadows
  <LongDesc> Soft grasses and flowers grow upon the gently rolling terrain of the Caelidh Meadows.  The soft chirping of crickets drifts through the air.
  <AdjacentDesc> %w are the Caelidh Meadows.
  <Terrain> meadow
</RoomType>

// Dune Sea rooms

<RoomType DuneSea>
  <ShortDesc> the Dune Sea
  <LongDesc> The seemingly endless sands of the Dune Sea, the great desert stretching across the center of Almeria, shift ceaselessly all around.
  <AdjacentDesc> The Dune Sea is %w.
  <Items> Dune Sea,,dune sea,,desert,,sands,,sand::The sands, blown constantly by the wind, build up into the great shifting dunes for which the desert is named.
  <Terrain> desert
</RoomType>

// Worldspine rooms

<RoomType WorldspineFoothills>
  <ShortDesc> the foothills of the Worldspine
  <LongDesc> These are the foothills of the Worldspine, the range of massive barrier peaks that separate the lands of Almeria from the Northlands.  The broken hills are covered with light evergreen forest.
  <AdjacentDesc> %t are the foothills of the Worldspine.
  <Items> foothills,,hills,,broken hills::The hills are roughly formed and steep in places.;;forest,,light forest,,trees,,evergreen forest,,light evergreen forest::A variety of trees, mostly pine and spruce, form a light layer of forestation upon these hills.;;Worldspine,,worldspine,,peaks,,mountains::The intimidating Worldspine range is comprised of formidable, jagged mountains.
  <Terrain> hills forest
</RoomType>

<RoomType WorldspineBase>
  <ShortDesc> the base of the Worldspine
  <LongDesc> Jutting from the earth are the mountains of the Worldspine, terrible peaks that reach toward the sky like stone claws.  Here, at their base, they bear a light cover of evergreen forest.
  <AdjacentDesc> The base of the Worldspine is %w.
  <Items> mountains,,peaks,,Worldspine,,worldspine::These tremendous mountains are the divisor between the lands of Almeria and the Northlands.;;forest,,trees,,evergreen forest::These trees cluster upon the mountain bases and form a light layer of forestation upon them.  They are predominantly pine and spruce.
  <Terrain> mountains forest
</RoomType>

<RoomType WorldspineSlope>
  <ShortDesc> the slopes of the Worldspine
  <LongDesc> These are the rough slopes of the Worldspine, the great mountains which form the boundary between Almeria and the Northlands.  The steep ascent is hard climbing, and the trees which decorate the lower reaches of these mountains are gnarled, stunted, and few here.
  <AdjacentDesc> %w are the slopes of the Worldspine.
  <Items> rough slopes,,slopes,,Worldspine,,worldspine,,mountains::These massive mountains are a difficult and dangerous climb.;;trees::The occasional dwarf pine or other gnarled tree ekes out a paltry existence on these high slopes.
  <Terrain> mountains
  <Altitude> 1
  <Access> climb
</RoomType>

<RoomType WorldspinePeak>
  <ShortDesc> a mountain peak in the Worldspine
  <LongDesc> Rising high above the lands of Almeria, this mountain peak of the Worldspine affords a glorious view, exhilarating despite the chill, thin air.
  <AdjacentDesc> One of the peaks of the Worldspine is %t.
  <Items> Almeria,,lands,,view,,almeria::The hills, plains, and forests of Almeria are spread out before you like a banquet table from this magnificent vantage.;;peak,,mountain peak::This peak stands atop one of the massive mountains of the Worldspine.;;Worldspine,,worldspine,,mountains::The great mountains of the Worldspine, which separate Almeria from the Northlands, are all around.
  <Terrain> mountains
  <Altitude> 1
  <Access> climb
</RoomType>

<RoomType WorldspineInterior>
  <ShortDesc> the interior of the Worldspine
  <Terrain> underground
  <Light> 0
  <Access> tunnel
</RoomType>

// Skyfire Jungle rooms

<RoomType SkyfireJungleOutskirtsLower>
  <ShortDesc> the outskirts of the Skyfire Jungle
  <LongDesc> The lush growth here marks the outskirts of the Skyfire Jungle, so named for the weird lights which sometimes appear above it at night.  The jungle's canopy, reaching high upward, is already dense enough to block out all light.
  <AdjacentDesc> %t are the outskirts of the Skyfire Jungle.
  <Items> massive trees,,trees,,thick vines,,vines,,great ferns,,ferns,,lush growth,,growth,,jungle,,Skyfire Jungle,,Jungle::The massive trees, thick vines, great ferns, and other multifarous growth here form the outskirts of the Skyfire Jungle.  Despite the density of the growth here, it is yet thinner than that of the true jungle.;;jungle's canopy,,canopy::The dense, light-blocking canopy of the jungle stretches high above.
  <Terrain> jungle
  <Light> 0
</RoomType>

<RoomType SkyfireJungleOutskirtsUpper>
  <ShortDesc> the canopy of the Skyfire Jungle's outskirts
  <LongDesc> This is the high, dense canopy of the Skyfire Jungle, intergrown with such a wealth of branches and vines as to make it nearly a single growth.  Despite the vegetation, some light manages to penetrate into these upper reaches of the jungle's outskirts.
  <AdjacentDesc> The canopy of the Skyfire Jungle's outskirts is %1w.
  <Items> dense canopy,,canopy,,branches,,vines,,growth,,vegetation::The vegetation of the Skyfire Jungle grows together into a dense canopy above the ground.;;jungle,,Jungle,,Skyfire Jungle::The Skyfire Jungle, named for strange lights that are said to appear above it betimes, is a tropical forest of great diversity.
  <Terrain> jungle
  <Access> climb
</RoomType>

<RoomType SkyfireJungleLower>
  <ShortDesc> the Skyfire Jungle
  <LongDesc> The lush growth here marks the outskirts of the Skyfire Jungle, so named for the weird lights which sometimes appear above it at night.  The jungle's canopy, reaching high upward, is already dense enough to block out all light.
  <AdjacentDesc> %t are the outskirts of the Skyfire Jungle.
  <Items> massive trees,,trees,,thick vines,,vines,,great ferns,,ferns,,lush growth,,growth,,jungle,,Skyfire Jungle,,Jungle::The massive trees, thick vines, great ferns, and other multifarous growth here form the outskirts of the Skyfire Jungle.  Despite the density of the growth here, it is yet thinner than that of the true jungle.;;jungle's canopy,,canopy::The dense, light-blocking canopy of the jungle stretches high above.
  <Terrain> jungle
  <Light> 0
</RoomType>

<RoomType SkyfireJungleUpper>
  <ShortDesc> the canopy of the Skyfire Jungle
  <LongDesc> This is the high, dense canopy of the Skyfire Jungle, intergrown with such a wealth of branches and vines as to make it nearly a single growth.  Even in these high reaches, the vegetation shuts out any light from above.
  <AdjacentDesc> %1t is the canopy of the Skyfire Jungle.
  <Items> dense canopy,,canopy,,branches,,vines,,growth,,vegetation::The vegetation of the Skyfire Jungle grows together into a dense canopy above the ground.;;jungle,,Jungle,,Skyfire Jungle::The Skyfire Jungle, named for strange lights that are said to appear above it betimes, is a tropical forest of great diversity.
  <Light> 0
  <Terrain> jungle
  <Access> climb
</RoomType>

// Vesuvon rooms

<RoomType VesuvonRim>
  <ShortDesc> the rim of Vesuvon
  <LongDesc> This is the rim of Vesuvon, an ancient volcano which has not erupted since the days of the Altrian Empire.  Despite its inactivity, hints of sulfuric gases waft from within it, along with a suggestion of rising heat.
  <AdjacentDesc> The rim of Vesuvon is %t.
  <Items> rim,,Vesuvon,,vesuvon,,volcano::The rim of the volcano is craggy and rough, but passable.;;sulfuric gases,,gases,,smell::There is a bare hint of a brimstone odor rising from within the volcano.
  <Terrain> mountains
  <Access> climb
  <Altitude> 1
</RoomType>

<RoomType VesuvonSlope>
  <ShortDesc> the slopes of Vesuvon
  <LongDesc> These are the slopes of the volcano Vesuvon, held to have been inactive for centuries.  The grade is relatively gentle, making the climb across the littered slope not too difficult, if slow.
  <AdjacentDesc> %w are the slopes of Vesuvon.
  <Items> slopes,,volcano,,Vesuvon,,vesuvon,,grade,,slope::The side of the dormant volcano is rough, and little grows here.
  <Terrain> mountains
  <Access> climb
  <Altitude> 1
</RoomType>

<RoomType VesuvonShaft>
  <ShortDesc> the shaft of Vesuvon
  <LongDesc> This is the shaft of the volcano Vesuvon, a rough vertical tunnel with numerous outcroppings which, while they make climbing a reasonable prospect, also block out the light from above.  Something of a sulfurous smell permeates the air, and the shaft seems somewhat unusually warm.
  <AdjacentDesc> %t is the shaft of Vesuvon.
  <Items> volcano,,Vesuvon,,vesuvon::Despite the volcano's long dormancy, the brimstone smell and heat here are unnerving.;;tunnel,,vertical tunnel,,shaft::The shaft winds somewhat, but is largely a straight course along the center of the volcano.;;outcroppings::These protrusions from the wall of the shaft take all manner of forms, and are numerous enough to swath the interior of the shaft in darkness.;;sulfurous smell,,smell::A faint but disturbing brimstone odor.
  <Terrain> tunnel
  <Light> 0
  <Outdoors> 0
  <Access> climb
</RoomType>

<RoomType VesuvonBase>
  <ShortDesc> the base of Vesuvon
  <LongDesc> The base of the inactive volcano Vesuvon is covered with jungle overgrowth, though the vegetation does not encroach upon the slopes of the mountain.
  <AdjacentDesc> %w is the base of Vesuvon.
  <Items> Vesuvon,,vesuvon,,volcano,,inactive volcano,,mountain,,slopes::The old volcano Vesuvon is generally said not to have erupted since the days of the Altrian Empire.;;jungle overgrowth,,jungle,,overgrowth,,vegetation::The lush growth of the Skyfire Jungle climbs over Vesuvon's base here, but does not reach up onto the volcano's slopes.
  <Terrain> mountains jungle
</RoomType>

// Atalantic Ocean rooms

<RoomType AtalanticShore>
  <ShortDesc> the shore of the Atalantic Ocean
  <LongDesc> This is the shore of the Atalantic Ocean, a broad beach of yellow-white sand.  The ocean waves roll up gently against the shore.
  <AdjacentDesc> The shore of the Atalantic Ocean is %t.
  <Items> sand,,yellow-white sand,,beach::The beach sand is mostly a fine grain with occasional rocks scattered here and there.;;ocean waves,,waves::The waves of the Atalantic Ocean swell high at points, but are generally not terribly violent.
  <Terrain> beach
</RoomType>

<RoomType AtalanticSurface>
  <ShortDesc> the surface of the Atalantic Ocean
  <LongDesc> Waves roll across the gray-green surface of the Atalantic Ocean, high but relatively calm and steady.  Brine spray scatters through the air as the waves climb to peaks.
  <AdjacentDesc> %w is the surface of the Atalantic Ocean.
  <Items> waves::The waves are not generally violent, but nonetheless rise high at times.;;brine spray,,spray::The brine spray carries with it the distinctive scent of the ocean.
  <Terrain> ocean surface
  <Access> swim
</RoomType>

<RoomType AtalanticShallow>
  <ShortDesc> the Atalantic Ocean
  <LongDesc> These are the waters of the Atalantic Ocean, beneath the surface but not yet so deep that the waters are entirely dark.
  <Items> water,,waters::The water is murky, but not entirely dark.
  <Access> dive
  <Terrain> ocean
  <Outdoors> 0
  <Altitude> -1
</RoomType>

<RoomType AtalanticBottomShallow>
  <ShortDesc> the bottom of the Atalantic Ocean
  <LongDesc> Below, a shelf of rock marks the bottom of the Atalantic Ocean, the waters of which are all around.  Here, the ocean floor is yet high enough that light from the surface penetrates.
  <AdjacentDesc> The bottom of the Atalantic Ocean is %t.
  <Items> shelf of rock,,shelf,,rock::The rock shelf is rough and overgrown with coral and kelp.;;water,,waters,,light::Though the water is murky, some dim light still illuminates the area.
  <Access> dive
  <Terrain> ocean bottom
  <Outdoors> 0
  <Altitude> -1
</RoomType>

<RoomType AtalanticDeep>
  <ShortDesc> the depths of the Atalantic Ocean
  <LongDesc> These are the depths of the Atalantic Ocean, where no light from the surface penetrates to illuminate the cold waters.
  <Items> water,,waters::The water is cold and dark at this depth.
  <Access> deepdive
  <Terrain> ocean
  <Light> 0
  <Outdoors> 0
  <Altitude> -2
</RoomType>

<RoomType AtalanticBottomDeep>
  <ShortDesc> the bottom of the Atalantic Ocean
  <LongDesc> The bleak rock shelf below demarcates the bottom of the Atalantic Ocean, here at a depth such that all light from the surface is long since faded, leaving the cold waters in darkness.
  <AdjacentDesc> The bottom of the Atalantic Ocean is %t.
  <Items> bleak rock shelf,,shelf,,rock::The rock below is mostly bare, with only occasional strange, stunted growing things among the silt gathered on it.;;things,,growing things::They are generally small, pale tubular growths.
  <Access> deepdive
  <Terrain> ocean bottom
  <Light> 0
  <Outdoors> 0
  <Altitude> -2
</RoomType>

// Whispering Forest rooms

<RoomType WhisperingForestOutskirts>
  <ShortDesc> the outskirts of the Whispering Forest
  <LongDesc> These are the outskirts of the Whispering Forest, a light and picturesque wood.
  <AdjacentDesc> %t are the outskirts of the Whispering Forest.
  <Terrain> forest
  <Outdoors> 3
</RoomType>

<RoomType WhisperingForest>
  <ShortDesc> the Whispering Forest
</RoomType>

// Blackwood rooms

<RoomType BlackwoodOuter>
  <ShortDesc> the outskirts of the Blackwood
  <LongDesc> These are the outskirts of the Blackwood, where the cover of trees is not yet so thick as to obscure all light.
  <Items> Blackwood,,blackwood,,trees,,forest::The Blackwood is a deciduous forest, made up largely of oak, ash, maple, and sycamore trees.  Here, on its outskirts, the trees do not grow so high nor so densely as elsewhere, where they block out nearly all light from above.
  <Terrain> forest
  <Outdoors> 3
  <AdjacentDesc> %w are the outskirts of the Blackwood.
  <Inhabitants> fox wolf
</RoomType>

<RoomType BlackwoodLower>
  <ShortDesc> the Blackwood
  <LongDesc> This is the Blackwood, a dense forest whose overhead foliage obscures nearly all light, leaving the ground beneath swathed in murk.  The tall trees reach upward toward the sky all around.
  <Items> Blackwood,,blackwood,,trees,,forest::The Blackwood is a deciduous forest made up largely of oak, ash, maple, and sycamore trees, all grown so densely together that light is all but nonexistent on the ground.;;ground::The murk-swathed ground is covered in fallen branches and leaves.
  <Terrain> forest
  <Outdoors> 3
  <AdjacentDesc> The Blackwood lies %t.
  <Inhabitants> fox wolf boar
  <Light> 0
</RoomType>

<RoomType BlackwoodUpper>
  <ShortDesc> the upper reaches of the Blackwood
  <LongDesc> These are the upper reaches of the Blackwood, the tops of the great trees whose foliage obscures the light from the ground below.  The densely intergrown branches and vines make movement between the treetops possible.
  <Items> Blackwood,,blackwood,,trees,,forest::The vine-swathed tops of the oaks, ashes, maples, and sycamores of the Blackwood reach high into the sky here.  Unlike the ground below, there is yet light in these upper reaches.;;vines::Various vines of all descriptions grow over and between the trees of the Blackwood.
  <Terrain> forest
  <Outdoors> 3
  <AdjacentDesc> The upper reaches of the Blackwood are %1t.
  <Inhabitants> squirrel tree_snake
  <Access> climb
  <Altitude> 1
</RoomType>

// Great Rift rooms

<RoomType RiftEdge>
  <ShortDesc> the edge of the Great Rift
  <LongDesc> This is the edge of the Great Rift, a tremendous gash in the earth which nearly bisects the continent of Almeria.  Massive rock prominences, like the torn skin around a wound, wall off the shifting sands of the Dune Sea.
  <AdjacentDesc> The edge of the Great Rift is %w.
  <Items> the Great Rift,,Rift,,rift,,great rift::The Great Rift is a tremendous gash in the earth, broad and deep with sheer rock walls on each side.;;massive rock prominences,,prominences,,rock prominences::These jagged protrusions rear up along the sides of the rift, forming a rough wall against the Dune Sea sands.
  <Terrain> ground
</RoomType>

<RoomType RiftWall>
  <ShortDesc> the wall of the Great Rift
  <LongDesc> This is the sheer cliff wall of the Great Rift.  There are enough ragged outcroppings and cracks in the rock to offer handholds, even if climbing still looks to be a dangerous prospect.  The shifting downdrafts along the wall merely compound the problem.
  <Items> the Great Rift,,Rift,,rift,,great rift::The Great Rift is a tremendous gash in the earth, broad and deep with sheer rock walls on each side.;;ragged outcroppings,,outcroppings,,cracks,,handholds::They do not inspire the greatest of confidence in the scalability of the Rift wall.;;wall,,cliff wall,,sheer cliff wall::The Rift wall looks for all the world like the side of an open wound in the earth.
  <Terrain> air downdraft
  <Access> climb
  <Altitude> -1
</RoomType>

<RoomType RiftBottom>
  <ShortDesc> the bottom of the Great Rift
  <LongDesc> This is the bottom of the Great Rift.  Heaps and mounds of fallen rock cover the terrain, making traversal of the bleak landscape a slow and hazardous process.
  <AdjacentDesc> The bottom of the Great Rift is %t.
  <Items> the Great Rift,,Rift,,rift,,great rift::The Great Rift is a tremendous gash in the earth, broad and deep with sheer rock walls on each side.;;fallen rock,,rock,,heaps,,mounds::Tumbled rock of all shapes and sizes, partially overgrown, litters the floor of the Rift.
  <Terrain> ground
  <Altitude> -2
</RoomType>

<RoomType Rift>
  <ShortDesc> the Great Rift
  <LongDesc> This is the center of the Great Rift, a dizzying descent into the depths of this monstrous scar in the earth.  Erratic updrafts blow in the gap.
  <AdjacentDesc> The Great Rift is %1t.
  <Items> the Great Rift,,Rift,,rift,,great rift::The Great Rift is a tremendous gash in the earth, broad and deep with sheer rock walls on each side.
  <Terrain> air updraft
  <Access> fly
  <Altitude> -1
</RoomType>

------------------------------- end rooms.conf -------------------------------

----------------------------- begin overlays.conf ----------------------------

// Map overlay configuration file by Chaos, Fri Jan 12 06:26:00 CST 1996

<OverlayType AltrianRoad>	// Overlay name
  <Realms> Altrian_Road	// Realms to set
  <Light> 0		// Light level to set
  <Inhabited> 15	// Percent chance of having a character present
  <Inhabitants> wanderer pilgrim	// Possible characters
  <Outdoors> 3		// Outdoors level to set
  <Access> walk		// How one can get into it
  <Terrain> road	// Terrains to add
  <Desc> An old Altrian road %r.	// To add to the room long desc
  <Items> road,,Altrian road,,altrian road::Though its stones are cracked and weathered, this road, built in the brighter, bygone days of the Altrian Empire, continues to serve its purpose.		// Item descriptions
  <Intersections> TalismanRiver::road^^bridge
</OverlayType>

------------------------------- end overlays.conf ----------------------------

----------------------------- begin map.c ------------------------------------

// 3D Map Generation Daemon
//
// by Chaos, Mon Dec  4 14:51:59 CST 1995
//
// second attempt at getting this stupid thing
// rolling by Chaos, Mon Aug 19 22:34:08 CDT 1996
//
// some fixes and expansions by Chaos, Wed Jan  1 22:01:22 EST 1997

// Inheritance

inherit "/std/daemon";

// Includes

#include <daemons.h>
#include <directions.h>
#include <map.h>

// Macros

#define Room_Short		0
#define Room_Long		1
#define Room_Adjacent		2
#define Room_Terrain		3
#define Room_Realms		4
#define Room_Light		5
#define Room_Outdoors		6
#define Room_Altitude		7
#define Room_Inhabited		8
#define Room_Inhabit		9
#define Room_Access		10
#define Room_Items		11

#define Room_Fields		12

#define Overlay_Desc		0
#define Overlay_Terrain		1
#define Overlay_Realms		2
#define Overlay_Light		3
#define Overlay_Outdoors	4
#define Overlay_Inhabited	5
#define Overlay_Inhabit		6
#define Overlay_Access		7
#define Overlay_Items		8
#define Overlay_Intersections	9

#define Overlay_Fields		10

#define Top_Code(x, y, z)	(x + "/" + y + "/" + z)

// Variables

private string *room_index, *overlay_index;
private mapping map, top, rooms, overlays;
private int x, y, z, tx, ty, tz, pop;

internal string map_conf, map_save, room_conf, overlay_conf, base_room;
internal mapping outline, acc, surr, queue, lines, distances, circles;
internal string room_prefix, character_prefix;
internal int ppl;

// Functions

void set_room_prefix(string new) {
	room_prefix = new;
}

string query_room_prefix() {
	return room_prefix;
}

void set_character_prefix(string new) {
	character_prefix = new;
}

string query_character_prefix() {
	return character_prefix;
}

void set_room_conf(string file) {
	room_conf = file;
}

string query_room_conf() {
	return room_conf;
}

void set_map_conf(string file) {
	map_conf = file;
}

string query_map_conf() {
	return map_conf;
}

void set_overlay_conf(string file) {
	overlay_conf = file;
}

string query_overlay_conf() {
	return overlay_conf;
}

void set_map_save(string file) {
	map_save = file;
}

string query_map_save() {
	return map_save;
}

void set_base_room(string file) {
	base_room = file;
}

string query_base_room() {
	return base_room;
}

private void set_point(int mx, int my, int mz, int val, status ov) {
	if(ov) {
	  string code;
	  code = Top_Code(mx, my, mz);
	  top[code] = set_bit(top[code] || "", val);
	} else map[mx, my][mz] = val;
}

private string *query_overlays_present(int mx, int my, int mz) {
string list, *out;
int i, j;
	out = ({});
	list = top[Top_Code(mx, my, mz)];
	if(!list)
	  return out;
	for(i = 0, j = sizeof(overlay_index); i < j; i++)
	  if(test_bit(list, i))
	    out += ({ overlay_index[i] });
	return out;
}

private varargs status has_overlay(int mx, int my, int mz, int val) {
	return test_bit(top[Top_Code(mx, my, mz)] || "", val);
}

private int round(float p) {
int i;
	i = to_int(p);
	p = p - to_float(i);
	if(p >= 0.5)
	  i++;
	return i;
}

private float query_coordinate_distance(int x1, int y1, int x2, int y2) {
string code;
	x1 -= x2;
	y1 -= y2;
	code = x1 + " " + y1;
	if(member(distances, code))
	  return distances[code];
	else return distances[code] = sqrt(to_float((x1 * x1) + (y1 * y1)));
}

private int *query_circle_profile(int radius) {
int i, j, *pro;
float rad;
	if(pro = circles[radius])
	  return pro;
	pro = ({});
	rad = to_float(radius);
	for(i = -radius; i <= radius; i++)
	  pro += ({ 0, i, i, 0 });
	for(i = 1; i <= radius; i++)
	  for(j = 1; j <= radius; j++)
	    if(sqrt(to_float((i * i) + (j * j))) <= rad)
	      pro += ({ i, j, -i, j, i, -j, -i, -j });
	return circles[radius] = pro;
}

private int *query_line_profile(int ix1, int iy1, int ix2, int iy2) {
int i, x, y, p, dx, dy, *pro;
float x1, y1, x2, y2, m, b;
string code;
	dx = ix2 - ix1;
	dy = iy2 - iy1;
	code = dx + " " + dy;
	if(pro = lines[code])
	  return pro;
	pro = ({});
	x1 = to_float(ix1);
	y1 = to_float(iy1);
	x2 = to_float(ix2);
	y2 = to_float(iy2);
	m = (float) (y2 - y1) / (x2 - x1);
	b = y1 - m * x1;
	for(p = -1; x1 <= x2; x1 += 1.0) {
	  y = round(m * x1 + b);
	  x = to_int(x1);
	  pro += ({ x - ix1, y - iy1 });
	  if(p != -1 && y - p > 1)
	    for(i = p + 1; i != y; i++)
	      pro += ({ x - ix1, i - iy1 });
	  p = y;
	}
	return lines[code] = pro;
}

private void draw_line(int x1, int y1, int x2, int y2, int t, int l,
	status ov) {
int i, j, *pro;
	if(y1 > y2) {
	  i = y1;
	  y1 = y2;
	  y2 = i;
	}
	if(x1 == x2) {
	  while(y1 <= y2) {
	    set_point(x1, y1++, l, t, ov);
	  }
	  return;
	}
	if(x1 > x2) {
	  i = x1;
	  x1 = x2;
	  x2 = i;
	}
	if(y1 == y2) {
	  while(x1 <= x2) {
	    set_point(x1++, y1, l, t, ov);
	  }
	  return;
	}
	pro = query_line_profile(x1, y1, x2, y2);
	for(i = 0, j = sizeof(pro); i < j; i += 2)
	  set_point(x1 + pro[i], y1 + pro[i + 1], l, t, ov);
}

private status file_updated(string conf, string save) {
int ct, st;
	if(file_size(save + ".o") < 1)
	  return 1;
	ct = get_dir(conf, 4)[0];
	st = get_dir(save + ".o", 4)[0];
	if(ct > st)
	  return 1;
}

private void write_map(string file) {
	save_object(file);
}

private void read_map(string file) {
	restore_object(file);
}

private void parse_rooms() {
string file, field, type, line, ind, val, *exp, *lines;
int i, j, k, l;
mapping item;
status conf;
mixed in;
	if(!query_room_conf())
	  raise_error("No room config file in " + file_name() + "\n");
	if(!query_map_save())
	  raise_error("No map save file in " + file_name() + "\n");
	if(!file_updated(query_room_conf(), query_map_save()))
	  return;
	file = read_file(query_room_conf());
	lines = explode(file, "\n");
	rooms = allocate_mapping(30, Room_Fields);
	for(i = 0, j = sizeof(lines); i < j; i++) {
	  line = lines[i];
	  if(member(line, '/') != -1)
	    sscanf(line, "%s//%s", line);
	  while(line[0] == ' ' || line[0] == '\t')
	    line = line[1..];
	  while(line[<1] == ' ' || line[<1] == '\t')
	    line = line[0..<2];
	  if(line == "")
	    continue;
	  if(line == "</RoomType>") {
	    if(!conf)
	      raise_error(format("RoomType close outside of RoomType in line " + (i + 1) + " of " + query_room_conf()));
	    conf = 0;
	    continue;
	  }
	  if(sscanf(line, "<RoomType %s>", type)) {
	    if(conf)
	      raise_error(format("RoomType open inside RoomType in line " + (i + 1) + " of " + query_room_conf()));
	    if(member(type, ' ') != -1)
	      raise_error(format("RoomType name contains space in line " + (i + 1) + " of " + query_room_conf()));
	    conf = 1;
	    if(type != "BASE" && member(rooms, "BASE"))
	      for(k = 0; k < Room_Fields; k++)
		rooms[type, k] = rooms["BASE", k];
	    continue;
	  }
	  if(!conf)
	    raise_error(format("RoomType open required before other directives may be used in line " + (i + 1) + " of " + query_room_conf()));
	  if(sscanf(line, "<%s> %s", field, in))
	    switch(field) {
	      case "ShortDesc"	:
		rooms[type, Room_Short] = in;
		break;
	      case "LongDesc"	:
		rooms[type, Room_Long] = in;
		break;
	      case "AdjacentDesc"	:
		rooms[type, Room_Adjacent] = in;
		break;
	      case "Terrain"	:
		rooms[type, Room_Terrain] = explode(in, " ");
		break;
	      case "Realms"	:
		rooms[type, Room_Realms] = explode(in, " ");
		break;
	      case "Light"	:
		rooms[type, Room_Light] = to_int(in);
		break;
	      case "Outdoors"	:
		rooms[type, Room_Outdoors] = to_int(in);
		break;
	      case "Altitude"	:
		rooms[type, Room_Altitude] = to_int(in);
		break;
	      case "Inhabited"	:
		rooms[type, Room_Inhabited] = to_int(in);
		break;
	      case "Inhabitants"	:
		rooms[type, Room_Inhabit] = explode(in, " ");
		break;
	      case "Access"	:
		rooms[type, Room_Access] = in;
		break;
	      case "Items"	:
		exp = explode(in, ";;");
		for(item = ([]), k = 0, l = sizeof(exp); k < l; k++) {
		  sscanf(exp[k], "%s::%s", ind, val);
		  item[explode(ind, ",,")] = val;
		}
		rooms[type, Room_Items] = item;
		break;
	      default	:
		raise_error(format("Unknown directive '" + field + "' in line " + (i + 1) + " of " + query_room_conf()));
	    } else raise_error(format("Syntax error in line " + (i + 1) + " of " + query_room_conf()));
	}
	room_index = ({ 0 }) + sort_array(m_indices(m_delete(rooms, "BASE")), #'>);
	if(sizeof(room_index) > 256)
	  raise_error(format("More than 255 RoomTypes defined in " + query_room_conf()));
}

private void parse_overlays() {
string file, field, type, line, ind, val, srch, repl, *exp, *each, *lines;
int i, j, k, l, m, n;
mapping item;
status conf;
mixed in;
	if(!query_overlay_conf())
	  raise_error("No overlay config file in " + file_name() + "\n");
	if(!query_map_save())
	  raise_error("No map save file in " + file_name() + "\n");
	if(!file_updated(query_overlay_conf(), query_map_save()))
	  return;
	top = ([]);
	file = read_file(query_overlay_conf());
	lines = explode(file, "\n");
	overlays = allocate_mapping(10, Overlay_Fields);
	for(i = 0, j = sizeof(lines); i < j; i++) {
	  line = lines[i];
	  if(member(line, '/') != -1)
	    sscanf(line, "%s//%s", line);
	  while(line[0] == ' ' || line[0] == '\t')
	    line = line[1..];
	  while(line[<1] == ' ' || line[<1] == '\t')
	    line = line[0..<2];
	  if(line == "")
	    continue;
	  if(line == "</OverlayType>") {
	    if(!conf)
	      raise_error(format("OverlayType close outside of OverlayType in line " + (i + 1) + " of " + query_overlay_conf()));
	    conf = 0;
	    continue;
	  }
	  if(sscanf(line, "<OverlayType %s>", type)) {
	    if(conf)
	      raise_error(format("OverlayType open inside OverlayType in line " + (i + 1) + " of " + query_overlay_conf()));
	    if(member(type, ' ') != -1)
	      raise_error(format("OverlayType name contains space in line " + (i + 1) + " of " + query_overlay_conf()));
	    conf = 1;
	    if(type != "BASE" && member(overlays, "BASE"))
	      for(k = 0; k < Overlay_Fields; k++)
		overlays[type, k] = overlays["BASE", k];
	    continue;
	  }
	  if(!conf)
	    raise_error(format("OverlayType open required before other directives may be used in line " + (i + 1) + " of " + query_overlay_conf()));
	  if(sscanf(line, "<%s> %s", field, in))
	    switch(field) {
	      case "Desc"	:
		overlays[type, Overlay_Desc] = in;
		break;
	      case "Terrain"	:
		overlays[type, Overlay_Terrain] = explode(in, " ");
		break;
	      case "Realms"	:
		overlays[type, Overlay_Realms] = explode(in, " ");
		break;
	      case "Light"	:
		overlays[type, Overlay_Light] = to_int(in);
		break;
	      case "Outdoors"	:
		overlays[type, Overlay_Outdoors] = to_int(in) + 1;
		break;
	      case "Inhabited"	:
		overlays[type, Overlay_Inhabited] = to_int(in);
		break;
	      case "Inhabitants"	:
		overlays[type, Overlay_Inhabit] = explode(in, " ");
		break;
	      case "Access"	:
		overlays[type, Overlay_Access] = in;
		break;
	      case "Items"	:
		exp = explode(in, ";;");
		for(item = ([]), k = 0, l = sizeof(exp); k < l; k++) {
		  sscanf(exp[k], "%s::%s", ind, val);
		  for(m = 0, n = sizeof(each = explode(ind, ",,")); m < n; m++)
		    item[each[m]] = val;
		}
		overlays[type, Overlay_Items] = item;
		break;
	      case "Intersections"	:
		exp = explode(in, ";;");
		for(item = ([]), k = 0, l = sizeof(exp); k < l; k++) {
		  sscanf(exp[k], "%s::%s^^%s", ind, srch, repl);
		  for(m = 0, n = sizeof(each = explode(ind, ",,")); m < n; m++)
		    item += ([ each[m] : srch; repl ]);
		}
		overlays[type, Overlay_Intersections] = item;
		break;
	      default	:
		raise_error(format("Unknown directive '" + field + "' in line " + (i + 1) + " of " + query_overlay_conf()));
	    } else raise_error(format("Syntax error in line " + (i + 1) + " of " + query_overlay_conf()));
	}
	overlay_index = ({ 0 }) + sort_array(m_indices(m_delete(overlays, "BASE")), #'>);
	if(sizeof(overlay_index) > 256)
	  raise_error(format("More than 255 OverlayTypes defined in " + query_overlay_conf()));
}

private void parse_map() {
int i, j, k, l, n, m, num, lev, out, mx, my, mz, nx, ny, nz, sh, *pro;
string file, type, line, code, field, *lines, *list;
status reg, ov, def;
mixed in;
	if(!query_map_conf())
	  raise_error("No map config file in " + file_name() + "\n");
	if(!query_map_save())
	  raise_error("No map save file in " + file_name() + "\n");
	if(!file_updated(query_map_conf(), query_map_save()))
	  return;
	file = read_file(query_map_conf());
	lines = explode(file, "\n");
	tx = ty = tz = pop = 0;
	for(n = 0, m = sizeof(lines); n < m; n++) {
	  line = lines[n];
	  if(member(line, '/') != -1)
	    sscanf(line, "%s//%s", line);
	  while(line[0] == ' ' || line[0] == '\t')
	    line = line[1..];
	  while(line[<1] == ' ' || line[<1] == '\t')
	    line = line[0..<2];
	  if(line == "")
	    continue;
	  if(!reg) {
	    if(sscanf(line, "<X> %d", x)) {
	      if(tx)
	        raise_error(format("X dimension redefined in line " + (n + 1) + " of " + query_map_conf()));
	      if(x < 0)
	        raise_error(format("Invalid X dimension value in line " + (n + 1) + " of " + query_map_conf()));
	      tx = x * 2 + 1;
	      continue;
	    }
	    if(sscanf(line, "<Y> %d", y)) {
	      if(ty)
	        raise_error(format("Y dimension redefined in line " + (n + 1) + " of " + query_map_conf()));
	      if(y < 0)
	        raise_error(format("Invalid Y dimension value in line " + (n + 1) + " of " + query_map_conf()));
	      ty = y * 2 + 1;
	      continue;
	    }
	    if(sscanf(line, "<Z> %d", z)) {
	      if(tz)
	        raise_error(format("Z dimension redefined in line " + (n + 1) + " of " + query_map_conf()));
	      if(z < 0)
	        raise_error(format("Invalid Z dimension value in line " + (n + 1) + " of " + query_map_conf()));
	      tz = z * 2 + 1;
	      continue;
	    }
	    if(sscanf(line, "<Population> %d", in)) {
	      if(pop)
	        raise_error(format("Population redefined in line " + (n + 1) + " of " + query_map_conf()));
	      if(in < 1)
	        raise_error(format("Invalid Population value in line " + (n + 1) + " of " + query_map_conf()));
	      pop = in;
	      continue;
	    }
	    if(sscanf(line, "<FillerType> %s", in)) {
	      if(!tx)
	        raise_error(format("FillerType without X dimension defined in line " + (n + 1) + " of " + query_map_conf()));
	      if(!ty)
	        raise_error(format("FillerType without Y dimension defined in line " + (n + 1) + " of " + query_map_conf()));
	      if(!tz)
	        raise_error(format("FillerType without Z dimension defined in line " + (n + 1) + " of " + query_map_conf()));
	      if(!pop)
	        raise_error(format("FillerType without Population defined in line " + (n + 1) + " of " + query_map_conf()));
	      reg = 1;
	      map = allocate_mapping(tx, ty);
	      if(member(in, ' ') != -1) {
		list = explode(in, " ");
		j = sizeof(list);
		if(j != tz)
		  raise_error(format("Number of RoomTypes for FillerType does not match number of map planes in line " + (n + 1) + " of " + query_map_conf()));
		pro = allocate(j);
		for(i = 0; i < j; i++) {
		  pro[i] = member(room_index, list[i]);
		  if(pro[i] == -1)
		    raise_error(format("Bad RoomType '" + list[i] + "' for FillerType in line " + (n + 1) + " of " + query_map_conf()));
		}
		code = to_string(pro);
	      } else {
		in = member(room_index, in);
		if(in == -1)
		  raise_error(format("Bad RoomType for FillerType in line " + (n + 1) + " of " + query_map_conf()));
	        code = to_string(value_allocate(tz, in));
	      }
	      for(i = 0; i < tx; i++)
	        for(j = 0; j < ty; j++)
	          map[i, j] = code;
	      continue;
	    }
	    raise_error(format("Only X, Y, Z, and Population directives allowed before FillerType in line " + (n + 1) + " of " + query_map_conf()));
	  } else {
	    if(line == "</Region>") {
	      if(!def)
	        raise_error(format("Region close while not in Region in line " + (n + 1) + " of " + query_map_conf()));
	      else if(ov)
	        raise_error(format("Region close while in Overlay in line " + (n + 1) + " of " + query_map_conf()));
	      def = 0;
	      continue;
	    }
	    if(line == "</Overlay>") {
	      if(!def)
	        raise_error(format("Overlay close while not in Overlay in line " + (n + 1) + " of " + query_map_conf()));
	      else if(!ov)
	        raise_error(format("Overlay close while in Region in line " + (n + 1) + " of " + query_map_conf()));
	      def = 0;
	      continue;
	    }
	    if(sscanf(line, "<Region %s>", type)) {
	      if(def)
	        if(ov)
	          raise_error(format("Region open while in Overlay in line " + (n + 1) + " of " + query_map_conf()));
	        else raise_error(format("Region open while in Region in line " + (n + 1) + " of " + query_map_conf()));
	      num = member(room_index, type);
	      if(num == -1)
	        raise_error(format("Bad RoomType for Region in line " + (n + 1) + " of " + query_map_conf()));
	      ov = 0;
	      def = 1;
	      continue;
	    }
	    if(sscanf(line, "<Overlay %s>", type)) {
	      if(def)
	        if(!ov)
	          raise_error(format("Overlay open while in Region in line " + (n + 1) + " of " + query_map_conf()));
	        else raise_error(format("Overlay open while in Overlay in line " + (n + 1) + " of " + query_map_conf()));
	      num = member(overlay_index, type);
	      if(num == -1)
	        raise_error(format("Bad OverlayType for Overlay in line " + (n + 1) + " of " + query_map_conf()));
	      ov = 1;
	      def = 1;
	      continue;
	    }
	    if(!def)
	      raise_error(format("Region or Overlay open required before other directives may be used in line " + (n + 1) + " of " + query_map_conf()));
	    if(sscanf(line, "<%s> %s", field, in) == 2)
	      switch(field) {
		case "Point"		:
		  if(sscanf(in, "%d, %d/%d", mz, mx, my) != 3)
		    raise_error(format("Bad parameters for Point in line " + (n + 1) + " of " + query_map_conf()));
		  set_point(mx + x, my + y, mz + z, num, ov);
		  break;
		case "Line"		:
		  if(sscanf(in, "%d, %d/%d, %d/%d", mz, mx, my, nx, ny) != 5)
		    raise_error(format("Bad parameters for Line in line " + (n + 1) + " of " + query_map_conf()));
		  draw_line(mx + x, my + y, nx + x, ny + y, num, mz + z, ov);
		  break;
		case "BroadLine"	:
		  if(sscanf(in, "%d, %d, %d/%d, %d/%d", mz, sh, mx, my, nx, ny) != 6)
		    raise_error(format("Bad parameters for BroadLine in line " + (n + 1) + " of " + query_map_conf()));
		  mx += x;
		  my += y;
		  mz += z;
		  nx += x;
		  ny += y;
		  if(sh < 0) {
		    my += sh;
		    ny += sh;
		    sh = -sh;
		  }
		  while(sh >= 0) {
		    draw_line(mx, my + sh, nx, ny + sh, num, mz, ov);
		    sh--;
		  }
		  break;
		case "Rectangle"	:
		  if(sscanf(in, "%d, %d/%d, %d/%d", mz, mx, my, nx, ny) != 5)
		    raise_error(format("Bad parameters for Rectangle in line " + (n + 1) + " of " + query_map_conf()));
		  mx += x;
		  my += y;
		  mz += z;
		  nx += x;
		  ny += y;
		  if(my > ny) {
		    i = my;
		    my = ny;
		    ny = i;
		  }
		  while(my <= ny) {
		    draw_line(mx, my, nx, my, num, mz, ov);
		    my++;
		  }
		  break;
		case "Circle"		:
		  if(sscanf(in, "%d, %d/%d, %d", mz, mx, my, out) != 4)
		    raise_error(format("Bad parameters for Circle in line " + (n + 1) + " of " + query_map_conf()));
		  if(out < 1)
		    raise_error(format("Bad radius for Circle in line " + (n + 1) + " of " + query_map_conf()));
		  mx += x;
		  my += y;
		  mz += z;
		  pro = query_circle_profile(out);
		  for(i = 0, j = sizeof(pro); i < j; i += 2)
		    set_point(pro[i] + mx, pro[i + 1] + my, mz, num, ov);
		  break;
		case "Plane"		:
		  if(ov)
		    raise_error(format("Plane directive while in Overlay in line " + (n + 1) + " of " + query_map_conf()));
		  if(!sscanf(in, "%d", mz))
		    raise_error(format("Bad parameters for Plane in line " + (n + 1) + " of " + query_map_conf()));
		  mz += z;
		  for(i = 0; i < tx; i++)
		    for(j = 0; j < ty; j++)
		      map[i, j][mz] = num;
		  break;
		case "SurroundRoom"	:
		  if(sscanf(in, "%d, %s", mz, in) != 2)
		    raise_error(format("Bad parameters for SurroundRoom in line " + (n + 1) + " of " + query_map_conf()));
		  lev = mz + z;
		  pro = ({});
		  in = member(room_index, in);
		  if(in == -1)
		    raise_error(format("Bad RoomType for SurroundRoom in line " + (n + 1) + " of " + query_map_conf()));
		  for(i = 0; i < tx; i++)
		    for(j = 0; j < ty; j++)
		      if(map[i, j][lev] == in) {
			if(i < tx - 1 && map[i + 1, j][lev] != in)
			  pro += ({ i + 1, j });
			if(i > 0 && map[i - 1, j][lev] != in)
			  pro += ({ i - 1, j });
			if(j < ty - 1 && map[i, j + 1][lev] != in)
			  pro += ({ i, j + 1 });
			if(j > 0 && map[i, j - 1][lev] != in)
			  pro += ({ i, j - 1 });
		      }
		  for(i = 0, j = sizeof(pro); i < j; i += 2)
		    set_point(pro[i], pro[i + 1], lev, num, ov);
		  break;
		case "SurroundOverlay"	:
		  if(sscanf(in, "%d, %s", mz, in) != 2)
		    raise_error(format("Bad parameters for SurroundOverlay in line " + (n + 1) + " of " + query_map_conf()));
		  lev = mz + z;
		  pro = ({});
		  in = member(overlay_index, in);
		  if(in == -1)
		    raise_error(format("Bad OverlayType for SurroundOverlay in line " + (n + 1) + " of " + query_map_conf()));
		  for(i = 0; i < tx; i++)
		    for(j = 0; i < ty; j++)
		      if(has_overlay(i, j, lev, in)) {
			if(i < tx - 1 && !has_overlay(i + l, j, lev, in))
			  pro += ({ i + 1, j });
			if(i > 0 && !has_overlay(i - 1, j, lev, in))
			  pro += ({ i - 1, j });
			if(j < ty - 1 && !has_overlay(i, j + 1, lev, in))
			  pro += ({ i, j + 1 });
			if(j > 0 && !has_overlay(i, j - 1, lev, in))
			  pro += ({ i, j - 1 });
		      }
		  for(i = 0, j = sizeof(pro); i < j; i += 2)
		    set_point(pro[i], pro[i + 1], lev, num, ov);
		  break;
		default			:
		  raise_error(format("Unknown directive '" + field + "' in line " + (n + 1) + " of " + query_map_conf()));
	      }
	    else raise_error(format("Syntax error in line " + (n + 1) + " of " + query_map_conf()));
	  }
	}
}

private string resolve_access(string a, string b) {
string c;
	if(!a)
	  return b;
	if(!b)
	  return a;
	if(a == b)
	  return a;
	if(a > b) {
	  c = a;
	  a = b;
	  b = c;
	}
	if(a == "climb")
	  return a;
	else if(a == "fly")
	  return a;
	else if(a == "swim" || a == "dive" || a == "deepdive")
	  if(b == "tunnel")
	    return a;
	  else return b;
	else return b;
}

string query_room_access(int mx, int my, int mz) {
string out, code, type, *over;
int ind, i, j;
	code = Top_Code(mx, my, mz);
	if(member(acc, code))
	  return acc[code];
	mx += x;
	my += y;
	mz += z;
	ind = map[mx, my][mz];
	type = room_index[ind];
	out = rooms[type, Room_Access];
	over = query_overlays_present(mx, my, mz);
	for(i = 0, j = sizeof(over); i < j; i++)
	  out = resolve_access(out, overlays[over[i], Overlay_Access]);
	return acc[code] = out;
}

private mapping query_room_exits(int mx, int my, int mz) {
int i, j, lx, ly, lz;
string *ind, type;
mapping list;
	list = allocate_mapping(5, 2);
	for(i = 0, j = sizeof(ind = m_indices(surr)); i < j; i++) {
	  lx = mx + surr[ind[i], 0];
	  ly = my + surr[ind[i], 1];
	  lz = mz + surr[ind[i], 2];
	  if(lx + x >= 0 && ly + y >= 0 && lz + z >= 0)
	    if(lx + x < tx && ly + y < ty && lz + z < tz)
	      switch(type = query_room_access(lx, ly, lz)) {
		case "walk"	:
		  list[ind[i], 0] = room_prefix + lx + "_" + ly + "_" + lz;
		  break;
		case "tunnel"	:
		  break;
		default		:
		  list[ind[i], 0] = room_prefix + lx + "_" + ly + "_" + lz;
		  list[ind[i], 1] = "access_" + type;
		  break;
	      }
	}
	return list;
}

private string *query_overlay_directions(int mx, int my, int mz, int type) {
int i, j, lx, ly, lz;
string *list, *ind;
	mx += x;
	my += y;
	mz += z;
	list = ({});
	for(i = 0, j = sizeof(ind = m_indices(surr)); i < j; i++) {
	  lx = mx + surr[ind[i], 0];
	  ly = my + surr[ind[i], 1];
	  lz = mz + surr[ind[i], 2];
	  if(lx >= 0 && ly >= 0 && lz >= 0)
	    if(lx < tx && ly < ty && lz < tz)
	      if(has_overlay(lx, ly, lz, type))
		list += ({ ind[i] });
	}
	return list;
}

private string direction_primus(string dir) {
	return Direction_Description[dir];
}

private string direction_secundus(string dir) {
	return dir + "ward";
}

private string *query_adjacent_descs(int mx, int my, int mz) {
string desc, *ind, *out, *list;
int i, j, lx, ly, lz;
mapping dir;
	mx += x;
	my += y;
	mz += z;
	dir = ([]);
	for(i = 0, j = sizeof(ind = m_indices(surr)); i < j; i++) {
	  lx = mx + surr[ind[i], 0];
	  ly = my + surr[ind[i], 1];
	  lz = mz + surr[ind[i], 2];
	  if(lx >= 0 && ly >= 0 && lz >= 0)
	    if(lx < tx && ly < ty && lz < tz)
	      if(desc = rooms[room_index[map[lx, ly][lz]], Room_Adjacent])
		if(member(dir, desc))
		  dir[desc] += ({ ind[i] });
		else dir[desc] = ({ ind[i] });
	}
	for(out = ({}), i = 0, j = sizeof(ind = m_indices(dir)); i < j; i++) {
	  desc = ind[i];
	  if(strstr(desc, "%s") != -1) {
	    list = dir[ind[i]] - ({ "up" });
	    if(!sizeof(list))
	      continue;
	    desc = replace(desc, "%s", list_array(map_array(list, #'direction_primus)));
	  }
	  if(strstr(desc, "%v") != -1) {
	    list = dir[ind[i]] - ({ "up" });
	    if(!sizeof(list))
	      continue;
	    desc = replace(desc, "%v", list_array(map_array(list, #'direction_secundus)));
	  }
	  if(strstr(desc, "%u") != -1) {
	    list = dir[ind[i]] - ({ "down" });
	    if(!sizeof(list))
	      continue;
	    desc = replace(desc, "%u", list_array(map_array(list, #'direction_primus)));
	  }
	  if(strstr(desc, "%x") != -1) {
	    list = dir[ind[i]] - ({ "down" });
	    if(!sizeof(list))
	      continue;
	    desc = replace(desc, "%x", list_array(map_array(list, #'direction_secundus)));
	  }
	  if(strstr(desc, "%t") != -1)
	    desc = replace(desc, "%t", list_array(map_array(dir[ind[i]], #'direction_primus)));
	  if(strstr(desc, "%w") != -1)
	    desc = replace(desc, "%w", list_array(map_array(dir[ind[i]], #'direction_secundus)));
	  out += ({ capitalize(desc) });
	}
	return out;
}

private string format_values(string key, mapping map) {
	return format(map[key]);
}

mixed *query_room_settings(int mx, int my, int mz) {
string *long, *terr, *over, *rlm, *chk, *list;
string code, type, new, desc, srch, repl;
int i, j, k, l, m, n, ind, lx, ly, lz;
mapping item, oitem, intr;
mixed *set;
status mod;
	code = Top_Code(mx, my, mz);
	if(member(outline, code))
	  return outline[code];
	lx = mx + x;
	ly = my + y;
	lz = mz + z;
	set = allocate(Map_Room_Fields);
	ind = map[lx, ly][lz];
	type = room_index[ind];
	set[Map_Room_Coordinates] = ({ mx, my, mz });
	set[Map_Room_Short] = rooms[type, Room_Short];
	set[Map_Room_Light] = rooms[type, Room_Light];
	set[Map_Room_Outdoors] = rooms[type, Room_Outdoors];
	set[Map_Room_Altitude] = rooms[type, Room_Altitude];
	set[Map_Room_Access] = query_room_access(mx, my, mz);
	long = ({ rooms[type, Room_Long] }) + query_adjacent_descs(mx, my, mz);
	terr = rooms[type, Room_Terrain] || ({});
	rlm = rooms[type, Room_Realms] || ({});
	item = rooms[type, Room_Items] || ([]);
	if(ppl < pop && random(100) < rooms[type, Room_Inhabited]) {
	  chk = rooms[type, Room_Inhabit];
	  set[Map_Room_Inhabit] = ([ character_prefix + random_element(chk) : 1 ]);
	  ppl++;
	}
	over = query_overlays_present(lx, ly, lz);
	for(i = 0, j = sizeof(over); i < j; i++) {
	  terr += overlays[over[i], Overlay_Terrain] || ({});
	  rlm += overlays[over[i], Overlay_Realms] || ({});
	  if(overlays[over[i], Overlay_Outdoors] > 0 && set[Map_Room_Outdoors] >= overlays[over[i], Overlay_Outdoors])
	    set[Map_Room_Outdoors] = overlays[over[i], Overlay_Outdoors] - 1;
	  set[Map_Room_Light] += overlays[over[i], Overlay_Light];
	  if(ppl < pop & random(100) < overlays[over[i], Overlay_Inhabited]) {
	    chk = overlays[over[i], Overlay_Inhabit];
	    if(!set[Map_Room_Inhabit])
	      set[Map_Room_Inhabit] = ([ character_prefix + random_element(chk) : 1 ]);
	    else set[Map_Room_Inhabit][character_prefix + random_element(chk)]++;
	    ppl++;
	  }
	  desc = overlays[over[i], Overlay_Desc];
	  oitem = overlays[over[i], Overlay_Items];
	  if(intr = overlays[over[i], Overlay_Intersections])
	    for(k = 0, l = sizeof(chk = m_indices(intr)); k < l; k++)
	      if(member(over, chk[k]) != -1) {
		srch = intr[chk[k], 0];
		repl = intr[chk[k], 1];
		if(desc)
		  desc = replace(desc, srch, repl);
		if(oitem)
		  for(m = 0, n = sizeof(list = m_indices(oitem)); m < n; m++) {
		    new = replace(list[m], srch, repl);
		    if(new != list[m]) {
		      if(!mod) {
			oitem = copy_mapping(oitem);
			mod = 1;
		      }
		      oitem[new] = oitem[list[m]];
		      m_delete(oitem, list[m]);
		      list[m] = new;
		    }
		    new = replace(oitem[list[m]], srch, repl);
		    if(new != oitem[list[m]]) {
		      if(!mod) {
			oitem = copy_mapping(oitem);
			mod = 1;
		      }
		      oitem[list[m]] = new;
		    }
		  }
	      }
	  if(oitem)
	    item += oitem;
	  if(desc) {
	    if(strstr(desc, "%r") != -1) {
	      list = query_overlay_directions(mx, my, mz, member(overlay_index, over[i]));
	      if(!sizeof(list))
		desc = replace(desc, "%r", "is here");
	      else if(sizeof(list) > 2)
		desc = replace(desc, "%r", "forms a crossroads here, running " + list_array(sort_array(list, #'>)));
	      else desc = replace(desc, "%r", "runs " + list_array(sort_array(list, #'>)) + " from here");
	    }
	    if(strstr(desc, "%t") != -1) {
	      list = query_overlay_directions(mx, my, mz, member(overlay_index, over[i]));
	      if(!sizeof(list))
		desc = replace(desc, "%t", "is here");
	      else desc = replace(desc, "%t", list_array(map_array(list, #'direction_primus)));
	    }
	    if(strstr(desc, "%w") != -1) {
	      list = query_overlay_directions(mx, my, mz, member(overlay_index, over[i]));
	      if(!sizeof(list))
		desc = replace(desc, "%w", "is here");
	      else desc = replace(desc, "%w", list_array(map_array(list, #'direction_secundus)));
	    }
	    long += ({ capitalize(desc) });
	  }
	}
	if(sizeof(terr))
	  set[Map_Room_Terrain] = unique(terr);
	if(sizeof(rlm))
	  set[Map_Room_Realms] = unique(rlm);
	set[Map_Room_Long] = format(implode(long, "  "));
	if(sizeof(item))
	  set[Map_Room_Items] = map_mapping(item, #'format_values, item);
	set[Map_Room_Exits] = query_room_exits(mx, my, mz);
	set[Map_Room_File] = room_prefix + mx + "_" + my + "_" + mz;
	return outline[code] = set;
}

mapping query_room_queue() {
	return queue;
}

void enqueue_room(object obj) {
	queue += ([ obj ]);
}

void dequeue_room(object obj) {
	queue -= ([ obj ]);
}

private object retrieve_room() {
object *list;
	if(sizeof(list = m_indices(queue))) {
	  queue -= ([ list[0] ]);
	  return list[0];
	} else
	  return clone_object(query_base_room());
}

object query_virtual_room(string name) {
int mx, my, mz;
	if(sscanf(name, room_prefix + "%d_%d_%d", mx, my, mz) == 3)
	  if(mx >= -x && mx <= x && my >= -y && my <= y && mz >= -z && mz <= z)
	    return retrieve_room()->configure_map_room(query_room_settings(mx, my, mz));
}

void configure_custom_room(object room) {
int mx, my, mz;
	if(sscanf(file_name(room), room_prefix + "%d_%d_%d", mx, my, mz) == 3)
	  if(mx >= -x && mx <= x && my >= -y && my <= y && mz >= -z && mz <= z)
	    room->configure_map_room(query_room_settings(mx, my, mz));
}

void initialize_map() {
	read_map(query_map_save());
	parse_rooms();
	parse_overlays();
	parse_map();
	write_map(query_map_save());
}

void create() {
::create();
	lines = Distribution->query_map_lines();
	distances = Distribution->query_map_distances();
	circles = Distribution->query_map_circles();
	outline = ([]);
	acc = ([]);
	top = ([]);
	queue = ([]);
	surr = ([
	  "north"	: 0; 1; 0,
	  "south"	: 0; -1; 0,
	  "east"	: 1; 0; 0,
	  "west"	: -1; 0; 0,
	  "up"		: 0; 0; 1,
	  "down"	: 0; 0; -1,
	]);
}

------------------------------- end map.c ------------------------------------

----------------------------- begin map_room.c -------------------------------

// Map room base inheritable
//
// by Chaos, Tue Aug 20 14:09:47 CDT 1996

// Inheritance

inherit "/std/room";

// Includes

#include <map.h>
#include <realtime.h>
#include <stats.h>
#include <terrains.h>

// Variables

internal int *coordinates;
internal mixed control;
internal string access;
internal status custom;

// Functions

status is_map() {
	return 1;
}

int *query_map_coordinates() {
	return coordinates;
}

void set_access(string new) {
	access = new;
}

string query_access() {
	return access;
}

void set_map_control(mixed daemon) {
	control = daemon;
	if(custom = file_size(file_name() + ".c") > 0)
	  control->configure_custom_room(this_object());
}

mixed query_map_control() {
	return control;
}

void fall(object who) {
mixed *in, *out, *hit;
int i, j, dam;
object *seq;
string next;
	seq = ({ this_object() });
	while(next = seq[<1]->query_exits()["down"]) {
	  seq += ({ next->load() });
	  if(next->query_access() != "fly" && next->query_access() != "climb")
	    break;
	}
	out = ({ who, ({ "fall", who }), "downward" });
	in = ({ who, ({ "fall", who }), "in from above" });
	hit = ({ who, ({ "land", who }), "on the surface" });
	for(i = 0, j = sizeof(seq) - 1; i < j; i++) {
	  tell_room(seq[i], out);
	  seq[i]->catch_msg(out);
	  tell_room(seq[i + 1], in);
	  seq[i + 1]->catch_msg(in);
	}
	j++;
	if(environment(who) != seq[<1])
	  who->move(seq[<1]);
	tell_room(seq[<1], hit);
	seq[<1]->catch_msg(hit);
	if(j <= 3 && seq[<1]->query_terrain(Terrain_Water) && who->query_skill("swimming") > 30)
	  dam = 1;
	else dam = 2;
	who->do_damage(({ random(j * 50 * dam), j * dam }), 0, -1, "crushing");
}

status access_fly(string arg, status looking) {
	if(arg || looking || !this_player() || this_player()->query_flight())
	  return 0;
	write(format("You cannot fly."));
	return 1;
}

status access_float(string arg, status looking) {
	if(arg || looking || !this_player() || this_player()->query_flight())
	  return 0;
	write(format("You cannot fly."));
	return 1;
}

status access_swim(string arg, status looking) {
	if(arg || looking || !this_player() || this_player()->query_flight() || this_player()->query_skill("swimming") > 10)
	  return 0;
	write(format("You cannot swim."));
	return 1;
}

status access_dive(string arg, status looking) {
	if(arg || looking || !this_player() || this_player()->query_skill("swimming") > 10)
	  return 0;
	write(format("You cannot swim."));
	return 1;
}

status access_deepdive(string arg, status looking) {
	if(arg || looking || !this_player())
	  return 0;
	if(this_player()->query_skill("swimming") <= 10) {
	  write(format("You cannot swim."));
	  return 1;
	}
	if(!this_player()->query_altitude_immune() && this_player()->query_resistance("crushing") < 50) {
	  write(format("The pressure would crush you."));
	  return 1;
	}
}

status access_climb(string arg, status looking) {
int sk;
	if(arg || looking || !this_player() || this_player()->query_flight())
	  return 0;
	sk = this_player()->query_skill("climbing");
	if(sk < 10) {
	  write(format("You cannot climb."));
	  return 1;
	} else {
	  sk += min(this_player()->query_average_stat(({ Stat_Str, Stat_Dex, Stat_Int, Stat_Per })), 100);
	  if(random(150) > sk) {
	    this_player()->message(({ 0, ({ "try", 0 }), "to climb " + query_verb() + "ward but", ({ "lose", 0 }), ({ 'r', 0, "grip" })}));
	    fall(this_player());
	    return 1;
	  } else this_player()->message(({ 0, ({ "climb", 0 }), query_verb() + "ward" }));
	  if(!random(5))
	    this_player()->add_skill_exp("climbing", 1);
	}
}

void check_flight(object who) {
	if(query_access() == "fly" && !who->query_flight())
	  fall(who);
}

void init() {
::init();
	this_player() && this_player()->check_flight();
	if(!custom)
	  control->dequeue_room(this_object());
}

void exit() {
	if(!custom && find_call_out("queue_check") == -1)
	  call_out("queue_check", 5);
}

void queue_check() {
	if(!first_inventory() && !custom)
	  control->enqueue_room(this_object());
}

object configure_map_room(mixed *info) {
object obj;
	if(file_name() != info[Map_Room_File]) {
	  if(obj = find_object(info[Map_Room_File]))
	    obj->remove();
	  rename_object(this_object(), info[Map_Room_File]);
	}
	coordinates = info[Map_Room_Coordinates];
	set_short(info[Map_Room_Short]);
	set_long(info[Map_Room_Long]);
	set_exits(info[Map_Room_Exits]);
	set_outdoors(info[Map_Room_Outdoors]);
	set_access(info[Map_Room_Access]);
	set_light(info[Map_Room_Light] - query_light());
	if(info[Map_Room_Altitude] || query_altitude())
	  set_altitude(info[Map_Room_Altitude]);
	set_terrain(info[Map_Room_Terrain] || ({}));
	set_realms(info[Map_Room_Realms] || ({}));
	set_item_descriptions(info[Map_Room_Items] || ([]));
	if(info[Map_Room_Inhabit]) {
	  set_contents(info[Map_Room_Inhabit]);
	  if(info[Map_Room_Populated] < time() - Time_Hour) {
	    info[Map_Room_Populated] = time();
	    reset();
	  }
	} else
	  set_contents(0);
	return this_object();
}

------------------------------- end map_room.c -------------------------------




More information about the mud-dev-archive mailing list