First, it doesn't work in all walls, e.g. this one in the start map:
If I use a regular ricochet algorithm in this wall, it won't go to the side, and when I try to make it slide, it always bounces back to the player's origin. It's extremely weird how it doesn't work the same way on all walls. There are several walls and ceilings that have this same problem in the start map.
Second, it slides across the surface, but I realized this is not exactly what I wanted, because the beam goes to the side when the wall isn't perfectly orthogonal to the player's angles. What I really want is to make the beam "wrap" (I'm not sure whether this is the best word to describe this) across the wall, following this red line I've drawn using GIMP:
This is my code:
Code: Select all
void() W_FireLightning =
{
local float cells;
local vector org;
if (self.ammo_cells < 1)
{
self.weapon = W_BestWeapon ();
W_SetCurrentAmmo ();
return;
}
// explode if under water
if (self.waterlevel > 1)
{
cells = self.ammo_cells;
self.ammo_cells = 0;
W_SetCurrentAmmo ();
T_RadiusDamage (self, self, 35*cells, world);
return;
}
if (self.t_width < time)
{
sound (self, CHAN_WEAPON, "weapons/lhit.wav", 1, ATTN_NORM);
self.t_width = time + 0.6;
}
self.punchangle_x = -2;
self.currentammo = self.ammo_cells = self.ammo_cells - 1;
org = self.origin + '0 0 16';
traceline (org, org + v_forward*600, TRUE, self);
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
WriteEntity (MSG_BROADCAST, self);
WriteCoord (MSG_BROADCAST, org_x);
WriteCoord (MSG_BROADCAST, org_y);
WriteCoord (MSG_BROADCAST, org_z);
WriteCoord (MSG_BROADCAST, trace_endpos_x);
WriteCoord (MSG_BROADCAST, trace_endpos_y);
WriteCoord (MSG_BROADCAST, trace_endpos_z);
if (trace_fraction < 1)
{
vector olddir, newdir, oldpos;
entity e;
e = spawn ();
oldpos = trace_endpos;
olddir = v_forward * 600;
newdir_x = olddir_x * (-1 * trace_plane_normal_x + 1);
newdir_y = olddir_y * (-1 * trace_plane_normal_y + 1);
newdir_z = olddir_z * (-1 * trace_plane_normal_z + 1);
// newdir = normalize (newdir);
traceline (oldpos, oldpos + newdir /* * 600 * (1 - trace_fraction) */, TRUE, self);
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
WriteEntity (MSG_BROADCAST, e);
WriteCoord (MSG_BROADCAST, oldpos_x);
WriteCoord (MSG_BROADCAST, oldpos_y);
WriteCoord (MSG_BROADCAST, oldpos_z);
WriteCoord (MSG_BROADCAST, trace_endpos_x);
WriteCoord (MSG_BROADCAST, trace_endpos_y);
WriteCoord (MSG_BROADCAST, trace_endpos_z);
remove (e);
}
LightningDamage (self.origin, trace_endpos + v_forward*4, self, 30);
};