diff options
author | Matthew Cline <zelgadis@sourceforge.net> | 2009-11-06 19:26:31 -0800 |
---|---|---|
committer | Matthew Cline <zelgadis@sourceforge.net> | 2009-11-06 19:26:31 -0800 |
commit | be871d682e8087ab38c5e9e054190daf6f81fff2 (patch) | |
tree | e31a44ad0f851c3946f6d665021bb9b206dd5a66 /crawl-ref/source/dbg-scan.cc | |
parent | 8051b93a756f55ba7985f4e6ffe4a833ce0b41cb (diff) | |
download | crawl-ref-be871d682e8087ab38c5e9e054190daf6f81fff2.tar.gz crawl-ref-be871d682e8087ab38c5e9e054190daf6f81fff2.zip |
Split up debug.cc
Diffstat (limited to 'crawl-ref/source/dbg-scan.cc')
-rw-r--r-- | crawl-ref/source/dbg-scan.cc | 531 |
1 files changed, 531 insertions, 0 deletions
diff --git a/crawl-ref/source/dbg-scan.cc b/crawl-ref/source/dbg-scan.cc new file mode 100644 index 0000000000..15981d2a5b --- /dev/null +++ b/crawl-ref/source/dbg-scan.cc @@ -0,0 +1,531 @@ +/* + * File: dbg-scan.cc + * Summary: Debugging code to scan the list of items and monsters. + * Written by: Linley Henzell and Jesse Jones + */ + +#include "AppHdr.h" + +#include "dbg-scan.h" + +#include "artefact.h" +#include "coord.h" +#include "coordit.h" +#include "dbg-util.h" +#include "dungeon.h" +#include "itemname.h" +#include "message.h" +#include "mon-util.h" +#include "state.h" + +#define DEBUG_ITEM_SCAN 1 +#if DEBUG_ITEM_SCAN +static void _dump_item( const char *name, int num, const item_def &item ) +{ + mpr(name, MSGCH_ERROR); + + mprf(" item #%d: base: %d; sub: %d; plus: %d; plus2: %d; special: %ld", + num, item.base_type, item.sub_type, + item.plus, item.plus2, item.special ); + + mprf(" quant: %d; colour: %d; ident: 0x%08lx; ident_type: %d", + item.quantity, item.colour, item.flags, + get_ident_type( item ) ); + + mprf(" x: %d; y: %d; link: %d", item.pos.x, item.pos.y, item.link ); + + crawl_state.cancel_cmd_repeat(); +} + +//--------------------------------------------------------------- +// +// debug_item_scan +// +//--------------------------------------------------------------- +void debug_item_scan( void ) +{ + int i; + char name[256]; + + FixedVector<bool, MAX_ITEMS> visited; + visited.init(false); + + // First we're going to check all the stacks on the level: + for (rectangle_iterator ri(0); ri; ++ri) + { + // Unlinked temporary items. + if (*ri == coord_def()) + continue; + + // Looking for infinite stacks (ie more links than items allowed) + // and for items which have bad coordinates (can't find their stack) + for (int obj = igrd(*ri); obj != NON_ITEM; obj = mitm[obj].link) + { + if (obj < 0 || obj > MAX_ITEMS) + { + if (igrd(*ri) == obj) + { + mprf(MSGCH_ERROR, "Igrd has invalid item index %d " + "at (%d, %d)", + obj, ri->x, ri->y); + } + else + { + mprf(MSGCH_ERROR, "Item in stack at (%d, %d) has ", + "invalid link %d", + ri->x, ri->y, obj); + } + break; + } + + // Check for invalid (zero quantity) items that are linked in. + if (!mitm[obj].is_valid()) + { + mprf(MSGCH_ERROR, "Linked invalid item at (%d,%d)!", + ri->x, ri->y); + _dump_item( mitm[obj].name(DESC_PLAIN).c_str(), obj, mitm[obj] ); + } + + // Check that item knows what stack it's in. + if (mitm[obj].pos != *ri) + { + mprf(MSGCH_ERROR,"Item position incorrect at (%d,%d)!", + ri->x, ri->y); + _dump_item( mitm[obj].name(DESC_PLAIN).c_str(), + obj, mitm[obj] ); + } + + // If we run into a premarked item we're in real trouble, + // this will also keep this from being an infinite loop. + if (visited[obj]) + { + mprf(MSGCH_ERROR, + "Potential INFINITE STACK at (%d, %d)", ri->x, ri->y); + break; + } + visited[obj] = true; + } + } + + // Now scan all the items on the level: + for (i = 0; i < MAX_ITEMS; ++i) + { + if (!mitm[i].is_valid()) + continue; + + strcpy(name, mitm[i].name(DESC_PLAIN).c_str()); + + const monsters* mon = mitm[i].holding_monster(); + + // Don't check (-1, -1) player items or (-2, -2) monster items + // (except to make sure that the monster is alive). + if (mitm[i].pos.origin()) + { + mpr("Unlinked temporary item:", MSGCH_ERROR); + _dump_item( name, i, mitm[i] ); + } + else if (mon != NULL && mon->type == MONS_NO_MONSTER) + { + mpr("Unlinked item held by dead monster:", MSGCH_ERROR); + _dump_item( name, i, mitm[i] ); + } + else if ((mitm[i].pos.x > 0 || mitm[i].pos.y > 0) && !visited[i]) + { + mpr("Unlinked item:", MSGCH_ERROR); + _dump_item( name, i, mitm[i] ); + + if (!in_bounds(mitm[i].pos)) + { + mprf(MSGCH_ERROR, "Item position (%d, %d) is out of bounds", + mitm[i].pos.x, mitm[i].pos.y); + } + else + { + mprf("igrd(%d,%d) = %d", + mitm[i].pos.x, mitm[i].pos.y, igrd( mitm[i].pos )); + } + + // Let's check to see if it's an errant monster object: + for (int j = 0; j < MAX_MONSTERS; ++j) + for (int k = 0; k < NUM_MONSTER_SLOTS; ++k) + { + if (menv[j].inv[k] == i) + { + mprf("Held by monster #%d: %s at (%d,%d)", + j, menv[j].name(DESC_CAP_A, true).c_str(), + menv[j].pos().x, menv[j].pos().y); + } + } + } + + // Current bad items of interest: + // -- armour and weapons with large enchantments/illegal special vals + // + // -- items described as questionable (the class 100 bug) + // + // -- eggplant is an illegal throwing weapon + // + // -- bola is an illegal fixed artefact + // + // -- items described as buggy (typically adjectives out of range) + // (note: covers buggy, bugginess, buggily, whatever else) + // + if (strstr( name, "questionable" ) != NULL + || strstr( name, "eggplant" ) != NULL + || strstr( name, "bola" ) != NULL + || strstr( name, "bugg" ) != NULL) + { + mpr("Bad item:", MSGCH_ERROR); + _dump_item( name, i, mitm[i] ); + } + else if ((mitm[i].base_type == OBJ_WEAPONS + && (abs(mitm[i].plus) > 30 + || abs(mitm[i].plus2) > 30 + || !is_artefact( mitm[i] ) + && mitm[i].special >= NUM_SPECIAL_WEAPONS)) + + || (mitm[i].base_type == OBJ_MISSILES + && (abs(mitm[i].plus) > 25 + || !is_artefact( mitm[i] ) + && mitm[i].special >= NUM_SPECIAL_MISSILES)) + + || (mitm[i].base_type == OBJ_ARMOUR + && (abs(mitm[i].plus) > 25 + || !is_artefact( mitm[i] ) + && mitm[i].special >= NUM_SPECIAL_ARMOURS))) + { + mpr("Bad plus or special value:", MSGCH_ERROR); + _dump_item( name, i, mitm[i] ); + } + else if (mitm[i].flags & ISFLAG_SUMMONED + && in_bounds(mitm[i].pos)) + { + mpr("Summoned item on floor:", MSGCH_ERROR); + _dump_item( name, i, mitm[i] ); + } + } + + // Quickly scan monsters for "program bug"s. + for (i = 0; i < MAX_MONSTERS; ++i) + { + const monsters& monster = menv[i]; + + if (monster.type == MONS_NO_MONSTER) + continue; + + if (monster.name(DESC_PLAIN, true).find("questionable") != + std::string::npos) + { + mprf(MSGCH_ERROR, "Program bug detected!"); + mprf(MSGCH_ERROR, + "Buggy monster detected: monster #%d; position (%d,%d)", + i, monster.pos().x, monster.pos().y); + } + } +} +#endif + +#define DEBUG_MONS_SCAN 1 +#if DEBUG_MONS_SCAN +static void _announce_level_prob(bool warned) +{ + if (!warned && Generating_Level) + { + mpr("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", MSGCH_ERROR); + mpr("mgrd problem occurred during level generation", MSGCH_ERROR); + + debug_dump_levgen(); + } +} + +static bool _inside_vault(const vault_placement& place, const coord_def &pos) +{ + const coord_def delta = pos - place.pos; + + return (delta.x >= 0 && delta.y >= 0 + && delta.x < place.size.x && delta.y < place.size.y); +} + +static std::vector<std::string> _in_vaults(const coord_def &pos) +{ + std::vector<std::string> out; + + for (unsigned int i = 0; i < Level_Vaults.size(); ++i) + { + const vault_placement &vault = Level_Vaults[i]; + if (_inside_vault(vault, pos)) + out.push_back(vault.map.name); + } + + for (unsigned int i = 0; i < Temp_Vaults.size(); ++i) + { + const vault_placement &vault = Temp_Vaults[i]; + if (_inside_vault(vault, pos)) + out.push_back(vault.map.name); + } + + return (out); +} + +void debug_mons_scan() +{ + std::vector<coord_def> bogus_pos; + std::vector<int> bogus_idx; + + bool warned = false; + for (int y = 0; y < GYM; ++y) + for (int x = 0; x < GXM; ++x) + { + const int mons = mgrd[x][y]; + if (mons == NON_MONSTER) + continue; + + if (invalid_monster_index(mons)) + { + mprf(MSGCH_ERROR, "mgrd at (%d, %d) has invalid monster " + "index %d", + x, y, mons); + continue; + } + + const monsters *m = &menv[mons]; + const coord_def pos(x, y); + if (m->pos() != pos) + { + bogus_pos.push_back(pos); + bogus_idx.push_back(mons); + + _announce_level_prob(warned); + mprf(MSGCH_WARN, + "Bogosity: mgrd at (%d,%d) points at %s, " + "but monster is at (%d,%d)", + x, y, m->name(DESC_PLAIN, true).c_str(), + m->pos().x, m->pos().y); + if (!m->alive()) + mpr("Additionally, it isn't alive.", MSGCH_WARN); + warned = true; + } + else if (!m->alive()) + { + _announce_level_prob(warned); + mprf(MSGCH_WARN, + "mgrd at (%d,%d) points at dead monster %s", + x, y, m->name(DESC_PLAIN, true).c_str()); + warned = true; + } + } + + std::vector<int> floating_mons; + bool is_floating[MAX_MONSTERS]; + + for (int i = 0; i < MAX_MONSTERS; ++i) + { + is_floating[i] = false; + + const monsters *m = &menv[i]; + if (!m->alive()) + continue; + + coord_def pos = m->pos(); + + if (!in_bounds(pos)) + { + mprf(MSGCH_ERROR, "Out of bounds monster: %s at (%d, %d), " + "midx = %d", + m->full_name(DESC_PLAIN, true).c_str(), + pos.x, pos.y, i); + } + else if (mgrd(pos) != i) + { + floating_mons.push_back(i); + is_floating[i] = true; + + _announce_level_prob(warned); + mprf(MSGCH_WARN, "Floating monster: %s at (%d,%d), midx = %d", + m->full_name(DESC_PLAIN, true).c_str(), + pos.x, pos.y, i); + warned = true; + for (int j = 0; j < MAX_MONSTERS; ++j) + { + if (i == j) + continue; + + const monsters *m2 = &menv[j]; + + if (m2->pos() != m->pos()) + continue; + + std::string full = m2->full_name(DESC_PLAIN, true); + if (m2->alive()) + { + mprf(MSGCH_WARN, "Also at (%d, %d): %s, midx = %d", + pos.x, pos.y, full.c_str(), j); + } + else if (m2->type != -1) + { + mprf(MSGCH_WARN, "Dead mon also at (%d, %d): %s," + "midx = %d", + pos.x, pos.y, full.c_str(), j); + } + } + } // if (mgrd(m->pos()) != i) + + for (int j = 0; j < NUM_MONSTER_SLOTS; ++j) + { + const int idx = m->inv[j]; + if (idx == NON_ITEM) + continue; + + if (idx < 0 || idx > MAX_ITEMS) + { + mprf(MSGCH_ERROR, "Monster %s (%d, %d) has invalid item " + "index %d in slot %d.", + m->full_name(DESC_PLAIN, true).c_str(), + pos.x, pos.y, idx, j); + continue; + } + item_def &item(mitm[idx]); + + if (!item.is_valid()) + { + _announce_level_prob(warned); + warned = true; + mprf(MSGCH_WARN, "Monster %s (%d, %d) holding invalid item in " + "slot %d (midx = %d)", + m->full_name(DESC_PLAIN, true).c_str(), + pos.x, pos.y, j, i); + continue; + } + + const monsters* holder = item.holding_monster(); + + if (holder == NULL) + { + _announce_level_prob(warned); + warned = true; + mprf(MSGCH_WARN, "Monster %s (%d, %d) holding non-monster " + "item (midx = %d)", + m->full_name(DESC_PLAIN, true).c_str(), + pos.x, pos.y, i); + _dump_item( item.name(DESC_PLAIN, false, true).c_str(), + idx, item ); + continue; + } + + if (holder != m) + { + _announce_level_prob(warned); + warned = true; + mprf(MSGCH_WARN, "Monster %s (%d, %d) [midx = %d] holding " + "item %s, but item thinks it's held by " + "monster %s (%d, %d) [midx = %d]", + m->full_name(DESC_PLAIN, true).c_str(), + m->pos().x, m->pos().y, i, + item.name(DESC_PLAIN).c_str(), + holder->full_name(DESC_PLAIN, true).c_str(), + holder->pos().x, holder->pos().y, holder->mindex()); + + bool found = false; + for (int k = 0; k < NUM_MONSTER_SLOTS; ++k) + { + if (holder->inv[k] == idx) + { + mpr("Other monster thinks it's holding the item, too.", + MSGCH_WARN); + found = true; + break; + } + } + if (!found) + mpr("Other monster isn't holding it, though.", MSGCH_WARN); + } // if (holder != m) + } // for (int j = 0; j < NUM_MONSTER_SLOTS; j++) + } // for (int i = 0; i < MAX_MONSTERS; ++i) + + // No problems? + if (!warned) + return; + + // If this wasn't the result of generating a level then there's nothing + // more to report. + if (!Generating_Level) + { + // Force the dev to notice problems. :P + more(); + return; + } + + // No vaults to report on? + if (Level_Vaults.size() == 0 && Temp_Vaults.size() == 0) + { + mpr("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", MSGCH_ERROR); + // Force the dev to notice problems. :P + more(); + return; + } + + mpr(""); + + for (unsigned int i = 0; i < floating_mons.size(); ++i) + { + const int idx = floating_mons[i]; + const monsters* mon = &menv[idx]; + std::vector<std::string> vaults = _in_vaults(mon->pos()); + + std::string str = + make_stringf("Floating monster %s (%d, %d)", + mon->name(DESC_PLAIN, true).c_str(), + mon->pos().x, mon->pos().y); + + if (vaults.size() == 0) + mprf(MSGCH_WARN, "%s not in any vaults.", str.c_str()); + else + { + mpr_comma_separated_list(str + " in vault(s) ", vaults, + " and ", ", ", MSGCH_WARN); + } + } + + mpr(""); + + for (unsigned int i = 0; i < bogus_pos.size(); ++i) + { + const coord_def pos = bogus_pos[i]; + const int idx = bogus_idx[i]; + const monsters* mon = &menv[idx]; + + std::string str = + make_stringf("Bogus mgrd (%d, %d) pointing to %s", + pos.x, pos.y, mon->name(DESC_PLAIN, true).c_str()); + + std::vector<std::string> vaults = _in_vaults(pos); + + if (vaults.size() == 0) + mprf(MSGCH_WARN, "%s not in any vaults.", str.c_str()); + else + { + mpr_comma_separated_list(str + " in vault(s) ", vaults, + " and ", ", ", MSGCH_WARN); + } + + // Don't report on same monster twice. + if (is_floating[idx]) + continue; + + str = "Monster pointed to"; + vaults = _in_vaults(mon->pos()); + + if (vaults.size() == 0) + mprf(MSGCH_WARN, "%s not in any vaults.", str.c_str()); + else + { + mpr_comma_separated_list(str + " in vault(s) ", vaults, + " and ", ", ", MSGCH_WARN); + } + } + + mpr("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!", MSGCH_ERROR); + // Force the dev to notice problems. :P + more(); +} +#endif |