NOTE: This uses a weird hack to prevent a bug which sometimes happens when a chaos beam is fired into the corner of a room. I think it's caused by ray.advance(true) and ray.regress() not being symmetrical.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@7783 c06c8d41-db1a-0410-9941-cceddc491573
Q52ILIIFMJ6HBSIUF7V7XQ6DQJGGYMHUZJ6CWVQKDX2JKBHEP2HAC
AYU5OVG2HZO46KDAPKUWAVHS5HTYFKUWIMIRMTHAXVVFEDJE7YPAC
GVCGKTH5IJ4VSQEIN4CRC7ZFVZW26JPIYNCPTO7GY66CSZZEW3ZQC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC
AS2IQQJNNCEQNXXKTGYHLB7RO3ZKCF4F7GK6FJH66BOOKDDRGNIQC
JJULXW764V5C2HJKZNWQAEWB6QM5YZADD7ZCE35LYTBFEM6PMYCAC
CDFS7Z74W5HKPQIHQICOG442KQFXUSBGGLDDQLE3MG74T44YU6AQC
FLAGBNUNSIQNFDN53CDWABJRTTFWDL4PG34AI474ZKPXDEPYHOAQC
Z3YHSEJ2ELRDG5DIDLP4MQSHNDRCTD5BSMVRBWOLF2S7TLRBGSBAC
5FHWTG7M6FW4B3I33YI7QSM3OZIB6ZGC6TI6JISSLY5Y43HI56VAC
}
double ray_def::get_degrees() const
{
if (slope > 100.0)
{
if (quadrant == 3 || quadrant == 2)
return (90.0);
else
return (270.0);
}
else if (double_is_zero(slope))
{
if (quadrant == 0 || quadrant == 3)
return (0.0);
else
return (180.0);
}
double deg = atan(slope) * 180.0 / M_PI;
switch (quadrant)
{
case 0:
return (360.0 - deg);
case 1:
return (180.0 + deg);
case 2:
return (180.0 - deg);
case 3:
return (deg);
}
ASSERT(!"ray has illegal quadrant");
return (0.0);
}
void ray_def::set_degrees(double deg)
{
while (deg < 0.0)
deg += 360.0;
while (deg >= 360.0)
deg -= 360.0;
double _slope = tan(deg / 180.0 * M_PI);
if (double_is_zero(_slope))
{
slope = 0.0;
if (deg < 90.0 || deg > 270.0)
quadrant = 0; // right/east
else
quadrant = 1; // left/west
}
else if (_slope > 0)
{
slope = _slope;
if (deg >= 180.0 && deg <= 270.0)
quadrant = 1;
else
quadrant = 3;
}
else
{
slope = -_slope;
if (deg >= 90 && deg <= 180)
quadrant = 2;
else
quadrant = 0;
}
if (slope > 1000.0)
slope = 1000.0;
}
static void _munge_bounced_bolt(bolt &old_bolt, bolt &new_bolt,
ray_def &old_ray, ray_def &new_ray)
{
if (new_bolt.real_flavour != BEAM_CHAOS)
return;
double old_deg = old_ray.get_degrees();
double new_deg = new_ray.get_degrees();
double angle = abs(old_deg - new_deg);
if (angle >= 180.0)
angle -= 180.0;
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;
if (new_deg < old_deg)
shift = -shift;
new_ray.set_degrees(new_deg + shift);
#if DEBUG_DIAGNOSTICS || 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);
#endif
// Don't use up range in bouncing off walls, so that chaos beams have
// as many chances as possible to bounce. They're like demented
// 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();
// enchantment is yours.
if (pbolt.is_enchantment())
// enchantment is yours (and it wasn't a chaos beam, since with chaos
// enchantments are entirely random, and if it randomly attempts
// something which ends up having no obvious effect then the player
// isn't going to realize it).
if (pbolt.is_enchantment() && pbolt.real_flavour != BEAM_CHAOS)