summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDShaligram <DShaligram@c06c8d41-db1a-0410-9941-cceddc491573>2006-08-15 22:02:22 +0000
committerDShaligram <DShaligram@c06c8d41-db1a-0410-9941-cceddc491573>2006-08-15 22:02:22 +0000
commite36f2c8cdfe62621f6490e40d3a3e18dd93d9de7 (patch)
tree38b51d3a4472af19c0fbfa113134c393099b3b6d
parent8f126891d8dda651dd68f1da691abefc471b27c5 (diff)
downloadcrawl-ref-e36f2c8cdfe62621f6490e40d3a3e18dd93d9de7.tar.gz
crawl-ref-e36f2c8cdfe62621f6490e40d3a3e18dd93d9de7.zip
r33@calamity: dshaligram | 2006-08-16 03:34:30 +051800
* Remove monsters from LOS when a new game starts. * Allow related monsters to swap positions * Cleaned up some other stuff, removed most viewport magic numbers from direct.cc. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/branches/stone_soup@20 c06c8d41-db1a-0410-9941-cceddc491573
-rw-r--r--crawl-ref/source/acr.cc7
-rw-r--r--crawl-ref/source/defines.h18
-rw-r--r--crawl-ref/source/direct.cc66
-rw-r--r--crawl-ref/source/direct.h20
-rw-r--r--crawl-ref/source/enum.h3
-rw-r--r--crawl-ref/source/mon-util.cc139
-rw-r--r--crawl-ref/source/mon-util.h20
-rw-r--r--crawl-ref/source/monstuff.cc743
-rw-r--r--crawl-ref/source/monstuff.h2
-rw-r--r--crawl-ref/source/mstuff2.cc3
-rw-r--r--crawl-ref/source/spl-cast.cc4
-rw-r--r--crawl-ref/source/stuff.cc47
-rw-r--r--crawl-ref/source/stuff.h4
-rw-r--r--crawl-ref/source/view.cc16
14 files changed, 710 insertions, 382 deletions
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc
index 7f0f4d5125..5c582e52e9 100644
--- a/crawl-ref/source/acr.cc
+++ b/crawl-ref/source/acr.cc
@@ -2856,6 +2856,13 @@ static bool initialise(void)
// set vision radius to player's current vision
setLOSRadius( you.current_vision );
+
+ if (newc)
+ {
+ // For a new game, wipe out monsters in LOS.
+ zap_los_monsters();
+ }
+
viewwindow(1, false); // This just puts the view up for the first turn.
item();
diff --git a/crawl-ref/source/defines.h b/crawl-ref/source/defines.h
index d7c28980d8..d124244593 100644
--- a/crawl-ref/source/defines.h
+++ b/crawl-ref/source/defines.h
@@ -64,6 +64,24 @@
// max y-bound for level generation {dlb}
#define GYM 70
+#define LOS_SX 8
+#define LOS_EX 25
+#define LOS_SY 1
+#define LOS_EY 17
+
+#define VIEW_SX 1
+#define VIEW_EX 33
+#define VIEW_SY 1
+#define VIEW_EY 17
+
+#define VIEW_Y_DIFF (((VIEW_EX - VIEW_SX + 1) - (VIEW_EY - VIEW_SY + 1)) / 2)
+
+// View centre must be the same as LOS centre.
+// VIEW_CX == 17
+#define VIEW_CX ((VIEW_SX + VIEW_EX) / 2)
+// VIEW_CY == 9
+#define VIEW_CY ((VIEW_SY + VIEW_EY) / 2)
+
// max traps per level
#define MAX_TRAPS 30
diff --git a/crawl-ref/source/direct.cc b/crawl-ref/source/direct.cc
index cab6fc74fa..ad12091c91 100644
--- a/crawl-ref/source/direct.cc
+++ b/crawl-ref/source/direct.cc
@@ -143,7 +143,7 @@ void direction( struct dist &moves, int restrict, int mode )
// XXX. this is ALWAYS in relation to the player. But a bit of a hack
// nonetheless! --GDL
- gotoxy( 18, 9 );
+ gotoxy( VIEW_CX + 1, VIEW_CY );
int keyin = getchm(KC_TARGETING);
@@ -365,8 +365,8 @@ void look_around(struct dist &moves, bool justLooking, int first_move, int mode)
bool dirChosen = false;
bool targChosen = false;
int dir = 0;
- int cx = 17;
- int cy = 9;
+ int cx = VIEW_CX;
+ int cy = VIEW_CY;
int newcx, newcy;
int mx, my; // actual map x,y (scratch)
int mid; // monster id (scratch)
@@ -519,8 +519,8 @@ void look_around(struct dist &moves, bool justLooking, int first_move, int mode)
case '?':
targChosen = true;
- mx = you.x_pos + cx - 17;
- my = you.y_pos + cy - 9;
+ mx = you.x_pos + cx - VIEW_CX;
+ my = you.y_pos + cy - VIEW_CY;
mid = mgrd[mx][my];
if (mid == NON_MONSTER)
@@ -535,7 +535,7 @@ void look_around(struct dist &moves, bool justLooking, int first_move, int mode)
redraw_screen();
mesclr( true );
// describe the cell again.
- describe_cell(you.x_pos + cx - 17, you.y_pos + cy - 9);
+ describe_cell(view2gridX(cx), view2gridY(cy));
break;
case '\r':
@@ -545,12 +545,12 @@ void look_around(struct dist &moves, bool justLooking, int first_move, int mode)
// If we're in look-around mode, and the cursor is on
// the character and there's a valid travel target
// within the viewport, jump to that target.
- if (justLooking && cx == 17 && cy == 9)
+ if (justLooking && cx == VIEW_CX && cy == VIEW_CY)
{
if (you.travel_x > 0 && you.travel_y > 0)
{
- int nx = you.travel_x - you.x_pos + 17;
- int ny = you.travel_y - you.y_pos + 9;
+ int nx = grid2viewX(you.travel_x);
+ int ny = grid2viewY(you.travel_y);
if (in_viewport_bounds(nx, ny))
{
newcx = nx;
@@ -602,16 +602,16 @@ void look_around(struct dist &moves, bool justLooking, int first_move, int mode)
moves.isValid = true;
moves.isTarget = true;
- moves.tx = you.x_pos + cx - 17;
- moves.ty = you.y_pos + cy - 9;
+ moves.tx = you.x_pos + cx - VIEW_CX;
+ moves.ty = you.y_pos + cy - VIEW_CY;
if (moves.tx == you.x_pos && moves.ty == you.y_pos)
moves.isMe = true;
else
{
// try to set you.previous target
- mx = you.x_pos + cx - 17;
- my = you.y_pos + cy - 9;
+ mx = you.x_pos + cx - VIEW_CX;
+ my = you.y_pos + cy - VIEW_CY;
mid = mgrd[mx][my];
if (mid == NON_MONSTER)
@@ -633,10 +633,10 @@ void look_around(struct dist &moves, bool justLooking, int first_move, int mode)
}
// bounds check for newcx, newcy
- if (newcx < 1) newcx = 1;
- if (newcx > 33) newcx = 33;
- if (newcy < 1) newcy = 1;
- if (newcy > 17) newcy = 17;
+ if (newcx < VIEW_SX) newcx = VIEW_SX;
+ if (newcx > VIEW_EX) newcx = VIEW_EX;
+ if (newcy < VIEW_SY) newcy = VIEW_SY;
+ if (newcy > VIEW_EY) newcy = VIEW_EY;
// no-op if the cursor doesn't move.
if (newcx == cx && newcy == cy)
@@ -649,11 +649,11 @@ void look_around(struct dist &moves, bool justLooking, int first_move, int mode)
if (!in_vlos(cx, cy))
{
mpr("You can't see that place.");
- describe_oos_square(you.x_pos + cx - 17,
- you.y_pos + cy - 9);
+ describe_oos_square(you.x_pos + cx - VIEW_CX,
+ you.y_pos + cy - VIEW_CY);
continue;
}
- describe_cell(you.x_pos + cx - 17, you.y_pos + cy - 9);
+ describe_cell(you.x_pos + cx - VIEW_CX, you.y_pos + cy - VIEW_CY);
} // end WHILE
mesclr( true );
@@ -661,18 +661,19 @@ void look_around(struct dist &moves, bool justLooking, int first_move, int mode)
bool in_vlos(int x, int y)
{
- return in_los_bounds(x, y) && (env.show[x - 8][y] || (x == 17 && y == 9));
+ return in_los_bounds(x, y)
+ && (env.show[x - LOS_SX][y] || (x == VIEW_CX && y == VIEW_CY));
}
bool in_los(int x, int y)
{
- const int tx = x + 9 - you.x_pos,
- ty = y + 9 - you.y_pos;
+ const int tx = x + VIEW_CX - you.x_pos,
+ ty = y + VIEW_CY - you.y_pos;
- if (!in_los_bounds(tx + 8, ty))
+ if (!in_los_bounds(tx, ty))
return (false);
- return (x == you.x_pos && y == you.y_pos) || env.show[tx][ty];
+ return (x == you.x_pos && y == you.y_pos) || env.show[tx - LOS_SX][ty];
}
static bool find_monster( int x, int y, int mode )
@@ -760,12 +761,12 @@ static int next_los(int dir, int los, bool wrap)
bool in_viewport_bounds(int x, int y)
{
- return (x >= 1 && x <= 33 && y >= 1 && y <= 17);
+ return (x >= VIEW_SX && x <= VIEW_EX && y >= VIEW_SY && y <= VIEW_EY);
}
bool in_los_bounds(int x, int y)
{
- return !(x > 25 || x < 8 || y > 17 || y < 1);
+ return !(x > LOS_EX || x < LOS_SX || y > LOS_EY || y < LOS_SY);
}
//---------------------------------------------------------------
@@ -805,7 +806,8 @@ static char find_square( unsigned char xps, unsigned char yps,
{
// We've been told to flip between visible/hidden, so we
// need to find what we're currently on.
- bool vis = (env.show[xps - 8][yps] || (xps == 17 && yps == 9));
+ bool vis = (env.show[xps - 8][yps]
+ || (xps == VIEW_CX && yps == VIEW_CY));
if (wrap && (vis != (los == LOS_FLIPVH)) == (direction == 1))
{
@@ -828,9 +830,9 @@ static char find_square( unsigned char xps, unsigned char yps,
onlyVis = (los & LOS_VISIBLE);
onlyHidden = (los & LOS_HIDDEN);
- const int minx = 1, maxx = 33,
- miny = -7, maxy = 25,
- ctrx = 17, ctry = 9;
+ const int minx = VIEW_SX, maxx = VIEW_EX,
+ miny = VIEW_SY - VIEW_Y_DIFF, maxy = VIEW_EY + VIEW_Y_DIFF,
+ ctrx = VIEW_CX, ctry = VIEW_CY;
while (temp_xps >= minx - 1 && temp_xps <= maxx
&& temp_yps <= maxy && temp_yps >= miny - 1)
@@ -963,7 +965,7 @@ static char find_square( unsigned char xps, unsigned char yps,
// continue;
if (temp_xps < minx - 1 || temp_xps > maxx
- || temp_yps < 1 || temp_yps > 17)
+ || temp_yps < VIEW_SY || temp_yps > VIEW_EY)
continue;
if (targ_x < 1 || targ_x >= GXM || targ_y < 1 || targ_y >= GYM)
diff --git a/crawl-ref/source/direct.h b/crawl-ref/source/direct.h
index e591107578..d3aec5816a 100644
--- a/crawl-ref/source/direct.h
+++ b/crawl-ref/source/direct.h
@@ -44,4 +44,24 @@ bool in_vlos(int x, int y);
std::string feature_description(int mx, int my);
+inline int view2gridX(int vx)
+{
+ return (you.x_pos + vx - VIEW_CX);
+}
+
+inline int view2gridY(int vy)
+{
+ return (you.y_pos + vy - VIEW_CY);
+}
+
+inline int grid2viewX(int gx)
+{
+ return (gx - you.x_pos + VIEW_CX);
+}
+
+inline int grid2viewY(int gy)
+{
+ return (gy - you.y_pos + VIEW_CY);
+}
+
#endif
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index 0fa37aa2cc..a803a5d5c6 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -1396,7 +1396,8 @@ enum KILLER // monster_die(), thing_thrown
KILL_YOU_MISSILE,
KILL_MON_MISSILE,
KILL_MISC, // 5
- KILL_RESET // abjuration, etc.
+ KILL_RESET, // abjuration, etc.
+ KILL_DISMISSED // only on new game startup
};
#define YOU_KILL(x) ((x) == KILL_YOU || (x) == KILL_YOU_MISSILE)
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 73e10916af..eeb629802b 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -111,10 +111,10 @@ static const char *monster_spell_name[] = {
#endif
static int mons_exp_mod(int mclass);
-static monsterentry *seekmonster(int *p_monsterid);
+static monsterentry *seekmonster(int p_monsterid);
// macro that saves some typing, nothing more
-#define smc seekmonster(&mc)
+#define smc seekmonster(mc)
/* ******************** BEGIN PUBLIC FUNCTIONS ******************** */
void mons_init(FixedVector < unsigned short, 1000 > &colour)
@@ -200,6 +200,21 @@ int mons_holiness(int mc)
return (smc->holiness);
} // end mons_holiness()
+bool mons_is_stationary(const monsters *mons)
+{
+ return (mons->type == MONS_OKLOB_PLANT
+ || mons->type == MONS_PLANT
+ || mons->type == MONS_FUNGUS
+ || mons->type == MONS_CURSE_SKULL
+ || (mons->type >= MONS_CURSE_TOE
+ && mons->type <= MONS_POTION_MIMIC));
+}
+
+bool invalid_monster(const monsters *mons)
+{
+ return (!mons || mons->type == -1);
+}
+
bool mons_is_mimic( int mc )
{
return (mons_charclass( mc ) == MONS_GOLD_MIMIC);
@@ -301,7 +316,7 @@ char mons_see_invis( struct monsters *mon )
{
if (mon->type == MONS_PLAYER_GHOST || mon->type == MONS_PANDEMONIUM_DEMON)
return (ghost.values[ GVAL_SEE_INVIS ]);
- else if (((seekmonster(&mon->type))->bitfields & M_SEE_INVIS) != 0)
+ else if (((seekmonster(mon->type))->bitfields & M_SEE_INVIS) != 0)
return (1);
else if (scan_mon_inv_randarts( mon, RAP_EYESIGHT ) > 0)
return (1);
@@ -374,7 +389,7 @@ int mons_damage(int mc, int rt)
int mons_resist_magic( struct monsters *mon )
{
- int u = (seekmonster(&mon->type))->resist_magic;
+ int u = (seekmonster(mon->type))->resist_magic;
// negative values get multiplied with mhd
if (u < 0)
@@ -685,7 +700,7 @@ int hit_points(int hit_dice, int min_hp, int rand_hp)
// of monster, not a pacticular monsters current hit dice. -- bwr
int mons_type_hit_dice( int type )
{
- struct monsterentry *mon_class = seekmonster( &type );
+ struct monsterentry *mon_class = seekmonster( type );
if (mon_class)
return (mon_class->hpdice[0]);
@@ -897,7 +912,7 @@ void define_monster(int k)
int m2_class = menv[k].type;
int m2_HD, m2_hp, m2_hp_max, m2_AC, m2_ev, m2_speed;
int m2_sec = menv[k].number;
- struct monsterentry *m = seekmonster(&m2_class);
+ struct monsterentry *m = seekmonster(m2_class);
m2_HD = m->hpdice[0];
@@ -1160,7 +1175,7 @@ void moname(int mons_num, bool vis, char descrip, char glog[ ITEMNAME_SIZE ])
glog[0] = '\0';
char gmon_name[ ITEMNAME_SIZE ] = "";
- strcpy( gmon_name, seekmonster( &mons_num )->name );
+ strcpy( gmon_name, seekmonster( mons_num )->name );
if (!vis)
{
@@ -1227,14 +1242,12 @@ void moname(int mons_num, bool vis, char descrip, char glog[ ITEMNAME_SIZE ])
/* ********************* END PUBLIC FUNCTIONS ********************* */
// see mons_init for initialization of mon_entry array.
-static struct monsterentry *seekmonster(int *p_monsterid)
+static monsterentry *seekmonster(int p_monsterid)
{
- ASSERT(p_monsterid != 0);
-
- int me = mon_entry[(*p_monsterid)];
+ int me = mon_entry[p_monsterid];
if (me >= 0) // PARANOIA
- return (&mondata[mon_entry[(*p_monsterid)]]);
+ return (&mondata[me]);
else
return (NULL);
} // end seekmonster()
@@ -1311,30 +1324,52 @@ bool mons_aligned(int m1, int m2)
return (fr1 == fr2);
}
-bool mons_friendly(struct monsters *m)
+bool mons_friendly(const monsters *m)
{
return (m->attitude == ATT_FRIENDLY || mons_has_ench(m, ENCH_CHARM));
}
-bool mons_is_stabbable(struct monsters *m)
+bool mons_is_confused(const monsters *m)
+{
+ return (mons_has_ench(m, ENCH_CONFUSION) &&
+ !mons_class_flag(m->type, M_CONFUSED));
+}
+
+bool mons_is_fleeing(const monsters *m)
+{
+ return (m->behaviour == BEH_FLEE);
+}
+
+bool mons_is_sleeping(const monsters *m)
+{
+ return (m->behaviour == BEH_SLEEP);
+}
+
+bool mons_is_batty(const monsters *m)
+{
+ return testbits(m->flags, MF_BATTY);
+}
+
+bool mons_looks_stabbable(const monsters *m)
{
// Make sure oklob plants are never highlighted. That'll defeat the
// point of making them look like normal plants.
return (!mons_class_flag(m->type, M_NO_EXP_GAIN)
&& m->type != MONS_OKLOB_PLANT
+ && !mons_is_mimic(m->type)
&& !mons_friendly(m)
- && m->behaviour == BEH_SLEEP);
+ && mons_is_sleeping(m));
}
-bool mons_maybe_stabbable(struct monsters *m)
+bool mons_looks_distracted(const monsters *m)
{
return (!mons_class_flag(m->type, M_NO_EXP_GAIN)
&& m->type != MONS_OKLOB_PLANT
+ && !mons_is_mimic(m->type)
&& !mons_friendly(m)
- && ((m->foe != MHITYOU && !testbits(m->flags, MF_BATTY))
- || (mons_has_ench(m, ENCH_CONFUSION) &&
- !mons_class_flag(m->type, M_CONFUSED))
- || m->behaviour == BEH_FLEE));
+ && ((m->foe != MHITYOU && !mons_is_batty(m))
+ || mons_is_confused(m)
+ || mons_is_fleeing(m)));
}
/* ******************************************************************
@@ -1411,7 +1446,7 @@ bool mons_should_fire(struct bolt &beam)
return (false);
}
-int mons_has_ench(struct monsters *mon, unsigned int ench, unsigned int ench2)
+int mons_has_ench(const monsters *mon, unsigned int ench, unsigned int ench2)
{
// silliness
if (ench == ENCH_NONE)
@@ -2023,3 +2058,65 @@ const char *mons_pronoun(int mon_type, int variant)
return ("");
}
+
+bool monster_can_swap(const monsters *m)
+{
+ const monsterentry *me = seekmonster(m->type);
+ if (!me)
+ return (false);
+
+ // Efreet and fire elementals are disqualified because they leave behind
+ // clouds of flame.
+ if (m->type == MONS_EFREET || m->type == MONS_FIRE_ELEMENTAL)
+ return (false);
+
+ int mchar = me->showchar;
+ // Somewhat arbitrary: giants and dragons are too big to get past anything,
+ // beetles are too dumb (arguable), dancing weapons can't communicate, eyes
+ // aren't pushers and shovers, zombies are zombies. Worms and elementals
+ // are on the list because all 'w' are currently unrelated.
+ return (mchar != 'C' && mchar != 'B' && mchar != '(' && mchar != 'D'
+ && mchar != 'G' && mchar != 'Z' && mchar != 'w' && mchar != '#');
+}
+
+// Returns true if m1 and m2 are related, and m1 is higher up the totem pole
+// than m2. The criteria for being related are somewhat loose, as you can see
+// below.
+bool monster_senior(const monsters *m1, const monsters *m2)
+{
+ const monsterentry *me1 = seekmonster(m1->type),
+ *me2 = seekmonster(m2->type);
+
+ if (!me1 || !me2)
+ return (false);
+
+ int mchar1 = me1->showchar,
+ mchar2 = me2->showchar;
+
+ // If both are demons, the smaller number is the nastier demon.
+ if (isdigit(mchar1) && isdigit(mchar2))
+ return (mchar1 < mchar2);
+
+ // &s are the evillest demons of all, well apart from Geryon, who really
+ // profits from *not* pushing past beasts.
+ if (mchar1 == '&' && isdigit(mchar2) && m1->type != MONS_GERYON)
+ return (m1->hit_dice > m2->hit_dice);
+
+ // Skeletal warriors can push past zombies large and small.
+ if (m1->type == MONS_SKELETAL_WARRIOR && (mchar2 == 'z' || mchar2 == 'Z'))
+ return (m1->hit_dice > m2->hit_dice);
+
+ if (m1->type == MONS_QUEEN_BEE
+ && (m2->type == MONS_KILLER_BEE
+ || m2->type == MONS_KILLER_BEE_LARVA))
+ return (true);
+
+ if (m1->type == MONS_KILLER_BEE && m2->type == MONS_KILLER_BEE_LARVA)
+ return (true);
+
+ // Special-case gnolls so they can't get past (hob)goblins
+ if (m1->type == MONS_GNOLL && m2->type != MONS_GNOLL)
+ return (false);
+
+ return (mchar1 == mchar2 && m1->hit_dice > m2->hit_dice);
+}
diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h
index c22b1a0442..a74abfa5a3 100644
--- a/crawl-ref/source/mon-util.h
+++ b/crawl-ref/source/mon-util.h
@@ -407,10 +407,14 @@ bool mons_aligned(int m1, int m2);
/* ***********************************************************************
* called from: monstuff acr
* *********************************************************************** */
-bool mons_friendly(struct monsters *m);
+bool mons_friendly(const monsters *m);
+bool mons_is_confused(const monsters *m);
+bool mons_is_fleeing(const monsters *m);
+bool mons_is_sleeping(const monsters *m);
+bool mons_is_batty(const monsters *m);
-int mons_has_ench( struct monsters *mon, unsigned int ench,
+int mons_has_ench( const monsters *mon, unsigned int ench,
unsigned int ench2 = ENCH_NONE );
int mons_del_ench( struct monsters *mon, unsigned int ench,
@@ -418,10 +422,18 @@ int mons_del_ench( struct monsters *mon, unsigned int ench,
bool mons_add_ench( struct monsters *mon, unsigned int ench );
-bool mons_is_stabbable(struct monsters *m);
+bool mons_looks_stabbable(const monsters *m);
-bool mons_maybe_stabbable(struct monsters *m);
+bool mons_looks_distracted(const monsters *m);
bool check_mons_resist_magic( struct monsters *monster, int pow );
+bool mons_is_stationary(const monsters *mons);
+
+bool invalid_monster(const monsters *mons);
+
+bool monster_can_swap(const monsters *m);
+
+bool monster_senior(const monsters *first, const monsters *second);
+
#endif
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index 34577f1407..cd5d36e5e2 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -58,11 +58,14 @@ static void monster_move(struct monsters *monster);
static bool plant_spit(struct monsters *monster, struct bolt &pbolt);
static int map_wand_to_mspell(int wand_type);
-char mmov_x, mmov_y;
+// [dshaligram] Doesn't need to be extern.
+static int mmov_x, mmov_y;
static int compass_x[8] = { -1, 0, 1, 1, 1, 0, -1, -1 };
static int compass_y[8] = { -1, -1, -1, 0, 1, 1, 1, 0 };
+static bool immobile_monster[MAX_MONSTERS];
+
#define FAR_AWAY 1000000 // used in monster_move()
// This function creates an arteficial item to represent a mimic's appearance.
@@ -620,6 +623,9 @@ void monster_die(struct monsters *monster, char killer, int i)
place_cloud( CLOUD_GREY_SMOKE_MON + random2(3), monster->x,
monster->y, 1 + random2(3) );
+ // fall-through
+
+ case KILL_DISMISSED:
for (dmi = MSLOT_GOLD; dmi >= MSLOT_WEAPON; dmi--)
{ /* takes whatever it's carrying back home */
if (monster->inv[dmi] != NON_ITEM)
@@ -680,7 +686,7 @@ void monster_die(struct monsters *monster, char killer, int i)
you.unique_creatures[ monster->type - 280 ] = 0;
}
- if (killer != KILL_RESET)
+ if (killer != KILL_RESET && killer != KILL_DISMISSED)
{
you.kills.record_kill(monster, killer, pet_kill);
@@ -3411,357 +3417,362 @@ static bool handle_throw(struct monsters *monster, bolt & beem)
return (false);
} // end handle_throw()
-
-//---------------------------------------------------------------
-//
-// handle_monsters
-//
-// This is the routine that controls monster AI.
-//
-//---------------------------------------------------------------
-void handle_monsters(void)
+static void handle_monster_move(int i, monsters *monster)
{
- bool brkk = false;
+ bool brkk = false;
struct bolt beem;
- int i;
+ FixedArray <unsigned int, 19, 19> show;
- FixedArray < unsigned int, 19, 19 > show;
+ if (monster->hit_points > monster->max_hit_points)
+ monster->hit_points = monster->max_hit_points;
-// losight(show, grd, you.x_pos, you.y_pos);
+ // monster just summoned (or just took stairs), skip this action
+ if (testbits( monster->flags, MF_JUST_SUMMONED ))
+ {
+ monster->flags &= ~MF_JUST_SUMMONED;
+ return;
+ }
+
+ monster->speed_increment += (monster->speed * you.time_taken) / 10;
- for (i = 0; i < MAX_MONSTERS; i++)
+ if (you.slow > 0)
{
- struct monsters *monster = &menv[i];
+ monster->speed_increment += (monster->speed * you.time_taken) / 10;
+ }
- if (monster->type != -1)
+ // Handle enchantments and clouds on nonmoving monsters:
+ if (monster->speed == 0)
+ {
+ if (env.cgrid[monster->x][monster->y] != EMPTY_CLOUD
+ && !mons_has_ench( monster, ENCH_SUBMERGED ))
{
- if (monster->hit_points > monster->max_hit_points)
- monster->hit_points = monster->max_hit_points;
+ mons_in_cloud( monster );
+ }
- // monster just summoned (or just took stairs), skip this action
- if (testbits( monster->flags, MF_JUST_SUMMONED ))
- {
- monster->flags &= ~MF_JUST_SUMMONED;
- continue;
- }
+ handle_enchantment( monster );
+ }
- monster->speed_increment += (monster->speed * you.time_taken) / 10;
+ // memory is decremented here for a reason -- we only want it
+ // decrementing once per monster "move"
+ if (monster->foe_memory > 0)
+ monster->foe_memory--;
+
+ if (monster->type == MONS_GLOWING_SHAPESHIFTER)
+ mons_add_ench( monster, ENCH_GLOWING_SHAPESHIFTER );
+
+ // otherwise there are potential problems with summonings
+ if (monster->type == MONS_SHAPESHIFTER)
+ mons_add_ench( monster, ENCH_SHAPESHIFTER );
+
+ // We reset batty monsters from wander to seek here, instead
+ // of in handle_behaviour() since that will be called with
+ // every single movement, and we want these monsters to
+ // hit and run. -- bwr
+ if (monster->foe != MHITNOT
+ && monster->behaviour == BEH_WANDER
+ && testbits( monster->flags, MF_BATTY ))
+ {
+ monster->behaviour = BEH_SEEK;
+ }
- if (you.slow > 0)
- {
- monster->speed_increment += (monster->speed * you.time_taken) / 10;
- }
+ while (monster->speed_increment >= 80)
+ { // The continues & breaks are WRT this.
+ if (monster->type != -1 && monster->hit_points < 1)
+ break;
- // Handle enchantments and clouds on nonmoving monsters:
- if (monster->speed == 0)
- {
- if (env.cgrid[monster->x][monster->y] != EMPTY_CLOUD
- && !mons_has_ench( monster, ENCH_SUBMERGED ))
- {
- mons_in_cloud( monster );
- }
+ monster->speed_increment -= 10;
- handle_enchantment( monster );
- }
+ if (env.cgrid[monster->x][monster->y] != EMPTY_CLOUD)
+ {
+ if (mons_has_ench( monster, ENCH_SUBMERGED ))
+ break;
+
+ if (monster->type == -1)
+ break; // problem with vortices
- // memory is decremented here for a reason -- we only want it
- // decrementing once per monster "move"
- if (monster->foe_memory > 0)
- monster->foe_memory--;
-
- if (monster->type == MONS_GLOWING_SHAPESHIFTER)
- mons_add_ench( monster, ENCH_GLOWING_SHAPESHIFTER );
-
- // otherwise there are potential problems with summonings
- if (monster->type == MONS_SHAPESHIFTER)
- mons_add_ench( monster, ENCH_SHAPESHIFTER );
-
- // We reset batty monsters from wander to seek here, instead
- // of in handle_behaviour() since that will be called with
- // every single movement, and we want these monsters to
- // hit and run. -- bwr
- if (monster->foe != MHITNOT
- && monster->behaviour == BEH_WANDER
- && testbits( monster->flags, MF_BATTY ))
+ mons_in_cloud(monster);
+
+ if (monster->type == -1)
{
- monster->behaviour = BEH_SEEK;
+ monster->speed_increment = 1;
+ break;
}
+ }
- while (monster->speed_increment >= 80)
- { // The continues & breaks are WRT this.
- if (monster->type != -1 && monster->hit_points < 1)
- break;
+ handle_behaviour(monster);
- monster->speed_increment -= 10;
+ if (handle_enchantment(monster))
+ continue;
- if (env.cgrid[monster->x][monster->y] != EMPTY_CLOUD)
- {
- if (mons_has_ench( monster, ENCH_SUBMERGED ))
- break;
+ // submerging monsters will hide from clouds
+ const int habitat = monster_habitat( monster->type );
+ if (habitat != DNGN_FLOOR
+ && habitat == grd[monster->x][monster->y]
+ && env.cgrid[monster->x][monster->y] != EMPTY_CLOUD)
+ {
+ mons_add_ench( monster, ENCH_SUBMERGED );
+ }
- if (monster->type == -1)
- break; // problem with vortices
+ // regenerate:
+ if (monster_descriptor(monster->type, MDSC_REGENERATES)
- mons_in_cloud(monster);
+ || (monster->type == MONS_FIRE_ELEMENTAL
+ && (grd[monster->x][monster->y] == DNGN_LAVA
+ || env.cgrid[monster->x][monster->y] == CLOUD_FIRE
+ || env.cgrid[monster->x][monster->y] == CLOUD_FIRE_MON))
- if (monster->type == -1)
- {
- monster->speed_increment = 1;
- break;
- }
- }
+ || (monster->type == MONS_WATER_ELEMENTAL
+ && (grd[monster->x][monster->y] == DNGN_SHALLOW_WATER
+ || grd[monster->x][monster->y] == DNGN_DEEP_WATER))
- handle_behaviour(monster);
+ || (monster->type == MONS_AIR_ELEMENTAL
+ && env.cgrid[monster->x][monster->y] == EMPTY_CLOUD
+ && one_chance_in(3))
- if (handle_enchantment(monster))
- continue;
+ || one_chance_in(25))
+ {
+ heal_monster(monster, 1, false);
+ }
- // submerging monsters will hide from clouds
- const int habitat = monster_habitat( monster->type );
- if (habitat != DNGN_FLOOR
- && habitat == grd[monster->x][monster->y]
- && env.cgrid[monster->x][monster->y] != EMPTY_CLOUD)
- {
- mons_add_ench( monster, ENCH_SUBMERGED );
- }
+ if (monster->speed >= 100)
+ continue;
+
+ if (monster->type == MONS_ZOMBIE_SMALL
+ || monster->type == MONS_ZOMBIE_LARGE
+ || monster->type == MONS_SIMULACRUM_SMALL
+ || monster->type == MONS_SIMULACRUM_LARGE
+ || monster->type == MONS_SKELETON_SMALL
+ || monster->type == MONS_SKELETON_LARGE)
+ {
+ monster->max_hit_points = monster->hit_points;
+ }
- // regenerate:
- if (monster_descriptor(monster->type, MDSC_REGENERATES)
+ if (igrd[monster->x][monster->y] != NON_ITEM
+ && (mons_itemuse(monster->type) == MONUSE_WEAPONS_ARMOUR
+ || mons_itemuse(monster->type) == MONUSE_EATS_ITEMS
+ || monster->type == MONS_NECROPHAGE
+ || monster->type == MONS_GHOUL))
+ {
+ if (handle_pickup(monster))
+ continue;
+ }
- || (monster->type == MONS_FIRE_ELEMENTAL
- && (grd[monster->x][monster->y] == DNGN_LAVA
- || env.cgrid[monster->x][monster->y] == CLOUD_FIRE
- || env.cgrid[monster->x][monster->y] == CLOUD_FIRE_MON))
+ // calculates mmov_x, mmov_y based on monster target.
+ handle_movement(monster);
- || (monster->type == MONS_WATER_ELEMENTAL
- && (grd[monster->x][monster->y] == DNGN_SHALLOW_WATER
- || grd[monster->x][monster->y] == DNGN_DEEP_WATER))
+ brkk = false;
- || (monster->type == MONS_AIR_ELEMENTAL
- && env.cgrid[monster->x][monster->y] == EMPTY_CLOUD
- && one_chance_in(3))
+ if (mons_has_ench( monster, ENCH_CONFUSION )
+ || (monster->type == MONS_AIR_ELEMENTAL
+ && mons_has_ench( monster, ENCH_SUBMERGED )))
+ {
+ mmov_x = random2(3) - 1;
+ mmov_y = random2(3) - 1;
- || one_chance_in(25))
- {
- heal_monster(monster, 1, false);
- }
+ // bounds check: don't let confused monsters try to run
+ // off the map
+ if (monster->target_x + mmov_x < 0
+ || monster->target_x + mmov_x >= GXM)
+ {
+ mmov_x = 0;
+ }
- if (monster->speed >= 100)
- continue;
+ if (monster->target_y + mmov_y < 0
+ || monster->target_y + mmov_y >= GYM)
+ {
+ mmov_y = 0;
+ }
- if (monster->type == MONS_ZOMBIE_SMALL
- || monster->type == MONS_ZOMBIE_LARGE
- || monster->type == MONS_SIMULACRUM_SMALL
- || monster->type == MONS_SIMULACRUM_LARGE
- || monster->type == MONS_SKELETON_SMALL
- || monster->type == MONS_SKELETON_LARGE)
- {
- monster->max_hit_points = monster->hit_points;
- }
+ if (mgrd[monster->x + mmov_x][monster->y + mmov_y] != NON_MONSTER
+ && (mmov_x != 0 || mmov_y != 0))
+ {
+ mmov_x = 0;
+ mmov_y = 0;
- if (igrd[monster->x][monster->y] != NON_ITEM
- && (mons_itemuse(monster->type) == MONUSE_WEAPONS_ARMOUR
- || mons_itemuse(monster->type) == MONUSE_EATS_ITEMS
- || monster->type == MONS_NECROPHAGE
- || monster->type == MONS_GHOUL))
+ if (monsters_fight(i, mgrd[monster->x + mmov_x][monster->y + mmov_y]))
{
- if (handle_pickup(monster))
- continue;
+ brkk = true;
}
+ }
+ }
- // calculates mmov_x, mmov_y based on monster target.
- handle_movement(monster);
+ if (brkk)
+ continue;
- brkk = false;
+ handle_nearby_ability( monster );
- if (mons_has_ench( monster, ENCH_CONFUSION )
- || (monster->type == MONS_AIR_ELEMENTAL
- && mons_has_ench( monster, ENCH_SUBMERGED )))
- {
- mmov_x = random2(3) - 1;
- mmov_y = random2(3) - 1;
+ beem.target_x = monster->target_x;
+ beem.target_y = monster->target_y;
- // bounds check: don't let confused monsters try to run
- // off the map
- if (monster->target_x + mmov_x < 0
- || monster->target_x + mmov_x >= GXM)
- {
- mmov_x = 0;
- }
+ if (monster->behaviour != BEH_SLEEP
+ && monster->behaviour != BEH_WANDER)
+ {
+ // prevents unfriendlies from nuking you from offscreen.
+ // How nice!
+ if (mons_friendly(monster) || mons_near(monster))
+ {
+ if (handle_special_ability(monster, beem))
+ continue;
- if (monster->target_y + mmov_y < 0
- || monster->target_y + mmov_y >= GYM)
- {
- mmov_y = 0;
- }
+ if (handle_potion(monster, beem))
+ continue;
- if (mgrd[monster->x + mmov_x][monster->y + mmov_y] != NON_MONSTER
- && (mmov_x != 0 || mmov_y != 0))
- {
- mmov_x = 0;
- mmov_y = 0;
+ if (handle_scroll(monster))
+ continue;
- if (monsters_fight(i, mgrd[monster->x + mmov_x][monster->y + mmov_y]))
- {
- brkk = true;
- }
- }
+ // shapeshifters don't get spells
+ if (!mons_has_ench( monster, ENCH_GLOWING_SHAPESHIFTER,
+ ENCH_SHAPESHIFTER )
+ || !mons_class_flag( monster->type, M_ACTUAL_SPELLS ))
+ {
+ if (handle_spell(monster, beem))
+ continue;
}
- if (brkk)
+ if (handle_wand(monster, beem))
continue;
- handle_nearby_ability( monster );
+ if (handle_reaching(monster))
+ continue;
+ }
- beem.target_x = monster->target_x;
- beem.target_y = monster->target_y;
+ if (handle_throw(monster, beem))
+ continue;
+ }
- if (monster->behaviour != BEH_SLEEP
- && monster->behaviour != BEH_WANDER)
+ // see if we move into (and fight) an unfriendly monster
+ int targmon = mgrd[monster->x + mmov_x][monster->y + mmov_y];
+ if (targmon != NON_MONSTER
+ && targmon != i
+ && !mons_aligned(i, targmon))
+ {
+ // figure out if they fight
+ if (monsters_fight(i, targmon))
+ {
+ if (testbits(monster->flags, MF_BATTY))
{
- // prevents unfriendlies from nuking you from offscreen.
- // How nice!
- if (mons_friendly(monster) || mons_near(monster))
- {
- if (handle_special_ability(monster, beem))
- continue;
-
- if (handle_potion(monster, beem))
- continue;
-
- if (handle_scroll(monster))
- continue;
+ monster->behaviour = BEH_WANDER;
+ monster->target_x = 10 + random2(GXM - 10);
+ monster->target_y = 10 + random2(GYM - 10);
+ // monster->speed_increment -= monster->speed;
+ }
- // shapeshifters don't get spells
- if (!mons_has_ench( monster, ENCH_GLOWING_SHAPESHIFTER,
- ENCH_SHAPESHIFTER )
- || !mons_class_flag( monster->type, M_ACTUAL_SPELLS ))
- {
- if (handle_spell(monster, beem))
- continue;
- }
+ mmov_x = 0;
+ mmov_y = 0;
+ brkk = true;
+ }
+ }
- if (handle_wand(monster, beem))
- continue;
+ if (brkk)
+ continue;
- if (handle_reaching(monster))
- continue;
- }
+ if (monster->x + mmov_x == you.x_pos
+ && monster->y + mmov_y == you.y_pos)
+ {
+ bool isFriendly = mons_friendly(monster);
+ bool attacked = false;
- if (handle_throw(monster, beem))
- continue;
- }
+ if (!isFriendly)
+ {
+ monster_attack(i);
+ attacked = true;
- // see if we move into (and fight) an unfriendly monster
- int targmon = mgrd[monster->x + mmov_x][monster->y + mmov_y];
- if (targmon != NON_MONSTER
- && targmon != i
- && !mons_aligned(i, targmon))
+ if (testbits(monster->flags, MF_BATTY))
{
- // figure out if they fight
- if (monsters_fight(i, targmon))
- {
- if (testbits(monster->flags, MF_BATTY))
- {
- monster->behaviour = BEH_WANDER;
- monster->target_x = 10 + random2(GXM - 10);
- monster->target_y = 10 + random2(GYM - 10);
- // monster->speed_increment -= monster->speed;
- }
-
- mmov_x = 0;
- mmov_y = 0;
- brkk = true;
- }
+ monster->behaviour = BEH_WANDER;
+ monster->target_x = 10 + random2(GXM - 10);
+ monster->target_y = 10 + random2(GYM - 10);
}
+ }
- if (brkk)
- continue;
+ if ((monster->type == MONS_GIANT_SPORE
+ || monster->type == MONS_BALL_LIGHTNING)
+ && monster->hit_points < 1)
+ {
- if (monster->x + mmov_x == you.x_pos
- && monster->y + mmov_y == you.y_pos)
- {
- bool isFriendly = mons_friendly(monster);
- bool attacked = false;
+ // detach monster from the grid first, so it
+ // doesn't get hit by its own explosion (GDL)
+ mgrd[monster->x][monster->y] = NON_MONSTER;
- if (!isFriendly)
- {
- monster_attack(i);
- attacked = true;
+ spore_goes_pop(monster);
+ monster_cleanup(monster);
+ continue;
+ }
- if (testbits(monster->flags, MF_BATTY))
- {
- monster->behaviour = BEH_WANDER;
- monster->target_x = 10 + random2(GXM - 10);
- monster->target_y = 10 + random2(GYM - 10);
- }
- }
+ if (attacked)
+ {
+ mmov_x = 0;
+ mmov_y = 0;
+ continue; //break;
+ }
+ }
- if ((monster->type == MONS_GIANT_SPORE
- || monster->type == MONS_BALL_LIGHTNING)
- && monster->hit_points < 1)
- {
+ if (invalid_monster(monster) || mons_is_stationary(monster))
+ continue;
- // detach monster from the grid first, so it
- // doesn't get hit by its own explosion (GDL)
- mgrd[monster->x][monster->y] = NON_MONSTER;
+ monster_move(monster);
- spore_goes_pop(monster);
- monster_cleanup(monster);
- continue;
- }
+ // reevaluate behaviour, since the monster's
+ // surroundings have changed (it may have moved,
+ // or died for that matter. Don't bother for
+ // dead monsters. :)
+ if (monster->type != -1)
+ handle_behaviour(monster);
- if (attacked)
- {
- mmov_x = 0;
- mmov_y = 0;
- continue; //break;
- }
- }
+ } // end while
- if (monster->type == -1 || monster->type == MONS_OKLOB_PLANT
- || monster->type == MONS_CURSE_SKULL
- || (monster->type >= MONS_CURSE_TOE
- && monster->type <= MONS_POTION_MIMIC))
- {
- continue;
- }
+ if (monster->type != -1 && monster->hit_points < 1)
+ {
+ if (monster->type == MONS_GIANT_SPORE
+ || monster->type == MONS_BALL_LIGHTNING)
+ {
+ // detach monster from the grid first, so it
+ // doesn't get hit by its own explosion (GDL)
+ mgrd[monster->x][monster->y] = NON_MONSTER;
- monster_move(monster);
+ spore_goes_pop( monster );
+ monster_cleanup( monster );
+ return;
+ }
+ else
+ {
+ monster_die( monster, KILL_MISC, 0 );
+ }
+ }
+}
- // reevaluate behaviour, since the monster's
- // surroundings have changed (it may have moved,
- // or died for that matter. Don't bother for
- // dead monsters. :)
- if (monster->type != -1)
- handle_behaviour(monster);
+//---------------------------------------------------------------
+//
+// handle_monsters
+//
+// This is the routine that controls monster AI.
+//
+//---------------------------------------------------------------
+void handle_monsters(void)
+{
+ // Keep track of monsters that have already moved and don't allow
+ // them to move again.
+ memset(immobile_monster, 0, sizeof immobile_monster);
- } // end while
+ for (int i = 0; i < MAX_MONSTERS; i++)
+ {
+ struct monsters *monster = &menv[i];
- if (monster->type != -1 && monster->hit_points < 1)
- {
- if (monster->type == MONS_GIANT_SPORE
- || monster->type == MONS_BALL_LIGHTNING)
- {
- // detach monster from the grid first, so it
- // doesn't get hit by its own explosion (GDL)
- mgrd[monster->x][monster->y] = NON_MONSTER;
+ if (monster->type == -1 || immobile_monster[i])
+ continue;
- spore_goes_pop( monster );
- monster_cleanup( monster );
- continue;
- }
- else
- {
- monster_die( monster, KILL_MISC, 0 );
- }
- }
- } // end of if (mons_class != -1)
+ const int mx = monster->x,
+ my = monster->y;
+ handle_monster_move(i, monster);
+
+ if (!invalid_monster(monster)
+ && (monster->x != mx || monster->y != my))
+ immobile_monster[i] = true;
} // end of for loop
// Clear any summoning flags so that lower indiced
// monsters get their actions in the next round.
- for (i = 0; i < MAX_MONSTERS; i++)
+ for (int i = 0; i < MAX_MONSTERS; i++)
{
menv[i].flags &= ~MF_JUST_SUMMONED;
}
@@ -4102,6 +4113,134 @@ static bool handle_pickup(struct monsters *monster)
return (true);
} // end handle_pickup()
+static void jelly_grows(monsters *monster)
+{
+ if (!silenced(you.x_pos, you.y_pos)
+ && !silenced(monster->x, monster->y))
+ {
+ strcpy(info, "You hear a");
+ if (!mons_near(monster))
+ strcat(info, " distant");
+ strcat(info, " slurping noise.");
+ mpr(info, MSGCH_SOUND);
+ }
+
+ monster->hit_points += 5;
+
+ // note here, that this makes jellies "grow" {dlb}:
+ if (monster->hit_points > monster->max_hit_points)
+ monster->max_hit_points = monster->hit_points;
+
+ if (mons_class_flag( monster->type, M_SPLITS ))
+ {
+ // and here is where the jelly might divide {dlb}
+ const int reqd = (monster->hit_dice < 6) ? 50
+ : monster->hit_dice * 8;
+
+ if (monster->hit_points >= reqd)
+ jelly_divide(monster);
+ }
+}
+
+static bool mons_can_displace(const monsters *mpusher, const monsters *mpushee)
+{
+ if (invalid_monster(mpusher) || invalid_monster(mpushee))
+ return (false);
+
+ const int ipushee = monster_index(mpushee);
+ if (ipushee < 0 || ipushee >= MAX_MONSTERS)
+ return (false);
+
+ if (immobile_monster[ipushee])
+ return (false);
+
+ // Confused monsters can't be pushed past, sleeping monsters
+ // can't push. Note that sleeping monsters can't be pushed
+ // past, either, but they may be woken up by a crowd trying to
+ // elbow past them, and the wake-up check happens downstream.
+ if (mons_is_confused(mpusher) || mons_is_confused(mpushee)
+ || mons_is_sleeping(mpusher))
+ return (false);
+
+ // Batty monsters are unpushable
+ if (mons_is_batty(mpusher) || mons_is_batty(mpushee))
+ return (false);
+
+ if (!monster_can_swap(mpusher))
+ return (false);
+
+ if (!monster_senior(mpusher, mpushee))
+ return (false);
+
+ return (true);
+}
+
+static bool monster_swaps_places( monsters *mon, int mx, int my )
+{
+ if (!mx && !my)
+ return (false);
+
+ int targmon = mgrd[mon->x + mx][mon->y + my];
+ if (targmon == MHITNOT || targmon == MHITYOU)
+ return (false);
+
+ monsters *m2 = &menv[targmon];
+ if (!mons_can_displace(mon, m2))
+ return (false);
+
+ if (mons_is_sleeping(m2))
+ {
+ if (one_chance_in(2))
+ {
+#ifdef DEBUG_DIAGNOSTICS
+ char mname[ITEMNAME_SIZE];
+ moname(m2->type, true, DESC_PLAIN, mname);
+ mprf(MSGCH_DIAGNOSTICS,
+ "Alerting monster %s at (%d,%d)", mname, m2->x, m2->y);
+#endif
+ behaviour_event( m2, ME_ALERT, MHITNOT );
+ }
+ return (false);
+ }
+
+ // Check that both monsters will be happy at their proposed new locations.
+ const int cx = mon->x, cy = mon->y,
+ nx = mon->x + mx, ny = mon->y + my;
+ if (!habitat_okay(mon, grd[nx][ny])
+ || !habitat_okay(m2, grd[cx][cy]))
+ return (false);
+
+ // Okay, do the swap!
+#ifdef DEBUG_DIAGNOSTICS
+ char mname[ITEMNAME_SIZE];
+ moname(mon->type, true, DESC_PLAIN, mname);
+ mprf(MSGCH_DIAGNOSTICS,
+ "Swap: %s (%d,%d)->(%d,%d) (%d;%d)",
+ mname, mon->x, mon->y, nx, ny, mon->speed_increment, mon->speed);
+#endif
+ mon->x = nx;
+ mon->y = ny;
+ mgrd[nx][ny] = monster_index(mon);
+
+#ifdef DEBUG_DIAGNOSTICS
+ moname(m2->type, true, DESC_PLAIN, mname);
+ mprf(MSGCH_DIAGNOSTICS,
+ "Swap: %s (%d,%d)->(%d,%d) (%d;%d)",
+ mname, m2->x, m2->y, cx, cy, mon->speed_increment, mon->speed);
+#endif
+ m2->x = cx;
+ m2->y = cy;
+ const int m2i = monster_index(m2);
+ ASSERT(m2i >= 0 && m2i < MAX_MONSTERS);
+ mgrd[cx][cy] = m2i;
+ immobile_monster[m2i] = true;
+
+ mons_trap(mon);
+ mons_trap(m2);
+
+ return (false);
+}
+
static void monster_move(struct monsters *monster)
{
FixedArray < bool, 3, 3 > good_move;
@@ -4230,7 +4369,12 @@ static void monster_move(struct monsters *monster)
// are aligned differently
if (mgrd[targ_x][targ_y] != NON_MONSTER)
{
- if (mons_aligned(monster_index(monster), mgrd[targ_x][targ_y]))
+ const int thismonster = monster_index(monster),
+ targmonster = mgrd[targ_x][targ_y];
+ if (mons_aligned(thismonster, targmonster)
+ && targmonster != MHITNOT
+ && targmonster != MHITYOU
+ && !mons_can_displace(monster, &menv[targmonster]))
{
good_move[count_x][count_y] = false;
continue;
@@ -4357,31 +4501,7 @@ static void monster_move(struct monsters *monster)
{
grd[monster->x + mmov_x][monster->y + mmov_y] = DNGN_FLOOR;
- if (!silenced(you.x_pos, you.y_pos)
- && !silenced(monster->x, monster->y))
- {
- strcpy(info, "You hear a");
- if (!mons_near(monster))
- strcat(info, " distant");
- strcat(info, " slurping noise.");
- mpr(info, MSGCH_SOUND);
- }
-
- monster->hit_points += 5;
-
- // note here, that this makes jellies "grow" {dlb}:
- if (monster->hit_points > monster->max_hit_points)
- monster->max_hit_points = monster->hit_points;
-
- if (mons_class_flag( monster->type, M_SPLITS ))
- {
- // and here is where the jelly might divide {dlb}
- const int reqd = (monster->hit_dice < 6) ? 50
- : monster->hit_dice * 8;
-
- if (monster->hit_points >= reqd)
- jelly_divide(monster);
- }
+ jelly_grows(monster);
} // done door-eating jellies
@@ -4567,7 +4687,12 @@ forget_it:
int targmon = mgrd[monster->x + mmov_x][monster->y + mmov_y];
if (targmon != NON_MONSTER)
{
- monsters_fight(monster_index(monster), targmon);
+ if (mons_aligned(monster_index(monster), targmon))
+ monster_swaps_places(monster, mmov_x, mmov_y);
+ else
+ monsters_fight(monster_index(monster), targmon);
+
+ // If the monster swapped places, the work's already done.
mmov_x = 0;
mmov_y = 0;
}
@@ -4596,9 +4721,7 @@ forget_it:
mgrd[monster->x][monster->y] = monster_index(monster);
// monsters stepping on traps:
- if (grd[monster->x][monster->y] >= DNGN_TRAP_MECHANICAL
- && grd[monster->x][monster->y] <= DNGN_UNDISCOVERED_TRAP
- && (mmov_x != 0 || mmov_y != 0))
+ if (mmov_x != 0 || mmov_y != 0)
{
mons_trap(monster);
}
@@ -4935,7 +5058,7 @@ bool message_current_target(void)
} // end message_current_target()
// aaah, the simple joys of pointer arithmetic! {dlb}:
-unsigned int monster_index(struct monsters *monster)
+unsigned int monster_index(const monsters *monster)
{
return (monster - menv.buffer());
} // end monster_index()
diff --git a/crawl-ref/source/monstuff.h b/crawl-ref/source/monstuff.h
index f6202f23ae..296ee6b14e 100644
--- a/crawl-ref/source/monstuff.h
+++ b/crawl-ref/source/monstuff.h
@@ -131,7 +131,7 @@ bool message_current_target(void);
/* ***********************************************************************
* called from: xxx
* *********************************************************************** */
-unsigned int monster_index(struct monsters *monster);
+unsigned int monster_index(const monsters *monster);
// last updated 08jun2000 {dlb}
diff --git a/crawl-ref/source/mstuff2.cc b/crawl-ref/source/mstuff2.cc
index 38d0d8c885..d2e87ede33 100644
--- a/crawl-ref/source/mstuff2.cc
+++ b/crawl-ref/source/mstuff2.cc
@@ -49,6 +49,9 @@ static unsigned char monster_abjuration(int pow, bool test);
// to be some sort of trap prior to function call: {dlb}
void mons_trap(struct monsters *monster)
{
+ if (!is_trap_square(monster->x, monster->y))
+ return;
+
int temp_rand = 0; // probability determination {dlb}
// single calculation permissible {dlb}
diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc
index 35cff2da38..e572fe4a6e 100644
--- a/crawl-ref/source/spl-cast.cc
+++ b/crawl-ref/source/spl-cast.cc
@@ -402,7 +402,9 @@ int spell_fail(int spell)
&& (spell_typematch(spell, SPTYP_CONJURATION)
|| spell_typematch(spell, SPTYP_SUMMONING)))
{
- chance2 /= 2;
+ // [dshaligram] Fail rate multiplier used to be .5, scaled
+ // back to 2/3.
+ chance2 = chance2 * 2 / 3;
}
if (you.duration[DUR_TRANSFORMATION] > 0)
diff --git a/crawl-ref/source/stuff.cc b/crawl-ref/source/stuff.cc
index 72e919f8f7..7826d6b269 100644
--- a/crawl-ref/source/stuff.cc
+++ b/crawl-ref/source/stuff.cc
@@ -14,7 +14,9 @@
*/
#include "AppHdr.h"
+#include "direct.h"
#include "stuff.h"
+#include "view.h"
#include <stdlib.h>
#include <stdio.h>
@@ -780,3 +782,48 @@ int near_stairs(int px, int py, int max_dist, unsigned char &stair_gfx)
return false;
}
+
+bool is_trap_square(int x, int y)
+{
+ return (grd[x][y] >= DNGN_TRAP_MECHANICAL
+ && grd[x][y] <= DNGN_UNDISCOVERED_TRAP);
+}
+
+// Does the equivalent of KILL_RESET on all monsters in LOS. Should only be
+// applied to new games.
+void zap_los_monsters()
+{
+ losight(env.show, grd, you.x_pos, you.y_pos);
+
+ for (int y = LOS_SY; y <= LOS_EY; ++y)
+ {
+ for (int x = LOS_SX; x <= LOS_EX; ++x)
+ {
+ if (!in_vlos(x, y))
+ continue;
+
+ const int gx = view2gridX(x),
+ gy = view2gridY(y);
+
+ if (!in_map_grid(gx, gy))
+ continue;
+
+ if (gx == you.x_pos && gy == you.y_pos)
+ continue;
+
+ int imon = mgrd[gx][gy];
+ if (imon == NON_MONSTER || imon == MHITYOU)
+ continue;
+
+ // If we ever allow starting with a friendly monster,
+ // we'll have to check here.
+ monsters *mon = &menv[imon];
+#ifdef DEBUG_DIAGNOSTICS
+ char mname[ITEMNAME_SIZE];
+ moname(mon->type, true, DESC_PLAIN, mname);
+ mprf(MSGCH_DIAGNOSTICS, "Dismissing %s", mname);
+#endif
+ monster_die(mon, KILL_DISMISSED, 0);
+ }
+ }
+}
diff --git a/crawl-ref/source/stuff.h b/crawl-ref/source/stuff.h
index b27ef2e10c..25691fd56f 100644
--- a/crawl-ref/source/stuff.h
+++ b/crawl-ref/source/stuff.h
@@ -76,5 +76,9 @@ inline bool testbits(unsigned int flags, unsigned int test)
return ((flags & test) == test);
}
+bool is_trap_square(int x, int y);
+
+void zap_los_monsters();
+
#endif
diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc
index c4b4a23e0f..6bb8d1bdef 100644
--- a/crawl-ref/source/view.cc
+++ b/crawl-ref/source/view.cc
@@ -1272,18 +1272,14 @@ void monster_grid(bool do_updates)
|= COLFLAG_FRIENDLY_MONSTER;
}
else if (Options.stab_brand != CHATTR_NORMAL
- && !mons_is_mimic(monster->type)
- && monster->type != MONS_OKLOB_PLANT
- && mons_is_stabbable(monster))
+ && mons_looks_stabbable(monster))
{
env.show_col[monster->x - you.x_pos + 9]
[monster->y - you.y_pos + 9]
|= COLFLAG_WILLSTAB;
}
else if (Options.may_stab_brand != CHATTR_NORMAL
- && !mons_is_mimic(monster->type)
- && monster->type != MONS_OKLOB_PLANT
- && mons_maybe_stabbable(monster))
+ && mons_looks_distracted(monster))
{
env.show_col[monster->x - you.x_pos + 9]
[monster->y - you.y_pos + 9]
@@ -1305,9 +1301,7 @@ void monster_grid(bool do_updates)
}
if (Options.stab_brand != CHATTR_NORMAL
- && !mons_is_mimic(monster->type)
- && monster->type != MONS_OKLOB_PLANT
- && mons_is_stabbable(monster))
+ && mons_looks_stabbable(monster))
{
unsigned short &colour =
env.show_col[monster->x - you.x_pos + 9]
@@ -1315,9 +1309,7 @@ void monster_grid(bool do_updates)
colour = dos_brand(colour, Options.stab_brand);
}
else if (Options.may_stab_brand != CHATTR_NORMAL
- && !mons_is_mimic(monster->type)
- && monster->type != MONS_OKLOB_PLANT
- && mons_maybe_stabbable(monster))
+ && mons_looks_stabbable(monster))
{
unsigned short &colour =
env.show_col[monster->x - you.x_pos + 9]