summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/terrain.cc
diff options
context:
space:
mode:
authorzelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573>2007-09-15 23:33:50 +0000
committerzelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573>2007-09-15 23:33:50 +0000
commitfa763ba1bc7285247a5b1438d59633383a80cf6c (patch)
treef4b632fea66f43dc6c1415fdaa4feead0b6ff90d /crawl-ref/source/terrain.cc
parent4d88632cb99d368956dec86732f7d275ffb941e8 (diff)
downloadcrawl-ref-fa763ba1bc7285247a5b1438d59633383a80cf6c.tar.gz
crawl-ref-fa763ba1bc7285247a5b1438d59633383a80cf6c.zip
Split off portions of externs.h and enum.h into other files. The
crawl_environment, player and monsters classes have been left in externs.h, which necessitates that all of the enums references by those classes stay in enums.h, since you can't forward declare an enum. However, it's a start. Also, portions of misc.{cc,h} have been split off into traps.{cc,h}, place.{cc,h} and terrain.{cc,h} git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@2095 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source/terrain.cc')
-rw-r--r--crawl-ref/source/terrain.cc543
1 files changed, 543 insertions, 0 deletions
diff --git a/crawl-ref/source/terrain.cc b/crawl-ref/source/terrain.cc
new file mode 100644
index 0000000000..cdca9d6017
--- /dev/null
+++ b/crawl-ref/source/terrain.cc
@@ -0,0 +1,543 @@
+/*
+ * File: terrain.cc
+ * Summary: Terrain related functions.
+ * Written by: Linley Henzell
+ *
+ * Modified for Crawl Reference by $Author: j-p-e-g $ on $Date: 2007-09-03 06:41:30 -0700 (Mon, 03 Sep 2007) $
+ *
+ * Change History (most recent first):
+ *
+ * <1> 9/11/07 MPC Split from misc.cc
+ */
+
+#include "externs.h"
+#include "terrain.h"
+
+#include "dgnevent.h"
+#include "itemprop.h"
+#include "items.h"
+#include "message.h"
+#include "misc.h"
+#include "monplace.h"
+#include "monstuff.h"
+#include "mstuff2.h"
+#include "ouch.h"
+#include "overmap.h"
+#include "player.h"
+#include "religion.h"
+#include "spells3.h"
+#include "stuff.h"
+#include "view.h"
+
+bool grid_is_wall( dungeon_feature_type grid )
+{
+ return (grid == DNGN_ROCK_WALL
+ || grid == DNGN_STONE_WALL
+ || grid == DNGN_METAL_WALL
+ || grid == DNGN_GREEN_CRYSTAL_WALL
+ || grid == DNGN_WAX_WALL
+ || grid == DNGN_PERMAROCK_WALL);
+}
+
+bool grid_is_stone_stair(dungeon_feature_type grid)
+{
+ switch (grid)
+ {
+ case DNGN_STONE_STAIRS_UP_I:
+ case DNGN_STONE_STAIRS_UP_II:
+ case DNGN_STONE_STAIRS_UP_III:
+ case DNGN_STONE_STAIRS_DOWN_I:
+ case DNGN_STONE_STAIRS_DOWN_II:
+ case DNGN_STONE_STAIRS_DOWN_III:
+ return (true);
+ default:
+ return (false);
+ }
+}
+
+bool grid_is_rock_stair(dungeon_feature_type grid)
+{
+ switch (grid)
+ {
+ case DNGN_ROCK_STAIRS_UP:
+ case DNGN_ROCK_STAIRS_DOWN:
+ return (true);
+ default:
+ return (false);
+ }
+}
+
+bool grid_sealable_portal(dungeon_feature_type grid)
+{
+ switch (grid)
+ {
+ case DNGN_ENTER_HELL:
+ case DNGN_ENTER_ABYSS:
+ case DNGN_ENTER_PANDEMONIUM:
+ case DNGN_ENTER_LABYRINTH:
+ case DNGN_ENTER_PORTAL_VAULT:
+ return (true);
+ default:
+ return (false);
+ }
+}
+
+bool grid_is_portal(dungeon_feature_type grid)
+{
+ return (grid == DNGN_ENTER_PORTAL_VAULT || grid == DNGN_EXIT_PORTAL_VAULT);
+}
+
+command_type grid_stair_direction(dungeon_feature_type grid)
+{
+ switch (grid)
+ {
+ case DNGN_STONE_STAIRS_UP_I:
+ case DNGN_STONE_STAIRS_UP_II:
+ case DNGN_STONE_STAIRS_UP_III:
+ case DNGN_ROCK_STAIRS_UP:
+ case DNGN_RETURN_FROM_ORCISH_MINES:
+ case DNGN_RETURN_FROM_HIVE:
+ case DNGN_RETURN_FROM_LAIR:
+ case DNGN_RETURN_FROM_SLIME_PITS:
+ case DNGN_RETURN_FROM_VAULTS:
+ case DNGN_RETURN_FROM_CRYPT:
+ case DNGN_RETURN_FROM_HALL_OF_BLADES:
+ case DNGN_RETURN_FROM_ZOT:
+ case DNGN_RETURN_FROM_TEMPLE:
+ case DNGN_RETURN_FROM_SNAKE_PIT:
+ case DNGN_RETURN_FROM_ELVEN_HALLS:
+ case DNGN_RETURN_FROM_TOMB:
+ case DNGN_RETURN_FROM_SWAMP:
+ case DNGN_RETURN_FROM_SHOALS:
+ case DNGN_RETURN_RESERVED_2:
+ case DNGN_RETURN_RESERVED_3:
+ case DNGN_RETURN_RESERVED_4:
+ case DNGN_ENTER_SHOP:
+ case DNGN_EXIT_HELL:
+ case DNGN_EXIT_PORTAL_VAULT:
+ return (CMD_GO_UPSTAIRS);
+
+ case DNGN_ENTER_PORTAL_VAULT:
+ case DNGN_ENTER_HELL:
+ case DNGN_ENTER_LABYRINTH:
+ case DNGN_STONE_STAIRS_DOWN_I:
+ case DNGN_STONE_STAIRS_DOWN_II:
+ case DNGN_STONE_STAIRS_DOWN_III:
+ case DNGN_ROCK_STAIRS_DOWN:
+ case DNGN_ENTER_DIS:
+ case DNGN_ENTER_GEHENNA:
+ case DNGN_ENTER_COCYTUS:
+ case DNGN_ENTER_TARTARUS:
+ case DNGN_ENTER_ABYSS:
+ case DNGN_EXIT_ABYSS:
+ case DNGN_ENTER_PANDEMONIUM:
+ case DNGN_EXIT_PANDEMONIUM:
+ case DNGN_TRANSIT_PANDEMONIUM:
+ case DNGN_ENTER_ORCISH_MINES:
+ case DNGN_ENTER_HIVE:
+ case DNGN_ENTER_LAIR:
+ case DNGN_ENTER_SLIME_PITS:
+ case DNGN_ENTER_VAULTS:
+ case DNGN_ENTER_CRYPT:
+ case DNGN_ENTER_HALL_OF_BLADES:
+ case DNGN_ENTER_ZOT:
+ case DNGN_ENTER_TEMPLE:
+ case DNGN_ENTER_SNAKE_PIT:
+ case DNGN_ENTER_ELVEN_HALLS:
+ case DNGN_ENTER_TOMB:
+ case DNGN_ENTER_SWAMP:
+ case DNGN_ENTER_SHOALS:
+ case DNGN_ENTER_RESERVED_2:
+ case DNGN_ENTER_RESERVED_3:
+ case DNGN_ENTER_RESERVED_4:
+ return (CMD_GO_DOWNSTAIRS);
+
+ default:
+ return (CMD_NO_CMD);
+ }
+}
+
+bool grid_is_opaque( dungeon_feature_type grid )
+{
+ return (grid < DNGN_MINSEE && grid != DNGN_ORCISH_IDOL);
+}
+
+bool grid_is_solid( dungeon_feature_type grid )
+{
+ return (grid < DNGN_MINMOVE);
+}
+
+bool grid_is_solid( int x, int y )
+{
+ return (grid_is_solid(grd[x][y]));
+}
+
+bool grid_is_solid(const coord_def &c)
+{
+ return (grid_is_solid(grd(c)));
+}
+
+bool grid_is_trap(dungeon_feature_type grid)
+{
+ return (grid == DNGN_TRAP_MECHANICAL || grid == DNGN_TRAP_MAGICAL
+ || grid == DNGN_TRAP_III);
+}
+
+bool grid_is_water( dungeon_feature_type grid )
+{
+ return (grid == DNGN_SHALLOW_WATER || grid == DNGN_DEEP_WATER);
+}
+
+bool grid_is_watery( dungeon_feature_type grid )
+{
+ return (grid_is_water(grid) || grid == DNGN_BLUE_FOUNTAIN);
+}
+
+bool grid_destroys_items( dungeon_feature_type grid )
+{
+ return (grid == DNGN_LAVA || grid == DNGN_DEEP_WATER);
+}
+
+// returns 0 if grid is not an altar, else it returns the GOD_* type
+god_type grid_altar_god( dungeon_feature_type grid )
+{
+ if (grid >= DNGN_ALTAR_ZIN && grid <= DNGN_ALTAR_BEOGH)
+ return (static_cast<god_type>( grid - DNGN_ALTAR_ZIN + 1 ));
+
+ return (GOD_NO_GOD);
+}
+
+// returns DNGN_FLOOR for non-gods, otherwise returns the altar for
+// the god.
+dungeon_feature_type altar_for_god( god_type god )
+{
+ if (god == GOD_NO_GOD || god >= NUM_GODS)
+ return (DNGN_FLOOR); // Yeah, lame. Tell me about it.
+
+ return static_cast<dungeon_feature_type>(DNGN_ALTAR_ZIN + god - 1);
+}
+
+bool grid_is_branch_stairs( dungeon_feature_type grid )
+{
+ return ((grid >= DNGN_ENTER_ORCISH_MINES && grid <= DNGN_ENTER_RESERVED_4)
+ || (grid >= DNGN_ENTER_DIS && grid <= DNGN_ENTER_TARTARUS));
+}
+
+int grid_secret_door_appearance( int gx, int gy )
+{
+ int ret = DNGN_FLOOR;
+
+ for (int dx = -1; dx <= 1; dx++)
+ {
+ for (int dy = -1; dy <= 1; dy++)
+ {
+ // only considering orthogonal grids
+ if ((abs(dx) + abs(dy)) % 2 == 0)
+ continue;
+
+ const dungeon_feature_type targ = grd[gx + dx][gy + dy];
+
+ if (!grid_is_wall( targ ))
+ continue;
+
+ if (ret == DNGN_FLOOR)
+ ret = targ;
+ else if (ret != targ)
+ ret = ((ret < targ) ? ret : targ);
+ }
+ }
+
+ return ((ret == DNGN_FLOOR) ? DNGN_ROCK_WALL
+ : ret);
+}
+
+const char *grid_item_destruction_message( dungeon_feature_type grid )
+{
+ return grid == DNGN_DEEP_WATER? "You hear a splash."
+ : grid == DNGN_LAVA ? "You hear a sizzling splash."
+ : "You hear a crunching noise.";
+}
+
+static coord_def dgn_find_nearest_square(
+ const coord_def &pos,
+ bool (*acceptable)(const coord_def &),
+ bool (*traversable)(const coord_def &) = NULL)
+{
+ memset(travel_point_distance, 0, sizeof(travel_distance_grid_t));
+
+ std::list<coord_def> points[2];
+ int iter = 0;
+ points[iter].push_back(pos);
+
+ while (!points[iter].empty())
+ {
+ for (std::list<coord_def>::iterator i = points[iter].begin();
+ i != points[iter].end(); ++i)
+ {
+ const coord_def &p = *i;
+
+ if (p != pos && acceptable(p))
+ return (p);
+
+ travel_point_distance[p.x][p.y] = 1;
+ for (int yi = -1; yi <= 1; ++yi)
+ {
+ for (int xi = -1; xi <= 1; ++xi)
+ {
+ if (!xi && !yi)
+ continue;
+
+ const coord_def np = p + coord_def(xi, yi);
+ if (!in_bounds(np) || travel_point_distance[np.x][np.y])
+ continue;
+
+ if (traversable && !traversable(np))
+ continue;
+
+ points[!iter].push_back(np);
+ }
+ }
+ }
+
+ points[iter].clear();
+ iter = !iter;
+ }
+
+ coord_def unfound;
+ return (unfound);
+}
+
+static bool item_safe_square(const coord_def &pos)
+{
+ const dungeon_feature_type feat = grd(pos);
+ return (is_traversable(feat) && !grid_destroys_items(feat));
+}
+
+// Moves an item on the floor to the nearest adjacent floor-space.
+static bool dgn_shift_item(const coord_def &pos, item_def &item)
+{
+ const coord_def np = dgn_find_nearest_square(pos, item_safe_square);
+ if (in_bounds(np) && np != pos)
+ {
+ int index = item.index();
+ move_item_to_grid(&index, np.x, np.y);
+ return (true);
+ }
+ return (false);
+}
+
+static bool is_critical_feature(dungeon_feature_type feat)
+{
+ return (grid_stair_direction(feat) != CMD_NO_CMD
+ || grid_altar_god(feat) != GOD_NO_GOD);
+}
+
+static bool is_feature_shift_target(const coord_def &pos)
+{
+ return (grd(pos) == DNGN_FLOOR && !dungeon_events.has_listeners_at(pos));
+}
+
+static bool dgn_shift_feature(const coord_def &pos)
+{
+ const dungeon_feature_type dfeat = grd(pos);
+ if (!is_critical_feature(dfeat) && !env.markers.find(pos, MAT_ANY))
+ return (false);
+
+ const coord_def dest =
+ dgn_find_nearest_square(pos, is_feature_shift_target);
+ if (in_bounds(dest) && dest != pos)
+ {
+ grd(dest) = dfeat;
+
+ if (dfeat == DNGN_ENTER_SHOP)
+ {
+ if (shop_struct *s = get_shop(pos.x, pos.y))
+ {
+ s->x = dest.x;
+ s->y = dest.y;
+ }
+ }
+ env.markers.move(pos, dest);
+ dungeon_events.move_listeners(pos, dest);
+ }
+ return (true);
+}
+
+static void dgn_check_terrain_items(const coord_def &pos, bool preserve_items)
+{
+ const dungeon_feature_type grid = grd(pos);
+ if (grid_is_solid(grid) || grid_destroys_items(grid))
+ {
+ int item = igrd(pos);
+ bool did_destroy = false;
+ while (item != NON_ITEM)
+ {
+ const int curr = item;
+ item = mitm[item].link;
+
+ // Game-critical item.
+ if (preserve_items || item_is_critical(mitm[curr]))
+ dgn_shift_item(pos, mitm[curr]);
+ else
+ {
+ destroy_item(curr);
+ did_destroy = true;
+ }
+ }
+ if (did_destroy && player_can_hear(pos))
+ mprf(MSGCH_SOUND, grid_item_destruction_message(grid));
+ }
+}
+
+static void dgn_check_terrain_monsters(const coord_def &pos)
+{
+ const int mindex = mgrd(pos);
+ if (mindex != NON_MONSTER)
+ {
+ monsters *mons = &menv[mindex];
+ if (grid_is_solid(grd(pos)))
+ monster_teleport(mons, true, false);
+ else
+ mons_check_pool(mons, KILL_MISC, -1);
+ }
+}
+
+void dungeon_terrain_changed(const coord_def &pos,
+ dungeon_feature_type nfeat,
+ bool affect_player,
+ bool preserve_features,
+ bool preserve_items)
+{
+ if (nfeat != DNGN_UNSEEN)
+ {
+ if (preserve_features)
+ dgn_shift_feature(pos);
+ unnotice_feature(level_pos(level_id::current(), pos));
+ grd(pos) = nfeat;
+ env.grid_colours(pos) = BLACK;
+ if (is_notable_terrain(nfeat) && see_grid(pos))
+ seen_notable_thing(nfeat, pos.x, pos.y);
+ }
+
+ dgn_check_terrain_items(pos, preserve_items);
+ if (affect_player && pos == you.pos())
+ {
+ if (!grid_is_solid(grd(pos)))
+ {
+ if (!you.flies())
+ move_player_to_grid(pos.x, pos.y, false, true, false);
+ }
+ else
+ you_teleport_now(true, false);
+ }
+ dgn_check_terrain_monsters(pos);
+}
+
+// returns true if we manage to scramble free.
+bool fall_into_a_pool( int entry_x, int entry_y, bool allow_shift,
+ unsigned char terrain )
+{
+ bool escape = false;
+ FixedVector< char, 2 > empty;
+
+ if (you.species == SP_MERFOLK && terrain == DNGN_DEEP_WATER)
+ {
+ // These can happen when we enter deep water directly -- bwr
+ merfolk_start_swimming();
+ return (false);
+ }
+
+ // sanity check
+ if (terrain != DNGN_LAVA && beogh_water_walk())
+ return (false);
+
+ mprf("You fall into the %s!",
+ (terrain == DNGN_LAVA) ? "lava" :
+ (terrain == DNGN_DEEP_WATER) ? "water"
+ : "programming rift");
+
+ more();
+ mesclr();
+
+ if (terrain == DNGN_LAVA)
+ {
+ const int resist = player_res_fire();
+
+ if (resist <= 0)
+ {
+ mpr( "The lava burns you to a cinder!" );
+ ouch( INSTANT_DEATH, 0, KILLED_BY_LAVA );
+ }
+ else
+ {
+ // should boost # of bangs per damage in the future {dlb}
+ mpr( "The lava burns you!" );
+ ouch( (10 + roll_dice(2,50)) / resist, 0, KILLED_BY_LAVA );
+ }
+
+ expose_player_to_element( BEAM_LAVA, 14 );
+ }
+
+ // a distinction between stepping and falling from you.duration[DUR_LEVITATION]
+ // prevents stepping into a thin stream of lava to get to the other side.
+ if (scramble())
+ {
+ if (allow_shift)
+ {
+ if (empty_surrounds( you.x_pos, you.y_pos, DNGN_FLOOR, 1,
+ false, empty ))
+ {
+ escape = true;
+ }
+ else
+ {
+ escape = false;
+ }
+ }
+ else
+ {
+ // back out the way we came in, if possible
+ if (grid_distance( you.x_pos, you.y_pos, entry_x, entry_y ) == 1
+ && (entry_x != empty[0] || entry_y != empty[1])
+ && mgrd[entry_x][entry_y] == NON_MONSTER)
+ {
+ escape = true;
+ empty[0] = entry_x;
+ empty[1] = entry_y;
+ }
+ else // zero or two or more squares away, with no way back
+ {
+ escape = false;
+ }
+ }
+ }
+ else
+ {
+ mpr("You try to escape, but your burden drags you down!");
+ }
+
+ if (escape)
+ {
+ const coord_def pos(empty[0], empty[1]);
+ if (in_bounds(pos) && !is_grid_dangerous(grd(pos)))
+ {
+ mpr("You manage to scramble free!");
+ move_player_to_grid( empty[0], empty[1], false, false, true );
+
+ if (terrain == DNGN_LAVA)
+ expose_player_to_element( BEAM_LAVA, 14 );
+
+ return (true);
+ }
+ }
+
+ mpr("You drown...");
+
+ if (terrain == DNGN_LAVA)
+ ouch( INSTANT_DEATH, 0, KILLED_BY_LAVA );
+ else if (terrain == DNGN_DEEP_WATER)
+ ouch( INSTANT_DEATH, 0, KILLED_BY_WATER );
+
+ return (false);
+} // end fall_into_a_pool()
+