summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/beam.cc
diff options
context:
space:
mode:
authorzelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573>2008-12-26 05:40:06 +0000
committerzelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573>2008-12-26 05:40:06 +0000
commitab2a95081c9a02d5ffaf6349db865938a7f90a3d (patch)
treef711660dd9e02cab4b725f4546246bf6b77de3db /crawl-ref/source/beam.cc
parentecb9b51784088ab22126740c4080557612d63db0 (diff)
downloadcrawl-ref-ab2a95081c9a02d5ffaf6349db865938a7f90a3d.tar.gz
crawl-ref-ab2a95081c9a02d5ffaf6349db865938a7f90a3d.zip
Don't let chaos beam bounce off of one wall immediately into an adjacent wall;
prevents chaos beams from bouncing *thorugh* walls. If the beam passes out of bounds (the player was right at an edge of the map and fired the beam off the map) then finish the beam and regress back into bounds. Always finish beam if it hits a wall and neither affects the wall nor bounces. Regress out of walls before dropping an item. Don't regress out of walls if target == source. More assertions. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@7977 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source/beam.cc')
-rw-r--r--crawl-ref/source/beam.cc94
1 files changed, 56 insertions, 38 deletions
diff --git a/crawl-ref/source/beam.cc b/crawl-ref/source/beam.cc
index 2f0bda82d7..f28bde46e5 100644
--- a/crawl-ref/source/beam.cc
+++ b/crawl-ref/source/beam.cc
@@ -1414,13 +1414,30 @@ static void _munge_bounced_bolt(bolt &old_bolt, bolt &new_bolt,
double max = 90.0 + (angle / 2.0);
double min = -90.0 + (angle / 2.0);
- double shift = (double) random_range(min * 10000, max * 10000) / 10000.0;
+ double shift;
- if (new_deg < old_deg)
- shift = -shift;
- new_ray.set_degrees(new_deg + shift);
+ ray_def temp_ray = new_ray;
+ for (int tries = 0; tries < 20; tries++)
+ {
+ shift = (double) random_range(min * 10000, max * 10000) / 10000.0;
+
+ if (new_deg < old_deg)
+ shift = -shift;
+ temp_ray.set_degrees(new_deg + shift);
+
+ // Don't bounce straight into another wall. Can happen if the beam
+ // is shot into an inside corner.
+ ray_def test_ray = temp_ray;
+ test_ray.advance(true);
+ if (in_bounds(test_ray.pos()) && !grid_is_solid(test_ray.pos()))
+ break;
+
+ shift = 0.0;
+ temp_ray = new_ray;
+ }
-#if DEBUG_DIAGNOSTICS || DEBUG_CHAOS_BOUNCE
+ new_ray = temp_ray;
+#if DEBUG_DIAGNOSTICS || DEBUG_BEAM || DEBUG_CHAOS_BOUNCE
mprf(MSGCH_DIAGNOSTICS,
"chaos beam: old_deg = %5.2f, new_deg = %5.2f, shift = %5.2f",
(float) old_deg, (float) new_deg, (float) shift);
@@ -1431,32 +1448,6 @@ static void _munge_bounced_bolt(bolt &old_bolt, bolt &new_bolt,
// ping-pong balls on caffeine.
int range_spent = new_bolt.range_used - old_bolt.range_used;
new_bolt.range += range_spent;
-
- // XXX HACK: This is to avoid a problem which seems to be caused by
- // ray.advance(true) taking the shortest path but ray.regress() using raw
- // advancement to backtrack: say that the user fires a chaos beam
- // south-west into the corner, the bouncing code regresses it to point X,
- // then it randomly changes direction to slightly south of
- // due east:
- //
- // #####
- // # @ #
- // #X #
- // Y#####
- //
- // The ray advances via shortest path into the wall grid two squares
- // directly south of the player, and then tries to regress for another
- // bounce. However, it uses raw advancement to regress, which updates the
- // internal floating point representation of the position, and since it's
- // now travelling almost due west as it "regresses" it stays inside the
- // wall until it reaches point Y. (At least, I think that's what's
- // happening. The result is definitely the chaos beam passing through
- // the corner and ending up outside the room)
- //
- // Everything else I've tried to fix this causes an assertion somewhere
- // else.
- new_ray.advance(true);
- new_ray.regress();
}
bool bolt::invisible() const
@@ -1469,6 +1460,8 @@ void bolt::initialize_fire()
ASSERT(flavour > BEAM_NONE && flavour < BEAM_FIRST_PSEUDO);
ASSERT(!drop_item || item);
ASSERT(range >= 0);
+ ASSERT(chose_ray && in_bounds(ray.pos())
+ || !chose_ray && in_bounds(source));
real_flavour = flavour;
@@ -1763,14 +1756,16 @@ void bolt::hit_wall()
if (!invalid_monster_index(mgrd(pos())))
affect_monster( &menv[mgrd(pos())] );
- // Regress for explosions: blow up one step earlier.
- if (is_explosion && !in_explosion_phase)
+ // Regress for explosions: blow up in an open grid (if regressing
+ // makes any sense). Also regress when dropping items.
+ if (!aimed_at_spot
+ && ((is_explosion && !in_explosion_phase) || drop_item))
{
do {
ray.regress();
- } while (grid_is_solid(ray.pos()));
- finish_beam();
+ } while (ray.pos() != source && grid_is_solid(ray.pos()));
}
+ finish_beam();
}
}
@@ -1874,8 +1869,8 @@ void bolt::do_fire()
msg_generated = false;
if (target == source)
{
- auto_hit = true;
- aimed_at_spot = true;
+ auto_hit = true;
+ aimed_at_spot = true;
use_target_as_pos = true;
}
else
@@ -1892,7 +1887,7 @@ void bolt::do_fire()
oldValue = set_buffering(false);
#endif
- while (true)
+ while (in_bounds(pos()))
{
affect_cell();
@@ -1906,6 +1901,8 @@ void bolt::do_fire()
if (stop_at_target() && pos() == target)
break;
+ ASSERT(!grid_is_solid(grd(pos())));
+
const bool was_seen = seen;
if (!was_seen && range > 0 && !invisible() && see_grid(pos()))
seen = true;
@@ -1932,6 +1929,24 @@ void bolt::do_fire()
ray.advance(true);
}
+ if (!in_bounds(pos()))
+ {
+ ASSERT(!aimed_at_spot);
+#ifdef DEBUG
+ mprf(MSGCH_DIAGNOSTICS, "fire_beam(): beam '%s' passed off edge of "
+ "map (item = '%s')", name.c_str(),
+ item ? item->name(DESC_PLAIN).c_str() : "none");
+#endif
+
+ int tries = std::max(GXM, GYM);
+
+ while (!in_bounds(ray.pos()) && tries-- > 0)
+ ray.regress();
+
+ // Something bizarre happening if we can't get back onto the map.
+ ASSERT(in_bounds(pos()));
+ }
+
// The beam has terminated.
affect_endpoint();
@@ -5069,6 +5084,9 @@ static sweep_type _radial_sweep(int r)
bool bolt::explode(bool show_more, bool hole_in_the_middle)
{
+ ASSERT(!in_explosion_phase);
+ ASSERT(ex_size > 0);
+
real_flavour = flavour;
const int r = std::min(ex_size, MAX_EXPLOSION_RADIUS);
in_explosion_phase = true;