summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/monplace.cc
diff options
context:
space:
mode:
Diffstat (limited to 'crawl-ref/source/monplace.cc')
-rw-r--r--crawl-ref/source/monplace.cc153
1 files changed, 117 insertions, 36 deletions
diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc
index 55bc258d88..3e0c01ac01 100644
--- a/crawl-ref/source/monplace.cc
+++ b/crawl-ref/source/monplace.cc
@@ -13,6 +13,7 @@
#include "AppHdr.h"
#include "monplace.h"
+#include "branch.h"
#include "externs.h"
#include "lev-pand.h"
#include "makeitem.h"
@@ -301,7 +302,7 @@ monster_type pick_random_monster(const level_id &place,
mon_type = static_cast<monster_type>(random2(NUM_MONSTERS));
count++;
}
- while (mons_rarity(mon_type) == 0 && count < 2000);
+ while (mons_rarity(mon_type, place) == 0 && count < 2000);
if (count == 2000)
return (MONS_PROGRAM_BUG);
@@ -332,6 +333,13 @@ bool place_monster(int &id, int mon_type, int power, beh_type behaviour,
int band_monsters[BIG_BAND]; // band monster types
int lev_mons = power; // final 'power'
int i;
+
+ // player shoved out of the way?
+ bool shoved = false;
+ unsigned char stair_gfx = 0;
+ int tries = 0;
+ int pval = 0;
+ level_id place = level_id::current();
// set initial id to -1 (unsuccessful create)
id = -1;
@@ -341,18 +349,89 @@ bool place_monster(int &id, int mon_type, int power, beh_type behaviour,
return (false);
// (2) take care of random monsters
- if (mon_type == RANDOM_MONSTER
- && player_in_branch( BRANCH_HALL_OF_BLADES ))
- {
- mon_type = MONS_DANCING_WEAPON;
- }
-
if (mon_type == RANDOM_MONSTER)
{
- mon_type = pick_random_monster(level_id::current(), lev_mons,
+ // respect destination level for staircases
+ if (proximity == PROX_NEAR_STAIRS)
+ {
+ while(++tries <= 320)
+ {
+ px = 5 + random2(GXM - 10);
+ py = 5 + random2(GYM - 10);
+
+ if (mgrd[px][py] != NON_MONSTER
+ || (px == you.x_pos && py == you.y_pos))
+ {
+ continue;
+ }
+
+ // Is the monster happy where we want to put it?
+ unsigned char grid_wanted = monster_habitat(mon_type);
+ if (!grid_compatible(grid_wanted, grd[px][py], true))
+ continue;
+
+ // Is the grid verboten?
+ if (!unforbidden( coord_def(px, py), mmask ))
+ continue;
+
+ // don't generate monsters on top of teleport traps
+ int trap = trap_at_xy(px, py);
+ if (trap >= 0)
+ {
+ if (env.trap[trap].type == TRAP_TELEPORT)
+ continue;
+ }
+
+ // check whether there's a stair
+ // and whether it leads to another branch
+ pval = near_stairs(px, py, 1, stair_gfx, place.branch);
+
+ // no monsters spawned in the Temple
+ if (branches[place.branch].id == BRANCH_ECUMENICAL_TEMPLE)
+ continue;
+
+ // found a position near the stairs!
+ if (pval > 0)
+ break;
+ }
+ if (tries > 320)
+ { // give up and try somewhere else
+ proximity = PROX_AWAY_FROM_PLAYER;
+ }
+ else
+ {
+ if ( stair_gfx == '>' ) // deeper level
+ lev_mons++;
+ else if (stair_gfx == '<') // higher level
+ {
+ // monsters don't come from outside the dungeon
+ if (lev_mons <= 0)
+ {
+ proximity = PROX_AWAY_FROM_PLAYER;
+ // or maybe allow 1st level monsters, having visited the
+ // surface, to re-enter the dungeon
+ // in that case lev_mons stays as it is
+ }
+ else
+ lev_mons--;
+ }
+// mprf("branch := %d, level := %d",
+// branches[place.branch].id, lev_mons+1);
+
+ }
+ } // end proximity check
+
+ if (branches[place.branch].id == BRANCH_HALL_OF_BLADES)
+ mon_type = MONS_DANCING_WEAPON;
+ else
+ {
+ // now pick a monster of the given branch and level
+ mon_type = pick_random_monster(place, lev_mons,
lev_mons);
- if (mon_type == MONS_PROGRAM_BUG)
- return (false);
+
+ if (mon_type == MONS_PROGRAM_BUG)
+ return (false);
+ }
}
// (3) decide on banding (good lord!)
@@ -368,22 +447,24 @@ bool place_monster(int &id, int mon_type, int power, beh_type behaviour,
band_monsters[i] = band_member( band, power );
}
- // Monsters that can't move shouldn't be taking the stairs -- bwr
- if (proximity == PROX_NEAR_STAIRS && mons_class_is_stationary( mon_type ))
- proximity = PROX_AWAY_FROM_PLAYER;
+ if (proximity == PROX_NEAR_STAIRS)
+ {
+ // for some cases disallow monsters on stairs
+ if (mons_class_is_stationary( mon_type )
+ || pval == 2 && (mons_speed(mon_type) == 0
+ || grd[px][py] == DNGN_LAVA || grd[px][py] == DNGN_DEEP_WATER))
+ {
+ proximity = PROX_AWAY_FROM_PLAYER;
+ }
+ }
// (4) for first monster, choose location. This is pretty intensive.
bool proxOK;
bool close_to_player;
- // player shoved out of the way?
- bool shoved = false;
- unsigned char stair_gfx = 0;
- int pval = 0;
-
if (!summoned)
{
- int tries = 0;
+ tries = 0;
// try to pick px, py that is
// a) not occupied
// b) compatible
@@ -391,23 +472,27 @@ bool place_monster(int &id, int mon_type, int power, beh_type behaviour,
unsigned char grid_wanted = monster_habitat(mon_type);
while(true)
{
- tries ++;
- // give up on stair placement?
- if (proximity == PROX_NEAR_STAIRS)
+ // handled above, won't change anymore
+ if (proximity == PROX_NEAR_STAIRS && tries)
{
- if (tries > 320)
- {
- proximity = PROX_AWAY_FROM_PLAYER;
- tries = 0;
- }
+ proximity = PROX_AWAY_FROM_PLAYER;
+ tries = 0;
}
// Dropped number of tries from 60.
- else if (tries > 45)
+ else if (tries >= 45)
return (false);
- px = 5 + random2(GXM - 10);
- py = 5 + random2(GYM - 10);
-
+ tries ++;
+
+ // placement already decided for PROX_NEAR_STAIRS
+ if (proximity != PROX_NEAR_STAIRS)
+ {
+ px = 5 + random2(GXM - 10);
+ py = 5 + random2(GYM - 10);
+ }
+
+ // Let's recheck these even for PROX_NEAR_STAIRS, just in case
+
// occupied?
if (mgrd[px][py] != NON_MONSTER
|| (px == you.x_pos && py == you.y_pos))
@@ -456,8 +541,7 @@ bool place_monster(int &id, int mon_type, int power, beh_type behaviour,
break;
case PROX_NEAR_STAIRS:
- pval = near_stairs(px, py, 1, stair_gfx);
- if (pval == 2)
+ if (pval == 2) // player on stairs
{
// 0 speed monsters can't shove player out of their way.
if (mons_speed(mon_type) == 0)
@@ -546,9 +630,6 @@ bool place_monster(int &id, int mon_type, int power, beh_type behaviour,
lev_mons, extra, false, dur);
}
- // if summoned onto traps, directly affect monster
- menv[id].apply_location_effects();
-
// placement of first monster, at least, was a success.
return (true);
}