Annotation of brogue-ce/src/brogue/SeedCatalog.c, Revision 1.1
1.1 ! rubenllo 1: /*
! 2: * SeedCatalog.c
! 3: * Brogue
! 4: *
! 5: * Copyright 2012. All rights reserved.
! 6: *
! 7: * This file is part of Brogue.
! 8: *
! 9: * This program is free software: you can redistribute it and/or modify
! 10: * it under the terms of the GNU Affero General Public License as
! 11: * published by the Free Software Foundation, either version 3 of the
! 12: * License, or (at your option) any later version.
! 13: *
! 14: * This program is distributed in the hope that it will be useful,
! 15: * but WITHOUT ANY WARRANTY; without even the implied warranty of
! 16: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 17: * GNU Affero General Public License for more details.
! 18: *
! 19: * You should have received a copy of the GNU Affero General Public License
! 20: * along with this program. If not, see <http://www.gnu.org/licenses/>.
! 21: */
! 22:
! 23: #include "Rogue.h"
! 24: #include "IncludeGlobals.h"
! 25:
! 26: #define CSV_HEADER_STRING "dungeon_version,seed,depth,quantity,category,kind,enchantment,runic,vault_number,opens_vault_number,carried_by_monster_name,ally_status_name,mutation_name"
! 27: #define NO_ENCHANTMENT_STRING ""
! 28: #define NO_RUNIC_STRING ""
! 29: #define NO_VAULT_STRING ""
! 30: #define NO_OPENS_VAULT_STRING ""
! 31: #define NO_CARRIED_BY_MONSTER_STRING ""
! 32: #define NO_ALLY_STATUS_STRING ""
! 33: #define NO_MUTATION_STRING ""
! 34:
! 35: static void printSeedCatalogCsvLine(unsigned long seed, short depth, short quantity, char categoryName[50], char kindName[50],
! 36: char enchantment[50], char runicName[50], char vaultNumber[10], char opensVaultNumber[10],
! 37: char carriedByMonsterName[50], char allyStatusName[20], char mutationName[100]){
! 38:
! 39: printf("%s,%lu,%i,%i,%s,%s,%s,%s,%s,%s,%s,%s,%s\n", BROGUE_DUNGEON_VERSION_STRING, seed, depth, quantity, categoryName,
! 40: kindName, enchantment, runicName, vaultNumber, opensVaultNumber, carriedByMonsterName, allyStatusName,
! 41: mutationName);
! 42: }
! 43:
! 44: static void getMonsterDetailedName(creature *theMonster, char *theMonsterName) {
! 45: if (theMonster->mutationIndex >= 0) {
! 46: sprintf(theMonsterName, "%s [%s]", theMonster->info.monsterName, mutationCatalog[theMonster->mutationIndex].title);
! 47: } else {
! 48: strcpy(theMonsterName, theMonster->info.monsterName);
! 49: }
! 50: }
! 51:
! 52: static void printSeedCatalogItem(item *theItem, creature *theMonster, boolean isCsvFormat) {
! 53: char inGameItemName[500] = "", carriedByMonsterName[100] = "", vaultNumber[36] = "", opensVaultNumber[36] = "";
! 54: char categoryName[20] = "", kindName[50] = "", enchantment[5] = "", runicName[30] = "", mutationName[100] = "";
! 55:
! 56: if (isCsvFormat) { //for csv output we need the item name components: category, kind, enchantment, & runic
! 57: strcpy(categoryName, itemCategoryNames[unflag(theItem->category)]);
! 58: itemKindName(theItem, kindName);
! 59: itemRunicName(theItem, runicName);
! 60: if (theItem->category & (ARMOR | CHARM | RING | STAFF | WAND | WEAPON)) { //enchantable items
! 61: if (theItem->category == WAND) {
! 62: sprintf(enchantment, "%i", theItem->charges);
! 63: } else {
! 64: sprintf(enchantment, "%i", theItem->enchant1);
! 65: }
! 66: }
! 67: } else {
! 68: itemName(theItem, inGameItemName, true, true, NULL); //for standard output, use the in-game item name as base
! 69: }
! 70:
! 71: if (theMonster != NULL) { //carried by monster
! 72: if (isCsvFormat) {
! 73: sprintf(carriedByMonsterName, theMonster->info.monsterName);
! 74: strcpy(mutationName, theMonster->mutationIndex >= 0 ? mutationCatalog[theMonster->mutationIndex].title : "");
! 75: } else {
! 76: getMonsterDetailedName(theMonster, carriedByMonsterName);
! 77: }
! 78: }
! 79:
! 80: // vaultNumber
! 81: if (pmap[theItem->xLoc][theItem->yLoc].machineNumber > 0) {
! 82: //not all machines are "vaults" so we need to exclude some.
! 83: if (pmap[theItem->xLoc][theItem->yLoc].layers[0] != ALTAR_SWITCH
! 84: && pmap[theItem->xLoc][theItem->yLoc].layers[0] != ALTAR_SWITCH_RETRACTING
! 85: && pmap[theItem->xLoc][theItem->yLoc].layers[0] != ALTAR_CAGE_RETRACTABLE
! 86: && pmap[theItem->xLoc][theItem->yLoc].layers[0] != ALTAR_INERT
! 87: && pmap[theItem->xLoc][theItem->yLoc].layers[0] != AMULET_SWITCH
! 88: && pmap[theItem->xLoc][theItem->yLoc].layers[0] != FLOOR) {
! 89:
! 90: sprintf(vaultNumber, isCsvFormat ? "%i" : " (vault %i)", pmap[theItem->xLoc][theItem->yLoc].machineNumber);
! 91: }
! 92: }
! 93:
! 94: // opensVaultNumber
! 95: if (theItem->category == KEY && theItem->kind == KEY_DOOR) {
! 96: sprintf(opensVaultNumber, isCsvFormat ? "%i" : " (opens vault %i)",
! 97: pmap[theItem->keyLoc[0].x][theItem->keyLoc[0].y].machineNumber - 1);
! 98: }
! 99:
! 100: if (isCsvFormat) {
! 101: printSeedCatalogCsvLine(rogue.seed, rogue.depthLevel, theItem->quantity, categoryName, kindName, enchantment,
! 102: runicName, vaultNumber, opensVaultNumber, carriedByMonsterName, NO_ALLY_STATUS_STRING,
! 103: mutationName);
! 104: } else {
! 105: upperCase(inGameItemName);
! 106: if (theMonster != NULL) {
! 107: printf(" %s (%s)%s%s\n", inGameItemName, carriedByMonsterName, vaultNumber, opensVaultNumber);
! 108: } else {
! 109: printf(" %s%s%s\n", inGameItemName, vaultNumber, opensVaultNumber);
! 110: }
! 111: }
! 112: }
! 113:
! 114: static void printSeedCatalogMonster(creature *theMonster, boolean isCsvFormat) {
! 115: char categoryName[10] = "", allyStatusName[20] = "", mutationName[100] = "", theMonsterName[100] = "";
! 116:
! 117: strcpy(mutationName, theMonster->mutationIndex >= 0 ? mutationCatalog[theMonster->mutationIndex].title : "");
! 118:
! 119: if (theMonster->bookkeepingFlags & MB_CAPTIVE) {
! 120: strcpy(categoryName,"ally");
! 121: if (cellHasTMFlag(theMonster->xLoc, theMonster->yLoc, TM_PROMOTES_WITH_KEY)) {
! 122: strcpy(allyStatusName, isCsvFormat ? "caged" : "A caged ");
! 123: } else {
! 124: strcpy(allyStatusName, isCsvFormat ? "shackled" : "A shackled ");
! 125: }
! 126: } else if (theMonster->creatureState == MONSTER_ALLY) {
! 127: strcpy(categoryName,"ally");
! 128: strcpy(allyStatusName, isCsvFormat ? "allied" : "An allied ");
! 129: } else {
! 130: strcpy(categoryName,"monster");
! 131: }
! 132:
! 133: if (isCsvFormat) {
! 134: printSeedCatalogCsvLine(rogue.seed, rogue.depthLevel, 1, categoryName, theMonster->info.monsterName,
! 135: NO_ENCHANTMENT_STRING, NO_RUNIC_STRING, NO_VAULT_STRING, NO_OPENS_VAULT_STRING,
! 136: NO_CARRIED_BY_MONSTER_STRING, allyStatusName, mutationName);
! 137: } else {
! 138: getMonsterDetailedName(theMonster, theMonsterName);
! 139: printf(" %s%s\n", allyStatusName, theMonsterName);
! 140: }
! 141: }
! 142:
! 143: static void printSeedCatalogMonsters(boolean isCsvFormat, boolean includeAll) {
! 144: creature *theMonster;
! 145:
! 146: for (theMonster = monsters->nextCreature; theMonster != NULL; theMonster = theMonster->nextCreature) {
! 147: if (theMonster->bookkeepingFlags & MB_CAPTIVE || theMonster->creatureState == MONSTER_ALLY || includeAll) {
! 148: printSeedCatalogMonster(theMonster, isCsvFormat);
! 149: }
! 150: }
! 151:
! 152: for (theMonster = dormantMonsters->nextCreature; theMonster != NULL; theMonster = theMonster->nextCreature) {
! 153: if (theMonster->bookkeepingFlags & MB_CAPTIVE || theMonster->creatureState == MONSTER_ALLY || includeAll) {
! 154: printSeedCatalogMonster(theMonster, isCsvFormat);
! 155: }
! 156: }
! 157: }
! 158:
! 159: static void printSeedCatalogMonsterItems(boolean isCsvFormat) {
! 160: creature *theMonster;
! 161:
! 162: for (theMonster = monsters->nextCreature; theMonster != NULL; theMonster = theMonster->nextCreature) {
! 163: if (theMonster->carriedItem != NULL && theMonster->carriedItem->category != GOLD) {
! 164: printSeedCatalogItem(theMonster->carriedItem, theMonster, isCsvFormat);
! 165: }
! 166: }
! 167:
! 168: for (theMonster = dormantMonsters->nextCreature; theMonster != NULL; theMonster = theMonster->nextCreature) {
! 169: if (theMonster->carriedItem != NULL && theMonster->carriedItem->category != GOLD) {
! 170: printSeedCatalogItem(theMonster->carriedItem, theMonster, isCsvFormat);
! 171: }
! 172: }
! 173: }
! 174:
! 175: static void printSeedCatalogFloorGold(int gold, short piles, boolean isCsvFormat) {
! 176: char kindName[50] = "";
! 177:
! 178: if (isCsvFormat) {
! 179: if (piles == 1) {
! 180: strcpy(kindName, "gold pieces");
! 181: } else if (piles > 1) {
! 182: sprintf(kindName, "gold pieces (%i piles)", piles);
! 183: }
! 184: printSeedCatalogCsvLine(rogue.seed, rogue.depthLevel, gold, "gold", kindName, NO_ENCHANTMENT_STRING,
! 185: NO_RUNIC_STRING, NO_VAULT_STRING, NO_OPENS_VAULT_STRING, NO_CARRIED_BY_MONSTER_STRING,
! 186: NO_ALLY_STATUS_STRING, NO_MUTATION_STRING);
! 187: } else {
! 188: if (piles == 1) {
! 189: printf(" %i gold pieces\n", gold);
! 190: } else if (piles > 1) {
! 191: printf(" %i gold pieces (%i piles)\n", gold, piles);
! 192: }
! 193: }
! 194: }
! 195:
! 196: static void printSeedCatalogFloorItems(boolean isCsvFormat) {
! 197: item *theItem;
! 198: int gold = 0;
! 199: short piles = 0;
! 200:
! 201: for (theItem = floorItems->nextItem; theItem != NULL; theItem = theItem->nextItem) {
! 202: if (theItem->category == GOLD) {
! 203: piles++;
! 204: gold += theItem->quantity;
! 205: } else if (theItem->category == AMULET) {
! 206: } else {
! 207: printSeedCatalogItem(theItem, NULL, isCsvFormat);
! 208: }
! 209: }
! 210:
! 211: if (gold > 0) {
! 212: printSeedCatalogFloorGold(gold, piles, isCsvFormat);
! 213: }
! 214: }
! 215:
! 216: static void printSeedCatalogAltars(boolean isCsvFormat) {
! 217: short i, j;
! 218: boolean c_altars[50] = {0}; //IO.displayMachines uses 50
! 219: char vaultNumber[10] = "";
! 220:
! 221: for (j = 0; j < DROWS; j++) {
! 222: for (i = 0; i < DCOLS; i++) {
! 223: if (pmap[i][j].layers[0] == RESURRECTION_ALTAR) {
! 224: sprintf(vaultNumber, "%i", pmap[i][j].machineNumber);
! 225: if (isCsvFormat) {
! 226: printSeedCatalogCsvLine(rogue.seed, rogue.depthLevel, 1, "altar", "resurrection altar",
! 227: NO_ENCHANTMENT_STRING, NO_RUNIC_STRING, vaultNumber, NO_OPENS_VAULT_STRING,
! 228: NO_CARRIED_BY_MONSTER_STRING, NO_ALLY_STATUS_STRING, NO_MUTATION_STRING);
! 229: } else {
! 230: printf(" A resurrection altar (vault %s)\n", vaultNumber);
! 231: }
! 232: }
! 233: // commutation altars come in pairs. we only want to print 1.
! 234: if (pmap[i][j].layers[0] == COMMUTATION_ALTAR) {
! 235: c_altars[pmap[i][j].machineNumber] = true;
! 236: }
! 237: }
! 238: }
! 239: for (i = 0; i < 50; i++) {
! 240: if (c_altars[i]) {
! 241: sprintf(vaultNumber, "%i", i);
! 242: if (isCsvFormat) {
! 243: printSeedCatalogCsvLine(rogue.seed, rogue.depthLevel, 1, "altar", "commutation altar",
! 244: NO_ENCHANTMENT_STRING, NO_RUNIC_STRING, vaultNumber, NO_OPENS_VAULT_STRING,
! 245: NO_CARRIED_BY_MONSTER_STRING, NO_ALLY_STATUS_STRING, NO_MUTATION_STRING);
! 246: } else {
! 247: printf(" A commutation altar (vault %s)\n",vaultNumber);
! 248: }
! 249: }
! 250: }
! 251: }
! 252:
! 253: void printSeedCatalog(unsigned long startingSeed, unsigned long numberOfSeedsToScan, unsigned int scanThroughDepth,
! 254: boolean isCsvFormat) {
! 255: unsigned long theSeed;
! 256: char path[BROGUE_FILENAME_MAX];
! 257: char message[1000] = "";
! 258: rogue.nextGame = NG_NOTHING;
! 259:
! 260: getAvailableFilePath(path, LAST_GAME_NAME, GAME_SUFFIX);
! 261: strcat(path, GAME_SUFFIX);
! 262:
! 263: sprintf(message, "Brogue seed catalog, seeds %lu to %lu, through depth %u.\n"
! 264: "Generated with %s. Dungeons unchanged since %s.\n\n"
! 265: "To play one of these seeds, press control-N from the title screen"
! 266: " and enter the seed number.\n",
! 267: startingSeed, startingSeed + numberOfSeedsToScan - 1, scanThroughDepth, BROGUE_VERSION_STRING,
! 268: BROGUE_DUNGEON_VERSION_STRING, scanThroughDepth);
! 269:
! 270: if (isCsvFormat) {
! 271: fprintf(stderr, "%s", message);
! 272: printf("%s\n",CSV_HEADER_STRING);
! 273: } else {
! 274: printf("%s", message);
! 275: }
! 276:
! 277: for (theSeed = startingSeed; theSeed < startingSeed + numberOfSeedsToScan; theSeed++) {
! 278: if (!isCsvFormat) {
! 279: printf("Seed %li:\n", theSeed);
! 280: }
! 281: fprintf(stderr, "Scanning seed %li...\n", theSeed);
! 282: rogue.nextGamePath[0] = '\0';
! 283: randomNumbersGenerated = 0;
! 284:
! 285: rogue.playbackMode = false;
! 286: rogue.playbackFastForward = false;
! 287: rogue.playbackBetweenTurns = false;
! 288:
! 289: strcpy(currentFilePath, path);
! 290: initializeRogue(theSeed);
! 291: rogue.playbackOmniscience = true;
! 292: for (rogue.depthLevel = 1; rogue.depthLevel <= scanThroughDepth; rogue.depthLevel++) {
! 293: startLevel(rogue.depthLevel == 1 ? 1 : rogue.depthLevel - 1, 1); // descending into level n
! 294: if (!isCsvFormat) {
! 295: printf(" Depth %i:\n", rogue.depthLevel);
! 296: }
! 297:
! 298: printSeedCatalogFloorItems(isCsvFormat);
! 299: printSeedCatalogMonsterItems(isCsvFormat);
! 300: printSeedCatalogMonsters(isCsvFormat, false); // captives and allies only
! 301: if (rogue.depthLevel >= 13) { // resurrection & commutation altars can spawn starting on 13
! 302: printSeedCatalogAltars(isCsvFormat);
! 303: }
! 304: }
! 305:
! 306: freeEverything();
! 307: remove(currentFilePath); // Don't add a spurious LastGame file to the brogue folder.
! 308: }
! 309:
! 310: }
CVSweb