summaryrefslogtreecommitdiffstats
path: root/crawl-ref
diff options
context:
space:
mode:
authorzelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573>2007-10-05 06:10:49 +0000
committerzelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573>2007-10-05 06:10:49 +0000
commit1db9c68406e0892e1ac7331dfd3b412b31741cb7 (patch)
treedabc507f32d87ba59c660f45fffa6b5b9042e6c5 /crawl-ref
parent70d59beabaddfbb2edefee1f610e16881c8ff771 (diff)
downloadcrawl-ref-1db9c68406e0892e1ac7331dfd3b412b31741cb7.tar.gz
crawl-ref-1db9c68406e0892e1ac7331dfd3b412b31741cb7.zip
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
Diffstat (limited to 'crawl-ref')
-rw-r--r--crawl-ref/source/acr.cc34
-rw-r--r--crawl-ref/source/branch.cc46
-rw-r--r--crawl-ref/source/branch.h1
-rw-r--r--crawl-ref/source/command.cc1
-rw-r--r--crawl-ref/source/dat/descript/features.txt3
-rw-r--r--crawl-ref/source/describe.cc4
-rw-r--r--crawl-ref/source/direct.cc8
-rw-r--r--crawl-ref/source/dungeon.cc20
-rw-r--r--crawl-ref/source/enum.h5
-rw-r--r--crawl-ref/source/externs.h21
-rw-r--r--crawl-ref/source/files.cc15
-rw-r--r--crawl-ref/source/luadgn.cc2
-rw-r--r--crawl-ref/source/misc.cc160
-rw-r--r--crawl-ref/source/misc.h3
-rw-r--r--crawl-ref/source/mon-util.cc219
-rw-r--r--crawl-ref/source/mon-util.h2
-rw-r--r--crawl-ref/source/monplace.cc24
-rw-r--r--crawl-ref/source/monstuff.cc6
-rw-r--r--crawl-ref/source/mstuff2.cc26
-rw-r--r--crawl-ref/source/overmap.cc150
-rw-r--r--crawl-ref/source/overmap.h12
-rw-r--r--crawl-ref/source/player.cc166
-rw-r--r--crawl-ref/source/spells3.cc2
-rw-r--r--crawl-ref/source/spells4.cc1
-rw-r--r--crawl-ref/source/state.cc3
-rw-r--r--crawl-ref/source/state.h2
-rw-r--r--crawl-ref/source/tags.cc17
-rw-r--r--crawl-ref/source/terrain.cc2
-rw-r--r--crawl-ref/source/traps.cc39
-rw-r--r--crawl-ref/source/view.cc8
30 files changed, 939 insertions, 63 deletions
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)
"<w>Ctrl-P</w> : show Previous messages\n"
"<w>Ctrl-R</w> : Redraw screen\n"
"<w>Ctrl-C</w> : Clear main and level maps\n"
+ "<w>Ctrl-I</w> : annotate the dungeon level\n"
"<w>#</w> : dump character to file\n"
"<w>:</w> : add note (use <w>?:</w> to read notes)\n"
"<w>~</w> : 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
@@ -85,6 +85,9 @@ A magical trap
A mechanical trap
%%%%
+A natural trap
+
+%%%%
A metal wall
A wall of bluish-grey metal.
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<trap_type>( 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<trap_type>( 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<PlaceInfo> 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<branch_type, level_id> stair_map_type;
typedef std::map<level_pos, shop_type> shop_map_type;
typedef std::map<level_pos, god_type> altar_map_type;
typedef std::map<level_pos, portal_type> portal_map_type;
+typedef std::map<level_id, std::string> 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 <white>Level Annotations</white>\n" ;
+
+ for (int i = 0; i < NUM_BRANCHES; ++i)
+ {
+ if (!has_notes[i])
+ continue;
+
+ Branch branch = branches[i];
+
+ disp += "\n<yellow>";
+ disp += branch.shortname;
+ disp += "</yellow>\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 += "<white>";
+ disp += depth_str;
+ disp += ":</white> ";
+ 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<PlaceInfo> 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<std::string> 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<branch_type, level_id> stair_level;
extern std::map<level_pos, shop_type> shops_present;
extern std::map<level_pos, god_type> altars_present;
extern std::map<level_pos, portal_type> portals_present;
+extern std::map<level_id, std::string> 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<god_type>);
marshallMap(th, portals_present,
marshall_level_pos, marshall_as_long<portal_type>);
+ marshallMap(th, level_annotations,
+ marshall_level_id, marshall_string);
marshallPlaceInfo(th, you.global_info);
std::vector<PlaceInfo> 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<god_type>);
unmarshallMap(th, portals_present,
unmarshall_level_pos, unmarshall_long_as<portal_type>);
+ 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: