diff options
-rw-r--r-- | crawl-ref/source/acr.cc | 10 | ||||
-rw-r--r-- | crawl-ref/source/beam.cc | 60 | ||||
-rw-r--r-- | crawl-ref/source/fight.cc | 44 | ||||
-rw-r--r-- | crawl-ref/source/mon-data.h | 5 | ||||
-rw-r--r-- | crawl-ref/source/mon-util.cc | 2 | ||||
-rw-r--r-- | crawl-ref/source/mon-util.h | 2 | ||||
-rw-r--r-- | crawl-ref/source/monplace.cc | 13 | ||||
-rw-r--r-- | crawl-ref/source/monstuff.cc | 12 | ||||
-rw-r--r-- | crawl-ref/source/terrain.cc | 9 | ||||
-rw-r--r-- | crawl-ref/source/terrain.h | 5 |
10 files changed, 145 insertions, 17 deletions
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc index 515d82eb04..5af97eb4a9 100644 --- a/crawl-ref/source/acr.cc +++ b/crawl-ref/source/acr.cc @@ -3223,7 +3223,6 @@ static void open_door(int move_x, int move_y, bool check_confused) if (mon != NON_MONSTER && player_can_hit_monster(&menv[mon])) { - if (mons_is_caught(&menv[mon])) { @@ -3737,6 +3736,11 @@ static void move_player(int move_x, int move_y) } else // attack! { + // XXX: Moving into a normal wall does nothing and uses no + // turns or energy, but moving into a wall which contains + // an invisible monster attacks the monster, thus allowing + // the player to figure out which adjacent wall an invis + // monster is in "for free". you_attack( targ_monst, true ); you.turn_is_over = true; @@ -3772,9 +3776,9 @@ static void move_player(int move_x, int move_y) } // BCR - Easy doors single move - if (targ_grid == DNGN_CLOSED_DOOR && Options.easy_open) + if (targ_grid == DNGN_CLOSED_DOOR && Options.easy_open && !attacking) open_door(move_x, move_y, false); - else if (!targ_pass) + else if (!targ_pass && !attacking) { stop_running(); diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc index 6a497e9aba..b3879d27a4 100644 --- a/crawl-ref/source/beam.cc +++ b/crawl-ref/source/beam.cc @@ -1240,6 +1240,32 @@ static void zappy( zap_type z_type, int power, bolt &pbolt ) */ +// Affect monster in wall unless it can shield itself using the wall +// (M_WALL_SHIELDED). The wall will always shield the monster if the +// beam bounces off the wall, and a monster can't use a metal wall to +// shield itself from electricty. +static bool affect_mon_in_wall(bolt &pbolt, item_def *item, int tx, int ty) +{ + UNUSED(item); + + int mid = mgrd[tx][ty]; + + if (mid == NON_MONSTER) + return false; + + if (pbolt.is_enchant + || (!pbolt.is_explosion && !pbolt.is_big_cloud + && (grd[tx][ty] != DNGN_METAL_WALL + || !pbolt.flavour != BEAM_ELECTRICITY))) + { + monsters *mons = &menv[mid]; + if (!mons_class_flag(mons->type, M_WALL_SHIELDED)) + return true; + } + + return false; +} + /* * Beam pseudo code: * @@ -1350,6 +1376,12 @@ void fire_beam( bolt &pbolt, item_def *item ) // should we ever get a tracer with a wall-affecting // beam (possible I suppose), we'll quit tracing now. if (!pbolt.is_tracer) + { + pbolt.is_tracer = false; + rangeRemaining -= affect(pbolt, tx, ty); + pbolt.is_tracer = true; + } + else rangeRemaining -= affect(pbolt, tx, ty); // if it's still a wall, quit. @@ -1358,9 +1390,13 @@ void fire_beam( bolt &pbolt, item_def *item ) } else { - // BEGIN bounce case + // BEGIN bounce case. Bouncing protects any monster + // in the wall. if (!isBouncy(pbolt, grd[tx][ty])) { + // Affect any monster that might be in the wall. + rangeRemaining -= affect(pbolt, tx, ty); + do ray.regress(); while (grid_is_solid(grd(ray.pos()))); @@ -2491,10 +2527,28 @@ int affect(bolt &beam, int x, int y) { rangeUsed += affect_wall(beam, x, y); } - // if it's still a wall, quit - we can't do anything else to - // a wall. Otherwise effects (like clouds, etc) are still possible. + // if it's still a wall, quit - we can't do anything else to a + // wall (but we still might be able to do something to any + // monster inside the wall). Otherwise effects (like clouds, + // etc) are still possible. if (grid_is_solid(grd[x][y])) + { + int mid = mgrd[x][y]; + if (mid != NON_MONSTER) + { + monsters *mon = &menv[mid]; + if (affect_mon_in_wall(beam, NULL, x, y)) + rangeUsed += affect_monster( beam, mon ); + else if (you.can_see(mon)) + { + mprf("The %s protects %s from harm.", + raw_feature_description(grd(mon->pos())).c_str(), + mon->name(DESC_NOCAP_THE).c_str()); + } + } + return (rangeUsed); + } } // grd[x][y] will NOT be a wall for the remainder of this function. diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc index 50b5869f77..a77844f618 100644 --- a/crawl-ref/source/fight.cc +++ b/crawl-ref/source/fight.cc @@ -505,6 +505,50 @@ bool melee_attack::attack() xom_is_stimulated(128); } + // Defending monster protects itself from attacks using the + // wall it's in. + if (defender->atype() == ACT_MONSTER && grid_is_solid(def->pos()) + && mons_class_flag(def->type, M_WALL_SHIELDED)) + { + std::string feat_name = raw_feature_description(grd(def->pos())); + + if (attacker->atype() == ACT_PLAYER) + { + player_apply_attack_delay(); + + if (you.can_see(def)) + { + mprf("The %s protects %s from harm.", + feat_name.c_str(), + def->name(DESC_NOCAP_THE).c_str()); + } + else + { + mprf("You hit the %s.", + feat_name.c_str()); + } + } + else if (you.can_see(atk)) + { + // Make sure the monster uses up some energy, even though + // it didn't actually land a blow. + monsterentry *entry = get_monster_data(atk->type); + atk->speed_increment -= entry->energy_usage.attack; + + if (!mons_near(def)) + simple_monster_message(atk, " hits something"); + else if (!you.can_see(atk)) + mprf("%s hits the %s.", def->name(DESC_CAP_THE).c_str(), + feat_name.c_str()); + else + mprf("%s tries to hit the %s, but is blocked by the %s.", + atk->name(DESC_CAP_THE).c_str(), + def->name(DESC_NOCAP_THE).c_str(), + feat_name.c_str()); + } + return (true); + } + // Allow god to get offended, etc. attacker->attacking(defender); diff --git a/crawl-ref/source/mon-data.h b/crawl-ref/source/mon-data.h index 0c8b71c8e1..de9adb26e2 100644 --- a/crawl-ref/source/mon-data.h +++ b/crawl-ref/source/mon-data.h @@ -3875,7 +3875,7 @@ { MONS_WATER_ELEMENTAL, '{', LIGHTBLUE, "water elemental", - M_FLIES, + M_FLIES | M_AMPHIBIOUS, MR_RES_POISON | MR_VUL_FIRE | MR_RES_ELEC, 0, 10, MONS_EARTH_ELEMENTAL, MONS_WATER_ELEMENTAL, MH_NONLIVING, MAG_IMMUNE, { {AT_HIT, AF_PLAIN, 25}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, @@ -3900,7 +3900,8 @@ // begin "move through rock" monsters {mpc} { MONS_ROCK_WORM, 'w', BROWN, "rock worm", - M_NO_FLAGS, + //M_NO_FLAGS, + M_WALL_SHIELDED, MR_RES_POISON | MR_RES_FIRE | MR_RES_COLD | MR_RES_ELEC, 0, 10, MONS_WORM, MONS_ROCK_WORM, MH_NATURAL, -3, { {AT_BITE, AF_PLAIN, 20}, AT_NO_ATK, AT_NO_ATK, AT_NO_ATK }, diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc index 3474059a72..0c1d290cf6 100644 --- a/crawl-ref/source/mon-util.cc +++ b/crawl-ref/source/mon-util.cc @@ -2413,7 +2413,7 @@ bool mons_class_can_pass(const int mclass, const dungeon_feature_type grid) switch (mclass) { case MONS_ROCK_WORM: - return (grid >= DNGN_ROCK_WALL && grid <= DNGN_CLEAR_PERMAROCK_WALL); + return (!grid_is_solid(grid) || grid_is_rock(grid)); } return !grid_is_solid(grid); diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h index ef8aa03a2b..3c39e81179 100644 --- a/crawl-ref/source/mon-util.h +++ b/crawl-ref/source/mon-util.h @@ -116,6 +116,8 @@ enum mons_class_flags M_ARCHER = (1<<23), // gets various archery boosts + M_WALL_SHIELDED = (1<<24), // Shielded from attacks if in wall + M_SPECIAL_ABILITY = (1<<26), // XXX: eventually make these spells? M_NO_SKELETON = (1<<29), // boneless corpses diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc index ea96452e24..3380be6130 100644 --- a/crawl-ref/source/monplace.cc +++ b/crawl-ref/source/monplace.cc @@ -105,15 +105,16 @@ bool monster_habitable_grid(int monster_class, int actual_grid, int flies, && (actual_grid == DNGN_LAVA || actual_grid == DNGN_DEEP_WATER)) - // Amphibious critters are happy in the water. + // Amphibious critters are happy in water or on land. || (mons_class_flag(monster_class, M_AMPHIBIOUS) - && grid_compatible(DNGN_DEEP_WATER, actual_grid)) + && ((preferred_habitat == DNGN_FLOOR + && grid_compatible(DNGN_DEEP_WATER, actual_grid)) + || (preferred_habitat == DNGN_DEEP_WATER + && grid_compatible(DNGN_FLOOR, actual_grid)))) - // And water elementals are native to the water but happy on land + // Rock worms are native to walls but are happy on the floor // as well. - || ((monster_class == MONS_WATER_ELEMENTAL - || monster_class == MONS_MERFOLK - || monster_class == MONS_MERMAID) + || (monster_class == MONS_ROCK_WORM && grid_compatible(DNGN_FLOOR, actual_grid))); } diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc index 71e832426f..14130fa1ae 100644 --- a/crawl-ref/source/monstuff.cc +++ b/crawl-ref/source/monstuff.cc @@ -1759,6 +1759,11 @@ void behaviour_event( monsters *mon, int event, int src, // 1. Evalutates current AI state // 2. Sets monster targetx,y based on current foe // +// XXX: Monsters of I_NORMAL or above should select a new target +// if their current target is another monser which is sitting in +// a wall and is immune to most attacks while in a wall +// (M_WALL_SHIELDED), unless the monster has a spell or special/nearby +// ability which isn't affected by M_WALL_SHIELDED. //--------------------------------------------------------------- static void handle_behaviour(monsters *mon) { @@ -2095,6 +2100,13 @@ static void handle_behaviour(monsters *mon) // we can jump back to WANDER if the foe // isn't present. + // XXX: If a monster can move through solid grids then it + // should preferentially flee towards the nearest solid grid + // it can move through. If it has M_WALL_SHIELDED is will + // be (mostly) safe as soon as it enters the wall, and even + // if it doesn't once it moves again it will be on the other + // side of the wall and likely beyond the reach of the player. + if (isFriendly) { // Special-cased below so that it will flee *towards* you diff --git a/crawl-ref/source/terrain.cc b/crawl-ref/source/terrain.cc index af31a735d5..8c9e122944 100644 --- a/crawl-ref/source/terrain.cc +++ b/crawl-ref/source/terrain.cc @@ -175,6 +175,15 @@ bool grid_is_solid(const coord_def &c) return (grid_is_solid(grd(c))); } +bool grid_is_rock( dungeon_feature_type grid ) +{ + return (grid == DNGN_ORCISH_IDOL + || grid == DNGN_GRANITE_STATUE + || grid == DNGN_SECRET_DOOR + || (grid >= DNGN_ROCK_WALL + && grid <= DNGN_CLEAR_PERMAROCK_WALL)); +} + bool grid_is_trap(dungeon_feature_type grid) { return (grid == DNGN_TRAP_MECHANICAL || grid == DNGN_TRAP_MAGICAL diff --git a/crawl-ref/source/terrain.h b/crawl-ref/source/terrain.h index 5839d4d02e..51caa559d6 100644 --- a/crawl-ref/source/terrain.h +++ b/crawl-ref/source/terrain.h @@ -28,10 +28,11 @@ bool fall_into_a_pool( int entry_x, int entry_y, bool allow_shift, bool grid_is_wall(dungeon_feature_type grid); bool grid_is_opaque(dungeon_feature_type grid); bool grid_is_solid(dungeon_feature_type grid); -bool grid_is_stone_stair(dungeon_feature_type grid); -bool grid_is_rock_stair(dungeon_feature_type grid); bool grid_is_solid(int x, int y); bool grid_is_solid(const coord_def &c); +bool grid_is_rock(dungeon_feature_type grid); +bool grid_is_stone_stair(dungeon_feature_type grid); +bool grid_is_rock_stair(dungeon_feature_type grid); bool grid_is_trap(dungeon_feature_type grid); command_type grid_stair_direction(dungeon_feature_type grid); bool grid_sealable_portal(dungeon_feature_type grid); |