diff options
-rw-r--r-- | crawl-ref/source/acr.cc | 7 | ||||
-rw-r--r-- | crawl-ref/source/defines.h | 18 | ||||
-rw-r--r-- | crawl-ref/source/direct.cc | 66 | ||||
-rw-r--r-- | crawl-ref/source/direct.h | 20 | ||||
-rw-r--r-- | crawl-ref/source/enum.h | 3 | ||||
-rw-r--r-- | crawl-ref/source/mon-util.cc | 139 | ||||
-rw-r--r-- | crawl-ref/source/mon-util.h | 20 | ||||
-rw-r--r-- | crawl-ref/source/monstuff.cc | 743 | ||||
-rw-r--r-- | crawl-ref/source/monstuff.h | 2 | ||||
-rw-r--r-- | crawl-ref/source/mstuff2.cc | 3 | ||||
-rw-r--r-- | crawl-ref/source/spl-cast.cc | 4 | ||||
-rw-r--r-- | crawl-ref/source/stuff.cc | 47 | ||||
-rw-r--r-- | crawl-ref/source/stuff.h | 4 | ||||
-rw-r--r-- | crawl-ref/source/view.cc | 16 |
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] |