1 /**
2 * \file wiz-stats.c
3 * \brief Statistics collection on dungeon generation
4 *
5 * Copyright (c) 2008 Andi Sidwell
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * * Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 *
13 * * Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
16 */
17 #include "math.h"
18 #include "angband.h"
19 #include "cave.h"
20 #include "cmds.h"
21 #include "effects.h"
22 #include "game-input.h"
23 #include "generate.h"
24 #include "init.h"
25 #include "mon-make.h"
26 #include "monster.h"
27 #include "obj-init.h"
28 #include "obj-pile.h"
29 #include "obj-randart.h"
30 #include "obj-tval.h"
31 #include "obj-util.h"
32 #include "object.h"
33 #include "ui-command.h"
34 #include "wizard.h"
35
36 /**
37 * The stats programs here will provide information on the dungeon, the monsters
38 * in it, and the items that they drop. Statistics are gotten from a given
39 * level by generating a new level, collecting all the items (noting if they
40 * were generated in a vault). Then all non-unique monsters are killed and
41 * their stats are tracked.
42 * The items from these monster drops are then collected and analyzed. Lastly,
43 * all unique monsters are killed, and their drops are analyzed. In this way,
44 * it is possible to separate unique drops and normal monster drops.
45 *
46 * There are two options for simulating the entirety of the dungeon. There is
47 * a "diving" option that begins each level with all artifacts and uniques
48 * available; and there is a "level-clearing" option that simulates all 100
49 * levels of the dungeon, removing artifacts and uniques as they are
50 * discovered/killed. "diving" option only catalogues every 5 levels.
51 *
52 * At the end of the "level-clearing" log file, extra post-processing is done
53 * to find the mean and standard deviation for the level you are likely to
54 * first gain an item with a key resistance or item.
55 *
56 * In addition to these sims there is a shorter sim that tests for dungeon
57 * connectivity.
58 */
59
60 #ifdef USE_STATS
61
62 /*** Statsgen ***/
63
64 /* Logfile to store results in */
65 static ang_file *stats_log = NULL;
66
67 /* this is the size of arrays used to calculate mean and std_dev.
68 * these values will be calculated over the first TRIES_SIZE attempts
69 * or less if TRIES_SIZE is less than tries
70 */
71 #define TRIES_SIZE 100
72 #define MAX_LVL 101
73
74 /* default for number of tries */
75 int tries=50;
76 /* the simulation number that we are on */
77 int iter;
78 /* amount to add each time an item comes up */
79 static double addval;
80 /* flag for whether we are in clearing mode */
81 bool clearing = false;
82 /* flag for regenning randart */
83 bool regen = false;
84
85 /*** These are items to track for each iteration ***/
86 /* total number of artifacts found */
87 static int art_it[TRIES_SIZE];
88
89 /*** handle gold separately ***/
90 /* gold */
91 static double gold_total[MAX_LVL], gold_floor[MAX_LVL], gold_mon[MAX_LVL];
92
93
94 typedef enum stat_code
95 {
96 ST_BEGIN,
97 ST_EQUIPMENT,
98 ST_FA_EQUIPMENT,
99 ST_SI_EQUIPMENT,
100 ST_RESIST_EQUIPMENT,
101 ST_RBASE_EQUIPMENT,
102 ST_RPOIS_EQUIPMENT,
103 ST_RNEXUS_EQUIPMENT,
104 ST_RBLIND_EQUIPMENT,
105 ST_RCONF_EQUIPMENT,
106 ST_SPEED_EQUIPMENT,
107 ST_TELEP_EQUIPMENT,
108 ST_ARMORS,
109 ST_BAD_ARMOR,
110 ST_AVERAGE_ARMOR,
111 ST_GOOD_ARMOR,
112 ST_STR_ARMOR,
113 ST_INT_ARMOR,
114 ST_WIS_ARMOR,
115 ST_DEX_ARMOR,
116 ST_CON_ARMOR,
117 ST_CURSED_ARMOR,
118 ST_WEAPONS,
119 ST_BAD_WEAPONS,
120 ST_AVERAGE_WEAPONS,
121 ST_GOOD_WEAPONS,
122 ST_SLAY_WEAPONS,
123 ST_SLAYEVIL_WEAPONS,
124 ST_KILL_WEAPONS,
125 ST_BRAND_WEAPONS,
126 ST_WESTERNESSE_WEAPONS,
127 ST_DEFENDER_WEAPONS,
128 ST_GONDOLIN_WEAPONS,
129 ST_HOLY_WEAPONS,
130 ST_XTRABLOWS_WEAPONS,
131 ST_TELEP_WEAPONS,
132 ST_HUGE_WEAPONS,
133 ST_ENDGAME_WEAPONS,
134 ST_MORGUL_WEAPONS,
135 ST_BOWS,
136 ST_BAD_BOWS,
137 ST_AVERAGE_BOWS,
138 ST_GOOD_BOWS,
139 ST_VERYGOOD_BOWS,
140 ST_XTRAMIGHT_BOWS,
141 ST_XTRASHOTS_BOWS,
142 ST_BUCKLAND_BOWS,
143 ST_TELEP_BOWS,
144 ST_CURSED_BOWS,
145 ST_POTIONS,
146 ST_GAINSTAT_POTIONS,
147 ST_HEALING_POTIONS,
148 ST_BIGHEAL_POTIONS,
149 ST_RESTOREMANA_POTIONS,
150 ST_SCROLLS,
151 ST_ENDGAME_SCROLLS,
152 ST_ACQUIRE_SCROLLS,
153 ST_RODS,
154 ST_UTILITY_RODS,
155 ST_TELEPOTHER_RODS,
156 ST_DETECTALL_RODS,
157 ST_ENDGAME_RODS,
158 ST_STAVES,
159 ST_SPEED_STAVES,
160 ST_DESTRUCTION_STAVES,
161 ST_KILL_STAVES,
162 ST_ENDGAME_STAVES,
163 ST_WANDS,
164 ST_TELEPOTHER_WANDS,
165 ST_RINGS,
166 ST_SPEEDS_RINGS,
167 ST_STAT_RINGS,
168 ST_RPOIS_RINGS,
169 ST_FA_RINGS,
170 ST_SI_RINGS,
171 ST_BRAND_RINGS,
172 ST_ELVEN_RINGS,
173 ST_ONE_RINGS,
174 ST_CURSED_RINGS,
175 ST_AMULETS,
176 ST_WIS_AMULETS,
177 ST_TELEP_AMULETS,
178 ST_ENDGAME_AMULETS,
179 ST_CURSED_AMULETS,
180 ST_AMMO,
181 ST_BAD_AMMO,
182 ST_AVERAGE_AMMO,
183 ST_GOOD_AMMO,
184 ST_BRANDSLAY_AMMO,
185 ST_VERYGOOD_AMMO,
186 ST_AWESOME_AMMO,
187 ST_SLAYEVIL_AMMO,
188 ST_HOLY_AMMO,
189 ST_BOOKS,
190 ST_1ST_BOOKS,
191 ST_2ND_BOOKS,
192 ST_3RD_BOOKS,
193 ST_4TH_BOOKS,
194 ST_5TH_BOOKS,
195 ST_6TH_BOOKS,
196 ST_7TH_BOOKS,
197 ST_8TH_BOOKS,
198 ST_9TH_BOOKS,
199 ST_END
200 }
201 stat_code;
202
203
204 struct stat_data
205 {
206 stat_code st;
207 char *name;
208 };
209
210 static const struct stat_data stat_message[] =
211 {
212 {ST_BEGIN, ""},
213 {ST_EQUIPMENT, "\n ***EQUIPMENT*** \n All: "},
214 {ST_FA_EQUIPMENT, " Free Action "},
215 {ST_SI_EQUIPMENT, " See Invis "},
216 {ST_RESIST_EQUIPMENT, " Low Resist "},
217 {ST_RBASE_EQUIPMENT, " Resist Base "},
218 {ST_RPOIS_EQUIPMENT, " Resist Pois "},
219 {ST_RNEXUS_EQUIPMENT, " Res. Nexus "},
220 {ST_RBLIND_EQUIPMENT, " Res. Blind "},
221 {ST_RCONF_EQUIPMENT, " Res. Conf. "},
222 {ST_SPEED_EQUIPMENT, " Speed "},
223 {ST_TELEP_EQUIPMENT, " Telepathy "},
224 {ST_ARMORS, "\n ***ARMOR*** \n All: "},
225 {ST_BAD_ARMOR, " Bad "},
226 {ST_AVERAGE_ARMOR, " Average "},
227 {ST_GOOD_ARMOR, " Good "},
228 {ST_STR_ARMOR, " +Strength "},
229 {ST_INT_ARMOR, " +Intel. "},
230 {ST_WIS_ARMOR, " +Wisdom "},
231 {ST_DEX_ARMOR, " +Dexterity "},
232 {ST_CON_ARMOR, " +Const. "},
233 {ST_CURSED_ARMOR, " Cursed "},
234 {ST_WEAPONS, "\n ***WEAPONS*** \n All: "},
235 {ST_BAD_WEAPONS, " Bad "},
236 {ST_AVERAGE_WEAPONS, " Average "},
237 {ST_GOOD_WEAPONS, " Good "},
238 {ST_SLAY_WEAPONS, " Weak Slay "},
239 {ST_SLAYEVIL_WEAPONS, " Slay evil "},
240 {ST_KILL_WEAPONS, " *Slay* "},
241 {ST_BRAND_WEAPONS, " Brand "},
242 {ST_WESTERNESSE_WEAPONS, " Westernesse "},
243 {ST_DEFENDER_WEAPONS, " Defender "},
244 {ST_GONDOLIN_WEAPONS, " Gondolin "},
245 {ST_HOLY_WEAPONS, " Holy Avengr "},
246 {ST_XTRABLOWS_WEAPONS, " Extra Blows "},
247 {ST_TELEP_WEAPONS, " Telepathy "},
248 {ST_HUGE_WEAPONS, " Huge "},//MoD, SoS and BoC
249 {ST_ENDGAME_WEAPONS, " Endgame "},//MoD, SoS and BoC with slay evil or x2B
250 {ST_MORGUL_WEAPONS, " Morgul "},
251 {ST_BOWS, "\n ***LAUNCHERS*** \n All: "},
252 {ST_BAD_BOWS, " Bad "},
253 {ST_AVERAGE_BOWS, " Average "},
254 {ST_GOOD_BOWS, " Good "},
255 {ST_VERYGOOD_BOWS, " Very Good "},//Power > 15
256 {ST_XTRAMIGHT_BOWS, " Extra might "},
257 {ST_XTRASHOTS_BOWS, " Extra shots "},
258 {ST_BUCKLAND_BOWS, " Buckland "},
259 {ST_TELEP_BOWS, " Telepathy "},
260 {ST_CURSED_BOWS, " Cursed "},
261 {ST_POTIONS, "\n ***POTIONS*** \n All: "},
262 {ST_GAINSTAT_POTIONS, " Gain stat "},//includes *enlight*
263 {ST_HEALING_POTIONS, " Healing "},
264 {ST_BIGHEAL_POTIONS, " Big heal "},//*heal* and life
265 {ST_RESTOREMANA_POTIONS, " Rest. Mana "},
266 {ST_SCROLLS, "\n ***SCROLLS*** \n All: "},
267 {ST_ENDGAME_SCROLLS, " Endgame "},// destruction, banish, mass banish, rune
268 {ST_ACQUIRE_SCROLLS, " Acquire. "},
269 {ST_RODS, "\n ***RODS*** \n All: "},
270 {ST_UTILITY_RODS, " Utility "},//dtrap, dstairs, dobj, light, illum
271 {ST_TELEPOTHER_RODS, " Tele Other "},
272 {ST_DETECTALL_RODS, " Detect all "},
273 {ST_ENDGAME_RODS, " Endgame "},//speed, healing
274 {ST_STAVES, "\n ***STAVES*** \n All: "},
275 {ST_SPEED_STAVES, " Speed "},
276 {ST_DESTRUCTION_STAVES, " Destruction "},
277 {ST_KILL_STAVES, " Kill "},//dispel evil, power, holiness
278 {ST_ENDGAME_STAVES, " Endgame "},//healing, magi, banishment
279 {ST_WANDS, "\n ***WANDS*** \n All: "},
280 {ST_TELEPOTHER_WANDS, " Tele Other "},
281 {ST_RINGS, "\n ***RINGS*** \n All: "},
282 {ST_SPEEDS_RINGS, " Speed "},
283 {ST_STAT_RINGS, " Stat "},//str, dex, con, int
284 {ST_RPOIS_RINGS, " Res. Pois. "},
285 {ST_FA_RINGS, " Free Action "},
286 {ST_SI_RINGS, " See Invis. "},
287 {ST_BRAND_RINGS, " Brand "},
288 {ST_ELVEN_RINGS, " Elven "},
289 {ST_ONE_RINGS, " The One "},
290 {ST_CURSED_RINGS, " Cursed "},
291 {ST_RINGS, "\n ***AMULETS*** \n All: "},
292 {ST_WIS_AMULETS, " Wisdom "},
293 {ST_TELEP_AMULETS, " Telepathy "},
294 {ST_ENDGAME_AMULETS, " Endgame "},//Trickery, weaponmastery, magi
295 {ST_CURSED_AMULETS, " Cursed "},
296 {ST_AMMO, "\n ***AMMO*** \n All: "},
297 {ST_BAD_AMMO, " Bad "},
298 {ST_AVERAGE_AMMO, " Average "},
299 {ST_GOOD_AMMO, " Good "},
300 {ST_BAD_AMMO, " Brand "},
301 {ST_VERYGOOD_AMMO, " Very Good "},//seeker or mithril
302 {ST_AWESOME_AMMO, " Awesome "},//seeker, mithril + brand
303 {ST_SLAYEVIL_AMMO, " Slay evil "},
304 {ST_HOLY_AMMO, " Holy might "},
305 {ST_BOOKS, "\n ***BOOKS*** \n All: "},
306 {ST_1ST_BOOKS, " Book 1 "},
307 {ST_2ND_BOOKS, " Book 2 "},
308 {ST_3RD_BOOKS, " Book 3 "},
309 {ST_4TH_BOOKS, " Book 4 "},
310 {ST_5TH_BOOKS, " Book 5 "},
311 {ST_6TH_BOOKS, " Book 6 "},
312 {ST_7TH_BOOKS, " Book 7 "},
313 {ST_8TH_BOOKS, " Book 8 "},
314 {ST_9TH_BOOKS, " Book 9 "},
315 };
316
317 double stat_all[ST_END][3][MAX_LVL];
318
319 /* Values for things we want to find the level where it's
320 * most likely to be first found */
321 typedef enum stat_first_find
322 {
323 ST_FF_BEGIN,
324 ST_FF_FA,
325 ST_FF_SI,
326 ST_FF_RPOIS,
327 ST_FF_RNEXUS,
328 ST_FF_RCONF,
329 ST_FF_RBLIND,
330 ST_FF_TELEP,
331 ST_FF_BOOK1,
332 ST_FF_BOOK2,
333 ST_FF_BOOK3,
334 ST_FF_BOOK4,
335 ST_FF_BOOK5,
336 ST_FF_BOOK6,
337 ST_FF_BOOK7,
338 ST_FF_BOOK8,
339 ST_FF_BOOK9,
340 ST_FF_END
341 }
342 stat_first_find;
343
344 struct stat_ff_data
345 {
346 stat_first_find st_ff;
347 stat_code st;
348 char *name;
349 };
350
351 static const struct stat_ff_data stat_ff_message[] =
352 {
353 {ST_FF_BEGIN,ST_BEGIN,""},
354 {ST_FF_FA, ST_FA_EQUIPMENT, "FA \t"},
355 {ST_FF_SI, ST_SI_EQUIPMENT, "SI \t"},
356 {ST_FF_RPOIS, ST_RPOIS_EQUIPMENT, "Rpois \t"},
357 {ST_FF_RNEXUS, ST_RNEXUS_EQUIPMENT, "Rnexus \t"},
358 {ST_FF_RCONF, ST_RCONF_EQUIPMENT, "Rconf \t"},
359 {ST_FF_RBLIND, ST_RBLIND_EQUIPMENT, "Rblind \t"},
360 {ST_FF_TELEP, ST_TELEP_EQUIPMENT, "Telep \t"},
361 {ST_FF_BOOK1, ST_1ST_BOOKS, "Book1 \t"},
362 {ST_FF_BOOK2, ST_2ND_BOOKS, "Book2 \t"},
363 {ST_FF_BOOK3, ST_3RD_BOOKS, "Book3 \t"},
364 {ST_FF_BOOK4, ST_4TH_BOOKS, "Book4 \t"},
365 {ST_FF_BOOK5, ST_5TH_BOOKS, "Book5 \t"},
366 {ST_FF_BOOK6, ST_6TH_BOOKS, "Book6 \t"},
367 {ST_FF_BOOK7, ST_7TH_BOOKS, "Book7 \t"},
368 {ST_FF_BOOK8, ST_8TH_BOOKS, "Book8 \t"},
369 {ST_FF_BOOK9, ST_9TH_BOOKS, "Book9 \t"},
370 };
371
372 int stat_ff_all[ST_FF_END][TRIES_SIZE];
373
374
375
376 /* basic artifact info */
377 static double art_total[MAX_LVL], art_spec[MAX_LVL], art_norm[MAX_LVL];
378
379 /* artifact level info */
380 static double art_shal[MAX_LVL], art_ave[MAX_LVL], art_ood[MAX_LVL];
381
382 /* where normal artifacts come from */
383 static double art_mon[MAX_LVL], art_uniq[MAX_LVL], art_floor[MAX_LVL], art_vault[MAX_LVL], art_mon_vault[MAX_LVL];
384
385
386
387 /* monster info */
388 static double mon_total[MAX_LVL], mon_ood[MAX_LVL], mon_deadly[MAX_LVL];
389
390 /* unique info */
391 static double uniq_total[MAX_LVL], uniq_ood[MAX_LVL], uniq_deadly[MAX_LVL];
392
393
394 /* set everything to 0.0 to begin */
init_stat_vals()395 static void init_stat_vals()
396 {
397 int i,j,k;
398
399 for (i = 0; i < ST_END;i++)
400 for (j = 0; j < 3; k = j++)
401 for (k = 0; k < MAX_LVL; k++)
402 stat_all[i][j][k] = 0.0;
403
404 for (i = 1; i < TRIES_SIZE; i++)
405 art_it[i] = 0;
406
407 for (i = 0; i < ST_FF_END; i++)
408 for (j = 0; j < TRIES_SIZE; j++)
409 stat_ff_all[i][j] = 0.0;
410 }
411
412 /*
413 * Record the first level we find something
414 */
first_find(stat_first_find st)415 static bool first_find(stat_first_find st)
416 {
417 /* make sure we're not on an iteration above our array limit */
418 if (iter >= TRIES_SIZE) return false;
419
420 /* make sure we haven't found it earlier on this iteration */
421 if (stat_ff_all[st][iter] > 0) return false;
422
423 /* assign the depth to this value */
424 stat_ff_all[st][iter] = player->depth;
425
426 /* success */
427 return true;
428 }
429
430 /*
431 * Add the number of drops for a specifci stat
432 */
add_stats(stat_code st,bool vault,bool mon,int number)433 static void add_stats(stat_code st, bool vault, bool mon, int number)
434 {
435 int lvl;
436
437 /* get player level */
438 lvl=player->depth;
439
440 /* be careful about bounds */
441 if ((lvl > MAX_LVL) || (lvl < 0)) return;
442
443 /* add to the total */
444 stat_all[st][0][lvl] += addval * number;
445
446 /* add to the total from vaults */
447 if ((!mon) && (vault)) stat_all[st][2][lvl] += addval * number;
448
449 /* add to the total from monsters */
450 if (mon) stat_all[st][1][lvl] += addval * number;
451
452 }
453
454 /*
455 * This will get data on an object
456 * It gets a lot of stuff, pretty much everything that I
457 * thought was reasonable to get. However, you might have
458 * a much different opinion. Luckily, I tried to make it
459 * trivial to add new items to log.
460 */
get_obj_data(const struct object * obj,int y,int x,bool mon,bool uniq)461 static void get_obj_data(const struct object *obj, int y, int x, bool mon,
462 bool uniq)
463 {
464
465 bool vault = square_isvault(cave, loc(x, y));
466 int number = obj->number;
467 static int lvl;
468 struct artifact *art;
469
470 double gold_temp = 0;
471
472 assert(obj->kind);
473
474 /* get player depth */
475 lvl = player->depth;
476
477 /* check for some stuff that we will use regardless of type */
478 /* originally this was armor, but I decided to generalize it */
479
480 /* has free action (hack: don't include Inertia)*/
481 if (of_has(obj->flags, OF_FREE_ACT) &&
482 !((obj->tval == TV_AMULET) &&
483 (!strstr(obj->kind->name, "Inertia")))) {
484
485 /* add the stats */
486 add_stats(ST_FA_EQUIPMENT, vault, mon, number);
487
488 /* record first level */
489 first_find(ST_FF_FA);
490 }
491
492
493 /* has see invis */
494 if (of_has(obj->flags, OF_SEE_INVIS)){
495
496 add_stats(ST_SI_EQUIPMENT, vault, mon, number);
497 first_find(ST_FF_SI);
498 }
499 /* has at least one basic resist */
500 if ((obj->el_info[ELEM_ACID].res_level == 1) ||
501 (obj->el_info[ELEM_ELEC].res_level == 1) ||
502 (obj->el_info[ELEM_COLD].res_level == 1) ||
503 (obj->el_info[ELEM_FIRE].res_level == 1)){
504
505 add_stats(ST_RESIST_EQUIPMENT, vault, mon, number);
506 }
507
508 /* has rbase */
509 if ((obj->el_info[ELEM_ACID].res_level == 1) &&
510 (obj->el_info[ELEM_ELEC].res_level == 1) &&
511 (obj->el_info[ELEM_COLD].res_level == 1) &&
512 (obj->el_info[ELEM_FIRE].res_level == 1))
513 add_stats(ST_RBASE_EQUIPMENT, vault, mon, number);
514
515 /* has resist poison */
516 if (obj->el_info[ELEM_POIS].res_level == 1){
517
518 add_stats(ST_RPOIS_EQUIPMENT, vault, mon, number);
519 first_find(ST_FF_RPOIS);
520
521 }
522 /* has resist nexus */
523 if (obj->el_info[ELEM_NEXUS].res_level == 1){
524
525 add_stats(ST_RNEXUS_EQUIPMENT, vault, mon, number);
526 first_find(ST_FF_RNEXUS);
527 }
528 /* has resist blind */
529 if (of_has(obj->flags, OF_PROT_BLIND)){
530
531 add_stats(ST_RBLIND_EQUIPMENT, vault, mon, number);
532 first_find(ST_FF_RBLIND);
533 }
534
535 /* has resist conf */
536 if (of_has(obj->flags, OF_PROT_CONF)){
537
538 add_stats(ST_RCONF_EQUIPMENT, vault, mon, number);
539 first_find(ST_FF_RCONF);
540 }
541
542 /* has speed */
543 if (obj->modifiers[OBJ_MOD_SPEED] != 0)
544 add_stats(ST_SPEED_EQUIPMENT, vault, mon, number);
545
546 /* has telepathy */
547 if (of_has(obj->flags, OF_TELEPATHY)){
548
549 add_stats(ST_TELEP_EQUIPMENT, vault, mon, number);
550 first_find(ST_FF_TELEP);
551 }
552
553 switch(obj->tval){
554
555 /* armor */
556 case TV_BOOTS:
557 case TV_GLOVES:
558 case TV_HELM:
559 case TV_CROWN:
560 case TV_SHIELD:
561 case TV_CLOAK:
562 case TV_SOFT_ARMOR:
563 case TV_HARD_ARMOR:
564 case TV_DRAG_ARMOR:{
565
566 /* do not include artifacts */
567 if (obj->artifact) break;
568
569 /* add to armor total */
570 add_stats(ST_ARMORS, vault, mon, number);
571
572 /* check if bad, good, or average */
573 if (obj->to_a < 0)
574 add_stats(ST_BAD_ARMOR, vault, mon, number);
575 if (obj->to_h == 0)
576 add_stats(ST_AVERAGE_ARMOR, vault, mon, number);
577 if (obj->to_h > 0)
578 add_stats(ST_GOOD_ARMOR, vault, mon, number);
579
580 /* has str boost */
581 if (obj->modifiers[OBJ_MOD_STR] != 0)
582 add_stats(ST_STR_ARMOR, vault, mon, number);
583
584 /* has dex boost */
585 if (obj->modifiers[OBJ_MOD_DEX] != 0)
586 add_stats(ST_DEX_ARMOR, vault, mon, number);
587
588 /* has int boost */
589 if (obj->modifiers[OBJ_MOD_INT] != 0)
590 add_stats(ST_INT_ARMOR, vault, mon, number);
591
592 if (obj->modifiers[OBJ_MOD_WIS] != 0)
593 add_stats(ST_WIS_ARMOR, vault, mon, number);
594
595 if (obj->modifiers[OBJ_MOD_CON] != 0)
596 add_stats(ST_CON_ARMOR, vault, mon, number);
597
598 if (obj->curses)
599 add_stats(ST_CURSED_ARMOR, vault, mon, number);
600
601 break;
602 }
603
604 /* weapons */
605 case TV_DIGGING:
606 case TV_HAFTED:
607 case TV_POLEARM:
608 case TV_SWORD:{
609
610 /* do not include artifacts */
611 if (obj->artifact) break;
612
613 /* add to weapon total */
614 add_stats(ST_WEAPONS, vault, mon, number);
615
616 /* check if bad, good, or average */
617 if ((obj->to_h < 0) && (obj->to_d < 0))
618 add_stats(ST_BAD_WEAPONS, vault, mon, number);
619 if ((obj->to_h == 0) && (obj->to_d == 0))
620 add_stats(ST_AVERAGE_WEAPONS, vault, mon, number);
621 if ((obj->to_h > 0) && (obj->to_d > 0))
622 add_stats(ST_GOOD_WEAPONS, vault, mon, number);
623
624 /* Egos by name - changes results a little */
625 if (obj->ego) {
626 /* slay evil */
627 if (strstr(obj->ego->name, "of Slay Evil"))
628 add_stats(ST_SLAYEVIL_WEAPONS, vault, mon, number);
629
630 /* slay weapons */
631 else if (strstr(obj->ego->name, "of Slay"))
632 add_stats(ST_SLAY_WEAPONS, vault, mon, number);
633 /* kill flag */
634 if (strstr(obj->ego->name, "of *Slay"))
635 add_stats(ST_KILL_WEAPONS, vault, mon, number);
636
637 /* determine westernesse by flags */
638 if (strstr(obj->ego->name, "Westernesse"))
639 add_stats(ST_WESTERNESSE_WEAPONS, vault, mon, number);
640
641 /* determine defender by flags */
642 if (strstr(obj->ego->name, "Defender"))
643 add_stats(ST_DEFENDER_WEAPONS, vault, mon, number);
644
645 /* determine gondolin by flags */
646 if (strstr(obj->ego->name, "Gondolin"))
647 add_stats(ST_GONDOLIN_WEAPONS, vault, mon, number);
648
649 /* determine holy avenger by flags */
650 if (strstr(obj->ego->name, "Avenger"))
651 add_stats(ST_HOLY_WEAPONS, vault, mon, number);
652
653 /* is morgul */
654 if (strstr(obj->ego->name, "Morgul"))
655 add_stats(ST_MORGUL_WEAPONS, vault, mon, number);
656 }
657
658 /* branded weapons */
659 if (obj->brands)
660 add_stats(ST_BRAND_WEAPONS, vault, mon, number);
661
662 /* extra blows */
663 if (obj->modifiers[OBJ_MOD_BLOWS] > 0)
664 add_stats(ST_XTRABLOWS_WEAPONS, vault, mon, number);
665
666 /* telepathy */
667 if (of_has(obj->flags, OF_TELEPATHY))
668 add_stats(ST_TELEP_WEAPONS, vault, mon, number);
669
670 /* is a top of the line weapon */
671 if (((obj->tval == TV_HAFTED) &&
672 (!strstr(obj->kind->name, "Disruption"))) ||
673 ((obj->tval == TV_POLEARM) &&
674 (!strstr(obj->kind->name, "Slicing"))) ||
675 ((obj->tval == TV_SWORD) &&
676 (!strstr(obj->kind->name, "Chaos")))) {
677 add_stats(ST_HUGE_WEAPONS, vault, mon, number);
678
679 /* is uber need to fix ACB
680 if ((of_has(obj->flags, OF_SLAY_EVIL)) || (obj->modifiers[OBJ_MOD_BLOWS] > 0))
681 add_stats(ST_UBWE, vault, mon, number); */
682
683 }
684
685 break;
686 }
687
688 /* launchers */
689 case TV_BOW:{
690
691 /* do not include artifacts */
692 if (obj->artifact) break;
693
694 /* add to launcher total */
695 add_stats(ST_BOWS, vault, mon, number);
696
697 /* check if bad, average, good, or very good */
698 if ((obj->to_h < 0) && (obj->to_d < 0))
699 add_stats(ST_BAD_BOWS, vault, mon, number);
700 if ((obj->to_h == 0) && (obj->to_d == 0))
701 add_stats(ST_AVERAGE_BOWS, vault, mon, number);
702 if ((obj->to_h > 0) && (obj->to_d > 0))
703 add_stats(ST_GOOD_BOWS, vault, mon, number);
704 if ((obj->to_h > 15) || (obj->to_d > 15))
705 add_stats(ST_VERYGOOD_BOWS, vault, mon, number);
706
707 /* check long bows and xbows for xtra might and/or shots */
708 if (obj->pval > 2)
709 {
710 if (obj->modifiers[OBJ_MOD_SHOTS] > 0)
711 add_stats(ST_XTRASHOTS_BOWS, vault, mon, number);
712
713 if (obj->modifiers[OBJ_MOD_MIGHT] > 0)
714 add_stats(ST_XTRAMIGHT_BOWS, vault, mon, number);
715 }
716
717 /* check for buckland */
718 if ((obj->pval == 2) &&
719 kf_has(obj->kind->kind_flags, KF_SHOOTS_SHOTS) &&
720 (obj->modifiers[OBJ_MOD_MIGHT] > 0) &&
721 (obj->modifiers[OBJ_MOD_SHOTS] > 0))
722 add_stats(ST_BUCKLAND_BOWS, vault, mon, number);
723
724 /* has telep */
725 if (of_has(obj->flags, OF_TELEPATHY))
726 add_stats(ST_TELEP_BOWS, vault, mon, number);
727
728 /* is cursed */
729 if (obj->curses)
730 add_stats(ST_CURSED_BOWS, vault, mon, number);
731 break;
732 }
733
734 /* potion */
735 case TV_POTION:{
736
737 /* Add total amounts */
738 add_stats(ST_POTIONS, vault, mon, number);
739
740 /* Stat gain */
741 if (strstr(obj->kind->name, "Strength") ||
742 strstr(obj->kind->name, "Intelligence") ||
743 strstr(obj->kind->name, "Wisdom") ||
744 strstr(obj->kind->name, "Dexterity") ||
745 strstr(obj->kind->name, "Constitution")) {
746 add_stats(ST_GAINSTAT_POTIONS, vault, mon, number);
747 } else if (strstr(obj->kind->name, "Augmentation")) {
748 /* Augmentation counts as 5 stat gain pots */
749 add_stats(ST_GAINSTAT_POTIONS, vault, mon, number * 5);
750 } else if (strstr(obj->kind->name, "*Enlightenment*")) {
751 /* *Enlight* counts as 2 stat pots */
752 add_stats(ST_GAINSTAT_POTIONS, vault, mon, number * 2);
753 } else if (strstr(obj->kind->name, "Restore Mana")) {
754 add_stats(ST_RESTOREMANA_POTIONS, vault, mon, number);
755 } else if ((strstr(obj->kind->name, "Life")) ||
756 (strstr(obj->kind->name, "*Healing*"))) {
757 add_stats(ST_ELVEN_RINGS, vault, mon, number);
758 } else if (strstr(obj->kind->name, "Healing")) {
759 add_stats(ST_HEALING_POTIONS, vault, mon, number);
760 }
761 break;
762 }
763
764 /* scrolls */
765 case TV_SCROLL:{
766
767 /* add total amounts */
768 add_stats(ST_SCROLLS, vault, mon, number);
769
770 if (strstr(obj->kind->name, "Banishment") ||
771 strstr(obj->kind->name, "Mass Banishment") ||
772 strstr(obj->kind->name, "Rune of Protection") ||
773 strstr(obj->kind->name, "*Destruction*")) {
774 add_stats(ST_ENDGAME_SCROLLS, vault, mon, number);
775 } else if (strstr(obj->kind->name, "Acquirement")) {
776 add_stats(ST_ACQUIRE_SCROLLS, vault, mon, number);
777 } else if (strstr(obj->kind->name, "*Acquirement*")) {
778 /* do the effect of 2 acquires */
779 add_stats(ST_ACQUIRE_SCROLLS, vault, mon, number * 2);
780 }
781 break;
782 }
783
784 /* rods */
785 case TV_ROD:{
786
787 /* add to total */
788 add_stats(ST_RODS, vault, mon, number);
789
790 if (strstr(obj->kind->name, "Trap Detection") ||
791 strstr(obj->kind->name, "Treasure Detection") ||
792 strstr(obj->kind->name, "Door/Stair Location") ||
793 strstr(obj->kind->name, "Illumination") ||
794 strstr(obj->kind->name, "Light")) {
795 add_stats(ST_UTILITY_RODS, vault, mon, number);
796 } else if (strstr(obj->kind->name, "Teleport Other")) {
797 add_stats(ST_TELEPOTHER_RODS, vault, mon, number);
798 } else if (strstr(obj->kind->name, "Detection")) {
799 add_stats(ST_DETECTALL_RODS, vault, mon, number);
800 } else if (strstr(obj->kind->name, "Speed") ||
801 strstr(obj->kind->name, "Healing")) {
802 add_stats(ST_ENDGAME_RODS, vault, mon, number);
803 }
804 break;
805 }
806
807 /* staves */
808 case TV_STAFF:{
809
810 add_stats(ST_STAVES, vault, mon, number);
811
812 if (strstr(obj->kind->name, "Speed")) {
813 add_stats(ST_SPEED_STAVES, vault, mon, number);
814 } else if (strstr(obj->kind->name, "*Destruction*")) {
815 add_stats(ST_DESTRUCTION_STAVES, vault, mon, number);
816 } else if (strstr(obj->kind->name, "Dispel Evil") ||
817 strstr(obj->kind->name, "Power") ||
818 strstr(obj->kind->name, "Holiness")) {
819 add_stats(ST_KILL_STAVES, vault, mon, number);
820 } else if (strstr(obj->kind->name, "Healing") ||
821 strstr(obj->kind->name, "Banishment") ||
822 strstr(obj->kind->name, "the Magi")) {
823 add_stats(ST_ENDGAME_STAVES, vault, mon, number);
824 }
825 break;
826 }
827
828 case TV_WAND:{
829
830 add_stats(ST_WANDS, vault, mon, number);
831
832 if (strstr(obj->kind->name, "Teleport Other"))
833 add_stats(ST_TELEPOTHER_WANDS, vault, mon, number);
834 break;
835 }
836
837 case TV_RING:{
838
839 add_stats(ST_RINGS, vault, mon, number);
840
841 /* is it cursed */
842 if (obj->curses)
843 add_stats(ST_CURSED_RINGS, vault, mon, number);
844
845 if (strstr(obj->kind->name, "Speed")) {
846 add_stats(ST_SPEEDS_RINGS, vault, mon, number);
847 } else if ((strstr(obj->kind->name, "Strength")) ||
848 (strstr(obj->kind->name, "Intelligence")) ||
849 (strstr(obj->kind->name, "Dexterity")) ||
850 (strstr(obj->kind->name, "Constitution"))) {
851 add_stats(ST_STAT_RINGS, vault, mon, number);
852 } else if (strstr(obj->kind->name, "Resist Poison")) {
853 add_stats(ST_RPOIS_RINGS, vault, mon, number);
854 } else if (strstr(obj->kind->name, "Free Action")) {
855 add_stats(ST_FA_RINGS, vault, mon, number);
856 } else if (strstr(obj->kind->name, "See invisible")) {
857 add_stats(ST_SI_RINGS, vault, mon, number);
858 } else if ((strstr(obj->kind->name, "Flames")) ||
859 (strstr(obj->kind->name, "Ice")) ||
860 (strstr(obj->kind->name, "Acid")) ||
861 (strstr(obj->kind->name, "Lightning"))) {
862 add_stats(ST_BRAND_RINGS, vault, mon, number);
863 } else if ((strstr(obj->kind->name, "Fire")) ||
864 (strstr(obj->kind->name, "Adamant")) ||
865 (strstr(obj->kind->name, "Firmament"))) {
866 add_stats(ST_ELVEN_RINGS, vault, mon, number);
867 } else if (strstr(obj->kind->name, "Power")) {
868 add_stats(ST_ONE_RINGS, vault, mon, number);
869 }
870
871
872 break;
873 }
874
875 case TV_AMULET:{
876
877 add_stats(ST_AMULETS, vault, mon, number);
878
879 if (strstr(obj->kind->name, "Wisdom")) {
880 add_stats(ST_WIS_AMULETS, vault, mon, number);
881 } else if ((strstr(obj->kind->name, "Magi")) ||
882 (strstr(obj->kind->name, "Trickery")) ||
883 (strstr(obj->kind->name, "Weaponmastery"))) {
884 add_stats(ST_ENDGAME_AMULETS, vault, mon, number);
885 } else if (strstr(obj->kind->name, "ESP")) {
886 add_stats(ST_TELEP_AMULETS, vault, mon, number);
887 }
888
889 /* is cursed */
890 if (obj->curses)
891 add_stats(ST_CURSED_AMULETS, vault, mon, number);
892
893 break;
894 }
895
896 case TV_SHOT:
897 case TV_ARROW:
898 case TV_BOLT:{
899
900 add_stats(ST_AMMO, vault, mon, number);
901
902 /* check if bad, average, good */
903 if ((obj->to_h < 0) && (obj->to_d < 0))
904 add_stats(ST_BAD_AMMO, vault, mon, number);
905 if ((obj->to_h == 0) && (obj->to_d == 0))
906 add_stats(ST_AVERAGE_AMMO, vault, mon, number);
907 if ((obj->to_h > 0) && (obj->to_d > 0))
908 add_stats(ST_GOOD_AMMO, vault, mon, number);
909
910 if (obj->ego)
911 add_stats(ST_BRANDSLAY_AMMO, vault, mon, number);
912
913 if (strstr(obj->kind->name, "Seeker") ||
914 strstr(obj->kind->name, "Mithril")) {
915
916 /* Mithril and seeker ammo */
917 add_stats(ST_VERYGOOD_AMMO, vault, mon, number);
918
919 /* Ego mithril and seeker ammo */
920 if (obj->ego) {
921 add_stats(ST_AWESOME_AMMO, vault, mon, number);
922
923 if (strstr(obj->ego->name, "of Slay Evil"))
924 add_stats(ST_SLAYEVIL_AMMO, vault, mon, number);
925
926 if (strstr(obj->ego->name, "of Holy Might"))
927 add_stats(ST_HOLY_AMMO, vault, mon, number);
928 }
929 }
930 break;
931 }
932
933 /* books have the same probability, only track one realm of them */
934 case TV_MAGIC_BOOK:{
935
936 switch(obj->sval){
937
938 /* svals begin at 0 and end at 8 */
939 case 0:{
940
941 add_stats(ST_1ST_BOOKS, vault, mon, number);
942 first_find(ST_FF_BOOK1);
943 break;
944 }
945
946 case 1:{
947
948 add_stats(ST_2ND_BOOKS, vault, mon, number);
949 first_find(ST_FF_BOOK2);
950 break;
951 }
952
953 case 2:{
954
955 add_stats(ST_3RD_BOOKS, vault, mon, number);
956 first_find(ST_FF_BOOK3);
957 break;
958 }
959
960 case 3:{
961
962 add_stats(ST_4TH_BOOKS, vault, mon, number);
963 first_find(ST_FF_BOOK4);
964 break;
965 }
966
967 case 4:{
968
969 add_stats(ST_5TH_BOOKS, vault, mon, number);
970 first_find(ST_FF_BOOK5);
971 break;
972 }
973
974 case 5:{
975
976 add_stats(ST_6TH_BOOKS, vault, mon, number);
977 first_find(ST_FF_BOOK6);
978 break;
979 }
980
981 case 6:{
982
983 add_stats(ST_7TH_BOOKS, vault, mon, number);
984 first_find(ST_FF_BOOK7);
985 break;
986 }
987
988 case 7:{
989
990 add_stats(ST_8TH_BOOKS, vault, mon, number);
991 first_find(ST_FF_BOOK8);
992 break;
993 }
994
995 case 8:{
996
997 add_stats(ST_9TH_BOOKS, vault, mon, number);
998 first_find(ST_FF_BOOK9);
999 break;
1000 }
1001
1002
1003 }
1004 break;
1005 }
1006 }
1007 /* check to see if we have an artifact */
1008 if (obj->artifact){
1009
1010 /* add to artifact level total */
1011 art_total[lvl] += addval;
1012
1013 /* add to the artifact iteration total */
1014 if (iter < TRIES_SIZE) art_it[iter]++;
1015
1016 /* Obtain the artifact info */
1017 art = obj->artifact;
1018
1019 //debugging, print out that we found the artifact
1020 //msg_format("Found artifact %s",art->name);
1021
1022 /* artifact is shallow */
1023 if (art->alloc_min < (player->depth - 20)) art_shal[lvl] += addval;
1024
1025 /* artifact is close to the player depth */
1026 if ((art->alloc_min >= player->depth - 20) &&
1027 (art->alloc_min <= player->depth )) art_ave[lvl] += addval;
1028
1029 /* artifact is out of depth */
1030 if (art->alloc_min > (player->depth)) art_ood[lvl] += addval;
1031
1032 /* check to see if it's a special artifact */
1033 if ((obj->tval == TV_LIGHT) || (obj->tval == TV_AMULET)
1034 || (obj->tval == TV_RING)){
1035
1036 /* increment special artifact counter */
1037 art_spec[lvl] += addval;
1038 } else {
1039 /* increment normal artifacts */
1040 art_norm[lvl] += addval;
1041
1042 /* did it come from a monster? */
1043 if (mon) art_mon[lvl] += addval;
1044
1045 /* did it come from a unique? */
1046 if (uniq) art_uniq[lvl] += addval;
1047
1048 /* was it in a vault? */
1049 if (vault){
1050
1051 /* did a monster drop it ?*/
1052 if ((mon) || (uniq)) art_mon_vault[lvl] += addval;
1053 else art_vault[lvl] += addval;
1054 } else {
1055 /* was it just lyin' on the floor? */
1056 if ((!uniq) && (!mon)) art_floor[lvl] += addval;
1057 }
1058 }
1059 /* preserve the artifact */
1060 if (!(clearing)) art->created = false;
1061 }
1062
1063 /* Get info on gold. */
1064 if (obj->tval == TV_GOLD){
1065
1066 int temp = obj->pval;
1067 gold_temp = temp;
1068 gold_total[lvl] += (gold_temp / tries);
1069
1070 /*From a monster? */
1071 if ((mon) || (uniq)) gold_mon[lvl] += (gold_temp / tries);
1072 else gold_floor[lvl] += (gold_temp / tries);
1073 }
1074
1075 }
1076
1077
1078
1079 /*
1080 * A rewrite of monster death that gets rid of some features
1081 * That we don't want to deal with. Namely, no notifying the
1082 * player and no generation of Morgoth artifacts
1083 *
1084 * It also replaces drop near with a new function that drops all
1085 * the items on the exact square that the monster was on.
1086 */
monster_death_stats(int m_idx)1087 void monster_death_stats(int m_idx)
1088 {
1089 struct object *obj;
1090 struct monster *mon;
1091 bool uniq;
1092
1093 assert(m_idx > 0);
1094 mon = cave_monster(cave, m_idx);
1095
1096 /* Check if monster is UNIQUE */
1097 uniq = rf_has(mon->race->flags,RF_UNIQUE);
1098
1099 /* Mimicked objects will have already been counted as floor objects */
1100 mon->mimicked_obj = NULL;
1101
1102 /* Drop objects being carried */
1103 obj = mon->held_obj;
1104 while (obj) {
1105 struct object *next = obj->next;
1106
1107 /* Object no longer held */
1108 obj->held_m_idx = 0;
1109
1110 /* Get data */
1111 get_obj_data(obj, mon->grid.y, mon->grid.x, true, uniq);
1112
1113 /* Delete the object */
1114 delist_object(cave, obj);
1115 object_delete(&obj);
1116
1117 /* Next */
1118 obj = next;
1119 }
1120
1121 /* Forget objects */
1122 mon->held_obj = NULL;
1123 }
1124
1125
1126
1127 /**
1128 * This will collect stats on a monster avoiding all unique monsters.
1129 * Afterwards it will kill the monsters.
1130 */
stats_monster(struct monster * mon,int i)1131 static bool stats_monster(struct monster *mon, int i)
1132 {
1133 static int lvl;
1134
1135 /* get player depth */
1136 lvl = player->depth;
1137
1138
1139 /* Increment monster count */
1140 mon_total[lvl] += addval;
1141
1142 /* Increment unique count if appropriate */
1143 if (rf_has(mon->race->flags, RF_UNIQUE)){
1144
1145 /* add to total */
1146 uniq_total[lvl] += addval;
1147
1148 /* kill the unique if we're in clearing mode */
1149 if (clearing) mon->race->max_num = 0;
1150
1151 /* debugging print that we killed it
1152 msg_format("Killed %s",race->name); */
1153 }
1154
1155 /* Is it mostly dangerous (10 levels ood or less?)*/
1156 if ((mon->race->level > player->depth) &&
1157 (mon->race->level <= player->depth + 10)) {
1158
1159 mon_ood[lvl] += addval;
1160
1161 /* Is it a unique */
1162 if (rf_has(mon->race->flags, RF_UNIQUE))
1163 uniq_ood[lvl] += addval;
1164 }
1165
1166
1167 /* Is it deadly? */
1168 if (mon->race->level > player->depth + 10){
1169
1170 mon_deadly[lvl] += addval;
1171
1172 /* Is it a unique? */
1173 if (rf_has(mon->race->flags, RF_UNIQUE))
1174 uniq_deadly[lvl] += addval;
1175 }
1176
1177 /* Generate treasure */
1178 monster_death_stats(i);
1179
1180 /* remove the monster */
1181 delete_monster_idx(i);
1182
1183 /* success */
1184 return true;
1185 }
1186
1187
1188 /**
1189 * Print heading infor for the file
1190 */
print_heading(void)1191 static void print_heading(void)
1192 {
1193 /* PRINT INFO STUFF */
1194 file_putf(stats_log," This is a Monte Carlo simulation, results are arranged by level \n");
1195 file_putf(stats_log," Monsters: OOD means between 1 and 10 levels deep, deadly is more than \n");
1196 file_putf(stats_log," 10 levels deep \n");
1197 file_putf(stats_log," Artifacts: info on artifact location (vault, floor, etc) \n");
1198 file_putf(stats_log," do not include special artifacts, only weapons and armor \n");
1199 file_putf(stats_log," Weapons : Big dice weapons are either BoC, SoS, or Mod. Uber \n");
1200 file_putf(stats_log," weapons, are one of the above with xblows or slay evil\n");
1201 file_putf(stats_log," Launchers: xtra shots and xtra might are only logged for x3 or\n");
1202 file_putf(stats_log," better. Very good has +to hit or + to dam > 15\n");
1203 file_putf(stats_log," Amulets: Endgame amulets are trickery, weaponmaster and magi\n");
1204 file_putf(stats_log," Armor: Low resist armor may have more than one basic resist (acid, \n");
1205 file_putf(stats_log," elec, fire, cold) but not all. \n");
1206 file_putf(stats_log," Books: Prayer and Magic books have the same probability. \n");
1207 file_putf(stats_log," Potions: Aug counts as 5 potions, *enlight* as 2. Healing potions are \n");
1208 file_putf(stats_log," only *Healing* and Life\n");
1209 file_putf(stats_log," Scrolls: Endgame scrolls include *Dest*, Rune, MBan and Ban \n");
1210 file_putf(stats_log," *Acq* counts as two Acq scrolls");
1211 file_putf(stats_log," Rods: Utility rods: d-obj, d-stairs, d-traps, light, illum \n");
1212 file_putf(stats_log," Endgame rods: Speed, Healing \n");
1213 file_putf(stats_log," Staves: Kill staves: dispel evil, power, holiness. \n");
1214 file_putf(stats_log," Power staves: healing, magi, banishment \n");
1215 }
1216
1217 /**
1218 * Print all the stats for each level
1219 */
print_stats(int lvl)1220 static void print_stats(int lvl)
1221 {
1222
1223 int i;
1224
1225 /* check bounds on lvl */
1226 if ((lvl < 0) || (lvl > 100)) return;
1227
1228 /* print level heading */
1229 file_putf(stats_log,"\n");
1230 file_putf(stats_log,"******** LEVEL %d , %d tries********* \n",lvl, tries);
1231 file_putf(stats_log,"\n");
1232
1233 /* print monster heading */
1234 file_putf(stats_log," MONSTER INFO \n");
1235 file_putf(stats_log," Total monsters: %f OOD: %f Deadly: %f \n",
1236 mon_total[lvl], mon_ood[lvl], mon_deadly[lvl]);
1237 file_putf(stats_log," Unique monsters: %f OOD: %f Deadly: %f \n",
1238 uniq_total[lvl], uniq_ood[lvl], uniq_deadly[lvl]);
1239 /* print artifact heading */
1240
1241
1242
1243 file_putf(stats_log,"\n ARTIFACT INFO \n");
1244
1245 /* basic artifact info */
1246 file_putf(stats_log,"Total artifacts: %f Special artifacts: %f Weapons/armor: %f \n",
1247 art_total[lvl], art_spec[lvl], art_norm[lvl]);
1248
1249 /* artifact depth info */
1250 file_putf(stats_log,"Shallow: %f Average: %f Ood: %f \n",
1251 art_shal[lvl],art_ave[lvl],art_ood[lvl]);
1252
1253 /* more advanced info */
1254 file_putf(stats_log,"From vaults: %f From floor (no vault): %f \n",
1255 art_vault[lvl],art_floor[lvl]);
1256 file_putf(stats_log,"Uniques: %f Monsters: %f Vault denizens: %f \n",
1257 art_uniq[lvl], art_mon[lvl], art_mon_vault[lvl]);
1258
1259
1260 for (i=ST_BEGIN; i<ST_END; i++){
1261 file_putf(stats_log, "%s%f From Monsters: %f In Vaults: %f \n", stat_message[i].name, stat_all[i][0][lvl], stat_all[i][1][lvl], stat_all[i][2][lvl]);
1262 }
1263
1264
1265 }
1266
1267 /**
1268 *Compute and print the mean and standard deviation for an array of known size
1269 */
mean_and_stdv(int array[TRIES_SIZE])1270 static void mean_and_stdv(int array[TRIES_SIZE])
1271 {
1272 int k, maxiter;
1273 double tot = 0, mean, stdev, temp = 0;
1274
1275 /* Get the maximum iteration value */
1276 maxiter = MIN(tries, TRIES_SIZE);
1277
1278 /* Sum the array */
1279 for (k = 0; k < maxiter; k++)
1280 tot += array[k];
1281
1282 /* Compute the mean */
1283 mean = tot / maxiter;
1284
1285 /* Sum up the squares */
1286 for (k = 0; k < maxiter; k++) temp += (array[k] - mean) * (array[k] - mean);
1287
1288 /* Compute standard dev */
1289 stdev = sqrt(temp / tries);
1290
1291 /* Print to file */
1292 file_putf(stats_log," mean: %f std-dev: %f \n",mean,stdev);
1293
1294 }
1295
1296 /**
1297 * Calculated the probability of finding an item by a specific level,
1298 * and print it to the output file
1299 */
1300
prob_of_find(double stat[MAX_LVL])1301 static void prob_of_find(double stat[MAX_LVL])
1302 {
1303 static int lvl, tmpcount;
1304 double find = 0.0, tmpfind = 0.0;
1305
1306 /* Skip town level */
1307 for (lvl = 1; lvl < MAX_LVL ; lvl++) {
1308
1309 /* Calculate the probability of not finding the stat */
1310 tmpfind=(1 - stat[lvl]);
1311
1312 /* Maximum probability is 98% */
1313 if (tmpfind < 0.02) tmpfind = 0.02;
1314
1315 /* Multiply probabilities of not finding */
1316 if (find <= 0) find = tmpfind; else find *= tmpfind;
1317
1318 /* Increase count to 5 */
1319 tmpcount++;
1320
1321 /* Print output every 5 levels */
1322 if (tmpcount == 5) {
1323
1324 /* print it */
1325 file_putf(stats_log,"%f \t",1-find);
1326
1327 /* reset temp counter */
1328 tmpcount=0;
1329 }
1330 }
1331
1332 /* Put a new line in prep of next entry */
1333 file_putf(stats_log,"\n");
1334 }
1335
1336 #if 0
1337 /**
1338 * Left this function unlinked for now
1339 */
1340 static double total(double stat[MAX_LVL])
1341 {
1342 int k;
1343 double out = 0;
1344
1345 for (k = 0; k < MAX_LVL; k++)
1346 out += stat[k];
1347
1348 return out;
1349 }
1350 #endif
1351
1352 /**
1353 * Post process select items
1354 */
post_process_stats(void)1355 static void post_process_stats(void)
1356 {
1357 double arttot;
1358 int i,k;
1359
1360 /* Output a title */
1361 file_putf(stats_log,"\n");
1362 file_putf(stats_log,"***** POST PROCESSING *****\n");
1363 file_putf(stats_log,"\n");
1364 file_putf(stats_log,"Item \t5\t\t\t10\t\t\t15\t\t\t20\t\t\t25\t\t\t");
1365 file_putf(stats_log,"30\t\t\t35\t\t\t40\t\t\t45\t\t\t50\t\t\t");
1366 file_putf(stats_log,"55\t\t\t60\t\t\t65\t\t\t70\t\t\t75\t\t\t");
1367 file_putf(stats_log,"80\t\t\t85\t\t\t90\t\t\t95\t\t\t100\n");
1368
1369 for (i = 1; i < ST_FF_END; i++) {
1370 file_putf(stats_log, stat_ff_message[i].name);
1371 prob_of_find(stat_all[stat_ff_message[i].st][0]);
1372 mean_and_stdv(stat_ff_all[i]);
1373 }
1374
1375 /* Print artifact total */
1376 arttot = 0;
1377
1378 for (k = 0; k < MAX_LVL; k++)
1379 arttot += art_total[k];
1380
1381 file_putf(stats_log,"\n");
1382 file_putf(stats_log,"Total number of artifacts found %f \n",arttot);
1383 mean_and_stdv(art_it);
1384
1385 /* Temporary stuff goes here */
1386 /* Dungeon book totals for Eddie
1387 file_putf(stats_log,"mb5: %f\n",total(b5_total));
1388 file_putf(stats_log,"mb6: %f\n",total(b6_total));
1389 file_putf(stats_log,"mb7: %f\n",total(b7_total));
1390 file_putf(stats_log,"mb8: %f\n",total(b8_total));
1391 file_putf(stats_log,"mb9: %f\n",total(b9_total));
1392 */
1393 }
1394
1395
1396
1397 /**
1398 * Scans the dungeon for objects
1399 */
scan_for_objects(void)1400 static void scan_for_objects(void)
1401 {
1402 int y, x;
1403
1404 for (y = 1; y < cave->height - 1; y++) {
1405 for (x = 1; x < cave->width - 1; x++) {
1406 struct loc grid = loc(x, y);
1407 struct object *obj;
1408
1409 while ((obj = square_object(cave, grid))) {
1410 /* Get data on the object */
1411 get_obj_data(obj, y, x, false, false);
1412
1413 /* Delete the object */
1414 square_delete_object(cave, grid, obj, false, false);
1415 }
1416 }
1417 }
1418 }
1419
1420 /**
1421 * This will scan the dungeon for monsters and then kill each
1422 * and every last one.
1423 */
scan_for_monsters(void)1424 static void scan_for_monsters(void)
1425 {
1426 int i;
1427
1428 /* Go through the monster list */
1429 for (i = 1; i < cave_monster_max(cave); i++) {
1430 struct monster *mon = cave_monster(cave, i);
1431
1432 /* Skip dead monsters */
1433 if (!mon->race) continue;
1434
1435 stats_monster(mon, i);
1436 }
1437 }
1438
1439 /**
1440 * This is the entry point for generation statistics.
1441 */
stats_collect_level(void)1442 static void stats_collect_level(void)
1443 {
1444 /* Make a dungeon */
1445 prepare_next_level(&cave, player);
1446
1447 /* Scan for objects, these are floor objects */
1448 scan_for_objects();
1449
1450 /* Get stats (and kill) all non-unique monsters */
1451 scan_for_monsters();
1452
1453 }
1454
1455 /**
1456 * This code will go through the artifact list and make each artifact
1457 * uncreated so that our sim player can find them again!
1458 */
uncreate_artifacts(void)1459 static void uncreate_artifacts(void)
1460 {
1461 int i;
1462
1463 /* Loop through artifacts */
1464 for (i = 0; z_info && i < z_info->a_max; i++) {
1465 struct artifact *art = &a_info[i];
1466
1467 /* Uncreate */
1468 art->created = false;
1469 }
1470 }
1471
1472 /**
1473 * This will revive all the uniques so the sim player
1474 * can kill them again.
1475 */
revive_uniques(void)1476 static void revive_uniques(void)
1477 {
1478 int i;
1479
1480 for (i = 1; i < z_info->r_max - 1; i++) {
1481 /* Get the monster info */
1482 struct monster_race *race = &r_info[i];
1483
1484 /* Revive the unique monster */
1485 if (rf_has(race->flags, RF_UNIQUE)) race->max_num = 1;
1486 }
1487 }
1488
1489 /**
1490 * This function loops through the level and does N iterations of
1491 * the stat calling function, assuming diving style.
1492 */
diving_stats(void)1493 static void diving_stats(void)
1494 {
1495 int depth;
1496
1497 /* Iterate through levels */
1498 for (depth = 0; depth < MAX_LVL; depth += 5) {
1499 player->depth = depth;
1500 if (player->depth == 0) player->depth = 1;
1501
1502 /* Do many iterations of each level */
1503 for (iter = 0; iter < tries; iter++)
1504 stats_collect_level();
1505
1506 /* Print the output to the file */
1507 print_stats(depth);
1508
1509 /* Show the level to check on status */
1510 do_cmd_redraw();
1511 }
1512 }
1513
1514 /**
1515 * This function loops through the level and does N iterations of
1516 * the stat calling function, assuming clearing style.
1517 */
clearing_stats(void)1518 static void clearing_stats(void)
1519 {
1520 int depth;
1521
1522 /* Do many iterations of the game */
1523 for (iter = 0; iter < tries; iter++) {
1524 /* Move all artifacts to uncreated */
1525 uncreate_artifacts();
1526
1527 /* Move all uniques to alive */
1528 revive_uniques();
1529
1530 /* Do randart regen */
1531 if ((regen) && (iter<tries)) {
1532 /* Get seed */
1533 int seed_randart = randint0(0x10000000);
1534
1535 /* Restore the standard artifacts */
1536 cleanup_parser(&randart_parser);
1537 deactivate_randart_file();
1538 run_parser(&artifact_parser);
1539
1540 /* regen randarts */
1541 do_randart(seed_randart, false);
1542 }
1543
1544 /* Do game iterations */
1545 for (depth = 1 ; depth < MAX_LVL; depth++) {
1546 /* Debug
1547 msg_format("Attempting level %d",depth); */
1548
1549 /* Move player to that depth */
1550 player->depth = depth;
1551
1552 /* Get stats */
1553 stats_collect_level();
1554
1555 /* Debug
1556 msg_format("Finished level %d,depth"); */
1557 }
1558
1559 msg("Iteration %d complete",iter);
1560 }
1561
1562 /* Restore original artifacts */
1563 if (regen) {
1564 cleanup_parser(&randart_parser);
1565 if (OPT(player, birth_randarts)) {
1566 activate_randart_file();
1567 run_parser(&randart_parser);
1568 deactivate_randart_file();
1569 } else {
1570 run_parser(&artifact_parser);
1571 }
1572 }
1573
1574 /* Print to file */
1575 for (depth = 0 ;depth < MAX_LVL; depth++)
1576 print_stats(depth);
1577
1578 /* Post processing */
1579 post_process_stats();
1580
1581 /* Display the current level */
1582 do_cmd_redraw();
1583 }
1584
1585 /**
1586 * Prompt the user for sim type and number of sims for a stats run
1587 */
stats_prompt(void)1588 static int stats_prompt(void)
1589 {
1590 static int temp,simtype = 1;
1591 static char tmp_val[100];
1592 static char prompt[50];
1593
1594 /* This is the prompt for no. of tries*/
1595 strnfmt(prompt, sizeof(prompt), "Num of simulations: ");
1596
1597 /* This is the default value (50) */
1598 strnfmt(tmp_val, sizeof(tmp_val), "%d", tries);
1599
1600 /* Ask for the input */
1601 if (!get_string(prompt, tmp_val, 7)) return 0;
1602
1603 /* Get the new value */
1604 temp = atoi(tmp_val);
1605
1606 /* Convert */
1607 if (temp < 1) temp = 1;
1608
1609 /* Save */
1610 tries = temp;
1611
1612 /* Set 'value to add' for arrays */
1613 addval = 1.0 / tries;
1614
1615 /* Get info on what type of run to do */
1616 strnfmt(prompt, sizeof(prompt), "Type of Sim: Diving (1) or Clearing (2) ");
1617
1618 /* Set default */
1619 strnfmt(tmp_val, sizeof(tmp_val), "%d", simtype);
1620
1621 /* Get the input */
1622 if (!get_string(prompt, tmp_val, 4)) return 0;
1623
1624 temp = atoi(tmp_val);
1625
1626 /* Make sure that the type is good */
1627 if ((temp == 1) || (temp == 2))
1628 simtype = temp;
1629 else
1630 return 0;
1631
1632 /* For clearing sim, check for randart regen */
1633 if (temp == 2) {
1634 /* Prompt */
1635 strnfmt(prompt, sizeof(prompt), "Regen randarts? (warning SLOW)");
1636
1637 regen = get_check(prompt) ? true : false;
1638 }
1639
1640 return simtype;
1641 }
1642
1643 /**
1644 * This is the function called from wiz-debug.c.
1645 */
stats_collect(void)1646 void stats_collect(void)
1647 {
1648 static int simtype;
1649 static bool auto_flag;
1650 char buf[1024];
1651
1652 /* Prompt the user for sim params */
1653 simtype = stats_prompt();
1654
1655 /* Make sure the results are good! */
1656 if (!((simtype == 1) || (simtype == 2)))
1657 return;
1658
1659 /* Are we in diving or clearing mode */
1660 if (simtype == 2)
1661 clearing = true;
1662 else
1663 clearing = false;
1664
1665 /* Open log file */
1666 path_build(buf, sizeof(buf), ANGBAND_DIR_USER, "stats.log");
1667 stats_log = file_open(buf, MODE_WRITE, FTYPE_TEXT);
1668
1669 /* Logging didn't work */
1670 if (!stats_log) {
1671 msg("Error - can't open stats.log for writing.");
1672 exit(1);
1673 }
1674
1675 /* Turn on auto-more. This will clear prompts for items
1676 * that drop under the player, or that can't fit on the
1677 * floor due to too many items. This is a very small amount
1678 * of items, even on deeper levels, so it's not worth worrying
1679 * too much about.
1680 */
1681 auto_flag = false;
1682
1683 if (!OPT(player, auto_more)) {
1684 /* Remember that we turned off auto_more */
1685 auto_flag = true;
1686
1687 /* Turn on auto-more */
1688 option_set(option_name(OPT_auto_more),true);
1689 }
1690
1691 /* Print heading for the file */
1692 print_heading();
1693
1694 /* Make sure all stats are 0 */
1695 init_stat_vals();
1696
1697 /* Select diving option */
1698 if (!clearing) diving_stats();
1699
1700 /* Select clearing option */
1701 if (clearing) clearing_stats();
1702
1703 /* Turn auto-more back off */
1704 if (auto_flag) option_set(option_name(OPT_auto_more), false);
1705
1706 /* Close log file */
1707 if (!file_close(stats_log)) {
1708 msg("Error - can't close stats.log file.");
1709 exit(1);
1710 }
1711 }
1712
1713 #define DIST_MAX 10000
1714
calc_cave_distances(int ** cave_dist)1715 void calc_cave_distances(int **cave_dist)
1716 {
1717 int dist;
1718
1719 /* Squares with distance from player of n - 1 */
1720 struct loc *ogrids;
1721 int n_old, cap_old;
1722
1723 /* Squares with distance from player of n */
1724 struct loc *ngrids;
1725 int n_new, cap_new;
1726
1727 /*
1728 * The perimeter of the cave should overestimate the space needed so
1729 * there's fewer reallocations within the loop.
1730 */
1731 cap_old = 2 * (cave->width + cave->height - 1);
1732 ogrids = mem_alloc(cap_old * sizeof(*ogrids));
1733 cap_new = cap_old;
1734 ngrids = mem_alloc(cap_new * sizeof(*ngrids));
1735
1736 /* The player's location is the first one to test. */
1737 ogrids[0] = player->grid;
1738 n_old = 1;
1739
1740 /* Distance from player starts at 0 */
1741 dist = 0;
1742
1743 /* Assign the distance value to the first square (player) */
1744 cave_dist[ogrids[0].y][ogrids[0].x] = dist;
1745
1746 do {
1747 int i, n_tmp;
1748 struct loc *gtmp;
1749
1750 n_new = 0;
1751 dist++;
1752
1753 /* Loop over all visited squares of the previous iteration */
1754 for (i = 0; i < n_old; i++){
1755 int d;
1756 /* Get the square we want to look at */
1757 int oy = ogrids[i].y;
1758 int ox = ogrids[i].x;
1759
1760 /* debug
1761 msg("x: %d y: %d dist: %d %d ",ox,oy,dist-1,i); */
1762
1763 /* Get all adjacent squares */
1764 for (d = 0; d < 8; d++) {
1765 /* Adjacent square location */
1766 int ty = oy + ddy_ddd[d];
1767 int tx = ox + ddx_ddd[d];
1768
1769 if (!(square_in_bounds_fully(cave, loc(tx, ty)))) continue;
1770
1771 /* Have we been here before? */
1772 if (cave_dist[ty][tx] >= 0) continue;
1773
1774 /*
1775 * Impassable terrain which isn't a door or
1776 * rubble blocks progress.
1777 */
1778 if (!square_ispassable(cave, loc(tx, ty)) &&
1779 !square_isdoor(cave, loc(tx, ty)) &&
1780 !square_isrubble(cave, loc(tx, ty))) continue;
1781
1782 /* Add the new location */
1783 if (n_new == cap_new - 1) {
1784 cap_new *= 2;
1785 ngrids = mem_realloc(ngrids,
1786 cap_new * sizeof(ngrids));
1787 }
1788 ngrids[n_new].y = ty;
1789 ngrids[n_new].x = tx;
1790 ++n_new;
1791
1792 /* Assign the distance to that spot */
1793 cave_dist[ty][tx] = dist;
1794
1795 /* debug
1796 msg("x: %d y: %d dist: %d ",tx,ty,dist); */
1797 }
1798 }
1799
1800 /* Swap the lists; do not need to preserve n_old. */
1801 gtmp = ogrids;
1802 ogrids = ngrids;
1803 ngrids = gtmp;
1804 n_tmp = cap_old;
1805 cap_old = cap_new;
1806 cap_new = n_tmp;
1807 n_old = n_new;
1808 } while (n_old > 0 && dist < DIST_MAX);
1809
1810 mem_free(ngrids);
1811 mem_free(ogrids);
1812 }
1813
pit_stats(void)1814 void pit_stats(void)
1815 {
1816 int tries = 1000;
1817 int depth = 0;
1818 int hist[z_info->pit_max];
1819 int j, p;
1820 int type = 1;
1821
1822 char tmp_val[100];
1823
1824 /* Initialize hist */
1825 for (p = 0; p < z_info->pit_max; p++)
1826 hist[p] = 0;
1827
1828 /* Format default value */
1829 strnfmt(tmp_val, sizeof(tmp_val), "%d", tries);
1830
1831 /* Ask for the input - take the first 7 characters*/
1832 if (!get_string("Num of simulations: ", tmp_val, 7)) return;
1833
1834 /* Get the new value */
1835 tries = atoi(tmp_val);
1836 if (tries < 1) tries = 1;
1837
1838 /* Format second default value */
1839 strnfmt(tmp_val, sizeof(tmp_val), "%d", type);
1840
1841 /* Ask for the input - take the first 7 characters*/
1842 if (!get_string("Pit type: ", tmp_val, 7)) return;
1843
1844 /* get the new value */
1845 type = atoi(tmp_val);
1846 if (type < 1) type = 1;
1847
1848 /* Format second default value */
1849 strnfmt(tmp_val, sizeof(tmp_val), "%d", player->depth);
1850
1851 /* Ask for the input - take the first 7 characters*/
1852 if (!get_string("Depth: ", tmp_val, 7)) return;
1853
1854 /* get the new value */
1855 depth = atoi(tmp_val);
1856 if (depth < 1) depth = 1;
1857
1858 for (j = 0; j < tries; j++) {
1859 int i;
1860 int pit_idx = 0;
1861 int pit_dist = 999;
1862
1863 for (i = 0; i < z_info->pit_max; i++) {
1864 int offset, dist;
1865 struct pit_profile *pit = &pit_info[i];
1866
1867 if (!pit->name || pit->room_type != type) continue;
1868
1869 offset = Rand_normal(pit->ave, 10);
1870 dist = ABS(offset - depth);
1871
1872 if (dist < pit_dist && one_in_(pit->rarity)) {
1873 pit_idx = i;
1874 pit_dist = dist;
1875 }
1876 }
1877
1878 hist[pit_idx]++;
1879 }
1880
1881 for (p = 0; p < z_info->pit_max; p++) {
1882 struct pit_profile *pit = &pit_info[p];
1883 if (pit->name)
1884 msg("Type: %s, Number: %d.", pit->name, hist[p]);
1885 }
1886
1887 return;
1888 }
1889
1890
1891 /**
1892 * Gather whether the dungeon has disconnects in it and whether the player
1893 * is disconnected from the stairs
1894 */
disconnect_stats(void)1895 void disconnect_stats(void)
1896 {
1897 int i, y, x;
1898
1899 int **cave_dist;
1900
1901 bool has_dsc, has_dsc_from_stairs;
1902
1903 static int temp;
1904 static char tmp_val[100];
1905 static char prompt[50];
1906
1907 long dsc_area = 0, dsc_from_stairs = 0;
1908 bool stop_for_dis;
1909 char path[1024];
1910 ang_file *disfile;
1911
1912 /* This is the prompt for no. of tries */
1913 strnfmt(prompt, sizeof(prompt), "Num of simulations: ");
1914
1915 /* This is the default value (50) */
1916 strnfmt(tmp_val, sizeof(tmp_val), "%d", tries);
1917
1918 /* Ask for the input */
1919 if (!get_string(prompt,tmp_val,7)) return;
1920
1921 /* Get the new value */
1922 temp = atoi(tmp_val);
1923
1924 /* Try at least once */
1925 if (temp < 1)
1926 temp = 1;
1927
1928 /* Save */
1929 tries = temp;
1930
1931 stop_for_dis = get_check("Stop if disconnected level found? ");
1932
1933 path_build(path, sizeof(path), ANGBAND_DIR_USER, "disconnect.html");
1934 disfile = file_open(path, MODE_WRITE, FTYPE_TEXT);
1935 if (disfile) {
1936 dump_level_header(disfile, "Disconnected Levels");
1937 }
1938
1939 for (i = 1; i <= tries; i++) {
1940 /* Assume no disconnected areas */
1941 has_dsc = false;
1942
1943 /* Assume you can't get to stairs */
1944 has_dsc_from_stairs = true;
1945
1946 /* Make a new cave */
1947 prepare_next_level(&cave, player);
1948
1949 /* Allocate the distance array */
1950 cave_dist = mem_zalloc(cave->height * sizeof(int*));
1951 for (y = 0; y < cave->height; y++)
1952 cave_dist[y] = mem_zalloc(cave->width * sizeof(int));
1953
1954 /* Set all cave spots to inaccessible */
1955 for (y = 0; y < cave->height; y++)
1956 for (x = 1; x < cave->width; x++)
1957 cave_dist[y][x] = -1;
1958
1959 /* Fill the distance array with the correct distances */
1960 calc_cave_distances(cave_dist);
1961
1962 /* Cycle through the dungeon */
1963 for (y = 1; y < cave->height - 1; y++) {
1964 for (x = 1; x < cave->width - 1; x++) {
1965 struct loc grid = loc(x, y);
1966
1967 /*
1968 * Don't care about impassable terrain that's
1969 * not a closed or secret door or impassable
1970 * rubble.
1971 */
1972 if (!square_ispassable(cave, grid) &&
1973 !square_isdoor(cave, grid) &&
1974 !square_isrubble(cave, grid)) continue;
1975
1976 /* Can we get there? */
1977 if (cave_dist[y][x] >= 0) {
1978
1979 /* Is it a down stairs? */
1980 if (square_isdownstairs(cave, grid)) {
1981
1982 has_dsc_from_stairs = false;
1983
1984 /* debug
1985 msg("dist to stairs: %d",cave_dist[y][x]); */
1986 }
1987 continue;
1988 }
1989
1990 /* Ignore vaults as they are often disconnected */
1991 if (square_isvault(cave, grid)) continue;
1992
1993 /* We have a disconnected area */
1994 has_dsc = true;
1995 }
1996 }
1997
1998 if (has_dsc_from_stairs) dsc_from_stairs++;
1999
2000 if (has_dsc) dsc_area++;
2001
2002 if (has_dsc || has_dsc_from_stairs) {
2003 if (disfile) {
2004 dump_level_body(disfile, "Disconnected Level",
2005 cave, cave_dist);
2006 }
2007 if (stop_for_dis) i = tries;
2008 }
2009
2010 /* Free arrays */
2011 for (y = 0; y < cave->height; y++)
2012 mem_free(cave_dist[y]);
2013 mem_free(cave_dist);
2014 }
2015
2016 msg("Total levels with disconnected areas: %ld",dsc_area);
2017 msg("Total levels isolated from stairs: %ld",dsc_from_stairs);
2018 if (disfile) {
2019 dump_level_footer(disfile);
2020 if (file_close(disfile)) {
2021 msg("Map is in disconnect.html.");
2022 }
2023 }
2024
2025 /* Redraw the level */
2026 do_cmd_redraw();
2027 }
2028
2029
2030 #else /* USE_STATS */
2031
stats_collect(void)2032 void stats_collect(void)
2033 {
2034 msg("Statistics generation not turned on in this build.");
2035 }
2036
disconnect_stats(void)2037 void disconnect_stats(void)
2038 {
2039 msg("Statistics generation not turned on in this build.");
2040 }
2041
pit_stats(void)2042 void pit_stats(void)
2043 {
2044 msg("Statistics generation not turned on in this build.");
2045 }
2046 #endif /* USE_STATS */
2047