1 /*
2  * PROPRIETARY INFORMATION.  This software is proprietary to POWDER
3  * Development, and is not to be reproduced, transmitted, or disclosed
4  * in any way without written permission.
5  *
6  * Produced by:	Jeff Lait
7  *
8  *      	POWDER Development
9  *
10  * NAME:        map.h ( POWDER Library, C++ )
11  *
12  * COMMENTS:
13  *	The MAP structure.  This defines one levels information.  It
14  *	contains all the items that are on the floor and all the mobs
15  *	that are in the level.
16  */
17 
18 #ifndef __map_h__
19 #define __map_h__
20 
21 //#define MAPSTATS
22 
23 #include "assert.h"
24 #include "glbdef.h"
25 #include "gfxengine.h"
26 #include "smokestack.h"
27 #include "itemstack.h"
28 #include "signpost.h"
29 
30 class MAP;
31 class MOB;
32 class ITEM;
33 class SRAMSTREAM;
34 class INTRINSIC_COUNTER;
35 
36 extern MAP		*glbCurLevel;
37 
38 struct PT2
39 {
40     int x, y;
41     int data;
42 };
43 
44 struct ROOM_DEF
45 {
46     PT2 size;
47     const SQUARE_NAMES *squarelist;
48 
49     // Per square lists
50     const PT2 *squareflaglist;
51     const PT2 *itemlist;
52     const PT2 *moblist;
53     const PT2 *itemtypelist;
54     const PT2 *moblevellist;
55     const PT2 *intrinsiclist;
56     const PT2 *signpostlist;
57 
58     // Global defines
59     int		minlevel, maxlevel;
60     u8		rarity;
61     u8		mandatory;
62     u8		onlyonce;
63     u8		allowstairs;
64     u8		allowgeneration;
65     u8		allowdig;
66     u8		allowitems;
67     u8		allowtel;
68     int		x, y;
69     s8		quest;
70     const char	*name;		// Specific room name from file name.
71 };
72 
73 struct ROOM
74 {
75     PT2			 l, h;
76     const ROOM_DEF	*definition;
77     int			 rotation;
78 };
79 
80 #define ROOM_FLIP_X 1
81 #define ROOM_FLIP_Y 2
82 #define ROOM_FLOP 4
83 
84 class MAP
85 {
86 public:
87     MAP(int level, BRANCH_NAMES branch);
88     virtual ~MAP();
89 
90     // Retrieves the random seed used to build this map.
getSeed()91     long		 getSeed() const { return mySeed; }
92 
93     // This deletes this map and all attached maps
94     void		 deleteAllMaps();
95 
96     // This returns true if their is a path between (sx,sy) and
97     // (ex,ey).  The next step is returned in (dx,dy).  This must
98     // be stateless.
99     // If two paths are equally cool (ie, cutting diagonals) picks
100     // one at random.
101     bool		 findPath(int sx, int sy,
102 				  int ex, int ey,
103 				  MOVE_NAMES movetype,
104 				  bool allowmob,
105 				  bool allowdoor,
106 				  int &dx, int &dy);
107 
108     // This updates the avatar smell at the given location.
109     // The smell should be 0 where the avatar is and lower the farther
110     // away.
111     void		updateAvatarSmell(int x, int y, int smell);
112 
113     // Determines the level of smell at the given square.
114     // Higher is smellier or closer to the avatar.  To make things
115     // normalized, 65535 is at the avatar, 0 is as far as possible.
116     int			getAvatarSmell(int x, int y) const;
117 
118     // Determines the direction closest to the avatar from the given point.
119     // If no direction is closer, returns false.
120     bool		getAvatarSmellGradient(MOB *mob, int x, int y, int &dx, int &dy) const;
121 
122     // This takes an empty map and adds people up to its desired
123     // monster count.
124     void		 populate();
125 
126     // This creates a monster appropriate for our level and puts
127     // it somewhere on the level.
128     // Returns true if successful
129     bool		 createAndPlaceNPC(bool avoidfov);
130 
131     // Refresh will update the gfx engine from this map.
132     // If preserve ray is turned on, any ray tiles in the
133     // overly plane will be preserved.
134     void		 refresh(bool preserve_ray = false);
135     // This will clear out & rebuild the dynamic light lists.
136     void		 updateLights();
137 
138     int			 getDesiredMobCount() const;
139     int			 getThreatLevel() const;
140 
141     // This runs the level's heartbeat script.  It may birth mobs
142     // if the world seems sparse.
143     void		 doHeartbeat();
144 
145     // Digger can be null.  Otherwise, it reports the appropriate messages
146     // about the possibility, and falls through the hole.
147     void		 digHole(int x, int y, MOB *digger);
148 
149     // Digger can be null.  Otherwise, it reports the appropriate messages
150     // about the possibility, and ends up in the pit.
151     // Does not create holes if already pit.
152     void		 digPit(int x, int y, MOB *digger);
153 
154     // Excavates a square.  Destroys boulders
155     bool		 digSquare(int x, int y, MOB *digger);
156 
157     // Grows a nice forest here.
158     void		 growForest(int x, int y, MOB *grower);
159 
160     // Torrential rain falls here
161     void		 downPour(int x, int y, MOB *pourer);
162 
163     // This floods the pit with the given fluid type, such as SQUARE_LAVA
164     // or SQUARE_WATER.
165     void		 floodSquare(SQUARE_NAMES tile, int x, int y,
166 			          MOB *flooder);
167 
168     // This maintaince function will drop all items on the given
169     // square.  The revealer is optional and says who gets credit for the
170     // discovery.  This does nothing if the square doesn't have depth.
171     void		 dropItems(int x, int y, MOB *revealer);
172 
173     // This will try and fill the square that the item is on
174     // with the item itself.  This plugs holes, fills water, etc.
175     // filler is the person to blame if someone is buried alive.
176     // This returns true if filling occured, in which case the item
177     // was deleted.
178     bool		 fillSquare(ITEM *boulder, MOB *filler,
179 				    ITEM **newitem = 0);
180 
181     // This will drop all mobs on the given square into the holes,
182     // provided they don't save via reflex.  They will also sink.
183     // forcetrap negates the reflex save, but they may still save
184     // due to flight, water walking, etc.  They may also save due
185     // to the SKILL_EVADETRAP, unless noskillevade is set.
186     // This returns false if a mob gets killed.
187     bool		 dropMobs(int x, int y, bool forcetrap, MOB *revealer,
188 				    bool noskillevade=false);
189 
190     // Trapper can be null.  Otherwise the trapper SHOULD gain
191     // responsibility for any deaths from the trap :>
192     // Returns whether trap creation was successful.  It can fail
193     // if the square is untrappable (Ie, not plain)
194     bool		 createTrap(int x, int y, MOB *trapper);
195 
196     // This will apply a strong cold effect to the square,
197     // turning water to ice, lava to rock.
198     bool		 freezeSquare(int x, int y, MOB *freezer);
199 
200     // This will apply electricity to the square
201     // If it is liquid, everyone in the liquid or touching it
202     // is fried
203     bool		 electrocuteSquare(int x, int y, MOB *shocker);
204 
205     // Places a moderate amount of water on the square.
206     void		 douseSquare(int x, int y, bool holy, MOB *douser);
207 
208     // This will apply a strong heat to the square, melting ice.
209     bool		 burnSquare(int x, int y, MOB *burner);
210 
211     // This will zap the square with electicity.
212     bool		 electrifySquare(int x, int y, int points,
213 					MOB *shocker);
214 
215     // This will bring all corpses/bones at given square back to life.
216     // Returns true if something happens.
217     bool		 resurrectCorpses(int x, int y, MOB *resser);
218 
219     // This creates a zombie out of the corpses.
220     bool		 raiseZombie(int x, int y, MOB *raiser);
221 
222     // This creates a skeleton out of the bones.
223     bool		 raiseSkeleton(int x, int y, MOB *raiser);
224 
225     // This moves all of the smoke on the level.
226     void		 moveSmoke();
227 
228     // This queries our additional smoke structures that maintain the
229     // type and ownership of smoke squares.
230     SMOKE_NAMES		 getSmoke(int x, int y, MOB **owner=0) const;
231 
232     // Queries our signpost structure for the proper sign post data
233     SIGNPOST_NAMES	 getSignPost(int x, int y) const;
234 
235     // This creates smoke at the given square.  It should be used
236     // rather than trying to explicitly set the SQUAREFLAG values.
237     // Owner is dude responsible for the effects.
238     void		 setSmoke(int x, int y, SMOKE_NAMES smoke, MOB *owner);
239 
240     // Applies a suck-into-space effect at the given coordinate,
241     // assumes a 4 way neighbour is space.
242     void		 applySuction(int x, int y);
243 
244     // This moves all the fluids on the level, filling pits, etc.
245     void		 moveFluids();
246 
247     void		 setWindDirection(int dx, int dy, int duration);
248 
249     // This only reports powerful winds such as the direct wind
250     // spell.  It is assumed people can easily override the slow
251     // currents that are present normally.
252     void		 getWindDirection(int &dx, int &dy);
253 
254     // This reports transient zephyrs as well
255     void		 getAmbientWindDirection(int &dx, int &dy);
256 
257     //
258     // Access methods.  Explicitly inlined.
259     //
setTile(u8 x,u8 y,SQUARE_NAMES tile)260     inline void		 setTile(u8 x, u8 y, SQUARE_NAMES tile)
261     {
262 	UT_ASSERT(x < MAP_WIDTH && y < MAP_HEIGHT);
263 	ourMapDirty = true;
264 	mySquares[x + y * MAP_WIDTH] = tile;
265     }
getTile(u8 x,u8 y)266     inline SQUARE_NAMES	 getTile(u8 x, u8 y) const
267     {
268 	UT_ASSERT(x < MAP_WIDTH && y < MAP_HEIGHT);
269 	return (SQUARE_NAMES) mySquares[x + y * MAP_WIDTH];
270     }
271     // Allows for out of bounds queries, returns SQUARE_EMPTY for those
getTileSafe(u8 x,u8 y)272     inline SQUARE_NAMES	 getTileSafe(u8 x, u8 y) const
273     {
274 	if (x >= MAP_WIDTH || y >= MAP_HEIGHT)
275 	{
276 	    return SQUARE_EMPTY;
277 	}
278 	return (SQUARE_NAMES) mySquares[x + y * MAP_WIDTH];
279     }
compareTile(u8 x,u8 y,SQUARE_NAMES tile)280     inline u8		 compareTile(u8 x, u8 y, SQUARE_NAMES tile)
281     {
282 	if (x >= MAP_WIDTH || y >= MAP_HEIGHT)
283 	    return false;
284 	return (getTile(x, y) == tile);
285     }
286     bool		 hasNeighbouringTile(int x, int y, SQUARE_NAMES tile,
287 				MOB *&srcmob);
288     inline void		 setFlag(u8 x, u8 y, int flag, bool state=true)
289     {
290 	UT_ASSERT(x < MAP_WIDTH && y < MAP_HEIGHT);
291 	if (!state)
292 	    clearFlag(x, y, flag);
293 	else
294 	    myFlags[x + y * MAP_WIDTH] |= flag;
295     }
clearFlag(u8 x,u8 y,int flag)296     inline void		 clearFlag(u8 x, u8 y, int flag)
297     {
298 	UT_ASSERT(x < MAP_WIDTH && y < MAP_HEIGHT);
299 	myFlags[x + y * MAP_WIDTH] &= ~flag;
300     }
301     // Note this does *not* return bool, as it does
302     // not return 0 or 1, but 0 or flag.  This is
303     // for silly performance reasons.
getFlag(u8 x,u8 y,int flag)304     inline int		 getFlag(u8 x, u8 y, int flag) const
305     {
306 	UT_ASSERT(x < MAP_WIDTH && y < MAP_HEIGHT);
307 	return myFlags[x + y * 32] & flag;
308     }
getRawFlag(u8 x,u8 y)309     inline u8		 getRawFlag(u8 x, u8 y) const
310     {
311 	UT_ASSERT(x < MAP_WIDTH && y < MAP_HEIGHT);
312 	return myFlags[x + y * 32];
313     }
setRawFlag(u8 x,u8 y,int flag)314     inline void		 setRawFlag(u8 x, u8 y, int flag)
315     {
316 	UT_ASSERT(x < MAP_WIDTH && y < MAP_HEIGHT);
317 	myFlags[x + y * 32] = flag;
318     }
319 
getDepth()320     int			 getDepth() const { return myDepth; }
321 
322     bool		 allowDiggingDown() const;
323     bool		 allowMobGeneration() const;
324     bool		 allowItemGeneration() const;
325     bool		 allowTeleportation() const;
326 
327     // This marks as mapped everything within the given radius & los.
328     void		 markMapped(int x, int y, int radx, int rady,
329 				    bool uselos = true);
330 
331     // This updates the temporary light field.
332     void		 applyTempLight(int x, int y, int radius);
333     // This applies a map flag to everything in the given radius.
334     void		 applyFlag(SQUAREFLAG_NAMES flag,
335 				    int cx, int cy, int radius,
336 				    bool uselos, bool state);
337 
338     // Is it transparent, can we see through it?
339     bool		 isTransparent(int x, int y) const;
340 
341     // Is lit, by some means or another?
342     bool		 isLit(int x, int y) const;
343 
344     // Is digging not a noop?  Includes boulders, but not creatures
345     bool		 isDiggable(int x, int y) const;
346 
347     // This builds a field of view table.  It sets the FOV temp flag
348     // to true whereever it is within range of rx & ry.
349     void		 buildFOV(int x, int y, int rx, int ry);
350 
351     bool		 hasFOV(int x, int y) const;
352 
353     // This determines if there is a straightline, +/- 1, between the
354     // locations.
355     bool		 hasLOS(int x1, int y1, int x2, int y2) const;
356     // This is a crappy FP algorithm.
357     bool		 hasSlowLOS(int x1, int y1, int x2, int y2) const;
358     // This LOS algorithm was written while rather drunk.
359     bool		 hasDrunkLOS(int x1, int y1, int x2, int y2) const;
360     // This determines if there exists any manhatten walk between the two
361     // locations.
362     // Definitely one of my stupider ideas.
363     bool		 hasManhattenLOS(int x1, int y1, int x2, int y2) const;
364 
365     void		 moveMob(MOB *mob, int ox, int oy, int nx, int ny);
366     void		 registerMob(MOB *mob);
367     void		 unregisterMob(MOB *mob);
getMobHead()368     MOB			*getMobHead() const { return myMobHead; }
369 
370     // Crushes any surrounding breakable walls to make room for this
371     void		 wallCrush(MOB *mob);
372 
373     // This finds all mobs interested in the given mob, which are also
374     // adjacent to the staircase, and causes them to go downstairs.
375     // The avatar is explicitly exempt from this.  Be careful as your
376     // pets may chase people down stairs :>
377     void		 chaseMobOnStaircase(SQUARE_NAMES destsquare,
378 			    int srcx, int srcy,
379 			    MOB *chasee,
380 			    MAP *nextmap);
381 
382     // Gives a brief listing of what is at the square...
383     // blind tells us if the viewer is blind.
384     bool		 describeSquare(int x, int y, bool blind,
385 					bool includeself);
386 
387     // This fetches the maps below or above us.  If they don't exist,
388     // they are created, unless they shouldn't exist when you will
389     // get 0 back.
390     MAP			*getMapUp(bool create = true);
391     MAP			*peekMapUp() const;
392     MAP			*getMapDown(bool create = true);
393     MAP			*peekMapDown() const;
394 
395     // What branch getMapBranch() would be on - where this map
396     // has a branch *to*.  BRANCH_NONE for no branch from here.
397     BRANCH_NAMES	 offshootName() const;
398     // The branch *this is on.  BRANCH_MAIN is, of course, the default.
399     BRANCH_NAMES	 branchName() const;
400     MAP			*getMapBranch(bool create = true);
401     MAP			*peekMapBranch() const;
402 
403     // This is used internally to set up a cross reference...
setMapUp(MAP * map)404     void		 setMapUp(MAP *map) { myMapUp = map; }
setMapDown(MAP * map)405     void		 setMapDown(MAP *map) { myMapDown = map; }
setMapBranch(MAP * branch)406     void		 setMapBranch(MAP *branch) { myMapBranch = branch; }
407 
408     // This finds the mob in the specified square.  Currently very slow.
409     MOB			*getMob(int x, int y) const;
410     // Does a full search for the mob, ignoring the cache.
411     // Does not respect garguantuan for important reasons!
412     MOB			*getMobPrecise(int x, int y) const;
413 
414     // Returns whoever is responsible for the status of this square
415     MOB			*getGuiltyMob(int x, int y) const;
416     void		 setGuiltyMob(int x, int y, MOB *mob);
417 
getItemHead()418     ITEM		*getItemHead() const { return myItemHead; }
419     ITEM		*getItem(int x, int y) const;
420     ITEM		*getItem(int x, int y, bool submerged) const;
421 
422     // This builds an itemstack of everything on the ground.  Submerged
423     // check, if positive, determines if submerged status is used.
424     // Note this just appends to the itemstack!
425     // If checkmapped is true, it only adds items that have their
426     // mapped bit set.
427     int 		 getItemStack(ITEMSTACK &stack, int x, int y,
428 					int submergecheck = -1,
429 					bool checkmapped = false) const;
430 
431     // This builds a mob stack of all tamed mobs directly in the
432     // control of the given mob.
433     // Returns number of pets.
434     // If sensable is true, only returns the pets that are sensable.
435     int			 getPets(MOBSTACK &stack, MOB *owner,
436 				 bool onlysensable) const;
437 
438     // This is the tile acquiring the item.
439     // This sets newitem to the stack it gets merged to, otherwise itself.
440     // Note item *can* be deleted here!
441     // If we are to believe the item's grade status, set ignoregrade.
442     // This is used for loading.
443     // The item can *also* be dropped down a hole so end up on a
444     // different level.  In this case, newitem is also set to 0.
445     void		 acquireItem(ITEM *item, int x, int y,
446 				     MOB *dropper,
447 				     ITEM **newitem = 0,
448 				     bool ignoregrade = false);
449     // This is the tile relieving & unlinking the item (as opposed to get)
450     ITEM		*dropItem(int x, int y);
451     void		 dropItem(ITEM *item);
452 
453     // If item is a bottle, fills with the liquid in tile x,y
454     void		 fillBottle(ITEM *item, int x, int y) const;
455 
456     // This gets a random location on the map that fits the given profile.
457     // It returns false if no such location was found.
458     bool		 findRandomLoc(int &x, int &y, int movetype,
459 					bool allowmob,
460 					bool doublesize,
461 					bool avoidfov,
462 					bool avoidfire,
463 					bool avoidacid,
464 					bool avoidnomob);
465 
466     // This finds an instance of the given tile.
467     // Returns false if no such tile exists.
468     bool		 findTile(SQUARE_NAMES tile, int &x, int &y);
469 
470     // This finds the closest tile to the given x/y coordinate that
471     // is legal according to the provided move mask & mob mask.
472     // It does a spiral search, and ignores LOS.
473     bool		 findCloseTile(int &x, int &y, MOVE_NAMES move,
474 					bool allowmob = false,
475 					int maxradius = MAP_WIDTH);
476 
477     // Does a simple search to see if this square is inside a room
478     // with no non-hidden exits.  This lets us warn the player that
479     // it isn't a dead end.
480     bool		 isSquareInLockedRoom(int x, int y) const;
481 
482     // This will run the heartbeat & doAI on all the critters that
483     // are not the avatar.
484     void		 moveNPCs();
485 
486     // Determines if the given movetype can go into the given square.
487     // Return false if it fails.
488     bool		 canMove(int x, int y, MOVE_NAMES movetype,
489 				    bool allowmob = true,
490 				    bool allowdoor = false,
491 				    bool allowitem = true);
492 
493     // Determines if a ray can move into the given square.
494     // If a mob there has reflection, it can't move there.
495     // If reflect is false, no reflection checks occur.
496     // didreflect is set to true if reflection occured.
497     bool		 canRayMove(int x, int y, MOVE_NAMES movetype,
498 				    bool reflect, bool *didreflect = 0);
499 
500     // Throws an item in a certain direction.
501     void		 throwItem(int x, int y, int dx, int dy,
502 				ITEM *item, ITEM *stack, ITEM *launcher,
503 				MOB *thrower,
504 				const ATTACK_DEF *attack,
505 				bool ricochet);
506 
507     // This draws a ray through the environment, appropriate overlay
508     // tiles.  If dobounce is true, it will bounce properly when
509     // it hits something impassable according to movetype.
510     // Each square it will trigger the raycallback, which can
511     // return false if the ray should die.
512     // The ray starts one square in the direction dx/dy.
513     // One of dx & dy must be non zero.
514     void		 fireRay(int ox, int oy, int dx, int dy,
515 				int length,
516 				MOVE_NAMES movetype, bool dobounce,
517 				bool raycallback(int x, int y, bool final,
518 						void *data),
519 				void *data);
520 
521     // This draws a ball in the environment, appropriate overlay tiles.
522     // Each square affected will trigger the ballcallback.  The result
523     // code of the ball callback is unused.
524     void		 fireBall(int ox, int oy, int rad, bool includecenter,
525 				bool ballcallback(int x, int y, bool final,
526 						    void *data),
527 				void *data);
528 
529     // Performs a knockback with the (possibly) two creatures.
530     // We specify the target of the knockback and the direction to apply
531     // it in.  If infinitemass is true, the source isn't eligible to
532     // be knocked back.
533     bool		 knockbackMob(int tx, int ty, int dx, int dy,
534 				    bool infinitemass,
535 				    bool ignoremob = false);
536 
537     // Save/load the global information to all maps
538     static void		 saveGlobal(SRAMSTREAM &os);
539     static void		 loadGlobal(SRAMSTREAM &is);
540     // Save the map...
541     void		 saveBranch(SRAMSTREAM &is, bool savebranch = true);
542     bool		 save(SRAMSTREAM &os, bool savebranch = true);
543     // And load...
544     void		 loadBranch(SRAMSTREAM &is, bool checkbranch = true);
545     bool		 load(SRAMSTREAM &is, bool checkbranch = true);
546 
547     bool		 verifyMob() const;
548     bool		 verifyMobLocal() const;
549 
550     bool		 verifyCounterGone(INTRINSIC_COUNTER *counter) const;
551     bool		 verifyCounterGoneLocal(INTRINSIC_COUNTER *counter) const;
552 
553     // The map can report messages.  These are eaten unless
554     // the avatar can see (x, y).
555     void		 reportMessage(const char *str, int x, int y) const;
reportMessage(BUF buf,int x,int y)556     void		 reportMessage(BUF buf, int x, int y) const
557 			 { reportMessage(buf.buffer(), x, y); }
558 
getItemCount()559     int			 getItemCount() const { return myItemCount; }
getMobCount()560     int			 getMobCount() const { return myMobCount; }
561 
562     // Returns the map which has the given mob, 0 if it shows up on
563     // no map.
564     MAP			*findMapWithMob(MOB *mob, bool usebranch=true) const;
565     bool		 isMobOnMap(MOB *mob) const;
566 
567     // Collapses the dungeon by destroying all non-quest items.
568     void		 collapseDungeon(bool dobranch = true);
569     void		 collapseThisDungeon();
570 
571 
572     // Flags that we want to (eventually) change the current level
573     // but can't immediately as we are in some ugly code stack that
574     // uses glbCurLevel
575     static void		 delayedLevelChange(MAP *newcurrent);
576 
577     // Looks for stashed level changes and applies them.
578     static void		 checkForAvatarMapChange();
579 
580     // This handles bookkeeping of glbCurLevel.  Do not set by hand!
581     static void		 changeCurrentLevel(MAP *newcurrent);
582 
583     // This will rebuild the pointer maps to be accurate for this.
584     // Should be glbCurLevel->refreshPtrMaps whenever glbCurLevel is changed.
585     void		 refreshPtrMaps();
586 
587     //
588     // Build methods.
589     // These methods are defined in build.cpp
590     // They are used to construct the map.
591     //
592 
593     // Generic build method, does different things depending on level,
594     // random chance, etc.
595     // The alreadysavedseed is a flag to ensure we don't resave the seed,
596     // as that would cause the random number seed to be changed when
597     // we try and force an exact rebuild by pre-setting the seed.
598     void		 build(bool alreadysavedseed);
599 
isLoading()600     static bool		 isLoading() { return ourIsLoading; }
601 
602     // Is this map unlocked?
603     bool		 isUnlocked() const;
604 
605 protected:
606     // This wipes out the map and fills it with a blank map.
607     // This will also delete all mobs and all creatures in the map.
608     void		 clear();
609 
610     // Specific map builders.
611     void		 buildRoguelike();
612     void		 buildQuest(GOD_NAMES god);
613     void		 buildBigRoom();
614     void		 buildDrunkenCavern(bool islit, bool allowlakes, bool allowroom, bool buildstaircase);
615     void		 buildMaze(int stride);
616 
617     // Attempts to smooth a map removing small dead end nooks.
618     void		 smooth(SQUARE_NAMES floor, SQUARE_NAMES wall);
619 
620     // Does a flood fill with the given tile type, replacing the
621     // given tile
622     void		 fillWithTile(int x, int y, SQUARE_NAMES newtile, SQUARE_NAMES oldtile);
623     // Qix style level, Bunch of walls subdividing the level.
624     void		 drawQixWall(int x, int y, int dx, int dy, bool islit);
625     void		 buildQix(bool islit);
626     // A cavern bisected by a river.
627     void		 buildRiverRoom();
628     void		 buildSurfaceWorld();
629     void		 buildTutorial();
630     // Builds the tridude spaceship
631     void		 buildSpaceShip();
632     // Builds Baezl'bub's lair - lots of water, lava, and caverns.
633     void		 buildHello();
634 
635     void		 drawCircle(int cx, int cy, int rad,
636 				    SQUARE_NAMES tile,
637 				    SQUAREFLAG_NAMES flag,
638 				    bool overwrite = false);
639 
640     void		 drawLine(int x1, int y1, int x2, int y2,
641 				SQUARE_NAMES tile,
642 				bool overwrite = false);
643 
644     // Specific type of move building
645     bool		 buildMoveDistance(int px, int py, MOVE_NAMES move);
646     // This builds the distance function given the given walk function...
647     bool		 buildDistance(int px, int py);
648 
649     // Builder functions.
650     bool		 drawPath(int sx, int sy, int ex, int ey,
651 				 bool lit = false);
652     bool		 drawPathStraight(int sx, int sy, int ex, int ey,
653 				 bool lit = false);
654     void		 drawPath_old(int sx, int sy, int ex, int ey,
655 				 bool lit = false);
656     bool		 drawCorridor(int sx, int sy, int sdx, int sdy,
657 				 int ex, int ey, int edx, int edy,
658 				 bool lit = false);
659     void		 createColouredTridudeLair(int x, int y, MOB_NAMES tridude, MOB *trueleader);
660     MOB			*createGoldenTridudeLair(int x, int y);
661     static const ROOM_DEF *chooseRandomRoom(int depth);
662     void		 buildRandomRoom(ROOM &room);
663 public:
664     void		 buildRandomRoomFromDefinition(ROOM &room,
665 					const ROOM_DEF *def);
666     void		 populateRoom(const ROOM &room);
667     void		 drawRoom(const ROOM &room,
668 				 bool lit,
669 				 bool mazetype,
670 				 bool caverntype);
671 protected:
672     void		 chooseRandomExit(int *enter, int *delta,
673 				 const ROOM &room);
674     void		 closeUnusedExits(const ROOM &room, bool force);
675     void		 roomToMapCoords(int &mx, int &my,
676 				const ROOM &room, int rx, int ry);
677     void		 mapToRoomCoords(int &rx, int &ry,
678 				const ROOM &room, int mx, int my);
679 
680     // Builder query functions, these aren't necessarily valid outside
681     // the building code.
682     bool		 isTileWall(int tile) const;
683     bool		 isMapWall(int x, int y) const;
684     bool		 isMapExit(int x, int y) const;
685     bool		 isRoomExit(const ROOM &room, int x, int y) const;
686     bool		 isMapPathway(int x, int y) const;
687     bool		 checkRoomFits(const ROOM &room);
688 
689     // This draws a path element, or a door if the destinatin is a wall.
690     void		 setPathTile(int x, int y, bool lit, bool usefloor);
691 
692     void		 addSignPost(SIGNPOST_NAMES post, int x, int y);
693 
694 public:
695 #ifdef MAPSTATS
696     static void		 printStatsHeader(FILE *fp);
697     bool		 printStats(FILE *fp);
698 #endif
699 
700 private:
701     // Data...
702     long		 mySeed;		// Random number seed used.
703     int			 myGlobalFlags;		// Global flags for this map.
704 
705     // Indices into SQUARE.
706     u8			*mySquares;
707     // These are the state flags for each world square...
708     u8			*myFlags;
709     // Stashed coords of the FOV map.
710     s8			 myFOVX, myFOVY;
711     // What branch we are on.
712     u8			 myBranch;
713     // How deep this map is.
714     s8			 myDepth;
715 
716     // Indices into SQUARE, TILE_VOID if blank.
717     // These are temporary arrays for efficient map refreshing.
718     static u16		*ourItemMap;
719     static u16		*ourMobMap;
720     // This is 0 if not a wall, 1 if a wall.
721     static u8		*ourWallMap;
722     // This is how far each square is from the desired destination,
723     // thus allowing gradiant computatin and path finding.
724     static u16		*ourDistanceMap;
725     static u16		*ourAvatarSmell;
726     static u16		 ourAvatarSmellWatermark;
727     // These track our cell positions & cutout values  used by the
728     // build functions.
729     static int		*ourCells;
730     static int		*ourCutOuts;
731 
732     // These are pointers to the first mob or item on each square.
733     // They are only valid for the current level.
734     static MOBREF	*ourMobRefMap;
735     static ITEM		**ourItemPtrMap;
736 
737     // This tracks who is responsible for each square
738     // It is not saved per level - changing level loses responsibility
739     static MOBREF	*ourMobGuiltyMap;
740 
741     // This is the mob list..
742     int			 myMobCount;
743     int			 myItemCount;
744     MOB			*myMobHead;
745     // If we unregister this mob, we will autobump it.
746     MOB			*myMobSafeNext;
747     // And the item list...
748     ITEM		*myItemHead;
749 
750     // Pointers to the double linked list of maps...
751     // Zero means not yet built.
752     MAP			*myMapUp;
753     MAP			*myMapDown;
754     // My branch and myself are on the same "level",
755     // myMapBranch->myMapBranch == this.
756     MAP			*myMapBranch;
757 
758     // Bleh... List of all valid smoke on the level.
759     // Entries may be SMOKE_NONE, in which case they are cleared out
760     // and waiting compression.
761     SMOKESTACK		 mySmokeStack;
762 
763     SIGNLIST		*mySignList;
764 
765     // Flags whether we are currently loading or not.
766     static bool		 ourIsLoading;
767 
768     // Flags the current wind direction and count down.
769     // Shared by all levels.  If count down is out, wind direction
770     // is random
771     static s8		 ourWindDX, ourWindDY;
772     static int		 ourWindCounter;
773     static bool		 ourMapDirty;
774     static MAP		*ourDelayedLevelChange;
775 };
776 
777 #endif
778