diff options
Diffstat (limited to 'crawl-ref/source/view.cc')
-rw-r--r-- | crawl-ref/source/view.cc | 246 |
1 files changed, 204 insertions, 42 deletions
diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc index 2cf125566c..121d9ca833 100644 --- a/crawl-ref/source/view.cc +++ b/crawl-ref/source/view.cc @@ -36,6 +36,7 @@ #include "externs.h" +#include "branch.h" #include "command.h" #include "cio.h" #include "cloud.h" @@ -43,6 +44,7 @@ #include "database.h" #include "debug.h" #include "delay.h" +#include "dgnevent.h" #include "direct.h" #include "dungeon.h" #include "format.h" @@ -65,6 +67,7 @@ #include "terrain.h" #include "travel.h" #include "tutorial.h" +#include "xom.h" // These are hidden from the rest of the world... use the functions // below to get information about the map grid. @@ -218,6 +221,8 @@ bool is_terrain_changed( int x, int y ) void set_terrain_changed( int x, int y ) { env.map[x][y].flags |= MAP_CHANGED_FLAG; + + dungeon_events.fire_position_event(DET_FEAT_CHANGE, coord_def(x, y)); } void set_terrain_mapped( int x, int y ) @@ -621,12 +626,18 @@ int get_mons_colour(const monsters *mons) { col |= COLFLAG_MAYSTAB; } - else if (Options.heap_brand != CHATTR_NORMAL - && mons_is_stationary(mons) - && in_bounds(mons->x, mons->y) - && igrd[mons->x][mons->y] != NON_ITEM) + else if (mons_is_stationary(mons)) { - col |= COLFLAG_ITEM_HEAP; + if (Options.stair_item_brand != CHATTR_NORMAL + && grid_stair_direction(grd(mons->pos())) != CMD_NO_CMD) + { + col |= COLFLAG_STAIR_ITEM; + } + else if (Options.heap_brand != CHATTR_NORMAL + && igrd(mons->pos()) != NON_ITEM) + { + col |= COLFLAG_ITEM_HEAP; + } } // Backlit monsters are fuzzy and override brands. @@ -682,7 +693,7 @@ void beogh_follower_convert(monsters *monster, bool orc_hit) return; } beogh_convert_orc(monster, orc_hit); - stop_running(); + stop_running(); } } else if (is_orc @@ -709,6 +720,28 @@ void beogh_follower_convert(monsters *monster, bool orc_hit) } } +static void handle_seen_interrupt(monsters* monster) +{ + activity_interrupt_data aid(monster); + if (monster->seen_context != "") + aid.context = monster->seen_context; + else if (testbits(monster->flags, MF_WAS_IN_VIEW)) + aid.context = "already seen"; + else + aid.context = "newly seen"; + + if (!mons_is_safe( static_cast<const monsters*>(monster) ) + && !mons_class_flag( monster->type, M_NO_EXP_GAIN ) + && !mons_is_mimic( monster->type )) + { + interrupt_activity( AI_SEE_MONSTER, aid ); + } + seen_monster( monster ); + + // Monster was viewed this turn + monster->flags |= MF_WAS_IN_VIEW; +} + void handle_monster_shouts(monsters* monster, bool force) { if (!force @@ -876,6 +909,19 @@ void handle_monster_shouts(monsters* monster, bool force) else if (param == "SOUND") channel = MSGCH_SOUND; + // Monster must come up from being submerged if it wants to + // shout. + if (mons_is_submerged(monster)) + { + monster->del_ench(ENCH_SUBMERGED); + if (you.can_see(monster)) + { + monster->seen_context = "bursts forth shouting"; + // Give interrupt message before shout message. + handle_seen_interrupt(monster); + } + } + msg::streams(channel) << msg << std::endl; } @@ -956,6 +1002,8 @@ void monster_grid(bool do_updates) void fire_monster_alerts() { + int num_hostile = 0; + for (int s = 0; s < MAX_MONSTERS; s++) { monsters *monster = &menv[s]; @@ -966,22 +1014,10 @@ void fire_monster_alerts() || mons_was_seen_this_turn(monster)) && !mons_is_submerged( monster )) { - activity_interrupt_data aid(monster); - if (testbits(monster->flags, MF_WAS_IN_VIEW)) - aid.context = "already seen"; - else - aid.context = "newly seen"; - - if (!mons_is_safe( static_cast<const monsters*>(monster) ) - && !mons_class_flag( monster->type, M_NO_EXP_GAIN ) - && !mons_is_mimic( monster->type )) - { - interrupt_activity( AI_SEE_MONSTER, aid ); - } - seen_monster( monster ); + handle_seen_interrupt(monster); - // Monster was viewed this turn - monster->flags |= MF_WAS_IN_VIEW; + if (mons_attitude(monster) == ATT_HOSTILE) + num_hostile++; } else { @@ -994,6 +1030,22 @@ void fire_monster_alerts() // Monster was not viewed this turn monster->flags &= ~MF_WAS_IN_VIEW; } + monster->seen_context = ""; + } + + // Xom thinks it's hilarious the way the player picks up an ever + // growing entourage of monsters while running through the Abyss. + // To approximate this, if the number of hostile monsters in view + // is greater than it ever was for this particular trip to the + // Abyss, Xom is stimulated in proprotion to the number of + // hostile monsters. Thus if the entourage doesn't grow, then + // Xom becomes bored. + if (you.level_type == LEVEL_ABYSS + && you.attribute[ATTR_ABYSS_ENTOURAGE] < num_hostile) + { + you.attribute[ATTR_ABYSS_ENTOURAGE] = num_hostile; + + xom_is_stimulated(16 * num_hostile); } monsters_seen_this_turn.clear(); @@ -1267,13 +1319,25 @@ bool noisy( int loudness, int nois_x, int nois_y, const char *msg ) const int dist = loudness * loudness; + const int player_distance = + distance( you.x_pos, you.y_pos, nois_x, nois_y ); // message the player - if (distance( you.x_pos, you.y_pos, nois_x, nois_y ) <= dist - && player_can_hear( nois_x, nois_y )) + if (player_distance <= dist && player_can_hear( nois_x, nois_y )) { if (msg) mpr( msg, MSGCH_SOUND ); + you.check_awaken(dist - player_distance); + + if (loudness >= 20 && you.duration[DUR_BEHELD]) + { + mprf("For a moment, you cannot hear the mermaid%s!", + you.beheld_by.size() == 1? "" : "s"); + mpr("You break out of your daze!", MSGCH_DURATION); + you.duration[DUR_BEHELD] = 0; + you.beheld_by.clear(); + } + ret = true; } @@ -1962,7 +2026,7 @@ static bool superior_ray(int shortest, int imbalance, bool find_ray( int sourcex, int sourcey, int targetx, int targety, bool allow_fallback, ray_def& ray, int cycle_dir, - bool find_shortest ) + bool find_shortest, bool ignore_solid ) { int cellray, inray; const int signx = ((targetx - sourcex >= 0) ? 1 : -1); @@ -2004,7 +2068,7 @@ bool find_ray( int sourcex, int sourcey, int targetx, int targety, { const int xi = signx * ray_coord_x[inray + cur_offset]; const int yi = signy * ray_coord_y[inray + cur_offset]; - if (inray < cellray + if (inray < cellray && !ignore_solid && grid_is_solid(grd[sourcex + xi][sourcey + yi])) { blocked = true; @@ -2122,6 +2186,48 @@ bool find_ray( int sourcex, int sourcey, int targetx, int targety, return false; } +// Count the number of matching features between two points along +// a beam-like path; the path will pass through solid features. +// By default, it exludes enpoints from the count. +int num_feats_between(int sourcex, int sourcey, int targetx, int targety, + dungeon_feature_type min_feat, + dungeon_feature_type max_feat, + bool exclude_endpoints) +{ + ray_def ray; + int count = 0; + int max_dist = grid_distance(sourcex, sourcey, targetx, targety); + + ray.fullray_idx = -1; // to quiet valgrind + find_ray( sourcex, sourcey, targetx, targety, true, ray, 0, true, true ); + + if (exclude_endpoints && ray.x() == sourcex && ray.y() == sourcey) + { + ray.advance(true); + max_dist--; + } + + int dist = 0; + while (dist++ <= max_dist) + { + dungeon_feature_type feat = grd[ray.x()][ray.y()]; + + if (feat >= min_feat && feat <= max_feat) + count++; + + if (ray.x() == targetx && ray.y() == targety) + { + if (exclude_endpoints && feat >= min_feat && feat <= max_feat) + count--; + + break; + } + ray.advance(true); + } + + return count; +} + // The rule behind LOS is: // Two cells can see each other if there is any line from some point // of the first to some point of the second ("generous" LOS.) @@ -2160,7 +2266,8 @@ bool find_ray( int sourcex, int sourcey, int targetx, int targety, // Smoke will now only block LOS after two cells of smoke. This is // done by updating with a second array. void losight(FixedArray < unsigned int, 19, 19 > &sh, - FixedArray < dungeon_feature_type, 80, 70 > &gr, int x_p, int y_p) + FixedArray < dungeon_feature_type, 80, 70 > &gr, int x_p, int y_p, + bool clear_walls_block) { raycast(); // go quadrant by quadrant @@ -2197,7 +2304,8 @@ void losight(FixedArray < unsigned int, 19, 19 > &sh, continue; // if this cell is opaque... - if ( grid_is_opaque(gr[realx][realy]) ) + if ( grid_is_opaque(gr[realx][realy]) + || (clear_walls_block && grid_is_wall(gr[realx][realy]))) { // then block the appropriate rays for ( unsigned int i = 0; i < num_words; ++i ) @@ -2404,7 +2512,7 @@ bool is_feature(int feature, int x, int y) { case DNGN_TRAP_MECHANICAL: case DNGN_TRAP_MAGICAL: - case DNGN_TRAP_III: + case DNGN_TRAP_NATURAL: return true; default: return false; @@ -2572,13 +2680,13 @@ static void draw_level_map(int start_x, int start_y, bool travel_mode) for (int screen_y = 0; screen_y < num_lines; screen_y++) { - for (int screen_x = 0; screen_x < num_cols - 1; screen_x++) + for (int screen_x = 0; screen_x < num_cols; screen_x++) { screen_buffer_t colour = DARKGREY; coord_def c(start_x + screen_x, start_y + screen_y); - if (!in_bounds(c)) + if (!map_bounds(c)) { buffer2[bufcount2 + 1] = DARKGREY; buffer2[bufcount2] = 0; @@ -2618,7 +2726,7 @@ static void draw_level_map(int start_x, int start_y, bool travel_mode) bufcount2 += 2; } } - puttext(1, top, num_cols - 1, top + num_lines - 1, buffer2); + puttext(1, top, num_cols, top + num_lines - 1, buffer2); } static void reset_travel_colours(std::vector<coord_def> &features) @@ -2634,7 +2742,7 @@ static void reset_travel_colours(std::vector<coord_def> &features) // the player from getting "artificial" location clues by using the // map to see how close to the end they are. They'll need to explore // to get that. This function is still a mess, though. -- bwr -void show_map( FixedVector<int, 2> &spec_place, bool travel_mode ) +void show_map( coord_def &spec_place, bool travel_mode ) { cursor_control ccon(!Options.use_fake_cursor); int i, j; @@ -2743,6 +2851,9 @@ void show_map( FixedVector<int, 2> &spec_place, bool travel_mode ) break; case CONTROL('F'): + forget_map(100, true); + break; + case CONTROL('W'): travel_cache.add_waypoint(start_x + curs_x - 1, start_y + curs_y - 1); @@ -2939,8 +3050,7 @@ void show_map( FixedVector<int, 2> &spec_place, bool travel_mode ) if (cme.left_clicked() && in_bounds(grdp)) { - spec_place[0] = grdp.x; - spec_place[1] = grdp.y; + spec_place = grdp; map_alive = false; } else if (cme.scroll_up()) @@ -2974,12 +3084,23 @@ void show_map( FixedVector<int, 2> &spec_place, bool travel_mode ) } else { - spec_place[0] = x; - spec_place[1] = y; + spec_place = coord_def(x, y); map_alive = false; break; } } + +#ifdef WIZARD + case 'T': + { + if (!you.wizard) + break; + you.moveto(start_x + curs_x - 1, start_y + curs_y - 1); + map_alive = false; + break; + } +#endif + default: move_x = 0; move_y = 0; @@ -3054,8 +3175,8 @@ bool magic_mapping(int map_radius, int proportion, bool suppress_msg, bool force) { if (!force && - ((you.level_type == LEVEL_ABYSS) || - (you.level_type == LEVEL_LABYRINTH && you.species != SP_MINOTAUR))) + (testbits(env.level_flags, LFLAG_NO_MAGIC_MAP) + || testbits(get_branch_flags(), BFLAG_NO_MAGIC_MAP))) { if (!suppress_msg) mpr("You feel momentarily disoriented."); @@ -3201,6 +3322,33 @@ bool see_grid( int grx, int gry ) return (false); } // end see_grid() +// answers the question: "Would a grid be within character's line of sight, +// even if all translucent/clear walls were made opaque?" +bool see_grid_no_trans( int grx, int gry ) +{ + // rare case: can player see self? (of course!) + if (grx == you.x_pos && gry == you.y_pos) + return (true); + + // check no_trans_show array + if (grid_distance( grx, gry, you.x_pos, you.y_pos ) < 9) + { + const int ex = grx - you.x_pos + 9; + const int ey = gry - you.y_pos + 9; + + if (env.no_trans_show[ex][ey]) + return (true); + } + + return (false); +} + +// Is the grid visible, but a translucent wall is in the way? +bool trans_wall_blocking( int grx, int gry ) +{ + return see_grid(grx, gry) && !see_grid_no_trans(grx, gry); +} + static const unsigned table[ NUM_CSET ][ NUM_DCHAR_TYPES ] = { // CSET_ASCII @@ -3325,6 +3473,15 @@ void init_feature_table( void ) Feature[i].magic_symbol = Options.char_table[ DCHAR_WALL_MAGIC ]; break; + case DNGN_CLEAR_ROCK_WALL: + case DNGN_CLEAR_STONE_WALL: + case DNGN_CLEAR_PERMAROCK_WALL: + Feature[i].dchar = DCHAR_WALL; + Feature[i].magic_symbol = Options.char_table[ DCHAR_WALL_MAGIC ]; + Feature[i].colour = LIGHTCYAN; + break; + + case DNGN_OPEN_DOOR: Feature[i].dchar = DCHAR_DOOR_OPEN; Feature[i].colour = LIGHTGREY; @@ -3424,10 +3581,10 @@ void init_feature_table( void ) Feature[i].map_colour = MAGENTA; break; - case DNGN_TRAP_III: - Feature[i].colour = LIGHTGREY; + case DNGN_TRAP_NATURAL: + Feature[i].colour = BROWN; Feature[i].dchar = DCHAR_TRAP; - Feature[i].map_colour = LIGHTGREY; + Feature[i].map_colour = BROWN; break; case DNGN_UNDISCOVERED_TRAP: @@ -4080,6 +4237,10 @@ void viewwindow(bool draw_it, bool do_updates) losight( env.show, grd, you.x_pos, you.y_pos ); // must be done first + // What would be visible, if all of the translucent walls were + // made opaque. + losight( env.no_trans_show, grd, you.x_pos, you.y_pos, true ); + env.show_col.init(LIGHTGREY); Show_Backup.init(0); @@ -4092,7 +4253,8 @@ void viewwindow(bool draw_it, bool do_updates) cursor_control cs(false); const bool map = player_in_mappable_area(); - const bool draw = !you.running || Options.travel_delay > -1; + const bool draw = + (!you.running || Options.travel_delay > -1) && !you.asleep(); int bufcount = 0; int flash_colour = you.flash_colour; |