ensure deterministic order for P_Random stuff passed as arguments

the evaluation order of arguments passed to functions is undefined in C/C++, so its up to the compiler in which order to evaluate these

P_Random functions modify the randomseed each time theyre called, which can lead to different outcomes (thus desynchs) on different platforms, compilers,

compiler versions etc.

so match up with the most common which is last to first (seemingly the order gcc on nix and windows handle it)

common case are mine/eggbomb explosions hitting the smk ice blocks causing desynchs when either server or client were clang compiled
This commit is contained in:
Alug 2025-09-17 18:08:06 +02:00
parent 3be59c8100
commit 693374c5c1
3 changed files with 179 additions and 70 deletions

View file

@ -1236,10 +1236,15 @@ static void K_SpawnBrakeDriftSparks(player_t *player) // Be sure to update the m
void K_SpawnNormalSpeedLines(player_t *player)
{
mobj_t *fast = P_SpawnMobj(player->mo->x + (P_RandomRange(-36,36) * player->mo->scale),
player->mo->y + (P_RandomRange(-36,36) * player->mo->scale),
player->mo->z + (player->mo->height/2) + (P_RandomRange(-20,20) * player->mo->scale),
MT_FASTLINE);
fixed_t rand_x;
fixed_t rand_y;
fixed_t rand_z;
rand_z = player->mo->z + (player->mo->height/2) + (P_RandomRange(-20,20) * player->mo->scale);
rand_y = player->mo->y + (P_RandomRange(-36,36) * player->mo->scale);
rand_x = player->mo->x + (P_RandomRange(-36,36) * player->mo->scale);
mobj_t *fast = P_SpawnMobj(rand_x, rand_y, rand_z, MT_FASTLINE);
P_SetTarget(&fast->target, player->mo);
fast->angle = K_MomentumAngle(player->mo);
@ -1284,10 +1289,15 @@ void K_SpawnNormalSpeedLines(player_t *player)
void K_SpawnDraftSpeedLines(player_t *player, fixed_t scale, skincolornum_t color, boolean translucent)
{
mobj_t *fast = P_SpawnMobj(player->mo->x + (P_RandomRange(-36,36) * player->mo->scale),
player->mo->y + (P_RandomRange(-36,36) * player->mo->scale),
player->mo->z + (player->mo->height/2) + (P_RandomRange(-20,20) * player->mo->scale),
MT_FASTLINE);
fixed_t rand_x;
fixed_t rand_y;
fixed_t rand_z;
rand_z = player->mo->z + (player->mo->height/2) + (P_RandomRange(-20,20) * player->mo->scale);
rand_y = player->mo->y + (P_RandomRange(-36,36) * player->mo->scale);
rand_x = player->mo->x + (P_RandomRange(-36,36) * player->mo->scale);
mobj_t *fast = P_SpawnMobj(rand_x, rand_y, rand_z, MT_FASTLINE);
P_SetTarget(&fast->target, player->mo);
fast->angle = K_MomentumAngle(player->mo);
@ -1308,11 +1318,15 @@ void K_SpawnDraftSpeedLines(player_t *player, fixed_t scale, skincolornum_t colo
void K_SpawnInvincibilitySpeedLines(mobj_t *mo)
{
mobj_t *fast = P_SpawnMobjFromMobj(mo,
P_RandomRange(-48, 48) * FRACUNIT,
P_RandomRange(-48, 48) * FRACUNIT,
P_RandomRange(0, 64) * FRACUNIT,
MT_FASTLINE);
fixed_t rand_x;
fixed_t rand_y;
fixed_t rand_z;
rand_z = P_RandomRange(0, 64) * FRACUNIT;
rand_y = P_RandomRange(-48, 48) * FRACUNIT;
rand_x = P_RandomRange(-48, 48) * FRACUNIT;
mobj_t *fast = P_SpawnMobjFromMobj(mo, rand_x, rand_y, rand_z, MT_FASTLINE);
P_SetMobjState(fast, S_KARTINVLINES1);
P_SetTarget(&fast->target, mo);
@ -2344,7 +2358,7 @@ static fixed_t K_GetInvincibilitySpeed(UINT16 time)
{
if (K_GetKartInvinType() == KARTINVIN_LEGACY)
return INVINSPEEDBOOSTLGC;
fixed_t t = min(FRACUNIT, K_InvincibilityGradient(time));
return Easing_OutCubic(t, 0, INVINSPEEDBOOSTALT);
}
@ -2353,7 +2367,7 @@ static fixed_t K_GetInvincibilityAccel(UINT16 time)
{
if (K_GetKartInvinType() == KARTINVIN_LEGACY)
return INVINACCELBOOSTLGC;
fixed_t t = min(FRACUNIT, K_InvincibilityGradient(time));
return Easing_OutCubic(t, 0, INVINACCELBOOSTALT);
}
@ -3539,6 +3553,9 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color)
mobj_t *dust;
mobj_t *truc;
INT32 speed, speed2;
fixed_t rand_x;
fixed_t rand_y;
fixed_t rand_z;
K_MatchGenericExtraFlags(smoldering, source);
smoldering->tics = TICRATE*3;
@ -3558,9 +3575,11 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color)
dust->scalespeed = source->scale/12;
P_InstaThrust(dust, dust->angle, FixedMul(20*FRACUNIT, source->scale));
truc = P_SpawnMobj(source->x + P_RandomRange(-radius, radius)*FRACUNIT,
source->y + P_RandomRange(-radius, radius)*FRACUNIT,
source->z + P_RandomRange(0, height)*FRACUNIT, MT_BOOMEXPLODE);
rand_z = source->z + P_RandomRange(0, height)*FRACUNIT;
rand_y = source->y + P_RandomRange(-radius, radius)*FRACUNIT;
rand_x = source->x + P_RandomRange(-radius, radius)*FRACUNIT;
truc = P_SpawnMobj(rand_x, rand_y, rand_z, MT_BOOMEXPLODE);
K_MatchGenericExtraFlags(truc, source);
P_SetScale(truc, source->scale);
truc->destscale = source->scale*6;
@ -3577,9 +3596,11 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color)
for (i = 0; i < 16; i++)
{
dust = P_SpawnMobj(source->x + P_RandomRange(-radius, radius)*FRACUNIT,
source->y + P_RandomRange(-radius, radius)*FRACUNIT,
source->z + P_RandomRange(0, height)*FRACUNIT, MT_SMOKE);
rand_z = source->z + P_RandomRange(0, height)*FRACUNIT;
rand_y = source->y + P_RandomRange(-radius, radius)*FRACUNIT;
rand_x = source->x + P_RandomRange(-radius, radius)*FRACUNIT;
dust = P_SpawnMobj(rand_x, rand_y, rand_z, MT_SMOKE);
P_SetMobjState(dust, S_OPAQUESMOKE1);
P_SetScale(dust, source->scale);
dust->destscale = source->scale*10;
@ -3587,9 +3608,11 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color)
dust->tics = 30;
dust->momz = P_RandomRange(FixedMul(3*FRACUNIT, source->scale)>>FRACBITS, FixedMul(7*FRACUNIT, source->scale)>>FRACBITS)*FRACUNIT;
truc = P_SpawnMobj(source->x + P_RandomRange(-radius, radius)*FRACUNIT,
source->y + P_RandomRange(-radius, radius)*FRACUNIT,
source->z + P_RandomRange(0, height)*FRACUNIT, MT_BOOMPARTICLE);
rand_z = source->z + P_RandomRange(0, height)*FRACUNIT;
rand_y = source->y + P_RandomRange(-radius, radius)*FRACUNIT;
rand_x = source->x + P_RandomRange(-radius, radius)*FRACUNIT;
truc = P_SpawnMobj(rand_x, rand_y, rand_z, MT_BOOMPARTICLE);
K_MatchGenericExtraFlags(truc, source);
P_SetScale(truc, source->scale);
truc->destscale = source->scale*5;
@ -4061,9 +4084,13 @@ void K_SpawnWipeoutTrail(mobj_t *mo, boolean translucent)
else
aoff += ANGLE_45;
dust = P_SpawnMobj(mo->x + FixedMul(24*mo->scale, FINECOSINE(aoff>>ANGLETOFINESHIFT)) + (P_RandomRange(-8,8) << FRACBITS),
mo->y + FixedMul(24*mo->scale, FINESINE(aoff>>ANGLETOFINESHIFT)) + (P_RandomRange(-8,8) << FRACBITS),
mo->z, MT_WIPEOUTTRAIL);
fixed_t rand_x;
fixed_t rand_y;
rand_y = mo->y + FixedMul(24*mo->scale, FINESINE(aoff>>ANGLETOFINESHIFT)) + (P_RandomRange(-8,8) << FRACBITS);
rand_x = mo->x + FixedMul(24*mo->scale, FINECOSINE(aoff>>ANGLETOFINESHIFT)) + (P_RandomRange(-8,8) << FRACBITS);
dust = P_SpawnMobj(rand_x, rand_y, mo->z, MT_WIPEOUTTRAIL);
P_SetTarget(&dust->target, mo);
dust->angle = K_MomentumAngle(mo);
@ -4538,7 +4565,13 @@ static void K_FlameDashLeftoverSmoke(mobj_t *src)
smoke->momy = 3*src->momy/4;
smoke->momz = 3*P_GetMobjZMovement(src)/4;
P_Thrust(smoke, src->angle + FixedAngle(P_RandomRange(135, 225)<<FRACBITS), P_RandomRange(0, 8) * src->scale);
fixed_t rand_angle;
fixed_t rand_move;
rand_move = P_RandomRange(0, 8) * src->scale;
rand_angle = src->angle + FixedAngle(P_RandomRange(135, 225)<<FRACBITS);
P_Thrust(smoke, rand_angle, rand_move);
smoke->momz += P_RandomRange(0, 4) * src->scale;
}
}
@ -5219,9 +5252,7 @@ mobj_t *K_CreatePaperItem(fixed_t x, fixed_t y, fixed_t z, angle_t angle, SINT8
drop->destscale = (3*drop->destscale)/2;
drop->angle = angle;
P_Thrust(drop,
FixedAngle(P_RandomFixed() * 180) + angle,
16*mapobjectscale);
P_Thrust(drop, FixedAngle(P_RandomFixed() * 180) + angle, 16*mapobjectscale);
drop->momz = flip * 3 * mapobjectscale;
if (drop->eflags & MFE_UNDERWATER)
@ -9362,8 +9393,8 @@ static vector3_t *K_FindPlayerCluster(fixed_t eps, INT32 (*func)(player_t *, fix
clusterplayer[i] = false;
// Density check
if (N > bestdensity)
{
if (N > bestdensity)
{
bestdensity = N;
findme = closesttocluster;

View file

@ -3424,7 +3424,14 @@ void A_FishJump(mobj_t *actor)
if (i < MAXPLAYERS)
{
fixed_t rad = actor->radius>>FRACBITS;
P_SpawnMobjFromMobj(actor, P_RandomRange(rad, -rad)<<FRACBITS, P_RandomRange(rad, -rad)<<FRACBITS, 0, (mobjtype_t)locvar2);
fixed_t rand_x;
fixed_t rand_y;
rand_y = P_RandomRange(rad, -rad)<<FRACBITS;
rand_x = P_RandomRange(rad, -rad)<<FRACBITS;
P_SpawnMobjFromMobj(actor, rand_x, rand_y, 0, (mobjtype_t)locvar2);
}
}
@ -3516,7 +3523,7 @@ void A_SignPlayer(mobj_t *actor)
if (!actor->target->player)
return;
// Set the sign to be an appropriate background color for this player's skincolor.
actor->color = skincolors[actor->target->player->skincolor].invcolor;
actor->frame += skincolors[actor->target->player->skincolor].invshade;
@ -7230,7 +7237,7 @@ void A_StateRangeByParameter(mobj_t *actor)
if (locvar2 - locvar1 < 0)
return; // invalid range
if (udmf)
{
parameter = actor->args[0];
@ -9673,7 +9680,7 @@ void A_FlickyCenter(mobj_t *actor)
return;
homeRadius = locvar2 ? FixedMul(abs(locvar2), actor->scale) : 384*actor->scale;
if (!actor->tracer)
{
mobj_t *flicky = P_InternalFlickySpawn(actor, locvar1, 1, false, 0);
@ -10118,11 +10125,16 @@ void A_FlameParticle(mobj_t *actor)
rad = actor->radius>>FRACBITS;
hei = actor->height>>FRACBITS;
particle = P_SpawnMobjFromMobj(actor,
P_RandomRange(rad, -rad)<<FRACBITS,
P_RandomRange(rad, -rad)<<FRACBITS,
P_RandomRange(hei/2, hei)<<FRACBITS,
type);
fixed_t rand_x;
fixed_t rand_y;
fixed_t rand_z;
rand_z = P_RandomRange(hei/2, hei)<<FRACBITS;
rand_y = P_RandomRange(rad, -rad)<<FRACBITS;
rand_x = P_RandomRange(rad, -rad)<<FRACBITS;
particle = P_SpawnMobjFromMobj(actor, rand_x, rand_y, rand_z, type);
P_SetObjectMomZ(particle, 2<<FRACBITS, false);
}
@ -10612,7 +10624,7 @@ void A_ItemPop(mobj_t *actor)
//if (actor->info->deathsound)
//S_StartSound(remains, actor->info->deathsound);
if (!((gametyperules & GTR_BUMPERS) && actor->target->player->bumper <= 0) && !itembreaker)
{
actor->target->player->itemroulette = KROULETTE_ACTIVE;
@ -10695,8 +10707,15 @@ void A_JawzExplode(mobj_t *actor)
{
INT32 speed, speed2;
truc = P_SpawnMobj(actor->x + P_RandomRange(-8, 8)*FRACUNIT, actor->y + P_RandomRange(-8, 8)*FRACUNIT,
actor->z + P_RandomRange(0, 8)*FRACUNIT, MT_BOOMPARTICLE);
fixed_t rand_x;
fixed_t rand_y;
fixed_t rand_z;
rand_z = actor->z + P_RandomRange(0, 8)*FRACUNIT;
rand_y = actor->y + P_RandomRange(-8, 8)*FRACUNIT;
rand_x = actor->x + P_RandomRange(-8, 8)*FRACUNIT;
truc = P_SpawnMobj(rand_x, rand_y, rand_z, MT_BOOMPARTICLE);
truc->scale = actor->scale*2;
speed = FixedMul(7*FRACUNIT, actor->scale)>>FRACBITS;
@ -10885,10 +10904,15 @@ void A_SPBChase(mobj_t *actor)
: (16*R_PointToDist2(0, 0, actor->tracer->momx, actor->tracer->momy))/15) // Going faster than the target
&& xyspeed > K_GetKartSpeed(actor->tracer->player, false, false)/4) // Don't display speedup lines at pitifully low speeds
{
mobj_t *fast = P_SpawnMobj(actor->x + (P_RandomRange(-24,24) * actor->scale),
actor->y + (P_RandomRange(-24,24) * actor->scale),
actor->z + (actor->height/2) + (P_RandomRange(-24,24) * actor->scale),
MT_FASTLINE);
fixed_t rand_x;
fixed_t rand_y;
fixed_t rand_z;
rand_z = actor->z + (actor->height/2) + (P_RandomRange(-24,24) * actor->scale);
rand_y = actor->y + (P_RandomRange(-24,24) * actor->scale);
rand_x = actor->x + (P_RandomRange(-24,24) * actor->scale);
mobj_t *fast = P_SpawnMobj(rand_x, rand_y, rand_z, MT_FASTLINE);
fast->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy);
//fast->momx = (3*actor->momx)/4;
//fast->momy = (3*actor->momy)/4;
@ -11283,8 +11307,15 @@ void A_FZBoomSmoke(mobj_t *actor)
for (i = 0; i < 8+(4*var1); i++)
{
mobj_t *smoke = P_SpawnMobj(actor->x + (P_RandomRange(-rad, rad)*actor->scale), actor->y + (P_RandomRange(-rad, rad)*actor->scale),
actor->z + (P_RandomRange(0, 72)*actor->scale), MT_THOK);
fixed_t rand_x;
fixed_t rand_y;
fixed_t rand_z;
rand_z = actor->z + (P_RandomRange(0, 72)*actor->scale);
rand_y = actor->y + (P_RandomRange(-rad, rad)*actor->scale);
rand_x = actor->x + (P_RandomRange(-rad, rad)*actor->scale);
mobj_t *smoke = P_SpawnMobj(rand_x, rand_y, rand_z, MT_THOK);
P_SetMobjState(smoke, S_FZEROSMOKE1);
smoke->tics += P_RandomRange(-3, 4);
@ -11445,13 +11476,20 @@ void A_MementosTPParticles(mobj_t *actor)
mobj_t *mo2;
int i = 0;
thinker_t *th;
fixed_t rand_x;
fixed_t rand_y;
fixed_t rand_z;
if (LUA_CallAction(A_MEMENTOSTPPARTICLES, (actor)))
return;
for (; i<4; i++)
{
particle = P_SpawnMobj(actor->x + (P_RandomRange(-256, 256)<<FRACBITS), actor->y + (P_RandomRange(-256, 256)<<FRACBITS), actor->z + (P_RandomRange(48, 256)<<FRACBITS), MT_MEMENTOSPARTICLE);
rand_z = actor->z + (P_RandomRange(48, 256)<<FRACBITS);
rand_y = actor->y + (P_RandomRange(-256, 256)<<FRACBITS);
rand_x = actor->x + (P_RandomRange(-256, 256)<<FRACBITS);
particle = P_SpawnMobj(rand_x, rand_y, rand_z, MT_MEMENTOSPARTICLE);
particle->frame = 0;
particle->color = ((i%2) ? (SKINCOLOR_RED) : (SKINCOLOR_BLACK));
particle->destscale = 1;
@ -11512,9 +11550,15 @@ void A_ReaperThinker(mobj_t *actor)
if (actor->scale < 2<<FRACBITS) // we haven't finished growing YET.
{
// Spawn particles as we grow out of the floor, ゴ ゴ ゴ ゴ
for (; i<16; i++)
for (; i < 16; i++)
{
particle = P_SpawnMobj(actor->x + (P_RandomRange(-60, 60)<<FRACBITS), actor->y + (P_RandomRange(-60, 60)<<FRACBITS), actor->z, MT_THOK);
fixed_t rand_x;
fixed_t rand_y;
rand_y = actor->y + (P_RandomRange(-60, 60)<<FRACBITS);
rand_x = actor->x + (P_RandomRange(-60, 60)<<FRACBITS);
particle = P_SpawnMobj(rand_x, rand_y, actor->z, MT_THOK);
particle->momz = 20<<FRACBITS;
particle->color = ((i%2 !=0) ? (SKINCOLOR_RED) : (SKINCOLOR_BLACK));
particle->frame = 0;

View file

@ -6847,7 +6847,7 @@ static void P_PlayerInvincibilityOverlay(mobj_t *thing)
{
I_Assert(thing->target != NULL);
I_Assert(thing->target->player != NULL);
if (!thing->target->player->invincibilitytimer)
{
P_SetTarget(&thing->target, NULL);
@ -7966,11 +7966,16 @@ static boolean P_MobjDeadThink(mobj_t *mobj)
if (!(mobj->fuse % 8))
{
fixed_t r = mobj->radius >> FRACBITS;
mobj_t *explosion = P_SpawnMobj(
mobj->x + (P_RandomRange(r, -r) << FRACBITS),
mobj->y + (P_RandomRange(r, -r) << FRACBITS),
mobj->z + (P_RandomKey(mobj->height >> FRACBITS) << FRACBITS),
MT_SONIC3KBOSSEXPLODE);
fixed_t rand_x;
fixed_t rand_y;
fixed_t rand_z;
rand_z = mobj->z + (P_RandomKey(mobj->height >> FRACBITS) << FRACBITS);
rand_y = mobj->y + (P_RandomRange(r, -r) << FRACBITS);
rand_x = mobj->x + (P_RandomRange(r, -r) << FRACBITS);
mobj_t *explosion = P_SpawnMobj(rand_x, rand_y, rand_z, MT_SONIC3KBOSSEXPLODE);
S_StartSound(explosion, sfx_s3kb4);
}
P_SetObjectMomZ(mobj, -2*FRACUNIT/3, true);
@ -8930,7 +8935,13 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
smoke->momy = mobj->target->momy/2;
smoke->momz = mobj->target->momz/2;
P_Thrust(smoke, mobj->angle+FixedAngle(P_RandomRange(135, 225)<<FRACBITS), P_RandomRange(0, 8) * mobj->target->scale);
fixed_t rand_angle;
fixed_t rand_move;
rand_move = P_RandomRange(0, 8) * mobj->target->scale;
rand_angle = mobj->angle+FixedAngle(P_RandomRange(135, 225)<<FRACBITS);
P_Thrust(smoke, rand_angle, rand_move);
}
break;
case MT_SPARKLETRAIL:
@ -9404,11 +9415,18 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
}
else
{
P_SpawnMobj(mobj->x + (P_RandomRange(-48,48)*mobj->scale),
mobj->y + (P_RandomRange(-48,48)*mobj->scale),
mobj->z + (24*mobj->scale) + (P_RandomRange(-8,8)*mobj->scale),
MT_SIGNSPARKLE);
fixed_t rand_x;
fixed_t rand_y;
fixed_t rand_z;
rand_z = mobj->z + (24*mobj->scale) + (P_RandomRange(-8,8)*mobj->scale);
rand_y = mobj->y + (P_RandomRange(-48,48)*mobj->scale);
rand_x = mobj->x + (P_RandomRange(-48,48)*mobj->scale);
P_SpawnMobj(rand_x, rand_y, rand_z, MT_SIGNSPARKLE);
mobj->flags &= ~MF_NOGRAVITY;
if (abs(mobj->z - mobj->movefactor) <= (512*mobj->scale) && !mobj->cvmem)
{
if (mobj->info->seesound)
@ -9466,7 +9484,14 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
else // fire + smoke pillar
{
UINT8 i;
mobj_t *fire = P_SpawnMobj(mobj->x + (P_RandomRange(-32, 32)*mobj->scale), mobj->y + (P_RandomRange(-32, 32)*mobj->scale), mobj->z, MT_THOK);
fixed_t rand_x;
fixed_t rand_y;
rand_y = mobj->y + (P_RandomRange(-32, 32)*mobj->scale);
rand_x = mobj->x + (P_RandomRange(-32, 32)*mobj->scale);
mobj_t *fire = P_SpawnMobj(rand_x, rand_y, mobj->z, MT_THOK);
fire->sprite = SPR_FPRT;
fire->frame = FF_FULLBRIGHT|FF_TRANS30;
@ -9478,7 +9503,10 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
for (i = 0; i < 2; i++)
{
mobj_t *smoke = P_SpawnMobj(mobj->x + (P_RandomRange(-16, 16)*mobj->scale), mobj->y + (P_RandomRange(-16, 16)*mobj->scale), mobj->z, MT_SMOKE);
rand_y = mobj->y + (P_RandomRange(-16, 16)*mobj->scale);
rand_x = mobj->x + (P_RandomRange(-16, 16)*mobj->scale);
mobj_t *smoke = P_SpawnMobj(rand_x, rand_y, mobj->z, MT_SMOKE);
P_SetMobjState(smoke, S_FZSLOWSMOKE1);
smoke->scale = mobj->scale;
@ -9702,9 +9730,15 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
if ((mobj->tracer && !P_MobjWasRemoved(mobj->tracer)) && !(leveltime % 10))
{
mobj_t *dust = P_SpawnMobj(mobj->x + (P_RandomRange(-4, 4)<<FRACBITS),
mobj->y + (P_RandomRange(-4, 4)<<FRACBITS),
mobj->z + (P_RandomRange(0, 2)<<FRACBITS), MT_BBZDUST);
fixed_t rand_x;
fixed_t rand_y;
fixed_t rand_z;
rand_z = mobj->z + (P_RandomRange(0, 2)<<FRACBITS);
rand_y = mobj->y + (P_RandomRange(-4, 4)<<FRACBITS);
rand_x = mobj->x + (P_RandomRange(-4, 4)<<FRACBITS);
mobj_t *dust = P_SpawnMobj(rand_x, rand_y, rand_z, MT_BBZDUST);
P_SetScale(dust, mobj->scale/2);
P_InstaThrust(dust, FixedAngle(P_RandomRange(0,359)<<FRACBITS), abs(mobj->tracer->momz)/2);