// Function: A_MixUp
//
// Description: Mix up all of the player positions.
//
// var1 = unused
// var2 = unused
//
void A_MixUp(mobj_t *actor)
{
boolean teleported[MAXPLAYERS];
INT32 i, numplayers = 0, prandom = 0;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_MixUp", actor))
return;
#else
(void)actor;
#endif
if (!multiplayer)
return;
// No mix-up monitors in hide and seek or time only race.
// The random factor is okay for other game modes, but in these, it is cripplingly unfair.
if (gametype == GT_HIDEANDSEEK || gametype == GT_RACE)
{
S_StartSound(actor, sfx_lose);
return;
}
numplayers = 0;
memset(teleported, 0, sizeof (teleported));
// Count the number of players in the game
// and grab their xyz coords
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].mo && players[i].mo->health > 0 && players[i].playerstate == PST_LIVE
&& !players[i].exiting && !players[i].powers[pw_super] && players[i].powers[pw_carry] != CR_NIGHTSMODE)
{
if ((netgame || multiplayer) && players[i].spectator) // Ignore spectators
continue;
numplayers++;
}
if (numplayers <= 1) // Not enough players to mix up.
{
S_StartSound(actor, sfx_lose);
return;
}
else if (numplayers == 2) // Special case -- simple swap
{
fixed_t x, y, z;
angle_t angle, drawangle;
INT32 one = -1, two = 0; // default value 0 to make the compiler shut up
// Zoom tube stuff
mobj_t *tempthing = NULL; //tracer
UINT16 carry1,carry2; //carry
INT32 transspeed; //player speed
// Starpost stuff
INT16 starpostx, starposty, starpostz;
INT32 starpostnum;
tic_t starposttime;
angle_t starpostangle;
fixed_t starpostscale;
INT32 mflags2;
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].mo && players[i].mo->health > 0 && players[i].playerstate == PST_LIVE
&& !players[i].exiting && !players[i].powers[pw_super])
{
if ((netgame || multiplayer) && players[i].spectator) // Ignore spectators
continue;
if (one == -1)
one = i;
else
{
two = i;
break;
}
}
//get this done first!
if (players[one].powers[pw_carry] == CR_MINECART && players[one].mo->tracer && !(P_MobjWasRemoved(players[one].mo->tracer)))
P_SetTarget(&players[one].mo->tracer->target, players[two].mo);
if (players[two].powers[pw_carry] == CR_MINECART && players[two].mo->tracer && !(P_MobjWasRemoved(players[two].mo->tracer)))
P_SetTarget(&players[two].mo->tracer->target, players[one].mo);
tempthing = players[one].mo->tracer;
P_SetTarget(&players[one].mo->tracer, players[two].mo->tracer);
P_SetTarget(&players[two].mo->tracer, tempthing);
//zoom tubes use player->speed to determine direction and speed
transspeed = players[one].speed;
players[one].speed = players[two].speed;
players[two].speed = transspeed;
//set flags variables now but DON'T set them.
carry1 = (players[one].powers[pw_carry] == CR_PLAYER ? CR_NONE : players[one].powers[pw_carry]);
carry2 = (players[two].powers[pw_carry] == CR_PLAYER ? CR_NONE : players[two].powers[pw_carry]);
x = players[one].mo->x;
y = players[one].mo->y;
z = players[one].mo->z;
angle = players[one].mo->angle;
drawangle = players[one].drawangle;
starpostx = players[one].starpostx;
starposty = players[one].starposty;
starpostz = players[one].starpostz;
starpostangle = players[one].starpostangle;
starpostscale = players[one].starpostscale;
starpostnum = players[one].starpostnum;
starposttime = players[one].starposttime;
mflags2 = players[one].mo->flags2;
P_MixUp(players[one].mo, players[two].mo->x, players[two].mo->y, players[two].mo->z, players[two].mo->angle,
players[two].starpostx, players[two].starposty, players[two].starpostz,
players[two].starpostnum, players[two].starposttime, players[two].starpostangle,
players[two].starpostscale, players[two].drawangle, players[two].mo->flags2);
P_MixUp(players[two].mo, x, y, z, angle, starpostx, starposty, starpostz,
starpostnum, starposttime, starpostangle,
starpostscale, drawangle, mflags2);
//carry set after mixup. Stupid P_ResetPlayer() takes away some of the stuff we look for...
//but not all of it! So we need to make sure they aren't set wrong or anything.
players[one].powers[pw_carry] = carry2;
players[two].powers[pw_carry] = carry1;
teleported[one] = true;
teleported[two] = true;
}
else
{
fixed_t position[MAXPLAYERS][3];
angle_t anglepos[MAXPLAYERS][2];
INT32 pindex[MAXPLAYERS], counter = 0, teleportfrom = 0;
// Zoom tube stuff
mobj_t *transtracer[MAXPLAYERS]; //tracer
//pflags_t transflag[MAXPLAYERS]; //cyan pink white pink cyan
UINT16 transcarry[MAXPLAYERS]; //player carry
INT32 transspeed[MAXPLAYERS]; //player speed
// Star post stuff
INT16 spposition[MAXPLAYERS][3];
INT32 starpostnum[MAXPLAYERS];
tic_t starposttime[MAXPLAYERS];
angle_t starpostangle[MAXPLAYERS];
fixed_t starpostscale[MAXPLAYERS];
INT32 flags2[MAXPLAYERS];
for (i = 0; i < MAXPLAYERS; i++)
{
position[i][0] = position[i][1] = position[i][2] = anglepos[i][0] = anglepos[i][1] = pindex[i] = -1;
teleported[i] = false;
}
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && players[i].playerstate == PST_LIVE
&& players[i].mo && players[i].mo->health > 0 && !players[i].exiting && !players[i].powers[pw_super] && players[i].powers[pw_carry] != CR_NIGHTSMODE)
{
if ((netgame || multiplayer) && players[i].spectator)// Ignore spectators
continue;
position[counter][0] = players[i].mo->x;
position[counter][1] = players[i].mo->y;
position[counter][2] = players[i].mo->z;
pindex[counter] = i;
anglepos[counter][0] = players[i].mo->angle;
anglepos[counter][1] = players[i].drawangle;
players[i].mo->momx = players[i].mo->momy = players[i].mo->momz =
players[i].rmomx = players[i].rmomy = 1;
players[i].cmomx = players[i].cmomy = 0;
transcarry[counter] = (players[i].powers[pw_carry] == CR_PLAYER ? CR_NONE : players[i].powers[pw_carry]);
transspeed[counter] = players[i].speed;
transtracer[counter] = players[i].mo->tracer;
spposition[counter][0] = players[i].starpostx;
spposition[counter][1] = players[i].starposty;
spposition[counter][2] = players[i].starpostz;
starpostnum[counter] = players[i].starpostnum;
starposttime[counter] = players[i].starposttime;
starpostangle[counter] = players[i].starpostangle;
starpostscale[counter] = players[i].starpostscale;
flags2[counter] = players[i].mo->flags2;
counter++;
}
}
counter = 0;
// Mix them up!
for (;;)
{
if (counter > 255) // fail-safe to avoid endless loop
break;
prandom = P_RandomByte();
prandom %= numplayers; // I love modular arithmetic, don't you?
if (prandom) // Make sure it's not a useless mix
break;
counter++;
}
counter = 0;
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && players[i].playerstate == PST_LIVE
&& players[i].mo && players[i].mo->health > 0 && !players[i].exiting && !players[i].powers[pw_super] && players[i].powers[pw_carry] != CR_NIGHTSMODE)
{
if ((netgame || multiplayer) && players[i].spectator)// Ignore spectators
continue;
teleportfrom = (counter + prandom) % numplayers;
//speed and tracer come before...
players[i].speed = transspeed[teleportfrom];
P_SetTarget(&players[i].mo->tracer, transtracer[teleportfrom]);
P_MixUp(players[i].mo, position[teleportfrom][0], position[teleportfrom][1], position[teleportfrom][2], anglepos[teleportfrom][0],
spposition[teleportfrom][0], spposition[teleportfrom][1], spposition[teleportfrom][2],
starpostnum[teleportfrom], starposttime[teleportfrom], starpostangle[teleportfrom],
starpostscale[teleportfrom], anglepos[teleportfrom][1], flags2[teleportfrom]);
//...carry after. same reasoning.
players[i].powers[pw_carry] = transcarry[teleportfrom];
if (transcarry[teleportfrom] == CR_MINECART && transtracer[teleportfrom] && !(P_MobjWasRemoved(transtracer[teleportfrom])))
P_SetTarget(&transtracer[teleportfrom]->target, players[i].mo);
teleported[i] = true;
counter++;
}
}
}
for (i = 0; i < MAXPLAYERS; i++)
{
if (teleported[i])
{
if (playeringame[i] && players[i].playerstate == PST_LIVE
&& players[i].mo && players[i].mo->health > 0 && !players[i].exiting && !players[i].powers[pw_super] && players[i].powers[pw_carry] != CR_NIGHTSMODE)
{
if ((netgame || multiplayer) && players[i].spectator)// Ignore spectators
continue;
P_SetThingPosition(players[i].mo);
#ifdef ESLOPE
players[i].mo->floorz = P_GetFloorZ(players[i].mo, players[i].mo->subsector->sector, players[i].mo->x, players[i].mo->y, NULL);
players[i].mo->ceilingz = P_GetCeilingZ(players[i].mo, players[i].mo->subsector->sector, players[i].mo->x, players[i].mo->y, NULL);
#else
players[i].mo->floorz = players[i].mo->subsector->sector->floorheight;
players[i].mo->ceilingz = players[i].mo->subsector->sector->ceilingheight;
#endif
P_CheckPosition(players[i].mo, players[i].mo->x, players[i].mo->y);
}
}
}
// Play the 'bowrwoosh!' sound
S_StartSound(NULL, sfx_mixup);
}