Annotation of brogue-ce/src/brogue/RogueMain.c, Revision 1.1
1.1 ! rubenllo 1: /*
! 2: * RogueMain.c
! 3: * Brogue
! 4: *
! 5: * Created by Brian Walker on 12/26/08.
! 6: * Copyright 2012. All rights reserved.
! 7: *
! 8: * This file is part of Brogue.
! 9: *
! 10: * This program is free software: you can redistribute it and/or modify
! 11: * it under the terms of the GNU Affero General Public License as
! 12: * published by the Free Software Foundation, either version 3 of the
! 13: * License, or (at your option) any later version.
! 14: *
! 15: * This program is distributed in the hope that it will be useful,
! 16: * but WITHOUT ANY WARRANTY; without even the implied warranty of
! 17: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 18: * GNU Affero General Public License for more details.
! 19: *
! 20: * You should have received a copy of the GNU Affero General Public License
! 21: * along with this program. If not, see <http://www.gnu.org/licenses/>.
! 22: */
! 23:
! 24: #include "Rogue.h"
! 25: #include "IncludeGlobals.h"
! 26: #include <time.h>
! 27:
! 28:
! 29: void rogueMain() {
! 30: previousGameSeed = 0;
! 31: mainBrogueJunction();
! 32: }
! 33:
! 34: void executeEvent(rogueEvent *theEvent) {
! 35: rogue.playbackBetweenTurns = false;
! 36: if (theEvent->eventType == KEYSTROKE) {
! 37: executeKeystroke(theEvent->param1, theEvent->controlKey, theEvent->shiftKey);
! 38: } else if (theEvent->eventType == MOUSE_UP
! 39: || theEvent->eventType == RIGHT_MOUSE_UP) {
! 40: executeMouseClick(theEvent);
! 41: }
! 42: }
! 43:
! 44: boolean fileExists(const char *pathname) {
! 45: FILE *openedFile;
! 46: openedFile = fopen(pathname, "rb");
! 47: if (openedFile) {
! 48: fclose(openedFile);
! 49: return true;
! 50: } else {
! 51: return false;
! 52: }
! 53: }
! 54:
! 55: // Player specifies a file; if all goes well, put it into path and return true.
! 56: // Otherwise, return false.
! 57: boolean chooseFile(char *path, char *prompt, char *defaultName, char *suffix) {
! 58:
! 59: if (getInputTextString(path,
! 60: prompt,
! 61: min(DCOLS-25, BROGUE_FILENAME_MAX - strlen(suffix)),
! 62: defaultName,
! 63: suffix,
! 64: TEXT_INPUT_FILENAME,
! 65: false)
! 66: && path[0] != '\0') {
! 67:
! 68: strcat(path, suffix);
! 69: return true;
! 70: } else {
! 71: return false;
! 72: }
! 73: }
! 74:
! 75: // If the file exists, copy it into currentFilePath. (Otherwise return false.)
! 76: // Then, strip off the suffix, replace it with ANNOTATION_SUFFIX,
! 77: // and if that file exists, copy that into annotationPathname. Return true.
! 78: boolean openFile(const char *path) {
! 79: short i;
! 80: char buf[BROGUE_FILENAME_MAX];
! 81: boolean retval;
! 82:
! 83: if (fileExists(path)) {
! 84:
! 85: strcpy(currentFilePath, path);
! 86: annotationPathname[0] = '\0';
! 87:
! 88: // Clip off the suffix.
! 89: strcpy(buf, path);
! 90: for (i = strlen(path); buf[i] != '.' && i > 0; i--) continue;
! 91: if (buf[i] == '.'
! 92: && i + strlen(ANNOTATION_SUFFIX) < BROGUE_FILENAME_MAX) {
! 93:
! 94: buf[i] = '\0'; // Snip!
! 95: strcat(buf, ANNOTATION_SUFFIX);
! 96: strcpy(annotationPathname, buf); // Load the annotations file too.
! 97: }
! 98: retval = true;
! 99: } else {
! 100: retval = false;
! 101: }
! 102:
! 103: return retval;
! 104: }
! 105:
! 106: void benchmark() {
! 107: short i, j, k;
! 108: const color sparklesauce = {10, 0, 20, 60, 40, 100, 30, true};
! 109: enum displayGlyph theChar;
! 110:
! 111: unsigned long initialTime = (unsigned long) time(NULL);
! 112: for (k=0; k<500; k++) {
! 113: for (i=0; i<COLS; i++) {
! 114: for (j=0; j<ROWS; j++) {
! 115: theChar = rand_range('!', '~');
! 116: plotCharWithColor(theChar, i, j, &sparklesauce, &sparklesauce);
! 117: }
! 118: }
! 119: pauseBrogue(1);
! 120: }
! 121: printf("\n\nBenchmark took a total of %lu seconds.", ((unsigned long) time(NULL)) - initialTime);
! 122: }
! 123:
! 124: void welcome() {
! 125: char buf[DCOLS*3], buf2[DCOLS*3];
! 126: message("Hello and welcome, adventurer, to the Dungeons of Doom!", false);
! 127: strcpy(buf, "Retrieve the ");
! 128: encodeMessageColor(buf, strlen(buf), &itemMessageColor);
! 129: strcat(buf, "Amulet of Yendor");
! 130: encodeMessageColor(buf, strlen(buf), &white);
! 131: sprintf(buf2, " from the %ith floor and escape with it!", AMULET_LEVEL);
! 132: strcat(buf, buf2);
! 133: message(buf, false);
! 134: if (KEYBOARD_LABELS) {
! 135: messageWithColor("Press <?> for help at any time.", &backgroundMessageColor, false);
! 136: }
! 137: flavorMessage("The doors to the dungeon slam shut behind you.");
! 138: }
! 139:
! 140: // Seed is used as the dungeon seed unless it's zero, in which case generate a new one.
! 141: // Either way, previousGameSeed is set to the seed we use.
! 142: // None of this seed stuff is applicable if we're playing a recording.
! 143: void initializeRogue(unsigned long seed) {
! 144: short i, j, k;
! 145: item *theItem;
! 146: boolean playingback, playbackFF, playbackPaused, wizard, displayAggroRangeMode;
! 147: boolean trueColorMode;
! 148: short oldRNG;
! 149:
! 150: playingback = rogue.playbackMode; // the only animals that need to go on the ark
! 151: playbackPaused = rogue.playbackPaused;
! 152: playbackFF = rogue.playbackFastForward;
! 153: wizard = rogue.wizard;
! 154: displayAggroRangeMode = rogue.displayAggroRangeMode;
! 155: trueColorMode = rogue.trueColorMode;
! 156: memset((void *) &rogue, 0, sizeof( playerCharacter )); // the flood
! 157: rogue.playbackMode = playingback;
! 158: rogue.playbackPaused = playbackPaused;
! 159: rogue.playbackFastForward = playbackFF;
! 160: rogue.wizard = wizard;
! 161: rogue.displayAggroRangeMode = displayAggroRangeMode;
! 162: rogue.trueColorMode = trueColorMode;
! 163:
! 164: rogue.gameHasEnded = false;
! 165: rogue.gameInProgress = true;
! 166: rogue.highScoreSaved = false;
! 167: rogue.cautiousMode = false;
! 168: rogue.milliseconds = 0;
! 169:
! 170: rogue.RNG = RNG_SUBSTANTIVE;
! 171: if (!rogue.playbackMode) {
! 172: rogue.seed = seedRandomGenerator(seed);
! 173: previousGameSeed = rogue.seed;
! 174: }
! 175:
! 176: //benchmark();
! 177:
! 178: initRecording();
! 179:
! 180: levels = malloc(sizeof(levelData) * (DEEPEST_LEVEL+1));
! 181: levels[0].upStairsLoc[0] = (DCOLS - 1) / 2 - 1;
! 182: levels[0].upStairsLoc[1] = DROWS - 2;
! 183:
! 184: // reset enchant and gain strength frequencies
! 185: rogue.lifePotionFrequency = 0;
! 186: rogue.strengthPotionFrequency = 40;
! 187: rogue.enchantScrollFrequency = 60;
! 188:
! 189: // all DF messages are eligible for display
! 190: resetDFMessageEligibility();
! 191:
! 192: // initialize the levels list
! 193: for (i=0; i<DEEPEST_LEVEL+1; i++) {
! 194: levels[i].levelSeed = (unsigned long) rand_range(0, 9999);
! 195: levels[i].levelSeed += (unsigned long) 10000 * rand_range(0, 9999);
! 196: levels[i].monsters = NULL;
! 197: levels[i].dormantMonsters = NULL;
! 198: levels[i].items = NULL;
! 199: levels[i].scentMap = NULL;
! 200: levels[i].visited = false;
! 201: levels[i].playerExitedVia[0] = 0;
! 202: levels[i].playerExitedVia[1] = 0;
! 203: do {
! 204: levels[i].downStairsLoc[0] = rand_range(1, DCOLS - 2);
! 205: levels[i].downStairsLoc[1] = rand_range(1, DROWS - 2);
! 206: } while (distanceBetween(levels[i].upStairsLoc[0], levels[i].upStairsLoc[1],
! 207: levels[i].downStairsLoc[0], levels[i].downStairsLoc[1]) < DCOLS / 3);
! 208: if (i < DEEPEST_LEVEL) {
! 209: levels[i+1].upStairsLoc[0] = levels[i].downStairsLoc[0];
! 210: levels[i+1].upStairsLoc[1] = levels[i].downStairsLoc[1];
! 211: }
! 212: }
! 213:
! 214: // initialize the waypoints list
! 215: for (i=0; i<MAX_WAYPOINT_COUNT; i++) {
! 216: rogue.wpDistance[i] = allocGrid();
! 217: fillGrid(rogue.wpDistance[i], 0);
! 218: }
! 219:
! 220: rogue.rewardRoomsGenerated = 0;
! 221:
! 222: // pre-shuffle the random terrain colors
! 223: oldRNG = rogue.RNG;
! 224: rogue.RNG = RNG_COSMETIC;
! 225: //assureCosmeticRNG;
! 226: for (i=0; i<DCOLS; i++) {
! 227: for( j=0; j<DROWS; j++ ) {
! 228: for (k=0; k<8; k++) {
! 229: terrainRandomValues[i][j][k] = rand_range(0, 1000);
! 230: }
! 231: }
! 232: }
! 233: restoreRNG;
! 234:
! 235: zeroOutGrid(displayDetail);
! 236:
! 237: for (i=0; i<NUMBER_MONSTER_KINDS; i++) {
! 238: monsterCatalog[i].monsterID = i;
! 239: }
! 240:
! 241: shuffleFlavors();
! 242:
! 243: for (i = 0; i < FEAT_COUNT; i++) {
! 244: rogue.featRecord[i] = featTable[i].initialValue;
! 245: }
! 246:
! 247: deleteMessages();
! 248: for (i = 0; i < MESSAGE_ARCHIVE_LINES; i++) { // Clear the message archive.
! 249: messageArchive[i][0] = '\0';
! 250: }
! 251: messageArchivePosition = 0;
! 252:
! 253: // Seed the stacks.
! 254: floorItems = (item *) malloc(sizeof(item));
! 255: memset(floorItems, '\0', sizeof(item));
! 256: floorItems->nextItem = NULL;
! 257:
! 258: packItems = (item *) malloc(sizeof(item));
! 259: memset(packItems, '\0', sizeof(item));
! 260: packItems->nextItem = NULL;
! 261:
! 262: monsterItemsHopper = (item *) malloc(sizeof(item));
! 263: memset(monsterItemsHopper, '\0', sizeof(item));
! 264: monsterItemsHopper->nextItem = NULL;
! 265:
! 266: for (i = 0; i < MAX_ITEMS_IN_MONSTER_ITEMS_HOPPER; i++) {
! 267: theItem = generateItem(ALL_ITEMS & ~FOOD, -1); // Monsters can't carry food: the food clock cannot be cheated!
! 268: theItem->nextItem = monsterItemsHopper->nextItem;
! 269: monsterItemsHopper->nextItem = theItem;
! 270: }
! 271:
! 272: monsters = (creature *) malloc(sizeof(creature));
! 273: memset(monsters, '\0', sizeof(creature));
! 274: monsters->nextCreature = NULL;
! 275:
! 276: dormantMonsters = (creature *) malloc(sizeof(creature));
! 277: memset(dormantMonsters, '\0', sizeof(creature));
! 278: dormantMonsters->nextCreature = NULL;
! 279:
! 280: graveyard = (creature *) malloc(sizeof(creature));
! 281: memset(graveyard, '\0', sizeof(creature));
! 282: graveyard->nextCreature = NULL;
! 283:
! 284: purgatory = (creature *) malloc(sizeof(creature));
! 285: memset(purgatory, '\0', sizeof(creature));
! 286: purgatory->nextCreature = NULL;
! 287:
! 288: scentMap = NULL;
! 289: safetyMap = allocGrid();
! 290: allySafetyMap = allocGrid();
! 291: chokeMap = allocGrid();
! 292:
! 293: rogue.mapToSafeTerrain = allocGrid();
! 294:
! 295: // Zero out the dynamic grids, as an essential safeguard against OOSes:
! 296: fillGrid(safetyMap, 0);
! 297: fillGrid(allySafetyMap, 0);
! 298: fillGrid(chokeMap, 0);
! 299: fillGrid(rogue.mapToSafeTerrain, 0);
! 300:
! 301: // initialize the player
! 302:
! 303: memset(&player, '\0', sizeof(creature));
! 304: player.info = monsterCatalog[0];
! 305: initializeGender(&player);
! 306: player.movementSpeed = player.info.movementSpeed;
! 307: player.attackSpeed = player.info.attackSpeed;
! 308: clearStatus(&player);
! 309: player.carriedItem = NULL;
! 310: player.status[STATUS_NUTRITION] = player.maxStatus[STATUS_NUTRITION] = STOMACH_SIZE;
! 311: player.currentHP = player.info.maxHP;
! 312: player.creatureState = MONSTER_ALLY;
! 313: player.ticksUntilTurn = 0;
! 314: player.mutationIndex = -1;
! 315:
! 316: rogue.depthLevel = 1;
! 317: rogue.deepestLevel = 1;
! 318: rogue.scentTurnNumber = 1000;
! 319: rogue.playerTurnNumber = 0;
! 320: rogue.absoluteTurnNumber = 0;
! 321: rogue.previousPoisonPercent = 0;
! 322: rogue.foodSpawned = 0;
! 323: rogue.lifePotionsSpawned = 0;
! 324: rogue.gold = 0;
! 325: rogue.goldGenerated = 0;
! 326: rogue.disturbed = false;
! 327: rogue.autoPlayingLevel = false;
! 328: rogue.automationActive = false;
! 329: rogue.justRested = false;
! 330: rogue.justSearched = false;
! 331: rogue.easyMode = false;
! 332: rogue.inWater = false;
! 333: rogue.creaturesWillFlashThisTurn = false;
! 334: rogue.updatedSafetyMapThisTurn = false;
! 335: rogue.updatedAllySafetyMapThisTurn = false;
! 336: rogue.updatedMapToSafeTerrainThisTurn = false;
! 337: rogue.updatedMapToShoreThisTurn = false;
! 338: rogue.strength = 12;
! 339: rogue.weapon = NULL;
! 340: rogue.armor = NULL;
! 341: rogue.ringLeft = NULL;
! 342: rogue.ringRight = NULL;
! 343: rogue.monsterSpawnFuse = rand_range(125, 175);
! 344: rogue.ticksTillUpdateEnvironment = 100;
! 345: rogue.mapToShore = NULL;
! 346: rogue.cursorLoc[0] = rogue.cursorLoc[1] = -1;
! 347: rogue.xpxpThisTurn = 0;
! 348:
! 349: rogue.yendorWarden = NULL;
! 350:
! 351: rogue.flares = NULL;
! 352: rogue.flareCount = rogue.flareCapacity = 0;
! 353:
! 354: rogue.minersLight = lightCatalog[MINERS_LIGHT];
! 355:
! 356: rogue.clairvoyance = rogue.regenerationBonus
! 357: = rogue.stealthBonus = rogue.transference = rogue.wisdomBonus = rogue.reaping = 0;
! 358: rogue.lightMultiplier = 1;
! 359:
! 360: theItem = generateItem(FOOD, RATION);
! 361: theItem = addItemToPack(theItem);
! 362:
! 363: theItem = generateItem(WEAPON, DAGGER);
! 364: theItem->enchant1 = theItem->enchant2 = 0;
! 365: theItem->flags &= ~(ITEM_CURSED | ITEM_RUNIC);
! 366: identify(theItem);
! 367: theItem = addItemToPack(theItem);
! 368: equipItem(theItem, false);
! 369:
! 370: theItem = generateItem(WEAPON, DART);
! 371: theItem->enchant1 = theItem->enchant2 = 0;
! 372: theItem->quantity = 15;
! 373: theItem->flags &= ~(ITEM_CURSED | ITEM_RUNIC);
! 374: identify(theItem);
! 375: theItem = addItemToPack(theItem);
! 376:
! 377: theItem = generateItem(ARMOR, LEATHER_ARMOR);
! 378: theItem->enchant1 = 0;
! 379: theItem->flags &= ~(ITEM_CURSED | ITEM_RUNIC);
! 380: identify(theItem);
! 381: theItem = addItemToPack(theItem);
! 382: equipItem(theItem, false);
! 383: player.status[STATUS_DONNING] = 0;
! 384:
! 385: recalculateEquipmentBonuses();
! 386:
! 387: DEBUG {
! 388: theItem = generateItem(RING, RING_CLAIRVOYANCE);
! 389: theItem->enchant1 = max(DROWS, DCOLS);
! 390: theItem->flags &= ~ITEM_CURSED;
! 391: identify(theItem);
! 392: theItem = addItemToPack(theItem);
! 393:
! 394: theItem = generateItem(RING, RING_AWARENESS);
! 395: theItem->enchant1 = 30;
! 396: theItem->flags &= ~ITEM_CURSED;
! 397: identify(theItem);
! 398: theItem = addItemToPack(theItem);
! 399:
! 400: theItem = generateItem(WEAPON, DAGGER);
! 401: theItem->enchant1 = 50;
! 402: theItem->enchant2 = W_QUIETUS;
! 403: theItem->flags &= ~(ITEM_CURSED);
! 404: theItem->flags |= (ITEM_PROTECTED | ITEM_RUNIC | ITEM_RUNIC_HINTED);
! 405: theItem->damage.lowerBound = theItem->damage.upperBound = 25;
! 406: identify(theItem);
! 407: theItem = addItemToPack(theItem);
! 408:
! 409: theItem = generateItem(ARMOR, LEATHER_ARMOR);
! 410: theItem->enchant1 = 50;
! 411: theItem->enchant2 = A_REFLECTION;
! 412: theItem->flags &= ~(ITEM_CURSED | ITEM_RUNIC_HINTED);
! 413: theItem->flags |= (ITEM_PROTECTED | ITEM_RUNIC);
! 414: identify(theItem);
! 415: theItem = addItemToPack(theItem);
! 416:
! 417: theItem = generateItem(STAFF, STAFF_FIRE);
! 418: theItem->enchant1 = 10;
! 419: theItem->charges = 300;
! 420: identify(theItem);
! 421: theItem = addItemToPack(theItem);
! 422:
! 423: theItem = generateItem(STAFF, STAFF_LIGHTNING);
! 424: theItem->enchant1 = 10;
! 425: theItem->charges = 300;
! 426: identify(theItem);
! 427: theItem = addItemToPack(theItem);
! 428:
! 429: theItem = generateItem(STAFF, STAFF_TUNNELING);
! 430: theItem->enchant1 = 10;
! 431: theItem->charges = 3000;
! 432: identify(theItem);
! 433: theItem = addItemToPack(theItem);
! 434:
! 435: theItem = generateItem(STAFF, STAFF_OBSTRUCTION);
! 436: theItem->enchant1 = 10;
! 437: theItem->charges = 300;
! 438: identify(theItem);
! 439: theItem = addItemToPack(theItem);
! 440:
! 441: theItem = generateItem(STAFF, STAFF_ENTRANCEMENT);
! 442: theItem->enchant1 = 10;
! 443: theItem->charges = 300;
! 444: identify(theItem);
! 445: theItem = addItemToPack(theItem);
! 446:
! 447: theItem = generateItem(WAND, WAND_BECKONING);
! 448: theItem->charges = 3000;
! 449: identify(theItem);
! 450: theItem = addItemToPack(theItem);
! 451:
! 452: theItem = generateItem(WAND, WAND_DOMINATION);
! 453: theItem->charges = 300;
! 454: identify(theItem);
! 455: theItem = addItemToPack(theItem);
! 456:
! 457: theItem = generateItem(WAND, WAND_PLENTY);
! 458: theItem->charges = 300;
! 459: identify(theItem);
! 460: theItem = addItemToPack(theItem);
! 461:
! 462: theItem = generateItem(WAND, WAND_NEGATION);
! 463: theItem->charges = 300;
! 464: identify(theItem);
! 465: theItem = addItemToPack(theItem);
! 466:
! 467: // short i;
! 468: // for (i=0; i < NUMBER_CHARM_KINDS && i < 4; i++) {
! 469: // theItem = generateItem(CHARM, i);
! 470: // theItem = addItemToPack(theItem);
! 471: // }
! 472: }
! 473: blackOutScreen();
! 474: welcome();
! 475: }
! 476:
! 477: // call this once per level to set all the dynamic colors as a function of depth
! 478: void updateColors() {
! 479: short i;
! 480:
! 481: for (i=0; i<NUMBER_DYNAMIC_COLORS; i++) {
! 482: *(dynamicColors[i][0]) = *(dynamicColors[i][1]);
! 483: applyColorAverage(dynamicColors[i][0], dynamicColors[i][2], min(100, max(0, rogue.depthLevel * 100 / AMULET_LEVEL)));
! 484: }
! 485: }
! 486:
! 487: void startLevel(short oldLevelNumber, short stairDirection) {
! 488: unsigned long oldSeed;
! 489: item *theItem;
! 490: short loc[2], i, j, x, y, px, py, flying, dir;
! 491: boolean placedPlayer;
! 492: creature *monst;
! 493: enum dungeonLayers layer;
! 494: unsigned long timeAway;
! 495: short **mapToStairs;
! 496: short **mapToPit;
! 497: boolean connectingStairsDiscovered;
! 498:
! 499: if (oldLevelNumber == DEEPEST_LEVEL && stairDirection != -1) {
! 500: return;
! 501: }
! 502:
! 503: synchronizePlayerTimeState();
! 504:
! 505: rogue.updatedSafetyMapThisTurn = false;
! 506: rogue.updatedAllySafetyMapThisTurn = false;
! 507: rogue.updatedMapToSafeTerrainThisTurn = false;
! 508:
! 509: rogue.cursorLoc[0] = -1;
! 510: rogue.cursorLoc[1] = -1;
! 511: rogue.lastTarget = NULL;
! 512:
! 513: connectingStairsDiscovered = (pmap[rogue.downLoc[0]][rogue.downLoc[1]].flags & (DISCOVERED | MAGIC_MAPPED) ? true : false);
! 514: if (stairDirection == 0) { // fallen
! 515: levels[oldLevelNumber-1].playerExitedVia[0] = player.xLoc;
! 516: levels[oldLevelNumber-1].playerExitedVia[1] = player.yLoc;
! 517: }
! 518:
! 519: if (oldLevelNumber != rogue.depthLevel) {
! 520: px = player.xLoc;
! 521: py = player.yLoc;
! 522: if (cellHasTerrainFlag(player.xLoc, player.yLoc, T_AUTO_DESCENT)) {
! 523: for (i=0; i<8; i++) {
! 524: if (!cellHasTerrainFlag(player.xLoc+nbDirs[i][0], player.yLoc+nbDirs[i][1], (T_PATHING_BLOCKER))) {
! 525: px = player.xLoc+nbDirs[i][0];
! 526: py = player.yLoc+nbDirs[i][1];
! 527: break;
! 528: }
! 529: }
! 530: }
! 531: mapToStairs = allocGrid();
! 532: fillGrid(mapToStairs, 0);
! 533: for (flying = 0; flying <= 1; flying++) {
! 534: fillGrid(mapToStairs, 0);
! 535: calculateDistances(mapToStairs, px, py, (flying ? T_OBSTRUCTS_PASSABILITY : T_PATHING_BLOCKER) | T_SACRED, NULL, true, true);
! 536: for (monst = monsters->nextCreature; monst != NULL; monst = monst->nextCreature) {
! 537: x = monst->xLoc;
! 538: y = monst->yLoc;
! 539: if (((monst->creatureState == MONSTER_TRACKING_SCENT && (stairDirection != 0 || monst->status[STATUS_LEVITATING]))
! 540: || monst->creatureState == MONSTER_ALLY || monst == rogue.yendorWarden)
! 541: && (stairDirection != 0 || monst->currentHP > 10 || monst->status[STATUS_LEVITATING])
! 542: && ((flying != 0) == ((monst->status[STATUS_LEVITATING] != 0)
! 543: || cellHasTerrainFlag(x, y, T_PATHING_BLOCKER)
! 544: || cellHasTerrainFlag(px, py, T_AUTO_DESCENT)))
! 545: && !(monst->bookkeepingFlags & MB_CAPTIVE)
! 546: && !(monst->info.flags & (MONST_WILL_NOT_USE_STAIRS | MONST_RESTRICTED_TO_LIQUID))
! 547: && !(cellHasTerrainFlag(x, y, T_OBSTRUCTS_PASSABILITY))
! 548: && !monst->status[STATUS_ENTRANCED]
! 549: && !monst->status[STATUS_PARALYZED]
! 550: && (mapToStairs[monst->xLoc][monst->yLoc] < 30000 || monst->creatureState == MONSTER_ALLY || monst == rogue.yendorWarden)) {
! 551:
! 552: monst->status[STATUS_ENTERS_LEVEL_IN] = clamp(mapToStairs[monst->xLoc][monst->yLoc] * monst->movementSpeed / 100 + 1, 1, 150);
! 553: switch (stairDirection) {
! 554: case 1:
! 555: monst->bookkeepingFlags |= MB_APPROACHING_DOWNSTAIRS;
! 556: break;
! 557: case -1:
! 558: monst->bookkeepingFlags |= MB_APPROACHING_UPSTAIRS;
! 559: break;
! 560: case 0:
! 561: monst->bookkeepingFlags |= MB_APPROACHING_PIT;
! 562: break;
! 563: default:
! 564: break;
! 565: }
! 566: }
! 567: }
! 568: }
! 569: freeGrid(mapToStairs);
! 570: }
! 571:
! 572: for (monst = monsters->nextCreature; monst != NULL; monst = monst->nextCreature) {
! 573: if (monst->mapToMe) {
! 574: freeGrid(monst->mapToMe);
! 575: monst->mapToMe = NULL;
! 576: }
! 577: if (rogue.patchVersion < 3 && monst->safetyMap) {
! 578: freeGrid(monst->safetyMap);
! 579: monst->safetyMap = NULL;
! 580: }
! 581: }
! 582: levels[oldLevelNumber-1].monsters = monsters->nextCreature;
! 583: levels[oldLevelNumber-1].dormantMonsters = dormantMonsters->nextCreature;
! 584: levels[oldLevelNumber-1].items = floorItems->nextItem;
! 585:
! 586: for (i=0; i<DCOLS; i++) {
! 587: for (j=0; j<DROWS; j++) {
! 588: if (pmap[i][j].flags & (rogue.patchVersion >= 3 ? ANY_KIND_OF_VISIBLE : VISIBLE)) {
! 589: // Remember visible cells upon exiting.
! 590: storeMemories(i, j);
! 591: }
! 592: for (layer = 0; layer < NUMBER_TERRAIN_LAYERS; layer++) {
! 593: levels[oldLevelNumber - 1].mapStorage[i][j].layers[layer] = pmap[i][j].layers[layer];
! 594: }
! 595: levels[oldLevelNumber - 1].mapStorage[i][j].volume = pmap[i][j].volume;
! 596: levels[oldLevelNumber - 1].mapStorage[i][j].flags = (pmap[i][j].flags & (rogue.patchVersion < 3 ? (PERMANENT_TILE_FLAGS & ~HAS_MONSTER) : PERMANENT_TILE_FLAGS));
! 597: levels[oldLevelNumber - 1].mapStorage[i][j].machineNumber = pmap[i][j].machineNumber;
! 598: levels[oldLevelNumber - 1].mapStorage[i][j].rememberedAppearance = pmap[i][j].rememberedAppearance;
! 599: levels[oldLevelNumber - 1].mapStorage[i][j].rememberedItemCategory = pmap[i][j].rememberedItemCategory;
! 600: levels[oldLevelNumber - 1].mapStorage[i][j].rememberedItemKind = pmap[i][j].rememberedItemKind;
! 601: levels[oldLevelNumber - 1].mapStorage[i][j].rememberedItemQuantity = pmap[i][j].rememberedItemQuantity;
! 602: levels[oldLevelNumber - 1].mapStorage[i][j].rememberedItemOriginDepth = pmap[i][j].rememberedItemOriginDepth;
! 603: levels[oldLevelNumber - 1].mapStorage[i][j].rememberedTerrain = pmap[i][j].rememberedTerrain;
! 604: levels[oldLevelNumber - 1].mapStorage[i][j].rememberedCellFlags = pmap[i][j].rememberedCellFlags;
! 605: levels[oldLevelNumber - 1].mapStorage[i][j].rememberedTerrainFlags = pmap[i][j].rememberedTerrainFlags;
! 606: levels[oldLevelNumber - 1].mapStorage[i][j].rememberedTMFlags = pmap[i][j].rememberedTMFlags;
! 607: }
! 608: }
! 609:
! 610: levels[oldLevelNumber - 1].awaySince = rogue.absoluteTurnNumber;
! 611:
! 612: // Prepare the new level
! 613: rogue.minersLightRadius = (DCOLS - 1) * FP_FACTOR;
! 614: for (i = 0; i < rogue.depthLevel; i++) {
! 615: rogue.minersLightRadius = rogue.minersLightRadius * 85 / 100;
! 616: }
! 617: rogue.minersLightRadius += FP_FACTOR * 225 / 100;
! 618: updateColors();
! 619: updateRingBonuses(); // also updates miner's light
! 620:
! 621: if (!levels[rogue.depthLevel - 1].visited) { // level has not already been visited
! 622: levels[rogue.depthLevel - 1].scentMap = allocGrid();
! 623: scentMap = levels[rogue.depthLevel - 1].scentMap;
! 624: fillGrid(levels[rogue.depthLevel - 1].scentMap, 0);
! 625: // generate new level
! 626: oldSeed = (unsigned long) rand_range(0, 9999);
! 627: oldSeed += (unsigned long) 10000 * rand_range(0, 9999);
! 628: seedRandomGenerator(levels[rogue.depthLevel - 1].levelSeed);
! 629:
! 630: // Load up next level's monsters and items, since one might have fallen from above.
! 631: monsters->nextCreature = levels[rogue.depthLevel-1].monsters;
! 632: dormantMonsters->nextCreature = levels[rogue.depthLevel-1].dormantMonsters;
! 633: floorItems->nextItem = levels[rogue.depthLevel-1].items;
! 634:
! 635: levels[rogue.depthLevel-1].monsters = NULL;
! 636: levels[rogue.depthLevel-1].dormantMonsters = NULL;
! 637: levels[rogue.depthLevel-1].items = NULL;
! 638:
! 639: digDungeon();
! 640: initializeLevel();
! 641: setUpWaypoints();
! 642:
! 643: shuffleTerrainColors(100, false);
! 644:
! 645: // If we somehow failed to generate the amulet altar,
! 646: // just toss an amulet in there somewhere.
! 647: // It'll be fiiine!
! 648: if (rogue.depthLevel == AMULET_LEVEL
! 649: && !numberOfMatchingPackItems(AMULET, 0, 0, false)
! 650: && levels[rogue.depthLevel-1].visited == false) {
! 651:
! 652: for (theItem = floorItems->nextItem; theItem != NULL; theItem = theItem->nextItem) {
! 653: if (theItem->category & AMULET) {
! 654: break;
! 655: }
! 656: }
! 657: for (monst = monsters->nextCreature; monst != NULL; monst = monst->nextCreature) {
! 658: if (monst->carriedItem
! 659: && (monst->carriedItem->category & AMULET)) {
! 660:
! 661: theItem = monst->carriedItem;
! 662: break;
! 663: }
! 664: }
! 665: if (!theItem) {
! 666: placeItem(generateItem(AMULET, 0), 0, 0);
! 667: }
! 668: }
! 669: seedRandomGenerator(oldSeed);
! 670:
! 671: //logLevel();
! 672:
! 673: // Simulate 50 turns so the level is broken in (swamp gas accumulating, brimstone percolating, etc.).
! 674: timeAway = 50;
! 675:
! 676: } else { // level has already been visited
! 677:
! 678: // restore level
! 679: scentMap = levels[rogue.depthLevel - 1].scentMap;
! 680: timeAway = clamp(0, rogue.absoluteTurnNumber - levels[rogue.depthLevel - 1].awaySince, 30000);
! 681:
! 682: for (i=0; i<DCOLS; i++) {
! 683: for (j=0; j<DROWS; j++) {
! 684: for (layer = 0; layer < NUMBER_TERRAIN_LAYERS; layer++) {
! 685: pmap[i][j].layers[layer] = levels[rogue.depthLevel - 1].mapStorage[i][j].layers[layer];
! 686: }
! 687: pmap[i][j].volume = levels[rogue.depthLevel - 1].mapStorage[i][j].volume;
! 688: pmap[i][j].flags = (levels[rogue.depthLevel - 1].mapStorage[i][j].flags & (rogue.patchVersion < 3 ? (PERMANENT_TILE_FLAGS & ~HAS_MONSTER) : PERMANENT_TILE_FLAGS));
! 689: pmap[i][j].machineNumber = levels[rogue.depthLevel - 1].mapStorage[i][j].machineNumber;
! 690: pmap[i][j].rememberedAppearance = levels[rogue.depthLevel - 1].mapStorage[i][j].rememberedAppearance;
! 691: pmap[i][j].rememberedItemCategory = levels[rogue.depthLevel - 1].mapStorage[i][j].rememberedItemCategory;
! 692: pmap[i][j].rememberedItemKind = levels[rogue.depthLevel - 1].mapStorage[i][j].rememberedItemKind;
! 693: pmap[i][j].rememberedItemQuantity = levels[rogue.depthLevel - 1].mapStorage[i][j].rememberedItemQuantity;
! 694: pmap[i][j].rememberedItemOriginDepth = levels[rogue.depthLevel - 1].mapStorage[i][j].rememberedItemOriginDepth;
! 695: pmap[i][j].rememberedTerrain = levels[rogue.depthLevel - 1].mapStorage[i][j].rememberedTerrain;
! 696: pmap[i][j].rememberedCellFlags = levels[rogue.depthLevel - 1].mapStorage[i][j].rememberedCellFlags;
! 697: pmap[i][j].rememberedTerrainFlags = levels[rogue.depthLevel - 1].mapStorage[i][j].rememberedTerrainFlags;
! 698: pmap[i][j].rememberedTMFlags = levels[rogue.depthLevel - 1].mapStorage[i][j].rememberedTMFlags;
! 699: }
! 700: }
! 701:
! 702: setUpWaypoints();
! 703:
! 704: rogue.downLoc[0] = levels[rogue.depthLevel - 1].downStairsLoc[0];
! 705: rogue.downLoc[1] = levels[rogue.depthLevel - 1].downStairsLoc[1];
! 706: rogue.upLoc[0] = levels[rogue.depthLevel - 1].upStairsLoc[0];
! 707: rogue.upLoc[1] = levels[rogue.depthLevel - 1].upStairsLoc[1];
! 708:
! 709: monsters->nextCreature = levels[rogue.depthLevel - 1].monsters;
! 710: dormantMonsters->nextCreature = levels[rogue.depthLevel - 1].dormantMonsters;
! 711: floorItems->nextItem = levels[rogue.depthLevel - 1].items;
! 712:
! 713: levels[rogue.depthLevel-1].monsters = NULL;
! 714: levels[rogue.depthLevel-1].dormantMonsters = NULL;
! 715: levels[rogue.depthLevel-1].items = NULL;
! 716:
! 717: for (theItem = floorItems->nextItem; theItem != NULL; theItem = theItem->nextItem) {
! 718: restoreItem(theItem);
! 719: }
! 720:
! 721: if (rogue.patchVersion < 3) {
! 722: mapToStairs = allocGrid();
! 723: mapToPit = allocGrid();
! 724: fillGrid(mapToStairs, 0);
! 725: fillGrid(mapToPit, 0);
! 726: calculateDistances(mapToStairs, player.xLoc, player.yLoc, T_PATHING_BLOCKER, NULL, true, true);
! 727: calculateDistances(mapToPit, levels[rogue.depthLevel-1].playerExitedVia[0],
! 728: levels[rogue.depthLevel-1].playerExitedVia[0], T_PATHING_BLOCKER, NULL, true, true);
! 729: for (monst = monsters->nextCreature; monst != NULL; monst = monst->nextCreature) {
! 730: restoreMonster(monst, mapToStairs, mapToPit);
! 731: }
! 732: freeGrid(mapToStairs);
! 733: freeGrid(mapToPit);
! 734: }
! 735: }
! 736:
! 737: // Simulate the environment!
! 738: // First bury the player in limbo while we run the simulation,
! 739: // so that any harmful terrain doesn't affect her during the process.
! 740: px = player.xLoc;
! 741: py = player.yLoc;
! 742: player.xLoc = player.yLoc = 0;
! 743: for (i = 0; i < 100 && i < (short) timeAway; i++) {
! 744: updateEnvironment();
! 745: }
! 746: player.xLoc = px;
! 747: player.yLoc = py;
! 748:
! 749: if (!levels[rogue.depthLevel-1].visited) {
! 750: levels[rogue.depthLevel-1].visited = true;
! 751: if (rogue.depthLevel == AMULET_LEVEL) {
! 752: messageWithColor("An alien energy permeates the area. The Amulet of Yendor must be nearby!", &itemMessageColor, false);
! 753: } else if (rogue.depthLevel == DEEPEST_LEVEL) {
! 754: messageWithColor("An overwhelming sense of peace and tranquility settles upon you.", &lightBlue, false);
! 755: }
! 756: }
! 757:
! 758: // Position the player.
! 759: if (stairDirection == 0) { // fell into the level
! 760:
! 761: getQualifyingLocNear(loc, player.xLoc, player.yLoc, true, 0,
! 762: (T_PATHING_BLOCKER),
! 763: (HAS_MONSTER | HAS_ITEM | HAS_STAIRS | IS_IN_MACHINE), false, false);
! 764: } else {
! 765: if (stairDirection == 1) { // heading downward
! 766: player.xLoc = rogue.upLoc[0];
! 767: player.yLoc = rogue.upLoc[1];
! 768: } else if (stairDirection == -1) { // heading upward
! 769: player.xLoc = rogue.downLoc[0];
! 770: player.yLoc = rogue.downLoc[1];
! 771: }
! 772:
! 773: placedPlayer = false;
! 774: for (dir=0; dir<4 && !placedPlayer; dir++) {
! 775: loc[0] = player.xLoc + nbDirs[dir][0];
! 776: loc[1] = player.yLoc + nbDirs[dir][1];
! 777: if (!cellHasTerrainFlag(loc[0], loc[1], T_PATHING_BLOCKER)
! 778: && !(pmap[loc[0]][loc[1]].flags & (HAS_MONSTER | HAS_ITEM | HAS_STAIRS | IS_IN_MACHINE))) {
! 779: placedPlayer = true;
! 780: }
! 781: }
! 782: if (!placedPlayer) {
! 783: getQualifyingPathLocNear(&loc[0], &loc[1],
! 784: player.xLoc, player.yLoc,
! 785: true,
! 786: T_DIVIDES_LEVEL, 0,
! 787: T_PATHING_BLOCKER, (HAS_MONSTER | HAS_ITEM | HAS_STAIRS | IS_IN_MACHINE),
! 788: false);
! 789: }
! 790: }
! 791: player.xLoc = loc[0];
! 792: player.yLoc = loc[1];
! 793:
! 794: pmap[player.xLoc][player.yLoc].flags |= HAS_PLAYER;
! 795:
! 796: if (connectingStairsDiscovered) {
! 797: for (i = rogue.upLoc[0]-1; i <= rogue.upLoc[0] + 1; i++) {
! 798: for (j = rogue.upLoc[1]-1; j <= rogue.upLoc[1] + 1; j++) {
! 799: if (coordinatesAreInMap(i, j)) {
! 800: discoverCell(i, j);
! 801: }
! 802: }
! 803: }
! 804: }
! 805: if (cellHasTerrainFlag(player.xLoc, player.yLoc, T_IS_DEEP_WATER) && !player.status[STATUS_LEVITATING]
! 806: && !cellHasTerrainFlag(player.xLoc, player.yLoc, (T_ENTANGLES | T_OBSTRUCTS_PASSABILITY))) {
! 807: rogue.inWater = true;
! 808: }
! 809:
! 810: if (levels[rogue.depthLevel - 1].visited && rogue.patchVersion >= 3) {
! 811: mapToStairs = allocGrid();
! 812: mapToPit = allocGrid();
! 813: fillGrid(mapToStairs, 0);
! 814: fillGrid(mapToPit, 0);
! 815: calculateDistances(mapToStairs, player.xLoc, player.yLoc, T_PATHING_BLOCKER, NULL, true, true);
! 816: calculateDistances(mapToPit, levels[rogue.depthLevel-1].playerExitedVia[0],
! 817: levels[rogue.depthLevel-1].playerExitedVia[1], T_PATHING_BLOCKER, NULL, true, true);
! 818: for (monst = monsters->nextCreature; monst != NULL; monst = monst->nextCreature) {
! 819: restoreMonster(monst, mapToStairs, mapToPit);
! 820: }
! 821: freeGrid(mapToStairs);
! 822: freeGrid(mapToPit);
! 823: }
! 824:
! 825: updateMapToShore();
! 826: updateVision(true);
! 827: rogue.aggroRange = currentAggroValue();
! 828:
! 829: // update monster states so none are hunting if there is no scent and they can't see the player
! 830: for (monst = monsters->nextCreature; monst != NULL; monst = monst->nextCreature) {
! 831: updateMonsterState(monst);
! 832: }
! 833:
! 834: rogue.playbackBetweenTurns = true;
! 835: displayLevel();
! 836: refreshSideBar(-1, -1, false);
! 837:
! 838: if (rogue.playerTurnNumber) {
! 839: rogue.playerTurnNumber++; // Increment even though no time has passed.
! 840: }
! 841: RNGCheck();
! 842: flushBufferToFile();
! 843: deleteAllFlares(); // So discovering something on the same turn that you fall down a level doesn't flash stuff on the previous level.
! 844: hideCursor();
! 845: }
! 846:
! 847: void freeGlobalDynamicGrid(short ***grid) {
! 848: if (*grid) {
! 849: freeGrid(*grid);
! 850: *grid = NULL;
! 851: }
! 852: }
! 853:
! 854: void freeCreature(creature *monst) {
! 855: freeGlobalDynamicGrid(&(monst->mapToMe));
! 856: freeGlobalDynamicGrid(&(monst->safetyMap));
! 857: if (monst->carriedItem) {
! 858: free(monst->carriedItem);
! 859: monst->carriedItem = NULL;
! 860: }
! 861: if (monst->carriedMonster) {
! 862: freeCreature(monst->carriedMonster);
! 863: monst->carriedMonster = NULL;
! 864: }
! 865: free(monst);
! 866: }
! 867:
! 868: void emptyGraveyard() {
! 869: creature *monst, *monst2;
! 870: for (monst = graveyard->nextCreature; monst != NULL; monst = monst2) {
! 871: monst2 = monst->nextCreature;
! 872: freeCreature(monst);
! 873: }
! 874: graveyard->nextCreature = NULL;
! 875: }
! 876:
! 877: void freeEverything() {
! 878: short i;
! 879: creature *monst, *monst2;
! 880: item *theItem, *theItem2;
! 881:
! 882: #ifdef AUDIT_RNG
! 883: fclose(RNGLogFile);
! 884: #endif
! 885:
! 886: freeGlobalDynamicGrid(&safetyMap);
! 887: freeGlobalDynamicGrid(&allySafetyMap);
! 888: freeGlobalDynamicGrid(&chokeMap);
! 889: freeGlobalDynamicGrid(&rogue.mapToShore);
! 890: freeGlobalDynamicGrid(&rogue.mapToSafeTerrain);
! 891:
! 892: for (i=0; i<DEEPEST_LEVEL+1; i++) {
! 893: for (monst = levels[i].monsters; monst != NULL; monst = monst2) {
! 894: monst2 = monst->nextCreature;
! 895: freeCreature(monst);
! 896: }
! 897: levels[i].monsters = NULL;
! 898: for (monst = levels[i].dormantMonsters; monst != NULL; monst = monst2) {
! 899: monst2 = monst->nextCreature;
! 900: freeCreature(monst);
! 901: }
! 902: levels[i].dormantMonsters = NULL;
! 903: for (theItem = levels[i].items; theItem != NULL; theItem = theItem2) {
! 904: theItem2 = theItem->nextItem;
! 905: deleteItem(theItem);
! 906: }
! 907: levels[i].items = NULL;
! 908: if (levels[i].scentMap) {
! 909: freeGrid(levels[i].scentMap);
! 910: levels[i].scentMap = NULL;
! 911: }
! 912: }
! 913: scentMap = NULL;
! 914: for (monst = monsters; monst != NULL; monst = monst2) {
! 915: monst2 = monst->nextCreature;
! 916: freeCreature(monst);
! 917: }
! 918: monsters = NULL;
! 919: for (monst = dormantMonsters; monst != NULL; monst = monst2) {
! 920: monst2 = monst->nextCreature;
! 921: freeCreature(monst);
! 922: }
! 923: dormantMonsters = NULL;
! 924: for (monst = graveyard; monst != NULL; monst = monst2) {
! 925: monst2 = monst->nextCreature;
! 926: freeCreature(monst);
! 927: }
! 928: graveyard = NULL;
! 929: for (monst = purgatory; monst != NULL; monst = monst2) {
! 930: monst2 = monst->nextCreature;
! 931: freeCreature(monst);
! 932: }
! 933: purgatory = NULL;
! 934: for (theItem = floorItems; theItem != NULL; theItem = theItem2) {
! 935: theItem2 = theItem->nextItem;
! 936: deleteItem(theItem);
! 937: }
! 938: floorItems = NULL;
! 939: for (theItem = packItems; theItem != NULL; theItem = theItem2) {
! 940: theItem2 = theItem->nextItem;
! 941: deleteItem(theItem);
! 942: }
! 943: packItems = NULL;
! 944: for (theItem = monsterItemsHopper; theItem != NULL; theItem = theItem2) {
! 945: theItem2 = theItem->nextItem;
! 946: deleteItem(theItem);
! 947: }
! 948: monsterItemsHopper = NULL;
! 949: for (i=0; i<MAX_WAYPOINT_COUNT; i++) {
! 950: freeGrid(rogue.wpDistance[i]);
! 951: }
! 952:
! 953: deleteAllFlares();
! 954: if (rogue.flares) {
! 955: free(rogue.flares);
! 956: rogue.flares = NULL;
! 957: }
! 958:
! 959: free(levels);
! 960: levels = NULL;
! 961: }
! 962:
! 963: void gameOver(char *killedBy, boolean useCustomPhrasing) {
! 964: short i, y;
! 965: char buf[200], highScoreText[200], buf2[200];
! 966: rogueHighScoresEntry theEntry;
! 967: cellDisplayBuffer dbuf[COLS][ROWS];
! 968: boolean playback;
! 969: rogueEvent theEvent;
! 970: item *theItem;
! 971: char recordingFilename[BROGUE_FILENAME_MAX] = {0};
! 972:
! 973: if (player.bookkeepingFlags & MB_IS_DYING) {
! 974: // we've already been through this once; let's avoid overkill.
! 975: return;
! 976: }
! 977:
! 978: player.bookkeepingFlags |= MB_IS_DYING;
! 979: rogue.autoPlayingLevel = false;
! 980: rogue.gameInProgress = false;
! 981: flushBufferToFile();
! 982:
! 983: if (rogue.quit) {
! 984: if (rogue.playbackMode) {
! 985: playback = rogue.playbackMode;
! 986: rogue.playbackMode = false;
! 987: message("(The player quit at this point.)", true);
! 988: rogue.playbackMode = playback;
! 989: }
! 990: } else {
! 991: playback = rogue.playbackMode;
! 992: if (!D_IMMORTAL) {
! 993: rogue.playbackMode = false;
! 994: }
! 995: strcpy(buf, "You die...");
! 996: if (KEYBOARD_LABELS) {
! 997: encodeMessageColor(buf, strlen(buf), &gray);
! 998: strcat(buf, " (press 'i' to view your inventory)");
! 999: }
! 1000: player.currentHP = 0; // So it shows up empty in the side bar.
! 1001: refreshSideBar(-1, -1, false);
! 1002: messageWithColor(buf, &badMessageColor, false);
! 1003: displayMoreSignWithoutWaitingForAcknowledgment();
! 1004:
! 1005: do {
! 1006: if (rogue.playbackMode) break;
! 1007: nextBrogueEvent(&theEvent, false, false, false);
! 1008: if (theEvent.eventType == KEYSTROKE
! 1009: && theEvent.param1 != ACKNOWLEDGE_KEY
! 1010: && theEvent.param1 != ESCAPE_KEY
! 1011: && theEvent.param1 != INVENTORY_KEY) {
! 1012:
! 1013: flashTemporaryAlert(" -- Press space or click to continue, or press 'i' to view inventory -- ", 1500);
! 1014: } else if (theEvent.eventType == KEYSTROKE && theEvent.param1 == INVENTORY_KEY) {
! 1015: for (theItem = packItems->nextItem; theItem != NULL; theItem = theItem->nextItem) {
! 1016: identify(theItem);
! 1017: theItem->flags &= ~ITEM_MAGIC_DETECTED;
! 1018: }
! 1019: displayInventory(ALL_ITEMS, 0, 0, true, false);
! 1020: }
! 1021: } while (!(theEvent.eventType == KEYSTROKE && (theEvent.param1 == ACKNOWLEDGE_KEY || theEvent.param1 == ESCAPE_KEY)
! 1022: || theEvent.eventType == MOUSE_UP));
! 1023:
! 1024: confirmMessages();
! 1025:
! 1026: rogue.playbackMode = playback;
! 1027: }
! 1028:
! 1029: rogue.creaturesWillFlashThisTurn = false;
! 1030:
! 1031: if (D_IMMORTAL && !rogue.quit) {
! 1032: message("...but then you get better.", false);
! 1033: player.currentHP = player.info.maxHP;
! 1034: if (player.status[STATUS_NUTRITION] < 10) {
! 1035: player.status[STATUS_NUTRITION] = STOMACH_SIZE;
! 1036: }
! 1037: player.bookkeepingFlags &= ~MB_IS_DYING;
! 1038: rogue.gameInProgress = true;
! 1039: return;
! 1040: }
! 1041:
! 1042: if (rogue.highScoreSaved) {
! 1043: return;
! 1044: }
! 1045: rogue.highScoreSaved = true;
! 1046:
! 1047: if (rogue.quit) {
! 1048: blackOutScreen();
! 1049: } else {
! 1050: copyDisplayBuffer(dbuf, displayBuffer);
! 1051: funkyFade(dbuf, &black, 0, 120, mapToWindowX(player.xLoc), mapToWindowY(player.yLoc), false);
! 1052: }
! 1053:
! 1054: if (useCustomPhrasing) {
! 1055: sprintf(buf, "%s on depth %i", killedBy, rogue.depthLevel);
! 1056: } else {
! 1057: sprintf(buf, "Killed by a%s %s on depth %i", (isVowelish(killedBy) ? "n" : ""), killedBy,
! 1058: rogue.depthLevel);
! 1059: }
! 1060: theEntry.score = rogue.gold;
! 1061: if (rogue.easyMode) {
! 1062: theEntry.score /= 10;
! 1063: }
! 1064: strcpy(highScoreText, buf);
! 1065: if (theEntry.score > 0) {
! 1066: sprintf(buf2, " with %li gold", theEntry.score);
! 1067: strcat(buf, buf2);
! 1068: }
! 1069: if (numberOfMatchingPackItems(AMULET, 0, 0, false) > 0) {
! 1070: strcat(buf, ", amulet in hand");
! 1071: }
! 1072: strcat(buf, ".");
! 1073: strcat(highScoreText, ".");
! 1074:
! 1075: strcpy(theEntry.description, highScoreText);
! 1076:
! 1077: if (!rogue.quit) {
! 1078: printString(buf, (COLS - strLenWithoutEscapes(buf)) / 2, ROWS / 2, &gray, &black, 0);
! 1079:
! 1080: y = ROWS / 2 + 3;
! 1081: for (i = 0; i < FEAT_COUNT; i++) {
! 1082: //printf("\nConduct %i (%s) is %s.", i, featTable[i].name, rogue.featRecord[i] ? "true" : "false");
! 1083: if (rogue.featRecord[i]
! 1084: && !featTable[i].initialValue) {
! 1085:
! 1086: sprintf(buf, "%s: %s", featTable[i].name, featTable[i].description);
! 1087: printString(buf, (COLS - strLenWithoutEscapes(buf)) / 2, y, &advancementMessageColor, &black, 0);
! 1088: y++;
! 1089: }
! 1090: }
! 1091:
! 1092: displayMoreSign();
! 1093: }
! 1094:
! 1095: if (serverMode) {
! 1096: blackOutScreen();
! 1097: saveRecordingNoPrompt(recordingFilename);
! 1098: } else {
! 1099: if (!rogue.playbackMode && saveHighScore(theEntry)) {
! 1100: printHighScores(true);
! 1101: }
! 1102: blackOutScreen();
! 1103: saveRecording(recordingFilename);
! 1104: }
! 1105:
! 1106: if (!rogue.playbackMode) {
! 1107: if (!rogue.quit) {
! 1108: notifyEvent(GAMEOVER_DEATH, theEntry.score, 0, theEntry.description, recordingFilename);
! 1109: } else {
! 1110: notifyEvent(GAMEOVER_QUIT, theEntry.score, 0, theEntry.description, recordingFilename);
! 1111: }
! 1112: } else {
! 1113: notifyEvent(GAMEOVER_RECORDING, 0, 0, "recording ended", "none");
! 1114: }
! 1115:
! 1116: rogue.gameHasEnded = true;
! 1117: }
! 1118:
! 1119: void victory(boolean superVictory) {
! 1120: char buf[COLS*3], victoryVerb[20];
! 1121: item *theItem;
! 1122: short i, j, gemCount = 0;
! 1123: unsigned long totalValue = 0;
! 1124: rogueHighScoresEntry theEntry;
! 1125: boolean qualified, isPlayback;
! 1126: cellDisplayBuffer dbuf[COLS][ROWS];
! 1127: char recordingFilename[BROGUE_FILENAME_MAX] = {0};
! 1128:
! 1129: rogue.gameInProgress = false;
! 1130: flushBufferToFile();
! 1131:
! 1132: //
! 1133: // First screen - Congratulations...
! 1134: //
! 1135: deleteMessages();
! 1136: if (superVictory) {
! 1137: message( "Light streams through the portal, and you are teleported out of the dungeon.", false);
! 1138: copyDisplayBuffer(dbuf, displayBuffer);
! 1139: funkyFade(dbuf, &superVictoryColor, 0, 240, mapToWindowX(player.xLoc), mapToWindowY(player.yLoc), false);
! 1140: displayMoreSign();
! 1141: printString("Congratulations; you have transcended the Dungeons of Doom! ", mapToWindowX(0), mapToWindowY(-1), &black, &white, 0);
! 1142: displayMoreSign();
! 1143: clearDisplayBuffer(dbuf);
! 1144: deleteMessages();
! 1145: strcpy(displayedMessage[0], "You retire in splendor, forever renowned for your remarkable triumph. ");
! 1146: } else {
! 1147: message( "You are bathed in sunlight as you throw open the heavy doors.", false);
! 1148: copyDisplayBuffer(dbuf, displayBuffer);
! 1149: funkyFade(dbuf, &white, 0, 240, mapToWindowX(player.xLoc), mapToWindowY(player.yLoc), false);
! 1150: displayMoreSign();
! 1151: printString("Congratulations; you have escaped from the Dungeons of Doom! ", mapToWindowX(0), mapToWindowY(-1), &black, &white, 0);
! 1152: displayMoreSign();
! 1153: clearDisplayBuffer(dbuf);
! 1154: deleteMessages();
! 1155: strcpy(displayedMessage[0], "You sell your treasures and live out your days in fame and glory.");
! 1156: }
! 1157:
! 1158: //
! 1159: // Second screen - Show inventory and item's value
! 1160: //
! 1161: printString(displayedMessage[0], mapToWindowX(0), mapToWindowY(-1), &white, &black, dbuf);
! 1162:
! 1163: plotCharToBuffer(G_GOLD, mapToWindowX(2), mapToWindowY(1), &yellow, &black, dbuf);
! 1164: printString("Gold", mapToWindowX(4), mapToWindowY(1), &white, &black, dbuf);
! 1165: sprintf(buf, "%li", rogue.gold);
! 1166: printString(buf, mapToWindowX(60), mapToWindowY(1), &itemMessageColor, &black, dbuf);
! 1167: totalValue += rogue.gold;
! 1168:
! 1169: for (i = 4, theItem = packItems->nextItem; theItem != NULL; theItem = theItem->nextItem) {
! 1170: if (theItem->category & GEM) {
! 1171: gemCount += theItem->quantity;
! 1172: }
! 1173: if (theItem->category == AMULET && superVictory) {
! 1174: plotCharToBuffer(G_AMULET, mapToWindowX(2), min(ROWS-1, i + 1), &yellow, &black, dbuf);
! 1175: printString("The Birthright of Yendor", mapToWindowX(4), min(ROWS-1, i + 1), &itemMessageColor, &black, dbuf);
! 1176: sprintf(buf, "%li", max(0, itemValue(theItem) * 2));
! 1177: printString(buf, mapToWindowX(60), min(ROWS-1, i + 1), &itemMessageColor, &black, dbuf);
! 1178: totalValue += max(0, itemValue(theItem) * 2);
! 1179: i++;
! 1180: } else {
! 1181: identify(theItem);
! 1182: itemName(theItem, buf, true, true, &white);
! 1183: upperCase(buf);
! 1184:
! 1185: plotCharToBuffer(theItem->displayChar, mapToWindowX(2), min(ROWS-1, i + 1), &yellow, &black, dbuf);
! 1186: printString(buf, mapToWindowX(4), min(ROWS-1, i + 1), &white, &black, dbuf);
! 1187:
! 1188: if (itemValue(theItem) > 0) {
! 1189: sprintf(buf, "%li", max(0, itemValue(theItem)));
! 1190: printString(buf, mapToWindowX(60), min(ROWS-1, i + 1), &itemMessageColor, &black, dbuf);
! 1191: }
! 1192:
! 1193: totalValue += max(0, itemValue(theItem));
! 1194: i++;
! 1195: }
! 1196: }
! 1197: i++;
! 1198: printString("TOTAL:", mapToWindowX(2), min(ROWS-1, i + 1), &lightBlue, &black, dbuf);
! 1199: sprintf(buf, "%li", totalValue);
! 1200: printString(buf, mapToWindowX(60), min(ROWS-1, i + 1), &lightBlue, &black, dbuf);
! 1201:
! 1202: funkyFade(dbuf, &white, 0, 120, COLS/2, ROWS/2, true);
! 1203: displayMoreSign();
! 1204:
! 1205: //
! 1206: // Third screen - List of achievements with recording save prompt
! 1207: //
! 1208: blackOutScreen();
! 1209:
! 1210: i = 4;
! 1211: printString("Achievements", mapToWindowX(2), i++, &lightBlue, &black, NULL);
! 1212:
! 1213: i++;
! 1214: for (j = 0; i < ROWS && j < FEAT_COUNT; j++) {
! 1215: if (rogue.featRecord[j]) {
! 1216: sprintf(buf, "%s: %s", featTable[j].name, featTable[j].description);
! 1217: printString(buf, mapToWindowX(2), i, &advancementMessageColor, &black, NULL);
! 1218: i++;
! 1219: }
! 1220: }
! 1221:
! 1222: strcpy(victoryVerb, superVictory ? "Mastered" : "Escaped");
! 1223: if (gemCount == 0) {
! 1224: sprintf(theEntry.description, "%s the Dungeons of Doom!", victoryVerb);
! 1225: } else if (gemCount == 1) {
! 1226: sprintf(theEntry.description, "%s the Dungeons of Doom with a lumenstone!", victoryVerb);
! 1227: } else {
! 1228: sprintf(theEntry.description, "%s the Dungeons of Doom with %i lumenstones!", victoryVerb, gemCount);
! 1229: }
! 1230:
! 1231: theEntry.score = totalValue;
! 1232:
! 1233: if (rogue.easyMode) {
! 1234: theEntry.score /= 10;
! 1235: }
! 1236:
! 1237: if (!rogue.wizard && !rogue.playbackMode) {
! 1238: qualified = saveHighScore(theEntry);
! 1239: } else {
! 1240: qualified = false;
! 1241: }
! 1242:
! 1243: isPlayback = rogue.playbackMode;
! 1244: rogue.playbackMode = false;
! 1245: rogue.playbackMode = isPlayback;
! 1246:
! 1247: if (serverMode) {
! 1248: // There's no save recording prompt, so let the player see achievements.
! 1249: displayMoreSign();
! 1250: saveRecordingNoPrompt(recordingFilename);
! 1251: } else {
! 1252: saveRecording(recordingFilename);
! 1253: printHighScores(qualified);
! 1254: }
! 1255:
! 1256: if (!rogue.playbackMode) {
! 1257: if (superVictory) {
! 1258: notifyEvent(GAMEOVER_SUPERVICTORY, theEntry.score, 0, theEntry.description, recordingFilename);
! 1259: } else {
! 1260: notifyEvent(GAMEOVER_VICTORY, theEntry.score, 0, theEntry.description, recordingFilename);
! 1261: }
! 1262: } else {
! 1263: notifyEvent(GAMEOVER_RECORDING, 0, 0, "recording ended", "none");
! 1264: }
! 1265:
! 1266: rogue.gameHasEnded = true;
! 1267: }
! 1268:
! 1269: void enableEasyMode() {
! 1270: if (rogue.easyMode) {
! 1271: message("Alas, all hope of salvation is lost. You shed scalding tears at your plight.", false);
! 1272: return;
! 1273: }
! 1274: message("A dark presence surrounds you, whispering promises of stolen power.", true);
! 1275: if (confirm("Succumb to demonic temptation (i.e. enable Easy Mode)?", false)) {
! 1276: recordKeystroke(EASY_MODE_KEY, false, true);
! 1277: message("An ancient and terrible evil burrows into your willing flesh!", true);
! 1278: player.info.displayChar = '&';
! 1279: rogue.easyMode = true;
! 1280: refreshDungeonCell(player.xLoc, player.yLoc);
! 1281: refreshSideBar(-1, -1, false);
! 1282: message("Wracked by spasms, your body contorts into an ALL-POWERFUL AMPERSAND!!!", false);
! 1283: message("You have a feeling that you will take 20% as much damage from now on.", false);
! 1284: message("But great power comes at a great price -- specifically, a 90% income tax rate.", false);
! 1285: } else {
! 1286: message("The evil dissipates, hissing, from the air around you.", false);
! 1287: }
! 1288: }
! 1289:
! 1290: // takes a flag of the form Fl(n) and returns n
! 1291: short unflag(unsigned long flag) {
! 1292: short i;
! 1293: for (i=0; i<32; i++) {
! 1294: if (flag >> i == 1) {
! 1295: return i;
! 1296: }
! 1297: }
! 1298: return -1;
! 1299: }
CVSweb