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