summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crawl-ref/source/abyss.cc5
-rw-r--r--crawl-ref/source/acr.cc10
-rw-r--r--crawl-ref/source/debug.cc4
-rw-r--r--crawl-ref/source/decks.cc19
-rw-r--r--crawl-ref/source/directn.cc2
-rw-r--r--crawl-ref/source/dungeon.cc4
-rw-r--r--crawl-ref/source/externs.h27
-rw-r--r--crawl-ref/source/hiscores.cc6
-rw-r--r--crawl-ref/source/misc.cc10
-rw-r--r--crawl-ref/source/mon-util.cc8
-rw-r--r--crawl-ref/source/monplace.cc50
-rw-r--r--crawl-ref/source/monstuff.cc30
-rw-r--r--crawl-ref/source/mstuff2.cc374
-rw-r--r--crawl-ref/source/ouch.cc2
-rw-r--r--crawl-ref/source/player.cc54
-rw-r--r--crawl-ref/source/spells2.cc15
-rw-r--r--crawl-ref/source/spells3.cc27
-rw-r--r--crawl-ref/source/spells4.cc11
-rw-r--r--crawl-ref/source/stash.cc2
-rw-r--r--crawl-ref/source/tags.cc9
-rw-r--r--crawl-ref/source/terrain.cc5
-rw-r--r--crawl-ref/source/terrain.h2
-rw-r--r--crawl-ref/source/traps.cc931
-rw-r--r--crawl-ref/source/traps.h14
24 files changed, 730 insertions, 891 deletions
diff --git a/crawl-ref/source/abyss.cc b/crawl-ref/source/abyss.cc
index 3ab081c559..34a44c16ad 100644
--- a/crawl-ref/source/abyss.cc
+++ b/crawl-ref/source/abyss.cc
@@ -811,8 +811,11 @@ static void _corrupt_square(const crawl_environment &oenv, const coord_def &c)
else
feat = oenv.grid(c);
- if (is_trap_square(feat) || feat == DNGN_SECRET_DOOR || feat == DNGN_UNSEEN)
+ if (grid_is_trap(feat, true)
+ || feat == DNGN_SECRET_DOOR || feat == DNGN_UNSEEN)
+ {
return;
+ }
if (is_traversable(grd(c)) && !is_traversable(feat)
&& _is_crowded_square(c))
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc
index e3629e580a..2a4b67a373 100644
--- a/crawl-ref/source/acr.cc
+++ b/crawl-ref/source/acr.cc
@@ -1697,10 +1697,9 @@ static void _go_upstairs()
static void _go_downstairs()
{
- bool shaft = (trap_type_at_xy(you.pos()) == TRAP_SHAFT
+ bool shaft = (get_trap_type(you.pos()) == TRAP_SHAFT
&& grd(you.pos()) != DNGN_UNDISCOVERED_TRAP);
-
if (_stairs_check_beheld())
return;
@@ -3021,7 +3020,7 @@ static void _check_shafts()
{
for (int i = 0; i < MAX_TRAPS; i++)
{
- trap_struct &trap = env.trap[i];
+ trap_def &trap = env.trap[i];
if (trap.type != TRAP_SHAFT)
continue;
@@ -3512,8 +3511,7 @@ static void _open_door(coord_def move, bool check_confused)
return;
}
- if (grd(doorpos) >= DNGN_TRAP_MECHANICAL
- && grd(doorpos) <= DNGN_TRAP_NATURAL)
+ if (find_trap(doorpos) && grd(doorpos) != DNGN_UNDISCOVERED_TRAP)
{
if (env.cgrid(doorpos) != EMPTY_CLOUD)
{
@@ -3521,7 +3519,7 @@ static void _open_door(coord_def move, bool check_confused)
return;
}
- disarm_trap(door_move);
+ disarm_trap(doorpos);
return;
}
}
diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc
index 830503590e..950c21ef1e 100644
--- a/crawl-ref/source/debug.cc
+++ b/crawl-ref/source/debug.cc
@@ -3844,10 +3844,8 @@ static void _debug_kill_traps()
{
for (int y = 0; y < GYM; ++y)
for (int x = 0; x < GXM; ++x)
- {
- if (is_trap_square(grd[x][y]))
+ if (grid_is_trap(grd[x][y], true))
grd[x][y] = DNGN_FLOOR;
- }
}
static int _debug_time_explore()
diff --git a/crawl-ref/source/decks.cc b/crawl-ref/source/decks.cc
index 567f5fb216..5f96a6da07 100644
--- a/crawl-ref/source/decks.cc
+++ b/crawl-ref/source/decks.cc
@@ -1480,14 +1480,8 @@ static void _warpwright_card(int power, deck_rarity_type rarity)
int count = 0;
coord_def f;
for (adjacent_iterator ai; ai; ++ai)
- {
- if (grd(*ai) == DNGN_FLOOR
- && trap_at_xy(*ai) == -1
- && one_chance_in(++count))
- {
+ if (grd(*ai) == DNGN_FLOOR && find_trap(*ai) && one_chance_in(++count))
f = *ai;
- }
- }
if (count > 0) // found a spot
{
@@ -1495,11 +1489,7 @@ static void _warpwright_card(int power, deck_rarity_type rarity)
{
// Mark it discovered if enough power.
if (get_power_level(power, rarity) >= 1)
- {
- const int i = trap_at_xy(f);
- if (i != -1) // should always happen
- grd(f) = trap_category(env.trap[i].type);
- }
+ find_trap(f)->reveal();
}
}
}
@@ -1533,8 +1523,7 @@ static void _flight_card(int power, deck_rarity_type rarity)
{
if (place_specific_trap(you.pos(), TRAP_SHAFT))
{
- const int i = trap_at_xy(you.pos());
- grd(you.pos()) = trap_category(env.trap[i].type);
+ find_trap(you.pos())->reveal();
mpr("A shaft materialises beneath you!");
}
}
@@ -1554,7 +1543,7 @@ static void _minefield_card(int power, deck_rarity_type rarity)
if ( *ri == you.pos() )
continue;
- if (grd(*ri) == DNGN_FLOOR && trap_at_xy(*ri) == -1
+ if (grd(*ri) == DNGN_FLOOR && !find_trap(*ri)
&& one_chance_in(4 - power_level))
{
if (you.level_type == LEVEL_ABYSS)
diff --git a/crawl-ref/source/directn.cc b/crawl-ref/source/directn.cc
index f6423335f3..6b84395f45 100644
--- a/crawl-ref/source/directn.cc
+++ b/crawl-ref/source/directn.cc
@@ -2510,7 +2510,7 @@ std::string feature_description(const coord_def& where, bool bloody,
case DNGN_TRAP_MECHANICAL:
case DNGN_TRAP_MAGICAL:
case DNGN_TRAP_NATURAL:
- return (feature_description(grid, trap_type_at_xy(where), bloody,
+ return (feature_description(grid, get_trap_type(where), bloody,
dtype, add_stop));
case DNGN_ENTER_SHOP:
return (shop_name(where, add_stop));
diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc
index 6b4bdda1c6..6b024755ea 100644
--- a/crawl-ref/source/dungeon.cc
+++ b/crawl-ref/source/dungeon.cc
@@ -2509,7 +2509,7 @@ static void _place_traps(int level_number)
for (int i = 0; i < num_traps; i++)
{
- trap_struct& ts(env.trap[i]);
+ trap_def& ts(env.trap[i]);
if (ts.type != TRAP_UNASSIGNED)
continue;
@@ -2540,6 +2540,7 @@ static void _place_traps(int level_number)
}
}
grd(ts.pos) = DNGN_UNDISCOVERED_TRAP;
+ ts.prepare_ammo();
}
}
@@ -7296,6 +7297,7 @@ bool place_specific_trap(const coord_def& where, trap_type spec_type)
env.trap[tcount].type = spec_type;
env.trap[tcount].pos = where;
grd(where) = DNGN_UNDISCOVERED_TRAP;
+ env.trap[tcount].prepare_ammo();
return (true);
}
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index bb1be8a97e..a200989c4f 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -363,6 +363,8 @@ public:
virtual bool backlit(bool check_haloed = true) const = 0;
virtual bool haloed() const = 0;
+ virtual bool handle_trap();
+
virtual void god_conduct(conduct_type thing_done, int level) { }
virtual bool incapacitated() const
@@ -1372,10 +1374,29 @@ struct shop_struct
FixedVector<unsigned char, 3> keeper_name;
};
-struct trap_struct
+struct trap_def
{
coord_def pos;
- trap_type type;
+ trap_type type;
+ int ammo_qty;
+
+ dungeon_feature_type category() const;
+ std::string name(description_level_type desc = DESC_PLAIN) const;
+ bool is_known(const actor* act = 0) const;
+ void trigger(actor& triggerer, bool flat_footed = false);
+ void disarm();
+ void destroy();
+ void hide();
+ void reveal();
+ void prepare_ammo();
+ bool type_has_ammo() const;
+ bool active() const;
+
+private:
+ void message_trap_entry();
+ void shoot_ammo(actor& act, bool was_known);
+ item_def generate_trap_item();
+ int shot_damage(actor& act);
};
struct map_cell
@@ -1479,7 +1500,7 @@ public:
unsigned char cloud_no;
FixedVector< shop_struct, MAX_SHOPS > shop; // shop list
- FixedVector< trap_struct, MAX_TRAPS > trap; // trap list
+ FixedVector< trap_def, MAX_TRAPS > trap; // trap list
FixedVector< monster_type, 20 > mons_alloc;
map_markers markers;
diff --git a/crawl-ref/source/hiscores.cc b/crawl-ref/source/hiscores.cc
index 0adefdc5b0..ec7a1f4145 100644
--- a/crawl-ref/source/hiscores.cc
+++ b/crawl-ref/source/hiscores.cc
@@ -1013,8 +1013,10 @@ void scorefile_entry::init()
if (calc_item_values) // winners only
{
- points += (250000 * num_diff_runes)
- * ((25000.0 * num_diff_runes) / (1+you.num_turns));
+ points +=
+ static_cast<long>(
+ (250000 * num_diff_runes)
+ * ((25000.0 * num_diff_runes) / (1+you.num_turns)));
}
// Players will have a hard time getting 1/10 of this (see XP cap):
diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc
index 04c51de4a5..1e85627792 100644
--- a/crawl-ref/source/misc.cc
+++ b/crawl-ref/source/misc.cc
@@ -1269,14 +1269,12 @@ void search_around( bool only_adjacent )
else if (grd(*ri) == DNGN_UNDISCOVERED_TRAP
&& x_chance_in_y(effective + 1, 17))
{
- const int i = trap_at_xy(*ri);
-
- if (i != -1)
+ trap_def* ptrap = find_trap(*ri);
+ if (ptrap)
{
- grd(*ri) = trap_category(env.trap[i].type);
+ ptrap->reveal();
mpr("You found a trap!");
learned_something_new(TUT_SEEN_TRAP, *ri);
-
exercise(SK_TRAPS_DOORS, (coinflip() ? 2 : 1));
}
else
@@ -1720,7 +1718,7 @@ 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.pos()) == TRAP_SHAFT
+ && get_trap_type(you.pos()) == TRAP_SHAFT
|| force_stair == DNGN_TRAP_NATURAL);
level_id shaft_dest;
int shaft_level = -1;
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index d78cc0d6d8..d35caa37c7 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -5464,7 +5464,7 @@ static bool _prepare_del_ench(monsters* mon, const mon_enchant &me)
{
if (mgrd(*ai) == NON_MONSTER
&& monster_habitable_grid(mon, grd(*ai))
- && trap_type_at_xy(*ai) == NUM_TRAPS)
+ && !find_trap(*ai))
{
if (one_chance_in(++okay_squares))
target_square = *ai;
@@ -6537,7 +6537,9 @@ void monsters::apply_location_effects()
dungeon_events.fire_position_event(DET_MONSTER_MOVED, pos());
// monsters stepping on traps:
- mons_trap(this);
+ trap_def* ptrap = find_trap(pos());
+ if (ptrap)
+ ptrap->trigger(*this);
if (alive())
mons_check_pool(this);
@@ -6578,7 +6580,7 @@ bool monsters::do_shaft()
// Handle instances of do_shaft() being invoked magically when
// the monster isn't standing over a shaft.
- if (trap_type_at_xy(this->pos()) != TRAP_SHAFT)
+ if (get_trap_type(this->pos()) != TRAP_SHAFT)
{
switch(grd(pos()))
{
diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc
index 523c18efaf..a60c628957 100644
--- a/crawl-ref/source/monplace.cc
+++ b/crawl-ref/source/monplace.cc
@@ -155,7 +155,7 @@ bool monster_habitable_grid(int monster_class,
bool monster_can_submerge(const monsters *mons, dungeon_feature_type grid)
{
if (mons->type == MONS_TRAPDOOR_SPIDER && grid == DNGN_FLOOR)
- return (trap_type_at_xy(mons->pos()) == NUM_TRAPS);
+ return (!find_trap(mons->pos()));
// Zombies of watery critters can not submerge.
switch (mons_habitat(mons))
@@ -458,12 +458,9 @@ static monster_type _resolve_monster_type(monster_type mon_type,
continue;
// Don't generate monsters on top of teleport traps.
- int trap = trap_at_xy(pos);
- if (trap >= 0)
- {
- if (!_can_place_on_trap(mon_type, env.trap[trap].type))
- continue;
- }
+ const trap_def* ptrap = find_trap(pos);
+ if (ptrap && !_can_place_on_trap(mon_type, ptrap->type))
+ continue;
// Check whether there's a stair
// and whether it leads to another branch.
@@ -574,12 +571,9 @@ static bool _valid_monster_location(const mgen_data &mg,
// Don't generate monsters on top of teleport traps.
// (How did they get there?)
- int trap = trap_at_xy(mg_pos);
- if (trap >= 0)
- {
- if (!_can_place_on_trap(mg.cls, env.trap[trap].type))
- return (false);
- }
+ const trap_def* ptrap = find_trap(mg_pos);
+ if (ptrap && !_can_place_on_trap(mg.cls, ptrap->type))
+ return (false);
return (true);
}
@@ -2654,14 +2648,16 @@ bool monster_pathfind::traversable(coord_def p)
return (false);
}
- const int trap = trap_at_xy(p);
- if (trap >= 0)
+ const trap_def* ptrap = find_trap(p);
+ if (ptrap)
{
- trap_type tt = env.trap[trap].type;
- if (tt == TRAP_ZOT && grd(p) != DNGN_UNDISCOVERED_TRAP
+ const trap_type tt = ptrap->type;
+
+ // Don't allow allies to pass over known (to them) Zot traps.
+ if (tt == TRAP_ZOT
+ && ptrap->is_known(mons)
&& mons_friendly(mons))
{
- // Don't allow allies to pass over known Zot traps.
return (false);
}
@@ -2700,19 +2696,11 @@ int monster_pathfind::travel_cost(coord_def npos)
}
// Try to avoid (known) traps.
- const int trap = trap_at_xy(npos);
- if (trap >= 0)
- {
- // A monster can be considered to know a trap if
- // a) they're hostile
- // b) they're friendly and *you* know about the trap (and told them)
- // c) they're friendly and know the terrain
- bool knows_trap = (!mons_friendly(mons)
- || grd(npos) != DNGN_UNDISCOVERED_TRAP
- || mons_intel(mons->type) >= I_NORMAL
- && mons_is_native_in_branch(mons));
-
- trap_type tt = env.trap[trap].type;
+ const trap_def* ptrap = find_trap(npos);
+ if (ptrap)
+ {
+ const bool knows_trap = ptrap->is_known(mons);
+ const trap_type tt = ptrap->type;
if (tt == TRAP_ALARM || tt == TRAP_ZOT)
{
// Your allies take extra precautions to avoid known alarm traps.
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index dc16649615..ede0784ae7 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -2410,7 +2410,7 @@ static void _find_all_level_exits(std::vector<level_exit> &e)
e.push_back(level_exit(p, false));
// Teleportation and shaft traps.
- const trap_type tt = trap_type_at_xy(p);
+ const trap_type tt = get_trap_type(p);
if (tt == TRAP_TELEPORT || tt == TRAP_SHAFT)
e.push_back(level_exit(p, false));
}
@@ -6475,7 +6475,10 @@ static bool _is_trap_safe(const monsters *monster, const coord_def& where,
if (intel == I_PLANT)
return (true);
- const trap_struct &trap = env.trap[trap_at_xy(where)];
+ const trap_def *ptrap = find_trap(where);
+ if (!ptrap)
+ return (true);
+ const trap_def& trap = *ptrap;
if (trap.type == TRAP_SHAFT && monster->will_trigger_shaft())
{
@@ -6490,22 +6493,10 @@ static bool _is_trap_safe(const monsters *monster, const coord_def& where,
// Monsters are not afraid of non-mechanical traps. XXX: If we add
// any non-mechanical traps that can damage monsters, we must add
// checks for them here.
- const bool mechanical = trap_category(trap.type) == DNGN_TRAP_MECHANICAL;
-
- const bool player_knows_trap = (grd(where) != DNGN_UNDISCOVERED_TRAP);
-
- // Smarter trap handling for intelligent monsters
- // * monsters native to a branch can be assumed to know the trap
- // locations and thus be able to avoid them
- // * friendlies and good neutrals can be assumed to have been warned
- // by the player about all traps s/he knows about
- // * very intelligent monsters can be assumed to have a high T&D
- // skill (or have memorised part of the dungeon layout ;) )
- if (intel >= I_NORMAL && mechanical
- && (mons_is_native_in_branch(monster)
- || mons_wont_attack(monster)
- && player_knows_trap
- || intel >= I_HIGH && one_chance_in(3)))
+ const bool mechanical = (trap.category() == DNGN_TRAP_MECHANICAL);
+ const bool player_knows_trap = (trap.is_known(&you));
+
+ if (trap.is_known(monster))
{
if (just_check)
return (false); // Square is blocked.
@@ -6776,8 +6767,7 @@ static bool _mon_can_move_to_pos(const monsters *monster,
// Wandering through a trap is OK if we're pretty healthy,
// really stupid, or immune to the trap.
- const int which_trap = trap_at_xy(targ);
- if (which_trap >= 0 && !_is_trap_safe(monster, targ, just_check))
+ if (!_is_trap_safe(monster, targ, just_check))
return (false);
if (targ_cloud_num != EMPTY_CLOUD)
diff --git a/crawl-ref/source/mstuff2.cc b/crawl-ref/source/mstuff2.cc
index 5eeaaf3c1a..773e4433cf 100644
--- a/crawl-ref/source/mstuff2.cc
+++ b/crawl-ref/source/mstuff2.cc
@@ -42,380 +42,6 @@
static int _monster_abjuration(const monsters *caster, bool actual);
-// NB: only works because grid location already verified
-// to be some sort of trap prior to function call: {dlb}
-void mons_trap(monsters *monster)
-{
- if (!is_trap_square(grd(monster->pos())))
- return;
-
- // single calculation permissible {dlb}
- bool monsterNearby = mons_near(monster);
-
- const int which_trap = trap_at_xy(monster->pos());
- if (which_trap == -1)
- return;
-
- trap_struct& trap(env.trap[which_trap]);
-
- bool trapKnown = (grd(monster->pos()) != DNGN_UNDISCOVERED_TRAP);
- bool revealTrap = false; // more sophisticated trap uncovering {dlb}
- bool projectileFired = false; // <sigh> I had to do it, I swear {dlb}
- int damage_taken = -1; // must initialize at -1 for this f(x) {dlb}
-
- bolt beem;
-
-
- // flying monsters neatly avoid mechanical traps
- // and may actually exit this function early: {dlb}
- if (mons_flies(monster))
- {
- if (trap_category(trap.type) == DNGN_TRAP_MECHANICAL)
- {
- if (trapKnown)
- simple_monster_message(monster, " flies safely over a trap.");
-
- return; // early return {dlb}
- }
- }
-
- // Trap damage to monsters is not a function of level, because they
- // are fairly stupid and tend to have fewer hp than players -- this
- // choice prevents traps from easily killing large monsters fairly
- // deep within the dungeon.
- switch (trap.type)
- {
- case TRAP_DART:
- projectileFired = true;
- beem.name = " dart";
- beem.damage = dice_def( 1, 4 );
- beem.colour = OBJ_MISSILES;
- beem.type = MI_DART;
- break;
- case TRAP_NEEDLE:
- projectileFired = true;
- beem.name = " needle";
- beem.damage = dice_def( 1, 0 );
- beem.colour = OBJ_MISSILES;
- beem.type = MI_NEEDLE;
- break;
- case TRAP_ARROW:
- projectileFired = true;
- beem.name = "n arrow";
- beem.damage = dice_def( 1, 7 );
- beem.colour = OBJ_MISSILES;
- beem.type = MI_ARROW;
- break;
- case TRAP_SPEAR:
- projectileFired = true;
- beem.name = " spear";
- beem.damage = dice_def( 1, 10 );
- beem.colour = OBJ_WEAPONS;
- beem.type = WPN_SPEAR;
- break;
- case TRAP_BOLT:
- projectileFired = true;
- beem.name = " bolt";
- beem.damage = dice_def( 1, 13 );
- beem.colour = OBJ_MISSILES;
- beem.type = MI_BOLT;
- break;
- case TRAP_AXE:
- projectileFired = true;
- beem.name = "n axe";
- beem.damage = dice_def( 1, 15 );
- beem.colour = OBJ_WEAPONS;
- beem.type = WPN_HAND_AXE;
- break;
- // teleport traps are *never* revealed through
- // the triggering action of a monster, as any
- // number of factors could have been in play: {dlb}
- case TRAP_TELEPORT:
- monster_teleport(monster, true);
- break;
- // Alarm traps aren't set off by hostile monsters, because that would
- // be way too nasty for the player.
- case TRAP_ALARM:
- if (!mons_friendly(monster) || silenced(monster->pos()))
- {
- if (trapKnown && you.can_see(monster) && !silenced(you.pos()))
- {
- mpr("The alarm trap makes no noise.");
- }
- return;
- }
-
- noisy(12, monster->pos());
-
- if (!silenced(you.pos()))
- {
- if (monsterNearby)
- {
- mpr("You hear a blaring wail!", MSGCH_SOUND);
- if (you.can_see(monster))
- revealTrap = true;
- }
- else
- mpr("You hear a distant blaring wail!", MSGCH_SOUND);
- }
-
- break;
- // blade traps sometimes fail to trigger altogether,
- // resulting in an "early return" from this f(x) for
- // some - otherwise, blade *always* revealed: {dlb}
- case TRAP_BLADE:
- if (one_chance_in(5)
- || trapKnown && intelligent_ally(monster) && coinflip())
- {
- if (trapKnown)
- {
- simple_monster_message(monster,
- " fails to trigger a blade trap.");
- }
- return; // early return {dlb}
- }
-
- if (random2(monster->ev) > 8
- || trapKnown && intelligent_ally(monster)
- && random2(monster->ev) > 8)
- {
- if (monsterNearby && !simple_monster_message(monster,
- " avoids a huge, swinging blade."))
- {
- mpr("A huge blade swings out!");
- }
-
- damage_taken = -1; // just to be certain {dlb}
- }
- else
- {
- if (monsterNearby)
- {
- std::string msg = "A huge blade swings out";
- if (player_monster_visible( monster ))
- {
- msg += " and slices into ";
- msg += monster->name(DESC_NOCAP_THE);
- }
- msg += "!";
- mpr(msg.c_str());
- }
-
- damage_taken = 10 + random2avg(29, 2);
- damage_taken -= random2(1 + monster->ac);
-
- if (damage_taken < 0)
- damage_taken = 0;
-
- if (!mons_is_summoned(monster))
- {
- bleed_onto_floor(monster->pos(), monster->type,
- damage_taken, true);
- }
- }
-
- revealTrap = true;
- break;
-
- case TRAP_NET:
- {
- if (one_chance_in(3)
- || trapKnown && intelligent_ally(monster) && coinflip())
- {
- if (trapKnown)
- {
- simple_monster_message(monster,
- " fails to trigger a net trap.");
- }
- return;
- }
-
- if (random2(monster->ev) > 8
- || trapKnown && intelligent_ally(monster)
- && random2(monster->ev) > 8)
- {
- if (monsterNearby && !simple_monster_message(monster,
- " nimbly jumps out of the way of a falling net."))
- {
- mpr("A large net falls down!");
- }
- }
- else
- {
- if (monsterNearby)
- {
- std::string msg = "A large net falls down";
- if (player_monster_visible( monster ))
- {
- msg += " onto ";
- msg += monster->name(DESC_NOCAP_THE);
- }
- msg += "!";
- mpr(msg.c_str());
- monster_caught_in_net(monster, beem);
- }
- }
- trap_item( OBJ_MISSILES, MI_THROWING_NET, trap.pos );
-
- if (mons_is_caught(monster))
- mark_net_trapping(monster->pos());
-
- grd(trap.pos) = DNGN_FLOOR;
- trap.type = TRAP_UNASSIGNED;
- break;
- }
- // zot traps are out to get *the player*! Hostile monsters
- // benefit and friendly monsters suffer - such is life - on
- // rare occasion, the trap affects nearby players, triggering
- // an "early return" - zot traps are *never* revealed - instead,
- // enchantment messages serve as clues to the trap's presence: {dlb}
- case TRAP_ZOT:
- if (mons_friendly(monster) || mons_good_neutral(monster))
- {
- MiscastEffect( monster, ZOT_TRAP_MISCAST, SPTYP_RANDOM,
- 3, "the power of Zot" );
- return; // early return
- }
- else if (monsterNearby)
- {
- if (one_chance_in(5))
- {
- mpr("The power of Zot is invoked against you!");
- MiscastEffect( &you, ZOT_TRAP_MISCAST, SPTYP_RANDOM,
- 3, "the power of Zot" );
-
- return; // early return {dlb}
- }
- }
-
- // output triggering message to player, where appropriate: {dlb}
- if (!silenced(monster->pos()) && !silenced(you.pos()))
- {
- if (monsterNearby)
- mpr("You hear a loud \"Zot\"!", MSGCH_SOUND);
- else
- mpr("You hear a distant \"Zot\"!", MSGCH_SOUND);
- }
-
- // XXX: It seem that back when a beam's colour determined its
- // flavour that Zot traps would heal, haste or make invisible
- // hostile monsters. The code has been fixed to work but
- // commented out.
-#if 0
- if (!mons_friendly(monster) && !mons_good_neutral(monster))
- {
- int temp_rand = random2(16);
-
- beem.thrower = KILL_MON; // probably unnecessary
- beem.aux_source.clear();
- beem.flavour = ((temp_rand < 3) ? BEAM_HASTE : // 3 in 16 {dlb}
- (temp_rand < 7) ? BEAM_INVISIBILITY //4 in 16 {dlb}
- : BEAM_HEALING); // 9 in 16 {dlb}
- mons_ench_f2(monster, beem);
- }
-#endif
-
- 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(trap.pos) = DNGN_FLOOR;
- trap.type = TRAP_UNASSIGNED;
- return;
- }
-
- if (!monster->will_trigger_shaft()
- || trapKnown && intelligent_ally(monster))
- {
- if (trapKnown && !monster->airborne())
- simple_monster_message(monster,
- " doesn't fall through the shaft.");
- return;
- }
-
- if (monster->do_shaft())
- revealTrap = true;
- break;
-
- default:
- break;
- }
-
-
- // go back and handle projectile traps: {dlb}
- bool apply_poison = false;
-
- if (projectileFired)
- {
- // projectile traps *always* revealed after "firing": {dlb}
- revealTrap = true;
-
- // determine whether projectile hits, calculate damage: {dlb}
- if (((20 + (you.your_level * 2)) * random2(200)) / 100
- >= monster->ev)
- {
- damage_taken = roll_dice( beem.damage );
- damage_taken -= random2(1 + monster->ac);
-
- if (damage_taken < 0)
- damage_taken = 0;
-
- if (beem.colour == OBJ_MISSILES
- && beem.type == MI_NEEDLE
- && x_chance_in_y(50 - (3 * monster->ac)/ 2, 100))
- {
- apply_poison = true;
- }
- }
- else
- {
- damage_taken = -1; // negative damage marks a miss
- }
-
- if (monsterNearby)
- {
- mprf("A%s %s %s%s!",
- beem.name.c_str(),
- (damage_taken >= 0) ? "hits" : "misses",
- monster->name(DESC_NOCAP_THE).c_str(),
- (damage_taken == 0) ? ", but does no damage" : "");
- }
-
- if (apply_poison)
- poison_monster( monster, KC_OTHER );
-
- // Generate "fallen" projectile, where appropriate. {dlb}
- if (x_chance_in_y(7, 10))
- {
- beem.target = monster->pos();
- itrap(beem, which_trap);
- }
- }
-
-
- // reveal undiscovered traps, where appropriate: {dlb}
- if (monsterNearby && !trapKnown && revealTrap)
- grd(trap.pos) = trap_category(trap.type);
-
- // apply damage and handle death, where appropriate: {dlb}
- if (damage_taken > 0)
- {
- hurt_monster(monster, damage_taken);
-
- if (monster->hit_points < 1)
- {
- monster_die(monster, KILL_MISC, NON_MONSTER);
- monster->speed_increment = 1;
- }
- }
-}
-
static bool _mons_abjured(monsters *monster, bool nearby)
{
if (nearby && _monster_abjuration(monster, false) > 0
diff --git a/crawl-ref/source/ouch.cc b/crawl-ref/source/ouch.cc
index d4e85d8e44..e9ef6a4da9 100644
--- a/crawl-ref/source/ouch.cc
+++ b/crawl-ref/source/ouch.cc
@@ -858,7 +858,7 @@ void ouch(int dam, int death_source, kill_method_type death_type,
_xom_checks_damage(death_type, dam, death_source);
// for note taking
- std::string damage_desc = "";
+ std::string damage_desc;
if (!see_source)
{
snprintf(info, INFO_SIZE, "something (%d)", dam);
diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc
index 8cbdb12e3b..b62308d213 100644
--- a/crawl-ref/source/player.cc
+++ b/crawl-ref/source/player.cc
@@ -146,11 +146,10 @@ bool move_player_to_grid( const coord_def& p, bool stepped, bool allow_shift,
+ player_mutation_level(MUT_ACUTE_VISION)
- 2 * player_mutation_level(MUT_BLURRY_VISION);
- if (random2( skill ) > 6)
+ if (random2(skill) > 6)
{
- const int id = trap_at_xy( p );
- if (id != -1)
- grd(p) = trap_category( env.trap[id].type );
+ if (trap_def* ptrap = find_trap(p))
+ ptrap->reveal();
viewwindow(true, false);
@@ -175,7 +174,7 @@ bool move_player_to_grid( const coord_def& p, bool stepped, bool allow_shift,
#endif
|| new_grid == DNGN_TRAP_NATURAL)
{
- const trap_type type = trap_type_at_xy(p);
+ const trap_type type = get_trap_type(p);
if (type == TRAP_ZOT)
{
if (!yes_or_no("Do you really want to step into the Zot trap"))
@@ -301,37 +300,8 @@ bool move_player_to_grid( const coord_def& p, bool stepped, bool allow_shift,
expose_player_to_element( BEAM_LAVA );
// Traps go off.
- if (new_grid >= DNGN_TRAP_MECHANICAL && new_grid <= DNGN_UNDISCOVERED_TRAP)
- {
- int id = trap_at_xy( you.pos() );
-
- if (id != -1)
- {
- bool trap_known = true;
-
- if (new_grid == DNGN_UNDISCOVERED_TRAP)
- {
- trap_known = false;
-
- const dungeon_feature_type type =
- trap_category( env.trap[id].type );
- grd(you.pos()) = type;
- set_envmap_obj(you.pos(), type);
- }
-
- // It's not easy to blink onto a trap without setting it off.
- if (!stepped)
- trap_known = false;
-
- // mechanical traps and shafts cannot be set off if the
- // player is flying or levitating
- if (!player_is_airborne()
- || trap_category( env.trap[id].type ) == DNGN_TRAP_MAGICAL)
- {
- handle_traps(env.trap[id].type, id, trap_known);
- }
- }
- }
+ if (trap_def* ptrap = find_trap(you.pos()))
+ ptrap->trigger(you, !stepped); // blinking makes it hard to evade
return (true);
}
@@ -5410,6 +5380,14 @@ bool actor::can_pass_through(const coord_def &c) const
return can_pass_through_feat(grd(c));
}
+bool actor::handle_trap()
+{
+ trap_def* trap = find_trap(pos());
+ if (trap)
+ trap->trigger(*this);
+ return (trap != NULL);
+}
+
//////////////////////////////////////////////////////////////////////////////
// player
@@ -6275,7 +6253,7 @@ int player::armour_class() const
int player::melee_evasion(const actor *act) const
{
return (player_evasion()
- - (act->visible()? 0 : 10)
+ - ((!act || act->visible()) ? 0 : 10)
- (you_are_delayed()? 5 : 0));
}
@@ -6985,7 +6963,7 @@ bool player::do_shaft()
// Handle instances of do_shaft() being invoked magically when
// the player isn't standing over a shaft.
- if (trap_type_at_xy(this->pos()) != TRAP_SHAFT)
+ if (get_trap_type(this->pos()) != TRAP_SHAFT)
{
switch (grd(you.pos()))
{
diff --git a/crawl-ref/source/spells2.cc b/crawl-ref/source/spells2.cc
index a31c75483e..f181ab51b5 100644
--- a/crawl-ref/source/spells2.cc
+++ b/crawl-ref/source/spells2.cc
@@ -57,16 +57,17 @@ int detect_traps( int pow )
for (int i = 0; i < MAX_TRAPS; i++)
{
- const coord_def p = env.trap[i].pos;
+ trap_def& trap = env.trap[i];
- if (grid_distance( you.pos(), p) < range
- && grd(p) == DNGN_UNDISCOVERED_TRAP)
+ if (!trap.active())
+ continue;
+
+ if (grid_distance(you.pos(), trap.pos) < range && !trap.is_known())
{
traps_found++;
-
- grd(p) = trap_category( env.trap[i].type );
- set_envmap_obj(p, grd(p));
- set_terrain_mapped(p);
+ trap.reveal();
+ set_envmap_obj(trap.pos, grd(trap.pos));
+ set_terrain_mapped(trap.pos);
}
}
diff --git a/crawl-ref/source/spells3.cc b/crawl-ref/source/spells3.cc
index dc2f817dd2..85add52f2d 100644
--- a/crawl-ref/source/spells3.cc
+++ b/crawl-ref/source/spells3.cc
@@ -1432,17 +1432,9 @@ bool entomb(int powc)
if (env.cgrid(*ai) != EMPTY_CLOUD)
delete_cloud( env.cgrid(*ai) );
- // mechanical traps are destroyed {dlb}:
- int which_trap = trap_at_xy(*ai);
- if ( which_trap != -1 )
- {
- trap_struct& trap(env.trap[which_trap]);
- if (trap_category(trap.type) == DNGN_TRAP_MECHANICAL)
- {
- trap.type = TRAP_UNASSIGNED;
- trap.pos.set(1,1);
- }
- }
+ // All traps are destroyed
+ if (trap_def* ptrap = find_trap(*ai))
+ ptrap->destroy();
// Finally, place the wall {dlb}:
grd(*ai) = DNGN_ROCK_WALL;
@@ -1627,14 +1619,13 @@ bool cast_sanctuary(const int power)
if (env.map(pos).property == FPROP_BLOODY && see_grid(pos))
blood_count++;
- if (trap_type_at_xy(pos) != NUM_TRAPS
- && grd(pos) == DNGN_UNDISCOVERED_TRAP)
+ if (trap_def* ptrap = find_trap(pos))
{
- const dungeon_feature_type type =
- trap_category( trap_type_at_xy(pos) );
- grd(pos) = type;
- set_envmap_obj(pos, type);
- trap_count++;
+ if (!ptrap->is_known())
+ {
+ ptrap->reveal();
+ ++trap_count;
+ }
}
// forming patterns
diff --git a/crawl-ref/source/spells4.cc b/crawl-ref/source/spells4.cc
index 5e3c4ad0f6..21052d9ba4 100644
--- a/crawl-ref/source/spells4.cc
+++ b/crawl-ref/source/spells4.cc
@@ -1701,7 +1701,6 @@ bool cast_fragmentation(int pow, const dist& spd)
{
bolt beam;
int debris = 0;
- int trap;
bool explode = false;
bool hole = true;
const char *what = NULL;
@@ -1951,9 +1950,9 @@ bool cast_fragmentation(int pow, const dist& spd)
case DNGN_UNDISCOVERED_TRAP:
case DNGN_TRAP_MECHANICAL:
- trap = trap_at_xy(spd.target);
- if (trap != -1
- && trap_category(env.trap[trap].type) != DNGN_TRAP_MECHANICAL)
+ {
+ trap_def* ptrap = find_trap(spd.target);
+ if (ptrap && ptrap->category() != DNGN_TRAP_MECHANICAL)
{
// Non-mechanical traps don't explode with this spell. -- bwr
break;
@@ -1969,9 +1968,9 @@ bool cast_fragmentation(int pow, const dist& spd)
beam.damage.num = 2;
// Exploded traps are nonfunctional, ammo is also ruined -- bwr
- grd(spd.target) = DNGN_FLOOR;
- env.trap[trap].type = TRAP_UNASSIGNED;
+ ptrap->destroy();
break;
+ }
//
// Stone doors and arches
diff --git a/crawl-ref/source/stash.cc b/crawl-ref/source/stash.cc
index 17104cdddb..1c9dcf83f3 100644
--- a/crawl-ref/source/stash.cc
+++ b/crawl-ref/source/stash.cc
@@ -271,7 +271,7 @@ void Stash::update()
feat = DNGN_FLOOR;
if (grid_is_trap(feat))
- trap = trap_type_at_xy(p);
+ trap = get_trap_type(p);
int objl = igrd[x][y];
// If this is your position, you know what's on this square
diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc
index 9df9fccc26..b531fb8b22 100644
--- a/crawl-ref/source/tags.cc
+++ b/crawl-ref/source/tags.cc
@@ -1731,8 +1731,8 @@ static void tag_construct_level_items(writer &th)
for (int i = 0; i < MAX_TRAPS; ++i)
{
marshallByte(th, env.trap[i].type);
- marshallByte(th, env.trap[i].pos.x);
- marshallByte(th, env.trap[i].pos.y);
+ marshallCoord(th, env.trap[i].pos);
+ marshallShort(th, env.trap[i].ammo_qty);
}
// how many items?
@@ -2018,9 +2018,8 @@ static void tag_read_level_items(reader &th, char minorVersion)
env.trap[i].type =
static_cast<trap_type>(
static_cast<unsigned char>(unmarshallByte(th)) );
-
- env.trap[i].pos.x = unmarshallByte(th);
- env.trap[i].pos.y = unmarshallByte(th);
+ unmarshallCoord(th, env.trap[i].pos);
+ env.trap[i].ammo_qty = unmarshallShort(th);
}
// how many items?
diff --git a/crawl-ref/source/terrain.cc b/crawl-ref/source/terrain.cc
index 67a2fa84b6..ae538be8fb 100644
--- a/crawl-ref/source/terrain.cc
+++ b/crawl-ref/source/terrain.cc
@@ -181,10 +181,11 @@ bool grid_is_permarock(dungeon_feature_type grid)
return (grid == DNGN_PERMAROCK_WALL || grid == DNGN_CLEAR_PERMAROCK_WALL);
}
-bool grid_is_trap(dungeon_feature_type grid)
+bool grid_is_trap(dungeon_feature_type grid, bool undiscovered_too)
{
return (grid == DNGN_TRAP_MECHANICAL || grid == DNGN_TRAP_MAGICAL
- || grid == DNGN_TRAP_NATURAL);
+ || grid == DNGN_TRAP_NATURAL
+ || (undiscovered_too && grid == DNGN_UNDISCOVERED_TRAP));
}
bool grid_is_water(dungeon_feature_type grid)
diff --git a/crawl-ref/source/terrain.h b/crawl-ref/source/terrain.h
index 44c3121c8f..2c32be9af7 100644
--- a/crawl-ref/source/terrain.h
+++ b/crawl-ref/source/terrain.h
@@ -30,7 +30,7 @@ bool grid_is_rock(dungeon_feature_type grid);
bool grid_is_permarock(dungeon_feature_type grid);
bool grid_is_stone_stair(dungeon_feature_type grid);
bool grid_is_escape_hatch(dungeon_feature_type grid);
-bool grid_is_trap(dungeon_feature_type grid);
+bool grid_is_trap(dungeon_feature_type grid, bool undiscovered_too = false);
command_type grid_stair_direction(dungeon_feature_type grid);
bool grid_sealable_portal(dungeon_feature_type grid);
bool grid_is_portal(dungeon_feature_type grid);
diff --git a/crawl-ref/source/traps.cc b/crawl-ref/source/traps.cc
index 16aaa0ab87..a49a914852 100644
--- a/crawl-ref/source/traps.cc
+++ b/crawl-ref/source/traps.cc
@@ -16,11 +16,14 @@
#include "beam.h"
#include "branch.h"
#include "delay.h"
+#include "describe.h"
#include "directn.h"
#include "it_use2.h"
-#include "items.h"
+#include "itemname.h"
#include "itemprop.h"
+#include "items.h"
#include "makeitem.h"
+#include "message.h"
#include "misc.h"
#include "mon-util.h"
#include "monstuff.h"
@@ -38,7 +41,133 @@
#include "tutorial.h"
#include "view.h"
-static void dart_trap(bool trap_known, int trapped, bolt &pbolt, bool poison);
+bool trap_def::active() const
+{
+ return (this->type != TRAP_UNASSIGNED);
+}
+
+bool trap_def::type_has_ammo() const
+{
+ bool rc = false;
+ switch (this->type)
+ {
+ case TRAP_DART: case TRAP_ARROW: case TRAP_BOLT:
+ case TRAP_NEEDLE: case TRAP_SPEAR: case TRAP_AXE:
+ rc = true;
+ default:
+ break;
+ }
+ return rc;
+}
+
+void trap_def::message_trap_entry()
+{
+ if (this->type == TRAP_TELEPORT)
+ mpr("You enter a teleport trap!");
+}
+
+void trap_def::disarm()
+{
+ if (this->type_has_ammo() && this->ammo_qty > 0)
+ {
+ item_def trap_item = this->generate_trap_item();
+ trap_item.quantity = this->ammo_qty;
+ copy_item_to_grid(trap_item, this->pos);
+ }
+ this->destroy();
+}
+
+void trap_def::destroy()
+{
+ grd(this->pos) = DNGN_FLOOR;
+ this->ammo_qty = 0;
+ this->pos = coord_def(-1,-1);
+ this->type = TRAP_UNASSIGNED;
+}
+
+void trap_def::hide()
+{
+ grd(this->pos) = DNGN_UNDISCOVERED_TRAP;
+}
+
+void trap_def::prepare_ammo()
+{
+ switch (this->type)
+ {
+ case TRAP_DART:
+ case TRAP_ARROW:
+ case TRAP_BOLT:
+ case TRAP_NEEDLE:
+ this->ammo_qty = 3 + random2avg(9, 3);
+ break;
+ case TRAP_SPEAR:
+ case TRAP_AXE:
+ this->ammo_qty = 2 + random2avg(6, 3);
+ break;
+ default:
+ this->ammo_qty = 0;
+ break;
+ }
+}
+
+void trap_def::reveal()
+{
+ const dungeon_feature_type cat = this->category();
+ grd(this->pos) = cat;
+ set_envmap_obj(this->pos, cat);
+}
+
+std::string trap_def::name(description_level_type desc) const
+{
+ if (this->type >= NUM_TRAPS)
+ return ("buggy");
+
+ const char* basename = trap_name(this->type);
+ if (desc == DESC_CAP_A || desc == DESC_NOCAP_A)
+ {
+ std::string prefix = (desc == DESC_CAP_A ? "A" : "a");
+ if (is_vowel(basename[0]))
+ prefix += 'n';
+ prefix += ' ';
+ return (prefix + basename);
+ }
+ else if (desc == DESC_CAP_THE)
+ return (std::string("The ") + basename);
+ else if (desc == DESC_NOCAP_THE)
+ return (std::string("the ") + basename);
+ else // everything else
+ return (basename);
+}
+
+bool trap_def::is_known(const actor* act) const
+{
+ bool rc = false;
+ const bool player_knows = (grd(pos) != DNGN_UNDISCOVERED_TRAP);
+
+ if (act == NULL || act->atype() == ACT_PLAYER)
+ rc = player_knows;
+ else if (act->atype() == ACT_MONSTER)
+ {
+ const monsters* monster = static_cast<const monsters*>(act);
+ const bool mechanical = (this->category() == DNGN_TRAP_MECHANICAL);
+ const int intel = mons_intel(monster->type);
+
+ // Smarter trap handling for intelligent monsters
+ // * monsters native to a branch can be assumed to know the trap
+ // locations and thus be able to avoid them
+ // * friendlies and good neutrals can be assumed to have been warned
+ // by the player about all traps s/he knows about
+ // * very intelligent monsters can be assumed to have a high T&D
+ // skill (or have memorised part of the dungeon layout ;) )
+
+ rc = (intel >= I_NORMAL && mechanical
+ && (mons_is_native_in_branch(monster)
+ || (mons_wont_attack(monster) && player_knows)
+ || (intel >= I_HIGH && one_chance_in(3))));
+ }
+ return rc;
+}
+
// Returns the number of a net on a given square.
// If trapped only stationary ones are counted
@@ -213,318 +342,370 @@ void check_net_will_hold_monster(monsters *mons)
mons->add_ench(ENCH_HELD);
}
-static void dart_trap(bool trap_known, int trapped, bolt &pbolt, bool poison)
+void trap_def::trigger(actor& triggerer, bool flat_footed)
{
- int damage_taken = 0;
- int trap_hit, your_dodge;
+ const bool you_know = this->is_known();
+ const bool trig_knows = !flat_footed && this->is_known(&triggerer);
- if (one_chance_in(5) || (trap_known && !one_chance_in(4)))
- {
- mprf( "You avoid triggering a%s trap.", pbolt.name.c_str() );
- return;
- }
+ const bool you_trigger = (triggerer.atype() == ACT_PLAYER);
+ const bool in_sight = see_grid(this->pos);
- if (you.equip[EQ_SHIELD] != -1 && one_chance_in(3))
- exercise( SK_SHIELDS, 1 );
+ monsters* m = NULL;
+ if (triggerer.atype() == ACT_MONSTER)
+ m = static_cast<monsters*>(&triggerer);
- std::string msg = "A" + pbolt.name + " shoots out and ";
+ // Anything stepping onto a trap almost always reveals it.
+ // (We can rehide it later for the exceptions.)
+ if (in_sight)
+ this->reveal();
- if (random2( 20 + 5 * you.shield_blocks * you.shield_blocks )
- < player_shield_class())
+ // Only magical traps affect flying critters.
+ if (triggerer.airborne() && this->category() != DNGN_TRAP_MAGICAL)
{
- you.shield_blocks++;
- msg += "hits your shield.";
- mpr(msg.c_str());
+ if (you_know && m)
+ simple_monster_message(m, " flies safely over a trap.");
+ return;
}
- else
+
+ // OK, something is going to happen.
+ if (you_trigger)
+ this->message_trap_entry();
+
+ if (this->type_has_ammo())
+ this->shoot_ammo(triggerer, trig_knows);
+ else switch (this->type)
{
- // note that this uses full ( not random2limit(foo,40) )
- // player_evasion.
- trap_hit = (20 + (you.your_level * 2)) * random2(200) / 100;
+ case TRAP_TELEPORT:
+ // Never revealed.
+ if (!you_know)
+ this->hide();
+ triggerer.teleport(true);
+ break;
- your_dodge = player_evasion() + random2(you.dex) / 3
- - 2 + (you.duration[DUR_REPEL_MISSILES] * 10);
+ case TRAP_ALARM:
+ if (silenced(this->pos))
+ {
+ if (you_know && in_sight)
+ mpr("The alarm trap is silent.");
- if (trap_hit >= your_dodge && you.duration[DUR_DEFLECT_MISSILES] == 0)
+ // If it's silent, you don't know about it.
+ if (!you_know)
+ this->hide();
+ }
+ else if (!(m && mons_friendly(m)))
{
- msg += "hits you!";
- mpr(msg.c_str());
+ // Alarm traps aren't set off by hostile monsters, because
+ // that would be way too nasty for the player.
+ const char* message_here = "An alarm trap emits a blaring wail!";
+ const char* message_near = "You hear a blaring wail!";
+ const char* message_far = "You hear a distant blaring wail!";
+ noisy(12, this->pos, (you_trigger ? message_here :
+ (in_sight ? message_near : message_far)));
+ }
+ break;
- if (poison && x_chance_in_y(50 - (3 * player_AC()) / 2, 100)
- && !player_res_poison())
+ case TRAP_BLADE:
+ if (you_trigger)
+ {
+ if (trig_knows && one_chance_in(3))
+ mpr("You avoid triggering a blade trap.");
+ else if (random2limit(player_evasion(), 40)
+ + (random2(you.dex) / 3) + (trig_knows ? 3 : 0) > 8)
{
- poison_player( 1 + random2(3) );
+ mpr("A huge blade swings just past you!");
}
-
- damage_taken = roll_dice( pbolt.damage );
- damage_taken -= random2( player_AC() + 1 );
-
- if (damage_taken > 0)
+ else
{
- ouch(damage_taken, NON_MONSTER, KILLED_BY_TRAP,
- pbolt.name.c_str());
+ mpr("A huge blade swings out and slices into you!");
+ const int damage = (you.your_level * 2) + random2avg(29, 2)
+ - random2(1 + player_AC());
+ ouch(damage, NON_MONSTER, KILLED_BY_TRAP, " blade");
+ bleed_onto_floor(you.pos(), -1, damage, true);
}
}
- else
+ else if (m)
{
- msg += "misses you.";
- mpr(msg.c_str());
+ if (one_chance_in(5) || (trig_knows && coinflip()))
+ {
+ // Trap doesn't trigger. Don't reveal it.
+ if (you_know)
+ {
+ simple_monster_message(m,
+ " fails to trigger a blade trap.");
+ }
+ else
+ this->hide();
+ }
+ else if (random2(m->ev) > 8 || (trig_knows && random2(m->ev) > 8))
+ {
+ if (in_sight &&
+ !simple_monster_message(m,
+ " avoids a huge, swinging blade."))
+ {
+ mpr("A huge blade swings out!");
+ }
+ }
+ else
+ {
+ if (in_sight)
+ {
+ std::string msg = "A huge blade swings out";
+ if (player_monster_visible( m ))
+ {
+ msg += " and slices into ";
+ msg += m->name(DESC_NOCAP_THE);
+ }
+ msg += "!";
+ mpr(msg.c_str());
+ }
+
+ int damage_taken = 10 + random2avg(29, 2) - random2(1 + m->ac);
+
+ if (damage_taken < 0)
+ damage_taken = 0;
+
+ if (!mons_is_summoned(m))
+ bleed_onto_floor(m->pos(), m->type, damage_taken, true);
+
+ hurt_monster(m, damage_taken);
+ if (m->hit_points < 1)
+ monster_die(m, KILL_MISC, NON_MONSTER);
+ }
}
-
- if (player_light_armour(true) && coinflip())
- exercise( SK_DODGING, 1 );
- }
-
- pbolt.target = you.pos();
-
- if (coinflip())
- itrap( pbolt, trapped );
-} // end dart_trap()
-
-//
-// itrap takes location from target_x, target_y of bolt strcture.
-//
-
-void itrap( bolt &pbolt, int trapped )
-{
- object_class_type base_type = OBJ_MISSILES;
- int sub_type = MI_DART;
-
- switch (env.trap[trapped].type)
- {
- case TRAP_DART:
- base_type = OBJ_MISSILES;
- sub_type = MI_DART;
- break;
- case TRAP_ARROW:
- base_type = OBJ_MISSILES;
- sub_type = MI_ARROW;
- break;
- case TRAP_BOLT:
- base_type = OBJ_MISSILES;
- sub_type = MI_BOLT;
- break;
- case TRAP_SPEAR:
- base_type = OBJ_WEAPONS;
- sub_type = WPN_SPEAR;
- break;
- case TRAP_AXE:
- base_type = OBJ_WEAPONS;
- sub_type = WPN_HAND_AXE;
- break;
- case TRAP_NEEDLE:
- base_type = OBJ_MISSILES;
- sub_type = MI_NEEDLE;
break;
+
case TRAP_NET:
- base_type = OBJ_MISSILES;
- sub_type = MI_THROWING_NET;
- break;
- default:
- return;
- }
-
- trap_item( base_type, sub_type, pbolt.target );
-
- return;
-}
-
-void handle_traps(trap_type trt, int i, bool trap_known)
-{
- struct bolt beam;
-
- bool branchtype = false;
-
- // Mark traps as racial, if applicable. See the list of racial
- // restrictions in _determine_weapon_race() and
- // _determine_missile_race() in makeitem.cc.
- if (trap_category(trt) == DNGN_TRAP_MECHANICAL && trt != TRAP_BLADE
- && trt != TRAP_NET)
- {
- if (you.where_are_you == BRANCH_ORCISH_MINES)
+ if (you_trigger)
{
- beam.name = "n orcish";
- branchtype = true;
+ if (trig_knows && one_chance_in(3))
+ mpr("A net swings high above you.");
+ else
+ {
+ if (random2limit(player_evasion(), 40)
+ + (random2(you.dex) / 3) + (trig_knows ? 3 : 0) > 12)
+ {
+ mpr("A net drops to the ground!");
+ }
+ else
+ {
+ mpr("A large net falls onto you!");
+ player_caught_in_net();
+ }
+
+ item_def item = this->generate_trap_item();
+ copy_item_to_grid(item, triggerer.pos());
+
+ if (you.attribute[ATTR_HELD])
+ mark_net_trapping(you.pos());
+
+ this->destroy();
+ }
}
- else if (you.where_are_you == BRANCH_ELVEN_HALLS
- && trt != TRAP_AXE && trt != TRAP_BOLT)
+ else if (m)
{
- beam.name = "n elven";
- branchtype = true;
- }
- else
- beam.name = "";
- }
-
- switch (trt)
- {
- case TRAP_DART:
- beam.name += " dart";
- beam.damage = dice_def( 1, 4 + (you.your_level / 2) );
- dart_trap(trap_known, i, beam, false);
- break;
-
- case TRAP_NEEDLE:
- beam.name += " needle";
- beam.damage = dice_def( 1, 0 );
- dart_trap(trap_known, i, beam, true);
- break;
-
- case TRAP_ARROW:
- beam.name += (branchtype? "" : "n");
- beam.name += " arrow";
- beam.damage = dice_def( 1, 7 + you.your_level );
- dart_trap(trap_known, i, beam, false);
- break;
-
- case TRAP_BOLT:
- beam.name += " bolt";
- beam.damage = dice_def( 1, 13 + you.your_level );
- dart_trap(trap_known, i, beam, false);
- break;
-
- case TRAP_SPEAR:
- beam.name += " spear";
- beam.damage = dice_def( 1, 10 + you.your_level );
- dart_trap(trap_known, i, beam, false);
- break;
-
- case TRAP_AXE:
- beam.name += (branchtype? "" : "n");
- beam.name += " axe";
- beam.damage = dice_def( 1, 15 + you.your_level );
- dart_trap(trap_known, i, beam, false);
- break;
-
- case TRAP_TELEPORT:
- mpr("You enter a teleport trap!");
+ bool triggered = true;
+ if (one_chance_in(3) || (trig_knows && coinflip()))
+ {
+ triggered = false;
+ if (you_know)
+ simple_monster_message(m, " fails to trigger a net trap.");
+ }
+ if (random2(m->ev) > 8
+ || (trig_knows && random2(m->ev) > 8))
+ {
+ if (in_sight)
+ {
+ if (!simple_monster_message(m,
+ " nimbly jumps out of the way "
+ "of a falling net."))
+ {
+ mpr("A large net falls down!");
+ }
+ }
+ else
+ {
+ // FIXME: net traps don't trigger unless you can see
+ // them? Preserving old behaviour here.
+ if (in_sight)
+ {
+ msg::stream << "A large net falls down";
+ if (player_monster_visible(m))
+ msg::stream << " onto " << m->name(DESC_NOCAP_THE);
+ msg::stream << "!" << std::endl;
+ }
+ // FIXME: Fake a beam for monster_caught_in_net.
+ bolt beam;
+ beam.flavour = BEAM_MISSILE;
+ beam.thrower = KILL_MISC;
+ beam.beam_source = NON_MONSTER;
+ monster_caught_in_net(m, beam);
+ }
+ }
- if (scan_randarts(RAP_PREVENT_TELEPORTATION))
- mpr("You feel a weird sense of stasis.");
- else
- you_teleport_now( true );
- break;
+ if (triggered)
+ {
+ item_def item = this->generate_trap_item();
+ copy_item_to_grid(item, triggerer.pos());
- case TRAP_ALARM:
- if (silenced(you.pos()))
- {
- if (trap_known)
- mpr("The alarm is silenced.");
- else
- grd(you.pos()) = DNGN_UNDISCOVERED_TRAP;
- return;
+ if (mons_is_caught(m))
+ mark_net_trapping(m->pos());
+
+ this->destroy();
+ }
}
-
- noisy(12, you.pos(), "An alarm trap emits a blaring wail!");
-
break;
- case TRAP_BLADE:
- if (trap_known && one_chance_in(3))
- mpr("You avoid triggering a blade trap.");
- else if (random2limit(player_evasion(), 40)
- + (random2(you.dex) / 3) + (trap_known ? 3 : 0) > 8)
+ case TRAP_ZOT:
+ if (you_trigger)
{
- mpr("A huge blade swings just past you!");
+ mpr((trig_knows) ? "You enter the Zot trap."
+ : "Oh no! You have blundered into a Zot trap!");
+ MiscastEffect( &you, ZOT_TRAP_MISCAST, SPTYP_RANDOM,
+ 3, "a Zot trap" );
}
- else
+ else if (m)
{
- mpr("A huge blade swings out and slices into you!");
- int damage = (you.your_level * 2) + random2avg(29, 2)
- - random2(1 + player_AC());
- ouch(damage, NON_MONSTER, KILLED_BY_TRAP, " blade");
- bleed_onto_floor(you.pos(), -1, damage, true);
- }
- break;
+ // Zot traps are out to get *the player*! Hostile monsters
+ // benefit and friendly monsters suffer. Such is life.
- case TRAP_NET:
- if (trap_known && one_chance_in(3))
- mpr("A net swings high above you.");
- else
- {
- if (random2limit(player_evasion(), 40)
- + (random2(you.dex) / 3) + (trap_known ? 3 : 0) > 12)
+ // Preserving original functionality: don't reveal location.
+ if (!you_know)
+ this->hide();
+
+ if (mons_wont_attack(m))
{
- mpr("A net drops to the ground!");
+ MiscastEffect( m, ZOT_TRAP_MISCAST, SPTYP_RANDOM,
+ 3, "the power of Zot" );
}
- else
+ else if (in_sight)
{
- mpr("A large net falls onto you!");
- player_caught_in_net();
+ if (one_chance_in(5))
+ {
+ mpr("The power of Zot is invoked against you!");
+ MiscastEffect( &you, ZOT_TRAP_MISCAST, SPTYP_RANDOM,
+ 3, "the power of Zot" );
+ }
+ }
+ else if (player_can_hear(this->pos))
+ {
+ mprf(MSGCH_SOUND, "You hear a %s \"Zot\"!",
+ in_sight ? "loud" : "distant");
}
-
- trap_item( OBJ_MISSILES, MI_THROWING_NET, env.trap[i].pos);
- if (you.attribute[ATTR_HELD])
- mark_net_trapping(you.pos());
-
- grd(env.trap[i].pos) = DNGN_FLOOR;
- 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:
- {
- if (!you.will_trigger_shaft())
- {
- if (trap_known && !you.airborne())
- mpr("You don't fall through the shaft.");
-
- if (!trap_known)
- grd(you.pos()) = DNGN_UNDISCOVERED_TRAP;
+ // Known shafts don't trigger as traps.
+ if (trig_knows)
+ break;
- return;
+ if (!triggerer.will_trigger_shaft())
+ {
+ if (!you_know)
+ this->hide();
+ else if (!triggerer.airborne())
+ {
+ if (you_trigger)
+ {
+ mpr("You don't fall through the shaft.");
+ }
+ else if (m)
+ {
+ simple_monster_message(m,
+ " doesn't fall through the shaft.");
+ }
+ }
}
// Paranoia
if (!is_valid_shaft_level())
{
- if (trap_known)
+ if (you_know && in_sight)
mpr("The shaft disappears in a puff of logic!");
- grd(env.trap[i].pos) = DNGN_FLOOR;
- env.trap[i].type = TRAP_UNASSIGNED;
- return;
+ this->destroy();
}
-
- if (!you.do_shaft() && !trap_known)
+ else
{
- grd(you.pos()) = DNGN_UNDISCOVERED_TRAP;
- return;
+ // Fire away!
+ const bool revealed = triggerer.do_shaft();
+ if (!revealed && !you_know)
+ this->hide();
}
-
break;
- }
- case TRAP_ZOT:
default:
- mpr((trap_known) ? "You enter the Zot trap."
- : "Oh no! You have blundered into a Zot trap!");
- MiscastEffect( &you, ZOT_TRAP_MISCAST, SPTYP_RANDOM,
- 3, "a Zot trap" );
break;
}
- learned_something_new(TUT_SEEN_TRAP, you.pos());
-
- if (!trap_known) // Now you know...
- exercise(SK_TRAPS_DOORS, ((coinflip()) ? 2 : 1));
+
+ if (you_trigger)
+ {
+ learned_something_new(TUT_SEEN_TRAP, this->pos);
+
+ // Exercise T&D if the trap revealed itself.
+ if (!you_know && this->is_known())
+ exercise(SK_TRAPS_DOORS, ((coinflip()) ? 2 : 1));
+ }
}
-void destroy_trap( const coord_def& pos )
+int trap_def::shot_damage(actor& act)
{
- for (int i = 0; i < MAX_TRAPS; ++i)
+ if (act.atype() == ACT_PLAYER)
{
- if (env.trap[i].pos == pos && env.trap[i].type != TRAP_UNASSIGNED)
+ switch (this->type)
{
- grd(pos) = DNGN_FLOOR;
- env.trap[i].type = TRAP_UNASSIGNED;
- return;
+ case TRAP_NEEDLE: return 0;
+ case TRAP_DART: return random2( 4 + you.your_level/2) + 1;
+ case TRAP_ARROW: return random2( 7 + you.your_level) + 1;
+ case TRAP_SPEAR: return random2(10 + you.your_level) + 1;
+ case TRAP_BOLT: return random2(13 + you.your_level) + 1;
+ case TRAP_AXE: return random2(15 + you.your_level) + 1;
+ default: return 0;
+ }
+ }
+ else if (act.atype() == ACT_MONSTER)
+ {
+ // Trap damage to monsters is not a function of level, because
+ // they are fairly stupid and tend to have fewer hp than
+ // players -- this choice prevents traps from easily killing
+ // large monsters fairly deep within the dungeon.
+ switch (this->type)
+ {
+ case TRAP_NEEDLE: return 0;
+ case TRAP_DART: return random2( 4) + 1;
+ case TRAP_ARROW: return random2( 7) + 1;
+ case TRAP_SPEAR: return random2(10) + 1;
+ case TRAP_BOLT: return random2(13) + 1;
+ case TRAP_AXE: return random2(15) + 1;
+ default: return 0;
}
}
+ return (0);
+}
+
+void destroy_trap( const coord_def& pos )
+{
+ if (trap_def* ptrap = find_trap(pos))
+ ptrap->destroy();
+}
+
+trap_def* find_trap(const coord_def& pos)
+{
+ for (int i = 0; i < MAX_TRAPS; ++i)
+ if (env.trap[i].pos == pos && env.trap[i].type != TRAP_UNASSIGNED)
+ return (&env.trap[i]);
+ return (NULL);
+}
+
+trap_type get_trap_type(const coord_def& pos)
+{
+ if (trap_def* ptrap = find_trap(pos))
+ return (ptrap->type);
+ return (TRAP_UNASSIGNED);
}
-void disarm_trap( dist &disa )
+// where *must* point to a valid, discovered trap.
+void disarm_trap(const coord_def& where)
{
if (you.duration[DUR_BERSERKER])
{
@@ -532,21 +713,9 @@ void disarm_trap( dist &disa )
return;
}
- int i, j;
+ trap_def& trap = *find_trap(where);
- for (i = 0; i < MAX_TRAPS; i++)
- {
- if (env.trap[i].pos == you.pos() + disa.delta)
- break;
-
- if (i == MAX_TRAPS - 1)
- {
- mpr("Error - couldn't find that trap.", MSGCH_ERROR);
- return;
- }
- }
-
- switch (trap_category(env.trap[i].type))
+ switch (trap.category())
{
case DNGN_TRAP_MAGICAL:
mpr("You can't disarm that trap.");
@@ -559,59 +728,36 @@ void disarm_trap( dist &disa )
break;
}
+ // Make the actual attempt
+ you.turn_is_over = true;
if (random2(you.skills[SK_TRAPS_DOORS] + 2) <= random2(you.your_level + 5))
{
mpr("You failed to disarm the trap.");
-
- you.turn_is_over = true;
-
if (random2(you.dex) > 5 + random2(5 + you.your_level))
exercise(SK_TRAPS_DOORS, 1 + random2(you.your_level / 5));
else
{
- if (env.trap[i].type == TRAP_NET && env.trap[i].pos != you.pos())
+ if (trap.type == TRAP_NET && trap.pos != you.pos())
{
if (coinflip())
- return;
-
- mpr("You stumble into the trap!");
- move_player_to_grid( env.trap[i].pos, true, false, true);
+ {
+ mpr("You stumble into the trap!");
+ move_player_to_grid(trap.pos, true, false, true);
+ }
}
else
- handle_traps(env.trap[i].type, i, false);
+ trap.trigger(you, true);
if (coinflip())
exercise(SK_TRAPS_DOORS, 1);
}
-
- return;
}
-
- mpr("You have disarmed the trap.");
-
- bolt beam;
-
- beam.target = you.pos() + disa.delta;
-
- if (env.trap[i].type == TRAP_NET)
- trap_item( OBJ_MISSILES, MI_THROWING_NET, beam.target );
- else if (env.trap[i].type != TRAP_BLADE
- && trap_category(env.trap[i].type) == DNGN_TRAP_MECHANICAL)
+ else
{
- const int num_to_make = 10 + random2(you.skills[SK_TRAPS_DOORS]);
- for (j = 0; j < num_to_make; j++)
- {
- // Places items (eg darts), which will automatically stack.
- itrap(beam, i);
- }
+ mpr("You have disarmed the trap.");
+ trap.disarm();
+ exercise(SK_TRAPS_DOORS, 1 + random2(5) + (you.your_level/5));
}
-
- grd(you.pos() + disa.delta) = DNGN_FLOOR;
- env.trap[i].type = TRAP_UNASSIGNED;
- you.turn_is_over = true;
-
- // Reduced from 5 + random2(5).
- exercise(SK_TRAPS_DOORS, 1 + random2(5) + (you.your_level / 5));
}
// Attempts to take a net off a given monster.
@@ -890,65 +1036,177 @@ void clear_trapping_net()
you.attribute[ATTR_HELD] = 0;
}
-bool trap_item(object_class_type base_type, char sub_type,
- const coord_def& where)
+item_def trap_def::generate_trap_item()
{
item_def item;
- item.base_type = base_type;
- item.sub_type = sub_type;
- item.plus = 0;
- item.plus2 = 0;
- item.flags = 0;
- item.special = 0;
+ object_class_type base;
+ int sub;
+
+ switch (this->type)
+ {
+ case TRAP_DART: base = OBJ_MISSILES; sub = MI_DART; break;
+ case TRAP_ARROW: base = OBJ_MISSILES; sub = MI_ARROW; break;
+ case TRAP_BOLT: base = OBJ_MISSILES; sub = MI_BOLT; break;
+ case TRAP_SPEAR: base = OBJ_WEAPONS; sub = WPN_SPEAR; break;
+ case TRAP_AXE: base = OBJ_WEAPONS; sub = WPN_HAND_AXE; break;
+ case TRAP_NEEDLE: base = OBJ_MISSILES; sub = MI_NEEDLE; break;
+ case TRAP_NET: base = OBJ_MISSILES; sub = MI_THROWING_NET; break;
+ default: return item;
+ }
+
+ item.base_type = base;
+ item.sub_type = sub;
item.quantity = 1;
- if (base_type == OBJ_MISSILES)
+ if (base == OBJ_MISSILES)
{
- if (sub_type == MI_NEEDLE)
- set_item_ego_type( item, OBJ_MISSILES, SPMSL_POISONED );
- else
- set_item_ego_type( item, OBJ_MISSILES, SPMSL_NORMAL );
+ set_item_ego_type(item, base,
+ (sub == MI_NEEDLE) ? SPMSL_POISONED : SPMSL_NORMAL);
}
else
{
- set_item_ego_type( item, OBJ_WEAPONS, SPWPN_NORMAL );
+ set_item_ego_type(item, base, SPWPN_NORMAL);
}
+ // give appropriate racial flag for Orcish Mines and Elven Halls
+ // should we ever allow properties of dungeon features, we could use that
+ if (you.where_are_you == BRANCH_ORCISH_MINES)
+ set_equip_race( item, ISFLAG_ORCISH );
+ else if (you.where_are_you == BRANCH_ELVEN_HALLS)
+ set_equip_race( item, ISFLAG_ELVEN );
+
item_colour(item);
+ return item;
+}
- if (igrd(where) != NON_ITEM)
+// Shoot a single piece of ammo at the relevant actor.
+void trap_def::shoot_ammo(actor& act, bool was_known)
+{
+ if (this->ammo_qty <= 0)
{
- if (items_stack( item, mitm[ igrd(where) ] ))
+ if (act.atype() == ACT_PLAYER)
+ mpr("The trap is out of ammunition!");
+ else if (player_can_hear(this->pos))
+ mpr("You hear a soft click.");
+ this->disarm();
+ }
+ else
+ {
+ item_def shot = this->generate_trap_item();
+ bool poison = (this->type == TRAP_NEEDLE);
+ int damage_taken =
+ this->shot_damage(act) - random2(act.armour_class()+1);
+ if (damage_taken < 0)
+ damage_taken = 0;
+
+ if (act.atype() == ACT_PLAYER)
{
- inc_mitm_item_quantity( igrd(where), 1 );
- return (false);
- }
+ if (one_chance_in(5) || (was_known && !one_chance_in(4)))
+ {
+ mprf( "You avoid triggering %s trap.",
+ this->name(DESC_NOCAP_A).c_str() );
- // don't want to go overboard here. Will only generate up to three
- // separate trap items, or less if there are other items present.
- if (mitm[ igrd(where) ].link != NON_ITEM
- && (item.base_type != OBJ_MISSILES
- || item.sub_type != MI_THROWING_NET))
+ return; // no ammo generated either
+ }
+
+ // Start constructing the message.
+ std::string msg = shot.name(DESC_CAP_A) + " shoots out and ";
+
+ // Check for shield blocking.
+ // Exercise only if the trap was unknown (to prevent scumming.)
+ if (!was_known && you.shield() && one_chance_in(3))
+ exercise(SK_SHIELDS, 1);
+
+ if (random2(20 + 5 * you.shield_blocks * you.shield_blocks)
+ < player_shield_class())
+ {
+ you.shield_blocks++;
+ msg += "hits your shield.";
+ mpr(msg.c_str());
+ }
+ else
+ {
+ // note that this uses full (not random2limit(foo,40))
+ // player_evasion.
+ int trap_hit = (20 + (you.your_level*2)) * random2(200) / 100;
+ int your_dodge = player_evasion() + random2(you.dex) / 3
+ - 2 + (you.duration[DUR_REPEL_MISSILES] * 10);
+
+ // Check if it got past dodging. Deflect Missiles provides
+ // immunity to such traps.
+ if (trap_hit >= your_dodge
+ && you.duration[DUR_DEFLECT_MISSILES] == 0)
+ {
+ // OK, we've been hit.
+ msg += "hits you!";
+ mpr(msg.c_str());
+
+ // Needle traps can poison.
+ if (poison && !player_res_poison()
+ && x_chance_in_y(50 - (3*player_AC()) / 2, 100))
+ {
+ poison_player(1 + random2(3));
+ }
+
+ ouch(damage_taken, NON_MONSTER, KILLED_BY_TRAP,
+ shot.name(DESC_PLAIN).c_str());
+ }
+ else // trap dodged
+ {
+ msg += "misses you.";
+ mpr(msg.c_str());
+ }
+
+ // Exercise only if the trap was unknown (to prevent scumming.)
+ if (!was_known && player_light_armour(true) && coinflip())
+ exercise(SK_DODGING, 1);
+ }
+ }
+ else if (act.atype() == ACT_MONSTER)
{
- if (mitm[ mitm[ igrd(where) ].link ].link != NON_ITEM)
- return (false);
+ // XXX reveal the trap XXX
+
+ monsters* monster = static_cast<monsters *>(&act);
+
+ // Determine whether projectile hits.
+ bool hit = (((20+(you.your_level*2))*random2(200))/100
+ >= monster->ev);
+
+ // Check whether to poison.
+ if (poison)
+ poison = (hit && x_chance_in_y(50 - (3*monster->ac)/2, 100));
+
+ if (see_grid(act.pos()))
+ {
+ mprf("%s %s %s%s!",
+ shot.name(DESC_CAP_A).c_str(),
+ hit ? "hits" : "misses",
+ monster->name(DESC_NOCAP_THE).c_str(),
+ (damage_taken == 0
+ && !poison) ? ", but does no damage" : "");
+ }
+
+ if (poison)
+ poison_monster(monster, KC_OTHER);
+
+ // Apply damage.
+ hurt_monster(monster, damage_taken);
+ if (monster->hit_points < 1)
+ monster_die(monster, KILL_MISC, NON_MONSTER);
}
- }
- // give appropriate racial flag for Orcish Mines and Elven Halls
- // should we ever allow properties of dungeon features, we could use that
- if (you.where_are_you == BRANCH_ORCISH_MINES)
- set_equip_race( item, ISFLAG_ORCISH );
- else if (you.where_are_you == BRANCH_ELVEN_HALLS)
- set_equip_race( item, ISFLAG_ELVEN );
+ // Drop the item (sometimes.)
+ if (coinflip())
+ copy_item_to_grid(shot, act.pos());
- return (!copy_item_to_grid( item, where, 1 ));
-} // end trap_item()
+ this->ammo_qty--;
+ }
+}
-// returns appropriate trap symbol for a given trap type {dlb}
-dungeon_feature_type trap_category(trap_type type)
+// returns appropriate trap symbol
+dungeon_feature_type trap_def::category() const
{
- switch (type)
+ switch (this->type)
{
case TRAP_SHAFT:
return (DNGN_TRAP_NATURAL);
@@ -969,7 +1227,8 @@ dungeon_feature_type trap_category(trap_type type)
default: // what *would* be the default? {dlb}
return (DNGN_TRAP_MECHANICAL);
}
-} // end trap_category()
+}
+
// Returns index of the trap for a given (x,y) coordinate pair {dlb}
int trap_at_xy(const coord_def& xy)
diff --git a/crawl-ref/source/traps.h b/crawl-ref/source/traps.h
index d939aa3285..bfa5eaa528 100644
--- a/crawl-ref/source/traps.h
+++ b/crawl-ref/source/traps.h
@@ -12,18 +12,14 @@
#include "enum.h"
#include "travel.h"
-struct dist;
struct bolt;
class monsters;
-bool trap_item(object_class_type base_type, char sub_type,
- const coord_def& where);
-
// last updated 12may2000 {dlb}
/* ***********************************************************************
* called from: acr
* *********************************************************************** */
-void disarm_trap(struct dist &disa);
+void disarm_trap(const coord_def& where);
void remove_net_from( monsters *mon );
void free_self_from_net(void);
@@ -39,11 +35,9 @@ void player_caught_in_net(void);
void clear_trapping_net(void);
void check_net_will_hold_monster(monsters *mon);
-void itrap(struct bolt &pbolt, int trapped);
-void destroy_trap( const coord_def& pos );
-dungeon_feature_type trap_category(trap_type type);
-int trap_at_xy(const coord_def& xy);
-trap_type trap_type_at_xy(const coord_def& xy);
+void destroy_trap(const coord_def& pos);
+trap_def* find_trap(const coord_def& where);
+trap_type get_trap_type(const coord_def& where);
bool is_valid_shaft_level(const level_id &place = level_id::current());
level_id generic_shaft_dest(coord_def pos);