simplistic, and it's not currently possible to make a "baited" shaft; also, there is no threshold weight, so even a single dart will open up (and thus reveal) a shaft trap. Breaks savefile compatibility.
Monsters which fall through a shaft now show up 100% of the time on the player's next visit to the shaft's destination level. Also, the monster is placed close to the spot where the player would end up if s/he went through the same shaft.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@2988 c06c8d41-db1a-0410-9941-cceddc491573
475LL4U4ND6PTNV4XKC7WQAOJC7RF2VCCVX3DRILP2PKIBFYWE6QC
HRUS4XOL5WZ5C7IIAIXCAP765ZTWCSDQ2VVOBRNXYXGEJ5PRKC6AC
S2LIBA2CLTZ6ZU66AUZ2CCNLCDOBSGWQGTZ6HFAFP2XSWAALGLSQC
TFZ4TER7O2Z4FOGF2RCPEPYIHBTUA4LG3ECXLR7XGLCC6GO6OOTAC
SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC
7KWDC7XFNMBLSUO2HISIROBINZBX5T67LJEEXTAORXW2YZ7VWFGAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
AVCMVFA3MKCXHO6H44UK5KJNIHTGQV7UA7GYXM26VI6TXXU5ZN6QC
W5VEC2PBIM5DMU5233HOWAZUEPTGWJRZZIA3H35YYQQW6BTP6XUAC
LEY3EZGTCBV6CYX4L727KQ4ZXL2LZLT5WESN3WAF65VRMX4EDP4QC
PJ7HBIWAV3H23LXGZAAD2QYJ7HMOFOIR5ZJ4U2UTHI766LOTRRWQC
EOMCPVNQLX3IMLC46EAO67DPBH5KEG2FQTPBLGU62HIRWA3UQ7XQC
MSQI3TH6T62JAXQGLL52QZCWAMC372TGB6ZNNRDGUGMJKBNNV2VAC
2WRXQTGYDBLV46WRNVIUKGNA5QS563XZNNW3N2L6PVOCHIP2YGHQC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
RYT42Z6CED4KV5CCJ45CHZ3DQGLFMDCVH6CSQZNXOILULDG4MXVQC
GBUB77EAYHOFY6GQ5IY3ZSBC7FSQFZZKYNBD5QMCQFIKFLYLWHOQC
UZ6N6HOUPGVSPC5NQROEEDWMEGJA5XUWUY2AKH5QG65AZ25PVXDAC
}
level_id generic_shaft_dest(level_pos lpos)
{
level_id lid = lpos.id;
coord_def pos = lpos.pos;
if (lid.level_type != LEVEL_DUNGEON)
return lid;
int curr_depth = lid.depth;
Branch &branch = branches[lid.branch];
lid.depth += ((pos.x + pos.y) % 3) + 1;
if (lid.depth > branch.depth)
lid.depth = branch.depth;
if (lid.depth == curr_depth)
return lid;
// Only shafts on the level immediately above a dangerous branch
// bottom will take you to that dangerous bottom, and shafts can't
// be created during level generation time.
if (branch.dangerous_bottom_level
&& lid.depth == branch.depth
&& (branch.depth - curr_depth) > 1)
{
lid.depth--;
}
return lid;
}
level_id generic_shaft_dest(coord_def pos)
{
return generic_shaft_dest(level_pos(level_id::current(), pos));
}
void handle_items_on_shaft(int x, int y, bool open_shaft)
{
if (!is_valid_shaft_level())
return;
coord_def pos(x, y);
level_id dest = generic_shaft_dest(pos);
if (dest == level_id::current())
return;
int o = igrd(pos);
if (o == NON_ITEM)
return;
igrd(pos) = NON_ITEM;
if (is_terrain_seen(pos) && open_shaft)
{
mpr("A shaft opens up in the floor!");
grd(pos) = DNGN_TRAP_NATURAL;
}
while (o != NON_ITEM)
{
int next = mitm[o].link;
if (is_valid_item( mitm[o] ))
{
if (is_terrain_seen(pos))
{
mprf("%s falls through the shaft.",
mitm[o].name(DESC_INVENTORY).c_str());
}
add_item_to_transit(dest, mitm[o]);
mitm[o].base_type = OBJ_UNASSIGNED;
mitm[o].quantity = 0;
mitm[o].props.clear();
}
o = next;
}
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 dangerous 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;
return generic_shaft_dest(pos());
}
static void cull_lost_items(i_transit_list &ilist, int how_many)
{
// First pass, drop non-artifacts.
for (i_transit_list::iterator i = ilist.begin(); i != ilist.end(); )
{
i_transit_list::iterator finger = i++;
if (!is_artefact(*finger))
{
ilist.erase(finger);
if (--how_many <= MAX_LOST)
return;
}
}
// Second pass, drop randarts.
for (i_transit_list::iterator i = ilist.begin(); i != ilist.end(); )
{
i_transit_list::iterator finger = i++;
if (is_random_artefact(*finger))
{
ilist.erase(finger);
if (--how_many <= MAX_LOST)
return;
}
}
// Third pass, drop unrandarts.
for (i_transit_list::iterator i = ilist.begin(); i != ilist.end(); )
{
i_transit_list::iterator finger = i++;
if (is_unrandom_artefact(*finger))
{
ilist.erase(finger);
if (--how_many <= MAX_LOST)
return;
}
}
// If we're still over the limit (unlikely), just lose
// the old ones.
while (how_many-- > MAX_LOST && !ilist.empty())
ilist.erase( ilist.begin() );
}
}
void add_item_to_transit(const level_id &lid, const item_def &i)
{
i_transit_list &ilist = transiting_items[lid];
ilist.push_back(i);
#ifdef DEBUG_DIAGNOSTICS
mprf(MSGCH_DIAGNOSTICS, "Item in transit: %s",
i.name(DESC_PLAIN).c_str());
#endif
const int how_many = ilist.size();
if (how_many > MAX_LOST)
cull_lost_items(ilist, how_many);
}
void place_transiting_items()
{
level_id c = level_id::current();
items_in_transit::iterator i = transiting_items.find(c);
if (i == transiting_items.end())
return;
i_transit_list &ilist = i->second;
i_transit_list keep;
i_transit_list::iterator item;
for (item = ilist.begin(); item != ilist.end(); item++)
{
coord_def pos(item->x, item->y);
if (!in_bounds(pos))
{
pos.x = random_range(X_BOUND_1 + 1, X_BOUND_2 - 1);
pos.y = random_range(Y_BOUND_1 + 1, Y_BOUND_2 - 1);
}
const coord_def where_to_go =
dgn_find_nearby_stair(DNGN_ROCK_STAIRS_DOWN, pos, true);
// List of items we couldn't place
if (!copy_item_to_grid(*item, where_to_go.x, where_to_go.y))
keep.push_back(*item);
if (m.find_place_to_live(near_player))
bool placed = false;
// In certain instances (currently, falling through a shaft)
// try to place monster a close as possible to its previous
// <x,y> coordinates.
if (!near_player && you.level_type == LEVEL_DUNGEON
&& in_bounds(m.pos()))
{
const coord_def where_to_go =
dgn_find_nearby_stair(DNGN_ROCK_STAIRS_DOWN,
m.pos(), true);
if (monster_habitable_grid(&m, grd(where_to_go)))
{
if (where_to_go == you.pos())
near_player = true;
else
{
mgrd[where_to_go.x][where_to_go.y] = monster_index(&m);
placed = true;
}
}
}
if (!placed)
placed = m.find_place_to_live(near_player);
if (placed)