summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/wiz-dgn.cc
diff options
context:
space:
mode:
authorMatthew Cline <zelgadis@sourceforge.net>2009-11-06 19:26:31 -0800
committerMatthew Cline <zelgadis@sourceforge.net>2009-11-06 19:26:31 -0800
commitbe871d682e8087ab38c5e9e054190daf6f81fff2 (patch)
treee31a44ad0f851c3946f6d665021bb9b206dd5a66 /crawl-ref/source/wiz-dgn.cc
parent8051b93a756f55ba7985f4e6ffe4a833ce0b41cb (diff)
downloadcrawl-ref-be871d682e8087ab38c5e9e054190daf6f81fff2.tar.gz
crawl-ref-be871d682e8087ab38c5e9e054190daf6f81fff2.zip
Split up debug.cc
Diffstat (limited to 'crawl-ref/source/wiz-dgn.cc')
-rw-r--r--crawl-ref/source/wiz-dgn.cc675
1 files changed, 675 insertions, 0 deletions
diff --git a/crawl-ref/source/wiz-dgn.cc b/crawl-ref/source/wiz-dgn.cc
new file mode 100644
index 0000000000..3e8149b84f
--- /dev/null
+++ b/crawl-ref/source/wiz-dgn.cc
@@ -0,0 +1,675 @@
+/*
+ * File: wiz-dgn.h
+ * Summary: Dungeon related wizard functions.
+ * Written by: Linley Henzell and Jesse Jones
+ */
+
+#include "AppHdr.h"
+
+#include "wiz-dgn.h"
+
+#include "branch.h"
+#include "cio.h"
+#include "coord.h"
+#include "coordit.h"
+#include "delay.h"
+#include "dungeon.h"
+#include "effects.h"
+#include "files.h"
+#include "items.h"
+#include "l_defs.h"
+#include "mapmark.h"
+#include "maps.h"
+#include "message.h"
+#include "misc.h"
+#include "options.h"
+#include "place.h"
+#include "player.h"
+#include "stuff.h"
+#include "terrain.h"
+#include "traps.h"
+#include "view.h"
+#include "wiz-mon.h"
+
+#ifdef WIZARD
+static dungeon_feature_type _find_appropriate_stairs(bool down)
+{
+ if (you.level_type == LEVEL_DUNGEON)
+ {
+ int depth = subdungeon_depth(you.where_are_you, you.your_level);
+ if (down)
+ depth++;
+ else
+ depth--;
+
+ // Can't go down from bottom level of a branch.
+ if (depth > branches[you.where_are_you].depth)
+ {
+ mpr("Can't go down from the bottom of a branch.");
+ return DNGN_UNSEEN;
+ }
+ // Going up from top level of branch
+ else if (depth == 0)
+ {
+ // Special cases
+ if (you.where_are_you == BRANCH_VESTIBULE_OF_HELL)
+ return DNGN_EXIT_HELL;
+ else if (you.where_are_you == BRANCH_MAIN_DUNGEON)
+ return DNGN_STONE_STAIRS_UP_I;
+
+ dungeon_feature_type stairs = your_branch().exit_stairs;
+
+ if (stairs < DNGN_RETURN_FROM_FIRST_BRANCH
+ || stairs > DNGN_RETURN_FROM_LAST_BRANCH)
+ {
+ mpr("This branch has no exit stairs defined.");
+ return DNGN_UNSEEN;
+ }
+ return (stairs);
+ }
+ // Branch non-edge cases
+ else if (depth >= 1)
+ {
+ if (down)
+ return DNGN_STONE_STAIRS_DOWN_I;
+ else
+ return DNGN_ESCAPE_HATCH_UP;
+ }
+ else
+ {
+ mpr("Bug in determining level exit.");
+ return DNGN_UNSEEN;
+ }
+ }
+
+ switch (you.level_type)
+ {
+ case LEVEL_LABYRINTH:
+ if (down)
+ {
+ mpr("Can't go down in the Labyrinth.");
+ return DNGN_UNSEEN;
+ }
+ else
+ return DNGN_ESCAPE_HATCH_UP;
+
+ case LEVEL_ABYSS:
+ return DNGN_EXIT_ABYSS;
+
+ case LEVEL_PANDEMONIUM:
+ if (down)
+ return DNGN_TRANSIT_PANDEMONIUM;
+ else
+ return DNGN_EXIT_PANDEMONIUM;
+
+ case LEVEL_PORTAL_VAULT:
+ return DNGN_EXIT_PORTAL_VAULT;
+
+ default:
+ mpr("Unknown level type.");
+ return DNGN_UNSEEN;
+ }
+
+ mpr("Impossible occurrence in find_appropriate_stairs()");
+ return DNGN_UNSEEN;
+}
+
+void wizard_place_stairs( bool down )
+{
+ dungeon_feature_type stairs = _find_appropriate_stairs(down);
+
+ if (stairs == DNGN_UNSEEN)
+ return;
+
+ dungeon_terrain_changed(you.pos(), stairs, false);
+}
+
+// Try to find and use stairs already in the portal vault level,
+// since this might be a multi-level portal vault like a ziggurat.
+bool _take_portal_vault_stairs( const bool down )
+{
+ ASSERT(you.level_type == LEVEL_PORTAL_VAULT);
+
+ const command_type cmd = down ? CMD_GO_DOWNSTAIRS : CMD_GO_UPSTAIRS;
+
+ coord_def stair_pos(-1, -1);
+
+ for (rectangle_iterator ri(1); ri; ++ri)
+ {
+ if (feat_stair_direction(grd(*ri)) == cmd)
+ {
+ stair_pos = *ri;
+ break;
+ }
+ }
+
+ if (!in_bounds(stair_pos))
+ return (false);
+
+ clear_trapping_net();
+ you.set_position(stair_pos);
+
+ if (down)
+ down_stairs(you.your_level);
+ else
+ up_stairs();
+
+ return (true);
+}
+
+void wizard_level_travel( bool down )
+{
+ if (you.level_type == LEVEL_PORTAL_VAULT)
+ if (_take_portal_vault_stairs(down))
+ return;
+
+ dungeon_feature_type stairs = _find_appropriate_stairs(down);
+
+ if (stairs == DNGN_UNSEEN)
+ return;
+
+ // This lets us, for example, use &U to exit from Pandemonium and
+ // &D to go to the next level.
+ command_type real_dir = feat_stair_direction(stairs);
+ if (down && real_dir == CMD_GO_UPSTAIRS
+ || !down && real_dir == CMD_GO_DOWNSTAIRS)
+ {
+ down = !down;
+ }
+
+ if (down)
+ down_stairs(you.your_level, stairs);
+ else
+ up_stairs(stairs);
+}
+
+static void _wizard_go_to_level(const level_pos &pos)
+{
+ const int abs_depth = absdungeon_depth(pos.id.branch, pos.id.depth);
+ dungeon_feature_type stair_taken =
+ abs_depth > you.your_level? DNGN_STONE_STAIRS_DOWN_I
+ : DNGN_STONE_STAIRS_UP_I;
+
+ if (abs_depth > you.your_level && pos.id.depth == 1
+ && pos.id.branch != BRANCH_MAIN_DUNGEON)
+ {
+ stair_taken = branches[pos.id.branch].entry_stairs;
+ }
+
+ const int old_level = you.your_level;
+ const branch_type old_where = you.where_are_you;
+ const level_area_type old_level_type = you.level_type;
+
+ you.level_type = LEVEL_DUNGEON;
+ you.where_are_you = static_cast<branch_type>(pos.id.branch);
+ you.your_level = abs_depth;
+
+ const bool newlevel = load(stair_taken, LOAD_ENTER_LEVEL, old_level_type,
+ old_level, old_where);
+#ifdef USE_TILE
+ TileNewLevel(newlevel);
+#else
+ UNUSED(newlevel);
+#endif
+ if (!crawl_state.test)
+ save_game_state();
+ new_level();
+ viewwindow(true, true);
+
+ // Tell stash-tracker and travel that we've changed levels.
+ trackers_init_new_level(true);
+}
+
+void wizard_interlevel_travel()
+{
+ std::string name;
+ const level_pos pos =
+ prompt_translevel_target(TPF_ALLOW_UPDOWN | TPF_SHOW_ALL_BRANCHES, name).p;
+
+ if (pos.id.depth < 1 || pos.id.depth > branches[pos.id.branch].depth)
+ {
+ canned_msg(MSG_OK);
+ return;
+ }
+
+ _wizard_go_to_level(pos);
+}
+
+void wizard_create_portal()
+{
+ mpr("Destination for portal (defaults to 'bazaar')? ", MSGCH_PROMPT);
+ char specs[256];
+ if (cancelable_get_line(specs, sizeof(specs)))
+ {
+ canned_msg( MSG_OK );
+ return;
+ }
+
+ std::string dst = specs;
+ dst = trim_string(dst);
+ dst = replace_all(dst, " ", "_");
+
+ if (dst.empty())
+ dst = "bazaar";
+
+ if (!find_map_by_name(dst) && !random_map_for_tag(dst))
+ {
+ mprf("No map named '%s' or tagged '%s'.", dst.c_str(), dst.c_str());
+ }
+ else
+ {
+ map_wiz_props_marker *marker = new map_wiz_props_marker(you.pos());
+ marker->set_property("dst", dst);
+ marker->set_property("desc", "wizard portal, dest = " + dst);
+ env.markers.add(marker);
+ dungeon_terrain_changed(you.pos(), DNGN_ENTER_PORTAL_VAULT, false);
+ }
+}
+
+void wizard_create_feature_number()
+{
+ char specs[256];
+ int feat_num;
+ mpr("Create which feature (by number)? ", MSGCH_PROMPT);
+
+ if (!cancelable_get_line(specs, sizeof(specs))
+ && (feat_num = atoi(specs)))
+ {
+ dungeon_feature_type feat = static_cast<dungeon_feature_type>(feat_num);
+ if (feat == DNGN_ENTER_SHOP)
+ {
+ debug_make_shop();
+ return;
+ }
+
+ dungeon_terrain_changed(you.pos(), feat, false);
+#ifdef USE_TILE
+ env.tile_flv(you.pos()).special = 0;
+#endif
+ }
+ else
+ canned_msg(MSG_OK);
+}
+
+void wizard_create_feature_name()
+{
+ char specs[256];
+ mpr("Create which feature (by name)? ", MSGCH_PROMPT);
+ if (!cancelable_get_line(specs, sizeof(specs)) && specs[0] != 0)
+ {
+ // Accept both "shallow_water" and "Shallow water"
+ std::string name = lowercase_string(specs);
+ name = replace_all(name, " ", "_");
+
+ dungeon_feature_type feat = dungeon_feature_by_name(name);
+ if (feat == DNGN_UNSEEN) // no exact match
+ {
+ std::vector<std::string> matches = dungeon_feature_matches(name);
+
+ if (matches.empty())
+ {
+ mprf(MSGCH_DIAGNOSTICS, "No features matching '%s'",
+ name.c_str());
+ return;
+ }
+
+ // Only one possible match, use that.
+ if (matches.size() == 1)
+ {
+ name = matches[0];
+ feat = dungeon_feature_by_name(name);
+ }
+ // Multiple matches, list them to wizard
+ else
+ {
+ std::string prefix = "No exact match for feature '" +
+ name + "', possible matches are: ";
+
+ // Use mpr_comma_separated_list() because the list
+ // might be *LONG*.
+ mpr_comma_separated_list(prefix, matches, " and ", ", ",
+ MSGCH_DIAGNOSTICS);
+ return;
+ }
+ }
+
+ if (feat == DNGN_ENTER_SHOP)
+ {
+ debug_make_shop();
+ return;
+ }
+
+ mprf(MSGCH_DIAGNOSTICS, "Setting (%d,%d) to %s (%d)",
+ you.pos().x, you.pos().y, name.c_str(), feat);
+ dungeon_terrain_changed(you.pos(), feat, false);
+#ifdef USE_TILE
+ env.tile_flv(you.pos()).special = 0;
+#endif
+ }
+ else
+ canned_msg(MSG_OK);
+}
+
+void wizard_list_branches()
+{
+ for (int i = 0; i < NUM_BRANCHES; ++i)
+ {
+ if (branches[i].startdepth != - 1)
+ {
+ mprf(MSGCH_DIAGNOSTICS, "Branch %d (%s) is on level %d of %s",
+ i, branches[i].longname, branches[i].startdepth,
+ branches[branches[i].parent_branch].abbrevname);
+ }
+ else if (i == BRANCH_SWAMP || i == BRANCH_SHOALS)
+ {
+ mprf(MSGCH_DIAGNOSTICS, "Branch %d (%s) was not generated "
+ "this game", i, branches[i].longname);
+ }
+ }
+}
+
+void wizard_map_level()
+{
+ if (testbits(env.level_flags, LFLAG_NOT_MAPPABLE)
+ || testbits(get_branch_flags(), BFLAG_NOT_MAPPABLE))
+ {
+ if (!yesno("Force level to be mappable?", true, 'n'))
+ {
+ canned_msg( MSG_OK );
+ return;
+ }
+
+ unset_level_flags(LFLAG_NOT_MAPPABLE | LFLAG_NO_MAGIC_MAP);
+ unset_branch_flags(BFLAG_NOT_MAPPABLE | BFLAG_NO_MAGIC_MAP);
+ }
+
+ magic_mapping(1000, 100, true, true);
+}
+
+static int find_trap_slot()
+{
+ for (int i = 0; i < MAX_TRAPS; ++i)
+ if (env.trap[i].type == TRAP_UNASSIGNED)
+ return (i);
+
+ return (-1);
+}
+
+void debug_make_trap()
+{
+ char requested_trap[80];
+ int trap_slot = find_trap_slot();
+ trap_type trap = TRAP_UNASSIGNED;
+ int gridch = grd(you.pos());
+
+ if (trap_slot == -1)
+ {
+ mpr("Sorry, this level can't take any more traps.");
+ return;
+ }
+
+ if (gridch != DNGN_FLOOR)
+ {
+ mpr("You need to be on a floor square to make a trap.");
+ return;
+ }
+
+ mprf(MSGCH_PROMPT, "What kind of trap? ");
+ get_input_line( requested_trap, sizeof( requested_trap ) );
+ if (!*requested_trap)
+ return;
+
+ strlwr(requested_trap);
+ std::vector<trap_type> matches;
+ std::vector<std::string> match_names;
+ for (int t = TRAP_DART; t < NUM_TRAPS; ++t)
+ {
+ const trap_type tr = static_cast<trap_type>(t);
+ const char* tname = trap_name(tr);
+ if (strstr(requested_trap, tname))
+ {
+ trap = tr;
+ break;
+ }
+ else if (strstr(tname, requested_trap))
+ {
+ matches.push_back(tr);
+ match_names.push_back(tname);
+ }
+ }
+
+ if (trap == TRAP_UNASSIGNED)
+ {
+ if (matches.empty())
+ {
+ mprf("I know no traps named \"%s\"", requested_trap);
+ return;
+ }
+ // Only one match, use that
+ else if (matches.size() == 1)
+ trap = matches[0];
+ else
+ {
+ std::string prefix = "No exact match for trap '";
+ prefix += requested_trap;
+ prefix += "', possible matches are: ";
+ mpr_comma_separated_list(prefix, match_names);
+
+ return;
+ }
+ }
+
+ place_specific_trap(you.pos(), trap);
+
+ mprf("Created a %s trap, marked it undiscovered", trap_name(trap));
+
+ if (trap == TRAP_SHAFT && !is_valid_shaft_level())
+ mpr("NOTE: Shaft traps aren't valid on this level.");
+}
+
+void debug_make_shop()
+{
+ char requested_shop[80];
+ int gridch = grd(you.pos());
+ bool have_shop_slots = false;
+ int new_shop_type = SHOP_UNASSIGNED;
+ bool representative = false;
+
+ if (gridch != DNGN_FLOOR)
+ {
+ mpr("Insufficient floor-space for new Wal-Mart.");
+ return;
+ }
+
+ for (int i = 0; i < MAX_SHOPS; ++i)
+ {
+ if (env.shop[i].type == SHOP_UNASSIGNED)
+ {
+ have_shop_slots = true;
+ break;
+ }
+ }
+
+ if (!have_shop_slots)
+ {
+ mpr("There are too many shops on this level.");
+ return;
+ }
+
+ mprf(MSGCH_PROMPT, "What kind of shop? ");
+ get_input_line( requested_shop, sizeof( requested_shop ) );
+ if (!*requested_shop)
+ return;
+
+ strlwr(requested_shop);
+ std::string s = replace_all_of(requested_shop, "*", "");
+ new_shop_type = str_to_shoptype(s);
+
+ if (new_shop_type == SHOP_UNASSIGNED || new_shop_type == -1)
+ {
+ mprf("Bad shop type: \"%s\"", requested_shop);
+ return;
+ }
+
+ representative = !!strchr(requested_shop, '*');
+
+ place_spec_shop(you.your_level, you.pos(),
+ new_shop_type, representative);
+ link_items();
+ mprf("Done.");
+}
+
+static void debug_load_map_by_name(std::string name)
+{
+ const bool place_on_us = strip_tag(name, "*", true);
+
+ level_clear_vault_memory();
+ const map_def *toplace = find_map_by_name(name);
+ if (!toplace)
+ {
+ std::vector<std::string> matches = find_map_matches(name);
+
+ if (matches.empty())
+ {
+ mprf("Can't find map named '%s'.", name.c_str());
+ return;
+ }
+ else if (matches.size() == 1)
+ {
+ std::string prompt = "Only match is '";
+ prompt += matches[0];
+ prompt += "', use that?";
+ if (!yesno(prompt.c_str(), true, 'y'))
+ return;
+
+ toplace = find_map_by_name(matches[0]);
+ }
+ else
+ {
+ std::string prompt = "No exact matches for '";
+ prompt += name;
+ prompt += "', possible matches are: ";
+ mpr_comma_separated_list(prompt, matches);
+ return;
+ }
+ }
+
+ coord_def where(-1, -1);
+ if ((toplace->orient == MAP_FLOAT || toplace->orient == MAP_NONE)
+ && place_on_us)
+ {
+ where = you.pos();
+ }
+
+ if (dgn_place_map(toplace, true, false, where))
+ mprf("Successfully placed %s.", toplace->name.c_str());
+ else
+ mprf("Failed to place %s.", toplace->name.c_str());
+}
+
+void debug_place_map()
+{
+ char what_to_make[100];
+ mesclr();
+ mprf(MSGCH_PROMPT, "Enter map name: ");
+ if (cancelable_get_line_autohist(what_to_make, sizeof what_to_make))
+ {
+ canned_msg(MSG_OK);
+ return;
+ }
+
+ std::string what = what_to_make;
+ trim_string(what);
+ if (what.empty())
+ {
+ canned_msg(MSG_OK);
+ return;
+ }
+
+ debug_load_map_by_name(what);
+}
+
+static void _debug_kill_traps()
+{
+ for (rectangle_iterator ri(1); ri; ++ri)
+ if (feat_is_trap(grd(*ri), true))
+ destroy_trap(*ri);
+}
+
+static int _debug_time_explore()
+{
+ viewwindow(true, false);
+ start_explore(false);
+
+ unwind_var<int> es(Options.explore_stop, 0);
+
+ const long start = you.num_turns;
+ while (you_are_delayed())
+ {
+ you.turn_is_over = false;
+ handle_delay();
+ you.num_turns++;
+ }
+
+ // Elapsed time might not match up if explore had to go through
+ // shallow water.
+ PlaceInfo& pi = you.get_place_info();
+ pi.elapsed_total = (pi.elapsed_explore + pi.elapsed_travel +
+ pi.elapsed_interlevel + pi.elapsed_resting +
+ pi.elapsed_other);
+
+ PlaceInfo& pi2 = you.global_info;
+ pi2.elapsed_total = (pi2.elapsed_explore + pi2.elapsed_travel +
+ pi2.elapsed_interlevel + pi2.elapsed_resting +
+ pi2.elapsed_other);
+
+ return (you.num_turns - start);
+}
+
+static void _debug_destroy_doors()
+{
+ for (int y = 0; y < GYM; ++y)
+ for (int x = 0; x < GXM; ++x)
+ {
+ const dungeon_feature_type feat = grd[x][y];
+ if (feat == DNGN_SECRET_DOOR || feat_is_closed_door(feat))
+ grd[x][y] = DNGN_FLOOR;
+ }
+}
+
+// Turns off greedy explore, then:
+// a) Destroys all traps on the level.
+// b) Kills all monsters on the level.
+// c) Suppresses monster generation.
+// d) Converts all closed doors and secret doors to floor.
+// e) Forgets map.
+// f) Counts number of turns needed to explore the level.
+void debug_test_explore()
+{
+ wizard_dismiss_all_monsters(true);
+ _debug_kill_traps();
+ _debug_destroy_doors();
+
+ forget_map(100);
+
+ // Remember where we are now.
+ const coord_def where = you.pos();
+
+ const int explore_turns = _debug_time_explore();
+
+ // Return to starting point.
+ you.moveto(where);
+
+ mprf("Explore took %d turns.", explore_turns);
+}
+
+void debug_shift_labyrinth()
+{
+ if (you.level_type != LEVEL_LABYRINTH)
+ {
+ mpr("This only makes sense in a labyrinth!");
+ return;
+ }
+ change_labyrinth(true);
+}
+#endif