summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crawl-ref/source/acr.cc21
-rw-r--r--crawl-ref/source/dat/descript.txt1
-rw-r--r--crawl-ref/source/debug.cc139
-rw-r--r--crawl-ref/source/debug.h8
-rw-r--r--crawl-ref/source/dungeon.cc16
-rw-r--r--crawl-ref/source/dungeon.h2
-rw-r--r--crawl-ref/source/externs.h12
-rw-r--r--crawl-ref/source/initfile.cc22
-rw-r--r--crawl-ref/source/maps.cc15
9 files changed, 210 insertions, 26 deletions
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc
index 71d9ccc754..c8e75f5b61 100644
--- a/crawl-ref/source/acr.cc
+++ b/crawl-ref/source/acr.cc
@@ -1638,7 +1638,8 @@ static void decrement_durations()
you.duration[DUR_REPEL_MISSILES]--;
if (you.duration[DUR_REPEL_MISSILES] == 6)
{
- mpr("Your repel missiles spell is about to expire...", MSGCH_DURATION);
+ mpr("Your repel missiles spell is about to expire...",
+ MSGCH_DURATION);
if (coinflip())
you.duration[DUR_REPEL_MISSILES]--;
}
@@ -1654,7 +1655,8 @@ static void decrement_durations()
you.duration[DUR_DEFLECT_MISSILES]--;
if (you.duration[DUR_DEFLECT_MISSILES] == 6)
{
- mpr("Your deflect missiles spell is about to expire...", MSGCH_DURATION);
+ mpr("Your deflect missiles spell is about to expire...",
+ MSGCH_DURATION);
if (coinflip())
you.duration[DUR_DEFLECT_MISSILES]--;
}
@@ -1726,8 +1728,6 @@ static void decrement_durations()
break;
case SPWPN_DISTORTION:
msg += " seems straighter.";
- // [dshaligram] Makes the brand unusable
- // miscast_effect( SPTYP_TRANSLOCATION, 9, 90, 100, "a distortion effect" );
break;
case SPWPN_PAIN:
msg += " seems less painful.";
@@ -3016,15 +3016,18 @@ static bool initialise(void)
// system initialisation stuff:
textbackground(0);
-#ifdef DOS
- directvideo = 1;
-#endif
-
clrscr();
+#ifdef DEBUG_DIAGNOSTICS
+ if (crawl_state.map_stat_gen)
+ {
+ generate_map_stats();
+ end(0, false);
+ }
+#endif
+
// sets up a new game:
const bool newc = new_game();
-
if (!newc)
restore_game();
diff --git a/crawl-ref/source/dat/descript.txt b/crawl-ref/source/dat/descript.txt
index fbe3ee1f12..e88f8c0501 100644
--- a/crawl-ref/source/dat/descript.txt
+++ b/crawl-ref/source/dat/descript.txt
@@ -92,6 +92,7 @@ A small twisted demon with a long, sharply pointed tail.
%%%%
rat
Wherever there are men, there are rats -- rattus rattus. This rat has grown large and aggressive in the pestilential dungeon environment.
+
How now? a rat? Dead, for a ducat, dead!
-William Shakespeare, Hamlet, Act III, 4
%%%%
diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc
index 903180a9c0..92dfd46534 100644
--- a/crawl-ref/source/debug.cc
+++ b/crawl-ref/source/debug.cc
@@ -51,6 +51,8 @@
#include "item_use.h"
#include "items.h"
#include "makeitem.h"
+#include "mapdef.h"
+#include "maps.h"
#include "misc.h"
#include "monplace.h"
#include "monstuff.h"
@@ -2116,3 +2118,140 @@ void debug_card()
}
#endif
+
+#ifdef DEBUG_DIAGNOSTICS
+
+// Map statistics generation.
+
+std::map<std::string, int> mapgen_try_count;
+std::map<std::string, int> mapgen_use_count;
+std::map<level_id, int> mapgen_level_maps;
+std::map<std::string, std::string> mapgen_errors;
+std::string mapgen_last_error;
+
+static int mg_levels_tried = 0, mg_levels_failed = 0;
+static void mg_build_levels(int niters)
+{
+ mesclr();
+ mprf("Generating dungeon map stats");
+
+ for (int br = BRANCH_MAIN_DUNGEON; br < NUM_BRANCHES; ++br)
+ {
+ if (branches[br].depth == -1)
+ continue;
+
+ const branch_type branch = static_cast<branch_type>(br);
+ for (int depth = 1; depth <= branches[br].depth; ++depth)
+ {
+ you.your_level = absdungeon_depth(branch, depth);
+ you.where_are_you = branch;
+ you.level_type = LEVEL_DUNGEON;
+
+ mesclr();
+ mprf("On %s (%d); %d levels, %d failed, %d errors%s, %d maps",
+ level_id::current().describe().c_str(), niters,
+ mg_levels_tried, mg_levels_failed, mapgen_errors.size(),
+ mapgen_last_error.empty()? ""
+ : (" (" + mapgen_last_error + ")").c_str(),
+ mapgen_use_count.size());
+
+ no_messages mx;
+ for (int i = 0; i < niters; ++i)
+ {
+ if (kbhit() && getch() == ESCAPE)
+ return;
+ ++mg_levels_tried;
+ if (!builder(you.your_level, you.level_type))
+ ++mg_levels_failed;
+ }
+ }
+ }
+}
+
+void mapgen_report_map_try(const map_def &map)
+{
+ mapgen_try_count[map.name]++;
+ mapgen_level_maps[level_id::current()]++;
+}
+
+void mapgen_report_map_use(const map_def &map)
+{
+ mapgen_use_count[map.name]++;
+}
+
+void mapgen_report_error(const map_def &map, const std::string &err)
+{
+ mapgen_last_error = err;
+}
+
+static void write_mapgen_stats()
+{
+ FILE *outf = fopen("mapgen.log", "w");
+ fprintf(outf, "Map Generation Stats\n\n");
+ fprintf(outf, "Levels attempted: %d, built: %d, failed: %d\n",
+ mg_levels_tried, mg_levels_tried - mg_levels_failed,
+ mg_levels_failed);
+
+ if (!mapgen_errors.empty())
+ {
+ fprintf(outf, "\n\nMap errors:\n");
+ for (std::map<std::string, std::string>::const_iterator i =
+ mapgen_errors.begin(); i != mapgen_errors.end(); ++i)
+ {
+ fprintf(outf, "%s: %s\n",
+ i->first.c_str(), i->second.c_str());
+ }
+ }
+
+ std::vector<level_id> mapless;
+ for (int i = BRANCH_MAIN_DUNGEON; i < NUM_BRANCHES; ++i)
+ {
+ if (branches[i].depth == -1)
+ continue;
+
+ const branch_type br = static_cast<branch_type>(i);
+ for (int dep = 1; dep <= branches[i].depth; ++i)
+ {
+ const level_id lid(br, dep);
+ if (mapgen_level_maps.find(lid) == mapgen_level_maps.end())
+ mapless.push_back(lid);
+ }
+ }
+
+ if (!mapless.empty())
+ {
+ fprintf(outf, "\n\nLevels with no maps:\n");
+ for (int i = 0, size = mapless.size(); i < size; ++i)
+ fprintf(outf, "%d) %s\n", i + 1, mapless[i].describe().c_str());
+ }
+
+ fprintf(outf, "\n\nMaps used:\n\n");
+ std::multimap<int, std::string> usedmaps;
+ for (std::map<std::string, int>::const_iterator i =
+ mapgen_try_count.begin(); i != mapgen_try_count.end(); ++i)
+ usedmaps.insert(std::pair<int, std::string>(i->second, i->first));
+
+ for (std::multimap<int, std::string>::const_reverse_iterator i =
+ usedmaps.rbegin(); i != usedmaps.rend(); ++i)
+ {
+ const int tries = i->first;
+ std::map<std::string, int>::const_iterator iuse =
+ mapgen_use_count.find(i->second);
+ const int uses = iuse == mapgen_use_count.end()? 0 : iuse->second;
+ if (tries == uses)
+ fprintf(outf, "%4d : %s\n", tries, i->second.c_str());
+ else
+ fprintf(outf, "%4d (%4d): %s\n", uses, tries, i->second.c_str());
+ }
+ fclose(outf);
+}
+
+void generate_map_stats()
+{
+ // We have to run map preludes ourselves.
+ run_map_preludes();
+ mg_build_levels(SysEnv.map_gen_iters);
+ write_mapgen_stats();
+}
+
+#endif // DEBUG_DIAGNOSTICS
diff --git a/crawl-ref/source/debug.h b/crawl-ref/source/debug.h
index 3e647052df..fe9efa0340 100644
--- a/crawl-ref/source/debug.h
+++ b/crawl-ref/source/debug.h
@@ -152,4 +152,12 @@ void debug_set_stats( void );
void debug_card();
+#ifdef DEBUG_DIAGNOSTICS
+void generate_map_stats();
+class map_def;
+void mapgen_report_map_try(const map_def &map);
+void mapgen_report_map_use(const map_def &map);
+void mapgen_report_error(const map_def &map, const std::string &err);
+#endif
+
#endif
diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc
index 6ef81ba2d4..b7229487e3 100644
--- a/crawl-ref/source/dungeon.cc
+++ b/crawl-ref/source/dungeon.cc
@@ -233,7 +233,7 @@ static void place_altars()
/**********************************************************************
* builder() - kickoff for the dungeon generator.
*********************************************************************/
-void builder(int level_number, int level_type)
+bool builder(int level_number, int level_type)
{
// N tries to build the level, after which we bail with a capital B.
int tries = 20;
@@ -243,13 +243,17 @@ void builder(int level_number, int level_type)
build_dungeon_level(level_number, level_type);
if (!dgn_level_vetoed && valid_dungeon_level(level_number, level_type))
- return;
+ return (true);
}
- // Failed to build level, bail out.
- save_game(true,
- make_stringf("Unable to generate level for '%s'!",
- level_id::current().describe().c_str()).c_str());
+ if (!crawl_state.map_stat_gen)
+ {
+ // Failed to build level, bail out.
+ save_game(true,
+ make_stringf("Unable to generate level for '%s'!",
+ level_id::current().describe().c_str()).c_str());
+ }
+ return (false);
}
static void mask_vault(const vault_placement &place, unsigned mask)
diff --git a/crawl-ref/source/dungeon.h b/crawl-ref/source/dungeon.h
index 60d953c931..8912d1d252 100644
--- a/crawl-ref/source/dungeon.h
+++ b/crawl-ref/source/dungeon.h
@@ -110,7 +110,7 @@ struct dgn_region
bool overlaps(const map_mask &dgn_map_mask) const;
};
-void builder(int level_number, int level_type);
+bool builder(int level_number, int level_type);
void define_zombie(int mid, int ztype, int cs, int power);
bool is_wall(int feature);
bool place_specific_trap(int spec_x, int spec_y, trap_type spec_type);
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index 994fa1dd22..8477dfad3a 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -1278,8 +1278,10 @@ struct game_state
bool saving_game; // Set to true while in save_game.
bool updating_scores; // Set to true while updating hiscores.
- int seen_hups; // Set to true if SIGHUP received.
+ int seen_hups; // Set to true if SIGHUP received.
+ bool map_stat_gen; // Set if we're generating stats on maps.
+
bool unicode_ok; // Is unicode support available?
std::string (*glyph2strfn)(unsigned glyph);
@@ -1290,9 +1292,9 @@ struct game_state
game_state() : mouse_enabled(false), waiting_for_command(false),
terminal_resized(false), io_inited(false), need_save(false),
saving_game(false), updating_scores(false),
- seen_hups(0), unicode_ok(false), glyph2strfn(NULL),
- multibyte_strlen(NULL), terminal_resize_handler(NULL),
- terminal_resize_check(NULL)
+ seen_hups(0), map_stat_gen(false), unicode_ok(false),
+ glyph2strfn(NULL), multibyte_strlen(NULL),
+ terminal_resize_handler(NULL), terminal_resize_check(NULL)
{
}
@@ -1351,6 +1353,8 @@ struct system_environment
std::string scorefile;
std::vector<std::string> cmd_args;
+
+ int map_gen_iters;
};
extern system_environment SysEnv;
diff --git a/crawl-ref/source/initfile.cc b/crawl-ref/source/initfile.cc
index 73b10fc005..82d888ed4f 100644
--- a/crawl-ref/source/initfile.cc
+++ b/crawl-ref/source/initfile.cc
@@ -586,7 +586,7 @@ void game_options::reset_options()
prev_weapon = WPN_UNKNOWN;
prev_book = SBT_NO_SELECTION;
prev_randpick = false;
- remember_name = false;
+ remember_name = true;
#ifdef USE_ASCII_CHARACTERS
char_set = CSET_ASCII;
@@ -2548,6 +2548,7 @@ enum commandline_option_type {
CLO_SCOREFILE,
CLO_MORGUE,
CLO_MACRO,
+ CLO_MAPSTAT,
CLO_NOPS
};
@@ -2555,7 +2556,7 @@ enum commandline_option_type {
static const char *cmd_ops[] = { "scores", "name", "race", "class",
"pizza", "plain", "dir", "rc", "tscores",
"vscores", "scorefile", "morgue",
- "macro" };
+ "macro", "mapstat" };
const int num_cmd_ops = CLO_NOPS;
bool arg_seen[num_cmd_ops];
@@ -2671,6 +2672,20 @@ bool parse_args( int argc, char **argv, bool rc_only )
}
break;
+ case CLO_MAPSTAT:
+ crawl_state.map_stat_gen = true;
+ if (next_is_param)
+ {
+ SysEnv.map_gen_iters = atoi(next_arg);
+ if (SysEnv.map_gen_iters < 1)
+ SysEnv.map_gen_iters = 1;
+ else if (SysEnv.map_gen_iters > 10000)
+ SysEnv.map_gen_iters = 10000;
+ }
+ else
+ SysEnv.map_gen_iters = 100;
+ break;
+
case CLO_MACRO:
if (!next_is_param)
return (false);
@@ -2708,9 +2723,6 @@ bool parse_args( int argc, char **argv, bool rc_only )
if (!next_is_param)
return (false);
- // if (strlen(next_arg) != 1)
- // return (false);
-
if (!rc_only)
{
if (o == 2)
diff --git a/crawl-ref/source/maps.cc b/crawl-ref/source/maps.cc
index d2d63f6eef..a71392ce46 100644
--- a/crawl-ref/source/maps.cc
+++ b/crawl-ref/source/maps.cc
@@ -63,6 +63,8 @@ int vault_main(
#ifdef DEBUG_DIAGNOSTICS
mprf(MSGCH_DIAGNOSTICS, "Generating level: %s",
vdefs[which_vault].name.c_str());
+ if (crawl_state.map_stat_gen)
+ mapgen_report_map_try(vdefs[which_vault]);
#endif
// first, fill in entirely with walls and null-terminate {dlb}:
@@ -78,7 +80,14 @@ int vault_main(
// Return value of zero forces dungeon.cc to regenerate the level, except
// for branch entry vaults where dungeon.cc just rejects the vault and
// places a vanilla entry.
- return write_vault( vdefs[which_vault], vgrid, place, avoid );
+ const int result = write_vault( vdefs[which_vault], vgrid, place, avoid );
+
+#ifdef DEBUG_DIAGNOSTICS
+ if (crawl_state.map_stat_gen && result > 0)
+ mapgen_report_map_use(vdefs[which_vault]);
+#endif
+
+ return (result);
}
static int write_vault(map_def &mdef, map_type map,
@@ -117,6 +126,10 @@ static bool resolve_map(map_def &map, const map_def &original)
std::string err = map.run_lua(true);
if (!err.empty())
{
+#ifdef DEBUG_DIAGNOSTICS
+ if (crawl_state.map_stat_gen)
+ mapgen_report_error(map, err);
+#endif
mprf(MSGCH_WARN, "Lua error: %s", err.c_str());
return (false);
}