- some cleanup on P_RailAttack plus a bit of parameter floatification in thingdef_codeptr.cpp

This commit is contained in:
Christoph Oelckers 2016-03-25 00:59:14 +01:00
parent 4d22b346f4
commit f76524f459
5 changed files with 120 additions and 87 deletions

View File

@ -564,7 +564,11 @@ static void FireRailgun(AActor *self, int offset_xy, bool fromweapon)
damage = deathmatch ? 100 : 150; damage = deathmatch ? 100 : 150;
P_RailAttack (self, damage, offset_xy); FRailParams p;
p.source = self;
p.damage = damage;
p.offset_xy = offset_xy;
P_RailAttack (&p);
} }

View File

@ -3009,7 +3009,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_MonsterRail)
self->Angles.Yaw += pr_railface.Random2() * 45./256; self->Angles.Yaw += pr_railface.Random2() * 45./256;
} }
P_RailAttack (self, self->GetMissileDamage (0, 1), 0); FRailParams p;
p.source = self;
p.damage = self->GetMissileDamage(0, 1);
P_RailAttack (&p);
self->Angles.Pitch = saved_pitch; self->Angles.Pitch = saved_pitch;
return 0; return 0;
} }

View File

@ -394,7 +394,28 @@ inline bool P_HitWater(AActor *thing, sector_t *sec, const fixedvec3 &pos, bool
return P_HitWater(thing, sec, fpos, checkabove, alert, force); return P_HitWater(thing, sec, fpos, checkabove, alert, force);
} }
void P_CheckSplash(AActor *self, double distance); void P_CheckSplash(AActor *self, double distance);
void P_RailAttack (AActor *source, int damage, int offset_xy, fixed_t offset_z = 0, int color1 = 0, int color2 = 0, double maxdiff = 0, int flags = 0, PClassActor *puff = NULL, angle_t angleoffset = 0, angle_t pitchoffset = 0, fixed_t distance = 8192*FRACUNIT, int duration = 0, double sparsity = 1.0, double drift = 1.0, PClassActor *spawnclass = NULL, int SpiralOffset = 270); // [RH] Shoot a railgun
struct FRailParams
{
AActor *source = nullptr;
int damage = 0;
double offset_xy = 0;
double offset_z = 0;
int color1 = 0, color2 = 0;
double maxdiff = 0;
int flags = 0;
PClassActor *puff = nullptr;
DAngle angleoffset = 0.;
DAngle pitchoffset = 0.;
double distance = 8192;
int duration = 0;
double sparsity = 1.0;
double drift = 1.0;
PClassActor *spawnclass = nullptr;
int SpiralOffset = 270;
}; // [RH] Shoot a railgun
void P_RailAttack(FRailParams *params);
enum // P_RailAttack / A_RailAttack / A_CustomRailgun / P_DrawRailTrail flags enum // P_RailAttack / A_RailAttack / A_CustomRailgun / P_DrawRailTrail flags
{ {

View File

@ -4681,51 +4681,45 @@ static ETraceStatus ProcessRailHit(FTraceResults &res, void *userdata)
// //
// //
//========================================================================== //==========================================================================
void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, int color1, int color2, double maxdiff, int railflags, PClassActor *puffclass, angle_t angleoffset, angle_t pitchoffset, fixed_t distance, int duration, double sparsity, double drift, PClassActor *spawnclass, int SpiralOffset) void P_RailAttack(FRailParams *p)
{ {
fixed_t vx, vy, vz; DVector3 start;
angle_t angle, pitch;
DVector3 start, end;
FTraceResults trace; FTraceResults trace;
fixed_t shootz;
PClassActor *puffclass = p->puff;
if (puffclass == NULL) if (puffclass == NULL)
{ {
puffclass = PClass::FindActor(NAME_BulletPuff); puffclass = PClass::FindActor(NAME_BulletPuff);
} }
pitch = ((angle_t)(-source->_f_pitch()) + pitchoffset) >> ANGLETOFINESHIFT; AActor *source = p->source;
angle = (source->_f_angle() + angleoffset) >> ANGLETOFINESHIFT; DAngle pitch = -source->Angles.Pitch + p->pitchoffset;
DAngle angle = source->Angles.Yaw + p->angleoffset;
vx = FixedMul(finecosine[pitch], finecosine[angle]); DVector3 vec(DRotator(pitch, angle, angle));
vy = FixedMul(finecosine[pitch], finesine[angle]); double shootz = source->Center() - source->FloatSpeed + p->offset_z;
vz = finesine[pitch];
shootz = source->_f_Z() - source->_f_floorclip() + (source->_f_height() >> 1) + offset_z; if (!(p->flags & RAF_CENTERZ))
if (!(railflags & RAF_CENTERZ))
{ {
if (source->player != NULL) if (source->player != NULL)
{ {
shootz += FLOAT2FIXED(source->player->mo->AttackZOffset * source->player->crouchfactor); shootz += source->player->mo->AttackZOffset * source->player->crouchfactor;
} }
else else
{ {
shootz += 8 * FRACUNIT; shootz += 8;
} }
} }
angle = ((source->_f_angle() + angleoffset) - ANG90) >> ANGLETOFINESHIFT; DVector2 xy = source->Vec2Angle(p->offset_xy, angle - 90.);
fixedvec2 xy = source->Vec2Offset(offset_xy * finecosine[angle], offset_xy * finesine[angle]);
RailData rail_data; RailData rail_data;
rail_data.Caller = source; rail_data.Caller = source;
rail_data.StopAtOne = !!(railflags & RAF_NOPIERCE); rail_data.StopAtOne = !!(p->flags & RAF_NOPIERCE);
start.X = FIXED2DBL(xy.x); start.X = xy.X;
start.Y = FIXED2DBL(xy.y); start.Y = xy.Y;
start.Z = FIXED2DBL(shootz); start.Z = shootz;
int flags; int flags;
@ -4735,9 +4729,7 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i
flags = (puffDefaults->flags6 & MF6_NOTRIGGER) ? 0 : TRACE_PCross | TRACE_Impact; flags = (puffDefaults->flags6 & MF6_NOTRIGGER) ? 0 : TRACE_PCross | TRACE_Impact;
rail_data.StopAtInvul = (puffDefaults->flags3 & MF3_FOILINVUL) ? false : true; rail_data.StopAtInvul = (puffDefaults->flags3 & MF3_FOILINVUL) ? false : true;
rail_data.ThruSpecies = (puffDefaults->flags6 & MF6_MTHRUSPECIES) ? true : false; rail_data.ThruSpecies = (puffDefaults->flags6 & MF6_MTHRUSPECIES) ? true : false;
Trace(xy.x, xy.y, shootz, source->Sector, vx, vy, vz, Trace(start, source->Sector, vec, p->distance, MF_SHOOTABLE, ML_BLOCKEVERYTHING, source, trace, flags, ProcessRailHit, &rail_data);
distance, MF_SHOOTABLE, ML_BLOCKEVERYTHING, source, trace,
flags, ProcessRailHit, &rail_data);
// Hurt anything the trace hit // Hurt anything the trace hit
unsigned int i; unsigned int i;
@ -4750,8 +4742,6 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i
for (i = 0; i < rail_data.RailHits.Size(); i++) for (i = 0; i < rail_data.RailHits.Size(); i++)
{ {
bool spawnpuff; bool spawnpuff;
bool bleed = false; bool bleed = false;
@ -4789,12 +4779,12 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i
if (puffDefaults->flags3 & MF3_FOILINVUL) dmgFlagPass |= DMG_FOILINVUL; if (puffDefaults->flags3 & MF3_FOILINVUL) dmgFlagPass |= DMG_FOILINVUL;
if (puffDefaults->flags7 & MF7_FOILBUDDHA) dmgFlagPass |= DMG_FOILBUDDHA; if (puffDefaults->flags7 & MF7_FOILBUDDHA) dmgFlagPass |= DMG_FOILBUDDHA;
} }
int newdam = P_DamageMobj(hitactor, thepuff ? thepuff : source, source, damage, damagetype, dmgFlagPass|DMG_USEANGLE, hitangle); int newdam = P_DamageMobj(hitactor, thepuff ? thepuff : source, source, p->damage, damagetype, dmgFlagPass|DMG_USEANGLE, hitangle);
if (bleed) if (bleed)
{ {
P_SpawnBlood(hitpos, hitangle, newdam > 0 ? newdam : damage, hitactor); P_SpawnBlood(hitpos, hitangle, newdam > 0 ? newdam : p->damage, hitactor);
P_TraceBleed(newdam > 0 ? newdam : damage, hitpos, hitactor, hitangle, ANGLE2DBL(pitch)); P_TraceBleed(newdam > 0 ? newdam : p->damage, hitpos, hitactor, hitangle, ANGLE2DBL(pitch));
} }
} }
@ -4843,8 +4833,7 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i
} }
// Draw the slug's trail. // Draw the slug's trail.
end = trace.HitPos; P_DrawRailTrail(source, start, trace.HitPos, p->color1, p->color2, p->maxdiff, p->flags, p->spawnclass, angle.BAMs(), p->duration, p->sparsity, p->drift, p->SpiralOffset);
P_DrawRailTrail(source, start, end, color1, color2, maxdiff, railflags, spawnclass, source->_f_angle() + angleoffset, duration, sparsity, drift, SpiralOffset);
} }
//========================================================================== //==========================================================================

View File

@ -313,12 +313,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetDistance)
} }
else else
{ {
fixedvec3 diff = self->_f_Vec3To(target); DVector3 diff = self->Vec3To(target);
if (checkz) if (checkz)
diff.z += (target->_f_height() - self->_f_height()) / 2; diff.Z += (target->Height - self->Height) / 2;
const double length = DVector3(FIXED2DBL(diff.x), FIXED2DBL(diff.y), (checkz) ? FIXED2DBL(diff.z) : 0).Length(); ret->SetFloat(diff.Length());
ret->SetFloat(length);
} }
return 1; return 1;
} }
@ -664,7 +663,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BasicAttack)
PARAM_INT (melee_damage); PARAM_INT (melee_damage);
PARAM_SOUND (melee_sound); PARAM_SOUND (melee_sound);
PARAM_CLASS (missile_type, AActor); PARAM_CLASS (missile_type, AActor);
PARAM_FIXED (missile_height); PARAM_FLOAT (missile_height);
if (missile_type != NULL) if (missile_type != NULL)
{ {
@ -928,7 +927,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_JumpIfTargetInsideMeleeRange)
static int DoJumpIfCloser(AActor *target, VM_ARGS) static int DoJumpIfCloser(AActor *target, VM_ARGS)
{ {
PARAM_ACTION_PROLOGUE; PARAM_ACTION_PROLOGUE;
PARAM_FIXED (dist); PARAM_FLOAT (dist);
PARAM_STATE (jump); PARAM_STATE (jump);
PARAM_BOOL_OPT(noz) { noz = false; } PARAM_BOOL_OPT(noz) { noz = false; }
@ -936,7 +935,7 @@ static int DoJumpIfCloser(AActor *target, VM_ARGS)
{ // No target - no jump { // No target - no jump
ACTION_RETURN_STATE(NULL); ACTION_RETURN_STATE(NULL);
} }
if (self->AproxDistance(target) < dist && if (self->Distance2D(target) < dist &&
(noz || (noz ||
((self->Z() > target->Z() && self->Z() - target->Top() < dist) || ((self->Z() > target->Z() && self->Z() - target->Top() < dist) ||
(self->Z() <= target->Z() && target->Z() - self->Top() < dist)))) (self->Z() <= target->Z() && target->Z() - self->Top() < dist))))
@ -1549,16 +1548,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FireBullets)
return 0; // out of ammo return 0; // out of ammo
} }
if (range == 0) if (range == 0) range = PLAYERMISSILERANGE;
range = PLAYERMISSILERANGE;
if (!(flags & FBF_NOFLASH)) static_cast<APlayerPawn *>(self)->PlayAttacking2 (); if (!(flags & FBF_NOFLASH)) static_cast<APlayerPawn *>(self)->PlayAttacking2 ();
if (!(flags & FBF_NOPITCH)) bslope = P_BulletSlope(self); if (!(flags & FBF_NOPITCH)) bslope = P_BulletSlope(self);
bangle = self->Angles.Yaw; bangle = self->Angles.Yaw;
if (pufftype == NULL) if (pufftype == NULL) pufftype = PClass::FindActor(NAME_BulletPuff);
pufftype = PClass::FindActor(NAME_BulletPuff);
if (weapon != NULL) if (weapon != NULL)
{ {
@ -1702,7 +1699,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch)
PARAM_INT_OPT (flags) { flags = CPF_USEAMMO; } PARAM_INT_OPT (flags) { flags = CPF_USEAMMO; }
PARAM_CLASS_OPT (pufftype, AActor) { pufftype = NULL; } PARAM_CLASS_OPT (pufftype, AActor) { pufftype = NULL; }
PARAM_FLOAT_OPT (range) { range = 0; } PARAM_FLOAT_OPT (range) { range = 0; }
PARAM_FIXED_OPT (lifesteal) { lifesteal = 0; } PARAM_FLOAT_OPT (lifesteal) { lifesteal = 0; }
PARAM_INT_OPT (lifestealmax) { lifestealmax = 0; } PARAM_INT_OPT (lifestealmax) { lifestealmax = 0; }
PARAM_CLASS_OPT (armorbonustype, ABasicArmorBonus) { armorbonustype = NULL; } PARAM_CLASS_OPT (armorbonustype, ABasicArmorBonus) { armorbonustype = NULL; }
PARAM_SOUND_OPT (MeleeSound) { MeleeSound = ""; } PARAM_SOUND_OPT (MeleeSound) { MeleeSound = ""; }
@ -1746,7 +1743,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch)
} }
else else
{ {
if (lifesteal && !(t.linetarget->flags5 & MF5_DONTDRAIN)) if (lifesteal > 0 && !(t.linetarget->flags5 & MF5_DONTDRAIN))
{ {
if (flags & CPF_STEALARMOR) if (flags & CPF_STEALARMOR)
{ {
@ -1758,7 +1755,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch)
{ {
assert(armorbonustype->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus))); assert(armorbonustype->IsDescendantOf(RUNTIME_CLASS(ABasicArmorBonus)));
ABasicArmorBonus *armorbonus = static_cast<ABasicArmorBonus *>(Spawn(armorbonustype)); ABasicArmorBonus *armorbonus = static_cast<ABasicArmorBonus *>(Spawn(armorbonustype));
armorbonus->SaveAmount *= (actualdamage * lifesteal) >> FRACBITS; armorbonus->SaveAmount *= int(actualdamage * lifesteal);
armorbonus->MaxSaveAmount = lifestealmax <= 0 ? armorbonus->MaxSaveAmount : lifestealmax; armorbonus->MaxSaveAmount = lifestealmax <= 0 ? armorbonus->MaxSaveAmount : lifestealmax;
armorbonus->flags |= MF_DROPPED; armorbonus->flags |= MF_DROPPED;
armorbonus->ClearCounters(); armorbonus->ClearCounters();
@ -1771,7 +1768,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch)
} }
else else
{ {
P_GiveBody (self, (actualdamage * lifesteal) >> FRACBITS, lifestealmax); P_GiveBody (self, int(actualdamage * lifesteal), lifestealmax);
} }
} }
if (weapon != NULL) if (weapon != NULL)
@ -1809,17 +1806,17 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack)
PARAM_INT_OPT (flags) { flags = 0; } PARAM_INT_OPT (flags) { flags = 0; }
PARAM_FLOAT_OPT (maxdiff) { maxdiff = 0; } PARAM_FLOAT_OPT (maxdiff) { maxdiff = 0; }
PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindActor(NAME_BulletPuff); } PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindActor(NAME_BulletPuff); }
PARAM_ANGLE_OPT (spread_xy) { spread_xy = 0; } PARAM_DANGLE_OPT(spread_xy) { spread_xy = 0.; }
PARAM_ANGLE_OPT (spread_z) { spread_z = 0; } PARAM_DANGLE_OPT(spread_z) { spread_z = 0.; }
PARAM_FIXED_OPT (range) { range = 0; } PARAM_FLOAT_OPT (range) { range = 0; }
PARAM_INT_OPT (duration) { duration = 0; } PARAM_INT_OPT (duration) { duration = 0; }
PARAM_FLOAT_OPT (sparsity) { sparsity = 1; } PARAM_FLOAT_OPT (sparsity) { sparsity = 1; }
PARAM_FLOAT_OPT (driftspeed) { driftspeed = 1; } PARAM_FLOAT_OPT (driftspeed) { driftspeed = 1; }
PARAM_CLASS_OPT (spawnclass, AActor){ spawnclass = NULL; } PARAM_CLASS_OPT (spawnclass, AActor){ spawnclass = NULL; }
PARAM_FIXED_OPT (spawnofs_z) { spawnofs_z = 0; } PARAM_FLOAT_OPT (spawnofs_z) { spawnofs_z = 0; }
PARAM_INT_OPT (SpiralOffset) { SpiralOffset = 270; } PARAM_INT_OPT (SpiralOffset) { SpiralOffset = 270; }
if (range == 0) range = 8192*FRACUNIT; if (range == 0) range = 8192;
if (sparsity == 0) sparsity=1.0; if (sparsity == 0) sparsity=1.0;
if (self->player == NULL) if (self->player == NULL)
@ -1834,21 +1831,31 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_RailAttack)
return 0; // out of ammo return 0; // out of ammo
} }
angle_t angle; if (!(flags & RAF_EXPLICITANGLE))
angle_t slope;
if (flags & RAF_EXPLICITANGLE)
{ {
angle = spread_xy; spread_xy = spread_xy * pr_crailgun.Random2() / 255;
slope = spread_z; spread_z = spread_z * pr_crailgun.Random2() / 255;
}
else
{
angle = pr_crailgun.Random2() * (spread_xy / 255);
slope = pr_crailgun.Random2() * (spread_z / 255);
} }
P_RailAttack (self, damage, spawnofs_xy, spawnofs_z, color1, color2, maxdiff, flags, pufftype, angle, slope, range, duration, sparsity, driftspeed, spawnclass, SpiralOffset); FRailParams p;
p.source = self;
p.damage = damage;
p.offset_xy = spawnofs_xy;
p.offset_z = spawnofs_z;
p.color1 = color1;
p.color2 = color2;
p.maxdiff = maxdiff;
p.flags = flags;
p.puff = pufftype;
p.angleoffset = spread_xy;
p.pitchoffset = spread_z;
p.distance = range;
p.duration = duration;
p.sparsity = sparsity;
p.drift = driftspeed;
p.spawnclass = spawnclass;
p.SpiralOffset = SpiralOffset;
P_RailAttack(&p);
return 0; return 0;
} }
@ -1876,14 +1883,14 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun)
PARAM_INT_OPT (aim) { aim = CRF_DONTAIM; } PARAM_INT_OPT (aim) { aim = CRF_DONTAIM; }
PARAM_FLOAT_OPT (maxdiff) { maxdiff = 0; } PARAM_FLOAT_OPT (maxdiff) { maxdiff = 0; }
PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindActor(NAME_BulletPuff); } PARAM_CLASS_OPT (pufftype, AActor) { pufftype = PClass::FindActor(NAME_BulletPuff); }
PARAM_ANGLE_OPT (spread_xy) { spread_xy = 0; } PARAM_DANGLE_OPT(spread_xy) { spread_xy = 0.; }
PARAM_ANGLE_OPT (spread_z) { spread_z = 0; } PARAM_DANGLE_OPT(spread_z) { spread_z = 0.; }
PARAM_FIXED_OPT (range) { range = 0; } PARAM_FLOAT_OPT (range) { range = 0; }
PARAM_INT_OPT (duration) { duration = 0; } PARAM_INT_OPT (duration) { duration = 0; }
PARAM_FLOAT_OPT (sparsity) { sparsity = 1; } PARAM_FLOAT_OPT (sparsity) { sparsity = 1; }
PARAM_FLOAT_OPT (driftspeed) { driftspeed = 1; } PARAM_FLOAT_OPT (driftspeed) { driftspeed = 1; }
PARAM_CLASS_OPT (spawnclass, AActor){ spawnclass = NULL; } PARAM_CLASS_OPT (spawnclass, AActor){ spawnclass = NULL; }
PARAM_FIXED_OPT (spawnofs_z) { spawnofs_z = 0; } PARAM_FLOAT_OPT (spawnofs_z) { spawnofs_z = 0; }
PARAM_INT_OPT (SpiralOffset) { SpiralOffset = 270; } PARAM_INT_OPT (SpiralOffset) { SpiralOffset = 270; }
if (range == 0) range = 8192*FRACUNIT; if (range == 0) range = 8192*FRACUNIT;
@ -1930,8 +1937,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun)
// Tricky: We must offset to the angle of the current position // Tricky: We must offset to the angle of the current position
// but then change the angle again to ensure proper aim. // but then change the angle again to ensure proper aim.
self->SetXY(self->Vec2Offset( self->SetXY(self->Vec2Offset(
FLOAT2FIXED(spawnofs_xy * self->Angles.Yaw.Cos()), spawnofs_xy * self->Angles.Yaw.Cos(),
FLOAT2FIXED(spawnofs_xy * self->Angles.Yaw.Sin()))); spawnofs_xy * self->Angles.Yaw.Sin()));
spawnofs_xy = 0; spawnofs_xy = 0;
self->Angles.Yaw = self->AngleTo(self->target,- self->target->Vel.X * 3, -self->target->Vel.Y * 3); self->Angles.Yaw = self->AngleTo(self->target,- self->target->Vel.X * 3, -self->target->Vel.Y * 3);
} }
@ -1943,23 +1950,31 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomRailgun)
} }
} }
angle_t angle = (self->_f_angle() - ANG90) >> ANGLETOFINESHIFT; if (!(flags & CRF_EXPLICITANGLE))
angle_t angleoffset;
angle_t slopeoffset;
if (flags & CRF_EXPLICITANGLE)
{ {
angleoffset = spread_xy; spread_xy = spread_xy * pr_crailgun.Random2() / 255;
slopeoffset = spread_z; spread_z = spread_z * pr_crailgun.Random2() / 255;
}
else
{
angleoffset = pr_crailgun.Random2() * (spread_xy / 255);
slopeoffset = pr_crailgun.Random2() * (spread_z / 255);
} }
P_RailAttack (self, damage, spawnofs_xy, spawnofs_z, color1, color2, maxdiff, flags, pufftype, angleoffset, slopeoffset, range, duration, sparsity, driftspeed, spawnclass,SpiralOffset); FRailParams p;
p.source = self;
p.damage = damage;
p.offset_xy = spawnofs_xy;
p.offset_z = spawnofs_z;
p.color1 = color1;
p.color2 = color2;
p.maxdiff = maxdiff;
p.flags = flags;
p.puff = pufftype;
p.angleoffset = spread_xy;
p.pitchoffset = spread_z;
p.distance = range;
p.duration = duration;
p.sparsity = sparsity;
p.drift = driftspeed;
p.spawnclass = spawnclass;
p.SpiralOffset = SpiralOffset;
P_RailAttack(&p);
self->SetXYZ(savedpos); self->SetXYZ(savedpos);
self->Angles.Yaw = saved_angle; self->Angles.Yaw = saved_angle;