[BACK]Return to RogueMain.c CVS log [TXT][DIR] Up to [contributed] / brogue-ce / src / brogue

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