Annotation of brogue-ce/src/brogue/SeedCatalog.c, Revision 1.1.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