From 1db9c68406e0892e1ac7331dfd3b412b31741cb7 Mon Sep 17 00:00:00 2001 From: zelgadis Date: Fri, 5 Oct 2007 06:10:49 +0000 Subject: Shaft traps (trap doors) [1792195] and level annotation [1769009] added, with the shaft traps changed as per comments on SF; shafts aren't randomly generated yet, so this doesn't change gameplay. Changed DNGN_TRAP_III to DNGN_TRAP_NATURAL, of which trap type the shaft traps are the only current member. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@2328 c06c8d41-db1a-0410-9941-cceddc491573 --- crawl-ref/source/acr.cc | 34 ++++- crawl-ref/source/branch.cc | 46 +++--- crawl-ref/source/branch.h | 1 + crawl-ref/source/command.cc | 1 + crawl-ref/source/dat/descript/features.txt | 3 + crawl-ref/source/describe.cc | 4 + crawl-ref/source/direct.cc | 8 +- crawl-ref/source/dungeon.cc | 20 ++- crawl-ref/source/enum.h | 5 +- crawl-ref/source/externs.h | 21 ++- crawl-ref/source/files.cc | 15 ++ crawl-ref/source/luadgn.cc | 2 +- crawl-ref/source/misc.cc | 160 +++++++++++++++++++-- crawl-ref/source/misc.h | 3 + crawl-ref/source/mon-util.cc | 219 +++++++++++++++++++++++++++++ crawl-ref/source/mon-util.h | 2 + crawl-ref/source/monplace.cc | 24 +++- crawl-ref/source/monstuff.cc | 6 +- crawl-ref/source/mstuff2.cc | 26 ++++ crawl-ref/source/overmap.cc | 150 ++++++++++++++++++++ crawl-ref/source/overmap.h | 12 ++ crawl-ref/source/player.cc | 166 +++++++++++++++++++++- crawl-ref/source/spells3.cc | 2 +- crawl-ref/source/spells4.cc | 1 - crawl-ref/source/state.cc | 3 +- crawl-ref/source/state.h | 2 + crawl-ref/source/tags.cc | 17 +++ crawl-ref/source/terrain.cc | 2 +- crawl-ref/source/traps.cc | 39 +++++ crawl-ref/source/view.cc | 8 +- 30 files changed, 939 insertions(+), 63 deletions(-) (limited to 'crawl-ref') diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc index 89ba2ed09d..96668a5f12 100644 --- a/crawl-ref/source/acr.cc +++ b/crawl-ref/source/acr.cc @@ -1448,6 +1448,23 @@ static bool toggle_flag( bool* flag, const char* flagname ) return *flag; } +static bool can_go_down_shaft() +{ + // Not a shaft + if (trap_type_at_xy(you.x_pos, you.y_pos) != TRAP_SHAFT) + return (false); + + // Undiscovered shaft + if (grd[you.x_pos][you.y_pos] == DNGN_UNDISCOVERED_TRAP) + return (false); + + // Have to fly to dive through it. + if (you.flies() != FL_FLY) + return (false); + + return (true); +} + static void go_downstairs(); static void go_upstairs() { @@ -1491,6 +1508,14 @@ static void go_upstairs() static void go_downstairs() { + if (trap_at_xy(you.x_pos, you.y_pos) == TRAP_SHAFT + && grd[you.x_pos][you.y_pos] != DNGN_UNDISCOVERED_TRAP + && !can_go_down_shaft()) + { + mpr("You must have controlled flight to dive through a shaft."); + return; + } + if (grid_stair_direction(grd(you.pos())) != CMD_GO_DOWNSTAIRS) { if (grd(you.pos()) == DNGN_STONE_ARCH) @@ -1953,6 +1978,10 @@ void process_command( command_type cmd ) mesclr(); break; + case CMD_ANNOTATE_LEVEL: + annotate_level(); + break; + case CMD_EXPLORE: // Start exploring start_explore(Options.explore_greedy); @@ -3094,7 +3123,7 @@ command_type keycode_to_command( keycode_type key ) case CONTROL('E'): return CMD_FORGET_STASH; case CONTROL('F'): return CMD_SEARCH_STASHES; case CONTROL('G'): return CMD_INTERLEVEL_TRAVEL; - case CONTROL('I'): return CMD_NO_CMD; + case CONTROL('I'): return CMD_ANNOTATE_LEVEL; case CONTROL('M'): return CMD_NO_CMD; case CONTROL('O'): return CMD_EXPLORE; case CONTROL('P'): return CMD_REPLAY_MESSAGES; @@ -3186,7 +3215,8 @@ static void open_door(int move_x, int move_y, bool check_confused) return; } - if (grd[dx][dy] >= DNGN_TRAP_MECHANICAL && grd[dx][dy] <= DNGN_TRAP_III) + if (grd[dx][dy] >= DNGN_TRAP_MECHANICAL + && grd[dx][dy] <= DNGN_TRAP_NATURAL) { if (env.cgrid[dx][dy] != EMPTY_CLOUD) { diff --git a/crawl-ref/source/branch.cc b/crawl-ref/source/branch.cc index a620777d20..d8e36f1a6c 100644 --- a/crawl-ref/source/branch.cc +++ b/crawl-ref/source/branch.cc @@ -115,7 +115,7 @@ Branch branches[] = { NULL, true, true, LIGHTGREY, BROWN, mons_standard_rare, mons_standard_level, - 8, 'D', false }, + 8, 'D', false, false }, { BRANCH_ECUMENICAL_TEMPLE, BRANCH_MAIN_DUNGEON, 1, 5, 0, 0, DNGN_ENTER_TEMPLE, DNGN_RETURN_FROM_TEMPLE, @@ -123,7 +123,7 @@ Branch branches[] = { NULL, false, false, LIGHTGREY, LIGHTGREY, mons_standard_rare, mons_standard_level, - 0, 'T', false }, + 0, 'T', false, false }, { BRANCH_ORCISH_MINES, BRANCH_MAIN_DUNGEON, 4, 6, 0, 0, DNGN_ENTER_ORCISH_MINES, DNGN_RETURN_FROM_ORCISH_MINES, @@ -131,7 +131,7 @@ Branch branches[] = { NULL, true, false, BROWN, BROWN, mons_mineorc_rare, mons_mineorc_level, - 20, 'O', false }, + 20, 'O', false, false }, { BRANCH_ELVEN_HALLS, BRANCH_ORCISH_MINES, 7, 4, 0, 0, DNGN_ENTER_ELVEN_HALLS, DNGN_RETURN_FROM_ELVEN_HALLS, @@ -139,7 +139,7 @@ Branch branches[] = { NULL, true, true, DARKGREY, LIGHTGREY, mons_hallelf_rare, mons_hallelf_level, - 8, 'E', false }, + 8, 'E', false, true }, { BRANCH_LAIR, BRANCH_MAIN_DUNGEON, 10, 8, 0, 0, DNGN_ENTER_LAIR, DNGN_RETURN_FROM_LAIR, @@ -147,7 +147,7 @@ Branch branches[] = { NULL, true, false, GREEN, BROWN, mons_lair_rare, mons_lair_level, - 5, 'L', false }, + 5, 'L', false, false }, { BRANCH_SWAMP, BRANCH_LAIR, 5, 3, 0, 0, DNGN_ENTER_SWAMP, DNGN_RETURN_FROM_SWAMP, @@ -155,7 +155,7 @@ Branch branches[] = { NULL, true, true, BROWN, BROWN, mons_swamp_rare, mons_swamp_level, - 0, 'S', false }, + 0, 'S', false, true }, { BRANCH_SHOALS, BRANCH_LAIR, 5, 4, 0, 0, DNGN_ENTER_SHOALS, DNGN_RETURN_FROM_SHOALS, @@ -163,7 +163,7 @@ Branch branches[] = { NULL, true, true, BROWN, BROWN, mons_shoals_rare, mons_shoals_level, - 0, 'A', false }, + 0, 'A', false, true }, { BRANCH_SLIME_PITS, BRANCH_LAIR, 6, 4, 0, 0, DNGN_ENTER_SLIME_PITS, DNGN_RETURN_FROM_SLIME_PITS, @@ -171,7 +171,7 @@ Branch branches[] = { NULL, false, false, GREEN, LIGHTGREEN, mons_pitslime_rare, mons_pitslime_level, - 5, 'M', false }, + 5, 'M', false, true }, { BRANCH_SNAKE_PIT, BRANCH_LAIR, 5, 7, 0, 0, DNGN_ENTER_SNAKE_PIT, DNGN_RETURN_FROM_SNAKE_PIT, @@ -179,7 +179,7 @@ Branch branches[] = { NULL, true, true, LIGHTGREEN, YELLOW, mons_pitsnake_rare, mons_pitsnake_level, - 10, 'P', false }, + 10, 'P', false, true }, { BRANCH_HIVE, BRANCH_MAIN_DUNGEON, 4, 15, 0, 0, DNGN_ENTER_HIVE, DNGN_RETURN_FROM_HIVE, @@ -187,7 +187,7 @@ Branch branches[] = { "You hear a buzzing sound coming from all directions.", false, false, YELLOW, BROWN, mons_hive_rare, mons_hive_level, - 0, 'H', false }, + 0, 'H', false, true }, { BRANCH_VAULTS, BRANCH_MAIN_DUNGEON, 8, 17, 0, 0, DNGN_ENTER_VAULTS, DNGN_RETURN_FROM_VAULTS, @@ -195,7 +195,7 @@ Branch branches[] = { NULL, true, true, LIGHTGREY, BROWN, mons_standard_rare, mons_standard_level, - 5, 'V', false }, + 5, 'V', false, true }, { BRANCH_HALL_OF_BLADES, BRANCH_VAULTS, 1, 4, 0, 0, @@ -204,7 +204,7 @@ Branch branches[] = { NULL, false, true, LIGHTGREY, LIGHTGREY, mons_hallblade_rare, mons_hallblade_level, - 0, 'B', false }, + 0, 'B', false, false }, { BRANCH_CRYPT, BRANCH_VAULTS, 5, 3, 0, 0, DNGN_ENTER_CRYPT, DNGN_RETURN_FROM_CRYPT, @@ -212,7 +212,7 @@ Branch branches[] = { NULL, false, true, LIGHTGREY, LIGHTGREY, mons_crypt_rare, mons_crypt_level, - 5, 'C', false }, + 5, 'C', false, false }, { BRANCH_TOMB, BRANCH_CRYPT, 3, 5, 0, 0, DNGN_ENTER_TOMB, DNGN_RETURN_FROM_TOMB, @@ -220,7 +220,7 @@ Branch branches[] = { NULL, false, true, YELLOW, LIGHTGREY, mons_tomb_rare, mons_tomb_level, - 0, 'G', false }, + 0, 'G', false, true }, { BRANCH_VESTIBULE_OF_HELL, BRANCH_MAIN_DUNGEON, 1, -1, 0, 0, DNGN_ENTER_HELL, NUM_FEATURES, // sentinel @@ -228,7 +228,7 @@ Branch branches[] = { NULL, false, true, LIGHTGREY, LIGHTGREY, mons_standard_rare, mons_standard_level, - 0, 'U', false }, + 0, 'U', false, false }, { BRANCH_DIS, BRANCH_VESTIBULE_OF_HELL, 7, -1, 0, 0, DNGN_ENTER_DIS, NUM_FEATURES, // sentinel @@ -236,7 +236,7 @@ Branch branches[] = { NULL, false, false, CYAN, CYAN, mons_dis_rare, mons_dis_level, - 0, 'I', true }, + 0, 'I', true, true }, { BRANCH_GEHENNA, BRANCH_VESTIBULE_OF_HELL, 7, -1, 0, 0, DNGN_ENTER_GEHENNA, NUM_FEATURES, // sentinel @@ -244,7 +244,7 @@ Branch branches[] = { NULL, false, false, DARKGREY, RED, mons_gehenna_rare, mons_gehenna_level, - 0, 'N', true }, + 0, 'N', true, true }, { BRANCH_COCYTUS, BRANCH_VESTIBULE_OF_HELL, 7, -1, 0, 0, DNGN_ENTER_COCYTUS, NUM_FEATURES, // sentinel @@ -252,7 +252,7 @@ Branch branches[] = { NULL, false, false, LIGHTBLUE, LIGHTCYAN, mons_cocytus_rare, mons_cocytus_level, - 0, 'X', true }, + 0, 'X', true, true }, { BRANCH_TARTARUS, BRANCH_VESTIBULE_OF_HELL, 7, -1, 0, 0, DNGN_ENTER_TARTARUS, NUM_FEATURES, // sentinel @@ -260,7 +260,7 @@ Branch branches[] = { NULL, false, false, DARKGREY, DARKGREY, mons_tartarus_rare, mons_tartarus_level, - 0, 'Y', true }, + 0, 'Y', true, true }, { BRANCH_INFERNO, BRANCH_MAIN_DUNGEON, -1, -1, 0, 0, NUM_FEATURES, NUM_FEATURES, @@ -268,7 +268,7 @@ Branch branches[] = { NULL, false, false, BLACK, BLACK, NULL, NULL, - 0, 'R', false }, + 0, 'R', false, false }, { BRANCH_THE_PIT, BRANCH_MAIN_DUNGEON, -1, -1, 0, 0, NUM_FEATURES, NUM_FEATURES, @@ -276,7 +276,7 @@ Branch branches[] = { NULL, false, false, BLACK, BLACK, NULL, NULL, - 0, '0', false }, + 0, '0', false, false }, { BRANCH_HALL_OF_ZOT, BRANCH_MAIN_DUNGEON, 5, 27, BFLAG_HAS_ORB, 0, DNGN_ENTER_ZOT, DNGN_RETURN_FROM_ZOT, @@ -284,7 +284,7 @@ Branch branches[] = { NULL, false, true, BLACK, BLACK, mons_hallzot_rare, mons_hallzot_level, - 1, 'Z', false }, + 1, 'Z', false, true }, { BRANCH_CAVERNS, BRANCH_MAIN_DUNGEON, -1, -1, 0, 0, NUM_FEATURES, NUM_FEATURES, @@ -292,5 +292,5 @@ Branch branches[] = { NULL, false, false, BLACK, BLACK, NULL, NULL, - 0, 0, false } + 0, 0, false, false } }; diff --git a/crawl-ref/source/branch.h b/crawl-ref/source/branch.h index b5629e4fac..404c40d6b9 100644 --- a/crawl-ref/source/branch.h +++ b/crawl-ref/source/branch.h @@ -46,6 +46,7 @@ struct Branch int altar_chance; // in percent int travel_shortcut; // which key to press for travel bool any_upstair_exits; // any upstair exits the branch (Hell branches) + bool dangerous_bottom_level; // bottom level is more dangerous than normal }; extern Branch branches[]; diff --git a/crawl-ref/source/command.cc b/crawl-ref/source/command.cc index 0013ba63f5..082fb00cfc 100644 --- a/crawl-ref/source/command.cc +++ b/crawl-ref/source/command.cc @@ -1463,6 +1463,7 @@ void list_commands(bool wizard, int hotkey, bool do_redraw_screen) "Ctrl-P : show Previous messages\n" "Ctrl-R : Redraw screen\n" "Ctrl-C : Clear main and level maps\n" + "Ctrl-I : annotate the dungeon level\n" "# : dump character to file\n" ": : add note (use ?: to read notes)\n" "~ : add macro\n" diff --git a/crawl-ref/source/dat/descript/features.txt b/crawl-ref/source/dat/descript/features.txt index f912be00c0..b7154b9d6e 100644 --- a/crawl-ref/source/dat/descript/features.txt +++ b/crawl-ref/source/dat/descript/features.txt @@ -84,6 +84,9 @@ A magical trap %%%% A mechanical trap +%%%% +A natural trap + %%%% A metal wall diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc index 2ef983478d..1ed2e3981d 100644 --- a/crawl-ref/source/describe.cc +++ b/crawl-ref/source/describe.cc @@ -338,6 +338,7 @@ static const char *trap_names[] = "dart", "arrow", "spear", "axe", "teleport", "amnesia", "blade", "bolt", "net", "zot", "needle", + "shaft" }; const char *trap_name(trap_type trap) @@ -357,6 +358,9 @@ int str_to_trap(const std::string &s) return (TRAP_RANDOM); else if (s == "suitable") return (TRAP_INDEPTH); + else if (s == "nonteleport" || s == "noteleport" || s == "nontele" + || s == "notele") + return (TRAP_NONTELEPORT); for (int i = 0; i < NUM_TRAPS; ++i) { diff --git a/crawl-ref/source/direct.cc b/crawl-ref/source/direct.cc index 7f4104878f..4cc6f30c57 100644 --- a/crawl-ref/source/direct.cc +++ b/crawl-ref/source/direct.cc @@ -1491,6 +1491,8 @@ std::string raw_feature_description(dungeon_feature_type grid, return ("Zot trap"); case TRAP_NEEDLE: return ("needle trap"); + case TRAP_SHAFT: + return ("shaft trap"); default: error_message_to_player(); return ("undefined trap"); @@ -1561,8 +1563,8 @@ std::string raw_feature_description(dungeon_feature_type grid, return ("mechanical trap"); case DNGN_TRAP_MAGICAL: return ("magical trap"); - case DNGN_TRAP_III: - return ("trap"); + case DNGN_TRAP_NATURAL: + return ("natural trap"); case DNGN_ENTER_SHOP: return ("shop"); case DNGN_ENTER_LABYRINTH: @@ -1714,7 +1716,7 @@ std::string feature_description(int mx, int my, description_level_type dtype, { case DNGN_TRAP_MECHANICAL: case DNGN_TRAP_MAGICAL: - case DNGN_TRAP_III: + case DNGN_TRAP_NATURAL: return (feature_description(grid, trap_type_at_xy(mx, my), dtype, add_stop)); case DNGN_ENTER_SHOP: diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc index d412241c18..118f960e15 100644 --- a/crawl-ref/source/dungeon.cc +++ b/crawl-ref/source/dungeon.cc @@ -6673,8 +6673,24 @@ static void jelly_pit(int level_number, spec_room &sr) bool place_specific_trap(int spec_x, int spec_y, trap_type spec_type) { - if (spec_type == TRAP_RANDOM) - spec_type = static_cast( random2(NUM_TRAPS) ); + if (spec_type == TRAP_RANDOM || spec_type == TRAP_NONTELEPORT) + { + trap_type forbidden1 = NUM_TRAPS; + trap_type forbidden2 = NUM_TRAPS; + + if (spec_type == TRAP_NONTELEPORT) + { + forbidden1 = TRAP_SHAFT; + forbidden2 = TRAP_TELEPORT; + } + else if (!is_valid_shaft_level()) + forbidden1 = TRAP_SHAFT; + + do + { + spec_type = static_cast( random2(NUM_TRAPS) ); + } while (spec_type == forbidden1 || spec_type == forbidden2); + } for (int tcount = 0; tcount < MAX_TRAPS; tcount++) { diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h index 4965e9cdf3..dbb0e9aff2 100644 --- a/crawl-ref/source/enum.h +++ b/crawl-ref/source/enum.h @@ -549,6 +549,8 @@ enum command_type CMD_MOUSE_MOVE, CMD_MOUSE_CLICK, + CMD_ANNOTATE_LEVEL, + /* overmap commands */ CMD_MAP_CLEAR_MAP, CMD_MAP_ADD_WAYPOINT, @@ -889,7 +891,7 @@ enum dungeon_feature_type DNGN_OPEN_DOOR, // 72 DNGN_TRAP_MECHANICAL = 75, // 75 DNGN_TRAP_MAGICAL, - DNGN_TRAP_III, + DNGN_TRAP_NATURAL, DNGN_UNDISCOVERED_TRAP, // 78 DNGN_ENTER_SHOP = 80, // 80 @@ -2548,6 +2550,7 @@ enum trap_type // env.trap_type[] TRAP_NET, TRAP_ZOT, TRAP_NEEDLE, + TRAP_SHAFT, NUM_TRAPS, // must remain last 'regular' member {dlb} TRAP_UNASSIGNED = 100, // keep set at 100 for now {dlb} TRAP_INDEPTH = 253, // Level-appropriate trap. diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h index 4aa1b1935f..1a29da26da 100644 --- a/crawl-ref/source/externs.h +++ b/crawl-ref/source/externs.h @@ -63,6 +63,7 @@ const int kPathLen = 256; class item_def; class melee_attack; class coord_def; +class level_id; class actor { @@ -84,6 +85,8 @@ public: virtual size_type body_size(int psize = PSIZE_TORSO, bool base = false) const = 0; + virtual int body_weight() const = 0; + virtual int total_weight() const = 0; virtual int damage_type(int which_attack = -1) = 0; virtual int damage_brand(int which_attack = -1) = 0; @@ -156,6 +159,8 @@ public: virtual int res_negative_energy() const = 0; virtual flight_type flies() const = 0; + virtual bool is_levitating() const = 0; + virtual bool airborne() const; virtual bool paralysed() const = 0; virtual bool confused() const = 0; @@ -184,6 +189,10 @@ public: { return (true); } + + virtual bool will_trigger_shaft() const; + virtual level_id shaft_dest() const; + virtual bool do_shaft() = 0; }; struct coord_def @@ -729,6 +738,8 @@ public: bool submerged() const; bool floundering() const; size_type body_size(int psize = PSIZE_TORSO, bool base = false) const; + int body_weight() const; + int total_weight() const; int damage_type(int attk = -1); int damage_brand(int attk = -1); bool has_claws() const; @@ -778,6 +789,8 @@ public: int res_elec() const; int res_poison() const; int res_negative_energy() const; + bool confusable() const; + bool slowable() const; flight_type flies() const; @@ -813,6 +826,8 @@ public: // modify the player object. std::vector get_all_place_info(bool visited_only = false, bool dungeon_only = false) const; + + bool do_shaft(); }; extern player you; @@ -840,7 +855,6 @@ public: }; class ghost_demon; -class level_id; class mon_enchant { @@ -980,6 +994,8 @@ public: bool can_drown() const; bool floundering() const; size_type body_size(int psize = PSIZE_TORSO, bool base = false) const; + int body_weight() const; + int total_weight() const; int damage_type(int attk = -1); int damage_brand(int attk = -1); @@ -1041,6 +1057,7 @@ public: int res_negative_energy() const; flight_type flies() const; + bool is_levitating() const; bool invisible() const; bool can_see_invisible() const; bool visible_to(actor *looker); @@ -1085,6 +1102,8 @@ public: static int base_speed(int mcls); + bool do_shaft(); + private: void init_with(const monsters &mons); void swap_slots(mon_inv_type a, mon_inv_type b); diff --git a/crawl-ref/source/files.cc b/crawl-ref/source/files.cc index d3848d7c3f..1c1af9c8d0 100644 --- a/crawl-ref/source/files.cc +++ b/crawl-ref/source/files.cc @@ -78,6 +78,7 @@ #include "mtransit.h" #include "notes.h" #include "output.h" +#include "overmap.h" #include "place.h" #include "player.h" #include "randart.h" @@ -902,6 +903,7 @@ bool load( dungeon_feature_type stair_taken, int load_mode, // GENERATE new level when the file can't be opened: if (levelFile == NULL) { + env.turns_on_level = -1; builder( you.your_level, you.level_type ); just_created_level = true; @@ -1029,6 +1031,19 @@ bool load( dungeon_feature_type stair_taken, int load_mode, setup_environment_effects(); + // Inform user of level's annotation. + if (get_level_annotation().length() > 0 + && !crawl_state.level_annotation_shown) + { + char buf[200]; + + sprintf(buf, "Level annotation: %s\n", + get_level_annotation().c_str() ); + mpr(buf, MSGCH_PLAIN, YELLOW); + } + + crawl_state.level_annotation_shown = false; + if (load_mode != LOAD_RESTART_GAME) { // Update PlaceInfo entries diff --git a/crawl-ref/source/luadgn.cc b/crawl-ref/source/luadgn.cc index 35c329ddf4..42e07d0ee6 100644 --- a/crawl-ref/source/luadgn.cc +++ b/crawl-ref/source/luadgn.cc @@ -1070,7 +1070,7 @@ const char *dngn_feature_names[] = "", "", "", "", "", "", "", "", "", "", "", "", "", "lava", "deep_water", "", "", "shallow_water", "water_stuck", "floor", "floor_special", "floor_reserved", "exit_hell", "enter_hell", - "open_door", "", "", "trap_mechanical", "trap_magical", "trap_iii", + "open_door", "", "", "trap_mechanical", "trap_magical", "trap_natural", "undiscovered_trap", "", "enter_shop", "enter_labyrinth", "stone_stairs_down_i", "stone_stairs_down_ii", "stone_stairs_down_iii", "rock_stairs_down", "stone_stairs_up_i", diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc index 9fa0620419..99d4071344 100644 --- a/crawl-ref/source/misc.cc +++ b/crawl-ref/source/misc.cc @@ -60,6 +60,7 @@ #include "mon-util.h" #include "monstuff.h" #include "ouch.h" +#include "overmap.h" #include "place.h" #include "player.h" #include "religion.h" @@ -541,6 +542,31 @@ void up_stairs(dungeon_feature_type force_stair, return; } + level_id old_level_id = level_id::current(); + LevelInfo &old_level_info = travel_cache.get_level_info(old_level_id); + + // Does the next level have a warning annotation? + coord_def pos(you.x_pos, you.y_pos); + level_id next_level_id = level_id::get_next_level_id(pos); + + crawl_state.level_annotation_shown = false; + + if (level_annotation_has("WARN", next_level_id) + && next_level_id != level_id::current() + && next_level_id.level_type == LEVEL_DUNGEON && !force_stair) + { + mpr("Warning: level annotation for next level is:", MSGCH_PROMPT); + mpr(get_level_annotation(next_level_id).c_str(), MSGCH_PROMPT); + + if (!yesno("Enter next level anyways?", true, 0, true, false)) + { + interrupt_activity( AI_FORCE_INTERRUPT ); + return; + } + + crawl_state.level_annotation_shown = true; + } + // Since the overloaded message set turn_is_over, I'm assuming that // the overloaded character makes an attempt... so we're doing this // check before that one. -- bwr @@ -581,9 +607,6 @@ void up_stairs(dungeon_feature_type force_stair, // Interlevel travel data: const bool collect_travel_data = can_travel_interlevel(); - level_id old_level_id = level_id::current(); - LevelInfo &old_level_info = travel_cache.get_level_info(old_level_id); - int stair_x = you.x_pos, stair_y = you.y_pos; if (collect_travel_data) old_level_info.update(); @@ -713,6 +736,8 @@ void up_stairs(dungeon_feature_type force_stair, travel_cache.get_level_info(new_level_id); new_level_info.update(); + int stair_x = you.x_pos, stair_y = you.y_pos; + // First we update the old level's stair. level_pos lp; lp.id = new_level_id; @@ -737,7 +762,7 @@ void up_stairs(dungeon_feature_type force_stair, guess = true; } - old_level_info.update_stair(stair_x, stair_y, lp, guess); + old_level_info.update_stair(you.x_pos, you.y_pos, lp, guess); // We *guess* that going up a staircase lands us on a downstair, // and that we can descend that downstair and get back to where we @@ -767,6 +792,12 @@ void down_stairs( int old_level, dungeon_feature_type force_stair, branch_type old_where = you.where_are_you; + bool shaft = ((!force_stair + && trap_type_at_xy(you.x_pos, you.y_pos) == TRAP_SHAFT) + || force_stair == DNGN_TRAP_NATURAL); + level_id shaft_dest; + int shaft_level = -1; + #ifdef SHUT_LABYRINTH if (stair_find == DNGN_ENTER_LABYRINTH) { @@ -777,7 +808,7 @@ void down_stairs( int old_level, dungeon_feature_type force_stair, #endif // probably still need this check here (teleportation) -- bwr - if (grid_stair_direction(stair_find) != CMD_GO_DOWNSTAIRS) + if (grid_stair_direction(stair_find) != CMD_GO_DOWNSTAIRS && !shaft) { if (stair_find == DNGN_STONE_ARCH) mpr("There is nothing on the other side of the stone arch."); @@ -806,6 +837,46 @@ void down_stairs( int old_level, dungeon_feature_type force_stair, return; } + if (shaft) + { + bool known_trap = (grd[you.x_pos][you.y_pos] != DNGN_UNDISCOVERED_TRAP + && !force_stair); + + if (you.airborne() && !known_trap && !force_stair) + { + mpr("You can't go down here!"); + return; + } + + if (you.airborne() && you.flies() != FL_FLY && !force_stair) + { + if (known_trap) + mpr("You must have controlled flight to dive through " + "a shaft."); + return; + } + + if (!is_valid_shaft_level()) + { + if (known_trap) + mpr("Strange, the shaft doesn't seem to lead anywhere."); + return; + } + + shaft_dest = you.shaft_dest(); + if (shaft_dest == level_id::current()) + { + if (known_trap) + mpr("Strange, the shaft doesn't seem to lead anywhere."); + return; + } + shaft_level = absdungeon_depth(shaft_dest.branch, + shaft_dest.depth); + + if (you.flies() != FL_FLY || force_stair) + mpr("You fall through a shaft!"); + } + // All checks are done, the player is on the move now. // Fire level-leaving trigger. @@ -839,7 +910,7 @@ void down_stairs( int old_level, dungeon_feature_type force_stair, switch (NUMBER_OF_RUNES_NEEDED) { case 1: - mpr("You need a Rune to enter this place."); + mpr("You need one more Rune to enter this place."); break; default: @@ -850,6 +921,28 @@ void down_stairs( int old_level, dungeon_feature_type force_stair, } } + // Does the next level have a warning annotation? + coord_def pos = you.pos(); + level_id next_level_id = level_id::get_next_level_id(pos); + + crawl_state.level_annotation_shown = false; + + if (level_annotation_has("WARN", next_level_id) + && next_level_id != level_id::current() + && next_level_id.level_type == LEVEL_DUNGEON && !force_stair) + { + mpr("Warning: level annotation for next level is:", MSGCH_PROMPT); + mpr(get_level_annotation(next_level_id).c_str(), MSGCH_PROMPT); + + if (!yesno("Enter next level anyways?", true, 0, true, false)) + { + interrupt_activity( AI_FORCE_INTERRUPT ); + return; + } + + crawl_state.level_annotation_shown = true; + } + // Interlevel travel data: bool collect_travel_data = can_travel_interlevel(); @@ -954,7 +1047,12 @@ void down_stairs( int old_level, dungeon_feature_type force_stair, KILLED_BY_FALLING_DOWN_STAIRS ); } - if (you.level_type == LEVEL_DUNGEON) + if (shaft) + { + you.your_level = shaft_level; + you.where_are_you = shaft_dest.branch; + } + else if (you.level_type == LEVEL_DUNGEON) you.your_level++; dungeon_feature_type stair_taken = stair_find; @@ -965,6 +1063,9 @@ void down_stairs( int old_level, dungeon_feature_type force_stair, if (you.level_type == LEVEL_PANDEMONIUM) stair_taken = DNGN_TRANSIT_PANDEMONIUM; + if (shaft) + stair_taken = DNGN_ROCK_STAIRS_DOWN; + switch (you.level_type) { case LEVEL_LABYRINTH: @@ -988,11 +1089,18 @@ void down_stairs( int old_level, dungeon_feature_type force_stair, break; default: - climb_message(stair_find, false, old_level_type); + if (shaft) + { + if (you.flies() == FL_FLY && !force_stair) + mpr("You dive down through the shaft."); + } + else + climb_message(stair_find, false, old_level_type); break; } - exit_stair_message(stair_find, false); + if (!shaft) + exit_stair_message(stair_find, false); if (entered_branch) { @@ -1077,7 +1185,12 @@ void down_stairs( int old_level, dungeon_feature_type force_stair, unsigned char pc = 0; unsigned char pt = random2avg(28, 3); - if (level_type_exits_up(you.level_type)) + if (shaft) + { + you.your_level = shaft_level; + you.where_are_you = shaft_dest.branch; + } + else if (level_type_exits_up(you.level_type)) you.your_level++; else if (level_type_exits_down(you.level_type) && !level_type_exits_down(old_level_type)) @@ -1367,6 +1480,33 @@ bool go_berserk(bool intentional) return true; } // end go_berserk() +bool is_valid_shaft_level() +{ + if (you.level_type != LEVEL_DUNGEON) + return (false); + + // Don't generate shafts in branches where teleport control + // is prevented. Prevents player from going down levels without + // reaching stairs, and also keeps player from getting stuck + // on lower levels with the innability to use teleport control to + // get back up. + if (testbits(get_branch_flags(), LFLAG_NO_TELE_CONTROL)) + { + return (false); + } + + int depth = subdungeon_depth(you.where_are_you, you.your_level); + + // When generating levels, don't place a shaft on the level + // immediately above the bottom of a branch if that branch is + // significantly more dangerous than normal. + int min_delta = 1; + if (env.turns_on_level == -1 && your_branch().dangerous_bottom_level) + min_delta = 2; + + return ((your_branch().depth - depth) >= min_delta); +} + bool is_damaging_cloud(cloud_type type) { switch (type) diff --git a/crawl-ref/source/misc.h b/crawl-ref/source/misc.h index 460c76e403..0dee017b67 100644 --- a/crawl-ref/source/misc.h +++ b/crawl-ref/source/misc.h @@ -123,4 +123,7 @@ bool scramble(void); bool interrupt_cmd_repeat( activity_interrupt_type ai, const activity_interrupt_data &at ); +////////////////////////////////////////////////////////////////////// +bool is_valid_shaft_level(); + #endif diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc index e9731e36d2..c125489b86 100644 --- a/crawl-ref/source/mon-util.cc +++ b/crawl-ref/source/mon-util.cc @@ -369,6 +369,17 @@ bool mons_is_stationary(const monsters *mons) return (mons_class_is_stationary(mons->type)); } +bool mons_class_is_confusable(int mc) +{ + return (smc->resist_magic < MAG_IMMUNE + && mons_intel(mc) > I_PLANT); +} + +bool mons_class_is_slowable(int mc) +{ + return (smc->resist_magic < MAG_IMMUNE); +} + // returns whether a monster is non-solid // and thus can't be affected by some traps bool mons_is_insubstantial(int type) @@ -2387,6 +2398,145 @@ size_type monsters::body_size(int /* psize */, bool /* base */) const return (e? e->size : SIZE_MEDIUM); } +int monsters::body_weight() const +{ + int mclass = type; + + switch(mclass) + { + case MONS_SPECTRAL_THING: + case MONS_SPECTRAL_WARRIOR: + case MONS_ELECTRIC_GOLEM: + case MONS_RAKSHASA_FAKE: + return 0; + + case MONS_ZOMBIE_SMALL: + case MONS_ZOMBIE_LARGE: + case MONS_SKELETON_SMALL: + case MONS_SKELETON_LARGE: + case MONS_SIMULACRUM_SMALL: + case MONS_SIMULACRUM_LARGE: + mclass = number; + break; + default: + break; + } + + int weight = mons_weight(mclass); + + // Water elementals are "insubstantial", but still have weight. + if (weight == 0 && type == MONS_WATER_ELEMENTAL) + weight = 1500; + + // weight == 0 in the monster entry indicates "no corpse". Can't + // use CE_NOCORPSE, because the corpse-effect field is used for + // corpseless monsters to indicate what happens if their blood + // is sucked. Grrrr. + if (weight == 0 && !mons_is_insubstantial(type)) + { + const monsterentry *entry = get_monster_data(mclass); + switch(entry->size) + { + case SIZE_TINY: + weight = 150; + break; + case SIZE_LITTLE: + weight = 300; + break; + case SIZE_SMALL: + weight = 425; + break; + case SIZE_MEDIUM: + weight = 550; + break; + case SIZE_LARGE: + weight = 1300; + break; + case SIZE_BIG: + weight = 1500; + break; + case SIZE_GIANT: + weight = 1800; + break; + case SIZE_HUGE: + weight = 2200; + break; + default: + mpr("ERROR: invalid monster body weight"); + perror("monsters::body_weight(): invalid monster body weight"); + end(0); + } + + switch(mclass) + { + case MONS_IRON_DEVIL: + weight += 550; + break; + + case MONS_STONE_GOLEM: + case MONS_EARTH_ELEMENTAL: + case MONS_CRYSTAL_GOLEM: + weight *= 2; + break; + + case MONS_IRON_DRAGON: + case MONS_IRON_GOLEM: + weight *= 3; + break; + + case MONS_QUICKSILVER_DRAGON: + case MONS_SILVER_STATUE: + weight *= 4; + break; + + case MONS_WOOD_GOLEM: + weight *= 2; + weight /= 3; + break; + + case MONS_FLYING_SKULL: + case MONS_CURSE_SKULL: + case MONS_SKELETAL_DRAGON: + case MONS_SKELETAL_WARRIOR: + weight /= 2; + break; + + case MONS_SHADOW_FIEND: + case MONS_SHADOW_IMP: + case MONS_SHADOW_DEMON: + weight /= 3; + break; + } + + switch(monster_symbols[mclass].glyph) + { + case 'L': + weight /= 2; + break; + + case 'p': + weight = 0; + break; + } + } + + if (type == MONS_SKELETON_SMALL || type == MONS_SKELETON_LARGE) + weight /= 2; + + return (weight); +} + +int monsters::total_weight() const +{ + int burden = 0; + + for (int i = 0; i < NUM_MONSTER_SLOTS; i++) + if (inv[i] != NON_ITEM) + burden += item_mass(mitm[inv[i]]) * mitm[inv[i]].quantity; + + return (body_weight() + burden); +} + int monsters::damage_type(int which_attack) { const item_def *mweap = weapon(which_attack); @@ -3307,6 +3457,11 @@ flight_type monsters::flies() const return (mons_flies(this)); } +bool monsters::is_levitating() const +{ + return (mons_class_flag(type, M_LEVITATE)); +} + int monsters::mons_species() const { return ::mons_species(type); @@ -4658,6 +4813,70 @@ void monsters::apply_location_effects() if (alive()) mons_check_pool(this); } + +bool monsters::do_shaft() +{ + if (!is_valid_shaft_level()) + return (false); + + bool nearby = mons_near(this); + bool vis = player_monster_visible(this); + + // Handle instances of do_shaft() being invoked magically when + // the monster isn't standing over a shaft. + if (trap_type_at_xy(x, y) != TRAP_SHAFT) + { + switch(grd[x][y]) + { + case DNGN_FLOOR: + case DNGN_OPEN_DOOR: + case DNGN_TRAP_MECHANICAL: + case DNGN_TRAP_MAGICAL: + case DNGN_TRAP_NATURAL: + case DNGN_UNDISCOVERED_TRAP: + case DNGN_ENTER_SHOP: + break; + + default: + return (false); + } + + if (airborne() || total_weight() == 0) + { + if (nearby) + { + if (vis) + mprf("A shaft briefly opens up underneath %s!", + name(DESC_NOCAP_THE).c_str()); + else + mpr("A shaft briefly opens up in the floor!"); + } + return (true); + } + } + + level_id lev = shaft_dest(); + + if (lev == level_id::current()) + return (false); + + set_transit(lev); + + if (nearby) + { + if (vis) + mprf("%s falls through a shaft!", + name(DESC_CAP_THE).c_str()); + else + mpr("A shaft briefly opens up in the floor!"); + } + + // Monster is no longer on this level + destroy_inventory(); + monster_cleanup(this); + + return true; +} ///////////////////////////////////////////////////////////////////////// // mon_enchant diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h index 9354469d08..6e4b032495 100644 --- a/crawl-ref/source/mon-util.h +++ b/crawl-ref/source/mon-util.h @@ -578,6 +578,8 @@ bool mons_looks_distracted(const monsters *m); bool check_mons_resist_magic( const monsters *monster, int pow ); bool mons_class_is_stationary(int monsclass); +bool mons_class_is_confusable(int monsclass); +bool mons_class_is_slowable(int monsclass); bool mons_is_stationary(const monsters *mons); bool mons_is_insubstantial(int type); bool mons_is_submerged( const monsters *mon ); diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc index 31ef7ef44a..693fcb1125 100644 --- a/crawl-ref/source/monplace.cc +++ b/crawl-ref/source/monplace.cc @@ -325,6 +325,24 @@ monster_type pick_random_monster(const level_id &place, return (mon_type); } +static bool can_place_on_trap(int mon_type, trap_type trap) +{ + if (trap == TRAP_TELEPORT) + return (false); + + if (trap == TRAP_SHAFT) + { + if (mon_type == RANDOM_MONSTER) + return (false); + + return (mons_class_flag(mon_type, M_FLIES) + || mons_class_flag(mon_type, M_LEVITATE) + || get_monster_data(mon_type)->size == SIZE_TINY); + } + + return (true); +} + bool place_monster(int &id, int mon_type, int power, beh_type behaviour, int target, bool summoned, int px, int py, bool allow_bands, proximity_type proximity, int extra, int dur, @@ -372,7 +390,7 @@ bool place_monster(int &id, int mon_type, int power, beh_type behaviour, int trap = trap_at_xy(px, py); if (trap >= 0) { - if (env.trap[trap].type == TRAP_TELEPORT) + if (!can_place_on_trap(mon_type, env.trap[trap].type)) continue; } @@ -509,7 +527,7 @@ bool place_monster(int &id, int mon_type, int power, beh_type behaviour, int trap = trap_at_xy(px, py); if (trap >= 0) { - if (env.trap[trap].type == TRAP_TELEPORT) + if (!can_place_on_trap(mon_type, env.trap[trap].type)) continue; } @@ -686,7 +704,7 @@ static int place_monster_aux( int mon_type, beh_type behaviour, int target, // (how do they get there?) int trap = trap_at_xy(fx, fy); if (trap >= 0) - if (env.trap[trap].type == TRAP_TELEPORT) + if (!can_place_on_trap(mon_type, env.trap[trap].type)) continue; // cool.. passes all tests diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc index bcf04efba4..f49a24aaf9 100644 --- a/crawl-ref/source/monstuff.cc +++ b/crawl-ref/source/monstuff.cc @@ -4514,8 +4514,7 @@ static void do_move_monster(monsters *monster, int xi, int yi) void mons_check_pool(monsters *mons, killer_type killer, int killnum) { // Levitating/flying monsters don't make contact with the terrain. - const flight_type lev = mons->flies(); - if (lev == FL_LEVITATE || (lev == FL_FLY && !mons->paralysed())) + if (mons->airborne()) return; int grid = grd(mons->pos()); @@ -4571,6 +4570,9 @@ static bool is_trap_safe(const monsters *monster, const trap_struct &trap) if (mons_intel(monster->type) == I_PLANT) return (true); + if (trap.type == TRAP_SHAFT && monster->will_trigger_shaft()) + return (false); + // Healthy monsters don't mind a little pain. XXX: Smart humanoids // with low hp should probably not try to go through high-damage // traps. diff --git a/crawl-ref/source/mstuff2.cc b/crawl-ref/source/mstuff2.cc index a202ea04dc..2c508f290b 100644 --- a/crawl-ref/source/mstuff2.cc +++ b/crawl-ref/source/mstuff2.cc @@ -299,6 +299,32 @@ void mons_trap(struct monsters *monster) damage_taken = 0; // just to be certain {dlb} break; + case TRAP_SHAFT: + { + // Paranoia + if (!is_valid_shaft_level()) + { + if (trapKnown && monsterNearby) + mpr("The shaft disappears in a puff of logic!"); + + grd[env.trap[which_trap].x][env.trap[which_trap].y] = DNGN_FLOOR; + env.trap[which_trap].type = TRAP_UNASSIGNED; + return; + } + + if (!monster->will_trigger_shaft()) + { + if (trapKnown && !monster->airborne()) + simple_monster_message(monster, + " fails to trigger the shaft."); + + return; + } + + revealTrap = monster->do_shaft(); + break; + } + default: break; } diff --git a/crawl-ref/source/overmap.cc b/crawl-ref/source/overmap.cc index b414e4e443..c1fb568ca8 100644 --- a/crawl-ref/source/overmap.cc +++ b/crawl-ref/source/overmap.cc @@ -26,6 +26,7 @@ #include "externs.h" #include "branch.h" +#include "cio.h" #include "dgnevent.h" #include "direct.h" #include "dungeon.h" @@ -43,11 +44,13 @@ typedef std::map stair_map_type; typedef std::map shop_map_type; typedef std::map altar_map_type; typedef std::map portal_map_type; +typedef std::map annotation_map_type; stair_map_type stair_level; shop_map_type shops_present; altar_map_type altars_present; portal_map_type portals_present; +annotation_map_type level_annotations; static void seen_altar( god_type god, const coord_def& pos ); static void seen_staircase(dungeon_feature_type which_staircase, @@ -368,6 +371,61 @@ std::string overview_description_string() disp += "You didn't discover anything interesting."; } + bool notes_exist = false; + bool has_notes[NUM_BRANCHES]; + + for (int i = 0; i < NUM_BRANCHES; ++i) + { + Branch branch = branches[i]; + + has_notes[i] = false; + for (int depth = 1; depth <= branch.depth; depth++) + { + const level_id li(branch.id, depth); + + if (get_level_annotation(li).length() > 0) + { + notes_exist = true; + has_notes[i] = true; + break; + } + } + } + + if (notes_exist) + { + disp += "\n\n Level Annotations\n" ; + + for (int i = 0; i < NUM_BRANCHES; ++i) + { + if (!has_notes[i]) + continue; + + Branch branch = branches[i]; + + disp += "\n"; + disp += branch.shortname; + disp += "\n"; + + for (int depth = 1; depth <= branch.depth; depth++) + { + const level_id li(branch.id, depth); + + if (get_level_annotation(li).length() > 0) + { + char depth_str[3]; + sprintf(depth_str, "%2d", depth); + + disp += ""; + disp += depth_str; + disp += ": "; + disp += get_level_annotation(li); + disp += + "\n"; + } + } + } + } + return disp; } @@ -510,3 +568,95 @@ void seen_other_thing( dungeon_feature_type which_thing, const coord_def& pos ) break; } } // end seen_other_thing() + +//////////////////////////////////////////////////////////////////////// + +void set_level_annotation(std::string str, + level_id li) +{ + if (str == "") + { + clear_level_annotation(li); + return; + } + + level_annotations[li] = str; +} + +void clear_level_annotation(level_id li) +{ + level_annotations.erase(li); +} + +std::string get_level_annotation(level_id li) +{ + annotation_map_type::const_iterator i = level_annotations.find(li); + + if (i == level_annotations.end()) + return ""; + + return (i->second); +} + +bool level_annotation_has(std::string find, + level_id li) +{ + std::string str = get_level_annotation(li); + + return (str.find(find) != std::string::npos); +} + +void annotate_level() +{ + level_id li = level_id::current(); + level_id li2 = level_id::current(); + + if (is_stair(grd[you.x_pos][you.y_pos])) + { + li2 = level_id::get_next_level_id(you.pos()); + + if (li2.level_type != LEVEL_DUNGEON || li2.depth <= 0) + li2 = level_id::current(); + } + + if (you.level_type != LEVEL_DUNGEON && li2.level_type != LEVEL_DUNGEON) + { + mpr("You can't annotate this level."); + return; + } + + if (you.level_type != LEVEL_DUNGEON) + li = li2; + else if (li2 != level_id::current()) + { + if (yesno("Annotate level on other end of current stairs?")) + li = li2; + } + + if (get_level_annotation(li).length() > 0) + { + mpr("Current level annotation is:", MSGCH_PROMPT); + mpr(get_level_annotation(li).c_str() ); + } + + mpr( "Set level annotation to what? ", MSGCH_PROMPT ); + + char buf[77]; + get_input_line( buf, sizeof(buf) ); + + if (strlen(buf) == 0) + { + if (get_level_annotation(li).length() > 0) + { + if (!yesno("Really clear the annotation?")) + return; + } + else + { + canned_msg(MSG_OK); + return; + } + } + + set_level_annotation(buf, li); +} diff --git a/crawl-ref/source/overmap.h b/crawl-ref/source/overmap.h index f9f16a71ad..035779f004 100644 --- a/crawl-ref/source/overmap.h +++ b/crawl-ref/source/overmap.h @@ -21,4 +21,16 @@ void display_overmap(); bool unnotice_feature(const level_pos &pos); std::string overview_description_string(); +/////////////////////////////////////////////////////////// +void set_level_annotation(std::string str, + level_id li = level_id::current()); +void clear_level_annotation(level_id li = level_id::current()); + +std::string get_level_annotation(level_id li = level_id::current()); + +bool level_annotation_has(std::string str, + level_id li = level_id::current()); + +void annotate_level(); + #endif diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc index 57562b1d85..c682fd9f5f 100644 --- a/crawl-ref/source/player.cc +++ b/crawl-ref/source/player.cc @@ -54,6 +54,7 @@ #include "notes.h" #include "ouch.h" #include "output.h" +#include "place.h" #include "randart.h" #include "religion.h" #include "skills.h" @@ -5016,6 +5017,46 @@ actor::~actor() { } +bool actor::will_trigger_shaft() const +{ + return (!airborne() && total_weight() >= 300 + && is_valid_shaft_level()); +} + +level_id actor::shaft_dest() const +{ + if (you.level_type != LEVEL_DUNGEON) + return level_id::current(); + + level_id lev = level_id::current(); + int curr_depth = subdungeon_depth(you.where_are_you, you.your_level); + + lev.depth += ((pos().x + pos().y) % 3) + 1; + + if (lev.depth > your_branch().depth) + lev.depth = your_branch().depth; + + if (lev.depth == curr_depth) + return lev; + + // Only shafts on the level immediately above a dangeorus branch + // bottom will take you to that dangerous bottom, and shafts can't + // be created during level generation time. + if (your_branch().dangerous_bottom_level + && lev.depth == your_branch().depth + && (your_branch().depth - curr_depth) > 1) + { + lev.depth--; + } + + return lev; +} + +bool actor::airborne() const +{ + return (is_levitating() || (flies() == FL_FLY && !paralysed())); +} + ////////////////////////////////////////////////////////////////////////////// // player @@ -5253,14 +5294,12 @@ coord_def player::pos() const bool player::is_levitating() const { - return (attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON || - attribute[ATTR_TRANSFORMATION] == TRAN_BAT || - duration[DUR_LEVITATION]); + return (duration[DUR_LEVITATION]); } bool player::in_water() const { - return (!player_is_levitating() && !beogh_water_walk() + return (!airborne() && !beogh_water_walk() && grid_is_water(grd[you.x_pos][you.y_pos])); } @@ -5341,6 +5380,64 @@ size_type player::body_size(int psize, bool base) const return (ret); } +int player::body_weight() const +{ + if (attribute[ATTR_TRANSFORMATION] == TRAN_AIR) + return 0; + + int weight; + switch(body_size(PSIZE_BODY)) + { + case SIZE_TINY: + weight = 150; + break; + case SIZE_LITTLE: + weight = 300; + break; + case SIZE_SMALL: + weight = 425; + break; + case SIZE_MEDIUM: + weight = 550; + break; + case SIZE_LARGE: + weight = 1300; + break; + case SIZE_BIG: + weight = 1500; + break; + case SIZE_GIANT: + weight = 1800; + break; + case SIZE_HUGE: + weight = 2200; + break; + default: + mpr("ERROR: invalid player body weight"); + perror("player::body_weight(): invalid player body weight"); + end(0); + } + + switch(attribute[ATTR_TRANSFORMATION]) + { + case TRAN_STATUE: + weight *= 2; + break; + case TRAN_LICH: + weight /= 2; + break; + default: + break; + } + + return (weight); +} + +int player::total_weight() const +{ + return (body_weight() + burden); +} + bool player::cannot_speak() const { if (silenced(x_pos, y_pos)) @@ -5723,14 +5820,29 @@ int player::res_negative_energy() const return (player_prot_life()); } +bool player::confusable() const +{ + return (player_mental_clarity() == 0); +} + +bool player::slowable() const +{ + return (!wearing_amulet(AMU_RESIST_SLOW)); +} + flight_type player::flies() const { - if ( !is_levitating() ) - return (FL_NONE); - else + if (attribute[ATTR_TRANSFORMATION] == TRAN_DRAGON || + attribute[ATTR_TRANSFORMATION] == TRAN_BAT) + { + return FL_FLY; + } + else if (is_levitating()) return (you.duration[DUR_CONTROLLED_FLIGHT] || wearing_amulet(AMU_CONTROLLED_FLIGHT) ? FL_FLY : FL_LEVITATE); + else + return (FL_NONE); } bool player::light_flight() const @@ -6173,3 +6285,43 @@ std::vector player::get_all_place_info(bool visited_only, return list; } +bool player::do_shaft() +{ + dungeon_feature_type force_stair = DNGN_UNSEEN; + + if (!is_valid_shaft_level()) + return (false); + + // Handle instances of do_shaft() being invoked magically when + // the player isn't standing over a shaft. + if (trap_type_at_xy(x_pos, y_pos) != TRAP_SHAFT) + { + switch(grd[x_pos][y_pos]) + { + case DNGN_FLOOR: + case DNGN_OPEN_DOOR: + case DNGN_TRAP_MECHANICAL: + case DNGN_TRAP_MAGICAL: + case DNGN_TRAP_NATURAL: + case DNGN_UNDISCOVERED_TRAP: + case DNGN_ENTER_SHOP: + break; + + default: + return (false); + } + + if (airborne() || total_weight() == 0) + { + mpr("A shaft briefly opens up underneath you!"); + return (true); + } + + force_stair = DNGN_TRAP_NATURAL; + } + + down_stairs(your_level, force_stair); + + return (true); +} + diff --git a/crawl-ref/source/spells3.cc b/crawl-ref/source/spells3.cc index f8e6621329..994900fc2b 100644 --- a/crawl-ref/source/spells3.cc +++ b/crawl-ref/source/spells3.cc @@ -673,7 +673,7 @@ bool entomb(int powc) const dungeon_feature_type safe_to_overwrite[] = { DNGN_FLOOR, DNGN_SHALLOW_WATER, DNGN_OPEN_DOOR, - DNGN_TRAP_MECHANICAL, DNGN_TRAP_MAGICAL, DNGN_TRAP_III, + DNGN_TRAP_MECHANICAL, DNGN_TRAP_MAGICAL, DNGN_TRAP_NATURAL, DNGN_UNDISCOVERED_TRAP, DNGN_FLOOR_SPECIAL }; diff --git a/crawl-ref/source/spells4.cc b/crawl-ref/source/spells4.cc index 486c649878..89a2080863 100644 --- a/crawl-ref/source/spells4.cc +++ b/crawl-ref/source/spells4.cc @@ -2667,7 +2667,6 @@ void cast_fragmentation(int pow) // jmf: ripped idea from airstrike : "The dungeon floor"); break; - case DNGN_TRAP_III: // What are these? Should they explode? -- bwr default: // FIXME: cute message for water? break; diff --git a/crawl-ref/source/state.cc b/crawl-ref/source/state.cc index 21c25d8450..2d086dd724 100644 --- a/crawl-ref/source/state.cc +++ b/crawl-ref/source/state.cc @@ -33,7 +33,8 @@ game_state::game_state() terminal_resize_check(NULL), doing_prev_cmd_again(false), prev_cmd(CMD_NO_CMD), repeat_cmd(CMD_NO_CMD), cmd_repeat_count(0), cmd_repeat_goal(0), prev_repetition_turn(0), - cmd_repeat_started_unsafe(false), input_line_curr(0) + cmd_repeat_started_unsafe(false), input_line_curr(0), + level_annotation_shown(false) { reset_cmd_repeat(); reset_cmd_again(); diff --git a/crawl-ref/source/state.h b/crawl-ref/source/state.h index 4b4952026a..8347cd0470 100644 --- a/crawl-ref/source/state.h +++ b/crawl-ref/source/state.h @@ -68,6 +68,8 @@ struct game_state std::vector input_line_strs; unsigned int input_line_curr; + bool level_annotation_shown; + protected: void reset_cmd_repeat(); void reset_cmd_again(); diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc index 757717c248..8b8eb8db18 100644 --- a/crawl-ref/source/tags.cc +++ b/crawl-ref/source/tags.cc @@ -96,6 +96,7 @@ extern std::map stair_level; extern std::map shops_present; extern std::map altars_present; extern std::map portals_present; +extern std::map level_annotations; // temp file pairs used for file level cleanup FixedArray < bool, MAX_LEVELS, NUM_BRANCHES > tmp_file_pairs; @@ -423,6 +424,12 @@ void marshallString(struct tagHeader &th, const std::string &data, int maxSize) th.offset += len; } +// To pass to marsahllMap +static void marshall_string(struct tagHeader &th, const std::string &data) +{ + marshallString(th, data); +} + // string -- unmarshall length & string data int unmarshallCString(struct tagHeader &th, char *data, int maxSize) { @@ -456,6 +463,12 @@ std::string unmarshallString(tagHeader &th, int maxSize) return (res); } +// To pass to unmarshallMap +static std::string unmarshall_string(struct tagHeader &th) +{ + return unmarshallString(th); +} + // boolean (to avoid system-dependant bool implementations) void marshallBoolean(struct tagHeader &th, bool data) { @@ -1039,6 +1052,8 @@ static void tag_construct_you_dungeon(struct tagHeader &th) marshall_level_pos, marshall_as_long); marshallMap(th, portals_present, marshall_level_pos, marshall_as_long); + marshallMap(th, level_annotations, + marshall_level_id, marshall_string); marshallPlaceInfo(th, you.global_info); std::vector list = you.get_all_place_info(); @@ -1435,6 +1450,8 @@ static void tag_read_you_dungeon(struct tagHeader &th) unmarshall_level_pos, unmarshall_long_as); unmarshallMap(th, portals_present, unmarshall_level_pos, unmarshall_long_as); + unmarshallMap(th, level_annotations, + unmarshall_level_id, unmarshall_string); PlaceInfo place_info = unmarshallPlaceInfo(th); ASSERT(place_info.is_global()); diff --git a/crawl-ref/source/terrain.cc b/crawl-ref/source/terrain.cc index 272768ba54..31e0c52308 100644 --- a/crawl-ref/source/terrain.cc +++ b/crawl-ref/source/terrain.cc @@ -177,7 +177,7 @@ bool grid_is_solid(const coord_def &c) bool grid_is_trap(dungeon_feature_type grid) { return (grid == DNGN_TRAP_MECHANICAL || grid == DNGN_TRAP_MAGICAL - || grid == DNGN_TRAP_III); + || grid == DNGN_TRAP_NATURAL); } bool grid_is_water( dungeon_feature_type grid ) diff --git a/crawl-ref/source/traps.cc b/crawl-ref/source/traps.cc index cc4638c842..ede8d6561e 100644 --- a/crawl-ref/source/traps.cc +++ b/crawl-ref/source/traps.cc @@ -383,6 +383,42 @@ void handle_traps(char trt, int i, bool trap_known) env.trap[i].type = TRAP_UNASSIGNED; } break; + + // If we don't trigger the shaft, and the player doesn't + // already know about it, don't let him/her notice it. + case TRAP_SHAFT: + { + // Paranoia + if (!is_valid_shaft_level()) + { + if (trap_known); + mpr("The shaft disappears in a puff of logic!"); + + grd[env.trap[i].x][env.trap[i].y] = DNGN_FLOOR; + env.trap[i].type = TRAP_UNASSIGNED; + return; + } + + if (!you.will_trigger_shaft()) + { + if (trap_known && !you.airborne()) + mpr("You fail to trigger the shaft."); + + if (!trap_known) + grd[you.x_pos][you.y_pos] = DNGN_UNDISCOVERED_TRAP; + + return; + } + + if (!you.do_shaft()) + if (!trap_known) + { + grd[you.x_pos][you.y_pos] = DNGN_UNDISCOVERED_TRAP; + return; + } + + break; + } case TRAP_ZOT: default: @@ -770,6 +806,9 @@ dungeon_feature_type trap_category(trap_type type) { switch (type) { + case TRAP_SHAFT: + return (DNGN_TRAP_NATURAL); + case TRAP_TELEPORT: case TRAP_AMNESIA: case TRAP_ZOT: diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc index de20a9dd85..f6ce704892 100644 --- a/crawl-ref/source/view.cc +++ b/crawl-ref/source/view.cc @@ -2524,7 +2524,7 @@ bool is_feature(int feature, int x, int y) { case DNGN_TRAP_MECHANICAL: case DNGN_TRAP_MAGICAL: - case DNGN_TRAP_III: + case DNGN_TRAP_NATURAL: return true; default: return false; @@ -3630,10 +3630,10 @@ void init_feature_table( void ) Feature[i].map_colour = MAGENTA; break; - case DNGN_TRAP_III: - Feature[i].colour = LIGHTGREY; + case DNGN_TRAP_NATURAL: + Feature[i].colour = BROWN; Feature[i].symbol = Options.char_table[ DCHAR_TRAP ]; - Feature[i].map_colour = LIGHTGREY; + Feature[i].map_colour = BROWN; break; case DNGN_UNDISCOVERED_TRAP: -- cgit v1.2.3-54-g00ecf