summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/noise.h
diff options
context:
space:
mode:
authorDarshan Shaligram <dshaligram@users.sourceforge.net>2011-01-06 23:42:46 +0530
committerDarshan Shaligram <dshaligram@users.sourceforge.net>2011-01-07 03:23:50 +0530
commit95cc9338a77e5c4182e0f6e807801c6bcd438847 (patch)
treeed09bac745294fb8e32c53ab813d343d36d1f009 /crawl-ref/source/noise.h
parent6129dcaa68151913ebcbc0a2fa3b3b1b4f9ad32d (diff)
downloadcrawl-ref-95cc9338a77e5c4182e0f6e807801c6bcd438847.tar.gz
crawl-ref-95cc9338a77e5c4182e0f6e807801c6bcd438847.zip
New noise propagation system.
The old noise propagation system alerted all monsters within `loudness' radius of the noise source, ignoring obstacles between the observer and the noise source. The new noise system applies only to monsters; the player is still messaged as before. This is for two reasons: 1. noisy() must return if the player heard the noise, which forces us to propagate the noise immediately for each noise, an unacceptable overhead on busy maps (such as Sprint). Therefore we cheat and use the old noise rules for the player. This is relatively simple to work around, since not many code paths rely on the noisy() return code, and these places can be changed to work around this lack of information. 2. The new noise system allows loud noises to drown out quiet noises. This may be an unacceptable loss of information for the player. The new system keeps track of noises produced by noisy(), but does not act on them immediately. Instead, all noises are processed in world_reacts. Noises are processed by a simple flood-out from their sources, attenuated by distance, terrain (such as closed doors, trees), and by twists in the noise's path (a winding corridor attenuates noise more than a straight line). Noise propagation and attenuation uses movement geometry, not LOS geometry, *but* attenuation assumes it is harder for the noise to change direction than to keep going in its old direction. To simplify handling of noises, it is assumed that louder noises overwhelm quieter noises. An actor exposed to both a loud and a quiet noise at the same distance will hear only the loud noise. However, an actor closer to the quiet noise than the loud noise will hear first the quiet noise, then the loud noise (because the floodfill visits points at an increasing radius from each noise source). Given two equally loud noises, the closer noise will always win. Multiple quiet noises emitted close together do not combined into a louder noise. Monsters hearing a noise at a distance from its source may not correctly guess the noise's origin if the noise did not travel in a straight line to the monster. Noises are currently processed before and after handle_monsters() so that monsters can react to noises produced by the player and by each other. We could conceivably drop one of the apply_noises() calls (probably the one after handle_monsters()) without adverse effects. Since the new noise system allows closed doors to cut off sound, I've dropped the Sprint noise attenuation from 1/3 to 1/2. If Crawl is compiled with DEBUG_NOISE_PROPAGATION, it will write a noise-grid.html dump file showing noise sources and intensities on the map for each call to apply_noises that processed a noise.
Diffstat (limited to 'crawl-ref/source/noise.h')
-rw-r--r--crawl-ref/source/noise.h157
1 files changed, 157 insertions, 0 deletions
diff --git a/crawl-ref/source/noise.h b/crawl-ref/source/noise.h
new file mode 100644
index 0000000000..df7115b1b3
--- /dev/null
+++ b/crawl-ref/source/noise.h
@@ -0,0 +1,157 @@
+// Private header for shout.h.
+
+#ifndef NOISE_H
+#define NOISE_H
+
+#include "externs.h"
+
+// [ds] The old noise system was pretty simple: noise level (loudness) ==
+// distance covered. Since the new system considers terrain when propagating
+// sound, using the same noise attenuation of 1 unit per square traveled would
+// mean greatly reduced sound propagation on average.
+//
+// To compensate for sound being blocked by walls and doors, I've lowered the
+// base attenuation from its original value of 1 (1000 millis).
+//
+// Note that this reduced attenuation makes open levels nastier, since there's
+// nothing to block sound propagation there, and the lowered attenuation means
+// sound goes farther.
+//
+const int BASE_NOISE_ATTENUATION_MILLIS = 850;
+const int NOISE_ATTENUATION_COMPLETE = 250000;
+const int LOWEST_AUDIBLE_NOISE_INTENSITY_MILLIS = 1000;
+
+int noise_attenuation_millis(const coord_def &pos);
+static inline int noise_is_audible(int noise_intensity_millis)
+{
+ return noise_intensity_millis >= LOWEST_AUDIBLE_NOISE_INTENSITY_MILLIS;
+}
+
+enum noise_flag_type
+{
+ NF_NONE = 0,
+ NF_MERMAID = 0x1,
+ NF_MESSAGE_IF_UNSEEN = 0x2,
+};
+
+struct noise_t
+{
+ coord_def noise_source;
+
+ std::string noise_player_msg;
+
+ // Millionths of noise intensity (i.e. the intensity passed to
+ // noisy() * 1000)
+ int noise_intensity_millis;
+
+ int16_t noise_id;
+
+ int16_t noise_producer_id;
+
+ uint16_t noise_flags;
+
+ noise_t(coord_def _noise_source = coord_def(),
+ std::string _noise_player_msg = "",
+ int16_t _noise_intensity_millis = 0,
+ int16_t _noise_producer_id = -1,
+ uint16_t _flags = 0)
+ : noise_source(_noise_source),
+ noise_player_msg(_noise_player_msg),
+ noise_intensity_millis(_noise_intensity_millis),
+ noise_id(-1),
+ noise_producer_id(_noise_producer_id),
+ noise_flags(_flags)
+ {
+ }
+
+ bool silent() const
+ {
+ return !noise_is_audible(noise_intensity_millis);
+ }
+
+ bool operator < (const noise_t &other) const
+ {
+ return noise_intensity_millis < other.noise_intensity_millis;
+ }
+};
+
+struct noise_cell
+{
+ // The cell from which the noise reached this cell (delta)
+ coord_def neighbour_delta;
+
+ int16_t noise_id;
+ int noise_intensity_millis;
+ int noise_travel_distance;
+
+ noise_cell();
+ bool can_apply_noise(int noise_intensity_millis) const;
+ bool apply_noise(int noise_intensity_millis,
+ int noise_id,
+ int travel_distance,
+ const coord_def &neighbour_delta);
+
+ bool silent() const
+ {
+ return !noise_is_audible(noise_intensity_millis);
+ }
+
+ // Given a destination cell adjacent to this cell, returns the
+ // angle of <previous cell> <pos> <next-pos>:
+ // * If all three cells are in a straight line, returns 0
+ // * If the target cell is a knight's move from the original position,
+ // returns 1
+ // * If the target cell makes a right angle from the original position,
+ // returns 2
+ // * If the target cell makes a sharp 45 degree angle, returns 3.
+ // * If the original position is the same as the new position, returns 4.
+ // This number is used to multiply the noise attenuation for noise passing
+ // through this cell.
+ int turn_angle(const coord_def &next_delta) const;
+};
+
+class noise_grid
+{
+public:
+ noise_grid();
+
+ // Register a noise on the noise grid. The noise will not actually
+ // propagate until propagate_noise() is called.
+ void register_noise(const noise_t &noise);
+
+ // Propagate noise from the noise sources registered.
+ void propagate_noise();
+
+ // Clear all noise from the noise grid.
+ void reset();
+
+ bool dirty() const { return !noises.empty(); }
+
+#ifdef DEBUG_NOISE_PROPAGATION
+ void dump_noise_grid(const std::string &filename) const;
+ void write_noise_grid(FILE *outf) const;
+ void write_cell(FILE *outf, coord_def p, int ch) const;
+#endif
+
+private:
+ bool propagate_noise_to_neighbour(int base_attenuation,
+ int travel_distance,
+ const noise_cell &cell,
+ const coord_def &pos,
+ const coord_def &next_position);
+ void apply_noise_effects(const coord_def &pos,
+ int noise_intensity_millis,
+ const noise_t &noise,
+ int noise_travel_distance);
+
+ coord_def noise_perceived_position(actor *act,
+ const coord_def &affected_position,
+ const noise_t &noise) const;
+
+private:
+ FixedArray<noise_cell, GXM, GYM> cells;
+ std::vector<noise_t> noises;
+ int affected_actor_count;
+};
+
+#endif