diff options
Diffstat (limited to 'crawl-ref/source/monplace.cc')
-rw-r--r-- | crawl-ref/source/monplace.cc | 153 |
1 files changed, 97 insertions, 56 deletions
diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc index fb5dec3f53..0df2f1f352 100644 --- a/crawl-ref/source/monplace.cc +++ b/crawl-ref/source/monplace.cc @@ -389,15 +389,19 @@ static monster_type resolve_monster_type(monster_type mon_type, || drac_colour_incompatible(mon_type, base_type))); } else if (mon_type == RANDOM_BASE_DRACONIAN) + { mon_type = static_cast<monster_type>( random_range(MONS_BLACK_DRACONIAN, MONS_PALE_DRACONIAN)); + } else if (mon_type == RANDOM_NONBASE_DRACONIAN) + { mon_type = static_cast<monster_type>( random_range(MONS_DRACONIAN_CALLER, MONS_DRACONIAN_SCORCHER)); + } - // (2) take care of non-drac random monsters + // (2) Take care of non-draconian random monsters. if (mon_type == RANDOM_MONSTER) { level_id place = level_id::current(); @@ -417,29 +421,30 @@ static monster_type resolve_monster_type(monster_type mon_type, if (!unforbidden( pos, mmask )) continue; - // don't generate monsters on top of teleport traps + // Don't generate monsters on top of teleport traps. int trap = trap_at_xy(pos.x, pos.y); if (trap >= 0) { if (!can_place_on_trap(mon_type, env.trap[trap].type)) - continue; + continue; } - // check whether there's a stair - // and whether it leads to another branch - pval = near_stairs(pos, 1, - *stair_type, place.branch); + // Check whether there's a stair + // and whether it leads to another branch. + pval = near_stairs(pos, 1, *stair_type, place.branch); - // no monsters spawned in the Temple + // No monsters spawned in the Temple. if (branches[place.branch].id == BRANCH_ECUMENICAL_TEMPLE) continue; - // found a position near the stairs! + // Found a position near the stairs! if (pval > 0) break; } + if (tries > 320) - { // give up and try somewhere else + { + // Give up and try somewhere else. proximity = PROX_AWAY_FROM_PLAYER; } else @@ -448,11 +453,11 @@ static monster_type resolve_monster_type(monster_type mon_type, ++*lev_mons; else if (*stair_type == DCHAR_STAIRS_UP) // higher level { - // monsters don't come from outside the dungeon + // Monsters don't come from outside the dungeon. if (*lev_mons <= 0) { proximity = PROX_AWAY_FROM_PLAYER; - // in that case lev_mons stays as it is + // In that case lev_mons stays as it is. } else --*lev_mons; @@ -464,36 +469,64 @@ static monster_type resolve_monster_type(monster_type mon_type, mon_type = MONS_DANCING_WEAPON; else { - // now pick a monster of the given branch and level + // Now pick a monster of the given branch and level. mon_type = pick_random_monster(place, *lev_mons, *lev_mons); } } return (mon_type); } +// A short function to check the results of near_stairs(). +// Returns 0 if the point is not near stairs. +// Returns 1 if the point is near unoccupied stairs. +// Returns 2 if the point is near player-occupied stairs. +static int _is_near_stairs(coord_def &p) +{ + int result = 0; + for (int i = -1; i <= 1; i++) + for (int j = -1; j <= 1; j++) + { + if (!in_bounds(p)) + continue; + + const dungeon_feature_type feat = grd(p); + if (is_stair(feat)) + { + // Shouldn't matter for escape hatches. + if (grid_is_escape_hatch(feat)) + continue; + + // Should there be several stairs, don't overwrite the + // player on stairs info. + if (result < 2) + result = (p == you.pos()? 2 : 1); + } + } + + return result; +} + int place_monster(mgen_data mg) { int band_size = 0; monster_type band_monsters[BIG_BAND]; // band monster types int tries = 0; - int pval = 0; dungeon_char_type stair_type = NUM_DCHAR_TYPES; int id = -1; - // (1) early out (summoned to occupied grid) + // (1) Early out (summoned to occupied grid). if (mg.use_position() && mgrd(mg.pos) != NON_MONSTER) return (false); - mg.cls = - resolve_monster_type(mg.cls, mg.proximity, mg.base_type, - mg.pos, mg.map_mask, - &stair_type, &mg.power); + mg.cls = resolve_monster_type(mg.cls, mg.proximity, mg.base_type, + mg.pos, mg.map_mask, + &stair_type, &mg.power); if (mg.cls == MONS_PROGRAM_BUG) return (false); - // (3) decide on banding (good lord!) + // (3) Decide on banding (good lord!) band_size = 1; band_monsters[0] = mg.cls; @@ -505,11 +538,13 @@ int place_monster(mgen_data mg) band_monsters[i] = _band_member( band, mg.power ); } + // Returns 2 if the monster is placed near player-occupied stairs. + int pval = _is_near_stairs(mg.pos); if (mg.proximity == PROX_NEAR_STAIRS) { - // for some cases disallow monsters on stairs + // For some cases disallow monsters on stairs. if (mons_class_is_stationary( mg.cls ) - || (pval == 2 + || (pval == 2 // Stairs occupied by player. && (mons_speed(mg.cls) == 0 || grd(mg.pos) == DNGN_LAVA || grd(mg.pos) == DNGN_DEEP_WATER))) { @@ -517,18 +552,18 @@ int place_monster(mgen_data mg) } } - // (4) for first monster, choose location. This is pretty intensive. + // (4) For first monster, choose location. This is pretty intensive. bool proxOK; bool close_to_player; - // player shoved out of the way? + // Player shoved out of the way? bool shoved = false; if (!mg.use_position()) { tries = 0; - // try to pick px, py that is + // Try to pick px, py that is // a) not occupied // b) compatible // c) in the 'correct' proximity to the player @@ -541,7 +576,7 @@ int place_monster(mgen_data mg) if (tries++ >= 45) return (false); - // placement already decided for PROX_NEAR_STAIRS + // Placement already decided for PROX_NEAR_STAIRS. if (mg.proximity != PROX_NEAR_STAIRS) mg.pos = random_in_bounds(); @@ -558,8 +593,8 @@ int place_monster(mgen_data mg) if (!unforbidden( mg.pos, mg.map_mask )) continue; - // don't generate monsters on top of teleport traps - // (how did they get there?) + // Don't generate monsters on top of teleport traps. + // (How did they get there?) int trap = trap_at_xy(mg.pos.x, mg.pos.y); if (trap >= 0) { @@ -567,7 +602,7 @@ int place_monster(mgen_data mg) continue; } - // check proximity to player + // Check proximity to player. proxOK = true; switch (mg.proximity) @@ -602,10 +637,10 @@ int place_monster(mgen_data mg) proxOK = false; break; } - // swap the monster and the player spots, unless the + // Swap the monster and the player spots, unless the // monster was generated in lava or deep water. - if (grd(mg.pos) == DNGN_LAVA || - grd(mg.pos) == DNGN_DEEP_WATER) + if (grd(mg.pos) == DNGN_LAVA + || grd(mg.pos) == DNGN_DEEP_WATER) { proxOK = false; break; @@ -633,7 +668,7 @@ int place_monster(mgen_data mg) if (id == -1) return (id); - // message to player from stairwell/gate appearance? + // Message to player from stairwell/gate appearance? if (see_grid(mg.pos) && mg.proximity == PROX_NEAR_STAIRS) { std::string msg; @@ -663,12 +698,13 @@ int place_monster(mgen_data mg) mpr(msg.c_str()); } - // special case: must update the view for monsters created in player LOS + // Special case: must update the view for monsters created + // in player LOS. viewwindow(true, false); } - // now, forget about banding if the first placement failed, or there's too - // many monsters already, or we successfully placed by stairs + // Now, forget about banding if the first placement failed, or there are + // too many monsters already, or we successfully placed by stairs. if (id >= MAX_MONSTERS - 30 || mg.proximity == PROX_NEAR_STAIRS) return (id); @@ -677,20 +713,19 @@ int place_monster(mgen_data mg) menv[id].flags |= MF_BAND_MEMBER; mgen_data band_template = mg; - // (5) for each band monster, loop call to place_monster_aux(). + // (5) For each band monster, loop call to place_monster_aux(). for (int i = 1; i < band_size; i++) { if (band_monsters[i] == MONS_PROGRAM_BUG) break; band_template.cls = band_monsters[i]; - const int band_id = - _place_monster_aux( band_template, false ); + const int band_id = _place_monster_aux( band_template, false ); if (band_id != -1 && band_id != NON_MONSTER) menv[band_id].flags |= MF_BAND_MEMBER; } - // placement of first monster, at least, was a success. + // Placement of first monster, at least, was a success. return (id); } @@ -1760,7 +1795,7 @@ int mons_place( mgen_data mg ) if (you.char_direction == GDT_ASCENDING && mg.cls == RANDOM_MONSTER && you.level_type == LEVEL_DUNGEON && !mg.summoned()) { - mg.cls = pick_zot_exit_defender(); + mg.cls = pick_zot_exit_defender(); mg.flags |= MG_PERMIT_BANDS; } @@ -1769,7 +1804,7 @@ int mons_place( mgen_data mg ) int mid = -1; - // translate level_type + // Translate level_type. switch (mg.level_type) { case LEVEL_PANDEMONIUM: @@ -1809,7 +1844,7 @@ int mons_place( mgen_data mg ) if (!(mg.flags & MG_FORCE_BEH)) player_angers_monster(creation); - // make summoned being aware of player's presence + // Make summoned being aware of player's presence. behaviour_event(creation, ME_ALERT, MHITYOU); if (creation->type == MONS_RAKSHASA_FAKE && !one_chance_in(3)) @@ -1824,8 +1859,10 @@ int mons_place( mgen_data mg ) static dungeon_feature_type _monster_habitat_feature(int mtype) { - return ((mtype == RANDOM_MONSTER) ? DNGN_FLOOR - : habitat2grid( mons_habitat_by_type(mtype) )); + if (mtype == RANDOM_MONSTER) + return DNGN_FLOOR; + + return habitat2grid( mons_habitat_by_type(mtype) ); } class newmons_square_find : public travel_pathfind @@ -1913,7 +1950,7 @@ coord_def find_newmons_square(int mons_class, const coord_def &p) // Might be better if we chose a space and tried to match the monster // to it in the case of RANDOM_MONSTER, that way if the target square - // is surrounded by water of lava this function would work. -- bwr + // is surrounded by water or lava this function would work. -- bwr if (empty_surrounds( p.x, p.y, spcw, 2, true, empty )) { pos.x = empty[0]; @@ -1967,25 +2004,28 @@ bool player_angers_monster(monsters *mon, bool actual) int create_monster( mgen_data mg ) { int summd = -1; - if (!(mg.force_place() - && in_bounds(mg.pos) - && mons_class_can_pass(mg.cls, grd(mg.pos)) - && mgrd(mg.pos) == NON_MONSTER - && mg.pos != you.pos())) + int type = (mons_class_is_zombified(mg.cls) ? mg.base_type + : mg.cls); + + if (!mg.force_place() + || !in_bounds(mg.pos) + || mgrd(mg.pos) != NON_MONSTER + || mg.pos == you.pos() + || !mons_class_can_pass(type, grd(mg.pos))) { - mg.pos = find_newmons_square(mg.cls, mg.pos); + mg.pos = find_newmons_square(type, mg.pos); } if (in_bounds(mg.pos)) summd = mons_place( mg ); - // determine whether creating a monster is successful (summd != -1) {dlb}: - // then handle the outcome {dlb}: + // Determine whether creating a monster is successful (summd != -1) {dlb}: + // then handle the outcome. {dlb}: if (summd == -1 && see_grid( mg.pos )) mpr("You see a puff of smoke."); - // the return value is either -1 (failure of some sort) - // or the index of the monster placed (if I read things right) {dlb} + // The return value is either -1 (failure of some sort) + // or the index of the monster placed (if I read things right). {dlb} return (summd); } @@ -1995,6 +2035,7 @@ bool empty_surrounds(int emx, int emy, dungeon_feature_type spc_wanted, FixedVector < char, 2 > &empty) { bool success; + // Assume all player summoning originates from player x,y. bool playerSummon = (emx == you.x_pos && emy == you.y_pos); |